From 7210f6e912c754fa989e16de440ec06cd31ca1f3 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 26 Dec 2016 10:19:48 -0800 Subject: [PATCH 001/583] 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 002/583] 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 003/583] 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 004/583] 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 005/583] 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 006/583] 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 007/583] 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 008/583] 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 009/583] 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 010/583] 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 011/583] 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 012/583] 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 013/583] 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 014/583] 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 015/583] 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 016/583] 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 017/583] 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 018/583] 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 019/583] 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 020/583] 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 021/583] 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 022/583] 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 023/583] 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 024/583] 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 025/583] 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 026/583] 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 027/583] 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 028/583] 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 029/583] 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 030/583] 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 031/583] 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 032/583] 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 033/583] 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 034/583] 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 035/583] 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 036/583] 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 037/583] 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 038/583] 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 039/583] 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 040/583] 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 041/583] 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 042/583] 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 043/583] 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 044/583] 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 045/583] 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 046/583] 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 047/583] 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 048/583] 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 049/583] 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 050/583] 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 051/583] 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 052/583] 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 053/583] 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 054/583] 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 055/583] 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 056/583] 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 057/583] 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 058/583] 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 059/583] 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 060/583] 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 061/583] 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 062/583] 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 063/583] 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 064/583] 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 065/583] 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 066/583] 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 067/583] 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 068/583] 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 069/583] 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 070/583] 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 071/583] 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 072/583] 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 073/583] 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 074/583] 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 075/583] 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 076/583] 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 077/583] 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 078/583] 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 079/583] 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 080/583] 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 081/583] 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 082/583] 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 083/583] 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 084/583] 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 085/583] 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 086/583] 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 087/583] 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 088/583] 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 089/583] 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 090/583] 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 091/583] 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 092/583] 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 093/583] 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 094/583] 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 095/583] 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 096/583] 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 097/583] 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 098/583] 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 099/583] 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 100/583] 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 101/583] 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 102/583] 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 103/583] 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 104/583] 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 105/583] 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 106/583] 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 107/583] 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 108/583] 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 109/583] 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 110/583] 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 111/583] 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 112/583] 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 113/583] 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 114/583] 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 115/583] 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 116/583] 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 117/583] 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 118/583] 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 119/583] 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 120/583] 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 121/583] 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 122/583] 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 123/583] 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 124/583] 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 127/583] 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 128/583] 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 129/583] 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 130/583] 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 131/583] 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 132/583] 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 133/583] 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 134/583] 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 135/583] 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 136/583] 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 137/583] 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 138/583] 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 139/583] 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 140/583] 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 141/583] 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 142/583] 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 143/583] 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 144/583] 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 145/583] 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 146/583] 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 147/583] 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 148/583] 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 149/583] 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 150/583] 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 151/583] 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 152/583] 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 153/583] 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 154/583] 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 155/583] 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 156/583] 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 157/583] 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 158/583] 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 159/583] 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 160/583] 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 161/583] 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 162/583] 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 163/583] 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 164/583] 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 165/583] 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 166/583] 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 167/583] 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 168/583] 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 169/583] 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 170/583] 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 171/583] 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 172/583] 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 173/583] 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 174/583] 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 175/583] 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 176/583] 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 177/583] 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 178/583] 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 179/583] 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 180/583] 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 181/583] 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 182/583] 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 183/583] 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 184/583] 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 185/583] 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 186/583] 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 187/583] 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 188/583] 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 189/583] 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 190/583] 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 191/583] 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 192/583] 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 193/583] 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 194/583] 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 195/583] 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 196/583] 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 197/583] 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 198/583] 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 199/583] 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 200/583] 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 201/583] 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 202/583] 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 203/583] 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 204/583] 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 205/583] 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 206/583] 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 207/583] 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 208/583] 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 209/583] 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 210/583] 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 211/583] 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 212/583] 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 213/583] 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 214/583] 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 215/583] 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 216/583] 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 217/583] 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 218/583] 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 219/583] 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 220/583] 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 221/583] 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 222/583] 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 223/583] 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 224/583] 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 225/583] 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 226/583] 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 227/583] 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 228/583] 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 229/583] 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 230/583] 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 231/583] 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 232/583] 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 233/583] 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 234/583] 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 235/583] 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 236/583] 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 237/583] 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 238/583] 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 239/583] 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 240/583] 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 241/583] 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 242/583] 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 243/583] 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 244/583] 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 245/583] 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 246/583] 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 247/583] 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 248/583] 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 249/583] 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 250/583] 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 251/583] 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 252/583] 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 253/583] 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 254/583] 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 255/583] 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 256/583] 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 257/583] 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 258/583] 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 259/583] 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 260/583] 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 261/583] 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 262/583] 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 263/583] 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 264/583] 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 265/583] 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 266/583] 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 267/583] 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 268/583] 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 269/583] 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 270/583] 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 271/583] 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 272/583] 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 273/583] 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 274/583] 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 275/583] 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 276/583] 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 277/583] 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 278/583] 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 279/583] 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 280/583] 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 281/583] 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 282/583] 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 283/583] 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 284/583] 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 285/583] 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 286/583] 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 287/583] 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 288/583] 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 289/583] 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 290/583] 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 291/583] 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 292/583] 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 293/583] 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 294/583] 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 295/583] 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 296/583] 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 297/583] 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 298/583] 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 299/583] 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 300/583] 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 301/583] 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 302/583] 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 303/583] 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 304/583] 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 305/583] 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 306/583] 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 307/583] 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 308/583] 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 309/583] 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 310/583] 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 311/583] 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 312/583] 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 313/583] 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 314/583] 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 315/583] 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 316/583] 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 317/583] 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 318/583] 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 319/583] 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 320/583] 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 321/583] 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 322/583] 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 323/583] 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 324/583] 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 325/583] 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 326/583] 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 327/583] 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 328/583] 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 329/583] 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 330/583] 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 331/583] 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 332/583] 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 333/583] 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 334/583] 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 335/583] 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 336/583] 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 337/583] 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 338/583] 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 339/583] 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 340/583] 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 341/583] 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 342/583] 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 343/583] 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 344/583] 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 345/583] 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 346/583] 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 347/583] 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 348/583] 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 349/583] 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 350/583] 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 351/583] 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 352/583] 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 353/583] 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 354/583] 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 355/583] 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 356/583] 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 357/583] 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 358/583] 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 359/583] 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 360/583] 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 361/583] 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 362/583] 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 363/583] 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 364/583] 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 365/583] 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 366/583] 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 367/583] 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 368/583] 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 369/583] 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 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 370/583] 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 371/583] 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 372/583] 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 373/583] 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 374/583] 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 375/583] 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 376/583] 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 377/583] 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 378/583] 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 379/583] 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 380/583] 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 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 381/583] 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 6d729f1f158ebc406262dad703b31470a42ea0a9 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 11 Dec 2017 10:36:42 -0800 Subject: [PATCH 382/583] 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 383/583] 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 384/583] 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 385/583] 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 386/583] 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 387/583] 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 388/583] 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 389/583] 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 390/583] 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 391/583] 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 392/583] 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 393/583] 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 394/583] 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 395/583] 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 396/583] 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 397/583] 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 398/583] 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 399/583] 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 400/583] 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 401/583] 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 402/583] 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 403/583] 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 c199344bbf443fe0ce880b0f24a1f11e56249455 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 18 Dec 2017 11:12:27 -0800 Subject: [PATCH 404/583] 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 8198a8ce7bebcd79ea5ba798bf5ee618ab2d1d33 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 23 Dec 2017 14:41:16 -0800 Subject: [PATCH 405/583] 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 406/583] 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 b1724b2f629e71e7bdf8b104dd052bfc95b140f2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 28 Dec 2017 14:39:16 -0800 Subject: [PATCH 407/583] 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 408/583] 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 409/583] 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 410/583] 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 1c2966f8e97da8cd08b5beb26583dc86772b5f11 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 11 Jan 2018 11:20:23 -0800 Subject: [PATCH 411/583] 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 412/583] 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 d79c33fb21eda6a2804d4820d2547526579ee128 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 13 Jan 2018 16:12:38 -0800 Subject: [PATCH 413/583] 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 414/583] 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 415/583] 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 ae728374c84a6bf65f4849d3341ad83140105005 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 15 Jan 2018 17:20:19 -0800 Subject: [PATCH 416/583] 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 7b8101c502e41930ec0e4d0217311eb2a2790c57 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 17 Jan 2018 12:25:24 -0800 Subject: [PATCH 417/583] 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 c7ee532173b97b67e93f3d0b02f3d425bb1ff96f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 18 Jan 2018 10:44:40 -0800 Subject: [PATCH 418/583] 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 d6c49adddb5cb76391591940846bf2986ff97129 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 19 Jan 2018 13:57:21 -0800 Subject: [PATCH 419/583] 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 420/583] 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 421/583] 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 422/583] 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 423/583] 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 5a2b072ddf781e9b1205935e4a68ff3ed166441e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 29 Jan 2018 20:32:06 -0800 Subject: [PATCH 424/583] 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 ede12553f2add216b56819501c3e53a7fd26040e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 30 Jan 2018 03:31:28 -0800 Subject: [PATCH 425/583] 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 2d0f80f78ede999250f8465eb2a154c54e7b9bef Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 30 Jan 2018 09:22:36 -0800 Subject: [PATCH 426/583] 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 427/583] 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 428/583] 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 429/583] 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 430/583] 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 eca250933df23dbc170c49df91c813c8327c8a6d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 1 Feb 2018 19:56:01 -0800 Subject: [PATCH 431/583] 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 432/583] 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 433/583] 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 434/583] 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 e95840b640658557a278ea6f881ce2bbfc2c8b7a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 2 Feb 2018 20:51:41 -0800 Subject: [PATCH 435/583] 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 db347c007dcb242cf0e4830bdb06b55eb1f6482a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 3 Feb 2018 09:39:39 -0800 Subject: [PATCH 436/583] 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 437/583] 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 438/583] 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 439/583] 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 440/583] 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 43441d0fd535dda9c475b9e5ecf654c3a8f20b32 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 6 Feb 2018 14:02:44 -0800 Subject: [PATCH 441/583] 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 bee4716a850f96283c3f71bda67d44c4f93df429 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 7 Feb 2018 12:56:30 -0800 Subject: [PATCH 442/583] 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 443/583] 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 444/583] 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 445/583] 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 446/583] 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 447/583] 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 448/583] 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 449/583] 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 450/583] 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 451/583] 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 452/583] 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 453/583] 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 454/583] 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 455/583] 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 456/583] 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 457/583] 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 5e482def18b824ca573d5d424f9a4b57a5f95ec1 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 8 Feb 2018 07:27:32 -0800 Subject: [PATCH 458/583] 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 459/583] 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 460/583] 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 461/583] 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 462/583] 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 19b858dbea1ae968a2f886213208fb53220cb059 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 9 Feb 2018 04:00:32 -0800 Subject: [PATCH 463/583] 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 5206e29bddccdad63bd61a50d6e3678aa9215a3d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 9 Feb 2018 09:18:05 -0800 Subject: [PATCH 464/583] 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 465/583] 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 466/583] 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 467/583] 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 e183f8b7434d4f2db72c7b6eac3778b2f639396c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 9 Feb 2018 21:46:45 -0800 Subject: [PATCH 468/583] 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 469/583] 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 470/583] 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 471/583] 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 4c1379e8c9600462934a6792742cb66b2e289239 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 19 Feb 2018 21:49:03 -0800 Subject: [PATCH 472/583] 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 473/583] 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 718e5a9b6c481f3c0f89389f7b740a8d909e9b9b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 6 Mar 2018 01:08:17 -0800 Subject: [PATCH 474/583] 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 475/583] 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 476/583] 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 e7d43ed516ab4a233e48e8b0c9aadf67d872c106 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 12 Mar 2018 11:22:05 -0700 Subject: [PATCH 477/583] 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 64954cc5510619d1c114e728e5b2746b1be7f73b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 13 Mar 2018 09:07:58 -0700 Subject: [PATCH 478/583] 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 479/583] 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 bf8ea92b992b64f0541a64fbeda127549455dfa3 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 13 Mar 2018 17:23:58 -0700 Subject: [PATCH 480/583] 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 59b142f8039763b4e1caa33258a86f767d94221a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 15 Mar 2018 06:48:26 -0700 Subject: [PATCH 481/583] 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 af96e4272403929969640cde16930e3f395ac82b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 15 Mar 2018 21:11:55 -0700 Subject: [PATCH 482/583] 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 a7e0f18482e69a2eb8c78e91f6f59f1c40310800 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 18 Mar 2018 16:53:04 -0700 Subject: [PATCH 483/583] 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 484/583] 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 485/583] 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 486/583] 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 8602c52bc93045133880ee547cba344223949665 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 19 Mar 2018 10:41:42 -0700 Subject: [PATCH 487/583] 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 488/583] 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 489/583] 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 490/583] 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 ba2e28fa0e9766b02a4840888ee1d57298c45ce2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 19 Mar 2018 14:55:38 -0700 Subject: [PATCH 491/583] 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 95980454359a7e2c8da1659fa3180e03f4259294 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 19 Mar 2018 15:49:28 -0700 Subject: [PATCH 492/583] 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 493/583] 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 494/583] 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 495/583] 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 496/583] 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 497/583] 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 dc01266354c38470cce566ba0e962ceda01a89ef Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 19 Mar 2018 20:50:24 -0700 Subject: [PATCH 498/583] 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 76eae5fa5c4c04f6bd3d8fbe419d063c441b293d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 20 Mar 2018 16:57:01 -0700 Subject: [PATCH 499/583] 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 500/583] 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 501/583] 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 502/583] 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 503/583] 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 504/583] 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 505/583] 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 506/583] 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 507/583] 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 508/583] 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 509/583] 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 510/583] 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 511/583] 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 512/583] 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 513/583] 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 514/583] 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 515/583] 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 516/583] 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 a79400a01bae238be7100bb36b7a10fcfb7f6dd6 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 25 Mar 2018 14:55:42 -0700 Subject: [PATCH 517/583] 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 518/583] 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 7063ad81cce2d6020c2495ca96d938ff504efb02 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 25 Mar 2018 19:42:06 -0700 Subject: [PATCH 519/583] 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 520/583] 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 521/583] 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 522/583] 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 aa2721517ba17938f257e678debda78f87d3d456 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 30 Mar 2018 16:24:22 -0700 Subject: [PATCH 523/583] 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 a914142c7c6caf89dca96f99c211f449d9725b26 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 31 Mar 2018 05:34:11 -0700 Subject: [PATCH 524/583] 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 525/583] 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 526/583] 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 a954ab7d8db1c62a6bcb295da21e63a821b69248 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 6 Apr 2018 08:38:01 -0700 Subject: [PATCH 527/583] 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 21738d9750aa5902173ad47df61f5f4c7dcaf9d2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 6 Apr 2018 15:59:55 -0700 Subject: [PATCH 528/583] 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 f2dfc0dc24c8594ae4d1181bfbb4b1848d057a94 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 8 Apr 2018 15:46:21 -0700 Subject: [PATCH 529/583] 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 530/583] 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 f7e49501af7c87f25109de4430214349c7ec479a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 13 Apr 2018 16:22:36 -0700 Subject: [PATCH 531/583] 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 532/583] 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 533/583] 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 534/583] 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 252fb4af6e6689adf9756a0ab31033d3cc9e6550 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sat, 14 Apr 2018 15:34:33 -0700 Subject: [PATCH 535/583] 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 536/583] 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 537/583] 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 538/583] 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 539/583] 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 540/583] 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 563f337997a0e684c20eee62e6862dd73e3cd91d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 27 Apr 2018 17:59:03 +0200 Subject: [PATCH 541/583] 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 542/583] 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 e940f53e9c58df2c1ca239bc3352dcf29b3a1caf Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 30 Apr 2018 07:57:33 -0700 Subject: [PATCH 543/583] 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 544/583] 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 545/583] 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 546/583] 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 78b9f0686a8fa8c03e7a9d6f17794fdb73d05ce2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 1 May 2018 07:43:29 -0700 Subject: [PATCH 547/583] 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 548/583] 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 549/583] 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 550/583] 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 551/583] 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 552/583] 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 553/583] 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 554/583] 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 555/583] 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 556/583] 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 557/583] 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 558/583] 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 559/583] 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 560/583] 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 1fc1249befedf49347cc606101af0021a2e0ff7c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 2 May 2018 11:28:13 -0700 Subject: [PATCH 561/583] 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 562/583] 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 563/583] 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 564/583] 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 e98c808f47e767f498d7b9325a59cb46de3d020d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 3 May 2018 03:18:29 -0700 Subject: [PATCH 565/583] 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 8ecff9e5ee3323db1ccfc831c03bba92c7db7a06 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 3 May 2018 08:04:10 -0700 Subject: [PATCH 566/583] 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 567/583] 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 568/583] 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 43403fafcd33ade94f66d13f1eb93a3b0ffe6b80 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 3 May 2018 13:23:59 -0700 Subject: [PATCH 569/583] 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 570/583] 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 571/583] 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 41072e3125f492ef5e1b47f08bfefbde9c2f74ff Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 8 May 2018 19:09:59 +0100 Subject: [PATCH 572/583] 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 573/583] 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 574/583] 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 575/583] 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 576/583] 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 577/583] 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 578/583] 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 579/583] 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 580/583] 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 dfeb4b5235f4cc42062011632c97d6ab095593a3 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 17 May 2018 16:45:12 -0700 Subject: [PATCH 581/583] 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 87ae679db61e7d3fbe3ffc7f07dd5f06f5409277 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 22 May 2018 17:03:35 -0700 Subject: [PATCH 582/583] 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 c963f6f2df8a113522173fe2cf024aa5962ac5b7 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 23 May 2018 08:02:16 -0700 Subject: [PATCH 583/583] 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());