From 7210f6e912c754fa989e16de440ec06cd31ca1f3 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 26 Dec 2016 10:19:48 -0800 Subject: [PATCH 001/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] 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/637] fix local search initialization of units, encode offset in clauses Signed-off-by: Nikolaj Bjorner --- src/sat/sat_clause.cpp | 18 +++++++++++++++++- src/sat/sat_clause.h | 2 ++ src/sat/sat_local_search.cpp | 27 +++++++++++++++++---------- src/sat/sat_solver.cpp | 8 ++++---- src/solver/parallel_params.pyg | 2 +- src/solver/parallel_tactic.cpp | 8 ++++++-- 6 files changed, 47 insertions(+), 18 deletions(-) diff --git a/src/sat/sat_clause.cpp b/src/sat/sat_clause.cpp index f9caffe94..78d62bac0 100644 --- a/src/sat/sat_clause.cpp +++ b/src/sat/sat_clause.cpp @@ -95,7 +95,6 @@ namespace sat { } } - bool clause::satisfied_by(model const & m) const { for (literal l : *this) { if (l.sign()) { @@ -110,6 +109,23 @@ namespace sat { return false; } + clause_offset clause::get_new_offset() const { + unsigned o1 = m_lits[0].index(); + if (sizeof(clause_offset) == 8) { + unsigned o2 = m_lits[1].index(); + return (clause_offset)o1 + (((clause_offset)o2) << 32); + } + return (clause_offset)o1; + } + + void clause::set_new_offset(clause_offset offset) { + m_lits[0] = to_literal(static_cast(offset)); + if (sizeof(offset) == 8) { + m_lits[1] = to_literal(static_cast(offset >> 32)); + } + } + + void tmp_clause::set(unsigned num_lits, literal const * lits, bool learned) { if (m_clause && m_clause->m_capacity < num_lits) { dealloc_svect(m_clause); diff --git a/src/sat/sat_clause.h b/src/sat/sat_clause.h index c42427afb..8b2d113c8 100644 --- a/src/sat/sat_clause.h +++ b/src/sat/sat_clause.h @@ -98,6 +98,8 @@ namespace sat { unsigned glue() const { return m_glue; } void set_psm(unsigned psm) { m_psm = psm > 255 ? 255 : psm; } unsigned psm() const { return m_psm; } + clause_offset get_new_offset() const; + void set_new_offset(clause_offset off); bool on_reinit_stack() const { return m_reinit_stack; } void set_reinit_stack(bool f) { m_reinit_stack = f; } diff --git a/src/sat/sat_local_search.cpp b/src/sat/sat_local_search.cpp index 35e371a9c..e02560e5f 100644 --- a/src/sat/sat_local_search.cpp +++ b/src/sat/sat_local_search.cpp @@ -79,11 +79,13 @@ namespace sat { void local_search::init_cur_solution() { for (var_info& vi : m_vars) { // use bias with a small probability - if (m_rand() % 10 < 5 || m_config.phase_sticky()) { - vi.m_value = ((unsigned)(m_rand() % 100) < vi.m_bias); - } - else { - vi.m_value = (m_rand() % 2) == 0; + if (!vi.m_unit) { + if (m_rand() % 10 < 5 || m_config.phase_sticky()) { + vi.m_value = ((unsigned)(m_rand() % 100) < vi.m_bias); + } + else { + vi.m_value = (m_rand() % 2) == 0; + } } } } @@ -149,7 +151,7 @@ namespace sat { void local_search::reinit() { - IF_VERBOSE(0, verbose_stream() << "(sat-local-search reinit)\n";); + IF_VERBOSE(1, verbose_stream() << "(sat-local-search reinit)\n";); if (true || !m_is_pb) { // // the following methods does NOT converge for pseudo-boolean @@ -216,13 +218,15 @@ namespace sat { for (unsigned i = 0; i < m_prop_queue.size() && i < m_vars.size(); ++i) { literal lit2 = m_prop_queue[i]; if (!is_true(lit2)) { - if (is_unit(lit2)) return false; + if (is_unit(lit2)) { + return false; + } flip_walksat(lit2.var()); add_propagation(lit2); } } if (m_prop_queue.size() >= m_vars.size()) { - IF_VERBOSE(0, verbose_stream() << "failed literal\n"); + IF_VERBOSE(0, verbose_stream() << "propagation loop\n"); return false; } if (unit) { @@ -328,6 +332,7 @@ namespace sat { return; } if (k == 1 && sz == 2) { + // IF_VERBOSE(0, verbose_stream() << "bin: " << ~c[0] << " + " << ~c[1] << " <= 1\n"); for (unsigned i = 0; i < 2; ++i) { literal t(c[i]), s(c[1-i]); m_vars.reserve(t.var() + 1); @@ -750,11 +755,12 @@ namespace sat { IF_VERBOSE(1, verbose_stream() << "(sat.local_search :unsat)\n"); return; } - + if (is_unit(best_var)) { + goto reflip; + } flip_walksat(best_var); literal lit(best_var, !cur_solution(best_var)); if (!propagate(lit)) { - IF_VERBOSE(0, verbose_stream() << "failed literal " << lit << "\n"); if (is_true(lit)) { flip_walksat(best_var); } @@ -774,6 +780,7 @@ namespace sat { } void local_search::flip_walksat(bool_var flipvar) { + VERIFY(!is_unit(flipvar)); m_vars[flipvar].m_value = !cur_solution(flipvar); bool flip_is_true = cur_solution(flipvar); diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 792883977..90ac876d2 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -529,26 +529,26 @@ namespace sat { IF_VERBOSE(1, verbose_stream() << "(sat-defrag)\n"); clause_allocator& alloc = m_cls_allocator[!m_cls_allocator_idx]; ptr_vector new_clauses, new_learned; - ptr_addr_map cls2offset; for (clause* c : m_clauses) c->unmark_used(); for (clause* c : m_learned) c->unmark_used(); +#if 0 svector vars; for (unsigned i = 0; i < num_vars(); ++i) vars.push_back(i); std::stable_sort(vars.begin(), vars.end(), cmp_activity(*this)); literal_vector lits; for (bool_var v : vars) lits.push_back(to_literal(v)), lits.push_back(~to_literal(v)); - // walk clauses, reallocate them in an order that defragments memory and creates locality. //for (literal lit : lits) { //watch_list& wlist = m_watches[lit.index()]; +#endif for (watch_list& wlist : m_watches) { for (watched& w : wlist) { if (w.is_clause()) { clause& c1 = get_clause(w); clause_offset offset; if (c1.was_used()) { - offset = cls2offset[&c1]; + offset = c1.get_new_offset(); } else { clause* c2 = alloc.copy_clause(c1); @@ -560,7 +560,7 @@ namespace sat { new_clauses.push_back(c2); } offset = get_offset(*c2); - cls2offset.insert(&c1, offset); + c1.set_new_offset(offset); } w = watched(w.get_blocked_literal(), offset); } diff --git a/src/solver/parallel_params.pyg b/src/solver/parallel_params.pyg index 58c00aa97..2d58cbb81 100644 --- a/src/solver/parallel_params.pyg +++ b/src/solver/parallel_params.pyg @@ -5,7 +5,7 @@ def_module_params('parallel', params=( ('enable', BOOL, False, 'enable parallel solver by default on selected tactics (for QF_BV)'), ('threads.max', UINT, 10000, 'caps maximal number of threads below the number of processors'), - ('conquer.batch_size', UINT, 1000, 'number of cubes to batch together for fast conquer'), + ('conquer.batch_size', UINT, 100, 'number of cubes to batch together for fast conquer'), ('conquer.restart.max', UINT, 5, 'maximal number of restarts during conquer phase'), ('conquer.delay', UINT, 10, 'delay of cubes until applying conquer'), ('conquer.backtrack_frequency', UINT, 10, 'frequency to apply core minimization during conquer'), diff --git a/src/solver/parallel_tactic.cpp b/src/solver/parallel_tactic.cpp index 748ee5d64..ac147672e 100644 --- a/src/solver/parallel_tactic.cpp +++ b/src/solver/parallel_tactic.cpp @@ -99,6 +99,8 @@ class parallel_tactic : public tactic { } } + bool in_shutdown() const { return m_shutdown; } + void add_task(solver_state* task) { std::lock_guard lock(m_mutex); m_tasks.push_back(task); @@ -285,6 +287,7 @@ class parallel_tactic : public tactic { p.set_uint("restart.max", pp.simplify_restart_max() * mult); p.set_bool("lookahead_simplify", true); p.set_bool("retain_blocked_clauses", retain_blocked); + if (m_depth > 1) p.set_uint("bce_delay", 0); get_solver().updt_params(p); } @@ -479,8 +482,8 @@ private: break; } - if (cubes.size() >= conquer_batch_size() || (!cubes.empty() && m_queue.is_idle())) { - spawn_cubes(s, std::max(2u, width), cubes); + if (cubes.size() >= conquer_batch_size()) { + spawn_cubes(s, 10*width, cubes); first = false; cubes.reset(); } @@ -575,6 +578,7 @@ private: } catch (z3_exception& ex) { IF_VERBOSE(1, verbose_stream() << ex.msg() << "\n";); + if (m_queue.in_shutdown()) return; m_queue.shutdown(); std::lock_guard lock(m_mutex); if (ex.has_error_code()) { From b8193a0ae62e9abc6a1c887b177d4bfec2757a5b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Sun, 29 Apr 2018 10:04:42 -0700 Subject: [PATCH 543/637] fix #1604 Signed-off-by: Nikolaj Bjorner --- src/cmd_context/context_params.cpp | 2 +- src/cmd_context/extra_cmds/dbg_cmds.cpp | 2 +- src/shell/lp_frontend.cpp | 4 +-- src/util/env_params.cpp | 2 +- src/util/gparams.cpp | 46 +++++++++---------------- src/util/gparams.h | 3 +- src/util/params.cpp | 23 +++++++------ 7 files changed, 35 insertions(+), 47 deletions(-) diff --git a/src/cmd_context/context_params.cpp b/src/cmd_context/context_params.cpp index 85ac2274b..ff39907da 100644 --- a/src/cmd_context/context_params.cpp +++ b/src/cmd_context/context_params.cpp @@ -135,7 +135,7 @@ void context_params::set(char const * param, char const * value) { } void context_params::updt_params() { - updt_params(gparams::get()); + updt_params(gparams::get_ref()); } void context_params::updt_params(params_ref const & p) { diff --git a/src/cmd_context/extra_cmds/dbg_cmds.cpp b/src/cmd_context/extra_cmds/dbg_cmds.cpp index 465bcb956..fa1d56fe2 100644 --- a/src/cmd_context/extra_cmds/dbg_cmds.cpp +++ b/src/cmd_context/extra_cmds/dbg_cmds.cpp @@ -271,7 +271,7 @@ UNARY_CMD(elim_unused_vars_cmd, "dbg-elim-unused-vars", "", "eliminate unu return; } expr_ref r(ctx.m()); - elim_unused_vars(ctx.m(), to_quantifier(arg), gparams::get(), r); + elim_unused_vars(ctx.m(), to_quantifier(arg), gparams::get_ref(), r); SASSERT(!is_quantifier(r) || !to_quantifier(r)->may_have_unused_vars()); ctx.display(ctx.regular_stream(), r); ctx.regular_stream() << std::endl; diff --git a/src/shell/lp_frontend.cpp b/src/shell/lp_frontend.cpp index c79396cd1..ad9bcbd54 100644 --- a/src/shell/lp_frontend.cpp +++ b/src/shell/lp_frontend.cpp @@ -55,8 +55,8 @@ struct front_end_resource_limit : public lp::lp_resource_limit { void run_solver(lp_params & params, char const * mps_file_name) { reslimit rlim; - unsigned timeout = gparams::get().get_uint("timeout", 0); - unsigned rlimit = gparams::get().get_uint("rlimit", 0); + unsigned timeout = gparams::get_ref().get_uint("timeout", 0); + unsigned rlimit = gparams::get_ref().get_uint("rlimit", 0); front_end_resource_limit lp_limit(rlim); scoped_rlimit _rlimit(rlim, rlimit); diff --git a/src/util/env_params.cpp b/src/util/env_params.cpp index c2b5f7974..3ba6df735 100644 --- a/src/util/env_params.cpp +++ b/src/util/env_params.cpp @@ -23,7 +23,7 @@ Notes: #include "util/memory_manager.h" void env_params::updt_params() { - params_ref p = gparams::get(); + params_ref const& p = gparams::get_ref(); set_verbosity_level(p.get_uint("verbose", get_verbosity_level())); enable_warning_messages(p.get_bool("warning", true)); memory::set_max_size(megabytes_to_bytes(p.get_uint("memory_max_size", 0))); diff --git a/src/util/gparams.cpp b/src/util/gparams.cpp index 12c335cdf..183525320 100644 --- a/src/util/gparams.cpp +++ b/src/util/gparams.cpp @@ -104,10 +104,8 @@ public: ~imp() { reset(); - dictionary::iterator it = m_module_param_descrs.begin(); - dictionary::iterator end = m_module_param_descrs.end(); - for (; it != end; ++it) { - dealloc(it->m_value); + for (auto & kv : m_module_param_descrs) { + dealloc(kv.m_value); } } @@ -115,10 +113,8 @@ public: #pragma omp critical (gparams) { m_params.reset(); - dictionary::iterator it = m_module_params.begin(); - dictionary::iterator end = m_module_params.end(); - for (; it != end; ++it) { - dealloc(it->m_value); + for (auto & kv : m_module_params) { + dealloc(kv.m_value); } m_module_params.reset(); } @@ -437,14 +433,8 @@ public: return result; } - params_ref get() { - params_ref result; - TRACE("gparams", tout << "get() m_params: " << m_params << "\n";); - #pragma omp critical (gparams) - { - result = m_params; - } - return result; + params_ref const& get_ref() { + return m_params; } // ----------------------------------------------- @@ -464,16 +454,14 @@ public: out << "Example: pp.decimal=true\n"; out << "\n"; } - dictionary::iterator it = get_module_param_descrs().begin(); - dictionary::iterator end = get_module_param_descrs().end(); - for (; it != end; ++it) { - out << "[module] " << it->m_key; + for (auto & kv : get_module_param_descrs()) { + out << "[module] " << kv.m_key; char const * descr = nullptr; - if (get_module_descrs().find(it->m_key, descr)) { + if (get_module_descrs().find(kv.m_key, descr)) { out << ", description: " << descr; } out << "\n"; - it->m_value->display(out, indent + 4, smt2_style, include_descr); + kv.m_value->display(out, indent + 4, smt2_style, include_descr); } } } @@ -481,12 +469,10 @@ public: void display_modules(std::ostream & out) { #pragma omp critical (gparams) { - dictionary::iterator it = get_module_param_descrs().begin(); - dictionary::iterator end = get_module_param_descrs().end(); - for (; it != end; ++it) { - out << "[module] " << it->m_key; + for (auto & kv : get_module_param_descrs()) { + out << "[module] " << kv.m_key; char const * descr = nullptr; - if (get_module_descrs().find(it->m_key, descr)) { + if (get_module_descrs().find(kv.m_key, descr)) { out << ", description: " << descr; } out << "\n"; @@ -618,10 +604,10 @@ params_ref gparams::get_module(symbol const & module_name) { return g_imp->get_module(module_name); } -params_ref gparams::get() { - TRACE("gparams", tout << "gparams::get()\n";); +params_ref const& gparams::get_ref() { + TRACE("gparams", tout << "gparams::get_ref()\n";); SASSERT(g_imp != 0); - return g_imp->get(); + return g_imp->get_ref(); } void gparams::display(std::ostream & out, unsigned indent, bool smt2_style, bool include_descr) { diff --git a/src/util/gparams.h b/src/util/gparams.h index 7ddaf0ccb..5334b28d0 100644 --- a/src/util/gparams.h +++ b/src/util/gparams.h @@ -106,7 +106,8 @@ public: /** \brief Return the global parameter set (i.e., parameters that are not associated with any particular module). */ - static params_ref get(); + + static params_ref const& get_ref(); /** \brief Dump information about available parameters in the given output stream. diff --git a/src/util/params.cpp b/src/util/params.cpp index 5e1e517c1..6bb6678cc 100644 --- a/src/util/params.cpp +++ b/src/util/params.cpp @@ -334,7 +334,10 @@ public: } void inc_ref() { m_ref_count++; } - void dec_ref() { SASSERT(m_ref_count > 0); m_ref_count--; if (m_ref_count == 0) dealloc(this); } + void dec_ref() { + SASSERT(m_ref_count > 0); + if (--m_ref_count == 0) dealloc(this); + } bool empty() const { return m_entries.empty(); } bool contains(symbol const & k) const; @@ -565,27 +568,25 @@ void params_ref::copy(params_ref const & src) { void params_ref::copy_core(params const * src) { if (src == nullptr) return; - svector::const_iterator it = src->m_entries.begin(); - svector::const_iterator end = src->m_entries.end(); - for (; it != end; ++it) { - switch (it->second.m_kind) { + for (auto const& p : src->m_entries) { + switch (p.second.m_kind) { case CPK_BOOL: - m_params->set_bool(it->first, it->second.m_bool_value); + m_params->set_bool(p.first, p.second.m_bool_value); break; case CPK_UINT: - m_params->set_uint(it->first, it->second.m_uint_value); + m_params->set_uint(p.first, p.second.m_uint_value); break; case CPK_DOUBLE: - m_params->set_double(it->first, it->second.m_double_value); + m_params->set_double(p.first, p.second.m_double_value); break; case CPK_NUMERAL: - m_params->set_rat(it->first, *(it->second.m_rat_value)); + m_params->set_rat(p.first, *(p.second.m_rat_value)); break; case CPK_SYMBOL: - m_params->set_sym(it->first, symbol::mk_symbol_from_c_ptr(it->second.m_sym_value)); + m_params->set_sym(p.first, symbol::mk_symbol_from_c_ptr(p.second.m_sym_value)); break; case CPK_STRING: - m_params->set_str(it->first, it->second.m_str_value); + m_params->set_str(p.first, p.second.m_str_value); break; default: UNREACHABLE(); From e940f53e9c58df2c1ca239bc3352dcf29b3a1caf Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Mon, 30 Apr 2018 07:57:33 -0700 Subject: [PATCH 544/637] 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 545/637] 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 546/637] 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 547/637] merge Signed-off-by: Nikolaj Bjorner --- src/api/java/Solver.java | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/src/api/java/Solver.java b/src/api/java/Solver.java index a1a852791..0370a9571 100644 --- a/src/api/java/Solver.java +++ b/src/api/java/Solver.java @@ -121,22 +121,6 @@ public class Solver extends Z3Object { } } - /** - * Load solver assertions from a file. - */ - public void fromFile(String file) - { - Native.solverFromFile(getContext().nCtx(), getNativeObject(), file); - } - - /** - * Load solver assertions from a string. - */ - public void fromString(String str) - { - Native.solverFromString(getContext().nCtx(), getNativeObject(), str); - } - /** * Assert multiple constraints into the solver, and track them (in the From 371880da04b0260c0db1bf5f4c3c6975fd8cfc70 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 1 May 2018 07:13:03 -0700 Subject: [PATCH 548/637] n/a Signed-off-by: Nikolaj Bjorner --- src/smt/smt_context.cpp | 54 ++++++++------------------------------ src/smt/smt_context_pp.cpp | 5 +--- src/smt/smt_enode.h | 41 +++++++++++++++++++++++------ 3 files changed, 45 insertions(+), 55 deletions(-) diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index e20eae0bd..177dbb355 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -627,10 +627,7 @@ namespace smt { */ void context::remove_parents_from_cg_table(enode * r1) { // Remove parents from the congruence table - enode_vector::iterator it = r1->begin_parents(); - enode_vector::iterator end = r1->end_parents(); - for (; it != end; ++it) { - enode * parent = *it; + for (enode * parent : r1->get_parents()) { #if 0 { static unsigned num_eqs = 0; @@ -675,10 +672,7 @@ namespace smt { */ void context::reinsert_parents_into_cg_table(enode * r1, enode * r2, enode * n1, enode * n2, eq_justification js) { enode_vector & r2_parents = r2->m_parents; - enode_vector::iterator it = r1->begin_parents(); - enode_vector::iterator end = r1->end_parents(); - for (; it != end; ++it) { - enode * parent = *it; + for (enode * parent : r1->get_parents()) { if (!parent->is_marked()) continue; parent->unset_mark(); @@ -1008,10 +1002,7 @@ namespace smt { r2->m_parents.shrink(r2_num_parents); // try to reinsert parents of r1 that are not cgr - it = r1->begin_parents(); - end = r1->end_parents(); - for (; it != end; ++it) { - enode * parent = *it; + for (enode * parent : r1->get_parents()) { TRACE("add_eq_parents", tout << "visiting: #" << parent->get_owner_id() << "\n";); if (parent->is_cgc_enabled()) { enode * cg = parent->m_cg; @@ -1206,10 +1197,7 @@ namespace smt { bool context::is_diseq_slow(enode * n1, enode * n2) const { if (n1->get_num_parents() > n2->get_num_parents()) std::swap(n1, n2); - enode_vector::iterator it = n1->begin_parents(); - enode_vector::iterator end = n1->end_parents(); - for (; it != end; ++it) { - enode * parent = *it; + for (enode * parent : n1->get_parents()) { if (parent->is_eq() && is_relevant(parent->get_owner()) && get_assignment(enode2bool_var(parent)) == l_false && ((parent->get_arg(0)->get_root() == n1->get_root() && parent->get_arg(1)->get_root() == n2->get_root()) || (parent->get_arg(1)->get_root() == n1->get_root() && parent->get_arg(0)->get_root() == n2->get_root()))) { @@ -1241,10 +1229,7 @@ namespace smt { return false; if (r1->get_num_parents() < SMALL_NUM_PARENTS) { TRACE("is_ext_diseq", tout << mk_bounded_pp(n1->get_owner(), m_manager) << " " << mk_bounded_pp(n2->get_owner(), m_manager) << " " << depth << "\n";); - enode_vector::iterator it1 = r1->begin_parents(); - enode_vector::iterator end1 = r1->end_parents(); - for (; it1 != end1; ++it1) { - enode * p1 = *it1; + for (enode* p1 : r1->get_parents()) { if (!is_relevant(p1)) continue; if (p1->is_eq()) @@ -1254,10 +1239,7 @@ namespace smt { func_decl * f = p1->get_decl(); TRACE("is_ext_diseq", tout << "p1: " << mk_bounded_pp(p1->get_owner(), m_manager) << "\n";); unsigned num_args = p1->get_num_args(); - enode_vector::iterator it2 = r2->begin_parents(); - enode_vector::iterator end2 = r2->end_parents(); - for (; it2 != end2; ++it2) { - enode * p2 = *it2; + for (enode * p2 : r2->get_parents()) { if (!is_relevant(p2)) continue; if (p2->is_eq()) @@ -1295,10 +1277,7 @@ namespace smt { } almost_cg_table & table = *(m_almost_cg_tables[depth]); table.reset(r1, r2); - enode_vector::iterator it1 = r1->begin_parents(); - enode_vector::iterator end1 = r1->end_parents(); - for (; it1 != end1; ++it1) { - enode * p1 = *it1; + for (enode* p1 : r1->get_parents()) { if (!is_relevant(p1)) continue; if (p1->is_eq()) @@ -1309,10 +1288,7 @@ namespace smt { } if (table.empty()) return false; - enode_vector::iterator it2 = r2->begin_parents(); - enode_vector::iterator end2 = r2->end_parents(); - for (; it2 != end2; ++it2) { - enode * p2 = *it2; + for (enode * p2 : r2->get_parents()) { if (!is_relevant(p2)) continue; if (p2->is_eq()) @@ -1519,10 +1495,7 @@ namespace smt { } TRACE("push_new_th_diseqs", tout << "#" << r->get_owner_id() << " v" << v << "\n";); theory_id th_id = th->get_id(); - enode_vector::iterator it = r->begin_parents(); - enode_vector::iterator end = r->end_parents(); - for (; it != end; ++it) { - enode * parent = *it; + for (enode * parent : r->get_parents()) { CTRACE("parent_bug", parent == 0, tout << "#" << r->get_owner_id() << ", num_parents: " << r->get_num_parents() << "\n"; display(tout);); if (parent->is_eq()) { bool_var bv = get_bool_var_of_id(parent->get_owner_id()); @@ -2197,9 +2170,7 @@ namespace smt { TRACE("cached_generation", tout << "caching: #" << n->get_id() << " " << e->get_generation() << "\n";); m_cached_generation.insert(n, e->get_generation()); } - unsigned num_args = to_app(n)->get_num_args(); - for (unsigned i = 0; i < num_args; i++) { - expr * arg = to_app(n)->get_arg(i); + for (expr * arg : *to_app(n)) { if (is_app(arg) || is_quantifier(arg)) todo.push_back(arg); } @@ -4228,10 +4199,7 @@ namespace smt { theory_var_list * l = n->get_th_var_list(); theory_id th_id = l->get_th_id(); - enode_vector::const_iterator it = n->begin_parents(); - enode_vector::const_iterator end = n->end_parents(); - for (; it != end; ++it) { - enode * parent = *it; + for (enode* parent : n->get_parents()) { family_id fid = parent->get_owner()->get_family_id(); if (fid != th_id && fid != m_manager.get_basic_family_id()) { TRACE("is_shared", tout << mk_pp(n->get_owner(), m_manager) << "\nis shared because of:\n" << mk_pp(parent->get_owner(), m_manager) << "\n";); diff --git a/src/smt/smt_context_pp.cpp b/src/smt/smt_context_pp.cpp index f4f56df5d..615cd2512 100644 --- a/src/smt/smt_context_pp.cpp +++ b/src/smt/smt_context_pp.cpp @@ -341,10 +341,7 @@ namespace smt { } void context::display_parent_eqs(std::ostream & out, enode * n) const { - enode_vector::iterator it = n->begin_parents(); - enode_vector::iterator end = n->end_parents(); - for (; it != end; ++it) { - enode * parent = *it; + for (enode* parent : n->get_parents()) { if (parent->is_eq()) display_eq_detail(out, parent); } diff --git a/src/smt/smt_enode.h b/src/smt/smt_enode.h index df6309424..6c8d156b4 100644 --- a/src/smt/smt_enode.h +++ b/src/smt/smt_enode.h @@ -216,15 +216,28 @@ namespace smt { return m_args; } - class args { + class const_args { enode const& n; public: - args(enode const& n):n(n) {} - args(enode const* n):n(*n) {} - enode_vector::const_iterator begin() const { return n.get_args(); } - enode_vector::const_iterator end() const { return n.get_args() + n.get_num_args(); } + const_args(enode const& n):n(n) {} + const_args(enode const* n):n(*n) {} + enode_vector::const_iterator begin() const { return n.m_args; } + enode_vector::const_iterator end() const { return n.m_args + n.get_num_args(); } }; + class args { + enode & n; + public: + args(enode & n):n(n) {} + args(enode * n):n(*n) {} + enode_vector::iterator begin() const { return n.m_args; } + enode_vector::iterator end() const { return n.m_args + n.get_num_args(); } + }; + + const_args get_const_args() const { return const_args(this); } + + // args get_args() { return args(this); } + // unsigned get_id() const { // return m_id; // } @@ -294,15 +307,27 @@ namespace smt { return m_commutative; } - class parents { + class const_parents { enode const& n; public: - parents(enode const& _n):n(_n) {} - parents(enode const* _n):n(*_n) {} + const_parents(enode const& _n):n(_n) {} + const_parents(enode const* _n):n(*_n) {} enode_vector::const_iterator begin() const { return n.begin_parents(); } enode_vector::const_iterator end() const { return n.end_parents(); } }; + class parents { + enode& n; + public: + parents(enode & _n):n(_n) {} + parents(enode * _n):n(*_n) {} + enode_vector::iterator begin() const { return n.begin_parents(); } + enode_vector::iterator end() const { return n.end_parents(); } + }; + + parents get_parents() { return parents(this); } + + const_parents get_const_parents() const { return const_parents(this); } unsigned get_num_parents() const { return m_parents.size(); From 78b9f0686a8fa8c03e7a9d6f17794fdb73d05ce2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 1 May 2018 07:43:29 -0700 Subject: [PATCH 549/637] 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 550/637] 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 551/637] 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 552/637] 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 553/637] 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 554/637] 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 555/637] 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 556/637] 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 557/637] 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 558/637] 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 559/637] 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 560/637] 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 561/637] 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 562/637] fix build Signed-off-by: Nikolaj Bjorner --- src/util/mpq.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/util/mpq.h b/src/util/mpq.h index 16b57237e..010bb2c8a 100644 --- a/src/util/mpq.h +++ b/src/util/mpq.h @@ -501,6 +501,8 @@ public: void machine_div(mpz const & a, mpz const & b, mpz & c) { mpz_manager::machine_div(a, b, c); } + void machine_div_rem(mpz const & a, mpz const & b, mpz & c, mpz& d) { mpz_manager::machine_div_rem(a, b, c, d); } + void div(mpz const & a, mpz const & b, mpz & c) { mpz_manager::div(a, b, c); } void rat_div(mpz const & a, mpz const & b, mpq & c) { From 6bff15e12efbadeb553dcc80bf1b5f5e3bd33536 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 2 May 2018 10:38:46 -0700 Subject: [PATCH 563/637] fix #1609 Signed-off-by: Nikolaj Bjorner --- src/api/python/z3/z3.py | 8 ++++++++ src/smt/smt_solver.cpp | 11 +++++++---- src/solver/combined_solver.cpp | 4 +++- 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index 36283356d..3eaf20763 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -9826,6 +9826,14 @@ def String(name, ctx=None): ctx = _get_ctx(ctx) return SeqRef(Z3_mk_const(ctx.ref(), to_symbol(name, ctx), StringSort(ctx).ast), ctx) +def SubString(s, offset, length): + """Extract substring or subsequence starting at offset""" + return Extract(s, offset, length) + +def SubSeq(s, offset, length): + """Extract substring or subsequence starting at offset""" + return Extract(s, offset, length) + def Strings(names, ctx=None): """Return a tuple of String constants. """ ctx = _get_ctx(ctx) diff --git a/src/smt/smt_solver.cpp b/src/smt/smt_solver.cpp index d813f249a..a5f9e0c34 100644 --- a/src/smt/smt_solver.cpp +++ b/src/smt/smt_solver.cpp @@ -61,10 +61,13 @@ namespace smt { smt_solver * result = alloc(smt_solver, m, p, m_logic); smt::kernel::copy(m_context, result->m_context); - for (auto & kv : m_name2assertion) - result->m_name2assertion.insert(translator(kv.m_key), - translator(kv.m_value)); - + for (auto & kv : m_name2assertion) { + expr* val = translator(kv.m_value); + expr* t = translator(kv.m_key); + result->m_name2assertion.insert(t, val); + result->solver_na2as::assert_expr(val, t); + m.inc_ref(val); + } return result; } diff --git a/src/solver/combined_solver.cpp b/src/solver/combined_solver.cpp index 9d2d8aa46..6469ab065 100644 --- a/src/solver/combined_solver.cpp +++ b/src/solver/combined_solver.cpp @@ -59,7 +59,8 @@ private: ref m_solver2; // We delay sending assertions to solver 2 // This is relevant for big benchmarks that are meant to be solved - // by a non-incremental solver. + // by a non-incremental solver. ); + bool m_solver2_initialized; bool m_ignore_solver1; @@ -137,6 +138,7 @@ public: } solver* translate(ast_manager& m, params_ref const& p) override { + TRACE("solver", tout << "translate\n";); solver* s1 = m_solver1->translate(m, p); solver* s2 = m_solver2->translate(m, p); combined_solver* r = alloc(combined_solver, s1, s2, p); From 1fc1249befedf49347cc606101af0021a2e0ff7c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 2 May 2018 11:28:13 -0700 Subject: [PATCH 564/637] 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 565/637] 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 566/637] 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 567/637] fix java Signed-off-by: Nikolaj Bjorner --- examples/java/JavaExample.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/examples/java/JavaExample.java b/examples/java/JavaExample.java index 7b8902768..90460de05 100644 --- a/examples/java/JavaExample.java +++ b/examples/java/JavaExample.java @@ -167,12 +167,12 @@ class JavaExample "function must be binary, and argument types must be equal to return type"); } - String bench = "(benchmark comm :formula (forall (x " + t.getName() + String bench = "(assert (forall (x " + t.getName() + ") (y " + t.getName() + ") (= (" + f.getName() + " x y) (" + f.getName() + " y x))))"; return ctx.parseSMTLIB2String(bench, new Symbol[] { t.getName() }, new Sort[] { t }, new Symbol[] { f.getName() }, - new FuncDecl[] { f }); + new FuncDecl[] { f })[0]; } // / "Hello world" example: create a Z3 logical context, and delete it. @@ -1041,7 +1041,7 @@ class JavaExample HashMap cfg = new HashMap(); cfg.put("model", "true"); Context ctx = new Context(cfg); - Expr a = ctx.parseSMTLIB2File(filename, null, null, null, null); + Expr a = ctx.MkAnd(ctx.parseSMTLIB2File(filename, null, null, null, null)); long t_diff = ((new Date()).getTime() - before.getTime()) / 1000; @@ -1445,7 +1445,7 @@ class JavaExample BoolExpr f = ctx.parseSMTLIB2String( "(declare-const x Int) (declare-const y Int) (assert (and (> x y) (> x 0)))", - null, null, null, null); + null, null, null, null)[0]; System.out.println("formula " + f); @SuppressWarnings("unused") @@ -1465,7 +1465,7 @@ class JavaExample FuncDecl[] decls = new FuncDecl[] { a, b }; BoolExpr f = ctx.parseSMTLIB2String("(assert (> a b))", null, null, - declNames, decls); + declNames, decls)[0]; System.out.println("formula: " + f); check(ctx, f, Status.SATISFIABLE); } @@ -1486,7 +1486,7 @@ class JavaExample BoolExpr thm = ctx.parseSMTLIB2String( "(assert (forall ((x Int) (y Int)) (=> (= x y) (= (gg x 0) (gg 0 y)))))", null, null, new Symbol[] { ctx.mkSymbol("gg") }, - new FuncDecl[] { g }); + new FuncDecl[] { g })[0]; System.out.println("formula: " + thm); prove(ctx, thm, false, ca); } @@ -1508,7 +1508,7 @@ class JavaExample * parenthesis */ "(declare-const x Int (declare-const y Int)) (assert (> x y))", - null, null, null, null); + null, null, null, null)[0]; } catch (Z3Exception e) { System.out.println("Z3 error: " + e); From c279fd9f2e7409842d25f0995cbfa381d1683548 Mon Sep 17 00:00:00 2001 From: Carsten Varming Date: Thu, 3 May 2018 03:06:58 +0000 Subject: [PATCH 568/637] Specify encoding of source files in mk_util.py --- scripts/mk_util.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 99de61703..3e40187c3 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -780,7 +780,7 @@ def extract_c_includes(fname): # We should generate and error for any occurrence of #include that does not match the previous pattern. non_std_inc_pat = re.compile(".*#include.*") - f = open(fname, 'r') + f = open(fname, encoding='utf-8', mode='r') linenum = 1 for line in f: m1 = std_inc_pat.match(line) From e98c808f47e767f498d7b9325a59cb46de3d020d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 3 May 2018 03:18:29 -0700 Subject: [PATCH 569/637] fixing compilation errors Signed-off-by: Nikolaj Bjorner --- examples/dotnet/Program.cs | 5 +---- examples/java/JavaExample.java | 2 +- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/examples/dotnet/Program.cs b/examples/dotnet/Program.cs index 0c2ce66c8..06cc66150 100644 --- a/examples/dotnet/Program.cs +++ b/examples/dotnet/Program.cs @@ -611,7 +611,6 @@ namespace test_mapi Expr f_x = ctx.MkApp(f, x); Expr f_y = ctx.MkApp(f, y); Expr g_y = ctx.MkApp(g, y); - Pattern[] pats = new Pattern[] { ctx.MkPattern(new Expr[] { f_x, g_y }) }; Expr[] no_pats = new Expr[] { f_y }; Expr[] bound = new Expr[2] { x, y }; Expr body = ctx.MkAnd(ctx.MkEq(f_x, f_y), ctx.MkEq(f_y, g_y)); @@ -628,7 +627,6 @@ namespace test_mapi Expr f_x = ctx.MkApp(f, x); Expr f_y = ctx.MkApp(f, y); Expr g_y = ctx.MkApp(g, y); - Pattern[] pats = new Pattern[] { ctx.MkPattern(new Expr[] { f_x, g_y }) }; Expr[] no_pats = new Expr[] { f_y }; Symbol[] names = new Symbol[] { ctx.MkSymbol("x"), ctx.MkSymbol("y") }; Sort[] sorts = new Sort[] { ctx.IntSort, ctx.IntSort }; @@ -729,7 +727,6 @@ namespace test_mapi { Console.WriteLine("BasicTests"); - Symbol qi = ctx.MkSymbol(1); Symbol fname = ctx.MkSymbol("f"); Symbol x = ctx.MkSymbol("x"); Symbol y = ctx.MkSymbol("y"); @@ -1319,7 +1316,7 @@ namespace test_mapi new Sort[] { int_type, int_type } // types of projection operators ); FuncDecl first = tuple.FieldDecls[0]; // declarations are for projections - FuncDecl second = tuple.FieldDecls[1]; + // FuncDecl second = tuple.FieldDecls[1]; Expr x = ctx.MkConst("x", int_type); Expr y = ctx.MkConst("y", int_type); Expr n1 = tuple.MkDecl[x, y]; diff --git a/examples/java/JavaExample.java b/examples/java/JavaExample.java index 90460de05..d4d8bb1ac 100644 --- a/examples/java/JavaExample.java +++ b/examples/java/JavaExample.java @@ -1508,7 +1508,7 @@ class JavaExample * parenthesis */ "(declare-const x Int (declare-const y Int)) (assert (> x y))", - null, null, null, null)[0]; + null, null, null, null); } catch (Z3Exception e) { System.out.println("Z3 error: " + e); From 6e03c7a54216f9da0a5cdbfb29a3a131a2b1ae09 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 3 May 2018 03:23:54 -0700 Subject: [PATCH 570/637] fix #1607 by filtering exceptions when the context is canceled Signed-off-by: Nikolaj Bjorner --- src/api/api_opt.cpp | 4 +++- src/api/api_solver.cpp | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/api/api_opt.cpp b/src/api/api_opt.cpp index 2712eef6f..7b8866b59 100644 --- a/src/api/api_opt.cpp +++ b/src/api/api_opt.cpp @@ -139,7 +139,9 @@ extern "C" { r = to_optimize_ptr(o)->optimize(); } catch (z3_exception& ex) { - mk_c(c)->handle_exception(ex); + if (!mk_c(c)->m().canceled()) { + mk_c(c)->handle_exception(ex); + } r = l_undef; } // to_optimize_ref(d).cleanup(); diff --git a/src/api/api_solver.cpp b/src/api/api_solver.cpp index 1b2e9dcc3..88ce8b144 100644 --- a/src/api/api_solver.cpp +++ b/src/api/api_solver.cpp @@ -361,7 +361,9 @@ extern "C" { } catch (z3_exception & ex) { to_solver_ref(s)->set_reason_unknown(eh); - mk_c(c)->handle_exception(ex); + if (!mk_c(c)->m().canceled()) { + mk_c(c)->handle_exception(ex); + } return Z3_L_UNDEF; } } From 8ecff9e5ee3323db1ccfc831c03bba92c7db7a06 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 3 May 2018 08:04:10 -0700 Subject: [PATCH 571/637] 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 572/637] 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 573/637] update model conversion Signed-off-by: Nikolaj Bjorner --- src/opt/opt_context.cpp | 5 +++-- src/sat/sat_solver/inc_sat_solver.cpp | 4 ++-- src/solver/tactic2solver.cpp | 4 +++- src/tactic/core/elim_uncnstr_tactic.cpp | 12 +++++------- 4 files changed, 13 insertions(+), 12 deletions(-) diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 237cd132f..e5f4bc133 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -1527,6 +1527,7 @@ namespace opt { } void context::validate_model() { + return; if (!gparams::get_ref().get_bool("model_validate", false)) return; expr_ref_vector fmls(m); get_hard_constraints(fmls); @@ -1536,9 +1537,9 @@ namespace opt { for (expr * f : fmls) { if (!mdl->eval(f, tmp) || !m.is_true(tmp)) { //IF_VERBOSE(0, m_fm->display(verbose_stream() << "fm\n")); - //IF_VERBOSE(0, m_model_converter->display(verbose_stream() << "mc\n")); + IF_VERBOSE(0, m_model_converter->display(verbose_stream() << "mc\n")); IF_VERBOSE(0, verbose_stream() << "Failed to validate " << mk_pp(f, m) << "\n" << tmp << "\n"); - //IF_VERBOSE(0, model_smt2_pp(verbose_stream(), m, *mdl, 0)); + IF_VERBOSE(0, model_smt2_pp(verbose_stream(), m, *mdl, 0)); IF_VERBOSE(11, verbose_stream() << to_string_internal() << "\n"); exit(0); } diff --git a/src/sat/sat_solver/inc_sat_solver.cpp b/src/sat/sat_solver/inc_sat_solver.cpp index 6107e5252..2e16bc33e 100644 --- a/src/sat/sat_solver/inc_sat_solver.cpp +++ b/src/sat/sat_solver/inc_sat_solver.cpp @@ -817,7 +817,7 @@ private: if (!gparams::get_ref().get_bool("model_validate", false)) return; - IF_VERBOSE(0, verbose_stream() << "Verifying solution\n";); + IF_VERBOSE(1, verbose_stream() << "Verifying solution\n";); model_evaluator eval(*mdl); eval.set_model_completion(false); bool all_true = true; @@ -842,7 +842,7 @@ private: IF_VERBOSE(0, for (auto const& kv : m_map) verbose_stream() << mk_pp(kv.m_key, m) << " |-> " << kv.m_value << "\n"); } else { - IF_VERBOSE(0, verbose_stream() << "solution verified\n"); + IF_VERBOSE(1, verbose_stream() << "solution verified\n"); // IF_VERBOSE(0, if (m_mcs.back()) m_mcs.back()->display(verbose_stream() << "mcs\n")); // IF_VERBOSE(0, if (m_sat_mc) m_sat_mc->display(verbose_stream() << "sat_mc\n")); // IF_VERBOSE(0, model_smt2_pp(verbose_stream() << "after\n", m, *mdl, 0);); diff --git a/src/solver/tactic2solver.cpp b/src/solver/tactic2solver.cpp index 8d7ab6a06..9118bb658 100644 --- a/src/solver/tactic2solver.cpp +++ b/src/solver/tactic2solver.cpp @@ -173,6 +173,7 @@ lbool tactic2solver::check_sat_core(unsigned num_assumptions, expr * const * ass break; } m_mc = g->mc(); + TRACE("tactic", if (m_mc) m_mc->display(tout);); } catch (z3_error & ex) { TRACE("tactic2solver", tout << "exception: " << ex.msg() << "\n";); @@ -225,8 +226,9 @@ void tactic2solver::get_unsat_core(ptr_vector & r) { } void tactic2solver::get_model_core(model_ref & m) { - if (m_result.get()) + if (m_result.get()) { m_result->get_model_core(m); + } } proof * tactic2solver::get_proof() { diff --git a/src/tactic/core/elim_uncnstr_tactic.cpp b/src/tactic/core/elim_uncnstr_tactic.cpp index 0f5e870f3..ce77f89d9 100644 --- a/src/tactic/core/elim_uncnstr_tactic.cpp +++ b/src/tactic/core/elim_uncnstr_tactic.cpp @@ -98,6 +98,7 @@ class elim_uncnstr_tactic : public tactic { TRACE("elim_uncnstr_bug", tout << "eliminating:\n" << mk_ismt2_pp(t, m()) << "\n";); TRACE("elim_uncnstr_bug_ll", tout << "eliminating:\n" << mk_bounded_pp(t, m()) << "\n";); m_fresh_vars.push_back(v); + if (m_mc) m_mc->hide(v); m_cache_domain.push_back(t); m_cache.insert(t, v); return true; @@ -856,15 +857,12 @@ class elim_uncnstr_tactic : public tactic { if (round == 0) { } else { - app_ref_vector & fresh_vars = m_rw->cfg().m_fresh_vars; - m_num_elim_apps = fresh_vars.size(); - if (m_mc.get()) { - for (app * f : fresh_vars) m_mc->hide(f); - g->add(m_mc.get()); - } + m_num_elim_apps = m_rw->cfg().m_fresh_vars.size(); + g->add(m_mc.get()); } + TRACE("elim_uncnstr", if (m_mc) m_mc->display(tout); else tout << "no mc\n";); m_mc = nullptr; - m_rw = nullptr; + m_rw = nullptr; result.push_back(g.get()); g->inc_depth(); return; From 888699548d4dea5b6729aa2b91a63ebb551df12d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 3 May 2018 11:59:49 -0700 Subject: [PATCH 574/637] Revert "Specify encoding of source files in mk_util.py" --- scripts/mk_util.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 3e40187c3..99de61703 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -780,7 +780,7 @@ def extract_c_includes(fname): # We should generate and error for any occurrence of #include that does not match the previous pattern. non_std_inc_pat = re.compile(".*#include.*") - f = open(fname, encoding='utf-8', mode='r') + f = open(fname, 'r') linenum = 1 for line in f: m1 = std_inc_pat.match(line) From 43403fafcd33ade94f66d13f1eb93a3b0ffe6b80 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 3 May 2018 13:23:59 -0700 Subject: [PATCH 575/637] 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 576/637] 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 577/637] fix if-def Signed-off-by: Nikolaj Bjorner --- src/test/sat_local_search.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/sat_local_search.cpp b/src/test/sat_local_search.cpp index 25fa59c95..4828046be 100644 --- a/src/test/sat_local_search.cpp +++ b/src/test/sat_local_search.cpp @@ -20,8 +20,6 @@ static bool build_instance(char const * filename, sat::solver& s, sat::local_sea #ifdef _WINDOWS int num_vars = 0, num_constraints = 0; sscanf_s(line, "%d %d", &num_vars, &num_constraints); -#else - return false; //std::cout << "number of variables: " << num_vars << '\n'; //std::cout << "number of constraints: " << num_constraints << '\n'; @@ -69,6 +67,8 @@ static bool build_instance(char const * filename, sat::solver& s, sat::local_sea infile.close(); return true; +#else + return false; #endif } From 2d5dd802386d78117d5ed9ddcbf8bc22ab3cb461 Mon Sep 17 00:00:00 2001 From: Daniel Schemmel Date: Mon, 7 May 2018 23:33:04 +0200 Subject: [PATCH 578/637] The Permutation Matrix' `values` function attempted an incorrect conversion. This causes compilation with GCC 8 to fail. I suspect it worked previously due to SFINAE. --- src/util/lp/permutation_matrix.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util/lp/permutation_matrix.h b/src/util/lp/permutation_matrix.h index 3c89b3646..8e664bba0 100644 --- a/src/util/lp/permutation_matrix.h +++ b/src/util/lp/permutation_matrix.h @@ -132,7 +132,7 @@ class permutation_matrix : public tail_matrix { unsigned size() const { return static_cast(m_rev.size()); } - unsigned * values() const { return m_permutation; } + unsigned * values() const { return m_permutation.c_ptr(); } void resize(unsigned size) { unsigned old_size = m_permutation.size(); From d097d90731a954f29937facbab9b1fcf17134363 Mon Sep 17 00:00:00 2001 From: corrodedHash Date: Tue, 8 May 2018 19:26:14 +0200 Subject: [PATCH 579/637] Fixed Segfault when failing to load datalog file --- src/muz/fp/datalog_parser.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/muz/fp/datalog_parser.cpp b/src/muz/fp/datalog_parser.cpp index dddca492b..a23d654b0 100644 --- a/src/muz/fp/datalog_parser.cpp +++ b/src/muz/fp/datalog_parser.cpp @@ -108,7 +108,9 @@ public: #endif } ~line_reader() { - fclose(m_file); + if (m_file != nullptr){ + fclose(m_file); + } } bool operator()() { return m_ok; } From 41072e3125f492ef5e1b47f08bfefbde9c2f74ff Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 8 May 2018 19:09:59 +0100 Subject: [PATCH 580/637] 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 581/637] 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 582/637] 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 583/637] 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 584/637] 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 585/637] 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 586/637] 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 587/637] 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 588/637] tune for unit test, delay initialize re-solver Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/seq_rewriter.h | 1 + src/smt/theory_seq.cpp | 6 ++++-- src/test/get_implied_equalities.cpp | 6 +++--- src/test/sat_local_search.cpp | 2 +- 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/ast/rewriter/seq_rewriter.h b/src/ast/rewriter/seq_rewriter.h index 95b043bd7..c96096c65 100644 --- a/src/ast/rewriter/seq_rewriter.h +++ b/src/ast/rewriter/seq_rewriter.h @@ -89,6 +89,7 @@ public: ~re2automaton(); eautomaton* operator()(expr* e); void set_solver(expr_solver* solver); + bool has_solver() const { return m_solver; } eautomaton* mk_product(eautomaton *a1, eautomaton *a2); }; diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp index 95f804863..b704795b2 100644 --- a/src/smt/theory_seq.cpp +++ b/src/smt/theory_seq.cpp @@ -238,8 +238,7 @@ theory_seq::~theory_seq() { } void theory_seq::init(context* ctx) { - theory::init(ctx); - m_mk_aut.set_solver(alloc(seq_expr_solver, m, get_context().get_fparams())); + theory::init(ctx); } final_check_status theory_seq::final_check_eh() { @@ -4168,6 +4167,9 @@ eautomaton* theory_seq::get_automaton(expr* re) { if (m_re2aut.find(re, result)) { return result; } + if (!m_mk_aut.has_solver()) { + m_mk_aut.set_solver(alloc(seq_expr_solver, m, get_context().get_fparams())); + } result = m_mk_aut(re); if (result) { display_expr disp(m); diff --git a/src/test/get_implied_equalities.cpp b/src/test/get_implied_equalities.cpp index 952fb121a..dae182a34 100644 --- a/src/test/get_implied_equalities.cpp +++ b/src/test/get_implied_equalities.cpp @@ -75,9 +75,9 @@ static void tst_get_implied_equalities1() { } static void tst_get_implied_equalities2() { - enable_trace("after_search"); - enable_trace("get_implied_equalities"); - enable_trace("implied_equalities"); + //enable_trace("after_search"); + //enable_trace("get_implied_equalities"); + //enable_trace("implied_equalities"); Z3_config cfg = Z3_mk_config(); Z3_context ctx = Z3_mk_context(cfg); Z3_del_config(cfg); diff --git a/src/test/sat_local_search.cpp b/src/test/sat_local_search.cpp index 4828046be..1116c5420 100644 --- a/src/test/sat_local_search.cpp +++ b/src/test/sat_local_search.cpp @@ -7,7 +7,6 @@ static bool build_instance(char const * filename, sat::solver& s, sat::local_search& local_search) { char line[16383]; - int cur_term; // for temperally storage std::ifstream infile(filename); @@ -18,6 +17,7 @@ static bool build_instance(char const * filename, sat::solver& s, sat::local_sea } infile.getline(line, 16383); #ifdef _WINDOWS + int cur_term; int num_vars = 0, num_constraints = 0; sscanf_s(line, "%d %d", &num_vars, &num_constraints); //std::cout << "number of variables: " << num_vars << '\n'; From c198b12743c10934c15d7574b13634f0f0d51b21 Mon Sep 17 00:00:00 2001 From: Sapan Bhatia Date: Tue, 15 May 2018 04:55:57 +0530 Subject: [PATCH 589/637] Big_int is no longer a part of OCaml's standard library and must be included via the num package: https://github.com/ocaml/num --- scripts/mk_util.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 99de61703..aab4bcb21 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -1932,8 +1932,14 @@ class MLComponent(Component): OCAML_FLAGS = '' if DEBUG_MODE: OCAML_FLAGS += '-g' - OCAMLCF = OCAMLC + ' ' + OCAML_FLAGS - OCAMLOPTF = OCAMLOPT + ' ' + OCAML_FLAGS + + if OCAMLFIND: + # Load Big_int, which is no longer part of the standard library, via the num package: https://github.com/ocaml/num + OCAMLCF = OCAMLFIND + ' ' + 'ocamlc -package num' + ' ' + OCAML_FLAGS + OCAMLOPTF = OCAMLFIND + ' ' + 'ocamlopt -package num' + ' ' + OCAML_FLAGS + else: + OCAMLCF = OCAMLC + ' ' + OCAML_FLAGS + OCAMLOPTF = OCAMLOPT + ' ' + OCAML_FLAGS src_dir = self.to_src_dir mk_dir(os.path.join(BUILD_DIR, self.sub_dir)) From dfeb4b5235f4cc42062011632c97d6ab095593a3 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 17 May 2018 16:45:12 -0700 Subject: [PATCH 590/637] updated sat state Signed-off-by: Nikolaj Bjorner --- src/sat/sat_simplifier.cpp | 3 --- src/sat/sat_solver.cpp | 5 ++--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/sat/sat_simplifier.cpp b/src/sat/sat_simplifier.cpp index efdf8a39a..4fd9b08be 100644 --- a/src/sat/sat_simplifier.cpp +++ b/src/sat/sat_simplifier.cpp @@ -192,8 +192,6 @@ namespace sat { return; if (!m_subsumption && !bce_enabled() && !bca_enabled() && !elim_vars_enabled()) return; - - // solver::scoped_disable_checkpoint _scoped_disable_checkpoint(s); initialize(); @@ -257,7 +255,6 @@ namespace sat { TRACE("sat_simplifier", s.display(tout); tout << "model_converter:\n"; s.m_mc.display(tout);); finalize(); - } /** diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index c55383a57..09fe08f18 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -530,7 +530,6 @@ namespace sat { } void solver::defrag_clauses() { - return; if (memory_pressure()) return; pop(scope_lvl()); IF_VERBOSE(1, verbose_stream() << "(sat-defrag)\n"); @@ -802,9 +801,9 @@ namespace sat { if (m_config.m_propagate_prefetch) { #if defined(__GLUC__) || defined(__clang__) - __builtin_prefetch((const char*)(&*(m_watches[l.index()].c_ptr()))); + __builtin_prefetch((const char*)((m_watches[l.index()].c_ptr()))); #else - _mm_prefetch((const char*)(&*(m_watches[l.index()].c_ptr())), _MM_HINT_T1); + _mm_prefetch((const char*)((m_watches[l.index()].c_ptr())), _MM_HINT_T1); #endif } From e5b14ab6825f48fffd09c758066b6a0b7b930f2f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 18 May 2018 14:03:32 -0700 Subject: [PATCH 591/637] fix #1625 Signed-off-by: Nikolaj Bjorner --- src/api/c++/z3++.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index b81927474..4bb1acded 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -2292,6 +2292,7 @@ namespace z3 { class optimize : public object { Z3_optimize m_opt; + public: class handle { unsigned m_h; @@ -2300,6 +2301,17 @@ namespace z3 { unsigned h() const { return m_h; } }; optimize(context& c):object(c) { m_opt = Z3_mk_optimize(c); Z3_optimize_inc_ref(c, m_opt); } + optimize(optimize& o):object(c) { + Z3_optimize_inc_ref(o.ctx(), o.m_opt); + m_opt = o.m_opt; + } + optimize& operator=(optimize const& o) { + Z3_optimize_inc_rec(o.ctx(), o.m_opt); + Z3_optimize_dec_ref(ctx(), m_opt); + m_opt = o.m_opt; + m_ctx = o.m_ctx; + return *this; + } ~optimize() { Z3_optimize_dec_ref(ctx(), m_opt); } operator Z3_optimize() const { return m_opt; } void add(expr const& e) { From 925867dc3ee4e4f0085d07d912cd9f7b7b904fa9 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 18 May 2018 14:14:00 -0700 Subject: [PATCH 592/637] fix #1621 Signed-off-by: Nikolaj Bjorner --- src/ast/ast_smt2_pp.cpp | 2 +- src/util/smt2_util.cpp | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/ast/ast_smt2_pp.cpp b/src/ast/ast_smt2_pp.cpp index aeaebc6bf..ade12de62 100644 --- a/src/ast/ast_smt2_pp.cpp +++ b/src/ast/ast_smt2_pp.cpp @@ -912,7 +912,7 @@ class smt2_printer { var_name = mk_smt2_quoted_symbol (*it); } else { - var_name = it->str ();\ + var_name = it->str (); } buf.push_back(mk_seq1(m(), fs, fs+1, f2f(), var_name.c_str ())); } diff --git a/src/util/smt2_util.cpp b/src/util/smt2_util.cpp index 8358c67ac..a218f0c27 100644 --- a/src/util/smt2_util.cpp +++ b/src/util/smt2_util.cpp @@ -34,6 +34,12 @@ bool is_smt2_quoted_symbol(char const * s) { if ('0' <= s[0] && s[0] <= '9') return true; unsigned len = static_cast(strlen(s)); + if (len > 2 && s[0] == '|' && s[len-1] == '|') { + for (unsigned i = 1; i + 1 < len; i++) + if (!is_smt2_simple_symbol_char(s[i])) + return true; + return false; + } for (unsigned i = 0; i < len; i++) if (!is_smt2_simple_symbol_char(s[i])) return true; From 83023603213157c06ad9eaf77b4f5eb96262bd1c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 18 May 2018 14:24:12 -0700 Subject: [PATCH 593/637] fix #1625 Signed-off-by: Nikolaj Bjorner --- src/api/c++/z3++.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index 4bb1acded..903086daa 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -2301,12 +2301,12 @@ namespace z3 { unsigned h() const { return m_h; } }; optimize(context& c):object(c) { m_opt = Z3_mk_optimize(c); Z3_optimize_inc_ref(c, m_opt); } - optimize(optimize& o):object(c) { + optimize(optimize& o):object(o) { Z3_optimize_inc_ref(o.ctx(), o.m_opt); m_opt = o.m_opt; } optimize& operator=(optimize const& o) { - Z3_optimize_inc_rec(o.ctx(), o.m_opt); + Z3_optimize_inc_ref(o.ctx(), o.m_opt); Z3_optimize_dec_ref(ctx(), m_opt); m_opt = o.m_opt; m_ctx = o.m_ctx; From d462ed3f0057a24fc1872a6a7a1e6ead34c970e0 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 18 May 2018 14:30:27 -0700 Subject: [PATCH 594/637] fix #1621 Signed-off-by: Nikolaj Bjorner --- src/util/smt2_util.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/util/smt2_util.cpp b/src/util/smt2_util.cpp index a218f0c27..365d8fe70 100644 --- a/src/util/smt2_util.cpp +++ b/src/util/smt2_util.cpp @@ -34,10 +34,14 @@ bool is_smt2_quoted_symbol(char const * s) { if ('0' <= s[0] && s[0] <= '9') return true; unsigned len = static_cast(strlen(s)); - if (len > 2 && s[0] == '|' && s[len-1] == '|') { - for (unsigned i = 1; i + 1 < len; i++) - if (!is_smt2_simple_symbol_char(s[i])) + if (len >= 2 && s[0] == '|' && s[len-1] == '|') { + for (unsigned i = 1; i + 1 < len; i++) { + if (s[i] == '\\' && i + 2 < len && (s[i+1] == '\\' || s[i+1] == '|')) { + i++; + } + else if (s[i] == '\\' || s[i] == '|') return true; + } return false; } for (unsigned i = 0; i < len; i++) From 1cc4a4ccc5ac7eb8a9e669ace3db89b9e0d607ff Mon Sep 17 00:00:00 2001 From: Daniel Schemmel Date: Sat, 19 May 2018 02:56:46 +0200 Subject: [PATCH 595/637] remove unused constructor that would construct lar_constraint in an partly initialized state. Fixes: variable may be used uninitialized --- src/util/lp/lar_constraints.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/util/lp/lar_constraints.h b/src/util/lp/lar_constraints.h index 9d3a0e0aa..5c33db8c6 100644 --- a/src/util/lp/lar_constraints.h +++ b/src/util/lp/lar_constraints.h @@ -84,7 +84,6 @@ struct lar_term_constraint: public lar_base_constraint { class lar_constraint : public lar_base_constraint { public: vector> m_coeffs; - lar_constraint() {} lar_constraint(const vector> & left_side, lconstraint_kind kind, const mpq & right_side) : lar_base_constraint(kind, right_side), m_coeffs(left_side) {} From 5134c168332147029a4d0fdb7cf945e0be18354f Mon Sep 17 00:00:00 2001 From: Daniel Schemmel Date: Sat, 19 May 2018 03:19:57 +0200 Subject: [PATCH 596/637] NULL-initialize pointers to help GCC static analyzer Fixes: variable may be used uninitialized --- src/ast/rewriter/poly_rewriter_def.h | 3 ++- src/ast/rewriter/rewriter_def.h | 6 +++--- src/smt/theory_str.cpp | 20 ++++++++++---------- src/tactic/core/solve_eqs_tactic.cpp | 4 ++-- 4 files changed, 17 insertions(+), 16 deletions(-) diff --git a/src/ast/rewriter/poly_rewriter_def.h b/src/ast/rewriter/poly_rewriter_def.h index f27c9ffcf..d65960857 100644 --- a/src/ast/rewriter/poly_rewriter_def.h +++ b/src/ast/rewriter/poly_rewriter_def.h @@ -431,7 +431,8 @@ struct poly_rewriter::hoist_cmul_lt { hoist_cmul_lt(poly_rewriter & r):m_r(r) {} bool operator()(expr * t1, expr * t2) const { - expr * pp1, * pp2; + expr * pp1 = nullptr; + expr * pp2 = nullptr; numeral c1, c2; bool is_mul1 = m_r.is_mul(t1, c1, pp1); bool is_mul2 = m_r.is_mul(t2, c2, pp2); diff --git a/src/ast/rewriter/rewriter_def.h b/src/ast/rewriter/rewriter_def.h index dfb6542d6..4d4c4f708 100644 --- a/src/ast/rewriter/rewriter_def.h +++ b/src/ast/rewriter/rewriter_def.h @@ -336,9 +336,9 @@ void rewriter_tpl::process_app(app * t, frame & fr) { UNREACHABLE(); } // TODO: add rewrite rules support - expr * def; - proof * def_pr; - quantifier * def_q; + expr * def = nullptr; + proof * def_pr = nullptr; + quantifier * def_q = nullptr; // When get_macro succeeds, then // we know that: // forall X. f(X) = def[X] diff --git a/src/smt/theory_str.cpp b/src/smt/theory_str.cpp index 126594b06..0c4d11420 100644 --- a/src/smt/theory_str.cpp +++ b/src/smt/theory_str.cpp @@ -1423,9 +1423,9 @@ namespace smt { // len(hd) = i // str.indexof(tl, N, 0) - expr * H; // "haystack" - expr * N; // "needle" - expr * i; // start index + expr * H = nullptr; // "haystack" + expr * N = nullptr; // "needle" + expr * i = nullptr; // start index u.str.is_index(e, H, N, i); expr_ref minus_one(m_autil.mk_numeral(rational::minus_one(), true), m); @@ -6951,8 +6951,8 @@ namespace smt { ast_manager & m = get_manager(); expr_ref_vector rhs(m); - expr * str; - expr * re; + expr * str = nullptr; + expr * re = nullptr; u.str.is_in_re(str_in_re, str, re); expr_ref strlen(mk_strlen(str), m); @@ -9929,8 +9929,8 @@ namespace smt { bool regex_axiom_add = false; for (obj_hashtable::iterator it = regex_terms.begin(); it != regex_terms.end(); ++it) { expr * str_in_re = *it; - expr * str; - expr * re; + expr * str = nullptr; + expr * re = nullptr; u.str.is_in_re(str_in_re, str, re); lbool current_assignment = ctx.get_assignment(str_in_re); TRACE("str", tout << "regex term: " << mk_pp(str, m) << " in " << mk_pp(re, m) << " : " << current_assignment << std::endl;); @@ -9944,7 +9944,7 @@ namespace smt { if (regex_term_to_length_constraint.contains(str_in_re)) { // use existing length constraint - expr * top_level_length_constraint; + expr * top_level_length_constraint = nullptr; regex_term_to_length_constraint.find(str_in_re, top_level_length_constraint); ptr_vector extra_length_vars; @@ -10473,8 +10473,8 @@ namespace smt { // that's consistent with the current length information for (ptr_vector::iterator term_it = str_in_re_terms.begin(); term_it != str_in_re_terms.end(); ++term_it) { - expr * _unused; - expr * re; + expr * _unused = nullptr; + expr * re = nullptr; SASSERT(u.str.is_in_re(*term_it)); u.str.is_in_re(*term_it, _unused, re); diff --git a/src/tactic/core/solve_eqs_tactic.cpp b/src/tactic/core/solve_eqs_tactic.cpp index 9253b7172..c95a79ff7 100644 --- a/src/tactic/core/solve_eqs_tactic.cpp +++ b/src/tactic/core/solve_eqs_tactic.cpp @@ -263,8 +263,8 @@ class solve_eqs_tactic : public tactic { bool solve_arith_core(app * lhs, expr * rhs, expr * eq, app_ref & var, expr_ref & def, proof_ref & pr) { SASSERT(m_a_util.is_add(lhs)); bool is_int = m_a_util.is_int(lhs); - expr * a; - expr * v; + expr * a = nullptr; + expr * v = nullptr; rational a_val; unsigned num = lhs->get_num_args(); unsigned i; From f02d031d119c413cebd3432a644206caed0459e6 Mon Sep 17 00:00:00 2001 From: Daniel Schemmel Date: Sat, 19 May 2018 03:47:11 +0200 Subject: [PATCH 597/637] As of GCC8, the throw by value, catch by reference idiom is enforced via -Wcatch-value --- src/cmd_context/basic_cmds.cpp | 4 ++-- src/interp/iz3translate_direct.cpp | 8 ++++---- src/math/subpaving/subpaving.cpp | 12 ++++++------ src/math/subpaving/subpaving_t_def.h | 4 ++-- src/shell/datalog_frontend.cpp | 2 +- src/tactic/aig/aig.cpp | 2 +- src/test/mpff.cpp | 6 +++--- 7 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/cmd_context/basic_cmds.cpp b/src/cmd_context/basic_cmds.cpp index 4e8806d62..56a354ee8 100644 --- a/src/cmd_context/basic_cmds.cpp +++ b/src/cmd_context/basic_cmds.cpp @@ -395,7 +395,7 @@ class set_option_cmd : public set_get_option_cmd { env_params::updt_params(); ctx.global_params_updated(); } - catch (gparams::exception ex) { + catch (const gparams::exception & ex) { throw cmd_exception(ex.msg()); } } @@ -620,7 +620,7 @@ public: try { ctx.regular_stream() << gparams::get_value(opt) << std::endl; } - catch (gparams::exception ex) { + catch (const gparams::exception & ex) { ctx.print_unsupported(opt, m_line, m_pos); } } diff --git a/src/interp/iz3translate_direct.cpp b/src/interp/iz3translate_direct.cpp index 8c2016149..9efb1a383 100644 --- a/src/interp/iz3translate_direct.cpp +++ b/src/interp/iz3translate_direct.cpp @@ -912,7 +912,7 @@ public: if(!add_local_antes(arg, hyps, dk == PR_UNIT_RESOLUTION && i == 0)) return false; } - catch (non_lit_local_ante) { + catch (const non_lit_local_ante &) { std::cout << "\n"; show_step(proof); show(conc(proof)); @@ -1138,7 +1138,7 @@ public: try { res = iproof->make_resolution(pnode,neg,pos); } - catch (const iz3proof::proof_error){ + catch (const iz3proof::proof_error &){ std::cout << "\nresolution error in theory lemma\n"; std::cout << "lits:\n"; for(unsigned j = 0; j < lits.size(); j++) @@ -1212,7 +1212,7 @@ public: try { res = iproof->make_resolution(pnode,neg,pos); } - catch (const iz3proof::proof_error){ + catch (const iz3proof::proof_error &){ std::cout << "\nresolution error in theory lemma\n"; std::cout << "lits:\n"; for(unsigned j = 0; j < lits.size(); j++) @@ -1418,7 +1418,7 @@ public: try { return iproof->make_resolution(pnode,neg,pos); } - catch (const iz3proof::proof_error){ + catch (const iz3proof::proof_error &){ std::cout << "resolution error in unit_resolution, position" << position << "\n"; show_step(proof); throw invalid_lemma(); diff --git a/src/math/subpaving/subpaving.cpp b/src/math/subpaving/subpaving.cpp index 16a9a9a9e..c43b74f0d 100644 --- a/src/math/subpaving/subpaving.cpp +++ b/src/math/subpaving/subpaving.cpp @@ -121,7 +121,7 @@ namespace subpaving { int2mpf(c, m_c); return m_ctx.mk_sum(m_c, sz, m_as.c_ptr(), xs); } - catch (f2n::exception) { + catch (const f2n::exception &) { throw subpaving::exception(); } } @@ -135,7 +135,7 @@ namespace subpaving { m.set(m_c, k); return reinterpret_cast(m_ctx.mk_ineq(x, m_c, lower, open)); } - catch (f2n::exception) { + catch (const f2n::exception &) { throw subpaving::exception(); } } @@ -178,7 +178,7 @@ namespace subpaving { int2hwf(c, m_c); return m_ctx.mk_sum(m_c, sz, m_as.c_ptr(), xs); } - catch (f2n::exception) { + catch (const f2n::exception &) { throw subpaving::exception(); } } @@ -192,7 +192,7 @@ namespace subpaving { m.set(m_c, k); return reinterpret_cast(m_ctx.mk_ineq(x, m_c, lower, open)); } - catch (f2n::exception) { + catch (const f2n::exception &) { throw subpaving::exception(); } } @@ -236,7 +236,7 @@ namespace subpaving { int2fpoint(c, m_c); return this->m_ctx.mk_sum(m_c, sz, m_as.c_ptr(), xs); } - catch (typename context_fpoint::numeral_manager::exception) { + catch (const typename context_fpoint::numeral_manager::exception &) { throw subpaving::exception(); } } @@ -251,7 +251,7 @@ namespace subpaving { m.set(m_c, m_qm, k); return reinterpret_cast(this->m_ctx.mk_ineq(x, m_c, lower, open)); } - catch (typename context_fpoint::numeral_manager::exception) { + catch (const typename context_fpoint::numeral_manager::exception &) { throw subpaving::exception(); } } diff --git a/src/math/subpaving/subpaving_t_def.h b/src/math/subpaving/subpaving_t_def.h index bb129fee7..cf93fbfad 100644 --- a/src/math/subpaving/subpaving_t_def.h +++ b/src/math/subpaving/subpaving_t_def.h @@ -1310,7 +1310,7 @@ bool context_t::relevant_new_bound(var x, numeral const & k, bool lower, bool TRACE("subpaving_relevant_bound", tout << "new bound is relevant\n";); return true; } - catch (typename C::exception) { + catch (const typename C::exception &) { // arithmetic module failed. set_arith_failed(); return false; @@ -1722,7 +1722,7 @@ void context_t::propagate(node * n, bound * b) { } } } - catch (typename C::exception) { + catch (const typename C::exception &) { // arithmetic module failed, ignore constraint set_arith_failed(); } diff --git a/src/shell/datalog_frontend.cpp b/src/shell/datalog_frontend.cpp index 9cc13b897..6596cc3b7 100644 --- a/src/shell/datalog_frontend.cpp +++ b/src/shell/datalog_frontend.cpp @@ -246,7 +246,7 @@ unsigned read_datalog(char const * file) { false); } - catch (out_of_memory_error) { + catch (const out_of_memory_error &) { std::cout << "\n\nOUT OF MEMORY!\n\n"; display_statistics( std::cout, diff --git a/src/tactic/aig/aig.cpp b/src/tactic/aig/aig.cpp index 6afac32b8..f6e12275f 100644 --- a/src/tactic/aig/aig.cpp +++ b/src/tactic/aig/aig.cpp @@ -1522,7 +1522,7 @@ public: } SASSERT(ref_count(r) >= 1); } - catch (aig_exception ex) { + catch (const aig_exception & ex) { dec_ref(r); throw ex; } diff --git a/src/test/mpff.cpp b/src/test/mpff.cpp index dd934831c..c78489f21 100644 --- a/src/test/mpff.cpp +++ b/src/test/mpff.cpp @@ -35,7 +35,7 @@ static void tst1() { std::cout << i << ": " << a << "\n"; } } - catch (z3_exception & ex) { + catch (const z3_exception & ex) { std::cout << ex.msg() << "\n"; } } @@ -432,7 +432,7 @@ static void tst_limits(unsigned prec) { m.round_to_plus_inf(); bool overflow = false; try { m.inc(a); } - catch (mpff_manager::overflow_exception) { overflow = true; } + catch (const mpff_manager::overflow_exception &) { overflow = true; } VERIFY(overflow); m.set_max(a); m.dec(a); @@ -446,7 +446,7 @@ static void tst_limits(unsigned prec) { ENSURE(m.eq(a, b)); overflow = true; try { m.dec(a); } - catch (mpff_manager::overflow_exception) { overflow = true; } + catch (const mpff_manager::overflow_exception &) { overflow = true; } ENSURE(overflow); m.round_to_plus_inf(); m.set_min(a); From 7d51353b8b097a22b0278cb50006c6b4ff5e0fe1 Mon Sep 17 00:00:00 2001 From: Joran Honig Date: Sat, 19 May 2018 11:13:53 +0200 Subject: [PATCH 598/637] Implement parallel python example --- examples/python/parallel.py | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 examples/python/parallel.py diff --git a/examples/python/parallel.py b/examples/python/parallel.py new file mode 100644 index 000000000..7903f58c9 --- /dev/null +++ b/examples/python/parallel.py @@ -0,0 +1,33 @@ +from z3 import * +from multiprocessing.pool import ThreadPool +from copy import deepcopy + +pool = ThreadPool(8) +x = Int('x') + +assert x.ctx == main_ctx() + + +def calculate(x, n, ctx): + """ Do a simple computation with a context""" + assert x.ctx == ctx + assert x.ctx != main_ctx() + + condition = And(x < 2, x > n, ctx) + solver = Solver(ctx=ctx) + solver.add(condition) + solver.check() + + +for i in range(100): + # Create new context for the computation + # Note that we need to do this sequentially, as parallel access to the current context or its objects + # will result in a segfault + i_context = Context() + x_i = deepcopy(x).translate(i_context) + + # Kick off parallel computation + pool.apply_async(calculate, [x_i, i, i_context]) + +pool.close() +pool.join() From e32dfad81e7fc14816c034d1a527975d0cc97138 Mon Sep 17 00:00:00 2001 From: Joran Honig Date: Sat, 19 May 2018 11:16:20 +0200 Subject: [PATCH 599/637] Add comments --- examples/python/parallel.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/examples/python/parallel.py b/examples/python/parallel.py index 7903f58c9..42ff50927 100644 --- a/examples/python/parallel.py +++ b/examples/python/parallel.py @@ -13,7 +13,10 @@ def calculate(x, n, ctx): assert x.ctx == ctx assert x.ctx != main_ctx() + # Parallel creation of z3 object condition = And(x < 2, x > n, ctx) + + # Parallel solving solver = Solver(ctx=ctx) solver.add(condition) solver.check() From 9c5a0ee8102dc248b29fbb930ecdb8158965ca21 Mon Sep 17 00:00:00 2001 From: Daniel Schemmel Date: Sat, 19 May 2018 04:17:52 +0200 Subject: [PATCH 600/637] Remove unnecessary (and confusing) parantheses around variable name in its declaration. Also fixes GCC warning [-Wparentheses]. --- src/interp/iz3base.cpp | 2 +- src/smt/theory_str.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/interp/iz3base.cpp b/src/interp/iz3base.cpp index 43e7bdff8..773f328ab 100644 --- a/src/interp/iz3base.cpp +++ b/src/interp/iz3base.cpp @@ -281,7 +281,7 @@ bool iz3base::is_sat(const std::vector &q, ast &_proof, std::vector &v _proof = cook(proof); } else if(vars.size()) { - model_ref(_m); + model_ref _m; s.get_model(_m); if (!_m.get()) { SASSERT(l_undef == res); diff --git a/src/smt/theory_str.cpp b/src/smt/theory_str.cpp index 0c4d11420..dde75c4bc 100644 --- a/src/smt/theory_str.cpp +++ b/src/smt/theory_str.cpp @@ -6768,7 +6768,7 @@ namespace smt { expr * sub2; if (u.re.is_to_re(re, sub1)) { SASSERT(u.str.is_string(sub1)); - zstring(str); + zstring str; u.str.is_string(sub1, str); lens.insert(str.length()); } else if (u.re.is_concat(re, sub1, sub2)) { From 78087483ca065c6518b3b09e2b945c9041862624 Mon Sep 17 00:00:00 2001 From: Daniel Schemmel Date: Sat, 19 May 2018 04:25:43 +0200 Subject: [PATCH 601/637] Add missing include The code should not have compiled previously, as smt::context was only forward declared at this point. --- src/smt/theory_arith.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/smt/theory_arith.h b/src/smt/theory_arith.h index 5040f1034..944efe6ce 100644 --- a/src/smt/theory_arith.h +++ b/src/smt/theory_arith.h @@ -31,6 +31,7 @@ Revision History: #include "smt/params/theory_arith_params.h" #include "smt/arith_eq_adapter.h" #include "smt/proto_model/numeral_factory.h" +#include "smt/smt_context.h" #include "util/obj_pair_hashtable.h" #include "smt/old_interval.h" #include "math/grobner/grobner.h" From 7467368266629486b3e11698f6e52ad8dd4a256f Mon Sep 17 00:00:00 2001 From: Daniel Schemmel Date: Mon, 21 May 2018 07:26:29 +0200 Subject: [PATCH 602/637] Use CMake's own mechanism for selecting language version if CMake version is new enough --- CMakeLists.txt | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e4732ef67..420c1a122 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -218,12 +218,17 @@ include(${CMAKE_SOURCE_DIR}/cmake/z3_add_cxx_flag.cmake) ################################################################################ # C++ language version ################################################################################ -# FIXME: Use CMake's own mechanism for selecting language version -if (("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU") OR ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")) - z3_add_cxx_flag("-std=c++11" REQUIRED) -else() - message(AUTHOR_WARNING "Not setting C++ language version for compiler") -endif() +if ("${CMAKE_VERSION}" VERSION_LESS "3.1") + # FIXME: Drop this when we upgrade to newer CMake versions. + if (("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU") OR ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")) + z3_add_cxx_flag("-std=c++11" REQUIRED) + else() + message(AUTHOR_WARNING "Not setting C++ language version for compiler") + endif() +else () + set(CMAKE_CXX_STANDARD 11) + set(CMAKE_CXX_STANDARD_REQUIRED ON) +endif () ################################################################################ # Platform detection From 3b1b82bef05a1b5fd69ece79c80a95fb6d72a990 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 22 May 2018 10:19:38 -0700 Subject: [PATCH 603/637] bumping version number by 1 for release tagging Signed-off-by: Nikolaj Bjorner --- CMakeLists.txt | 2 +- scripts/mk_project.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 420c1a122..afea250cb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -34,7 +34,7 @@ endif() ################################################################################ set(Z3_VERSION_MAJOR 4) set(Z3_VERSION_MINOR 7) -set(Z3_VERSION_PATCH 0) +set(Z3_VERSION_PATCH 1) set(Z3_VERSION_TWEAK 0) set(Z3_VERSION "${Z3_VERSION_MAJOR}.${Z3_VERSION_MINOR}.${Z3_VERSION_PATCH}.${Z3_VERSION_TWEAK}") set(Z3_FULL_VERSION_STR "${Z3_VERSION}") # Note this might be modified diff --git a/scripts/mk_project.py b/scripts/mk_project.py index 8f601f4fe..af4c92658 100644 --- a/scripts/mk_project.py +++ b/scripts/mk_project.py @@ -9,7 +9,7 @@ from mk_util import * # Z3 Project definition def init_project_def(): - set_version(4, 7, 0, 0) + set_version(4, 7, 1, 0) add_lib('util', []) add_lib('lp', ['util'], 'util/lp') add_lib('polynomial', ['util'], 'math/polynomial') From f2aae7cffa58686a8d251c87301c82cd4c2db200 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 22 May 2018 16:59:11 -0700 Subject: [PATCH 604/637] release notes Signed-off-by: Nikolaj Bjorner --- RELEASE_NOTES | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/RELEASE_NOTES b/RELEASE_NOTES index 86e7039dd..a99ec6b1e 100644 --- a/RELEASE_NOTES +++ b/RELEASE_NOTES @@ -1,5 +1,22 @@ RELEASE NOTES +Version 4.7.1 +============= + +- New requirements: + - uses stdbool and stdint as part of z3.h + +- New features: + - none + +- Removed features: + - none + +- Notes: + This is a minor release prior to a set of planned major updates. + It uses minor version 7 to indicate that the use of stdbool and + stdint are breaking changes to consumers of the C-based API. + Version 4.6.0 ============= From 87ae679db61e7d3fbe3ffc7f07dd5f06f5409277 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 22 May 2018 17:03:35 -0700 Subject: [PATCH 605/637] delay dereferencing justification Signed-off-by: Nikolaj Bjorner --- src/sat/sat_solver.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 09fe08f18..2c05cc52c 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -2761,7 +2761,7 @@ namespace sat { while (!m_lemma_min_stack.empty()) { bool_var var = m_lemma_min_stack.back(); m_lemma_min_stack.pop_back(); - justification js = m_justification[var]; + justification const& js = m_justification[var]; switch(js.get_kind()) { case justification::NONE: // it is a decision variable from a previous scope level From 363d7aad2ad243e8f871891322995830634b84f1 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 22 May 2018 20:02:08 -0700 Subject: [PATCH 606/637] fix bug reported in #1637 Signed-off-by: Nikolaj Bjorner --- src/nlsat/nlsat_explain.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/nlsat/nlsat_explain.cpp b/src/nlsat/nlsat_explain.cpp index ac16d9d68..2278e53dd 100644 --- a/src/nlsat/nlsat_explain.cpp +++ b/src/nlsat/nlsat_explain.cpp @@ -1463,6 +1463,7 @@ namespace nlsat { void project(var x, unsigned num, literal const * ls, scoped_literal_vector & result) { + m_result = &result; svector lits; TRACE("nlsat", tout << "project x" << x << "\n"; m_solver.display(tout);); @@ -1643,6 +1644,7 @@ namespace nlsat { ++num_lub; } } + TRACE("nlsat_explain", tout << ps << "\n";); if (num_lub == 0) { project_plus_infinity(x, ps); @@ -1668,7 +1670,7 @@ namespace nlsat { unsigned d = degree(p, x); lc = m_pm.coeff(p, x, d); if (!is_const(lc)) { - unsigned s = sign(p); + int s = sign(p); SASSERT(s != 0); atom::kind k = (s > 0)?(atom::GT):(atom::LT); add_simple_assumption(k, lc); @@ -1683,7 +1685,8 @@ namespace nlsat { unsigned d = degree(p, x); lc = m_pm.coeff(p, x, d); if (!is_const(lc)) { - unsigned s = sign(p); + int s = sign(p); + TRACE("nlsat_explain", tout << "degree: " << d << " " << lc << " sign: " << s << "\n";); SASSERT(s != 0); atom::kind k; if (s > 0) { From c963f6f2df8a113522173fe2cf024aa5962ac5b7 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 23 May 2018 08:02:16 -0700 Subject: [PATCH 607/637] merge with master Signed-off-by: Nikolaj Bjorner --- scripts/vsts.cmd | 40 -- src/api/api_solver.cpp | 2 +- .../simplifier/arith_simplifier_plugin.cpp | 496 ------------------ src/ast/simplifier/arith_simplifier_plugin.h | 97 ---- src/cmd_context/basic_cmds.cpp | 2 +- src/cmd_context/cmd_context.cpp | 7 +- src/opt/maxres.cpp | 1 - src/opt/opt_context.h | 31 -- src/solver/combined_solver.cpp | 2 +- 9 files changed, 9 insertions(+), 669 deletions(-) delete mode 100644 scripts/vsts.cmd delete mode 100644 src/ast/simplifier/arith_simplifier_plugin.cpp delete mode 100644 src/ast/simplifier/arith_simplifier_plugin.h diff --git a/scripts/vsts.cmd b/scripts/vsts.cmd deleted file mode 100644 index 3b3a60231..000000000 --- a/scripts/vsts.cmd +++ /dev/null @@ -1,40 +0,0 @@ -echo "Build" -md build -cd build -call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\VC\Auxiliary\Build\vcvars64.bat" -cmake -DBUILD_DOTNET_BINDINGS=True -DBUILD_JAVA_BINDINGS=True -DBUILD_PYTHON_BINDINGS=True -G "NMake Makefiles" ../ -nmake -rem TBD: test error level - -echo "Test python bindings" -pushd python -python z3test.py z3 -python z3test.py z3num -popd - -echo "Build and run examples" -nmake cpp_example -examples\cpp_example_build_dir\cpp_example.exe - -nmake c_example -examples\c_example_build_dir\c_example.exe - -rem nmake java_example -rem java_example.exe - -rem nmake dotnet_example -rem dotnet_example.exe - -echo "Build and run unit tests" -nmake test-z3 -rem TBD: test error level -rem test-z3.exe -a - - -cd .. -echo "Run regression tests" -git clone https://github.com/z3prover/z3test z3test -echo "test-benchmarks" -python z3test\scripts\test_benchmarks.py build\z3.exe z3test\regressions\smt2 -echo "benchmarks tested" - diff --git a/src/api/api_solver.cpp b/src/api/api_solver.cpp index ab1ea4a8e..657ff025c 100644 --- a/src/api/api_solver.cpp +++ b/src/api/api_solver.cpp @@ -152,7 +152,7 @@ extern "C" { return; } - bool initialized = to_solver(s)->m_solver.get() != 0; + bool initialized = to_solver(s)->m_solver.get() != nullptr; if (!initialized) init_solver(c, s); ptr_vector::const_iterator it = ctx->begin_assertions(); diff --git a/src/ast/simplifier/arith_simplifier_plugin.cpp b/src/ast/simplifier/arith_simplifier_plugin.cpp deleted file mode 100644 index 52f36ab04..000000000 --- a/src/ast/simplifier/arith_simplifier_plugin.cpp +++ /dev/null @@ -1,496 +0,0 @@ -/*++ -Copyright (c) 2007 Microsoft Corporation - -Module Name: - - arith_simplifier_plugin.cpp - -Abstract: - - Simplifier for the arithmetic family. - -Author: - - Leonardo (leonardo) 2008-01-08 - ---*/ -#include"arith_simplifier_plugin.h" -#include"ast_pp.h" -#include"ast_ll_pp.h" -#include"ast_smt2_pp.h" - -arith_simplifier_plugin::~arith_simplifier_plugin() { -} - -arith_simplifier_plugin::arith_simplifier_plugin(ast_manager & m, basic_simplifier_plugin & b, arith_simplifier_params & p): - poly_simplifier_plugin(symbol("arith"), m, OP_ADD, OP_MUL, OP_UMINUS, OP_SUB, OP_NUM), - m_params(p), - m_util(m), - m_bsimp(b), - m_int_zero(m), - m_real_zero(m) { - m_int_zero = m_util.mk_numeral(rational(0), true); - m_real_zero = m_util.mk_numeral(rational(0), false); -} - -/** - \brief Return true if the first monomial of t is negative. -*/ -bool arith_simplifier_plugin::is_neg_poly(expr * t) const { - if (m_util.is_add(t)) { - t = to_app(t)->get_arg(0); - } - if (m_util.is_mul(t)) { - t = to_app(t)->get_arg(0); - rational r; - if (is_numeral(t, r)) - return r.is_neg(); - } - return false; -} - -void arith_simplifier_plugin::get_monomial_gcd(expr_ref_vector& monomials, numeral& g) { - g = numeral::zero(); - numeral n; - for (unsigned i = 0; !g.is_one() && i < monomials.size(); ++i) { - expr* e = monomials[i].get(); - if (is_numeral(e, n)) { - g = gcd(abs(n), g); - } - else if (is_mul(e) && is_numeral(to_app(e)->get_arg(0), n)) { - g = gcd(abs(n), g); - } - else { - g = numeral::one(); - return; - } - } - if (g.is_zero()) { - g = numeral::one(); - } -} - -void arith_simplifier_plugin::div_monomial(expr_ref_vector& monomials, numeral const& g) { - numeral n; - for (unsigned i = 0; i < monomials.size(); ++i) { - expr* e = monomials[i].get(); - if (is_numeral(e, n)) { - SASSERT((n/g).is_int()); - monomials[i] = mk_numeral(n/g); - } - else if (is_mul(e) && is_numeral(to_app(e)->get_arg(0), n)) { - SASSERT((n/g).is_int()); - monomials[i] = mk_mul(n/g, to_app(e)->get_arg(1)); - } - else { - UNREACHABLE(); - } - } -} - -void arith_simplifier_plugin::gcd_reduce_monomial(expr_ref_vector& monomials, numeral& k) { - numeral g, n; - - get_monomial_gcd(monomials, g); - g = gcd(abs(k), g); - - if (g.is_one()) { - return; - } - SASSERT(g.is_pos()); - - k = k / g; - div_monomial(monomials, g); - -} - -template -void arith_simplifier_plugin::mk_le_ge_eq_core(expr * arg1, expr * arg2, expr_ref & result) { - set_curr_sort(arg1); - bool is_int = m_curr_sort->get_decl_kind() == INT_SORT; - expr_ref_vector monomials(m_manager); - rational k; - TRACE("arith_eq_bug", tout << mk_ismt2_pp(arg1, m_manager) << "\n" << mk_ismt2_pp(arg2, m_manager) << "\n";); - process_sum_of_monomials(false, arg1, monomials, k); - process_sum_of_monomials(true, arg2, monomials, k); - k.neg(); - if (is_int) { - numeral g; - get_monomial_gcd(monomials, g); - if (!g.is_one()) { - div_monomial(monomials, g); - switch(Kind) { - case LE: - // - // g*monmials' <= k - // <=> - // monomials' <= floor(k/g) - // - k = floor(k/g); - break; - case GE: - // - // g*monmials' >= k - // <=> - // monomials' >= ceil(k/g) - // - k = ceil(k/g); - break; - case EQ: - k = k/g; - if (!k.is_int()) { - result = m_manager.mk_false(); - return; - } - break; - } - } - } - expr_ref lhs(m_manager); - mk_sum_of_monomials(monomials, lhs); - if (m_util.is_numeral(lhs)) { - SASSERT(lhs == mk_zero()); - if (( Kind == LE && numeral::zero() <= k) || - ( Kind == GE && numeral::zero() >= k) || - ( Kind == EQ && numeral::zero() == k)) - result = m_manager.mk_true(); - else - result = m_manager.mk_false(); - } - else { - - if (is_neg_poly(lhs)) { - expr_ref neg_lhs(m_manager); - mk_uminus(lhs, neg_lhs); - lhs = neg_lhs; - k.neg(); - expr * rhs = m_util.mk_numeral(k, is_int); - switch (Kind) { - case LE: - result = m_util.mk_ge(lhs, rhs); - break; - case GE: - result = m_util.mk_le(lhs, rhs); - break; - case EQ: - result = m_manager.mk_eq(lhs, rhs); - break; - } - } - else { - expr * rhs = m_util.mk_numeral(k, is_int); - switch (Kind) { - case LE: - result = m_util.mk_le(lhs, rhs); - break; - case GE: - result = m_util.mk_ge(lhs, rhs); - break; - case EQ: - result = m_manager.mk_eq(lhs, rhs); - break; - } - } - } -} - -void arith_simplifier_plugin::mk_arith_eq(expr * arg1, expr * arg2, expr_ref & result) { - mk_le_ge_eq_core(arg1, arg2, result); -} - -void arith_simplifier_plugin::mk_le(expr * arg1, expr * arg2, expr_ref & result) { - mk_le_ge_eq_core(arg1, arg2, result); -} - -void arith_simplifier_plugin::mk_ge(expr * arg1, expr * arg2, expr_ref & result) { - mk_le_ge_eq_core(arg1, arg2, result); -} - -void arith_simplifier_plugin::mk_lt(expr * arg1, expr * arg2, expr_ref & result) { - expr_ref tmp(m_manager); - mk_le(arg2, arg1, tmp); - m_bsimp.mk_not(tmp, result); -} - -void arith_simplifier_plugin::mk_gt(expr * arg1, expr * arg2, expr_ref & result) { - expr_ref tmp(m_manager); - mk_le(arg1, arg2, tmp); - m_bsimp.mk_not(tmp, result); -} - -void arith_simplifier_plugin::gcd_normalize(numeral & coeff, expr_ref& term) { - if (!abs(coeff).is_one()) { - set_curr_sort(term); - SASSERT(m_curr_sort->get_decl_kind() == INT_SORT); - expr_ref_vector monomials(m_manager); - rational k; - monomials.push_back(mk_numeral(numeral(coeff), true)); - process_sum_of_monomials(false, term, monomials, k); - gcd_reduce_monomial(monomials, k); - numeral coeff1; - if (!is_numeral(monomials[0].get(), coeff1)) { - UNREACHABLE(); - } - if (coeff1 == coeff) { - return; - } - monomials[0] = mk_numeral(k, true); - coeff = coeff1; - mk_sum_of_monomials(monomials, term); - } -} - - -void arith_simplifier_plugin::mk_div(expr * arg1, expr * arg2, expr_ref & result) { - set_curr_sort(arg1); - numeral v1, v2; - bool is_int; - if (m_util.is_numeral(arg2, v2, is_int) && !v2.is_zero()) { - SASSERT(!is_int); - if (m_util.is_numeral(arg1, v1, is_int)) - result = m_util.mk_numeral(v1/v2, false); - else { - numeral k(1); - k /= v2; - - expr_ref inv_arg2(m_util.mk_numeral(k, false), m_manager); - mk_mul(inv_arg2, arg1, result); - } - } - else - result = m_util.mk_div(arg1, arg2); -} - -void arith_simplifier_plugin::mk_idiv(expr * arg1, expr * arg2, expr_ref & result) { - set_curr_sort(arg1); - numeral v1, v2; - bool is_int; - if (m_util.is_numeral(arg1, v1, is_int) && m_util.is_numeral(arg2, v2, is_int) && !v2.is_zero()) - result = m_util.mk_numeral(div(v1, v2), is_int); - else if (divides(arg2, arg1, result)) { - result = m_util.mk_mul(result, m_util.mk_idiv(arg2, arg2)); - } - else - result = m_util.mk_idiv(arg1, arg2); -} - -bool arith_simplifier_plugin::divides(expr* d, expr* n, expr_ref& quot) { - ast_manager& m = m_manager; - if (d == n) { - quot = m_util.mk_numeral(rational(1), m_util.is_int(d)); - return true; - } - if (m_util.is_mul(n)) { - expr_ref_vector muls(m); - muls.push_back(n); - expr* n1, *n2; - rational r1, r2; - for (unsigned i = 0; i < muls.size(); ++i) { - if (m_util.is_mul(muls[i].get(), n1, n2)) { - muls[i] = n1; - muls.push_back(n2); - --i; - } - } - if (m_util.is_numeral(d, r1) && !r1.is_zero()) { - for (unsigned i = 0; i < muls.size(); ++i) { - if (m_util.is_numeral(muls[i].get(), r2) && (r2 / r1).is_int()) { - muls[i] = m_util.mk_numeral(r2 / r1, m_util.is_int(d)); - quot = m_util.mk_mul(muls.size(), muls.c_ptr()); - return true; - } - } - } - else { - for (unsigned i = 0; i < muls.size(); ++i) { - if (d == muls[i].get()) { - muls[i] = muls.back(); - muls.pop_back(); - quot = m_util.mk_mul(muls.size(), muls.c_ptr()); - return true; - } - } - } - } - return false; -} - - -void arith_simplifier_plugin::prop_mod_const(expr * e, unsigned depth, numeral const& k, expr_ref& result) { - SASSERT(m_util.is_int(e)); - SASSERT(k.is_int() && k.is_pos()); - numeral n; - bool is_int; - - if (depth == 0) { - result = e; - } - else if (is_add(e) || is_mul(e)) { - expr_ref_vector args(m_manager); - expr_ref tmp(m_manager); - app* a = to_app(e); - for (unsigned i = 0; i < a->get_num_args(); ++i) { - prop_mod_const(a->get_arg(i), depth - 1, k, tmp); - args.push_back(tmp); - } - reduce(a->get_decl(), args.size(), args.c_ptr(), result); - } - else if (m_util.is_numeral(e, n, is_int) && is_int) { - result = mk_numeral(mod(n, k), true); - } - else { - result = e; - } -} - -void arith_simplifier_plugin::mk_mod(expr * arg1, expr * arg2, expr_ref & result) { - set_curr_sort(arg1); - numeral v1, v2; - bool is_int; - if (m_util.is_numeral(arg1, v1, is_int) && m_util.is_numeral(arg2, v2, is_int) && !v2.is_zero()) { - result = m_util.mk_numeral(mod(v1, v2), is_int); - } - else if (m_util.is_numeral(arg2, v2, is_int) && is_int && v2.is_one()) { - result = m_util.mk_numeral(numeral(0), true); - } - else if (m_util.is_numeral(arg2, v2, is_int) && is_int && v2.is_pos()) { - expr_ref tmp(m_manager); - prop_mod_const(arg1, 5, v2, tmp); - result = m_util.mk_mod(tmp, arg2); - } - else { - result = m_util.mk_mod(arg1, arg2); - } -} - -void arith_simplifier_plugin::mk_rem(expr * arg1, expr * arg2, expr_ref & result) { - set_curr_sort(arg1); - numeral v1, v2; - bool is_int; - if (m_util.is_numeral(arg1, v1, is_int) && m_util.is_numeral(arg2, v2, is_int) && !v2.is_zero()) { - numeral m = mod(v1, v2); - // - // rem(v1,v2) = if v2 >= 0 then mod(v1,v2) else -mod(v1,v2) - // - if (v2.is_neg()) { - m.neg(); - } - result = m_util.mk_numeral(m, is_int); - } - else if (m_util.is_numeral(arg2, v2, is_int) && is_int && v2.is_one()) { - result = m_util.mk_numeral(numeral(0), true); - } - else if (m_util.is_numeral(arg2, v2, is_int) && is_int && !v2.is_zero()) { - expr_ref tmp(m_manager); - prop_mod_const(arg1, 5, v2, tmp); - result = m_util.mk_mod(tmp, arg2); - if (v2.is_neg()) { - result = m_util.mk_uminus(result); - } - } - else { - result = m_util.mk_rem(arg1, arg2); - } -} - -void arith_simplifier_plugin::mk_to_real(expr * arg, expr_ref & result) { - numeral v; - if (m_util.is_numeral(arg, v)) - result = m_util.mk_numeral(v, false); - else - result = m_util.mk_to_real(arg); -} - -void arith_simplifier_plugin::mk_to_int(expr * arg, expr_ref & result) { - numeral v; - if (m_util.is_numeral(arg, v)) - result = m_util.mk_numeral(floor(v), true); - else if (m_util.is_to_real(arg)) - result = to_app(arg)->get_arg(0); - else - result = m_util.mk_to_int(arg); -} - -void arith_simplifier_plugin::mk_is_int(expr * arg, expr_ref & result) { - numeral v; - if (m_util.is_numeral(arg, v)) - result = v.is_int()?m_manager.mk_true():m_manager.mk_false(); - else if (m_util.is_to_real(arg)) - result = m_manager.mk_true(); - else - result = m_util.mk_is_int(arg); -} - -bool arith_simplifier_plugin::reduce(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result) { - set_reduce_invoked(); - SASSERT(f->get_family_id() == m_fid); - TRACE("arith_simplifier_plugin", tout << mk_pp(f, m_manager) << "\n"; - for (unsigned i = 0; i < num_args; i++) tout << mk_pp(args[i], m_manager) << "\n";); - arith_op_kind k = static_cast(f->get_decl_kind()); - switch (k) { - case OP_NUM: return false; - case OP_LE: if (m_presimp) return false; SASSERT(num_args == 2); mk_le(args[0], args[1], result); break; - case OP_GE: if (m_presimp) return false; SASSERT(num_args == 2); mk_ge(args[0], args[1], result); break; - case OP_LT: if (m_presimp) return false; SASSERT(num_args == 2); mk_lt(args[0], args[1], result); break; - case OP_GT: if (m_presimp) return false; SASSERT(num_args == 2); mk_gt(args[0], args[1], result); break; - case OP_ADD: mk_add(num_args, args, result); break; - case OP_SUB: mk_sub(num_args, args, result); break; - case OP_UMINUS: SASSERT(num_args == 1); mk_uminus(args[0], result); break; - case OP_MUL: - mk_mul(num_args, args, result); - TRACE("arith_simplifier_plugin", tout << mk_pp(result, m_manager) << "\n";); - break; - case OP_DIV: SASSERT(num_args == 2); mk_div(args[0], args[1], result); break; - case OP_IDIV: SASSERT(num_args == 2); mk_idiv(args[0], args[1], result); break; - case OP_REM: SASSERT(num_args == 2); mk_rem(args[0], args[1], result); break; - case OP_MOD: SASSERT(num_args == 2); mk_mod(args[0], args[1], result); break; - case OP_TO_REAL: SASSERT(num_args == 1); mk_to_real(args[0], result); break; - case OP_TO_INT: SASSERT(num_args == 1); mk_to_int(args[0], result); break; - case OP_IS_INT: SASSERT(num_args == 1); mk_is_int(args[0], result); break; - case OP_POWER: return false; - case OP_ABS: SASSERT(num_args == 1); mk_abs(args[0], result); break; - case OP_IRRATIONAL_ALGEBRAIC_NUM: return false; - case OP_DIV_0: return false; - case OP_IDIV_0: return false; - default: - return false; - } - TRACE("arith_simplifier_plugin", tout << mk_pp(result.get(), m_manager) << "\n";); - return true; -} - -void arith_simplifier_plugin::mk_abs(expr * arg, expr_ref & result) { - expr_ref c(m_manager); - expr_ref m_arg(m_manager); - mk_uminus(arg, m_arg); - mk_ge(arg, m_util.mk_numeral(rational(0), m_util.is_int(arg)), c); - m_bsimp.mk_ite(c, arg, m_arg, result); -} - -bool arith_simplifier_plugin::is_arith_term(expr * n) const { - return n->get_kind() == AST_APP && to_app(n)->get_family_id() == m_fid; -} - -bool arith_simplifier_plugin::reduce_eq(expr * lhs, expr * rhs, expr_ref & result) { - TRACE("reduce_eq_bug", tout << mk_ismt2_pp(lhs, m_manager) << "\n" << mk_ismt2_pp(rhs, m_manager) << "\n";); - set_reduce_invoked(); - if (m_presimp) { - return false; - } - if (m_params.m_arith_expand_eqs) { - expr_ref le(m_manager), ge(m_manager); - mk_le_ge_eq_core(lhs, rhs, le); - mk_le_ge_eq_core(lhs, rhs, ge); - m_bsimp.mk_and(le, ge, result); - return true; - } - - if (m_params.m_arith_process_all_eqs || is_arith_term(lhs) || is_arith_term(rhs)) { - mk_arith_eq(lhs, rhs, result); - return true; - } - return false; -} - - - diff --git a/src/ast/simplifier/arith_simplifier_plugin.h b/src/ast/simplifier/arith_simplifier_plugin.h deleted file mode 100644 index 045ee0e71..000000000 --- a/src/ast/simplifier/arith_simplifier_plugin.h +++ /dev/null @@ -1,97 +0,0 @@ -/*++ -Copyright (c) 2007 Microsoft Corporation - -Module Name: - - arith_simplifier_plugin.h - -Abstract: - - Simplifier for the arithmetic family. - -Author: - - Leonardo (leonardo) 2008-01-08 - ---*/ -#ifndef ARITH_SIMPLIFIER_PLUGIN_H_ -#define ARITH_SIMPLIFIER_PLUGIN_H_ - -#include"basic_simplifier_plugin.h" -#include"poly_simplifier_plugin.h" -#include"arith_decl_plugin.h" -#include"arith_simplifier_params.h" - -/** - \brief Simplifier for the arith family. -*/ -class arith_simplifier_plugin : public poly_simplifier_plugin { -public: - enum op_kind { - LE, GE, EQ - }; -protected: - arith_simplifier_params & m_params; - arith_util m_util; - basic_simplifier_plugin & m_bsimp; - expr_ref m_int_zero; - expr_ref m_real_zero; - - bool is_neg_poly(expr * t) const; - - template - void mk_le_ge_eq_core(expr * arg1, expr * arg2, expr_ref & result); - - void prop_mod_const(expr * e, unsigned depth, numeral const& k, expr_ref& result); - - void gcd_reduce_monomial(expr_ref_vector& monomials, numeral& k); - - void div_monomial(expr_ref_vector& monomials, numeral const& g); - void get_monomial_gcd(expr_ref_vector& monomials, numeral& g); - bool divides(expr* d, expr* n, expr_ref& quot); - -public: - arith_simplifier_plugin(ast_manager & m, basic_simplifier_plugin & b, arith_simplifier_params & p); - ~arith_simplifier_plugin(); - arith_util & get_arith_util() { return m_util; } - virtual numeral norm(const numeral & n) { return n; } - virtual bool is_numeral(expr * n, rational & val) const { bool f; return m_util.is_numeral(n, val, f); } - bool is_numeral(expr * n) const { return m_util.is_numeral(n); } - virtual bool is_minus_one(expr * n) const { numeral tmp; return is_numeral(n, tmp) && tmp.is_minus_one(); } - virtual expr * get_zero(sort * s) const { return m_util.is_int(s) ? m_int_zero.get() : m_real_zero.get(); } - - virtual app * mk_numeral(numeral const & n) { return m_util.mk_numeral(n, m_curr_sort->get_decl_kind() == INT_SORT); } - app * mk_numeral(numeral const & n, bool is_int) { return m_util.mk_numeral(n, is_int); } - bool is_int_sort(sort const * s) const { return m_util.is_int(s); } - bool is_real_sort(sort const * s) const { return m_util.is_real(s); } - bool is_arith_sort(sort const * s) const { return is_int_sort(s) || is_real_sort(s); } - bool is_int(expr const * n) const { return m_util.is_int(n); } - bool is_le(expr const * n) const { return m_util.is_le(n); } - bool is_ge(expr const * n) const { return m_util.is_ge(n); } - - virtual bool is_le_ge(expr * n) const { return is_le(n) || is_ge(n); } - - void mk_le(expr * arg1, expr * arg2, expr_ref & result); - void mk_ge(expr * arg1, expr * arg2, expr_ref & result); - void mk_lt(expr * arg1, expr * arg2, expr_ref & result); - void mk_gt(expr * arg1, expr * arg2, expr_ref & result); - void mk_arith_eq(expr * arg1, expr * arg2, expr_ref & result); - void mk_div(expr * arg1, expr * arg2, expr_ref & result); - void mk_idiv(expr * arg1, expr * arg2, expr_ref & result); - void mk_mod(expr * arg1, expr * arg2, expr_ref & result); - void mk_rem(expr * arg1, expr * arg2, expr_ref & result); - void mk_to_real(expr * arg, expr_ref & result); - void mk_to_int(expr * arg, expr_ref & result); - void mk_is_int(expr * arg, expr_ref & result); - void mk_abs(expr * arg, expr_ref & result); - - virtual bool reduce(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result); - virtual bool reduce_eq(expr * lhs, expr * rhs, expr_ref & result); - - bool is_arith_term(expr * n) const; - - void gcd_normalize(numeral & coeff, expr_ref& term); - -}; - -#endif /* ARITH_SIMPLIFIER_PLUGIN_H_ */ diff --git a/src/cmd_context/basic_cmds.cpp b/src/cmd_context/basic_cmds.cpp index 981fd801f..1d8fdb3de 100644 --- a/src/cmd_context/basic_cmds.cpp +++ b/src/cmd_context/basic_cmds.cpp @@ -619,7 +619,7 @@ public: try { ctx.regular_stream() << gparams::get_value(opt) << std::endl; } - catch (const gparams::exception & ex) { + catch (const gparams::exception &) { ctx.print_unsupported(opt, m_line, m_pos); } } diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp index 20b28ecc1..e42f884d6 100644 --- a/src/cmd_context/cmd_context.cpp +++ b/src/cmd_context/cmd_context.cpp @@ -1525,7 +1525,12 @@ void cmd_context::check_sat(unsigned num_assumptions, expr * const * assumptions throw ex; } catch (z3_exception & ex) { - m_solver->set_reason_unknown(ex.msg()); + if (m().canceled()) { + m_solver->set_reason_unknown(eh); + } + else { + m_solver->set_reason_unknown(ex.msg()); + } r = l_undef; } m_solver->set_status(r); diff --git a/src/opt/maxres.cpp b/src/opt/maxres.cpp index dd93ec74b..d49044d8d 100644 --- a/src/opt/maxres.cpp +++ b/src/opt/maxres.cpp @@ -64,7 +64,6 @@ Notes: #include "opt/opt_params.hpp" #include "opt/maxsmt.h" #include "opt/maxres.h" -// #include "opt/mss.h" using namespace opt; diff --git a/src/opt/opt_context.h b/src/opt/opt_context.h index 0f02dfb1c..b642f1d7a 100644 --- a/src/opt/opt_context.h +++ b/src/opt/opt_context.h @@ -182,27 +182,6 @@ namespace opt { void get_hard_constraints(expr_ref_vector& hard); expr_ref get_objective(unsigned i); -#if 0 - virtual void push(); - virtual void pop(unsigned n); - virtual bool empty() { return m_scoped_state.m_objectives.empty(); } - virtual void set_hard_constraints(ptr_vector & hard); - virtual lbool optimize(); - virtual void set_model(model_ref& _m) { m_model = _m; } - virtual void get_model_core(model_ref& _m); - virtual void get_box_model(model_ref& _m, unsigned index); - virtual void fix_model(model_ref& _m); - virtual void collect_statistics(statistics& stats) const; - virtual proof* get_proof() { return 0; } - virtual void get_labels(svector & r); - virtual void get_unsat_core(ptr_vector & r); - virtual std::string reason_unknown() const; - virtual void set_reason_unknown(char const* msg) { m_unknown = msg; } - - virtual void display_assignment(std::ostream& out); - virtual bool is_pareto() { return m_pareto.get() != 0; } - virtual void set_logic(symbol const& s) { m_logic = s; } -#endif void push() override; void pop(unsigned n) override; bool empty() override { return m_scoped_state.m_objectives.empty(); } @@ -244,16 +223,6 @@ namespace opt { expr_ref mk_ge(unsigned i, model_ref& model) override; expr_ref mk_le(unsigned i, model_ref& model) override; -#if 0 - virtual smt::context& smt_context() { return m_opt_solver->get_context(); } - virtual bool sat_enabled() const { return 0 != m_sat_solver.get(); } - virtual solver& get_solver(); - virtual ast_manager& get_manager() const { return this->m; } - virtual params_ref& params() { return m_params; } - virtual void enable_sls(bool force); - virtual symbol const& maxsat_engine() const { return m_maxsat_engine; } - virtual void get_base_model(model_ref& _m); -#endif generic_model_converter& fm() override { return *m_fm; } smt::context& smt_context() override { return m_opt_solver->get_context(); } bool sat_enabled() const override { return nullptr != m_sat_solver.get(); } diff --git a/src/solver/combined_solver.cpp b/src/solver/combined_solver.cpp index 6ce8a6ae0..a47302f5d 100644 --- a/src/solver/combined_solver.cpp +++ b/src/solver/combined_solver.cpp @@ -207,7 +207,7 @@ public: } catch (z3_exception& ex) { if (get_manager().canceled()) { - set_reason_unknown(Z3_CANCELED_MSG); + throw; } else { set_reason_unknown(ex.msg()); From 2800049dd4562359d400f00a2b57d6c6325eb4e7 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 23 May 2018 08:49:49 -0700 Subject: [PATCH 608/637] stale files Signed-off-by: Nikolaj Bjorner --- src/util/lp/nra_solver.cpp2 | 264 ------------------------------------ src/util/lp/nra_solver.h | 70 ---------- 2 files changed, 334 deletions(-) delete mode 100644 src/util/lp/nra_solver.cpp2 delete mode 100644 src/util/lp/nra_solver.h diff --git a/src/util/lp/nra_solver.cpp2 b/src/util/lp/nra_solver.cpp2 deleted file mode 100644 index 327d2b70f..000000000 --- a/src/util/lp/nra_solver.cpp2 +++ /dev/null @@ -1,264 +0,0 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Nikolaj Bjorner -*/ - -#include "util/lp/lar_solver.h" -#include "util/lp/nra_solver.h" -#include "nlsat/nlsat_solver.h" -#include "math/polynomial/polynomial.h" -#include "math/polynomial/algebraic_numbers.h" -#include "util/map.h" - - -namespace nra { - - struct mon_eq { - mon_eq(lp::var_index v, unsigned sz, lp::var_index const* vs): - m_v(v), m_vs(sz, vs) {} - lp::var_index m_v; - svector m_vs; - }; - - struct solver::imp { - lp::lar_solver& s; - reslimit& m_limit; - params_ref m_params; - u_map m_lp2nl; // map from lar_solver variables to nlsat::solver variables - scoped_ptr m_nlsat; - vector m_monomials; - unsigned_vector m_monomials_lim; - mutable std::unordered_map m_variable_values; // current model - - imp(lp::lar_solver& s, reslimit& lim, params_ref const& p): - s(s), - m_limit(lim), - m_params(p) { - } - - bool need_check() { - return !m_monomials.empty() && !check_assignments(); - } - - void add(lp::var_index v, unsigned sz, lp::var_index const* vs) { - m_monomials.push_back(mon_eq(v, sz, vs)); - } - - void push() { - m_monomials_lim.push_back(m_monomials.size()); - } - - void pop(unsigned n) { - if (n == 0) return; - m_monomials.shrink(m_monomials_lim[m_monomials_lim.size() - n]); - m_monomials_lim.shrink(m_monomials_lim.size() - n); - } - - /* - \brief Check if polynomials are well defined. - multiply values for vs and check if they are equal to value for v. - epsilon has been computed. - */ - bool check_assignment(mon_eq const& m) const { - rational r1 = m_variable_values[m.m_v]; - rational r2(1); - for (auto w : m.m_vs) { - r2 *= m_variable_values[w]; - } - return r1 == r2; - } - - bool check_assignments() const { - s.get_model(m_variable_values); - for (auto const& m : m_monomials) { - if (!check_assignment(m)) return false; - } - return true; - } - - /** - \brief one-shot nlsat check. - A one shot checker is the least functionality that can - enable non-linear reasoning. - In addition to checking satisfiability we would also need - to identify equalities in the model that should be assumed - with the remaining solver. - - TBD: use partial model from lra_solver to prime the state of nlsat_solver. - TBD: explore more incremental ways of applying nlsat (using assumptions) - */ - lbool check(lp::explanation_t& ex) { - SASSERT(need_check()); - m_nlsat = alloc(nlsat::solver, m_limit, m_params); - m_lp2nl.reset(); - vector core; - - // add linear inequalities from lra_solver - for (unsigned i = 0; i < s.constraint_count(); ++i) { - add_constraint(i); - } - - // add polynomial definitions. - for (auto const& m : m_monomials) { - add_monomial_eq(m); - } - // TBD: add variable bounds? - - lbool r = m_nlsat->check(); - TRACE("arith", m_nlsat->display(tout << r << "\n");); - switch (r) { - case l_true: - break; - case l_false: - ex.reset(); - m_nlsat->get_core(core); - for (auto c : core) { - unsigned idx = static_cast(static_cast(c) - this); - ex.push_back(std::pair(rational(1), idx)); - TRACE("arith", tout << "ex: " << idx << "\n";); - } - break; - - case l_undef: - break; - } - return r; - } - - void add_monomial_eq(mon_eq const& m) { - polynomial::manager& pm = m_nlsat->pm(); - svector vars; - for (auto v : m.m_vs) { - vars.push_back(lp2nl(v)); - } - polynomial::monomial_ref m1(pm.mk_monomial(vars.size(), vars.c_ptr()), pm); - polynomial::monomial_ref m2(pm.mk_monomial(lp2nl(m.m_v), 1), pm); - polynomial::monomial* mls[2] = { m1, m2 }; - polynomial::scoped_numeral_vector coeffs(pm.m()); - coeffs.push_back(mpz(1)); - coeffs.push_back(mpz(-1)); - polynomial::polynomial_ref p(pm.mk_polynomial(2, coeffs.c_ptr(), mls), pm); - polynomial::polynomial* ps[1] = { p }; - bool even[1] = { false }; - nlsat::literal lit = m_nlsat->mk_ineq_literal(nlsat::atom::kind::EQ, 1, ps, even); - m_nlsat->mk_clause(1, &lit, 0); - } - - void add_constraint(unsigned idx) { - auto& c = s.get_constraint(idx); - auto& pm = m_nlsat->pm(); - auto k = c.m_kind; - auto rhs = c.m_right_side; - auto lhs = c.get_left_side_coefficients(); - auto sz = lhs.size(); - svector vars; - rational den = denominator(rhs); - for (auto kv : lhs) { - vars.push_back(lp2nl(kv.second)); - den = lcm(den, denominator(kv.first)); - } - vector coeffs; - for (auto kv : lhs) { - coeffs.push_back(den * kv.first); - } - rhs *= den; - polynomial::polynomial_ref p(pm.mk_linear(sz, coeffs.c_ptr(), vars.c_ptr(), -rhs), pm); - polynomial::polynomial* ps[1] = { p }; - bool is_even[1] = { false }; - nlsat::literal lit; - nlsat::assumption a = this + idx; - switch (k) { - case lp::lconstraint_kind::LE: - lit = ~m_nlsat->mk_ineq_literal(nlsat::atom::kind::GT, 1, ps, is_even); - break; - case lp::lconstraint_kind::GE: - lit = ~m_nlsat->mk_ineq_literal(nlsat::atom::kind::LT, 1, ps, is_even); - break; - case lp::lconstraint_kind::LT: - lit = m_nlsat->mk_ineq_literal(nlsat::atom::kind::LT, 1, ps, is_even); - break; - case lp::lconstraint_kind::GT: - lit = m_nlsat->mk_ineq_literal(nlsat::atom::kind::GT, 1, ps, is_even); - break; - case lp::lconstraint_kind::EQ: - lit = m_nlsat->mk_ineq_literal(nlsat::atom::kind::EQ, 1, ps, is_even); - break; - } - m_nlsat->mk_clause(1, &lit, a); - } - - bool is_int(lp::var_index v) { - return s.var_is_int(v); - } - - - polynomial::var lp2nl(lp::var_index v) { - polynomial::var r; - if (!m_lp2nl.find(v, r)) { - r = m_nlsat->mk_var(is_int(v)); - m_lp2nl.insert(v, r); - } - return r; - } - - nlsat::anum const& value(lp::var_index v) const { - return m_nlsat->value(m_lp2nl.find(v)); - } - - nlsat::anum_manager& am() { - return m_nlsat->am(); - } - - std::ostream& display(std::ostream& out) const { - for (auto m : m_monomials) { - out << "v" << m.m_v << " = "; - for (auto v : m.m_vs) { - out << "v" << v << " "; - } - out << "\n"; - } - return out; - } - }; - - solver::solver(lp::lar_solver& s, reslimit& lim, params_ref const& p) { - m_imp = alloc(imp, s, lim, p); - } - - solver::~solver() { - dealloc(m_imp); - } - - void solver::add_monomial(lp::var_index v, unsigned sz, lp::var_index const* vs) { - m_imp->add(v, sz, vs); - } - - lbool solver::check(lp::explanation_t& ex) { - return m_imp->check(ex); - } - - bool solver::need_check() { - return m_imp->need_check(); - } - - void solver::push() { - m_imp->push(); - } - - void solver::pop(unsigned n) { - m_imp->pop(n); - } - - std::ostream& solver::display(std::ostream& out) const { - return m_imp->display(out); - } - - nlsat::anum const& solver::value(lp::var_index v) const { - return m_imp->value(v); - } - - nlsat::anum_manager& solver::am() { - return m_imp->am(); - } - -} diff --git a/src/util/lp/nra_solver.h b/src/util/lp/nra_solver.h deleted file mode 100644 index 70e614e91..000000000 --- a/src/util/lp/nra_solver.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Nikolaj Bjorner -*/ - -#pragma once -#include "util/vector.h" -#include "util/lp/lp_settings.h" -#include "util/rlimit.h" -#include "util/params.h" -#include "nlsat/nlsat_solver.h" - -namespace lp { - class lar_solver; -} - - -namespace nra { - - - - class solver { - struct imp; - imp* m_imp; - - public: - - solver(lp::lar_solver& s, reslimit& lim, params_ref const& p = params_ref()); - - ~solver(); - - /* - \brief Add a definition v = vs[0]*vs[1]*...*vs[sz-1] - The variable v is equal to the product of variables vs. - */ - void add_monomial(lp::var_index v, unsigned sz, lp::var_index const* vs); - - /* - \brief Check feasiblity of linear constraints augmented by polynomial definitions - that are added. - */ - lbool check(lp::explanation_t& ex); - - /* - \brief determine whether nra check is needed. - */ - bool need_check(); - - /* - \brief Access model. - */ - nlsat::anum const& value(lp::var_index v) const; - - nlsat::anum_manager& am(); - - /* - \brief push and pop scope. - Monomial definitions are retraced when popping scope. - */ - void push(); - - void pop(unsigned n); - - /* - \brief display state - */ - std::ostream& display(std::ostream& out) const; - - }; -} From 0708ecb543072f91219a27be229c4d1fee865a11 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 23 May 2018 09:11:33 -0700 Subject: [PATCH 609/637] dealing with compilers that don't take typename in non-template classes Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/pb2bv_rewriter.cpp | 22 +-- src/opt/sortmax.cpp | 22 +-- src/sat/ba_solver.h | 22 +-- src/smt/theory_pb.cpp | 4 +- src/tactic/arith/card2bv_tactic.h | 24 ++-- src/test/sorting_network.cpp | 20 +-- src/util/lp/cut_solver.h | 201 ---------------------------- src/util/lp/int_solver.h | 157 ---------------------- src/util/sorting_network.h | 4 +- 9 files changed, 59 insertions(+), 417 deletions(-) delete mode 100644 src/util/lp/cut_solver.h delete mode 100644 src/util/lp/int_solver.h diff --git a/src/ast/rewriter/pb2bv_rewriter.cpp b/src/ast/rewriter/pb2bv_rewriter.cpp index 47a8a044a..7da8b2d3f 100644 --- a/src/ast/rewriter/pb2bv_rewriter.cpp +++ b/src/ast/rewriter/pb2bv_rewriter.cpp @@ -43,8 +43,8 @@ struct pb2bv_rewriter::imp { unsigned m_compile_card; struct card2bv_rewriter { - typedef expr* literal; - typedef ptr_vector literal_vector; + typedef expr* pliteral; + typedef ptr_vector pliteral_vector; psort_nw m_sort; ast_manager& m; imp& m_imp; @@ -861,25 +861,25 @@ struct pb2bv_rewriter::imp { } // definitions used for sorting network - literal mk_false() { return m.mk_false(); } - literal mk_true() { return m.mk_true(); } - literal mk_max(literal a, literal b) { return trail(m.mk_or(a, b)); } - literal mk_min(literal a, literal b) { return trail(m.mk_and(a, b)); } - literal mk_not(literal a) { if (m.is_not(a,a)) return a; return trail(m.mk_not(a)); } + pliteral mk_false() { return m.mk_false(); } + pliteral mk_true() { return m.mk_true(); } + pliteral mk_max(pliteral a, pliteral b) { return trail(m.mk_or(a, b)); } + pliteral mk_min(pliteral a, pliteral b) { return trail(m.mk_and(a, b)); } + pliteral mk_not(pliteral a) { if (m.is_not(a,a)) return a; return trail(m.mk_not(a)); } - std::ostream& pp(std::ostream& out, literal lit) { return out << mk_ismt2_pp(lit, m); } + std::ostream& pp(std::ostream& out, pliteral lit) { return out << mk_ismt2_pp(lit, m); } - literal trail(literal l) { + pliteral trail(pliteral l) { m_trail.push_back(l); return l; } - literal fresh(char const* n) { + pliteral fresh(char const* n) { expr_ref fr(m.mk_fresh_const(n, m.mk_bool_sort()), m); m_imp.m_fresh.push_back(to_app(fr)->get_decl()); return trail(fr); } - void mk_clause(unsigned n, literal const* lits) { + void mk_clause(unsigned n, pliteral const* lits) { m_imp.m_lemmas.push_back(::mk_or(m, n, lits)); } diff --git a/src/opt/sortmax.cpp b/src/opt/sortmax.cpp index 6ea7feaad..9c45e42a2 100644 --- a/src/opt/sortmax.cpp +++ b/src/opt/sortmax.cpp @@ -30,8 +30,8 @@ namespace opt { class sortmax : public maxsmt_solver_base { public: - typedef expr* literal; - typedef ptr_vector literal_vector; + typedef expr* pliteral; + typedef ptr_vector pliteral_vector; psort_nw m_sort; expr_ref_vector m_trail; func_decl_ref_vector m_fresh; @@ -126,19 +126,19 @@ namespace opt { } // definitions used for sorting network - literal mk_false() { return m.mk_false(); } - literal mk_true() { return m.mk_true(); } - literal mk_max(literal a, literal b) { return trail(m.mk_or(a, b)); } - literal mk_min(literal a, literal b) { return trail(m.mk_and(a, b)); } - literal mk_not(literal a) { if (m.is_not(a,a)) return a; return trail(m.mk_not(a)); } + pliteral mk_false() { return m.mk_false(); } + pliteral mk_true() { return m.mk_true(); } + pliteral mk_max(pliteral a, pliteral b) { return trail(m.mk_or(a, b)); } + pliteral mk_min(pliteral a, pliteral b) { return trail(m.mk_and(a, b)); } + pliteral mk_not(pliteral a) { if (m.is_not(a,a)) return a; return trail(m.mk_not(a)); } - std::ostream& pp(std::ostream& out, literal lit) { return out << mk_pp(lit, m); } + std::ostream& pp(std::ostream& out, pliteral lit) { return out << mk_pp(lit, m); } - literal trail(literal l) { + pliteral trail(pliteral l) { m_trail.push_back(l); return l; } - literal fresh(char const* n) { + pliteral fresh(char const* n) { expr_ref fr(m.mk_fresh_const(n, m.mk_bool_sort()), m); func_decl* f = to_app(fr)->get_decl(); m_fresh.push_back(f); @@ -146,7 +146,7 @@ namespace opt { return trail(fr); } - void mk_clause(unsigned n, literal const* lits) { + void mk_clause(unsigned n, pliteral const* lits) { s().assert_expr(mk_or(m, n, lits)); } diff --git a/src/sat/ba_solver.h b/src/sat/ba_solver.h index 14482eabb..07e7cfd58 100644 --- a/src/sat/ba_solver.h +++ b/src/sat/ba_solver.h @@ -242,23 +242,23 @@ namespace sat { unsigned_vector m_pb_undef; struct ba_sort { - typedef typename sat::literal literal; - typedef typename sat::literal_vector literal_vector; + typedef sat::literal pliteral; + typedef sat::literal_vector pliteral_vector; ba_solver& s; - literal m_true; - literal_vector m_lits; + pliteral m_true; + pliteral_vector m_lits; ba_sort(ba_solver& s): s(s), m_true(null_literal) {} - literal mk_false(); - literal mk_true(); - literal mk_not(literal l); - literal fresh(char const*); - literal mk_max(literal l1, literal l2); - literal mk_min(literal l1, literal l2); + pliteral mk_false(); + pliteral mk_true(); + pliteral mk_not(pliteral l); + pliteral fresh(char const*); + pliteral mk_max(pliteral l1, pliteral l2); + pliteral mk_min(pliteral l1, pliteral l2); void mk_clause(unsigned n, literal const* lits); - std::ostream& pp(std::ostream& out, literal l) const; + std::ostream& pp(std::ostream& out, pliteral l) const; }; ba_sort m_ba; psort_nw m_sort; diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index 1e5b35fbf..9fc33a6a9 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -1392,8 +1392,8 @@ namespace smt { ast_manager& m; theory_pb& th; pb_util pb; - typedef smt::literal literal; - typedef smt::literal_vector literal_vector; + typedef smt::literal pliteral; + typedef smt::literal_vector pliteral_vector; psort_expr(context& c, theory_pb& th): ctx(c), diff --git a/src/tactic/arith/card2bv_tactic.h b/src/tactic/arith/card2bv_tactic.h index e11c78048..5e2051b50 100644 --- a/src/tactic/arith/card2bv_tactic.h +++ b/src/tactic/arith/card2bv_tactic.h @@ -34,8 +34,8 @@ namespace pb { class card2bv_rewriter { public: - typedef expr* literal; - typedef ptr_vector literal_vector; + typedef expr* pliteral; + typedef ptr_vector pliteral_vector; private: ast_manager& m; arith_util au; @@ -54,7 +54,7 @@ namespace pb { bool is_and(func_decl* f); bool is_atmost1(func_decl* f, unsigned sz, expr * const* args, expr_ref& result); expr_ref mk_atmost1(unsigned sz, expr * const* args); - void mk_at_most_1_small(bool last, unsigned n, literal const* xs, expr_ref_vector& result, expr_ref_vector& ors); + void mk_at_most_1_small(bool last, unsigned n, pliteral const* xs, expr_ref_vector& result, expr_ref_vector& ors); public: card2bv_rewriter(ast_manager& m); @@ -62,15 +62,15 @@ namespace pb { void mk_assert(func_decl * f, unsigned sz, expr * const* args, expr_ref & result, expr_ref_vector& lemmas); // definitions used for sorting network - literal mk_false() { return m.mk_false(); } - literal mk_true() { return m.mk_true(); } - literal mk_max(literal a, literal b) { return trail(m.mk_or(a, b)); } - literal mk_min(literal a, literal b) { return trail(m.mk_and(a, b)); } - literal mk_not(literal a) { if (m.is_not(a,a)) return a; return trail(m.mk_not(a)); } - std::ostream& pp(std::ostream& out, literal lit); - literal fresh(); - literal trail(literal l); - void mk_clause(unsigned n, literal const* lits); + pliteral mk_false() { return m.mk_false(); } + pliteral mk_true() { return m.mk_true(); } + pliteral mk_max(pliteral a, pliteral b) { return trail(m.mk_or(a, b)); } + pliteral mk_min(pliteral a, pliteral b) { return trail(m.mk_and(a, b)); } + pliteral mk_not(pliteral a) { if (m.is_not(a,a)) return a; return trail(m.mk_not(a)); } + std::ostream& pp(std::ostream& out, pliteral lit); + pliteral fresh(); + pliteral trail(pliteral l); + void mk_clause(unsigned n, pliteral const* lits); }; diff --git a/src/test/sorting_network.cpp b/src/test/sorting_network.cpp index e3bf2d653..f5c415c04 100644 --- a/src/test/sorting_network.cpp +++ b/src/test/sorting_network.cpp @@ -152,30 +152,30 @@ struct ast_ext2 { expr_ref_vector m_clauses; expr_ref_vector m_trail; ast_ext2(ast_manager& m):m(m), m_clauses(m), m_trail(m) {} - typedef expr* literal; - typedef ptr_vector literal_vector; + typedef expr* pliteral; + typedef ptr_vector pliteral_vector; expr* trail(expr* e) { m_trail.push_back(e); return e; } - literal mk_false() { return m.mk_false(); } - literal mk_true() { return m.mk_true(); } - literal mk_max(literal a, literal b) { + pliteral mk_false() { return m.mk_false(); } + pliteral mk_true() { return m.mk_true(); } + pliteral mk_max(pliteral a, pliteral b) { return trail(m.mk_or(a, b)); } - literal mk_min(literal a, literal b) { return trail(m.mk_and(a, b)); } - literal mk_not(literal a) { if (m.is_not(a,a)) return a; + pliteral mk_min(pliteral a, pliteral b) { return trail(m.mk_and(a, b)); } + pliteral mk_not(pliteral a) { if (m.is_not(a,a)) return a; return trail(m.mk_not(a)); } - std::ostream& pp(std::ostream& out, literal lit) { + std::ostream& pp(std::ostream& out, pliteral lit) { return out << mk_pp(lit, m); } - literal fresh(char const* n) { + pliteral fresh(char const* n) { return trail(m.mk_fresh_const(n, m.mk_bool_sort())); } - void mk_clause(unsigned n, literal const* lits) { + void mk_clause(unsigned n, pliteral const* lits) { m_clauses.push_back(mk_or(m, n, lits)); } }; diff --git a/src/util/lp/cut_solver.h b/src/util/lp/cut_solver.h deleted file mode 100644 index 18da0b88b..000000000 --- a/src/util/lp/cut_solver.h +++ /dev/null @@ -1,201 +0,0 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Nikolaj Bjorner, Lev Nachmanson -*/ -#pragma once -#include "util/vector.h" -#include "util/trace.h" -#include "util/lp/lp_settings.h" -namespace lp { -template -class cut_solver { - - struct ineq { // we only have less or equal, which is enough for integral variables - mpq m_bound; - vector> m_term; - ineq(vector>& term, mpq bound):m_bound(bound),m_term(term) { - } - }; - - vector m_ineqs; - - enum class lbool { - l_false, // false - l_true, // true - l_undef // undef - }; - - enum class literal_type { - BOOL, - INEQ, - BOUND - }; - - struct literal { - literal_type m_tag; - bool m_sign; // true means the pointed inequality is negated, or bound is negated, or boolean value is negated - - unsigned m_id; - unsigned m_index_of_ineq; // index into m_ineqs - bool m_bool_val; // used if m_tag is equal to BOOL - mpq m_bound; // used if m_tag is BOUND - literal(bool sign, bool val): m_tag(literal_type::BOOL), - m_bool_val(val){ - } - literal(bool sign, unsigned index_of_ineq) : m_tag(literal_type::INEQ), m_index_of_ineq(index_of_ineq) {} - }; - - bool lhs_is_int(const vector> & lhs) const { - for (auto & p : lhs) - if (p.first.is_int() == false) return false; - return true; - } - - public: - void add_ineq(vector> & lhs, mpq rhs) { - lp_assert(lhs_is_int(lhs)); - lp_assert(rhs.is_int()); - m_ineqs.push_back(ineq(lhs, rhs)); - } - - - bool m_inconsistent; // tracks if state is consistent - unsigned m_scope_lvl; // tracks the number of case splits - - svector m_trail; - // backtracking state from the SAT solver: - struct scope { - unsigned m_trail_lim; // pointer into assignment stack - unsigned m_clauses_to_reinit_lim; // ignore for now - bool m_inconsistent; // really needed? - }; - - svector m_scopes; - - bool at_base_lvl() const { return m_scope_lvl == 0; } - - lbool check() { - init_search(); - propagate(); - while (true) { - lbool r = bounded_search(); - if (r != lbool::l_undef) - return r; - - restart(); - simplify_problem(); - if (check_inconsistent()) return lbool::l_false; - gc(); - } - } - - cut_solver() { - } - - void init_search() { - // TBD - // initialize data-structures - } - - void simplify_problem() { - // no-op - } - - void gc() { - // no-op - } - - void restart() { - // no-op for now - } - - bool check_inconsistent() { - // TBD - return false; - } - - lbool bounded_search() { - while (true) { - checkpoint(); - bool done = false; - while (!done) { - lbool is_sat = propagate_and_backjump_step(done); - if (is_sat != lbool::l_true) return is_sat; - } - - gc(); - - if (!decide()) { - lbool is_sat = final_check(); - if (is_sat != lbool::l_undef) { - return is_sat; - } - } - } - } - - void checkpoint() { - // check for cancelation - } - - void cleanup() { - } - - lbool propagate_and_backjump_step(bool& done) { - done = true; - propagate(); - if (!inconsistent()) - return lbool::l_true; - if (!resolve_conflict()) - return lbool::l_false; - if (at_base_lvl()) { - cleanup(); // cleaner may propagate frozen clauses - if (inconsistent()) { - TRACE("sat", tout << "conflict at level 0\n";); - return lbool::l_false; - } - gc(); - } - done = false; - return lbool::l_true; - } - - lbool final_check() { - // there are no more case splits, and all clauses are satisfied. - // prepare the model for external consumption. - return lbool::l_true; - } - - - bool resolve_conflict() { - while (true) { - bool r = resolve_conflict_core(); - // after pop, clauses are reinitialized, - // this may trigger another conflict. - if (!r) - return false; - if (!inconsistent()) - return true; - } - } - - bool resolve_conflict_core() { - // this is where the main action is. - return true; - } - - void propagate() { - // this is where the main action is. - } - - bool decide() { - // this is where the main action is. - // pick the next variable and bound or value on the variable. - // return false if all variables have been assigned. - return false; - } - - bool inconsistent() const { return m_inconsistent; } - -}; -} diff --git a/src/util/lp/int_solver.h b/src/util/lp/int_solver.h deleted file mode 100644 index 56ddf16fd..000000000 --- a/src/util/lp/int_solver.h +++ /dev/null @@ -1,157 +0,0 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ -#pragma once -#include "util/lp/lp_settings.h" -#include "util/lp/static_matrix.h" -#include "util/lp/iterator_on_row.h" -#include "util/lp/int_set.h" -#include "util/lp/lar_term.h" -#include "util/lp/cut_solver.h" -#include "util/lp/lar_constraints.h" - -namespace lp { -class lar_solver; -template -struct lp_constraint; -enum class lia_move { - ok, - branch, - cut, - conflict, - continue_with_check, - give_up -}; - -struct explanation { - vector> m_explanation; - void push_justification(constraint_index j, const mpq& v) { - m_explanation.push_back(std::make_pair(v, j)); - } -}; - -class int_solver { -public: - // fields - lar_solver *m_lar_solver; - int_set m_old_values_set; - vector m_old_values_data; - unsigned m_branch_cut_counter; - - // methods - int_solver(lar_solver* lp); - int_set& inf_int_set(); - const int_set& inf_int_set() const; - // main function to check that solution provided by lar_solver is valid for integral values, - // or provide a way of how it can be adjusted. - lia_move check(lar_term& t, mpq& k, explanation& ex); - bool move_non_basic_column_to_bounds(unsigned j); - lia_move check_wrapper(lar_term& t, mpq& k, explanation& ex); -private: - - // how to tighten bounds for integer variables. - - bool gcd_test_for_row(static_matrix> & A, unsigned i, explanation &); - - // gcd test - // 5*x + 3*y + 6*z = 5 - // suppose x is fixed at 2. - // so we have 10 + 3(y + 2z) = 5 - // 5 = -3(y + 2z) - // this is unsolvable because 5/3 is not an integer. - // so we create a lemma that rules out this condition. - // - bool gcd_test(explanation & ); // returns false in case of failure. Creates a theory lemma in case of failure. - - // create goromy cuts - // either creates a conflict or a bound. - - // branch and bound: - // decide what to branch and bound on - // creates a fresh inequality. - - bool branch(const lp_constraint & new_inequality); - bool ext_gcd_test(iterator_on_row & it, - mpq const & least_coeff, - mpq const & lcm_den, - mpq const & consts, - explanation & ex); - void fill_explanation_from_fixed_columns(iterator_on_row & it, explanation &); - void add_to_explanation_from_fixed_or_boxed_column(unsigned j, explanation &); - void patch_int_infeasible_non_basic_column(unsigned j); - void patch_int_infeasible_nbasic_columns(); - bool get_freedom_interval_for_column(unsigned j, bool & inf_l, impq & l, bool & inf_u, impq & u, mpq & m); - linear_combination_iterator * get_column_iterator(unsigned j); - const impq & low_bound(unsigned j) const; - const impq & upper_bound(unsigned j) const; - bool is_int(unsigned j) const; - bool is_real(unsigned j) const; - bool is_base(unsigned j) const; - bool is_boxed(unsigned j) const; - bool is_fixed(unsigned j) const; - bool is_free(unsigned j) const; - bool value_is_int(unsigned j) const; - void set_value_for_nbasic_column(unsigned j, const impq & new_val); - void set_value_for_nbasic_column_ignore_old_values(unsigned j, const impq & new_val); - bool non_basic_columns_are_at_bounds() const; - void failed(); - bool is_feasible() const; - const impq & get_value(unsigned j) const; - void display_column(std::ostream & out, unsigned j) const; - bool inf_int_set_is_correct() const; - void update_column_in_int_inf_set(unsigned j); - bool column_is_int_inf(unsigned j) const; - void trace_inf_rows() const; - int find_inf_int_base_column(); - int find_inf_int_boxed_base_column_with_smallest_range(); - lp_settings& settings(); - bool move_non_basic_columns_to_bounds(); - void branch_infeasible_int_var(unsigned); - lia_move mk_gomory_cut(lar_term& t, mpq& k,explanation & ex, unsigned inf_col, linear_combination_iterator& iter); - lia_move report_conflict_from_gomory_cut(mpq & k); - void adjust_term_and_k_for_some_ints_case_gomory(lar_term& t, mpq& k, mpq& lcm_den); - void init_check_data(); - bool constrain_free_vars(linear_combination_iterator * r); - lia_move proceed_with_gomory_cut(lar_term& t, mpq& k, explanation& ex, unsigned j); - int find_free_var_in_gomory_row(linear_combination_iterator& iter); - bool is_gomory_cut_target(linear_combination_iterator &iter); - bool at_bound(unsigned j) const; - bool at_low(unsigned j) const; - bool at_upper(unsigned j) const; - bool has_low(unsigned j) const; - bool has_upper(unsigned j) const; - unsigned row_of_basic_column(unsigned j) const; - inline static bool is_rational(const impq & n) { - return is_zero(n.y); - } - - inline static - mpq fractional_part(const impq & n) { - lp_assert(is_rational(n)); - return n.x - floor(n.x); - } - void real_case_in_gomory_cut(const mpq & a, unsigned x_j, mpq & k, lar_term& t, explanation & ex, unsigned inf_column); - void int_case_in_gomory_cut(const mpq & a, unsigned x_j, mpq & k, lar_term& t, explanation& ex, mpq & lcm_den, unsigned inf_column); - constraint_index column_upper_bound_constraint(unsigned j) const; - constraint_index column_low_bound_constraint(unsigned j) const; - void display_row_info(std::ostream & out, unsigned row_index) const; - void gomory_cut_adjust_t_and_k(vector> & pol, lar_term & t, mpq &k, bool num_ints, mpq &lcm_den); - bool current_solution_is_inf_on_cut(const lar_term& t, const mpq& k) const; -public: - bool shift_var(unsigned j, unsigned range); -private: - unsigned random(); - bool has_inf_int() const; - lia_move create_branch_on_column(int j, lar_term& t, mpq& k, bool free_column) const; -public: - void display_inf_or_int_inf_columns(std::ostream & out) const; - template - void fill_cut_solver(cut_solver & cs); - template - void fill_cut_solver_for_constraint(const lar_base_constraint*, cut_solver& ); - template - void get_int_coeffs_from_constraint(const lar_base_constraint* c, vector>& coeff, T & rs); - -}; -} diff --git a/src/util/sorting_network.h b/src/util/sorting_network.h index 38c595125..f2906b00c 100644 --- a/src/util/sorting_network.h +++ b/src/util/sorting_network.h @@ -141,8 +141,8 @@ Notes: // Described in Abio et.al. CP 2013. template class psort_nw { - typedef typename psort_expr::literal literal; - typedef typename psort_expr::literal_vector literal_vector; + typedef typename psort_expr::pliteral literal; + typedef typename psort_expr::pliteral_vector literal_vector; sorting_network_config m_cfg; class vc { From f5775f265a3414972161fb86eefd2913c65cbf21 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 23 May 2018 09:21:33 -0700 Subject: [PATCH 610/637] fix python build script dependencies Signed-off-by: Nikolaj Bjorner --- scripts/mk_project.py | 6 +- src/solver/parallel_tactic.cpp | 5 - src/tactic/arith/elim01_tactic.cpp | 267 ----------------------------- 3 files changed, 3 insertions(+), 275 deletions(-) delete mode 100644 src/tactic/arith/elim01_tactic.cpp diff --git a/scripts/mk_project.py b/scripts/mk_project.py index 0590a8693..b03ced763 100644 --- a/scripts/mk_project.py +++ b/scripts/mk_project.py @@ -32,13 +32,13 @@ def init_project_def(): add_lib('grobner', ['ast'], 'math/grobner') add_lib('euclid', ['util'], 'math/euclid') add_lib('core_tactics', ['tactic', 'macros', 'normal_forms', 'rewriter'], 'tactic/core') - add_lib('sat_tactic', ['tactic', 'sat'], 'sat/tactic') + add_lib('proofs', ['rewriter', 'util'], 'ast/proofs') + add_lib('solver', ['model', 'tactic', 'proofs']) + add_lib('sat_tactic', ['tactic', 'sat', 'solver'], 'sat/tactic') add_lib('arith_tactics', ['core_tactics', 'sat'], 'tactic/arith') add_lib('nlsat_tactic', ['nlsat', 'sat_tactic', 'arith_tactics'], 'nlsat/tactic') add_lib('subpaving_tactic', ['core_tactics', 'subpaving'], 'math/subpaving/tactic') add_lib('aig_tactic', ['tactic'], 'tactic/aig') - add_lib('proofs', ['rewriter', 'util'], 'ast/proofs') - add_lib('solver', ['model', 'tactic', 'proofs']) add_lib('ackermannization', ['model', 'rewriter', 'ast', 'solver', 'tactic'], 'ackermannization') add_lib('interp', ['solver']) add_lib('cmd_context', ['solver', 'rewriter', 'interp']) diff --git a/src/solver/parallel_tactic.cpp b/src/solver/parallel_tactic.cpp index fb1001f32..451a62064 100644 --- a/src/solver/parallel_tactic.cpp +++ b/src/solver/parallel_tactic.cpp @@ -39,13 +39,8 @@ Notes: #include "solver/solver2tactic.h" #include "tactic/tactic.h" #include "tactic/tactical.h" -#include "tactic/portfolio/fd_solver.h" #include "solver/parallel_tactic.h" #include "solver/parallel_params.hpp" -#include "smt/tactic/smt_tactic.h" -#include "smt/smt_solver.h" -#include "sat/sat_solver/inc_sat_solver.h" -#include "sat/tactic/sat_tactic.h" class parallel_tactic : public tactic { diff --git a/src/tactic/arith/elim01_tactic.cpp b/src/tactic/arith/elim01_tactic.cpp deleted file mode 100644 index 46c6f1e1c..000000000 --- a/src/tactic/arith/elim01_tactic.cpp +++ /dev/null @@ -1,267 +0,0 @@ -/*++ -Copyright (c) 2013 Microsoft Corporation - -Module Name: - - elim01_tactic.cpp - -Abstract: - - Replace 0-1 integer variables by Booleans. - -Author: - - Nikolaj Bjorner (nbjorner) 2013-12-7 - -Notes: - ---*/ -#include "tactic/tactical.h" -#include "util/cooperate.h" -#include "tactic/arith/bound_manager.h" -#include "ast/ast_pp.h" -#include "ast/rewriter/expr_safe_replace.h" -#include "ast/arith_decl_plugin.h" -#include "tactic/arith/elim01_tactic.h" -#include "model/model_smt2_pp.h" -#include "ast/rewriter/th_rewriter.h" - -class bool2int_model_converter : public model_converter { - ast_manager& m; - arith_util a; - func_decl_ref_vector m_refs; - obj_hashtable m_bools; - vector > m_nums_as_bool; - ptr_vector m_nums_as_int; -public: - - bool2int_model_converter(ast_manager& m): - m(m), - a(m), - m_refs(m) - {} - - void operator()(model_ref & old_model, unsigned goal_idx) override { - SASSERT(goal_idx == 0); - model * new_model = alloc(model, m); - unsigned num = old_model->get_num_constants(); - for (unsigned i = 0; i < m_nums_as_int.size(); ++i) { - func_decl* f_old = m_nums_as_int[i]; - rational val(0); - rational po(1); - bool is_value = true; - for (unsigned j = 0; is_value && j < m_nums_as_bool[i].size(); ++j) { - func_decl* f = m_nums_as_bool[i][j]; - expr* fi = old_model->get_const_interp(f); - if (!fi) { - is_value = false; - } - else if (m.is_true(fi)) { - val += po; - } - else if (!m.is_false(fi)) { - is_value = false; - } - po *= rational(2); - } - if (is_value) { - expr* fi = a.mk_numeral(val, true); - new_model->register_decl(f_old, fi); - } - } - for (unsigned i = 0; i < num; ++i) { - func_decl* f = old_model->get_constant(i); - expr* fi = old_model->get_const_interp(f); - if (!m_bools.contains(f)) { - new_model->register_decl(f, fi); - } - } - num = old_model->get_num_functions(); - for (unsigned i = 0; i < num; i++) { - func_decl * f = old_model->get_function(i); - func_interp * fi = old_model->get_func_interp(f); - new_model->register_decl(f, fi->copy()); - } - new_model->copy_usort_interps(*old_model); - old_model = new_model; - } - - void insert(func_decl* x_new, func_decl* x_old) { - m_refs.push_back(x_new); - m_refs.push_back(x_old); - m_bools.insert(x_new); - m_nums_as_int.push_back(x_old); - m_nums_as_bool.push_back(ptr_vector()); - m_nums_as_bool.back().push_back(x_new); - } - - void insert(func_decl* x_old, unsigned sz, func_decl * const* x_new) { - m_nums_as_int.push_back(x_old); - m_nums_as_bool.push_back(ptr_vector()); - m_refs.push_back(x_old); - for (unsigned i = 0; i < sz; ++i) { - m_refs.push_back(x_new[i]); - m_nums_as_bool.back().push_back(x_new[i]); - m_bools.insert(x_new[i]); - } - } - - model_converter * translate(ast_translation & translator) override { - bool2int_model_converter* mc = alloc(bool2int_model_converter, translator.to()); - for (unsigned i = 0; i < m_nums_as_int.size(); ++i) { - mc->insert(m_nums_as_int[i], m_nums_as_bool[i].size(), m_nums_as_bool[i].c_ptr()); - } - return mc; - } -}; - - -class elim01_tactic : public tactic { -public: - typedef obj_hashtable expr_set; - ast_manager & m; - arith_util a; - th_rewriter m_rewriter; - params_ref m_params; - unsigned m_max_hi_default; - rational m_max_hi; - - elim01_tactic(ast_manager & _m, params_ref const & p): - m(_m), - a(m), - m_rewriter(m), - m_max_hi_default(8), - m_max_hi(rational(m_max_hi_default)) { - } - - ~elim01_tactic() override { - } - - void updt_params(params_ref const & p) override { - m_max_hi = rational(p.get_uint("max_coefficient", m_max_hi_default)); - m_params = p; - } - - void collect_param_descrs(param_descrs & r) override { - r.insert("max_coefficient", CPK_UINT, "(default: 1) maximal upper bound for finite range -> Bool conversion"); - } - - - void operator()(goal_ref const & g, - goal_ref_buffer & result, - model_converter_ref & mc, - proof_converter_ref & pc, - expr_dependency_ref & core) override { - SASSERT(g->is_well_sorted()); - mc = nullptr; pc = nullptr; core = nullptr; - - tactic_report report("elim01", *g); - - expr_safe_replace sub(m); - bool2int_model_converter* b2i = alloc(bool2int_model_converter, m); - mc = b2i; - bound_manager bounds(m); - expr_ref_vector axioms(m); - bounds(*g); - - rational zero(0); - bound_manager::iterator bit = bounds.begin(), bend = bounds.end(); - for (; bit != bend; ++bit) { - if (!is_app(*bit)) continue; - app* x = to_app(*bit); - bool s1 = false, s2 = false; - rational lo, hi; - if (a.is_int(x) && - bounds.has_lower(x, lo, s1) && !s1 && zero <= lo && - bounds.has_upper(x, hi, s2) && !s2 && hi <= m_max_hi && lo <= hi) { - add_variable(b2i, sub, x, lo.get_unsigned(), hi.get_unsigned(), axioms); - } - else if (a.is_int(x)) { - TRACE("pb", tout << "Not adding variable " << mk_pp(x, m) << " has lower: " - << bounds.has_lower(x, lo, s1) << " " << lo << " has upper: " - << bounds.has_upper(x, hi, s2) << " " << hi << "\n";); - } - } - - if (sub.empty()) { - result.push_back(g.get()); - return; - } - - expr_ref new_curr(m), tmp_curr(m); - proof_ref new_pr(m); - for (unsigned i = 0; i < g->size(); i++) { - expr * curr = g->form(i); - sub(curr, tmp_curr); - m_rewriter(tmp_curr, new_curr); - if (m.proofs_enabled()) { - new_pr = m.mk_rewrite(curr, new_curr); - new_pr = m.mk_modus_ponens(g->pr(i), new_pr); - } - g->update(i, new_curr, new_pr, g->dep(i)); - } - for (unsigned i = 0; i < axioms.size(); ++i) { - g->assert_expr(axioms[i].get()); - } - g->inc_depth(); - result.push_back(g.get()); - TRACE("pb", g->display(tout);); - SASSERT(g->is_well_sorted()); - - // TBD: support proof conversion (or not..) - } - - tactic * translate(ast_manager & m) override { - return alloc(elim01_tactic, m, m_params); - } - - void cleanup() override {} - - void add_variable(bool2int_model_converter* b2i, - expr_safe_replace& sub, - app* x, - unsigned min_value, - unsigned max_value, - expr_ref_vector& axioms) { - std::string name = x->get_decl()->get_name().str(); - unsigned sh = 0; - app_ref_vector xs(m), ites(m); - func_decl_ref_vector xfs(m); - app_ref zero(m), sum(m); - zero = a.mk_numeral(rational(0), true); - while (max_value >= (1ul << sh)) { - xs.push_back(m.mk_fresh_const(name.c_str(), m.mk_bool_sort())); - xfs.push_back(xs.back()->get_decl()); - ites.push_back(m.mk_ite(xs.back(), a.mk_numeral(rational(1 << sh), true), zero)); - ++sh; - } - switch (ites.size()) { - case 0: - sum = zero; - break; - case 1: - sum = ites[0].get(); - break; - default: - sum = a.mk_add(ites.size(), (expr*const*)ites.c_ptr()); - break; - } - TRACE("pb", tout << mk_pp(x, m) << " " << sum << " max: " << max_value << "\n";); - - sub.insert(x, sum); - b2i->insert(x->get_decl(), xfs.size(), xfs.c_ptr()); - // if max_value+1 is not a power of two: - if ((max_value & (max_value + 1)) != 0) { - axioms.push_back(a.mk_le(sum, a.mk_numeral(rational(max_value), true))); - } - if (min_value > 0) { - axioms.push_back(a.mk_ge(sum, a.mk_numeral(rational(min_value), true))); - } - } - -}; - -tactic * mk_elim01_tactic(ast_manager & m, params_ref const & p) { - return clean(alloc(elim01_tactic, m, p)); -} - From 510cb5ee6e9e8e7120b2112707e0ad3535e2f896 Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Wed, 23 May 2018 23:51:36 +0700 Subject: [PATCH 611/637] Z3_TRUE/Z3_FALSE should be true/false, not 1/0. Now that Z3_bool is a C bool, the associated constants should be as well. --- src/api/z3_api.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/api/z3_api.h b/src/api/z3_api.h index 0825f27a0..d5c279d63 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -83,14 +83,14 @@ typedef const char * Z3_string; typedef Z3_string * Z3_string_ptr; /** - \brief True value. It is just an alias for \c 1. + \brief True value. It is just an alias for \c true. */ -#define Z3_TRUE 1 +#define Z3_TRUE true /** - \brief False value. It is just an alias for \c 0. + \brief False value. It is just an alias for \c false. */ -#define Z3_FALSE 0 +#define Z3_FALSE false /** \brief Lifted Boolean type: \c false, \c undefined, \c true. From a3facc82fb61888557980b392431e298c9add8e3 Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Wed, 23 May 2018 23:52:51 +0700 Subject: [PATCH 612/637] Update OCaml docs for changes made elsewhere. This removes references to the PROOF_MODE that have been removed elsewhere. --- src/api/ml/z3.mli | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/api/ml/z3.mli b/src/api/ml/z3.mli index 14d2ceac4..0fd1242ee 100644 --- a/src/api/ml/z3.mli +++ b/src/api/ml/z3.mli @@ -2362,7 +2362,7 @@ sig (** Indicates whether the term is a proof by condensed transitivity of a relation - Condensed transitivity proof. This proof object is only used if the parameter PROOF_MODE is 1. + Condensed transitivity proof. It combines several symmetry and transitivity proofs. Example: T1: (R a b) @@ -2443,14 +2443,11 @@ sig (** Indicates whether the term is a proof by rewriting A proof for rewriting an expression t into an expression s. - This proof object is used if the parameter PROOF_MODE is 1. This proof object can have n antecedents. The antecedents are proofs for equalities used as substitution rules. - The object is also used in a few cases if the parameter PROOF_MODE is 2. - The cases are: + The object is also used in a few cases. The cases are: - When applying contextual simplification (CONTEXT_SIMPLIFIER=true) - When converting bit-vectors to Booleans (BIT2BOOL=true) - - When pulling ite expression up (PULL_CHEAP_ITE_TREES=true) *) val is_rewrite_star : Expr.expr -> bool (** Indicates whether the term is a proof for pulling quantifiers out. From 6db90a9333c0e44fca53cfb4d463c1a5189de6cb Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Wed, 23 May 2018 23:58:08 +0700 Subject: [PATCH 613/637] Fix missing word in C++ API docs. --- src/api/c++/z3++.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index 8d7825335..eef5d7904 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -187,7 +187,7 @@ namespace z3 { \brief The C++ API uses by defaults exceptions on errors. For applications that don't work well with exceptions (there should be only few) you have the ability to turn off exceptions. The tradeoffs are that applications - have to very careful about using check_error() after calls that may result in an + have to be very careful about using check_error() after calls that may result in an erroneous state. */ void set_enable_exceptions(bool f) { m_enable_exceptions = f; } From f9bdfe297853f3a318bbbd9e8485cf2759204afd Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 23 May 2018 10:30:14 -0700 Subject: [PATCH 614/637] fix x86 warning Signed-off-by: Nikolaj Bjorner --- src/sat/sat_clause.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/sat/sat_clause.cpp b/src/sat/sat_clause.cpp index 70378d9c6..3cbd3015b 100644 --- a/src/sat/sat_clause.cpp +++ b/src/sat/sat_clause.cpp @@ -111,18 +111,22 @@ namespace sat { clause_offset clause::get_new_offset() const { unsigned o1 = m_lits[0].index(); +#if defined(_AMD64_) || defined(_M_IA64) if (sizeof(clause_offset) == 8) { unsigned o2 = m_lits[1].index(); return (clause_offset)o1 + (((clause_offset)o2) << 32); } +#endif return (clause_offset)o1; } void clause::set_new_offset(clause_offset offset) { m_lits[0] = to_literal(static_cast(offset)); +#if defined(_AMD64_) || defined(_M_IA64) if (sizeof(offset) == 8) { m_lits[1] = to_literal(static_cast(offset >> 32)); } +#endif } From 278fd03f196db4972352aa8f26c0f98077872888 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 23 May 2018 13:31:26 -0700 Subject: [PATCH 615/637] GLU -> GNU fix #1643 Signed-off-by: Nikolaj Bjorner --- src/sat/sat_solver.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 2c05cc52c..15d941b5b 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -800,7 +800,7 @@ namespace sat { } if (m_config.m_propagate_prefetch) { -#if defined(__GLUC__) || defined(__clang__) +#if defined(__GNUC__) || defined(__clang__) __builtin_prefetch((const char*)((m_watches[l.index()].c_ptr()))); #else _mm_prefetch((const char*)((m_watches[l.index()].c_ptr())), _MM_HINT_T1); From 2e4fb8d356005a41a93a75707e47fa4c38106566 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 23 May 2018 16:33:27 -0700 Subject: [PATCH 616/637] work around VS2012 compiler bug Signed-off-by: Nikolaj Bjorner --- src/sat/sat_solver.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/sat/sat_solver.cpp b/src/sat/sat_solver.cpp index 15d941b5b..a59dd2b46 100644 --- a/src/sat/sat_solver.cpp +++ b/src/sat/sat_solver.cpp @@ -3241,9 +3241,10 @@ namespace sat { bool_var solver::max_var(clause_vector& clauses, bool_var v) { for (clause* cp : clauses) - for (literal l : *cp) - if (l.var() > v) - v = l.var(); + for (auto it = cp->begin(), end = cp->end(); it != end; ++it) { + if (it->var() > v) + v = it->var(); + } return v; } From d088a1b9f6697d9663fe3ee3afad7a8bad06875e Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 23 May 2018 18:25:14 -0700 Subject: [PATCH 617/637] updated release notes for merge Signed-off-by: Nikolaj Bjorner --- RELEASE_NOTES | 31 +++++++++++++++++++++++++++++++ src/util/lp/bound_propagator.h | 27 --------------------------- 2 files changed, 31 insertions(+), 27 deletions(-) delete mode 100644 src/util/lp/bound_propagator.h diff --git a/RELEASE_NOTES b/RELEASE_NOTES index a99ec6b1e..67aa3d810 100644 --- a/RELEASE_NOTES +++ b/RELEASE_NOTES @@ -1,5 +1,36 @@ RELEASE NOTES +Version 4.8.0 +============= + +- New requirements: + - A breaking change to the API is that parsers for SMT-LIB2 formulas return a vector of + formulas as opposed to a conjunction of formulas. The vector of formulas correspond to + the set of "assert" instructions in the SMT-LIB input. + +- New features + - A parallel mode is available for select theories, including QF_BV. + By setting parallel.enable=true Z3 will spawn a number of worker threads proportional to the + number of available CPU cores to apply cube and conquer solving on the goal. + - The SAT solver by default handle cardinality and PB constraints using a custom plugin + that operates directly on cardinality and PB constraints. + - A "cube" interface is exposed over the solver API. + - Model conversion is first class over the textual API, such that subgoals created from running a + solver can be passed in text files and a model for the original formula can be recreated from the result. + - This has also led to changes in how models are tracked over tactic subgoals. The API for + extracting models from apply_result have been replaced. + - An optional mode handles xor constraints using a custom xor propagator. + It is off by default and its value not demonstrated. + - The SAT solver includes new inprocessing technques that are available during simplification. + It performs asymmetric tautology elimination by default, and one can turn on more powerful inprocessing techniques + (known as ACCE, ABCE, CCE). Asymmetric branching also uses features introduced in Lingeling by exploiting binary implication graphs. + Use sat.acce=true to enable the full repertoire of inprocessing methods. By default, clauses that are "eliminated" by acce are tagged + as lemmas (redundant) and are garbage collected if their glue level is high. + +- Removed features: + - long deprecated API functions have been removed from z3_api.h + + Version 4.7.1 ============= diff --git a/src/util/lp/bound_propagator.h b/src/util/lp/bound_propagator.h deleted file mode 100644 index 128973c12..000000000 --- a/src/util/lp/bound_propagator.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - Copyright (c) 2017 Microsoft Corporation - Author: Lev Nachmanson -*/ -#pragma once -#include "util/lp/lp_settings.h" -namespace lp { -class lar_solver; -class bound_propagator { - std::unordered_map m_improved_low_bounds; // these maps map a column index to the corresponding index in ibounds - std::unordered_map m_improved_upper_bounds; - lar_solver & m_lar_solver; -public: - vector m_ibounds; -public: - bound_propagator(lar_solver & ls); - column_type get_column_type(unsigned) const; - const impq & get_low_bound(unsigned) const; - const impq & get_upper_bound(unsigned) const; - void try_add_bound(mpq v, unsigned j, bool is_low, bool coeff_before_j_is_pos, unsigned row_or_term_index, bool strict); - virtual bool bound_is_interesting(unsigned vi, - lp::lconstraint_kind kind, - const rational & bval) {return true;} - unsigned number_of_found_bounds() const { return m_ibounds.size(); } - virtual void consume(mpq const& v, unsigned j) { std::cout << "doh\n"; } -}; -} From 4f5775c531dff15dd5ecfca02651766b29c8c04f Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 24 May 2018 08:33:19 -0700 Subject: [PATCH 618/637] remove interpolation and duality dependencies Signed-off-by: Nikolaj Bjorner --- RELEASE_NOTES | 2 +- src/CMakeLists.txt | 5 - src/api/CMakeLists.txt | 2 - src/api/api_ast.cpp | 2 - src/api/dotnet/CMakeLists.txt | 1 - src/api/dotnet/InterpolationContext.cs | 161 - src/api/java/CMakeLists.txt | 1 - src/api/java/InterpolationContext.java | 210 -- src/api/z3.h | 1 - src/api/z3_api.h | 3 - src/api/z3_interp.h | 283 -- src/ast/ast.cpp | 7 - src/ast/ast.h | 4 +- src/cmd_context/CMakeLists.txt | 2 - src/cmd_context/cmd_context.cpp | 2 - src/cmd_context/interpolant_cmds.cpp | 263 -- src/cmd_context/interpolant_cmds.h | 24 - src/duality/CMakeLists.txt | 11 - src/duality/duality.h | 1365 ------- src/duality/duality_profiling.cpp | 144 - src/duality/duality_profiling.h | 38 - src/duality/duality_rpfp.cpp | 4250 ---------------------- src/duality/duality_solver.cpp | 3601 ------------------ src/duality/duality_wrapper.cpp | 744 ---- src/duality/duality_wrapper.h | 1489 -------- src/interp/CMakeLists.txt | 18 - src/interp/interp_params.pyg | 6 - src/interp/iz3base.cpp | 372 -- src/interp/iz3base.h | 195 - src/interp/iz3checker.cpp | 227 -- src/interp/iz3checker.h | 49 - src/interp/iz3exception.h | 28 - src/interp/iz3hash.h | 479 --- src/interp/iz3interp.cpp | 578 --- src/interp/iz3interp.h | 123 - src/interp/iz3mgr.cpp | 969 ----- src/interp/iz3mgr.h | 738 ---- src/interp/iz3pp.cpp | 185 - src/interp/iz3pp.h | 36 - src/interp/iz3profiling.cpp | 153 - src/interp/iz3profiling.h | 37 - src/interp/iz3proof.cpp | 628 ---- src/interp/iz3proof.h | 274 -- src/interp/iz3proof_itp.cpp | 3117 ---------------- src/interp/iz3proof_itp.h | 143 - src/interp/iz3scopes.cpp | 321 -- src/interp/iz3scopes.h | 222 -- src/interp/iz3secondary.h | 40 - src/interp/iz3translate.cpp | 2200 ----------- src/interp/iz3translate.h | 63 - src/interp/iz3translate_direct.cpp | 1717 --------- src/muz/base/dl_context.cpp | 15 +- src/muz/base/dl_engine_base.h | 1 - src/muz/duality/CMakeLists.txt | 8 - src/muz/duality/duality_dl_interface.cpp | 623 ---- src/muz/duality/duality_dl_interface.h | 80 - src/muz/fp/CMakeLists.txt | 1 - src/muz/fp/dl_register_engine.cpp | 3 - src/smt/smt_internalizer.cpp | 1 - 59 files changed, 3 insertions(+), 26262 deletions(-) delete mode 100644 src/api/dotnet/InterpolationContext.cs delete mode 100644 src/api/java/InterpolationContext.java delete mode 100644 src/api/z3_interp.h delete mode 100644 src/cmd_context/interpolant_cmds.cpp delete mode 100644 src/cmd_context/interpolant_cmds.h delete mode 100644 src/duality/CMakeLists.txt delete mode 100644 src/duality/duality.h delete mode 100644 src/duality/duality_profiling.cpp delete mode 100755 src/duality/duality_profiling.h delete mode 100644 src/duality/duality_rpfp.cpp delete mode 100644 src/duality/duality_solver.cpp delete mode 100644 src/duality/duality_wrapper.cpp delete mode 100644 src/duality/duality_wrapper.h delete mode 100644 src/interp/CMakeLists.txt delete mode 100644 src/interp/interp_params.pyg delete mode 100644 src/interp/iz3base.cpp delete mode 100755 src/interp/iz3base.h delete mode 100644 src/interp/iz3checker.cpp delete mode 100644 src/interp/iz3checker.h delete mode 100644 src/interp/iz3exception.h delete mode 100644 src/interp/iz3hash.h delete mode 100644 src/interp/iz3interp.cpp delete mode 100644 src/interp/iz3interp.h delete mode 100644 src/interp/iz3mgr.cpp delete mode 100644 src/interp/iz3mgr.h delete mode 100644 src/interp/iz3pp.cpp delete mode 100644 src/interp/iz3pp.h delete mode 100644 src/interp/iz3profiling.cpp delete mode 100755 src/interp/iz3profiling.h delete mode 100755 src/interp/iz3proof.cpp delete mode 100644 src/interp/iz3proof.h delete mode 100755 src/interp/iz3proof_itp.cpp delete mode 100644 src/interp/iz3proof_itp.h delete mode 100755 src/interp/iz3scopes.cpp delete mode 100755 src/interp/iz3scopes.h delete mode 100755 src/interp/iz3secondary.h delete mode 100644 src/interp/iz3translate.cpp delete mode 100755 src/interp/iz3translate.h delete mode 100644 src/interp/iz3translate_direct.cpp delete mode 100644 src/muz/duality/CMakeLists.txt delete mode 100644 src/muz/duality/duality_dl_interface.cpp delete mode 100644 src/muz/duality/duality_dl_interface.h diff --git a/RELEASE_NOTES b/RELEASE_NOTES index 67aa3d810..a2b526550 100644 --- a/RELEASE_NOTES +++ b/RELEASE_NOTES @@ -35,7 +35,7 @@ Version 4.7.1 ============= - New requirements: - - uses stdbool and stdint as part of z3.h + - uses stdbool and stdint as part of z3. - New features: - none diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d8a773747..9020c9e4b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -12,7 +12,6 @@ set(Z3_API_HEADER_FILES_TO_SCAN z3_rcf.h z3_fixedpoint.h z3_optimization.h - z3_interp.h z3_fpa.h z3_spacer.h ) @@ -63,7 +62,6 @@ add_subdirectory(sat/tactic) add_subdirectory(tactic/arith) add_subdirectory(nlsat/tactic) add_subdirectory(ackermannization) -add_subdirectory(interp) add_subdirectory(cmd_context) add_subdirectory(cmd_context/extra_cmds) add_subdirectory(parsers/smt2) @@ -79,7 +77,6 @@ add_subdirectory(tactic/bv) add_subdirectory(smt/tactic) add_subdirectory(tactic/sls) add_subdirectory(qe) -add_subdirectory(duality) add_subdirectory(muz/base) add_subdirectory(muz/dataflow) add_subdirectory(muz/transforms) @@ -89,7 +86,6 @@ add_subdirectory(muz/clp) add_subdirectory(muz/tab) add_subdirectory(muz/bmc) add_subdirectory(muz/ddnf) -add_subdirectory(muz/duality) add_subdirectory(muz/spacer) add_subdirectory(muz/fp) add_subdirectory(tactic/ufbv) @@ -159,7 +155,6 @@ set (libz3_public_headers z3_fpa.h z3.h c++/z3++.h - z3_interp.h z3_macros.h z3_optimization.h z3_polynomial.h diff --git a/src/api/CMakeLists.txt b/src/api/CMakeLists.txt index fcdbb1651..4a5514a7b 100644 --- a/src/api/CMakeLists.txt +++ b/src/api/CMakeLists.txt @@ -48,7 +48,6 @@ z3_add_component(api api_datatype.cpp api_fpa.cpp api_goal.cpp - api_interp.cpp api_log.cpp api_model.cpp api_numeral.cpp @@ -67,7 +66,6 @@ z3_add_component(api z3_replayer.cpp ${full_path_generated_files} COMPONENT_DEPENDENCIES - interp opt portfolio realclosure diff --git a/src/api/api_ast.cpp b/src/api/api_ast.cpp index 1f4a86903..536b94fb2 100644 --- a/src/api/api_ast.cpp +++ b/src/api/api_ast.cpp @@ -195,7 +195,6 @@ extern "C" { MK_BINARY(Z3_mk_xor, mk_c(c)->get_basic_fid(), OP_XOR, SKIP); MK_NARY(Z3_mk_and, mk_c(c)->get_basic_fid(), OP_AND, SKIP); MK_NARY(Z3_mk_or, mk_c(c)->get_basic_fid(), OP_OR, SKIP); - MK_UNARY(Z3_mk_interpolant, mk_c(c)->get_basic_fid(), OP_INTERP, SKIP); Z3_ast mk_ite_core(Z3_context c, Z3_ast t1, Z3_ast t2, Z3_ast t3) { expr * result = mk_c(c)->m().mk_ite(to_expr(t1), to_expr(t2), to_expr(t3)); @@ -900,7 +899,6 @@ extern "C" { case OP_NOT: return Z3_OP_NOT; case OP_IMPLIES: return Z3_OP_IMPLIES; case OP_OEQ: return Z3_OP_OEQ; - case OP_INTERP: return Z3_OP_INTERP; case PR_UNDEF: return Z3_OP_PR_UNDEF; case PR_TRUE: return Z3_OP_PR_TRUE; diff --git a/src/api/dotnet/CMakeLists.txt b/src/api/dotnet/CMakeLists.txt index add1b0ded..76516bf39 100644 --- a/src/api/dotnet/CMakeLists.txt +++ b/src/api/dotnet/CMakeLists.txt @@ -80,7 +80,6 @@ set(Z3_DOTNET_ASSEMBLY_SOURCES_IN_SRC_TREE Global.cs Goal.cs IDecRefQueue.cs - InterpolationContext.cs IntExpr.cs IntNum.cs IntSort.cs diff --git a/src/api/dotnet/InterpolationContext.cs b/src/api/dotnet/InterpolationContext.cs deleted file mode 100644 index e2b814983..000000000 --- a/src/api/dotnet/InterpolationContext.cs +++ /dev/null @@ -1,161 +0,0 @@ - -/*++ -Copyright (c) 2015 Microsoft Corporation - ---*/ - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Diagnostics.Contracts; -using System.Runtime.InteropServices; - -namespace Microsoft.Z3 -{ - /// - /// The InterpolationContext is suitable for generation of interpolants. - /// - /// For more information on interpolation please refer - /// too the C/C++ API, which is well documented. - [ContractVerification(true)] - public class InterpolationContext : Context - { - - /// - /// Constructor. - /// - public InterpolationContext() : base() { } - - /// - /// Constructor. - /// - /// - public InterpolationContext(Dictionary settings) : base(settings) { } - - #region Terms - /// - /// Create an expression that marks a formula position for interpolation. - /// - public BoolExpr MkInterpolant(BoolExpr a) - { - Contract.Requires(a != null); - Contract.Ensures(Contract.Result() != null); - - CheckContextMatch(a); - return new BoolExpr(this, Native.Z3_mk_interpolant(nCtx, a.NativeObject)); - } - #endregion - - /// - /// Computes an interpolant. - /// - /// For more information on interpolation please refer - /// too the function Z3_get_interpolant in the C/C++ API, which is - /// well documented. - public BoolExpr[] GetInterpolant(Expr pf, Expr pat, Params p) - { - Contract.Requires(pf != null); - Contract.Requires(pat != null); - Contract.Requires(p != null); - Contract.Ensures(Contract.Result() != null); - - CheckContextMatch(pf); - CheckContextMatch(pat); - CheckContextMatch(p); - - ASTVector seq = new ASTVector(this, Native.Z3_get_interpolant(nCtx, pf.NativeObject, pat.NativeObject, p.NativeObject)); - return seq.ToBoolExprArray(); - } - - /// - /// Computes an interpolant. - /// - /// For more information on interpolation please refer - /// too the function Z3_compute_interpolant in the C/C++ API, which is - /// well documented. - public Z3_lbool ComputeInterpolant(Expr pat, Params p, out BoolExpr[] interp, out Model model) - { - Contract.Requires(pat != null); - Contract.Requires(p != null); - Contract.Ensures(Contract.ValueAtReturn(out interp) != null); - Contract.Ensures(Contract.ValueAtReturn(out model) != null); - - CheckContextMatch(pat); - CheckContextMatch(p); - - IntPtr i = IntPtr.Zero, m = IntPtr.Zero; - int r = Native.Z3_compute_interpolant(nCtx, pat.NativeObject, p.NativeObject, ref i, ref m); - interp = new ASTVector(this, i).ToBoolExprArray(); - model = new Model(this, m); - return (Z3_lbool)r; - } - - /// - /// Return a string summarizing cumulative time used for interpolation. - /// - /// For more information on interpolation please refer - /// too the function Z3_interpolation_profile in the C/C++ API, which is - /// well documented. - public string InterpolationProfile() - { - return Native.Z3_interpolation_profile(nCtx); - } - - /// - /// Checks the correctness of an interpolant. - /// - /// For more information on interpolation please refer - /// too the function Z3_check_interpolant in the C/C++ API, which is - /// well documented. - public int CheckInterpolant(Expr[] cnsts, uint[] parents, BoolExpr[] interps, out string error, Expr[] theory) - { - Contract.Requires(cnsts.Length == parents.Length); - Contract.Requires(cnsts.Length == interps.Length + 1); - IntPtr n_err_str; - int r = Native.Z3_check_interpolant(nCtx, - (uint)cnsts.Length, - Expr.ArrayToNative(cnsts), - parents, - Expr.ArrayToNative(interps), - out n_err_str, - (uint)theory.Length, - Expr.ArrayToNative(theory)); - error = Marshal.PtrToStringAnsi(n_err_str); - return r; - } - - /// - /// Reads an interpolation problem from a file. - /// - /// For more information on interpolation please refer - /// too the function Z3_read_interpolation_problem in the C/C++ API, which is - /// well documented. - public int ReadInterpolationProblem(string filename, out Expr[] cnsts, out uint[] parents, out string error, out Expr[] theory) - { - uint num = 0; - IntPtr n_err_str; - ASTVector _cnsts = new ASTVector(this); - ASTVector _theory = new ASTVector(this); - - int r = Native.Z3_read_interpolation_problem(nCtx, _cnsts.NativeObject, ref num, out parents, filename, out n_err_str, _theory.NativeObject); - error = Marshal.PtrToStringAnsi(n_err_str); - cnsts = _cnsts.ToExprArray(); - parents = new uint[num]; - theory = _theory.ToExprArray(); - return r; - } - - /// - /// Writes an interpolation problem to a file. - /// - /// For more information on interpolation please refer - /// too the function Z3_write_interpolation_problem in the C/C++ API, which is - /// well documented. - public void WriteInterpolationProblem(string filename, Expr[] cnsts, uint[] parents, Expr[] theory) - { - Contract.Requires(cnsts.Length == parents.Length); - Native.Z3_write_interpolation_problem(nCtx, (uint)cnsts.Length, Expr.ArrayToNative(cnsts), parents, filename, (uint)theory.Length, Expr.ArrayToNative(theory)); - } - } -} diff --git a/src/api/java/CMakeLists.txt b/src/api/java/CMakeLists.txt index dce2bc4ea..7f0774955 100644 --- a/src/api/java/CMakeLists.txt +++ b/src/api/java/CMakeLists.txt @@ -137,7 +137,6 @@ set(Z3_JAVA_JAR_SOURCE_FILES GoalDecRefQueue.java Goal.java IDecRefQueue.java - InterpolationContext.java IntExpr.java IntNum.java IntSort.java diff --git a/src/api/java/InterpolationContext.java b/src/api/java/InterpolationContext.java deleted file mode 100644 index bce789807..000000000 --- a/src/api/java/InterpolationContext.java +++ /dev/null @@ -1,210 +0,0 @@ -/** -Copyright (c) 2012-2014 Microsoft Corporation - -Module Name: - - InterpolationContext.java - -Abstract: - -Author: - - @author Christoph Wintersteiger (cwinter) 2012-03-15 - -Notes: - -**/ - -package com.microsoft.z3; - -import com.microsoft.z3.enumerations.Z3_lbool; - -import java.util.Map; - -/** - * The InterpolationContext is suitable for generation of interpolants. - * - * Remarks: For more information on interpolation please refer - * too the C/C++ API, which is well documented. - **/ -public class InterpolationContext extends Context -{ - /** - * Constructor. - **/ - public static InterpolationContext mkContext() - { - long m_ctx; - synchronized(creation_lock) { - m_ctx = Native.mkInterpolationContext(0); - } - return new InterpolationContext(m_ctx); - } - - /** - * Constructor. - * - * - * Remarks: - * @see Context#Context - **/ - public static InterpolationContext mkContext(Map settings) - { - long m_ctx; - synchronized(creation_lock) { - long cfg = Native.mkConfig(); - for (Map.Entry kv : settings.entrySet()) - Native.setParamValue(cfg, kv.getKey(), kv.getValue()); - m_ctx = Native.mkInterpolationContext(cfg); - Native.delConfig(cfg); - } - return new InterpolationContext(m_ctx); - } - - private InterpolationContext(long m_ctx) { - super(m_ctx); - } - - /** - * Create an expression that marks a formula position for interpolation. - * @throws Z3Exception - **/ - public BoolExpr MkInterpolant(BoolExpr a) - { - checkContextMatch(a); - return new BoolExpr(this, Native.mkInterpolant(nCtx(), a.getNativeObject())); - } - - /** - * Computes an interpolant. - * Remarks: For more information on interpolation please refer - * too the function Z3_get_interpolant in the C/C++ API, which is - * well documented. - * @throws Z3Exception - **/ - public BoolExpr[] GetInterpolant(Expr pf, Expr pat, Params p) - { - checkContextMatch(pf); - checkContextMatch(pat); - checkContextMatch(p); - - ASTVector seq = new ASTVector(this, Native.getInterpolant(nCtx(), pf.getNativeObject(), pat.getNativeObject(), p.getNativeObject())); - return seq.ToBoolExprArray(); - } - - public class ComputeInterpolantResult - { - public Z3_lbool status = Z3_lbool.Z3_L_UNDEF; - public BoolExpr[] interp = null; - public Model model = null; - }; - - /** - * Computes an interpolant. - * Remarks: For more information on interpolation please refer - * too the function Z3_compute_interpolant in the C/C++ API, which is - * well documented. - * @throws Z3Exception - **/ - public ComputeInterpolantResult ComputeInterpolant(Expr pat, Params p) - { - checkContextMatch(pat); - checkContextMatch(p); - - ComputeInterpolantResult res = new ComputeInterpolantResult(); - Native.LongPtr n_i = new Native.LongPtr(); - Native.LongPtr n_m = new Native.LongPtr(); - res.status = Z3_lbool.fromInt(Native.computeInterpolant(nCtx(), pat.getNativeObject(), p.getNativeObject(), n_i, n_m)); - if (res.status == Z3_lbool.Z3_L_FALSE) - res.interp = (new ASTVector(this, n_i.value)).ToBoolExprArray(); - if (res.status == Z3_lbool.Z3_L_TRUE) - res.model = new Model(this, n_m.value); - return res; - } - - /// - /// Return a string summarizing cumulative time used for interpolation. - /// - /// Remarks: For more information on interpolation please refer - /// too the function Z3_interpolation_profile in the C/C++ API, which is - /// well documented. - public String InterpolationProfile() - { - return Native.interpolationProfile(nCtx()); - } - - public class CheckInterpolantResult - { - public int return_value = 0; - public String error = null; - } - - /// - /// Checks the correctness of an interpolant. - /// - /// Remarks: For more information on interpolation please refer - /// too the function Z3_check_interpolant in the C/C++ API, which is - /// well documented. - public CheckInterpolantResult CheckInterpolant(Expr[] cnsts, int[] parents, BoolExpr[] interps, String error, Expr[] theory) - { - CheckInterpolantResult res = new CheckInterpolantResult(); - Native.StringPtr n_err_str = new Native.StringPtr(); - res.return_value = Native.checkInterpolant(nCtx(), - cnsts.length, - Expr.arrayToNative(cnsts), - parents, - Expr.arrayToNative(interps), - n_err_str, - theory.length, - Expr.arrayToNative(theory)); - res.error = n_err_str.value; - return res; - } - - public class ReadInterpolationProblemResult - { - public int return_value = 0; - public Expr[] cnsts; - public int[] parents; - public String error; - public Expr[] theory; - }; - - /// - /// Reads an interpolation problem from a file. - /// - /// Remarks: For more information on interpolation please refer - /// too the function Z3_read_interpolation_problem in the C/C++ API, which is - /// well documented. - public ReadInterpolationProblemResult ReadInterpolationProblem(String filename) - { - ReadInterpolationProblemResult res = new ReadInterpolationProblemResult(); - Native.UIntArrayPtr n_parents = new Native.UIntArrayPtr(); - ASTVector _cnsts = new ASTVector(this); - ASTVector _theory = new ASTVector(this); - Native.StringPtr n_err_str = new Native.StringPtr(); - Native.IntPtr n_num = new Native.IntPtr(); - res.return_value = Native.readInterpolationProblem(nCtx(), _cnsts.getNativeObject(), n_num, - n_parents, filename, n_err_str, _theory.getNativeObject()); - res.error = n_err_str.value; - res.theory = _theory.ToExprArray(); - res.cnsts = _cnsts.ToExprArray(); - int num = n_num.value; - res.parents = new int[num]; - for (int i = 0; i < num; i++) { - res.parents[i] = n_parents.value[i]; - } - return res; - } - - /// - /// Writes an interpolation problem to a file. - /// - /// Remarks: For more information on interpolation please refer - /// too the function Z3_write_interpolation_problem in the C/C++ API, which is - /// well documented. - public void WriteInterpolationProblem(String filename, Expr[] cnsts, int[] parents, String error, Expr[] theory) - { - Native.writeInterpolationProblem(nCtx(), cnsts.length, Expr.arrayToNative(cnsts), parents, filename, theory.length, Expr.arrayToNative(theory)); - } -} diff --git a/src/api/z3.h b/src/api/z3.h index 37ea68f84..382bc4b07 100644 --- a/src/api/z3.h +++ b/src/api/z3.h @@ -32,7 +32,6 @@ Notes: #include "z3_rcf.h" #include "z3_fixedpoint.h" #include "z3_optimization.h" -#include "z3_interp.h" #include "z3_fpa.h" #include "z3_spacer.h" #endif diff --git a/src/api/z3_api.h b/src/api/z3_api.h index d5c279d63..3e47833b4 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -212,8 +212,6 @@ typedef enum - Z3_OP_OEQ Binary equivalence modulo namings. This binary predicate is used in proof terms. It captures equisatisfiability and equivalence modulo renamings. - - Z3_OP_INTERP Marks a sub-formula for interpolation. - - Z3_OP_ANUM Arithmetic numeral. - Z3_OP_AGNUM Arithmetic algebraic numeral. Algebraic numbers are used to represent irrational numbers in Z3. @@ -991,7 +989,6 @@ typedef enum { Z3_OP_NOT, Z3_OP_IMPLIES, Z3_OP_OEQ, - Z3_OP_INTERP, // Arithmetic Z3_OP_ANUM = 0x200, diff --git a/src/api/z3_interp.h b/src/api/z3_interp.h deleted file mode 100644 index 765870bd5..000000000 --- a/src/api/z3_interp.h +++ /dev/null @@ -1,283 +0,0 @@ -/*++ -Copyright (c) 2014 Microsoft Corporation - -Module Name: - - z3_interp.h - -Abstract: - - API for interpolation - -Author: - - Kenneth McMillan (kenmcmil) - -Notes: - ---*/ -#ifndef Z3_INTERPOLATION_H_ -#define Z3_INTERPOLATION_H_ - -#ifdef __cplusplus -extern "C" { -#endif // __cplusplus - - /** \defgroup capi C API */ - /*@{*/ - - /** @name Interpolation facilities */ - /*@{*/ - /** - \brief Create an AST node marking a formula position for interpolation. - - The node \c a must have Boolean sort. - - def_API('Z3_mk_interpolant', AST, (_in(CONTEXT), _in(AST))) - */ - Z3_ast Z3_API Z3_mk_interpolant(Z3_context c, Z3_ast a); - - - /** \brief This function generates a Z3 context suitable for generation of - interpolants. Formulas can be generated as abstract syntax trees in - this context using the Z3 C API. - - Interpolants are also generated as AST's in this context. - - If cfg is non-null, it will be used as the base configuration - for the Z3 context. This makes it possible to set Z3 options - to be used during interpolation. This feature should be used - with some caution however, as it may be that certain Z3 options - are incompatible with interpolation. - - def_API('Z3_mk_interpolation_context', CONTEXT, (_in(CONFIG),)) - - */ - - Z3_context Z3_API Z3_mk_interpolation_context(Z3_config cfg); - - /** Compute an interpolant from a refutation. This takes a proof of - "false" from a set of formulas C, and an interpolation - pattern. The pattern pat is a formula combining the formulas in C - using logical conjunction and the "interp" operator (see - #Z3_mk_interpolant). This interp operator is logically the identity - operator. It marks the sub-formulas of the pattern for which interpolants should - be computed. The interpolant is a map sigma from marked subformulas to - formulas, such that, for each marked subformula phi of pat (where phi sigma - is phi with sigma(psi) substituted for each subformula psi of phi such that - psi in dom(sigma)): - - 1) phi sigma implies sigma(phi), and - - 2) sigma(phi) is in the common uninterpreted vocabulary between - the formulas of C occurring in phi and those not occurring in - phi - - and moreover pat sigma implies false. In the simplest case - an interpolant for the pattern "(and (interp A) B)" maps A - to an interpolant for A /\ B. - - The return value is a vector of formulas representing sigma. The - vector contains sigma(phi) for each marked subformula of pat, in - pre-order traversal. This means that subformulas of phi occur before phi - in the vector. Also, subformulas that occur multiply in pat will - occur multiply in the result vector. - - In particular, calling Z3_get_interpolant on a pattern of the - form (interp ... (interp (and (interp A_1) A_2)) ... A_N) will - result in a sequence interpolant for A_1, A_2,... A_N. - - Neglecting interp markers, the pattern must be a conjunction of - formulas in C, the set of premises of the proof. Otherwise an - error is flagged. - - Any premises of the proof not present in the pattern are - treated as "background theory". Predicate and function symbols - occurring in the background theory are treated as interpreted and - thus always allowed in the interpolant. - - Interpolant may not necessarily be computable from all - proofs. To be sure an interpolant can be computed, the proof - must be generated by an SMT solver for which interpolation is - supported, and the premises must be expressed using only - theories and operators for which interpolation is supported. - - Currently, the only SMT solver that is supported is the legacy - SMT solver. Such a solver is available as the default solver in - \c Z3_context objects produced by #Z3_mk_interpolation_context. - Currently, the theories supported are equality with - uninterpreted functions, linear integer arithmetic, and the - theory of arrays (in SMT-LIB terms, this is AUFLIA). - Quantifiers are allowed. Use of any other operators (including - "labels") may result in failure to compute an interpolant from a - proof. - - Parameters: - - \param c logical context. - \param pf a refutation from premises (assertions) C - \param pat an interpolation pattern over C - \param p parameters - - def_API('Z3_get_interpolant', AST_VECTOR, (_in(CONTEXT), _in(AST), _in(AST), _in(PARAMS))) - */ - - Z3_ast_vector Z3_API Z3_get_interpolant(Z3_context c, Z3_ast pf, Z3_ast pat, Z3_params p); - - /* Compute an interpolant for an unsatisfiable conjunction of formulas. - - This takes as an argument an interpolation pattern as in - #Z3_get_interpolant. This is a conjunction, some subformulas of - which are marked with the "interp" operator (see #Z3_mk_interpolant). - - The conjunction is first checked for unsatisfiability. The result - of this check is returned in the out parameter "status". If the result - is unsat, an interpolant is computed from the refutation as in #Z3_get_interpolant - and returned as a vector of formulas. Otherwise the return value is - an empty formula. - - See #Z3_get_interpolant for a discussion of supported theories. - - The advantage of this function over #Z3_get_interpolant is that - it is not necessary to create a suitable SMT solver and generate - a proof. The disadvantage is that it is not possible to use the - solver incrementally. - - Parameters: - - \param c logical context. - \param pat an interpolation pattern - \param p parameters for solver creation - \param status returns the status of the sat check - \param model returns model if satisfiable - - Return value: status of SAT check - - def_API('Z3_compute_interpolant', INT, (_in(CONTEXT), _in(AST), _in(PARAMS), _out(AST_VECTOR), _out(MODEL))) - */ - - Z3_lbool Z3_API Z3_compute_interpolant(Z3_context c, - Z3_ast pat, - Z3_params p, - Z3_ast_vector *interp, - Z3_model *model); - - /** Return a string summarizing cumulative time used for - interpolation. This string is purely for entertainment purposes - and has no semantics. - - \param ctx The context (currently ignored) - - - def_API('Z3_interpolation_profile', STRING, (_in(CONTEXT),)) - */ - - Z3_string Z3_API Z3_interpolation_profile(Z3_context ctx); - - /** - \brief Read an interpolation problem from file. - - \param ctx The Z3 context. This resets the error handler of ctx. - \param filename The file name to read. - \param num Returns length of sequence. - \param cnsts Returns sequence of formulas (do not free) - \param parents Returns the parents vector (or NULL for sequence) - \param error Returns an error message in case of failure (do not free the string) - \param num_theory Number of theory terms - \param theory Theory terms - - Returns true on success. - - File formats: Currently two formats are supported, based on - SMT-LIB2. For sequence interpolants, the sequence of constraints is - represented by the sequence of "assert" commands in the file. - - For tree interpolants, one symbol of type bool is associated to - each vertex of the tree. For each vertex v there is an "assert" - of the form: - - (implies (and c1 ... cn f) v) - - where c1 .. cn are the children of v (which must precede v in the file) - and f is the formula associated to node v. The last formula in the - file is the root vertex, and is represented by the predicate "false". - - A solution to a tree interpolation problem can be thought of as a - valuation of the vertices that makes all the implications true - where each value is represented using the common symbols between - the formulas in the subtree and the remainder of the formulas. - - def_API('Z3_read_interpolation_problem', INT, (_in(CONTEXT), _in(AST_VECTOR), _out(UINT), _out_managed_array(2, UINT), _in(STRING), _out(STRING), _in(AST_VECTOR))) - - */ - - int Z3_API Z3_read_interpolation_problem(Z3_context ctx, - Z3_ast_vector cnsts, - unsigned* num, - unsigned* parents[], - Z3_string filename, - Z3_string_ptr error, - Z3_ast_vector theory); - - - - /** Check the correctness of an interpolant. The Z3 context must - have no constraints asserted when this call is made. That means - that after interpolating, you must first fully pop the Z3 - context before calling this. See Z3_interpolate for meaning of parameters. - - \param ctx The Z3 context. Must be generated by Z3_mk_interpolation_context - \param num The number of constraints in the sequence - \param cnsts Array of constraints (AST's in context ctx) - \param parents The parents vector (or NULL for sequence) - \param interps The interpolant to check - \param error Returns an error message if interpolant incorrect (do not free the string) - \param num_theory Number of theory terms - \param theory Theory terms - - Return value is Z3_L_TRUE if interpolant is verified, Z3_L_FALSE if - incorrect, and Z3_L_UNDEF if unknown. - - def_API('Z3_check_interpolant', INT, (_in(CONTEXT), _in(UINT), _in_array(1, AST), _in_array(1, UINT), _in_array(1, AST), _out(STRING), _in(UINT), _in_array(6, AST))) - */ - - int Z3_API Z3_check_interpolant(Z3_context ctx, - unsigned num, - Z3_ast cnsts[], - unsigned parents[], - Z3_ast *interps, - Z3_string_ptr error, - unsigned num_theory, - Z3_ast theory[]); - - /** Write an interpolation problem to file suitable for reading with - Z3_read_interpolation_problem. The output file is a sequence - of SMT-LIB2 format commands, suitable for reading with command-line Z3 - or other interpolating solvers. - - \param ctx The Z3 context. Must be generated by z3_mk_interpolation_context - \param num The number of constraints in the sequence - \param cnsts Array of constraints - \param parents The parents vector (or NULL for sequence) - \param filename The file name to write - \param num_theory Number of theory terms - \param theory Theory terms - - def_API('Z3_write_interpolation_problem', VOID, (_in(CONTEXT), _in(UINT), _in_array(1, AST), _in_array(1, UINT), _in(STRING), _in(UINT), _in_array(5, AST))) - */ - - void Z3_API Z3_write_interpolation_problem(Z3_context ctx, - unsigned num, - Z3_ast cnsts[], - unsigned parents[], - Z3_string filename, - unsigned num_theory, - Z3_ast theory[]); - /*@}*/ - /*@}*/ - -#ifdef __cplusplus -} -#endif // __cplusplus - -#endif diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index a07be0b22..cae1618c0 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -646,7 +646,6 @@ basic_decl_plugin::basic_decl_plugin(): m_iff_decl(nullptr), m_xor_decl(nullptr), m_not_decl(nullptr), - m_interp_decl(nullptr), m_implies_decl(nullptr), m_proof_sort(nullptr), @@ -865,7 +864,6 @@ void basic_decl_plugin::set_manager(ast_manager * m, family_id id) { m_iff_decl = mk_bool_op_decl("iff", OP_IFF, 2, false, true, false, false, true); m_xor_decl = mk_bool_op_decl("xor", OP_XOR, 2, true, true); m_not_decl = mk_bool_op_decl("not", OP_NOT, 1); - m_interp_decl = mk_bool_op_decl("interp", OP_INTERP, 1); m_implies_decl = mk_implies_decl(); m_proof_sort = m->mk_sort(symbol("Proof"), sort_info(id, PROOF_SORT)); @@ -890,7 +888,6 @@ void basic_decl_plugin::get_op_names(svector & op_names, symbol co op_names.push_back(builtin_name("or", OP_OR)); op_names.push_back(builtin_name("xor", OP_XOR)); op_names.push_back(builtin_name("not", OP_NOT)); - op_names.push_back(builtin_name("interp", OP_INTERP)); op_names.push_back(builtin_name("=>", OP_IMPLIES)); if (logic == symbol::null) { // user friendly aliases @@ -902,7 +899,6 @@ void basic_decl_plugin::get_op_names(svector & op_names, symbol co op_names.push_back(builtin_name("||", OP_OR)); op_names.push_back(builtin_name("equals", OP_EQ)); op_names.push_back(builtin_name("equiv", OP_IFF)); - op_names.push_back(builtin_name("@@", OP_INTERP)); } } @@ -923,7 +919,6 @@ void basic_decl_plugin::finalize() { DEC_REF(m_and_decl); DEC_REF(m_or_decl); DEC_REF(m_not_decl); - DEC_REF(m_interp_decl); DEC_REF(m_iff_decl); DEC_REF(m_xor_decl); DEC_REF(m_implies_decl); @@ -1056,7 +1051,6 @@ func_decl * basic_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters case OP_AND: return m_and_decl; case OP_OR: return m_or_decl; case OP_NOT: return m_not_decl; - case OP_INTERP: return m_interp_decl; case OP_IFF: return m_iff_decl; case OP_IMPLIES: return m_implies_decl; case OP_XOR: return m_xor_decl; @@ -1099,7 +1093,6 @@ func_decl * basic_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters case OP_AND: return m_and_decl; case OP_OR: return m_or_decl; case OP_NOT: return m_not_decl; - case OP_INTERP: return m_interp_decl; case OP_IFF: return m_iff_decl; case OP_IMPLIES: return m_implies_decl; case OP_XOR: return m_xor_decl; diff --git a/src/ast/ast.h b/src/ast/ast.h index 2db0fde04..e85f164e1 100644 --- a/src/ast/ast.h +++ b/src/ast/ast.h @@ -1041,7 +1041,7 @@ enum basic_sort_kind { }; enum basic_op_kind { - OP_TRUE, OP_FALSE, OP_EQ, OP_DISTINCT, OP_ITE, OP_AND, OP_OR, OP_IFF, OP_XOR, OP_NOT, OP_IMPLIES, OP_OEQ, OP_INTERP, LAST_BASIC_OP, + OP_TRUE, OP_FALSE, OP_EQ, OP_DISTINCT, OP_ITE, OP_AND, OP_OR, OP_IFF, OP_XOR, OP_NOT, OP_IMPLIES, OP_OEQ, LAST_BASIC_OP, PR_UNDEF, PR_TRUE, PR_ASSERTED, PR_GOAL, PR_MODUS_PONENS, PR_REFLEXIVITY, PR_SYMMETRY, PR_TRANSITIVITY, PR_TRANSITIVITY_STAR, PR_MONOTONICITY, PR_QUANT_INTRO, PR_DISTRIBUTIVITY, PR_AND_ELIM, PR_NOT_OR_ELIM, PR_REWRITE, PR_REWRITE_STAR, PR_PULL_QUANT, @@ -1063,7 +1063,6 @@ protected: func_decl * m_iff_decl; func_decl * m_xor_decl; func_decl * m_not_decl; - func_decl * m_interp_decl; func_decl * m_implies_decl; ptr_vector m_eq_decls; // cached eqs ptr_vector m_ite_decls; // cached ites @@ -2054,7 +2053,6 @@ public: app * mk_true() const { return m_true; } app * mk_false() const { return m_false; } app * mk_bool_val(bool b) { return b?m_true:m_false; } - app * mk_interp(expr * arg) { return mk_app(m_basic_family_id, OP_INTERP, arg); } func_decl* mk_and_decl() { diff --git a/src/cmd_context/CMakeLists.txt b/src/cmd_context/CMakeLists.txt index f7b888343..8da871f9a 100644 --- a/src/cmd_context/CMakeLists.txt +++ b/src/cmd_context/CMakeLists.txt @@ -8,14 +8,12 @@ z3_add_component(cmd_context context_params.cpp echo_tactic.cpp eval_cmd.cpp - interpolant_cmds.cpp parametric_cmd.cpp pdecl.cpp simplify_cmd.cpp tactic_cmds.cpp tactic_manager.cpp COMPONENT_DEPENDENCIES - interp rewriter solver EXTRA_REGISTER_MODULE_HEADERS diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp index e42f884d6..7d2b2f17a 100644 --- a/src/cmd_context/cmd_context.cpp +++ b/src/cmd_context/cmd_context.cpp @@ -46,7 +46,6 @@ Notes: #include "tactic/generic_model_converter.h" #include "solver/smt_logics.h" #include "cmd_context/basic_cmds.h" -#include "cmd_context/interpolant_cmds.h" #include "cmd_context/cmd_context.h" func_decls::func_decls(ast_manager & m, func_decl * f): @@ -484,7 +483,6 @@ cmd_context::cmd_context(bool main_ctx, ast_manager * m, symbol const & l): install_basic_cmds(*this); install_ext_basic_cmds(*this); install_core_tactic_cmds(*this); - install_interpolant_cmds(*this); SASSERT(m != 0 || !has_manager()); if (m_main_ctx) { set_verbose_stream(diagnostic_stream()); diff --git a/src/cmd_context/interpolant_cmds.cpp b/src/cmd_context/interpolant_cmds.cpp deleted file mode 100644 index dd1d0acec..000000000 --- a/src/cmd_context/interpolant_cmds.cpp +++ /dev/null @@ -1,263 +0,0 @@ -/*++ - Copyright (c) 2013 Microsoft Corporation - - Module Name: - - interpolant_cmds.cpp - - Abstract: - Commands for interpolation. - - Author: - - Leonardo (leonardo) 2011-12-23 - - Notes: - - --*/ -#include -#include "cmd_context/cmd_context.h" -#include "cmd_context/cmd_util.h" -#include "util/scoped_timer.h" -#include "util/scoped_ctrl_c.h" -#include "util/cancel_eh.h" -#include "ast/ast_pp.h" -#include "ast/ast_smt_pp.h" -#include "ast/ast_smt2_pp.h" -#include "cmd_context/parametric_cmd.h" -#include "util/mpq.h" -#include "ast/expr2var.h" -#include "ast/pp.h" -#include "interp/iz3interp.h" -#include "interp/iz3checker.h" -#include "interp/iz3profiling.h" -#include "interp/interp_params.hpp" -#include "ast/scoped_proof.h" - -static void show_interpolant_and_maybe_check(cmd_context & ctx, - ptr_vector &cnsts, - expr *t, - ptr_vector &interps, - params_ref &m_params, - bool check) -{ - - if (m_params.get_bool("som", false)) - m_params.set_bool("flat", true); - th_rewriter s(ctx.m(), m_params); - - ctx.regular_stream() << "(interpolants"; - for(unsigned i = 0; i < interps.size(); i++){ - expr_ref r(ctx.m()); - proof_ref pr(ctx.m()); - s(to_expr(interps[i]),r,pr); - ctx.regular_stream() << "\n " << r; - } - ctx.regular_stream() << ")\n"; - - s.cleanup(); - - // verify, for the paranoid... - if(check || interp_params(m_params).check()){ - std::ostringstream err; - ast_manager &_m = ctx.m(); - - // need a solver -- make one here FIXME is this right? - bool proofs_enabled, models_enabled, unsat_core_enabled; - params_ref p; - ctx.params().get_solver_params(_m, p, proofs_enabled, models_enabled, unsat_core_enabled); - scoped_ptr sp = (ctx.get_solver_factory())(_m, p, false, true, false, ctx.get_logic()); - - if(iz3check(_m,sp.get(),err,cnsts,t,interps)) - ctx.regular_stream() << "correct\n"; - else - ctx.regular_stream() << "incorrect: " << err.str().c_str() << "\n"; - } - - for(unsigned i = 0; i < interps.size(); i++){ - ctx.m().dec_ref(interps[i]); - } - - interp_params itp_params(m_params); - if(itp_params.profile()) - profiling::print(ctx.regular_stream()); - -} - -static void check_can_interpolate(cmd_context & ctx){ - if (!ctx.produce_interpolants()) - throw cmd_exception("interpolation is not enabled, use command (set-option :produce-interpolants true)"); -} - - -static void get_interpolant_and_maybe_check(cmd_context & ctx, expr * t, params_ref &m_params, bool check) { - - check_can_interpolate(ctx); - - // get the proof, if there is one - - if (!ctx.has_manager() || - ctx.cs_state() != cmd_context::css_unsat) - throw cmd_exception("proof is not available"); - expr_ref pr(ctx.m()); - pr = ctx.get_check_sat_result()->get_proof(); - if (pr == 0) - throw cmd_exception("proof is not available"); - - // get the assertions from the context - - ptr_vector::const_iterator it = ctx.begin_assertions(); - ptr_vector::const_iterator end = ctx.end_assertions(); - ptr_vector cnsts((unsigned)(end - it)); - for (int i = 0; it != end; ++it, ++i) - cnsts[i] = *it; - - // compute an interpolant - - ptr_vector interps; - - try { - iz3interpolate(ctx.m(),pr.get(),cnsts,t,interps,nullptr); - } - catch (iz3_bad_tree &) { - throw cmd_exception("interpolation pattern contains non-asserted formula"); - } - catch (iz3_incompleteness &) { - throw cmd_exception("incompleteness in interpolator"); - } - - show_interpolant_and_maybe_check(ctx, cnsts, t, interps, m_params, check); -} - -static void get_interpolant(cmd_context & ctx, expr * t, params_ref &m_params) { - get_interpolant_and_maybe_check(ctx,t,m_params,false); -} - -#if 0 -static void get_and_check_interpolant(cmd_context & ctx, params_ref &m_params, expr * t) { - get_interpolant_and_maybe_check(ctx,t,m_params,true); -} -#endif - -static void compute_interpolant_and_maybe_check(cmd_context & ctx, expr * t, params_ref &m_params, bool check){ - - // create a fresh solver suitable for interpolation - bool proofs_enabled, models_enabled, unsat_core_enabled; - params_ref p; - ast_manager &_m = ctx.m(); - // TODO: the following is a HACK to enable proofs in the old smt solver - // When we stop using that solver, this hack can be removed - scoped_proof_mode spm(_m,PGM_ENABLED); - ctx.params().get_solver_params(_m, p, proofs_enabled, models_enabled, unsat_core_enabled); - p.set_bool("proof", true); - scoped_ptr sp = (ctx.get_interpolating_solver_factory())(_m, p, true, models_enabled, false, ctx.get_logic()); - - ptr_vector cnsts; - ptr_vector interps; - model_ref m; - - // compute an interpolant - - lbool res; - try { - res = iz3interpolate(_m, *sp.get(), t, cnsts, interps, m, nullptr); - } - catch (iz3_incompleteness &) { - throw cmd_exception("incompleteness in interpolator"); - } - - switch(res){ - case l_false: - ctx.regular_stream() << "unsat\n"; - show_interpolant_and_maybe_check(ctx, cnsts, t, interps, m_params, check); - break; - - case l_true: - ctx.regular_stream() << "sat\n"; - // TODO: how to return the model to the context, if it exists? - break; - - case l_undef: - ctx.regular_stream() << "unknown\n"; - // TODO: how to return the model to the context, if it exists? - break; - } - - for(unsigned i = 0; i < cnsts.size(); i++) - ctx.m().dec_ref(cnsts[i]); - -} - -static expr *make_tree(cmd_context & ctx, const ptr_vector &exprs){ - if(exprs.size() == 0) - throw cmd_exception("not enough arguments"); - expr *foo = exprs[0]; - for(unsigned i = 1; i < exprs.size(); i++){ - foo = ctx.m().mk_and(ctx.m().mk_interp(foo),exprs[i]); - } - return foo; -} - -static void get_interpolant(cmd_context & ctx, const ptr_vector &exprs, params_ref &m_params) { - expr_ref foo(make_tree(ctx, exprs),ctx.m()); - get_interpolant(ctx,foo.get(),m_params); -} - -static void compute_interpolant(cmd_context & ctx, const ptr_vector &exprs, params_ref &m_params) { - expr_ref foo(make_tree(ctx, exprs),ctx.m()); - compute_interpolant_and_maybe_check(ctx,foo.get(),m_params,false); -} - - -// UNARY_CMD(get_interpolant_cmd, "get-interpolant", "", "get interpolant for marked positions in fmla", CPK_EXPR, expr *, get_interpolant(ctx, arg);); - -// UNARY_CMD(get_and_check_interpolant_cmd, "get-and-check-interpolant", "", "get and check interpolant for marked positions in fmla", CPK_EXPR, expr *, get_and_check_interpolant(ctx, arg);); - -class get_interpolant_cmd : public parametric_cmd { -protected: - ptr_vector m_targets; -public: - get_interpolant_cmd(char const * name = "get-interpolant"):parametric_cmd(name) {} - - char const * get_usage() const override { return "+"; } - - char const * get_main_descr() const override { - return "get interpolant for formulas"; - } - - void init_pdescrs(cmd_context & ctx, param_descrs & p) override { - } - - void prepare(cmd_context & ctx) override { - parametric_cmd::prepare(ctx); - m_targets.resize(0); - } - - cmd_arg_kind next_arg_kind(cmd_context & ctx) const override { - return CPK_EXPR; - } - - void set_next_arg(cmd_context & ctx, expr * arg) override { - m_targets.push_back(arg); - } - - void execute(cmd_context & ctx) override { - get_interpolant(ctx,m_targets,m_params); - } -}; - -class compute_interpolant_cmd : public get_interpolant_cmd { -public: - compute_interpolant_cmd(char const * name = "compute-interpolant"):get_interpolant_cmd(name) {} - - void execute(cmd_context & ctx) override { - compute_interpolant(ctx,m_targets,m_params); - } - -}; - -void install_interpolant_cmds(cmd_context & ctx) { - ctx.insert(alloc(get_interpolant_cmd)); - ctx.insert(alloc(compute_interpolant_cmd)); - // ctx.insert(alloc(get_and_check_interpolant_cmd)); -} diff --git a/src/cmd_context/interpolant_cmds.h b/src/cmd_context/interpolant_cmds.h deleted file mode 100644 index daef70926..000000000 --- a/src/cmd_context/interpolant_cmds.h +++ /dev/null @@ -1,24 +0,0 @@ -/*++ - Copyright (c) 2011 Microsoft Corporation - - Module Name: - - interpolant_cmds.h - - Abstract: - Commands for interpolation. - - Author: - - Leonardo (leonardo) 2011-12-23 - - Notes: - - --*/ -#ifndef INTERPOLANT_CMDS_H_ -#define INTERPOLANT_CMDS_H_ - -class cmd_context; -void install_interpolant_cmds(cmd_context & ctx); - -#endif diff --git a/src/duality/CMakeLists.txt b/src/duality/CMakeLists.txt deleted file mode 100644 index eb2d5c4f2..000000000 --- a/src/duality/CMakeLists.txt +++ /dev/null @@ -1,11 +0,0 @@ -z3_add_component(duality - SOURCES - duality_profiling.cpp - duality_rpfp.cpp - duality_solver.cpp - duality_wrapper.cpp - COMPONENT_DEPENDENCIES - interp - qe - smt -) diff --git a/src/duality/duality.h b/src/duality/duality.h deleted file mode 100644 index 9bf323d8b..000000000 --- a/src/duality/duality.h +++ /dev/null @@ -1,1365 +0,0 @@ -/*++ - Copyright (c) 2012 Microsoft Corporation - - Module Name: - - duality.h - - Abstract: - - main header for duality - - Author: - - Ken McMillan (kenmcmil) - - Revision History: - - - --*/ - -#pragma once - -#include "duality/duality_wrapper.h" -#include -#include -#include - -// make hash_map and hash_set available -using namespace stl_ext; - -namespace Duality { - - struct implicant_solver; - - /* Generic operations on Z3 formulas */ - - struct Z3User { - - context &ctx; - - typedef func_decl FuncDecl; - typedef expr Term; - - Z3User(context &_ctx) : ctx(_ctx){} - - const char *string_of_int(int n); - - Term conjoin(const std::vector &args); - - Term sum(const std::vector &args); - - Term CloneQuantifier(const Term &t, const Term &new_body); - - Term SubstRec(hash_map &memo, const Term &t); - - Term SubstRec(hash_map &memo, hash_map &map, const Term &t); - - void Strengthen(Term &x, const Term &y); - - // return the func_del of an app if it is uninterpreted - - bool get_relation(const Term &t, func_decl &R); - - // return true if term is an individual variable - // TODO: have to check that it is not a background symbol - - bool is_variable(const Term &t); - - FuncDecl SuffixFuncDecl(const Term &t, int n); - - - Term SubstRecHide(hash_map &memo, const Term &t, int number); - - void CollectConjuncts(const Term &f, std::vector &lits, bool pos = true); - - void SortTerms(std::vector &terms); - - Term SortSum(const Term &t); - - void Summarize(const Term &t); - - int CountOperators(const Term &t); - - Term SubstAtom(hash_map &memo, const expr &t, const expr &atom, const expr &val); - - Term CloneQuantAndSimp(const expr &t, const expr &body); - - Term RemoveRedundancy(const Term &t); - - Term IneqToEq(const Term &t); - - bool IsLiteral(const expr &lit, expr &atom, expr &val); - - expr Negate(const expr &f); - - expr SimplifyAndOr(const std::vector &args, bool is_and); - - expr ReallySimplifyAndOr(const std::vector &args, bool is_and); - - int MaxIndex(hash_map &memo, const Term &t); - - bool IsClosedFormula(const Term &t); - - Term AdjustQuantifiers(const Term &t); - - FuncDecl RenumberPred(const FuncDecl &f, int n); - - FuncDecl NumberPred(const FuncDecl &f, int n); - - Term ExtractStores(hash_map &memo, const Term &t, std::vector &cnstrs, hash_map &renaming); - - - protected: - - void SummarizeRec(hash_set &memo, std::vector &lits, int &ops, const Term &t); - int CountOperatorsRec(hash_set &memo, const Term &t); - void RemoveRedundancyOp(bool pol, std::vector &args, hash_map &smemo); - Term RemoveRedundancyRec(hash_map &memo, hash_map &smemo, const Term &t); - Term SubstAtomTriv(const expr &foo, const expr &atom, const expr &val); - expr ReduceAndOr(const std::vector &args, bool is_and, std::vector &res); - expr FinishAndOr(const std::vector &args, bool is_and); - expr PullCommonFactors(std::vector &args, bool is_and); - Term IneqToEqRec(hash_map &memo, const Term &t); - Term CloneQuantAndSimp(const expr &t, const expr &body, bool is_forall); - Term PushQuantifier(const expr &t, const expr &body, bool is_forall); - void CollectJuncts(const Term &f, std::vector &lits, decl_kind op, bool negate); - Term DeleteBoundRec(hash_map > &memo, int level, int num, const Term &t); - Term DeleteBound(int level, int num, const Term &t); - - }; - - /** This class represents a relation post-fixed point (RPFP) problem as - * a "problem graph". The graph consists of Nodes and hyper-edges. - * - * A node consists of - * - Annotation, a symbolic relation - * - Bound, a symbolic relation giving an upper bound on Annotation - * - * - * A hyper-edge consists of: - * - Children, a sequence of children Nodes, - * - F, a symbolic relational transformer, - * - Parent, a single parent Node. - * - * The graph is "solved" when: - * - For every Node n, n.Annotation subseteq n.Bound - * - For every hyperedge e, e.F(e.Children.Annotation) subseteq e.Parent.Annotation - * - * where, if x is a sequence of Nodes, x.Annotation is the sequences - * of Annotations of the nodes in the sequence. - * - * A symbolic Transformer consists of - * - RelParams, a sequence of relational symbols - * - IndParams, a sequence of individual symbols - * - Formula, a formula over RelParams and IndParams - * - * A Transformer t represents a function that takes sequence R of relations - * and yields the relation lambda (t.Indparams). Formula(R/RelParams). - * - * As a special case, a nullary Transformer (where RelParams is the empty sequence) - * represents a fixed relation. - * - * An RPFP consists of - * - Nodes, a set of Nodes - * - Edges, a set of hyper-edges - * - Context, a prover context that contains formula AST's - * - * Multiple RPFP's can use the same Context, but you should be careful - * that only one RPFP asserts constraints in the context at any time. - * - * */ - class RPFP : public Z3User - { - public: - - class Edge; - class Node; - bool HornClauses; - - - /** Interface class for interpolating solver. */ - - class LogicSolver { - public: - - context *ctx; /** Z3 context for formulas */ - solver *slvr; /** Z3 solver */ - bool need_goals; /** Can the solver use the goal tree to optimize interpolants? */ - solver aux_solver; /** For temporary use -- don't leave assertions here. */ - - /** Tree interpolation. This method assumes the formulas in TermTree - "assumptions" are currently asserted in the solver. The return - value indicates whether the assertions are satisfiable. In the - UNSAT case, a tree interpolant is returned in "interpolants". - In the SAT case, a model is returned. - */ - - virtual - lbool interpolate_tree(TermTree *assumptions, - TermTree *&interpolants, - model &_model, - TermTree *goals = nullptr, - bool weak = false - ) = 0; - - /** Declare a constant in the background theory. */ - virtual void declare_constant(const func_decl &f) = 0; - - /** Is this a background constant? */ - virtual bool is_constant(const func_decl &f) = 0; - - /** Get the constants in the background vocabulary */ - virtual hash_set &get_constants() = 0; - - /** Assert a background axiom. */ - virtual void assert_axiom(const expr &axiom) = 0; - - /** Get the background axioms. */ - virtual const std::vector &get_axioms() = 0; - - /** Return a string describing performance. */ - virtual std::string profile() = 0; - - virtual void write_interpolation_problem(const std::string &file_name, - const std::vector &assumptions, - const std::vector &theory - ){} - - /** Cancel, throw Canceled object if possible. */ - virtual void cancel(){ } - - /* Note: aux solver uses extensional array theory, since it - needs to be able to produce counter-models for - interpolants the have array equalities in them. - */ - LogicSolver(context &c) : aux_solver(c,true){} - - virtual ~LogicSolver(){} - }; - - /** This solver uses iZ3. */ - class iZ3LogicSolver : public LogicSolver { - public: - interpolating_context *ictx; /** iZ3 context for formulas */ - interpolating_solver *islvr; /** iZ3 solver */ - - lbool interpolate_tree(TermTree *assumptions, - TermTree *&interpolants, - model &_model, - TermTree *goals = nullptr, - bool weak = false) override - { - literals _labels; - islvr->SetWeakInterpolants(weak); - return islvr->interpolate_tree(assumptions,interpolants,_model,_labels,true); - } - - void assert_axiom(const expr &axiom) override { -#if 1 - // HACK: large "distict" predicates can kill the legacy SMT solver. - // encode them with a UIF - if(axiom.is_app() && axiom.decl().get_decl_kind() == Distinct) - if(axiom.num_args() > 10){ - sort s = axiom.arg(0).get_sort(); - std::vector sv; - sv.push_back(s); - int nargs = axiom.num_args(); - std::vector args(nargs); - func_decl f = ctx->fresh_func_decl("@distinct",sv,ctx->int_sort()); - for(int i = 0; i < nargs; i++){ - expr a = axiom.arg(i); - expr new_cnstr = f(a) == ctx->int_val(i); - args[i] = new_cnstr; - } - expr cnstr = ctx->make(And,args); - islvr->AssertInterpolationAxiom(cnstr); - return; - } -#endif - islvr->AssertInterpolationAxiom(axiom); - } - - const std::vector &get_axioms() override { - return islvr->GetInterpolationAxioms(); - } - - std::string profile() override { - return islvr->profile(); - } - -#if 0 - iZ3LogicSolver(config &_config){ - ctx = ictx = new interpolating_context(_config); - slvr = islvr = new interpolating_solver(*ictx); - need_goals = false; - islvr->SetWeakInterpolants(true); - } -#endif - - iZ3LogicSolver(context &c, bool models = true) : LogicSolver(c) { - ctx = ictx = &c; - slvr = islvr = new interpolating_solver(*ictx, models); - need_goals = false; - islvr->SetWeakInterpolants(true); - } - - void write_interpolation_problem(const std::string &file_name, - const std::vector &assumptions, - const std::vector &theory - ) override { -#if 0 - islvr->write_interpolation_problem(file_name,assumptions,theory); -#endif - - } - - void cancel() override {islvr->cancel();} - - /** Declare a constant in the background theory. */ - void declare_constant(const func_decl &f) override { - bckg.insert(f); - } - - /** Is this a background constant? */ - bool is_constant(const func_decl &f) override { - return bckg.find(f) != bckg.end(); - } - - /** Get the constants in the background vocabulary */ - hash_set &get_constants() override { - return bckg; - } - - ~iZ3LogicSolver() override { - // delete ictx; - delete islvr; - } - private: - hash_set bckg; - - }; - -#if 0 - /** Create a logic solver from a Z3 configuration. */ - static iZ3LogicSolver *CreateLogicSolver(config &_config){ - return new iZ3LogicSolver(_config); - } -#endif - - /** Create a logic solver from a low-level Z3 context. - Only use this if you know what you're doing. */ - static iZ3LogicSolver *CreateLogicSolver(context c){ - return new iZ3LogicSolver(c); - } - - LogicSolver *ls; - - protected: - int nodeCount; - int edgeCount; - - class stack_entry - { - public: - std::list edges; - std::list nodes; - std::list > constraints; - }; - - - public: - model dualModel; - protected: - literals dualLabels; - std::list stack; - std::vector axioms; // only saved here for printing purposes - solver &aux_solver; - hash_set *proof_core; - - public: - - /** Construct an RPFP graph with a given interpolating prover context. It is allowed to - have multiple RPFP's use the same context, but you should never have teo RPFP's - with the same conext asserting nodes or edges at the same time. Note, if you create - axioms in one RPFP, them create a second RPFP with the same context, the second will - inherit the axioms. - */ - - RPFP(LogicSolver *_ls) : Z3User(*(_ls->ctx)), dualModel(*(_ls->ctx)), aux_solver(_ls->aux_solver) - { - ls = _ls; - nodeCount = 0; - edgeCount = 0; - stack.push_back(stack_entry()); - HornClauses = false; - proof_core = nullptr; - } - - virtual ~RPFP(); - - /** Symbolic representation of a relational transformer */ - class Transformer - { - public: - std::vector RelParams; - std::vector IndParams; - Term Formula; - RPFP *owner; - hash_map labels; - - Transformer *Clone() - { - return new Transformer(*this); - } - - void SetEmpty(){ - Formula = owner->ctx.bool_val(false); - } - - void SetFull(){ - Formula = owner->ctx.bool_val(true); - } - - bool IsEmpty(){ - return eq(Formula,owner->ctx.bool_val(false)); - } - - bool IsFull(){ - return eq(Formula,owner->ctx.bool_val(true)); - } - - void UnionWith(const Transformer &other){ - Term t = owner->SubstParams(other.IndParams,IndParams,other.Formula); - Formula = Formula || t; - } - - void IntersectWith(const Transformer &other){ - Term t = owner->SubstParams(other.IndParams,IndParams,other.Formula); - Formula = Formula && t; - } - - bool SubsetEq(const Transformer &other){ - Term t = owner->SubstParams(other.IndParams,IndParams,other.Formula); - expr test = Formula && !t; - owner->aux_solver.push(); - owner->aux_solver.add(test); - check_result res = owner->aux_solver.check(); - owner->aux_solver.pop(1); - return res == unsat; - } - - void Complement(){ - Formula = !Formula; - } - - void Simplify(){ - Formula = Formula.simplify(); - } - - Transformer(const std::vector &_RelParams, const std::vector &_IndParams, const Term &_Formula, RPFP *_owner) - : RelParams(_RelParams), IndParams(_IndParams), Formula(_Formula) {owner = _owner;} - }; - - /** Create a symbolic transformer. */ - Transformer CreateTransformer(const std::vector &_RelParams, const std::vector &_IndParams, const Term &_Formula) - { - // var ops = new Util.ContextOps(ctx); - // var foo = ops.simplify_lhs(_Formula); - // t.Formula = foo.Item1; - // t.labels = foo.Item2; - return Transformer(_RelParams,_IndParams,_Formula,this); - } - - /** Create a relation (nullary relational transformer) */ - Transformer CreateRelation(const std::vector &_IndParams, const Term &_Formula) - { - return CreateTransformer(std::vector(), _IndParams, _Formula); - } - - /** A node in the RPFP graph */ - class Node - { - public: - FuncDecl Name; - Transformer Annotation; - Transformer Bound; - Transformer Underapprox; - RPFP *owner; - int number; - Edge *Outgoing; - std::vector Incoming; - Term dual; - Node *map; - unsigned recursion_bound; - - Node(const FuncDecl &_Name, const Transformer &_Annotation, const Transformer &_Bound, const Transformer &_Underapprox, const Term &_dual, RPFP *_owner, int _number) - : Name(_Name), Annotation(_Annotation), Bound(_Bound), Underapprox(_Underapprox), dual(_dual) {owner = _owner; number = _number; Outgoing = nullptr; recursion_bound = UINT_MAX;} - }; - - /** Create a node in the graph. The input is a term R(v_1...v_n) - * where R is an arbitrary relational symbol and v_1...v_n are - * arbitary distinct variables. The names are only of mnemonic value, - * however, the number and type of arguments determine the type - * of the relation at this node. */ - - Node *CreateNode(const Term &t) - { - std::vector _IndParams; - int nargs = t.num_args(); - _IndParams.reserve(nargs); - for(int i = 0; i < nargs; i++) - _IndParams.push_back(t.arg(i)); - Node *n = new Node(t.decl(), - CreateRelation(_IndParams,ctx.bool_val(true)), - CreateRelation(_IndParams,ctx.bool_val(true)), - CreateRelation(_IndParams,ctx.bool_val(false)), - expr(ctx), this, ++nodeCount - ); - nodes.push_back(n); - return n; - } - - /** Clone a node (can be from another graph). */ - - Node *CloneNode(Node *old) - { - Node *n = new Node(old->Name, - old->Annotation, - old->Bound, - old->Underapprox, - expr(ctx), - this, - ++nodeCount - ); - nodes.push_back(n); - n->map = old; - return n; - } - - /** Delete a node. You can only do this if not connected to any edges.*/ - void DeleteNode(Node *node){ - if(node->Outgoing || !node->Incoming.empty()) - throw "cannot delete RPFP node"; - for(std::vector::iterator it = nodes.end(), en = nodes.begin(); it != en;){ - if(*(--it) == node){ - nodes.erase(it); - break; - } - } - delete node; - } - - /** This class represents a hyper-edge in the RPFP graph */ - - class Edge - { - public: - Transformer F; - Node *Parent; - std::vector Children; - RPFP *owner; - int number; - // these should be internal... - Term dual; - hash_map relMap; - hash_map varMap; - Edge *map; - Term labeled; - std::vector constraints; - - Edge(Node *_Parent, const Transformer &_F, const std::vector &_Children, RPFP *_owner, int _number) - : F(_F), Parent(_Parent), Children(_Children), dual(expr(_owner->ctx)) { - owner = _owner; - number = _number; - } - }; - - - /** Create a hyper-edge. */ - Edge *CreateEdge(Node *_Parent, const Transformer &_F, const std::vector &_Children) - { - Edge *e = new Edge(_Parent,_F,_Children,this,++edgeCount); - _Parent->Outgoing = e; - for(unsigned i = 0; i < _Children.size(); i++) - _Children[i]->Incoming.push_back(e); - edges.push_back(e); - return e; - } - - - /** Delete a hyper-edge and unlink it from any nodes. */ - void DeleteEdge(Edge *edge){ - if(edge->Parent) - edge->Parent->Outgoing = nullptr; - for(unsigned int i = 0; i < edge->Children.size(); i++){ - std::vector &ic = edge->Children[i]->Incoming; - for(std::vector::iterator it = ic.begin(), en = ic.end(); it != en; ++it){ - if(*it == edge){ - ic.erase(it); - break; - } - } - } - for(std::vector::iterator it = edges.end(), en = edges.begin(); it != en;){ - if(*(--it) == edge){ - edges.erase(it); - break; - } - } - delete edge; - } - - /** Create an edge that lower-bounds its parent. */ - Edge *CreateLowerBoundEdge(Node *_Parent) - { - return CreateEdge(_Parent, _Parent->Annotation, std::vector()); - } - - - /** For incremental solving, asserts the constraint associated - * with this edge in the SMT context. If this edge is removed, - * you must pop the context accordingly. The second argument is - * the number of pushes we are inside. */ - - virtual void AssertEdge(Edge *e, int persist = 0, bool with_children = false, bool underapprox = false); - - /* Constrain an edge by the annotation of one of its children. */ - - void ConstrainParent(Edge *parent, Node *child); - - /** For incremental solving, asserts the negation of the upper bound associated - * with a node. - * */ - - void AssertNode(Node *n); - - /** Assert a constraint on an edge in the SMT context. - */ - void ConstrainEdge(Edge *e, const Term &t); - - /** Fix the truth values of atomic propositions in the given - edge to their values in the current assignment. */ - void FixCurrentState(Edge *root); - - void FixCurrentStateFull(Edge *edge, const expr &extra); - - void FixCurrentStateFull(Edge *edge, const std::vector &assumps, const hash_map &renaming); - - /** Declare a constant in the background theory. */ - - void DeclareConstant(const FuncDecl &f); - - /** Assert a background axiom. Background axioms can be used to provide the - * theory of auxilliary functions or relations. All symbols appearing in - * background axioms are considered global, and may appear in both transformer - * and relational solutions. Semantically, a solution to the RPFP gives - * an interpretation of the unknown relations for each interpretation of the - * auxilliary symbols that is consistent with the axioms. Axioms should be - * asserted before any calls to Push. They cannot be de-asserted by Pop. */ - - void AssertAxiom(const Term &t); - -#if 0 - /** Do not call this. */ - - void RemoveAxiom(const Term &t); -#endif - - /** Solve an RPFP graph. This means either strengthen the annotation - * so that the bound at the given root node is satisfied, or - * show that this cannot be done by giving a dual solution - * (i.e., a counterexample). - * - * In the current implementation, this only works for graphs that - * are: - * - tree-like - * - * - closed. - * - * In a tree-like graph, every nod has out most one incoming and one out-going edge, - * and there are no cycles. In a closed graph, every node has exactly one out-going - * edge. This means that the leaves of the tree are all hyper-edges with no - * children. Such an edge represents a relation (nullary transformer) and thus - * a lower bound on its parent. The parameter root must be the root of this tree. - * - * If Solve returns LBool.False, this indicates success. The annotation of the tree - * has been updated to satisfy the upper bound at the root. - * - * If Solve returns LBool.True, this indicates a counterexample. For each edge, - * you can then call Eval to determine the values of symbols in the transformer formula. - * You can also call Empty on a node to determine if its value in the counterexample - * is the empty relation. - * - * \param root The root of the tree - * \param persist Number of context pops through which result should persist - * - * - */ - - lbool Solve(Node *root, int persist); - - /** Same as Solve, but annotates only a single node. */ - - lbool SolveSingleNode(Node *root, Node *node); - - /** Get the constraint tree (but don't solve it) */ - - TermTree *GetConstraintTree(Node *root, Node *skip_descendant = nullptr); - - /** Dispose of the dual model (counterexample) if there is one. */ - - void DisposeDualModel(); - - /** Check satisfiability of asserted edges and nodes. Same functionality as - * Solve, except no primal solution (interpolant) is generated in the unsat case. */ - - check_result Check(Node *root, std::vector underapproxes = std::vector(), - std::vector *underapprox_core = nullptr); - - /** Update the model, attempting to make the propositional literals in assumps true. If possible, - return sat, else return unsat and keep the old model. */ - - check_result CheckUpdateModel(Node *root, std::vector assumps); - - /** Determines the value in the counterexample of a symbol occurring in the transformer formula of - * a given edge. */ - - Term Eval(Edge *e, const Term& t); - - /** Return the fact derived at node p in a counterexample. */ - - Term EvalNode(Node *p); - - /** Returns true if the given node is empty in the primal solution. For procedure summaries, - this means that the procedure is not called in the current counter-model. */ - - bool Empty(Node *p); - - /** Compute an underapproximation of every node in a tree rooted at "root", - based on a previously computed counterexample. */ - - Term ComputeUnderapprox(Node *root, int persist); - - /** Try to strengthen the annotation of a node by removing disjuncts. */ - void Generalize(Node *root, Node *node); - - - /** Compute disjunctive interpolant for node by case splitting */ - void InterpolateByCases(Node *root, Node *node); - - /** Push a scope. Assertions made after Push can be undone by Pop. */ - - void Push(); - - /** Exception thrown when bad clause is encountered */ - - struct bad_clause { - std::string msg; - int i; - bad_clause(const std::string &_msg, int _i){ - msg = _msg; - i = _i; - } - }; - - struct parse_error { - std::string msg; - parse_error(const std::string &_msg){ - msg = _msg; - } - }; - - struct file_not_found { - }; - - struct bad_format { - }; - - // thrown on internal error - struct Bad { - }; - - // thrown on more serious internal error - struct ReallyBad { - }; - - // throw when greedy reduction fails - struct greedy_reduce_failed {}; - - /** Pop a scope (see Push). Note, you cannot pop axioms. */ - - void Pop(int num_scopes); - - /** Erase the proof by performing a Pop, Push and re-assertion of - all the popped constraints */ - void PopPush(); - - /** Return true if the given edge is used in the proof of unsat. - Can be called only after Solve or Check returns an unsat result. */ - - bool EdgeUsedInProof(Edge *edge); - - - /** Convert a collection of clauses to Nodes and Edges in the RPFP. - - Predicate unknowns are uninterpreted predicates not - occurring in the background theory. - - Clauses are of the form - - B => P(t_1,...,t_k) - - where P is a predicate unknown and predicate unknowns - occur only positivey in H and only under existential - quantifiers in prenex form. - - Each predicate unknown maps to a node. Each clause maps to - an edge. Let C be a clause B => P(t_1,...,t_k) where the - sequence of predicate unknowns occurring in B (in order - of occurrence) is P_1..P_n. The clause maps to a transformer - T where: - - T.Relparams = P_1..P_n - T.Indparams = x_1...x+k - T.Formula = B /\ t_1 = x_1 /\ ... /\ t_k = x_k - - Throws exception bad_clause(msg,i) if a clause i is - in the wrong form. - - */ - - struct label_struct { - symbol name; - expr value; - bool pos; - label_struct(const symbol &s, const expr &e, bool b) - : name(s), value(e), pos(b) {} - }; - - -#ifdef _WINDOWS - __declspec(dllexport) -#endif - void FromClauses(const std::vector &clauses, const std::vector *bounds = nullptr); - - void FromFixpointContext(fixedpoint fp, std::vector &queries); - - void WriteSolution(std::ostream &s); - - void WriteCounterexample(std::ostream &s, Node *node); - - enum FileFormat {DualityFormat, SMT2Format, HornFormat}; - - /** Write the RPFP to a file (currently in SMTLIB 1.2 format) */ - void WriteProblemToFile(std::string filename, FileFormat format = DualityFormat); - - /** Read the RPFP from a file (in specified format) */ - void ReadProblemFromFile(std::string filename, FileFormat format = DualityFormat); - - /** Translate problem to Horn clause form */ - void ToClauses(std::vector &cnsts, FileFormat format = DualityFormat); - - /** Translate the RPFP to a fixed point context, with queries */ - fixedpoint ToFixedPointProblem(std::vector &queries); - - /** Nodes of the graph. */ - std::vector nodes; - - /** Edges of the graph. */ - std::vector edges; - - /** Fuse a vector of transformers. If the total number of inputs of the transformers - is N, then the result is an N-ary transformer whose output is the union of - the outputs of the given transformers. The is, suppose we have a vector of transformers - {T_i(r_i1,...,r_iN(i) : i=1..M}. The result is a transformer - - F(r_11,...,r_iN(1),...,r_M1,...,r_MN(M)) = - T_1(r_11,...,r_iN(1)) U ... U T_M(r_M1,...,r_MN(M)) - */ - - Transformer Fuse(const std::vector &trs); - - /** Fuse edges so that each node is the output of at most one edge. This - transformation is solution-preserving, but changes the numbering of edges in - counterexamples. - */ - void FuseEdges(); - - void RemoveDeadNodes(); - - Term SubstParams(const std::vector &from, - const std::vector &to, const Term &t); - - Term SubstParamsNoCapture(const std::vector &from, - const std::vector &to, const Term &t); - - Term Localize(Edge *e, const Term &t); - - void EvalNodeAsConstraint(Node *p, Transformer &res); - - TermTree *GetGoalTree(Node *root); - - int EvalTruth(hash_map &memo, Edge *e, const Term &f); - - void GetLabels(Edge *e, std::vector &labels); - - // int GetLabelsRec(hash_map *memo, const Term &f, std::vector &labels, bool labpos); - - /** Compute and save the proof core for future calls to - EdgeUsedInProof. You only need to call this if you will pop - the solver before calling EdgeUsedInProof. - */ - void ComputeProofCore(); - - int CumulativeDecisions(); - - void GreedyReduceNodes(std::vector &nodes); - - check_result CheckWithConstrainedNodes(std::vector &posnodes,std::vector &negnodes); - - solver &slvr(){ - return *ls->slvr; - } - - protected: - - void ClearProofCore(){ - if(proof_core) - delete proof_core; - proof_core = nullptr; - } - - Term SuffixVariable(const Term &t, int n); - - Term HideVariable(const Term &t, int n); - - void RedVars(Node *node, Term &b, std::vector &v); - - Term RedDualRela(Edge *e, std::vector &args, int idx); - - Term LocalizeRec(Edge *e, hash_map &memo, const Term &t); - - void SetEdgeMaps(Edge *e); - - Term ReducedDualEdge(Edge *e); - - TermTree *ToTermTree(Node *root, Node *skip_descendant = nullptr); - - TermTree *ToGoalTree(Node *root); - - void CollapseTermTreeRec(TermTree *root, TermTree *node); - - TermTree *CollapseTermTree(TermTree *node); - - void DecodeTree(Node *root, TermTree *interp, int persist); - - Term GetUpperBound(Node *n); - - TermTree *AddUpperBound(Node *root, TermTree *t); - -#if 0 - void WriteInterps(System.IO.StreamWriter f, TermTree t); -#endif - - void WriteEdgeVars(Edge *e, hash_map &memo, const Term &t, std::ostream &s); - - void WriteEdgeAssignment(std::ostream &s, Edge *e); - - - // Scan the clause body for occurrences of the predicate unknowns - - Term ScanBody(hash_map &memo, - const Term &t, - hash_map &pmap, - std::vector &res, - std::vector &nodes); - - Term RemoveLabelsRec(hash_map &memo, const Term &t, std::vector &lbls); - - Term RemoveLabels(const Term &t, std::vector &lbls); - - Term GetAnnotation(Node *n); - - - Term GetUnderapprox(Node *n); - - Term UnderapproxFlag(Node *n); - - hash_map underapprox_flag_rev; - - Node *UnderapproxFlagRev(const Term &flag); - - Term ProjectFormula(std::vector &keep_vec, const Term &f); - - int SubtermTruth(hash_map &memo, const Term &); - - void ImplicantRed(hash_map &memo, const Term &f, std::vector &lits, - hash_set *done, bool truth, hash_set &dont_cares); - - void Implicant(hash_map &memo, const Term &f, std::vector &lits, hash_set &dont_cares); - - Term UnderapproxFormula(const Term &f, hash_set &dont_cares); - - void ImplicantFullRed(hash_map &memo, const Term &f, std::vector &lits, - hash_set &done, hash_set &dont_cares, bool extensional = true); - - public: - Term UnderapproxFullFormula(const Term &f, bool extensional = true); - - protected: - Term ToRuleRec(Edge *e, hash_map &memo, const Term &t, std::vector &quants); - - hash_map resolve_ite_memo; - - Term ResolveIte(hash_map &memo, const Term &t, std::vector &lits, - hash_set *done, hash_set &dont_cares); - - struct ArrayValue { - bool defined; - std::map entries; - expr def_val; - }; - - void EvalArrayTerm(const Term &t, ArrayValue &res); - - Term EvalArrayEquality(const Term &f); - - Term ModelValueAsConstraint(const Term &t); - - void GetLabelsRec(hash_map &memo, const Term &f, std::vector &labels, - hash_set *done, bool truth); - - Term SubstBoundRec(hash_map > &memo, hash_map &subst, int level, const Term &t); - - Term SubstBound(hash_map &subst, const Term &t); - - void ConstrainEdgeLocalized(Edge *e, const Term &t); - - void GreedyReduce(solver &s, std::vector &conjuncts); - - void NegateLits(std::vector &lits); - - expr SimplifyOr(std::vector &lits); - - expr SimplifyAnd(std::vector &lits); - - void SetAnnotation(Node *root, const expr &t); - - void AddEdgeToSolver(Edge *edge); - - void AddEdgeToSolver(implicant_solver &aux_solver, Edge *edge); - - void AddToProofCore(hash_set &core); - - void GetGroundLitsUnderQuants(hash_set *memo, const Term &f, std::vector &res, int under); - - Term StrengthenFormulaByCaseSplitting(const Term &f, std::vector &case_lits); - - expr NegateLit(const expr &f); - - expr GetEdgeFormula(Edge *e, int persist, bool with_children, bool underapprox); - - bool IsVar(const expr &t); - - void GetVarsRec(hash_set &memo, const expr &cnst, std::vector &vars); - - expr UnhoistPullRec(hash_map & memo, const expr &w, hash_map & init_defs, hash_map & const_params, hash_map &const_params_inv, std::vector &new_params); - - void AddParamsToTransformer(Transformer &trans, const std::vector ¶ms); - - expr AddParamsToApp(const expr &app, const func_decl &new_decl, const std::vector ¶ms); - - expr GetRelRec(hash_set &memo, const expr &t, const func_decl &rel); - - expr GetRel(Edge *edge, int child_idx); - - void GetDefs(const expr &cnst, hash_map &defs); - - void GetDefsRec(const expr &cnst, hash_map &defs); - - void AddParamsToNode(Node *node, const std::vector ¶ms); - - void UnhoistLoop(Edge *loop_edge, Edge *init_edge); - - void Unhoist(); - - Term ElimIteRec(hash_map &memo, const Term &t, std::vector &cnsts); - - Term ElimIte(const Term &t); - - void MarkLiveNodes(hash_map > &outgoing, hash_set &live_nodes, Node *node); - - virtual void slvr_add(const expr &e); - - virtual void slvr_pop(int i); - - virtual void slvr_push(); - - virtual check_result slvr_check(unsigned n = 0, expr * const assumptions = nullptr, unsigned *core_size = nullptr, expr *core = nullptr); - - virtual lbool ls_interpolate_tree(TermTree *assumptions, - TermTree *&interpolants, - model &_model, - TermTree *goals = nullptr, - bool weak = false); - - virtual bool proof_core_contains(const expr &e); - - }; - - - /** RPFP solver base class. */ - - class Solver { - - public: - - class Counterexample { - private: - RPFP *tree; - RPFP::Node *root; - public: - Counterexample(){ - tree = nullptr; - root = nullptr; - } - Counterexample(RPFP *_tree, RPFP::Node *_root){ - tree = _tree; - root = _root; - } - ~Counterexample(){ - if(tree) delete tree; - } - void swap(Counterexample &other){ - std::swap(tree,other.tree); - std::swap(root,other.root); - } - void set(RPFP *_tree, RPFP::Node *_root){ - if(tree) delete tree; - tree = _tree; - root = _root; - } - void clear(){ - if(tree) delete tree; - tree = nullptr; - } - RPFP *get_tree() const {return tree;} - RPFP::Node *get_root() const {return root;} - private: - Counterexample &operator=(const Counterexample &); - Counterexample(const Counterexample &); - }; - - /** Solve the problem. You can optionally give an old - counterexample to use as a guide. This is chiefly useful for - abstraction refinement metholdologies, and is only used as a - heuristic. */ - - virtual bool Solve() = 0; - - virtual Counterexample &GetCounterexample() = 0; - - virtual bool SetOption(const std::string &option, const std::string &value) = 0; - - /** Learn heuristic information from another solver. This - is chiefly useful for abstraction refinement, when we want to - solve a series of similar problems. */ - - virtual void LearnFrom(Solver *old_solver) = 0; - - /** Return true if the solution be incorrect due to recursion bounding. - That is, the returned "solution" might contain all derivable facts up to the - given recursion bound, but not be actually a fixed point. - */ - - virtual bool IsResultRecursionBounded() = 0; - - virtual ~Solver(){} - - static Solver *Create(const std::string &solver_class, RPFP *rpfp); - - /** This can be called asynchrnously to cause Solve to throw a - Canceled exception at some time in the future. - */ - virtual void Cancel() = 0; - - /** Object thrown on cancellation */ - struct Canceled {}; - - /** Object thrown on incompleteness */ - struct Incompleteness {}; - }; -} - - -// Allow to hash on nodes and edges in deterministic way - -namespace hash_space { - template <> - class hash { - public: - size_t operator()(const Duality::RPFP::Node *p) const { - return p->number; - } - }; -} - -namespace hash_space { - template <> - class hash { - public: - size_t operator()(const Duality::RPFP::Edge *p) const { - return p->number; - } - }; -} - -// allow to walk sets of nodes without address dependency - -namespace std { - template <> - class less { - public: - bool operator()(Duality::RPFP::Node * const &s, Duality::RPFP::Node * const &t) const { - return s->number < t->number; // s.raw()->get_id() < t.raw()->get_id(); - } - }; -} - -// #define LIMIT_STACK_WEIGHT 5 - - -namespace Duality { - /** Caching version of RPFP. Instead of asserting constraints, returns assumption literals */ - - class RPFP_caching : public RPFP { - public: - - /** appends assumption literals for edge to lits. if with_children is true, - includes that annotation of the edge's children. - */ - void AssertEdgeCache(Edge *e, std::vector &lits, bool with_children = false); - - /** appends assumption literals for node to lits */ - void AssertNodeCache(Node *, std::vector lits); - - /** check assumption lits, and return core */ - check_result CheckCore(const std::vector &assumps, std::vector &core); - - /** Clone another RPFP into this one, keeping a map */ - void Clone(RPFP *other); - - /** Get the clone of a node */ - Node *GetNodeClone(Node *other_node); - - /** Get the clone of an edge */ - Edge *GetEdgeClone(Edge *other_edge); - - /** Try to strengthen the parent of an edge */ - void GeneralizeCache(Edge *edge); - - /** Try to propagate some facts from children to parents of edge. - Return true if success. */ - bool PropagateCache(Edge *edge); - - /** Construct a caching RPFP using a LogicSolver */ - RPFP_caching(LogicSolver *_ls) : RPFP(_ls) {} - - /** Constraint an edge by its child's annotation. Return - assumption lits. */ - void ConstrainParentCache(Edge *parent, Node *child, std::vector &lits); - -#ifdef LIMIT_STACK_WEIGHT - virtual void AssertEdge(Edge *e, int persist = 0, bool with_children = false, bool underapprox = false); -#endif - - ~RPFP_caching() override {} - - protected: - hash_map AssumptionLits; - hash_map NodeCloneMap; - hash_map EdgeCloneMap; - std::vector alit_stack; - std::vector alit_stack_sizes; - - // to let us use one solver per edge - struct edge_solver { - hash_map AssumptionLits; - uptr slvr; - }; - hash_map edge_solvers; - -#ifdef LIMIT_STACK_WEIGHT - struct weight_counter { - int val; - weight_counter(){val = 0;} - void swap(weight_counter &other){ - std::swap(val,other.val); - } - }; - - struct big_stack_entry { - weight_counter weight_added; - std::vector new_alits; - std::vector alit_stack; - std::vector alit_stack_sizes; - }; - - std::vector new_alits; - weight_counter weight_added; - std::vector big_stack; -#endif - - - - void GetAssumptionLits(const expr &fmla, std::vector &lits, hash_map *opt_map = nullptr); - - void GreedyReduceCache(std::vector &assumps, std::vector &core); - - void FilterCore(std::vector &core, std::vector &full_core); - void ConstrainEdgeLocalizedCache(Edge *e, const Term &tl, std::vector &lits); - - void slvr_add(const expr &e) override; - - void slvr_pop(int i) override; - - void slvr_push() override; - - check_result slvr_check(unsigned n = 0, expr * const assumptions = nullptr, unsigned *core_size = nullptr, expr *core = nullptr) override; - - lbool ls_interpolate_tree(TermTree *assumptions, - TermTree *&interpolants, - model &_model, - TermTree *goals = nullptr, - bool weak = false) override; - - bool proof_core_contains(const expr &e) override; - - void GetTermTreeAssertionLiterals(TermTree *assumptions); - - void GetTermTreeAssertionLiteralsRec(TermTree *assumptions); - - edge_solver &SolverForEdge(Edge *edge, bool models, bool axioms); - - public: - struct scoped_solver_for_edge { - solver *orig_slvr; - RPFP_caching *rpfp; - edge_solver *es; - scoped_solver_for_edge(RPFP_caching *_rpfp, Edge *edge, bool models = false, bool axioms = false){ - rpfp = _rpfp; - orig_slvr = rpfp->ls->slvr; - es = &(rpfp->SolverForEdge(edge,models,axioms)); - rpfp->ls->slvr = es->slvr.get(); - rpfp->AssumptionLits.swap(es->AssumptionLits); - } - ~scoped_solver_for_edge(){ - rpfp->ls->slvr = orig_slvr; - rpfp->AssumptionLits.swap(es->AssumptionLits); - } - }; - - }; - -} diff --git a/src/duality/duality_profiling.cpp b/src/duality/duality_profiling.cpp deleted file mode 100644 index 6bb995e2d..000000000 --- a/src/duality/duality_profiling.cpp +++ /dev/null @@ -1,144 +0,0 @@ -/*++ - Copyright (c) 2011 Microsoft Corporation - - Module Name: - - duality_profiling.cpp - - Abstract: - - collection performance information for duality - - Author: - - Ken McMillan (kenmcmil) - - Revision History: - - - --*/ - - -#include -#include -#include -#include -#include - -#ifdef _WINDOWS -#pragma warning(disable:4996) -#pragma warning(disable:4800) -#pragma warning(disable:4267) -#endif - -#include "duality/duality_wrapper.h" -#include "interp/iz3profiling.h" - -namespace Duality { - - void show_time(){ - output_time(std::cout,current_time()); - std::cout << "\n"; - } - - typedef std::map nmap; - - struct node { - std::string name; - clock_t time; - clock_t start_time; - nmap sub; - struct node *parent; - - node(); - } top; - - node::node(){ - time = 0; - parent = nullptr; - } - - struct node *current; - - struct init { - init(){ - top.name = "TOTAL"; - current = ⊤ - } - } initializer; - - struct time_entry { - clock_t t; - time_entry(){t = 0;}; - void add(clock_t incr){t += incr;} - }; - - struct ltstr - { - bool operator()(const char* s1, const char* s2) const - { - return strcmp(s1, s2) < 0; - } - }; - - typedef std::map tmap; - - static std::ostream *pfs; - - void print_node(node &top, int indent, tmap &totals){ - for(int i = 0; i < indent; i++) (*pfs) << " "; - (*pfs) << top.name; - int dots = 70 - 2 * indent - top.name.size(); - for(int i = 0; i second,indent+1,totals); - } - - void print_profile(std::ostream &os) { - pfs = &os; - top.time = 0; - for(nmap::iterator it = top.sub.begin(); it != top.sub.end(); it++) - top.time += it->second.time; - tmap totals; - print_node(top,0,totals); - (*pfs) << "TOTALS:" << std::endl; - for(tmap::iterator it = totals.begin(); it != totals.end(); it++){ - (*pfs) << (it->first) << " "; - output_time(*pfs, it->second.t); - (*pfs) << std::endl; - } - profiling::print(os); // print the interpolation stats - } - - void timer_start(const char *name){ - node &child = current->sub[name]; - if(child.name.empty()){ // a new node - child.parent = current; - child.name = name; - } - child.start_time = current_time(); - current = &child; - } - - void timer_stop(const char *name){ - if (current->name != name || !current->parent) { -#if 0 - std::cerr << "imbalanced timer_start and timer_stop"; - exit(1); -#endif - // in case we lost a timer stop due to an exception - while (current->name != name && current->parent) - current = current->parent; - if (current->parent) { - current->time += (current_time() - current->start_time); - current = current->parent; - } - return; - } - current->time += (current_time() - current->start_time); - current = current->parent; - } -} diff --git a/src/duality/duality_profiling.h b/src/duality/duality_profiling.h deleted file mode 100755 index 5f0e5120c..000000000 --- a/src/duality/duality_profiling.h +++ /dev/null @@ -1,38 +0,0 @@ -/*++ - Copyright (c) 2011 Microsoft Corporation - - Module Name: - - duality_profiling.h - - Abstract: - - collection performance information for duality - - Author: - - Ken McMillan (kenmcmil) - - Revision History: - - - --*/ - -#ifndef DUALITYPROFILING_H -#define DUALITYPROFILING_H - -#include - -namespace Duality { - /** Start a timer with given name */ - void timer_start(const char *); - /** Stop a timer with given name */ - void timer_stop(const char *); - /** Print out timings */ - void print_profile(std::ostream &s); - /** Show the current time. */ - void show_time(); -} - -#endif - diff --git a/src/duality/duality_rpfp.cpp b/src/duality/duality_rpfp.cpp deleted file mode 100644 index 3358eb45e..000000000 --- a/src/duality/duality_rpfp.cpp +++ /dev/null @@ -1,4250 +0,0 @@ -/*++ - Copyright (c) 2012 Microsoft Corporation - - Module Name: - - duality_rpfp.h - - Abstract: - - implements relational post-fixedpoint problem - (RPFP) data structure. - - Author: - - Ken McMillan (kenmcmil) - - Revision History: - - - --*/ - - - -#ifdef _WINDOWS -#pragma warning(disable:4996) -#pragma warning(disable:4800) -#pragma warning(disable:4267) -#endif - -#include -#include -#include -#include - - -#include "duality/duality.h" -#include "duality/duality_profiling.h" - -// TODO: do we need these? -#ifdef Z3OPS - -class Z3_subterm_truth { -public: - virtual bool eval(Z3_ast f) = 0; - ~Z3_subterm_truth(){} -}; - -Z3_subterm_truth *Z3_mk_subterm_truth(Z3_context ctx, Z3_model model); - -#endif - -#include - -// TODO: use something official for this -int debug_gauss = 0; - -namespace Duality { - - static char string_of_int_buffer[20]; - - const char *Z3User::string_of_int(int n){ - sprintf(string_of_int_buffer,"%d",n); - return string_of_int_buffer; - } - - RPFP::Term RPFP::SuffixVariable(const Term &t, int n) - { - std::string name = t.decl().name().str() + "_" + string_of_int(n); - return ctx.constant(name.c_str(), t.get_sort()); - } - - RPFP::Term RPFP::HideVariable(const Term &t, int n) - { - std::string name = std::string("@p_") + t.decl().name().str() + "_" + string_of_int(n); - return ctx.constant(name.c_str(), t.get_sort()); - } - - void RPFP::RedVars(Node *node, Term &b, std::vector &v) - { - int idx = node->number; - if(HornClauses) - b = ctx.bool_val(true); - else { - std::string name = std::string("@b_") + string_of_int(idx); - symbol sym = ctx.str_symbol(name.c_str()); - b = ctx.constant(sym,ctx.bool_sort()); - } - // ctx.constant(name.c_str(), ctx.bool_sort()); - v = node->Annotation.IndParams; - for(unsigned i = 0; i < v.size(); i++) - v[i] = SuffixVariable(v[i],idx); - } - - void Z3User::SummarizeRec(hash_set &memo, std::vector &lits, int &ops, const Term &t){ - if(memo.find(t) != memo.end()) - return; - memo.insert(t); - if(t.is_app()){ - decl_kind k = t.decl().get_decl_kind(); - if (k == And || k == Or || k == Not || k == Implies || k == Iff) { - ops++; - int nargs = t.num_args(); - for (int i = 0; i < nargs; i++) - SummarizeRec(memo, lits, ops, t.arg(i)); - return; - } - } - lits.push_back(t); - } - - int RPFP::CumulativeDecisions(){ -#if 0 - std::string stats = Z3_statistics_to_string(ctx); - int pos = stats.find("decisions:"); - pos += 10; - int end = stats.find('\n',pos); - std::string val = stats.substr(pos,end-pos); - return atoi(val.c_str()); -#endif - return slvr().get_num_decisions(); - } - - - void Z3User::Summarize(const Term &t){ - hash_set memo; std::vector lits; int ops = 0; - SummarizeRec(memo, lits, ops, t); - std::cout << ops << ": "; - for(unsigned i = 0; i < lits.size(); i++){ - if(i > 0) std::cout << ", "; - std::cout << lits[i]; - } - } - - int Z3User::CountOperatorsRec(hash_set &memo, const Term &t){ - if(memo.find(t) != memo.end()) - return 0; - memo.insert(t); - if(t.is_app()){ - decl_kind k = t.decl().get_decl_kind(); - if (k == And || k == Or) { - int count = 1; - int nargs = t.num_args(); - for (int i = 0; i < nargs; i++) - count += CountOperatorsRec(memo, t.arg(i)); - return count; - } - return 0; - } - if(t.is_quantifier()){ - int nbv = t.get_quantifier_num_bound(); - return CountOperatorsRec(memo,t.body()) + 2 * nbv; // count 2 for each quantifier - } - return 0; - } - - int Z3User::CountOperators(const Term &t){ - hash_set memo; - return CountOperatorsRec(memo,t); - } - - - Z3User::Term Z3User::conjoin(const std::vector &args){ - return ctx.make(And,args); - } - - Z3User::Term Z3User::sum(const std::vector &args){ - return ctx.make(Plus,args); - } - - RPFP::Term RPFP::RedDualRela(Edge *e, std::vector &args, int idx){ - Node *child = e->Children[idx]; - Term b(ctx); - std::vector v; - RedVars(child, b, v); - for (unsigned i = 0; i < args.size(); i++) { - if (eq(args[i].get_sort(), ctx.bool_sort())) - args[i] = ctx.make(Iff, args[i], v[i]); - else - args[i] = args[i] == v[i]; - } - return args.size() > 0 ? (b && conjoin(args)) : b; - } - - Z3User::Term Z3User::CloneQuantifier(const Term &t, const Term &new_body){ -#if 0 - Z3_context c = ctx; - Z3_ast a = t; - std::vector pats; - int num_pats = Z3_get_quantifier_num_patterns(c,a); - for(int i = 0; i < num_pats; i++) - pats.push_back(Z3_get_quantifier_pattern_ast(c,a,i)); - std::vector no_pats; - int num_no_pats = Z3_get_quantifier_num_patterns(c,a); - for(int i = 0; i < num_no_pats; i++) - no_pats.push_back(Z3_get_quantifier_no_pattern_ast(c,a,i)); - int bound = Z3_get_quantifier_num_bound(c,a); - std::vector sorts; - std::vector names; - for(int i = 0; i < bound; i++){ - sorts.push_back(Z3_get_quantifier_bound_sort(c,a,i)); - names.push_back(Z3_get_quantifier_bound_name(c,a,i)); - } - Z3_ast foo = Z3_mk_quantifier_ex(c, - Z3_is_quantifier_forall(c,a), - Z3_get_quantifier_weight(c,a), - 0, - 0, - num_pats, - VEC2PTR(pats), - num_no_pats, - VEC2PTR(no_pats), - bound, - VEC2PTR(sorts), - VEC2PTR(names), - new_body); - return expr(ctx,foo); -#endif - return clone_quantifier(t,new_body); - } - - - RPFP::Term RPFP::LocalizeRec(Edge *e, hash_map &memo, const Term &t) - { - std::pair foo(t,expr(ctx)); - std::pair::iterator, bool> bar = memo.insert(foo); - Term &res = bar.first->second; - if(!bar.second) return res; - hash_map::iterator it = e->varMap.find(t); - if (it != e->varMap.end()){ - res = it->second; - return res; - } - if (t.is_app()) { - func_decl f = t.decl(); - std::vector args; - int nargs = t.num_args(); - args.reserve(nargs); - for (int i = 0; i < nargs; i++) - args.push_back(LocalizeRec(e, memo, t.arg(i))); - hash_map::iterator rit = e->relMap.find(f); - if (rit != e->relMap.end()) - res = RedDualRela(e, args, (rit->second)); - else { - if (args.size() == 0 && f.get_decl_kind() == Uninterpreted && !ls->is_constant(f)) { - res = HideVariable(t, e->number); - } - else { - res = f(args.size(), VEC2PTR(args)); - } - } - } - else if (t.is_quantifier()) { - std::vector pats; - t.get_patterns(pats); - for (unsigned i = 0; i < pats.size(); i++) - pats[i] = LocalizeRec(e, memo, pats[i]); - Term body = LocalizeRec(e, memo, t.body()); - res = clone_quantifier(t, body, pats); - } - else res = t; - return res; - } - - void RPFP::SetEdgeMaps(Edge *e){ - timer_start("SetEdgeMaps"); - e->relMap.clear(); - e->varMap.clear(); - for(unsigned i = 0; i < e->F.RelParams.size(); i++){ - e->relMap[e->F.RelParams[i]] = i; - } - Term b(ctx); - std::vector v; - RedVars(e->Parent, b, v); - for(unsigned i = 0; i < e->F.IndParams.size(); i++){ - // func_decl parentParam = e->Parent.Annotation.IndParams[i]; - expr oldname = e->F.IndParams[i]; - expr newname = v[i]; - e->varMap[oldname] = newname; - } - timer_stop("SetEdgeMaps"); - - } - - - RPFP::Term RPFP::Localize(Edge *e, const Term &t){ - timer_start("Localize"); - hash_map memo; - if(e->F.IndParams.size() > 0 && e->varMap.empty()) - SetEdgeMaps(e); // TODO: why is this needed? - Term res = LocalizeRec(e,memo,t); - timer_stop("Localize"); - return res; - } - - - RPFP::Term RPFP::ReducedDualEdge(Edge *e) - { - SetEdgeMaps(e); - timer_start("RedVars"); - Term b(ctx); - std::vector v; - RedVars(e->Parent, b, v); - timer_stop("RedVars"); - // ast_to_track = (ast)b; - return implies(b, Localize(e, e->F.Formula)); - } - - TermTree *RPFP::ToTermTree(Node *root, Node *skip_descendant) - { - if(skip_descendant && root == skip_descendant) - return new TermTree(ctx.bool_val(true)); - Edge *e = root->Outgoing; - if(!e) return new TermTree(ctx.bool_val(true), std::vector()); - std::vector children(e->Children.size()); - for(unsigned i = 0; i < children.size(); i++) - children[i] = ToTermTree(e->Children[i],skip_descendant); - // Term top = ReducedDualEdge(e); - Term top = e->dual.null() ? ctx.bool_val(true) : e->dual; - TermTree *res = new TermTree(top, children); - for(unsigned i = 0; i < e->constraints.size(); i++) - res->addTerm(e->constraints[i]); - return res; - } - - TermTree *RPFP::GetGoalTree(Node *root){ - std::vector children(1); - children[0] = ToGoalTree(root); - return new TermTree(ctx.bool_val(false),children); - } - - TermTree *RPFP::ToGoalTree(Node *root) - { - Term b(ctx); - std::vector v; - RedVars(root, b, v); - Term goal = root->Name(v); - Edge *e = root->Outgoing; - if(!e) return new TermTree(goal, std::vector()); - std::vector children(e->Children.size()); - for(unsigned i = 0; i < children.size(); i++) - children[i] = ToGoalTree(e->Children[i]); - // Term top = ReducedDualEdge(e); - return new TermTree(goal, children); - } - - Z3User::Term Z3User::SubstRec(hash_map &memo, const Term &t) - { - std::pair foo(t,expr(ctx)); - std::pair::iterator, bool> bar = memo.insert(foo); - Term &res = bar.first->second; - if(!bar.second) return res; - if (t.is_app()) { - func_decl f = t.decl(); - std::vector args; - int nargs = t.num_args(); - args.reserve(nargs); - for (int i = 0; i < nargs; i++) - args.push_back(SubstRec(memo, t.arg(i))); - res = f(args.size(), VEC2PTR(args)); - } - else if (t.is_quantifier()) { - std::vector pats; - t.get_patterns(pats); - for (unsigned i = 0; i < pats.size(); i++) - pats[i] = SubstRec(memo, pats[i]); - Term body = SubstRec(memo, t.body()); - res = clone_quantifier(t, body, pats); - } - // res = CloneQuantifier(t,SubstRec(memo, t.body())); - else res = t; - return res; - } - - Z3User::Term Z3User::SubstRec(hash_map &memo, hash_map &map, const Term &t) - { - std::pair foo(t,expr(ctx)); - std::pair::iterator, bool> bar = memo.insert(foo); - Term &res = bar.first->second; - if(!bar.second) return res; - if (t.is_app()) { - func_decl f = t.decl(); - std::vector args; - int nargs = t.num_args(); - args.reserve(nargs); - for (int i = 0; i < nargs; i++) - args.push_back(SubstRec(memo, map, t.arg(i))); - hash_map::iterator it = map.find(f); - if (it != map.end()) - f = it->second; - res = f(args.size(), VEC2PTR(args)); - } - else if (t.is_quantifier()) { - std::vector pats; - t.get_patterns(pats); - for (unsigned i = 0; i < pats.size(); i++) - pats[i] = SubstRec(memo, map, pats[i]); - Term body = SubstRec(memo, map, t.body()); - res = clone_quantifier(t, body, pats); - } - // res = CloneQuantifier(t,SubstRec(memo, t.body())); - else res = t; - return res; - } - - Z3User::Term Z3User::ExtractStores(hash_map &memo, const Term &t, std::vector &cnstrs, hash_map &renaming) - { - std::pair foo(t,expr(ctx)); - std::pair::iterator, bool> bar = memo.insert(foo); - Term &res = bar.first->second; - if(!bar.second) return res; - if (t.is_app()) { - func_decl f = t.decl(); - std::vector args; - int nargs = t.num_args(); - args.reserve(nargs); - for (int i = 0; i < nargs; i++) - args.push_back(ExtractStores(memo, t.arg(i), cnstrs, renaming)); - res = f(args.size(), VEC2PTR(args)); - if (f.get_decl_kind() == Store) { - func_decl fresh = ctx.fresh_func_decl("@arr", res.get_sort()); - expr y = fresh(); - expr equ = ctx.make(Equal, y, res); - cnstrs.push_back(equ); - renaming[y] = res; - res = y; - } - } - else res = t; - return res; - } - - - bool Z3User::IsLiteral(const expr &lit, expr &atom, expr &val){ - if (!(lit.is_quantifier() && IsClosedFormula(lit))) { - if (!lit.is_app()) - return false; - decl_kind k = lit.decl().get_decl_kind(); - if (k == Not) { - if (IsLiteral(lit.arg(0), atom, val)) { - val = eq(val, ctx.bool_val(true)) ? ctx.bool_val(false) : ctx.bool_val(true); - return true; - } - return false; - } - if (k == And || k == Or || k == Iff || k == Implies) - return false; - } - atom = lit; - val = ctx.bool_val(true); - return true; - } - - expr Z3User::Negate(const expr &f){ - if(f.is_app() && f.decl().get_decl_kind() == Not) - return f.arg(0); - else if(eq(f,ctx.bool_val(true))) - return ctx.bool_val(false); - else if(eq(f,ctx.bool_val(false))) - return ctx.bool_val(true); - return !f; - } - - expr Z3User::ReduceAndOr(const std::vector &args, bool is_and, std::vector &res){ - for(unsigned i = 0; i < args.size(); i++) - if (!eq(args[i], ctx.bool_val(is_and))) { - if (eq(args[i], ctx.bool_val(!is_and))) - return ctx.bool_val(!is_and); - res.push_back(args[i]); - } - return expr(); - } - - expr Z3User::FinishAndOr(const std::vector &args, bool is_and){ - if(args.size() == 0) - return ctx.bool_val(is_and); - if(args.size() == 1) - return args[0]; - return ctx.make(is_and ? And : Or,args); - } - - expr Z3User::SimplifyAndOr(const std::vector &args, bool is_and){ - std::vector sargs; - expr res = ReduceAndOr(args,is_and,sargs); - if(!res.null()) return res; - return FinishAndOr(sargs,is_and); - } - - expr Z3User::PullCommonFactors(std::vector &args, bool is_and){ - - // first check if there's anything to do... - if(args.size() < 2) - return FinishAndOr(args,is_and); - for (unsigned i = 0; i < args.size(); i++) { - const expr &a = args[i]; - if (!(a.is_app() && a.decl().get_decl_kind() == (is_and ? Or : And))) - return FinishAndOr(args, is_and); - } - std::vector common; - for (unsigned i = 0; i < args.size(); i++) { - unsigned n = args[i].num_args(); - std::vector v(n), w; - for (unsigned j = 0; j < n; j++) - v[j] = args[i].arg(j); - std::less comp; - std::sort(v.begin(), v.end(), comp); - if (i == 0) - common.swap(v); - else { - std::set_intersection(common.begin(), common.end(), v.begin(), v.end(), std::inserter(w, w.begin()), comp); - common.swap(w); - } - } - if(common.empty()) - return FinishAndOr(args,is_and); - std::set common_set(common.begin(),common.end()); - for(unsigned i = 0; i < args.size(); i++){ - unsigned n = args[i].num_args(); - std::vector lits; - for (unsigned j = 0; j < n; j++) { - const expr b = args[i].arg(j); - if (common_set.find(b) == common_set.end()) - lits.push_back(b); - } - args[i] = SimplifyAndOr(lits,!is_and); - } - common.push_back(SimplifyAndOr(args,is_and)); - return SimplifyAndOr(common,!is_and); - } - - expr Z3User::ReallySimplifyAndOr(const std::vector &args, bool is_and){ - std::vector sargs; - expr res = ReduceAndOr(args,is_and,sargs); - if(!res.null()) return res; - return PullCommonFactors(sargs,is_and); - } - - Z3User::Term Z3User::SubstAtomTriv(const expr &foo, const expr &atom, const expr &val){ - if(eq(foo,atom)) - return val; - else if(foo.is_app() && foo.decl().get_decl_kind() == Not && eq(foo.arg(0),atom)) - return Negate(val); - else - return foo; - } - - Z3User::Term Z3User::PushQuantifier(const expr &t, const expr &body, bool is_forall){ - if (t.get_quantifier_num_bound() == 1) { - std::vector fmlas, free, not_free; - CollectJuncts(body, fmlas, is_forall ? Or : And, false); - for (unsigned i = 0; i < fmlas.size(); i++) { - const expr &fmla = fmlas[i]; - if (fmla.has_free(0)) - free.push_back(fmla); - else - not_free.push_back(fmla); - } - decl_kind op = is_forall ? Or : And; - if (free.empty()) - return DeleteBound(0, 1, SimplifyAndOr(not_free, op == And)); - expr q = clone_quantifier(is_forall ? Forall : Exists, t, SimplifyAndOr(free, op == And)); - if (!not_free.empty()) - q = ctx.make(op, q, DeleteBound(0, 1, SimplifyAndOr(not_free, op == And))); - return q; - } - return clone_quantifier(is_forall ? Forall : Exists,t,body); - } - - Z3User::Term Z3User::CloneQuantAndSimp(const expr &t, const expr &body, bool is_forall) { - if (body.is_app()) { - if (body.decl().get_decl_kind() == (is_forall ? And : Or)) { // quantifier distributes - int nargs = body.num_args(); - std::vector args(nargs); - for (int i = 0; i < nargs; i++) - args[i] = CloneQuantAndSimp(t, body.arg(i), is_forall); - return SimplifyAndOr(args, body.decl().get_decl_kind() == And); - } - else if (body.decl().get_decl_kind() == (is_forall ? Or : And)) { // quantifier distributes - return PushQuantifier(t, body, is_forall); // may distribute partially - } - else if (body.decl().get_decl_kind() == Not) { - return ctx.make(Not, CloneQuantAndSimp(t, body.arg(0), !is_forall)); - } - } - if (t.get_quantifier_num_bound() == 1 && !body.has_free(0)) - return DeleteBound(0, 1, body); // drop the quantifier - return clone_quantifier(is_forall ? Forall : Exists, t, body); - } - - Z3User::Term Z3User::CloneQuantAndSimp(const expr &t, const expr &body){ - return CloneQuantAndSimp(t,body,t.is_quantifier_forall()); - } - - Z3User::Term Z3User::SubstAtom(hash_map &memo, const expr &t, const expr &atom, const expr &val) { - std::pair foo(t, expr(ctx)); - std::pair::iterator, bool> bar = memo.insert(foo); - Term &res = bar.first->second; - if (!bar.second) return res; - if (t.is_app()) { - func_decl f = t.decl(); - decl_kind k = f.get_decl_kind(); - - // TODO: recur here, but how much? We don't want to be quadractic in formula size - - if (k == And || k == Or) { - int nargs = t.num_args(); - std::vector args(nargs); - for (int i = 0; i < nargs; i++) - args[i] = SubstAtom(memo, t.arg(i), atom, val); - res = ReallySimplifyAndOr(args, k == And); - return res; - } - } - else if (t.is_quantifier() && atom.is_quantifier()) { - if (eq(t, atom)) - res = val; - else - res = clone_quantifier(t, SubstAtom(memo, t.body(), atom, val)); - return res; - } - res = SubstAtomTriv(t, atom, val); - return res; - } - - void Z3User::RemoveRedundancyOp(bool pol, std::vector &args, hash_map &smemo) { - for (unsigned i = 0; i < args.size(); i++) { - const expr &lit = args[i]; - expr atom, val; - if (IsLiteral(lit, atom, val)) { - if (atom.is_app() && atom.decl().get_decl_kind() == Equal) - if (pol ? eq(val, ctx.bool_val(true)) : eq(val, ctx.bool_val(false))) { - expr lhs = atom.arg(0), rhs = atom.arg(1); - if (lhs.is_numeral()) - std::swap(lhs, rhs); - if (rhs.is_numeral() && lhs.is_app()) { - for (unsigned j = 0; j < args.size(); j++) - if (j != i) { - smemo.clear(); - smemo[lhs] = rhs; - args[j] = SubstRec(smemo, args[j]); - } - } - } - for (unsigned j = 0; j < args.size(); j++) - if (j != i) { - smemo.clear(); - args[j] = SubstAtom(smemo, args[j], atom, pol ? val : !val); - } - } - } - } - - - Z3User::Term Z3User::RemoveRedundancyRec(hash_map &memo, hash_map &smemo, const Term &t) { - std::pair foo(t, expr(ctx)); - std::pair::iterator, bool> bar = memo.insert(foo); - Term &res = bar.first->second; - if (!bar.second) return res; - if (t.is_app()) { - func_decl f = t.decl(); - std::vector args; - int nargs = t.num_args(); - args.reserve(nargs); - for (int i = 0; i < nargs; i++) - args.push_back(RemoveRedundancyRec(memo, smemo, t.arg(i))); - - decl_kind k = f.get_decl_kind(); - if (k == And) { - RemoveRedundancyOp(true, args, smemo); - res = ReallySimplifyAndOr(args, true); - } - else if (k == Or) { - RemoveRedundancyOp(false, args, smemo); - res = ReallySimplifyAndOr(args, false); - } - else { - if (k == Equal && args[0].get_id() > args[1].get_id()) - std::swap(args[0], args[1]); - res = f(args.size(), VEC2PTR(args)); - } - } - else if (t.is_quantifier()) { - Term body = RemoveRedundancyRec(memo, smemo, t.body()); - res = CloneQuantAndSimp(t, body); - } - else res = t; - return res; - } - - Z3User::Term Z3User::RemoveRedundancy(const Term &t){ - hash_map memo; - hash_map smemo; - return RemoveRedundancyRec(memo,smemo,t); - } - - Z3User::Term Z3User::AdjustQuantifiers(const Term &t) - { - if(t.is_quantifier() || (t.is_app() && t.has_quantifiers())) - return t.qe_lite(); - return t; - } - - Z3User::Term Z3User::IneqToEqRec(hash_map &memo, const Term &t) { - std::pair foo(t, expr(ctx)); - std::pair::iterator, bool> bar = memo.insert(foo); - Term &res = bar.first->second; - if (!bar.second) return res; - if (t.is_app()) { - func_decl f = t.decl(); - std::vector args; - int nargs = t.num_args(); - args.reserve(nargs); - for (int i = 0; i < nargs; i++) - args.push_back(IneqToEqRec(memo, t.arg(i))); - - decl_kind k = f.get_decl_kind(); - if (k == And) { - for (int i = 0; i < nargs - 1; i++) { - if ((args[i].is_app() && args[i].decl().get_decl_kind() == Geq && - args[i + 1].is_app() && args[i + 1].decl().get_decl_kind() == Leq) - || - (args[i].is_app() && args[i].decl().get_decl_kind() == Leq && - args[i + 1].is_app() && args[i + 1].decl().get_decl_kind() == Geq)) - if (eq(args[i].arg(0), args[i + 1].arg(0)) && eq(args[i].arg(1), args[i + 1].arg(1))) { - args[i] = ctx.make(Equal, args[i].arg(0), args[i].arg(1)); - args[i + 1] = ctx.bool_val(true); - } - } - } - res = f(args.size(), VEC2PTR(args)); - } - else if (t.is_quantifier()) { - Term body = IneqToEqRec(memo, t.body()); - res = clone_quantifier(t, body); - } - else res = t; - return res; - } - - Z3User::Term Z3User::IneqToEq(const Term &t){ - hash_map memo; - return IneqToEqRec(memo,t); - } - - Z3User::Term Z3User::SubstRecHide(hash_map &memo, const Term &t, int number) { - std::pair foo(t, expr(ctx)); - std::pair::iterator, bool> bar = memo.insert(foo); - Term &res = bar.first->second; - if (!bar.second) return res; - if (t.is_app()) { - func_decl f = t.decl(); - std::vector args; - int nargs = t.num_args(); - if (nargs == 0 && f.get_decl_kind() == Uninterpreted) { - std::string name = std::string("@q_") + t.decl().name().str() + "_" + string_of_int(number); - res = ctx.constant(name.c_str(), t.get_sort()); - return res; - } - args.reserve(nargs); - for (int i = 0; i < nargs; i++) - args.push_back(SubstRec(memo, t.arg(i))); - res = f(args.size(), VEC2PTR(args)); - } - else if (t.is_quantifier()) - res = CloneQuantifier(t, SubstRec(memo, t.body())); - else res = t; - return res; - } - - RPFP::Term RPFP::SubstParams(const std::vector &from, - const std::vector &to, const Term &t) { - hash_map memo; - bool some_diff = false; - for (unsigned i = 0; i < from.size(); i++) - if (i < to.size() && !eq(from[i], to[i])) { - memo[from[i]] = to[i]; - some_diff = true; - } - return some_diff ? SubstRec(memo, t) : t; - } - - RPFP::Term RPFP::SubstParamsNoCapture(const std::vector &from, - const std::vector &to, const Term &t) { - hash_map memo; - bool some_diff = false; - for (unsigned i = 0; i < from.size(); i++) - if (i < to.size() && !eq(from[i], to[i])) { - memo[from[i]] = to[i]; - // if the new param is not being mapped to anything else, we need to rename it to prevent capture - // note, if the new param *is* mapped later in the list, it will override this substitution - const expr &w = to[i]; - if (memo.find(w) == memo.end()) { - std::string old_name = w.decl().name().str(); - func_decl fresh = ctx.fresh_func_decl(old_name.c_str(), w.get_sort()); - expr y = fresh(); - memo[w] = y; - } - some_diff = true; - } - return some_diff ? SubstRec(memo, t) : t; - } - - - - RPFP::Transformer RPFP::Fuse(const std::vector &trs) { - assert(!trs.empty()); - const std::vector ¶ms = trs[0]->IndParams; - std::vector fmlas(trs.size()); - fmlas[0] = trs[0]->Formula; - for (unsigned i = 1; i < trs.size(); i++) - fmlas[i] = SubstParamsNoCapture(trs[i]->IndParams, params, trs[i]->Formula); - std::vector rel_params = trs[0]->RelParams; - for (unsigned i = 1; i < trs.size(); i++) { - const std::vector ¶ms2 = trs[i]->RelParams; - hash_map map; - for (unsigned j = 0; j < params2.size(); j++) { - func_decl rel = RenumberPred(params2[j], rel_params.size()); - rel_params.push_back(rel); - map[params2[j]] = rel; - } - hash_map memo; - fmlas[i] = SubstRec(memo, map, fmlas[i]); - } - return Transformer(rel_params, params, ctx.make(Or, fmlas), trs[0]->owner); - } - - - void Z3User::Strengthen(Term &x, const Term &y) - { - if (eq(x,ctx.bool_val(true))) - x = y; - else - x = x && y; - } - - void RPFP::SetAnnotation(Node *root, const expr &t){ - hash_map memo; - Term b; - std::vector v; - RedVars(root, b, v); - memo[b] = ctx.bool_val(true); - for (unsigned i = 0; i < v.size(); i++) - memo[v[i]] = root->Annotation.IndParams[i]; - Term annot = SubstRec(memo, t); - // Strengthen(ref root.Annotation.Formula, annot); - root->Annotation.Formula = annot; - } - - void RPFP::DecodeTree(Node *root, TermTree *interp, int persist) { - std::vector &ic = interp->getChildren(); - if (ic.size() > 0) { - std::vector &nc = root->Outgoing->Children; - for (unsigned i = 0; i < nc.size(); i++) - DecodeTree(nc[i], ic[i], persist); - } - SetAnnotation(root, interp->getTerm()); -#if 0 - if(persist != 0) - Z3_persist_ast(ctx,root->Annotation.Formula,persist); -#endif - } - - RPFP::Term RPFP::GetUpperBound(Node *n) - { - // TODO: cache this - Term b(ctx); std::vector v; - RedVars(n, b, v); - hash_map memo; - for (unsigned int i = 0; i < v.size(); i++) - memo[n->Bound.IndParams[i]] = v[i]; - Term cnst = SubstRec(memo, n->Bound.Formula); - return b && !cnst; - } - - RPFP::Term RPFP::GetAnnotation(Node *n) - { - if(eq(n->Annotation.Formula,ctx.bool_val(true))) - return n->Annotation.Formula; - // TODO: cache this - Term b(ctx); std::vector v; - RedVars(n, b, v); - hash_map memo; - for (unsigned i = 0; i < v.size(); i++) - memo[n->Annotation.IndParams[i]] = v[i]; - Term cnst = SubstRec(memo, n->Annotation.Formula); - return !b || cnst; - } - - RPFP::Term RPFP::GetUnderapprox(Node *n) - { - // TODO: cache this - Term b(ctx); std::vector v; - RedVars(n, b, v); - hash_map memo; - for (unsigned i = 0; i < v.size(); i++) - memo[n->Underapprox.IndParams[i]] = v[i]; - Term cnst = SubstRecHide(memo, n->Underapprox.Formula, n->number); - return !b || cnst; - } - - TermTree *RPFP::AddUpperBound(Node *root, TermTree *t) - { - Term f = !((ast)(root->dual)) ? ctx.bool_val(true) : root->dual; - std::vector c(1); c[0] = t; - return new TermTree(f, c); - } - -#if 0 - void RPFP::WriteInterps(System.IO.StreamWriter f, TermTree t) - { - foreach (var c in t.getChildren()) - WriteInterps(f, c); - f.WriteLine(t.getTerm()); - } -#endif - - - expr RPFP::GetEdgeFormula(Edge *e, int persist, bool with_children, bool underapprox) { - if (e->dual.null()) { - timer_start("ReducedDualEdge"); - e->dual = ReducedDualEdge(e); - timer_stop("ReducedDualEdge"); - timer_start("getting children"); - if (underapprox) { - std::vector cus(e->Children.size()); - for (unsigned i = 0; i < e->Children.size(); i++) - cus[i] = !UnderapproxFlag(e->Children[i]) || GetUnderapprox(e->Children[i]); - expr cnst = conjoin(cus); - e->dual = e->dual && cnst; - } - timer_stop("getting children"); - timer_start("Persisting"); - std::list::reverse_iterator it = stack.rbegin(); - for (int i = 0; i < persist && it != stack.rend(); i++) - it++; - if (it != stack.rend()) - it->edges.push_back(e); - timer_stop("Persisting"); - //Console.WriteLine("{0}", cnst); - } - return e->dual; - } - - /** For incremental solving, asserts the constraint associated - * with this edge in the SMT context. If this edge is removed, - * you must pop the context accordingly. The second argument is - * the number of pushes we are inside. The constraint formula - * will survive "persist" pops of the context. If you plan - * to reassert the edge after popping the context once, - * you can save time re-constructing the formula by setting - * "persist" to one. If you set "persist" too high, however, - * you could have a memory leak. - * - * The flag "with children" causes the annotations of the children - * to be asserted. The flag underapprox causes the underapproximations - * of the children to be asserted *conditionally*. See Check() on - * how to actually enforce these constraints. - * - */ - - void RPFP::AssertEdge(Edge *e, int persist, bool with_children, bool underapprox) { - if (eq(e->F.Formula, ctx.bool_val(true)) && (!with_children || e->Children.empty())) - return; - expr fmla = GetEdgeFormula(e, persist, with_children, underapprox); - timer_start("solver add"); - slvr_add(e->dual); - timer_stop("solver add"); - if (with_children) - for (unsigned i = 0; i < e->Children.size(); i++) - ConstrainParent(e, e->Children[i]); - } - - -#ifdef LIMIT_STACK_WEIGHT - void RPFP_caching::AssertEdge(Edge *e, int persist, bool with_children, bool underapprox) - { - unsigned old_new_alits = new_alits.size(); - if(eq(e->F.Formula,ctx.bool_val(true)) && (!with_children || e->Children.empty())) - return; - expr fmla = GetEdgeFormula(e, persist, with_children, underapprox); - timer_start("solver add"); - slvr_add(e->dual); - timer_stop("solver add"); - if(old_new_alits < new_alits.size()) - weight_added.val++; - if(with_children) - for(unsigned i = 0; i < e->Children.size(); i++) - ConstrainParent(e,e->Children[i]); - } -#endif - - // caching verion of above - void RPFP_caching::AssertEdgeCache(Edge *e, std::vector &lits, bool with_children) { - if (eq(e->F.Formula, ctx.bool_val(true)) && (!with_children || e->Children.empty())) - return; - expr fmla = GetEdgeFormula(e, 0, with_children, false); - GetAssumptionLits(fmla, lits); - if (with_children) - for (unsigned i = 0; i < e->Children.size(); i++) - ConstrainParentCache(e, e->Children[i], lits); - } - - void RPFP::slvr_add(const expr &e){ - slvr().add(e); - } - - void RPFP_caching::slvr_add(const expr &e){ - GetAssumptionLits(e,alit_stack); - } - - void RPFP::slvr_pop(int i){ - slvr().pop(i); - } - - void RPFP::slvr_push(){ - slvr().push(); - } - - void RPFP_caching::slvr_pop(int i){ - for(int j = 0; j < i; j++){ -#ifdef LIMIT_STACK_WEIGHT - if(alit_stack_sizes.empty()){ - if(big_stack.empty()) - throw "stack underflow"; - for(unsigned k = 0; k < new_alits.size(); k++){ - if(AssumptionLits.find(new_alits[k]) == AssumptionLits.end()) - throw "foo!"; - AssumptionLits.erase(new_alits[k]); - } - big_stack_entry &bsb = big_stack.back(); - bsb.alit_stack_sizes.swap(alit_stack_sizes); - bsb.alit_stack.swap(alit_stack); - bsb.new_alits.swap(new_alits); - bsb.weight_added.swap(weight_added); - big_stack.pop_back(); - slvr().pop(1); - continue; - } -#endif - alit_stack.resize(alit_stack_sizes.back()); - alit_stack_sizes.pop_back(); - } - } - - void RPFP_caching::slvr_push(){ -#ifdef LIMIT_STACK_WEIGHT - if(weight_added.val > LIMIT_STACK_WEIGHT){ - big_stack.resize(big_stack.size()+1); - big_stack_entry &bsb = big_stack.back(); - bsb.alit_stack_sizes.swap(alit_stack_sizes); - bsb.alit_stack.swap(alit_stack); - bsb.new_alits.swap(new_alits); - bsb.weight_added.swap(weight_added); - slvr().push(); - for(unsigned i = 0; i < bsb.alit_stack.size(); i++) - slvr().add(bsb.alit_stack[i]); - return; - } -#endif - alit_stack_sizes.push_back(alit_stack.size()); - } - - check_result RPFP::slvr_check(unsigned n, expr * const assumptions, unsigned *core_size, expr *core){ - return slvr().check(n, assumptions, core_size, core); - } - - check_result RPFP_caching::slvr_check(unsigned n, expr * const assumptions, unsigned *core_size, expr *core){ - unsigned oldsiz = alit_stack.size(); - if(n && assumptions) - std::copy(assumptions,assumptions+n,std::inserter(alit_stack,alit_stack.end())); - check_result res; - if (core_size && core) { - std::vector full_core(alit_stack.size()), core1(n); - std::copy(assumptions, assumptions + n, core1.begin()); - res = slvr().check(alit_stack.size(), VEC2PTR(alit_stack), core_size, VEC2PTR(full_core)); - full_core.resize(*core_size); - if (res == unsat) { - FilterCore(core1, full_core); - *core_size = core1.size(); - std::copy(core1.begin(), core1.end(), core); - } - } - else - res = slvr().check(alit_stack.size(), VEC2PTR(alit_stack)); - alit_stack.resize(oldsiz); - return res; - } - - lbool RPFP::ls_interpolate_tree(TermTree *assumptions, - TermTree *&interpolants, - model &_model, - TermTree *goals, - bool weak) { - return ls->interpolate_tree(assumptions, interpolants, _model, goals, weak); - } - - lbool RPFP_caching::ls_interpolate_tree(TermTree *assumptions, - TermTree *&interpolants, - model &_model, - TermTree *goals, - bool weak) { - GetTermTreeAssertionLiterals(assumptions); - return ls->interpolate_tree(assumptions, interpolants, _model, goals, weak); - } - - void RPFP_caching::GetTermTreeAssertionLiteralsRec(TermTree *assumptions){ - std::vector alits; - hash_map map; - GetAssumptionLits(assumptions->getTerm(),alits,&map); - std::vector &ts = assumptions->getTerms(); - for(unsigned i = 0; i < ts.size(); i++) - GetAssumptionLits(ts[i],alits,&map); - assumptions->setTerm(ctx.bool_val(true)); - ts = alits; - for(unsigned i = 0; i < alits.size(); i++) - ts.push_back(ctx.make(Implies,alits[i],map[alits[i]])); - for(unsigned i = 0; i < assumptions->getChildren().size(); i++) - GetTermTreeAssertionLiterals(assumptions->getChildren()[i]); - return; - } - - void RPFP_caching::GetTermTreeAssertionLiterals(TermTree *assumptions) { - // optimize binary case - if (assumptions->getChildren().size() == 1 - && assumptions->getChildren()[0]->getChildren().size() == 0) { - hash_map map; - TermTree *child = assumptions->getChildren()[0]; - std::vector dummy; - GetAssumptionLits(child->getTerm(), dummy, &map); - std::vector &ts = child->getTerms(); - for (unsigned i = 0; i < ts.size(); i++) - GetAssumptionLits(ts[i], dummy, &map); - std::vector assumps; - slvr().get_proof().get_assumptions(assumps); - if (!proof_core) { // save the proof core for later use - proof_core = new hash_set < ast > ; - for (unsigned i = 0; i < assumps.size(); i++) - proof_core->insert(assumps[i]); - } - std::vector *cnsts[2] = { &child->getTerms(), &assumptions->getTerms() }; - for (unsigned i = 0; i < assumps.size(); i++) { - expr &as = assumps[i]; - expr alit = (as.is_app() && as.decl().get_decl_kind() == Implies) ? as.arg(0) : as; - bool isA = map.find(alit) != map.end(); - cnsts[isA ? 0 : 1]->push_back(as); - } - } - else - GetTermTreeAssertionLiteralsRec(assumptions); - } - - void RPFP::AddToProofCore(hash_set &core){ - std::vector assumps; - slvr().get_proof().get_assumptions(assumps); - for(unsigned i = 0; i < assumps.size(); i++) - core.insert(assumps[i]); - } - - void RPFP::ComputeProofCore(){ - if(!proof_core){ - proof_core = new hash_set; - AddToProofCore(*proof_core); - } - } - - - void RPFP_caching::GetAssumptionLits(const expr &fmla, std::vector &lits, hash_map *opt_map) { - std::vector conjs; - CollectConjuncts(fmla, conjs); - for (unsigned i = 0; i < conjs.size(); i++) { - const expr &conj = conjs[i]; - std::pair foo(conj, expr(ctx)); - std::pair::iterator, bool> bar = AssumptionLits.insert(foo); - Term &res = bar.first->second; - if (bar.second) { - func_decl pred = ctx.fresh_func_decl("@alit", ctx.bool_sort()); - res = pred(); -#ifdef LIMIT_STACK_WEIGHT - new_alits.push_back(conj); -#endif - slvr().add(ctx.make(Implies, res, conj)); - // std::cout << res << ": " << conj << "\n"; - } - if (opt_map) - (*opt_map)[res] = conj; - lits.push_back(res); - } - } - - void RPFP::ConstrainParent(Edge *parent, Node *child){ - ConstrainEdgeLocalized(parent,GetAnnotation(child)); - } - - void RPFP_caching::ConstrainParentCache(Edge *parent, Node *child, std::vector &lits){ - ConstrainEdgeLocalizedCache(parent,GetAnnotation(child),lits); - } - - - /** For incremental solving, asserts the negation of the upper bound associated - * with a node. - * */ - - void RPFP::AssertNode(Node *n) - { - if (n->dual.null()) { - n->dual = GetUpperBound(n); - stack.back().nodes.push_back(n); - slvr_add(n->dual); - } - } - - // caching version of above - void RPFP_caching::AssertNodeCache(Node *n, std::vector lits){ - if (n->dual.null()) { - n->dual = GetUpperBound(n); - stack.back().nodes.push_back(n); - GetAssumptionLits(n->dual, lits); - } - } - - /** Clone another RPFP into this one, keeping a map */ - void RPFP_caching::Clone(RPFP *other) { -#if 0 - for(unsigned i = 0; i < other->nodes.size(); i++) - NodeCloneMap[other->nodes[i]] = CloneNode(other->nodes[i]); -#endif - for (unsigned i = 0; i < other->edges.size(); i++) { - Edge *edge = other->edges[i]; - Node *parent = CloneNode(edge->Parent); - std::vector cs; - for (unsigned j = 0; j < edge->Children.size(); j++) - // cs.push_back(NodeCloneMap[edge->Children[j]]); - cs.push_back(CloneNode(edge->Children[j])); - EdgeCloneMap[edge] = CreateEdge(parent, edge->F, cs); - } - } - - /** Get the clone of a node */ - RPFP::Node *RPFP_caching::GetNodeClone(Node *other_node){ - return NodeCloneMap[other_node]; - } - - /** Get the clone of an edge */ - RPFP::Edge *RPFP_caching::GetEdgeClone(Edge *other_edge){ - return EdgeCloneMap[other_edge]; - } - - /** check assumption lits, and return core */ - check_result RPFP_caching::CheckCore(const std::vector &assumps, std::vector &core){ - core.resize(assumps.size()); - unsigned core_size; - check_result res = slvr().check(assumps.size(),(expr *)VEC2PTR(assumps),&core_size, VEC2PTR(core)); - if(res == unsat) - core.resize(core_size); - else - core.clear(); - return res; - } - - - /** Assert a constraint on an edge in the SMT context. - */ - - void RPFP::ConstrainEdge(Edge *e, const Term &t) - { - Term tl = Localize(e, t); - ConstrainEdgeLocalized(e,tl); - } - - void RPFP::ConstrainEdgeLocalized(Edge *e, const Term &tl) - { - e->constraints.push_back(tl); - stack.back().constraints.push_back(std::pair(e,tl)); - slvr_add(tl); - } - - void RPFP_caching::ConstrainEdgeLocalizedCache(Edge *e, const Term &tl, std::vector &lits) - { - e->constraints.push_back(tl); - stack.back().constraints.push_back(std::pair(e,tl)); - GetAssumptionLits(tl,lits); - } - - - /** Declare a constant in the background theory. */ - - void RPFP::DeclareConstant(const FuncDecl &f){ - ls->declare_constant(f); - } - - /** Assert a background axiom. Background axioms can be used to provide the - * theory of auxilliary functions or relations. All symbols appearing in - * background axioms are considered global, and may appear in both transformer - * and relational solutions. Semantically, a solution to the RPFP gives - * an interpretation of the unknown relations for each interpretation of the - * auxilliary symbols that is consistent with the axioms. Axioms should be - * asserted before any calls to Push. They cannot be de-asserted by Pop. */ - - void RPFP::AssertAxiom(const Term &t) - { - ls->assert_axiom(t); - axioms.push_back(t); // for printing only - } - -#if 0 - /** Do not call this. */ - - void RPFP::RemoveAxiom(const Term &t) - { - slvr().RemoveInterpolationAxiom(t); - } -#endif - - /** Solve an RPFP graph. This means either strengthen the annotation - * so that the bound at the given root node is satisfied, or - * show that this cannot be done by giving a dual solution - * (i.e., a counterexample). - * - * In the current implementation, this only works for graphs that - * are: - * - tree-like - * - * - closed. - * - * In a tree-like graph, every nod has out most one incoming and one out-going edge, - * and there are no cycles. In a closed graph, every node has exactly one out-going - * edge. This means that the leaves of the tree are all hyper-edges with no - * children. Such an edge represents a relation (nullary transformer) and thus - * a lower bound on its parent. The parameter root must be the root of this tree. - * - * If Solve returns LBool.False, this indicates success. The annotation of the tree - * has been updated to satisfy the upper bound at the root. - * - * If Solve returns LBool.True, this indicates a counterexample. For each edge, - * you can then call Eval to determine the values of symbols in the transformer formula. - * You can also call Empty on a node to determine if its value in the counterexample - * is the empty relation. - * - * \param root The root of the tree - * \param persist Number of context pops through which result should persist - * - * - */ - - lbool RPFP::Solve(Node *root, int persist) - { - timer_start("Solve"); - TermTree *tree = GetConstraintTree(root); - TermTree *interpolant = nullptr; - TermTree *goals = nullptr; - if(ls->need_goals) - goals = GetGoalTree(root); - ClearProofCore(); - - // if (dualModel != null) dualModel.Dispose(); - // if (dualLabels != null) dualLabels.Dispose(); - - timer_start("interpolate_tree"); - lbool res = ls_interpolate_tree(tree, interpolant, dualModel,goals,true); - timer_stop("interpolate_tree"); - if (res == l_false) { - DecodeTree(root, interpolant->getChildren()[0], persist); - delete interpolant; - } - - delete tree; - if(goals) - delete goals; - - timer_stop("Solve"); - return res; - } - - void RPFP::CollapseTermTreeRec(TermTree *root, TermTree *node){ - root->addTerm(node->getTerm()); - std::vector &cnsts = node->getTerms(); - for(unsigned i = 0; i < cnsts.size(); i++) - root->addTerm(cnsts[i]); - std::vector &chs = node->getChildren(); - for(unsigned i = 0; i < chs.size(); i++){ - CollapseTermTreeRec(root,chs[i]); - } - } - - TermTree *RPFP::CollapseTermTree(TermTree *node){ - std::vector &chs = node->getChildren(); - for(unsigned i = 0; i < chs.size(); i++) - CollapseTermTreeRec(node,chs[i]); - for(unsigned i = 0; i < chs.size(); i++) - delete chs[i]; - chs.clear(); - return node; - } - - lbool RPFP::SolveSingleNode(Node *root, Node *node) - { - timer_start("Solve"); - TermTree *tree = CollapseTermTree(GetConstraintTree(root,node)); - tree->getChildren().push_back(CollapseTermTree(ToTermTree(node))); - TermTree *interpolant = nullptr; - ClearProofCore(); - - timer_start("interpolate_tree"); - lbool res = ls_interpolate_tree(tree, interpolant, dualModel,nullptr,true); - timer_stop("interpolate_tree"); - if (res == l_false) { - DecodeTree(node, interpolant->getChildren()[0], 0); - delete interpolant; - } - - delete tree; - timer_stop("Solve"); - return res; - } - - /** Get the constraint tree (but don't solve it) */ - - TermTree *RPFP::GetConstraintTree(Node *root, Node *skip_descendant) - { - return AddUpperBound(root, ToTermTree(root,skip_descendant)); - } - - /** Dispose of the dual model (counterexample) if there is one. */ - - void RPFP::DisposeDualModel() - { - dualModel = model(ctx,nullptr); - } - - RPFP::Term RPFP::UnderapproxFlag(Node *n){ - expr flag = ctx.constant((std::string("@under") + string_of_int(n->number)).c_str(), ctx.bool_sort()); - underapprox_flag_rev[flag] = n; - return flag; - } - - RPFP::Node *RPFP::UnderapproxFlagRev(const Term &flag){ - return underapprox_flag_rev[flag]; - } - - /** Check satisfiability of asserted edges and nodes. Same functionality as - * Solve, except no primal solution (interpolant) is generated in the unsat case. - * The vector underapproxes gives the set of node underapproximations to be enforced - * (assuming these were conditionally asserted by AssertEdge). - * - */ - - check_result RPFP::Check(Node *root, std::vector underapproxes, std::vector *underapprox_core) { - timer_start("Check"); - ClearProofCore(); - // if (dualModel != null) dualModel.Dispose(); - check_result res; - if (!underapproxes.size()) - res = slvr_check(); - else { - std::vector us(underapproxes.size()); - for (unsigned i = 0; i < underapproxes.size(); i++) - us[i] = UnderapproxFlag(underapproxes[i]); - slvr_check(); // TODO: no idea why I need to do this - if (underapprox_core) { - std::vector unsat_core(us.size()); - unsigned core_size = 0; - res = slvr_check(us.size(), VEC2PTR(us), &core_size, VEC2PTR(unsat_core)); - underapprox_core->resize(core_size); - for (unsigned i = 0; i < core_size; i++) - (*underapprox_core)[i] = UnderapproxFlagRev(unsat_core[i]); - } - else { - res = slvr_check(us.size(), VEC2PTR(us)); - bool dump = false; - if (dump) { - std::vector cnsts; - // cnsts.push_back(axioms[0]); - cnsts.push_back(root->dual); - cnsts.push_back(root->Outgoing->dual); - ls->write_interpolation_problem("temp.smt", cnsts, std::vector()); - } - } - // check_result temp = slvr_check(); - } - dualModel = slvr().get_model(); - timer_stop("Check"); - return res; - } - - check_result RPFP::CheckUpdateModel(Node *root, std::vector assumps){ - // check_result temp1 = slvr_check(); // no idea why I need to do this - ClearProofCore(); - check_result res = slvr_check(assumps.size(), VEC2PTR(assumps)); - model mod = slvr().get_model(); - if(!mod.null()) - dualModel = mod;; - return res; - } - - /** Determines the value in the counterexample of a symbol occurring in the transformer formula of - * a given edge. */ - - RPFP::Term RPFP::Eval(Edge *e, const Term& t) - { - Term tl = Localize(e, t); - return dualModel.eval(tl); - } - - /** Returns true if the given node is empty in the primal solution. For proceudure summaries, - this means that the procedure is not called in the current counter-model. */ - - bool RPFP::Empty(Node *p) - { - Term b; std::vector v; - RedVars(p, b, v); - // dualModel.show_internals(); - // std::cout << "b: " << b << std::endl; - expr bv = dualModel.eval(b); - // std::cout << "bv: " << bv << std::endl; - bool res = !eq(bv,ctx.bool_val(true)); - return res; - } - - RPFP::Term RPFP::EvalNode(Node *p) - { - Term b; std::vector v; - RedVars(p, b, v); - std::vector args; - for(unsigned i = 0; i < v.size(); i++) - args.push_back(dualModel.eval(v[i])); - return (p->Name)(args); - } - - void RPFP::EvalArrayTerm(const RPFP::Term &t, ArrayValue &res){ - if (t.is_app()) { - decl_kind k = t.decl().get_decl_kind(); - if (k == AsArray) { - func_decl fd = t.decl().get_func_decl_parameter(0); - func_interp r = dualModel.get_func_interp(fd); - int num = r.num_entries(); - res.defined = true; - for (int i = 0; i < num; i++) { - expr arg = r.get_arg(i, 0); - expr value = r.get_value(i); - res.entries[arg] = value; - } - res.def_val = r.else_value(); - return; - } - else if (k == Store) { - EvalArrayTerm(t.arg(0), res); - if (!res.defined)return; - expr addr = t.arg(1); - expr val = t.arg(2); - if (addr.is_numeral() && val.is_numeral()) { - if (eq(val, res.def_val)) - res.entries.erase(addr); - else - res.entries[addr] = val; - } - else - res.defined = false; - return; - } - } - res.defined = false; - } - - int eae_count = 0; - - RPFP::Term RPFP::EvalArrayEquality(const RPFP::Term &f) { - ArrayValue lhs, rhs; - eae_count++; - EvalArrayTerm(f.arg(0), lhs); - EvalArrayTerm(f.arg(1), rhs); - if (lhs.defined && rhs.defined) { - if (eq(lhs.def_val, rhs.def_val)) - if (lhs.entries == rhs.entries) - return ctx.bool_val(true); - return ctx.bool_val(false); - } - return f; - } - - /** Compute truth values of all boolean subterms in current model. - Assumes formulas has been simplified by Z3, so only boolean ops - ands and, or, not. Returns result in memo. - */ - - int RPFP::SubtermTruth(hash_map &memo, const Term &f) { - TRACE("duality", tout << f << "\n";); - if (memo.find(f) != memo.end()) { - return memo[f]; - } - int res; - if (f.is_app()) { - int nargs = f.num_args(); - decl_kind k = f.decl().get_decl_kind(); - if (k == Implies) { - res = SubtermTruth(memo, !f.arg(0) || f.arg(1)); - goto done; - } - if (k == And) { - res = 1; - for (int i = 0; i < nargs; i++) { - int ar = SubtermTruth(memo, f.arg(i)); - if (ar == 0) { - res = 0; - goto done; - } - if (ar == 2)res = 2; - } - goto done; - } - else if (k == Or) { - res = 0; - for (int i = 0; i < nargs; i++) { - int ar = SubtermTruth(memo, f.arg(i)); - if (ar == 1) { - res = 1; - goto done; - } - if (ar == 2)res = 2; - } - goto done; - } - else if (k == Not) { - int ar = SubtermTruth(memo, f.arg(0)); - res = (ar == 0) ? 1 : ((ar == 1) ? 0 : 2); - goto done; - } - } - { - bool pos; std::vector names; - if (f.is_label(pos, names)) { - res = SubtermTruth(memo, f.arg(0)); - goto done; - } - } - { - expr bv = dualModel.eval(f); - if (bv.is_app() && bv.decl().get_decl_kind() == Equal && - bv.arg(0).is_array()) { - bv = EvalArrayEquality(bv); - } - // Hack!!!! array equalities can occur negatively! - if (bv.is_app() && bv.decl().get_decl_kind() == Not && - bv.arg(0).decl().get_decl_kind() == Equal && - bv.arg(0).arg(0).is_array()) { - bv = dualModel.eval(!EvalArrayEquality(bv.arg(0))); - } - if (eq(bv, ctx.bool_val(true))) - res = 1; - else if (eq(bv, ctx.bool_val(false))) - res = 0; - else - res = 2; - } - done: - memo[f] = res; - return res; - } - - int RPFP::EvalTruth(hash_map &memo, Edge *e, const Term &f){ - Term tl = Localize(e, f); - return SubtermTruth(memo,tl); - } - - /** Compute truth values of all boolean subterms in current model. - Assumes formulas has been simplified by Z3, so only boolean ops - ands and, or, not. Returns result in memo. - */ - - - void RPFP::GetLabelsRec(hash_map &memo, const Term &f, std::vector &labels, - hash_set *done, bool truth) { - if (done[truth].find(f) != done[truth].end()) - return; /* already processed */ - if (f.is_app()) { - int nargs = f.num_args(); - decl_kind k = f.decl().get_decl_kind(); - if (k == Implies) { - GetLabelsRec(memo, f.arg(1) || !f.arg(0), labels, done, truth); - goto done; - } - if (k == Iff) { - int b = SubtermTruth(memo, f.arg(0)); - if (b == 2) { - goto done; - // bypass error - std::ostringstream os; - os << "disaster in SubtermTruth processing " << f; - throw default_exception(os.str()); - } - GetLabelsRec(memo, f.arg(1), labels, done, truth ? b : !b); - goto done; - } - if (truth ? k == And : k == Or) { - for (int i = 0; i < nargs; i++) - GetLabelsRec(memo, f.arg(i), labels, done, truth); - goto done; - } - if (truth ? k == Or : k == And) { - for (int i = 0; i < nargs; i++) { - Term a = f.arg(i); - timer_start("SubtermTruth"); - int b = SubtermTruth(memo, a); - timer_stop("SubtermTruth"); - if (truth ? (b == 1) : (b == 0)) { - GetLabelsRec(memo, a, labels, done, truth); - goto done; - } - } - /* Unreachable! */ - // throw "error in RPFP::GetLabelsRec"; - goto done; - } - else if (k == Not) { - GetLabelsRec(memo, f.arg(0), labels, done, !truth); - goto done; - } - else { - bool pos; std::vector names; - if (f.is_label(pos, names)) { - GetLabelsRec(memo, f.arg(0), labels, done, truth); - if (pos == truth) - for (unsigned i = 0; i < names.size(); i++) - labels.push_back(names[i]); - goto done; - } - } - } - done: - done[truth].insert(f); - } - - void RPFP::GetLabels(Edge *e, std::vector &labels){ - if(!e->map || e->map->labeled.null()) - return; - Term tl = Localize(e, e->map->labeled); - hash_map memo; - hash_set done[2]; - GetLabelsRec(memo,tl,labels,done,true); - } - -#ifdef Z3OPS - static Z3_subterm_truth *stt; -#endif - - int ir_count = 0; - - void RPFP::ImplicantRed(hash_map &memo, const Term &f, std::vector &lits, - hash_set *done, bool truth, hash_set &dont_cares) { - if (done[truth].find(f) != done[truth].end()) - return; /* already processed */ -#if 0 - int this_count = ir_count++; - if(this_count == 50092) - std::cout << "foo!\n"; -#endif - if (f.is_app()) { - int nargs = f.num_args(); - decl_kind k = f.decl().get_decl_kind(); - if (k == Implies) { - ImplicantRed(memo, f.arg(1) || !f.arg(0), lits, done, truth, dont_cares); - goto done; - } - if (k == Iff) { - int b = SubtermTruth(memo, f.arg(0)); - if (b == 2) { - std::ostringstream os; - os << "disaster in SubtermTruth processing " << f; - throw default_exception(os.str()); - } - ImplicantRed(memo, f.arg(1), lits, done, truth ? b : !b, dont_cares); - goto done; - } - if (truth ? k == And : k == Or) { - for (int i = 0; i < nargs; i++) - ImplicantRed(memo, f.arg(i), lits, done, truth, dont_cares); - goto done; - } - if (truth ? k == Or : k == And) { - for (int i = 0; i < nargs; i++) { - Term a = f.arg(i); -#if 0 - if(i == nargs - 1){ // last chance! - ImplicantRed(memo,a,lits,done,truth,dont_cares); - goto done; - } -#endif - timer_start("SubtermTruth"); -#ifdef Z3OPS - bool b = stt->eval(a); -#else - int b = SubtermTruth(memo, a); -#endif - timer_stop("SubtermTruth"); - if (truth ? (b == 1) : (b == 0)) { - ImplicantRed(memo, a, lits, done, truth, dont_cares); - goto done; - } - } - /* Unreachable! */ - // TODO: need to indicate this failure to caller - // std::cerr << "error in RPFP::ImplicantRed"; - goto done; - } - else if (k == Not) { - ImplicantRed(memo, f.arg(0), lits, done, !truth, dont_cares); - goto done; - } - } - { - if (dont_cares.find(f) == dont_cares.end()) { - expr rf = ResolveIte(memo, f, lits, done, dont_cares); - expr bv = truth ? rf : !rf; - lits.push_back(bv); - } - } - done: - done[truth].insert(f); - } - - void RPFP::ImplicantFullRed(hash_map &memo, const Term &f, std::vector &lits, - hash_set &done, hash_set &dont_cares, bool extensional) { - if (done.find(f) != done.end()) - return; /* already processed */ - if (f.is_app()) { - int nargs = f.num_args(); - decl_kind k = f.decl().get_decl_kind(); - if (k == Implies || k == Iff || k == And || k == Or || k == Not) { - for (int i = 0; i < nargs; i++) - ImplicantFullRed(memo, f.arg(i), lits, done, dont_cares, extensional); - goto done; - } - } - { - if (dont_cares.find(f) == dont_cares.end()) { - int b = SubtermTruth(memo, f); - if (b != 0 && b != 1) goto done; - if (f.is_app() && f.decl().get_decl_kind() == Equal && f.arg(0).is_array()) { - if (b == 1 && !extensional) { - expr x = dualModel.eval(f.arg(0)); expr y = dualModel.eval(f.arg(1)); - if (!eq(x, y)) - b = 0; - } - if (b == 0) - goto done; - } - expr bv = (b == 1) ? f : !f; - lits.push_back(bv); - } - } - done: - done.insert(f); - } - - RPFP::Term RPFP::ResolveIte(hash_map &memo, const Term &t, std::vector &lits, - hash_set *done, hash_set &dont_cares) { - if (resolve_ite_memo.find(t) != resolve_ite_memo.end()) - return resolve_ite_memo[t]; - Term res; - if (t.is_app()) { - func_decl f = t.decl(); - std::vector args; - int nargs = t.num_args(); - if (f.get_decl_kind() == Ite) { - timer_start("SubtermTruth"); -#ifdef Z3OPS - bool sel = stt->eval(t.arg(0)); -#else - int xval = SubtermTruth(memo, t.arg(0)); - bool sel; - if (xval == 0)sel = false; - else if (xval == 1)sel = true; - else - throw "unresolved ite in model"; -#endif - timer_stop("SubtermTruth"); - ImplicantRed(memo, t.arg(0), lits, done, sel, dont_cares); - res = ResolveIte(memo, t.arg(sel ? 1 : 2), lits, done, dont_cares); - } - else { - for (int i = 0; i < nargs; i++) - args.push_back(ResolveIte(memo, t.arg(i), lits, done, dont_cares)); - res = f(args.size(), VEC2PTR(args)); - } - } - else res = t; - resolve_ite_memo[t] = res; - return res; - } - - RPFP::Term RPFP::ElimIteRec(hash_map &memo, const Term &t, std::vector &cnsts) { - std::pair foo(t, expr(ctx)); - std::pair::iterator, bool> bar = memo.insert(foo); - Term &res = bar.first->second; - if (bar.second) { - if (t.is_app()) { - int nargs = t.num_args(); - std::vector args; - if (t.decl().get_decl_kind() == Equal) { - expr lhs = t.arg(0); - expr rhs = t.arg(1); - if (rhs.decl().get_decl_kind() == Ite) { - expr rhs_args[3]; - lhs = ElimIteRec(memo, lhs, cnsts); - for (int i = 0; i < 3; i++) - rhs_args[i] = ElimIteRec(memo, rhs.arg(i), cnsts); - res = (rhs_args[0] && (lhs == rhs_args[1])) || ((!rhs_args[0]) && (lhs == rhs_args[2])); - goto done; - } - } - if (t.decl().get_decl_kind() == Ite) { - func_decl sym = ctx.fresh_func_decl("@ite", t.get_sort()); - res = sym(); - cnsts.push_back(ElimIteRec(memo, ctx.make(Equal, res, t), cnsts)); - } - else { - for (int i = 0; i < nargs; i++) - args.push_back(ElimIteRec(memo, t.arg(i), cnsts)); - res = t.decl()(args.size(), VEC2PTR(args)); - } - } - else if (t.is_quantifier()) - res = clone_quantifier(t, ElimIteRec(memo, t.body(), cnsts)); - else - res = t; - } - done: - return res; - } - - RPFP::Term RPFP::ElimIte(const Term &t){ - hash_map memo; - std::vector cnsts; - expr res = ElimIteRec(memo,t,cnsts); - if(!cnsts.empty()){ - cnsts.push_back(res); - res = ctx.make(And,cnsts); - } - return res; - } - - void RPFP::Implicant(hash_map &memo, const Term &f, std::vector &lits, hash_set &dont_cares){ - hash_set done[2]; - ImplicantRed(memo,f,lits,done,true, dont_cares); - } - - - /** Underapproximate a formula using current counterexample. */ - - RPFP::Term RPFP::UnderapproxFormula(const Term &f, hash_set &dont_cares){ - /* first compute truth values of subterms */ - hash_map memo; -#ifdef Z3OPS - stt = Z3_mk_subterm_truth(ctx,dualModel); -#endif - // SubtermTruth(memo,f); - /* now compute an implicant */ - std::vector lits; - Implicant(memo,f,lits, dont_cares); -#ifdef Z3OPS - delete stt; stt = 0; -#endif - /* return conjunction of literals */ - return conjoin(lits); - } - - RPFP::Term RPFP::UnderapproxFullFormula(const Term &f, bool extensional){ - hash_set dont_cares; - resolve_ite_memo.clear(); - timer_start("UnderapproxFormula"); - /* first compute truth values of subterms */ - hash_map memo; - hash_set done; - std::vector lits; - ImplicantFullRed(memo,f,lits,done,dont_cares, extensional); - timer_stop("UnderapproxFormula"); - /* return conjunction of literals */ - return conjoin(lits); - } - - struct VariableProjector : Z3User { - - struct elim_cand { - Term var; - int sup; - Term val; - }; - - typedef expr Term; - - hash_set keep; - hash_map var_ord; - int num_vars; - std::vector elim_cands; - hash_map > sup_map; - hash_map elim_map; - std::vector ready_cands; - hash_map cand_map; - params simp_params; - - VariableProjector(Z3User &_user, std::vector &keep_vec) : - Z3User(_user), simp_params() { - num_vars = 0; - for (unsigned i = 0; i < keep_vec.size(); i++) { - keep.insert(keep_vec[i]); - var_ord[keep_vec[i]] = num_vars++; - } - } - int VarNum(const Term &v) { - if (var_ord.find(v) == var_ord.end()) - var_ord[v] = num_vars++; - return var_ord[v]; - } - - bool IsVar(const Term &t){ - return t.is_app() && t.num_args() == 0 && t.decl().get_decl_kind() == Uninterpreted; - } - - bool IsPropLit(const Term &t, Term &a) { - if (IsVar(t)) { - a = t; - return true; - } - else if (t.is_app() && t.decl().get_decl_kind() == Not) - return IsPropLit(t.arg(0), a); - return false; - } - - void CountOtherVarsRec(hash_map &memo, - const Term &t, - int id, - int &count) { - std::pair foo(t, 0); - std::pair::iterator, bool> bar = memo.insert(foo); - // int &res = bar.first->second; - if (!bar.second) return; - if (t.is_app()) { - func_decl f = t.decl(); - std::vector args; - int nargs = t.num_args(); - if (nargs == 0 && f.get_decl_kind() == Uninterpreted) { - if (cand_map.find(t) != cand_map.end()) { - count++; - sup_map[t].push_back(id); - } - } - for (int i = 0; i < nargs; i++) - CountOtherVarsRec(memo, t.arg(i), id, count); - } - else if (t.is_quantifier()) - CountOtherVarsRec(memo, t.body(), id, count); - } - - void NewElimCand(const Term &lhs, const Term &rhs) { - if (debug_gauss) { - std::cout << "mapping " << lhs << " to " << rhs << std::endl; - } - elim_cand cand; - cand.var = lhs; - cand.sup = 0; - cand.val = rhs; - elim_cands.push_back(cand); - cand_map[lhs] = elim_cands.size() - 1; - } - - void MakeElimCand(const Term &lhs, const Term &rhs) { - if (eq(lhs, rhs)) - return; - if (!IsVar(lhs)) { - if (IsVar(rhs)) { - MakeElimCand(rhs, lhs); - return; - } - else { - std::cout << "would have mapped a non-var\n"; - return; - } - } - if (IsVar(rhs) && VarNum(rhs) > VarNum(lhs)) { - MakeElimCand(rhs, lhs); - return; - } - if (keep.find(lhs) != keep.end()) - return; - if (cand_map.find(lhs) == cand_map.end()) - NewElimCand(lhs, rhs); - else { - int cand_idx = cand_map[lhs]; - if (IsVar(rhs) && cand_map.find(rhs) == cand_map.end() - && keep.find(rhs) == keep.end()) - NewElimCand(rhs, elim_cands[cand_idx].val); - elim_cands[cand_idx].val = rhs; - } - } - - Term FindRep(const Term &t) { - if (cand_map.find(t) == cand_map.end()) - return t; - Term &res = elim_cands[cand_map[t]].val; - if (IsVar(res)) { - assert(VarNum(res) < VarNum(t)); - res = FindRep(res); - return res; - } - return t; - } - - void GaussElimCheap(const std::vector &lits_in, - std::vector &lits_out) { - for (unsigned i = 0; i < lits_in.size(); i++) { - Term lit = lits_in[i]; - if (lit.is_app()) { - decl_kind k = lit.decl().get_decl_kind(); - if (k == Equal || k == Iff) - MakeElimCand(FindRep(lit.arg(0)), FindRep(lit.arg(1))); - } - } - - for (unsigned i = 0; i < elim_cands.size(); i++) { - elim_cand &cand = elim_cands[i]; - hash_map memo; - CountOtherVarsRec(memo, cand.val, i, cand.sup); - if (cand.sup == 0) - ready_cands.push_back(i); - } - - while (!ready_cands.empty()) { - elim_cand &cand = elim_cands[ready_cands.back()]; - ready_cands.pop_back(); - Term rep = FindRep(cand.var); - if (!eq(rep, cand.var)) - if (cand_map.find(rep) != cand_map.end()) { - int rep_pos = cand_map[rep]; - cand.val = elim_cands[rep_pos].val; - } - Term val = SubstRec(elim_map, cand.val); - if (debug_gauss) { - std::cout << "subbing " << cand.var << " --> " << val << std::endl; - } - elim_map[cand.var] = val; - std::vector &sup = sup_map[cand.var]; - for (unsigned i = 0; i < sup.size(); i++) { - int c = sup[i]; - if ((--elim_cands[c].sup) == 0) - ready_cands.push_back(c); - } - } - - for (unsigned i = 0; i < lits_in.size(); i++) { - Term lit = lits_in[i]; - lit = SubstRec(elim_map, lit); - lit = lit.simplify(); - if (eq(lit, ctx.bool_val(true))) - continue; - Term a; - if (IsPropLit(lit, a)) - if (keep.find(lit) == keep.end()) - continue; - lits_out.push_back(lit); - } - } - - // maps variables to constrains in which the occur pos, neg - hash_map la_index[2]; - hash_map la_coeffs[2]; - std::vector la_pos_vars; - bool fixing; - - void IndexLAcoeff(const Term &coeff1, const Term &coeff2, const Term &t, int id) { - Term coeff = coeff1 * coeff2; - coeff = coeff.simplify(); - Term is_pos = (coeff >= ctx.int_val(0)); - is_pos = is_pos.simplify(); - if (eq(is_pos, ctx.bool_val(true))) - IndexLA(true, coeff, t, id); - else - IndexLA(false, coeff, t, id); - } - - void IndexLAremove(const Term &t) { - if (IsVar(t)) { - la_index[0][t] = -1; // means ineligible to be eliminated - la_index[1][t] = -1; // (more that one occurrence, or occurs not in linear comb) - } - else if (t.is_app()) { - int nargs = t.num_args(); - for (int i = 0; i < nargs; i++) - IndexLAremove(t.arg(i)); - } - // TODO: quantifiers? - } - - - void IndexLA(bool pos, const Term &coeff, const Term &t, int id) { - if (t.is_numeral()) - return; - if (t.is_app()) { - int nargs = t.num_args(); - switch (t.decl().get_decl_kind()) { - case Plus: - for (int i = 0; i < nargs; i++) - IndexLA(pos, coeff, t.arg(i), id); - break; - case Sub: - IndexLA(pos, coeff, t.arg(0), id); - IndexLA(!pos, coeff, t.arg(1), id); - break; - case Times: - if (t.arg(0).is_numeral()) - IndexLAcoeff(coeff, t.arg(0), t.arg(1), id); - else if (t.arg(1).is_numeral()) - IndexLAcoeff(coeff, t.arg(1), t.arg(0), id); - break; - default: - if (IsVar(t) && (fixing || la_index[pos].find(t) == la_index[pos].end())) { - la_index[pos][t] = id; - la_coeffs[pos][t] = coeff; - if (pos && !fixing) - la_pos_vars.push_back(t); // this means we only add a var once - } - else - IndexLAremove(t); - } - } - } - - void IndexLAstart(bool pos, const Term &t, int id){ - IndexLA(pos,(pos ? ctx.int_val(1) : ctx.int_val(-1)), t, id); - } - - void IndexLApred(bool pos, const Term &p, int id) { - if (p.is_app()) { - switch (p.decl().get_decl_kind()) { - case Not: - IndexLApred(!pos, p.arg(0), id); - break; - case Leq: - case Lt: - IndexLAstart(!pos, p.arg(0), id); - IndexLAstart(pos, p.arg(1), id); - break; - case Geq: - case Gt: - IndexLAstart(pos, p.arg(0), id); - IndexLAstart(!pos, p.arg(1), id); - break; - default: - IndexLAremove(p); - } - } - } - - void IndexLAfix(const Term &p, int id){ - fixing = true; - IndexLApred(true,p,id); - fixing = false; - } - - bool IsCanonIneq(const Term &lit, Term &term, Term &bound) { - // std::cout << Z3_simplify_get_help(ctx) << std::endl; - bool pos = lit.decl().get_decl_kind() != Not; - Term atom = pos ? lit : lit.arg(0); - if (atom.decl().get_decl_kind() == Leq) { - if (pos) { - bound = atom.arg(0); - term = atom.arg(1).simplify(simp_params); -#if Z3_MAJOR_VERSION < 4 - term = SortSum(term); -#endif - } - else { - bound = (atom.arg(1) + ctx.int_val(1)); - term = atom.arg(0); - // std::cout << "simplifying bound: " << bound << std::endl; - bound = bound.simplify(); - term = term.simplify(simp_params); -#if Z3_MAJOR_VERSION < 4 - term = SortSum(term); -#endif - } - return true; - } - else if (atom.decl().get_decl_kind() == Geq) { - if (pos) { - bound = atom.arg(1); // integer axiom - term = atom.arg(0).simplify(simp_params); -#if Z3_MAJOR_VERSION < 4 - term = SortSum(term); -#endif - return true; - } - else { - bound = -(atom.arg(1) - ctx.int_val(1)); // integer axiom - term = -atom.arg(0); - bound = bound.simplify(); - term = term.simplify(simp_params); -#if Z3_MAJOR_VERSION < 4 - term = SortSum(term); -#endif - } - return true; - } - return false; - } - - Term CanonIneqTerm(const Term &p){ - Term term,bound; - Term ps = p.simplify(); - VERIFY(IsCanonIneq(ps,term,bound)); - return term - bound; - } - - void ElimRedundantBounds(std::vector &lits) { - hash_map best_bound; - for (unsigned i = 0; i < lits.size(); i++) { - lits[i] = lits[i].simplify(simp_params); - Term term, bound; - if (IsCanonIneq(lits[i], term, bound)) { - if (best_bound.find(term) == best_bound.end()) - best_bound[term] = i; - else { - int best = best_bound[term]; - Term bterm, bbound; - IsCanonIneq(lits[best], bterm, bbound); - Term comp = bound > bbound; - comp = comp.simplify(); - if (eq(comp, ctx.bool_val(true))) { - lits[best] = ctx.bool_val(true); - best_bound[term] = i; - } - else { - lits[i] = ctx.bool_val(true); - } - } - } - } - } - - void FourierMotzkinCheap(const std::vector &lits_in, - std::vector &lits_out) { - simp_params.set(":som", true); - simp_params.set(":sort-sums", true); - fixing = false; lits_out = lits_in; - ElimRedundantBounds(lits_out); - for (unsigned i = 0; i < lits_out.size(); i++) - IndexLApred(true, lits_out[i], i); - - for (unsigned i = 0; i < la_pos_vars.size(); i++) { - Term var = la_pos_vars[i]; - if (la_index[false].find(var) != la_index[false].end()) { - int pos_idx = la_index[true][var]; - int neg_idx = la_index[false][var]; - if (pos_idx >= 0 && neg_idx >= 0) { - if (keep.find(var) != keep.end()) { - std::cout << "would have eliminated keep var\n"; - continue; - } - Term tpos = CanonIneqTerm(lits_out[pos_idx]); - Term tneg = CanonIneqTerm(lits_out[neg_idx]); - Term pos_coeff = la_coeffs[true][var]; - Term neg_coeff = -la_coeffs[false][var]; - Term comb = neg_coeff * tpos + pos_coeff * tneg; - Term ineq = ctx.int_val(0) <= comb; - ineq = ineq.simplify(); - lits_out[pos_idx] = ineq; - lits_out[neg_idx] = ctx.bool_val(true); - IndexLAfix(ineq, pos_idx); - } - } - } - } - - Term ProjectFormula(const Term &f){ - std::vector lits, new_lits1, new_lits2; - CollectConjuncts(f,lits); - timer_start("GaussElimCheap"); - GaussElimCheap(lits,new_lits1); - timer_stop("GaussElimCheap"); - timer_start("FourierMotzkinCheap"); - FourierMotzkinCheap(new_lits1,new_lits2); - timer_stop("FourierMotzkinCheap"); - return conjoin(new_lits2); - } - }; - - void Z3User::CollectConjuncts(const Term &f, std::vector &lits, bool pos) { - if (f.is_app() && f.decl().get_decl_kind() == Not) - CollectConjuncts(f.arg(0), lits, !pos); - else if (pos && f.is_app() && f.decl().get_decl_kind() == And) { - int num_args = f.num_args(); - for (int i = 0; i < num_args; i++) - CollectConjuncts(f.arg(i), lits, true); - } - else if (!pos && f.is_app() && f.decl().get_decl_kind() == Or) { - int num_args = f.num_args(); - for (int i = 0; i < num_args; i++) - CollectConjuncts(f.arg(i), lits, false); - } - else if (pos) { - if (!eq(f, ctx.bool_val(true))) - lits.push_back(f); - } - else { - if (!eq(f, ctx.bool_val(false))) - lits.push_back(!f); - } - } - - void Z3User::CollectJuncts(const Term &f, std::vector &lits, decl_kind op, bool negate) { - if (f.is_app() && f.decl().get_decl_kind() == Not) - CollectJuncts(f.arg(0), lits, (op == And) ? Or : And, !negate); - else if (f.is_app() && f.decl().get_decl_kind() == op) { - int num_args = f.num_args(); - for (int i = 0; i < num_args; i++) - CollectJuncts(f.arg(i), lits, op, negate); - } - else { - expr junct = negate ? Negate(f) : f; - lits.push_back(junct); - } - } - - struct TermLt { - bool operator()(const expr &x, const expr &y){ - unsigned xid = x.get_id(); - unsigned yid = y.get_id(); - return xid < yid; - } - }; - - void Z3User::SortTerms(std::vector &terms){ - TermLt foo; - std::sort(terms.begin(),terms.end(),foo); - } - - Z3User::Term Z3User::SortSum(const Term &t){ - if(!(t.is_app() && t.decl().get_decl_kind() == Plus)) - return t; - int nargs = t.num_args(); - if(nargs < 2) return t; - std::vector args(nargs); - for(int i = 0; i < nargs; i++) - args[i] = t.arg(i); - SortTerms(args); - if(nargs == 2) - return args[0] + args[1]; - return sum(args); - } - - - RPFP::Term RPFP::ProjectFormula(std::vector &keep_vec, const Term &f){ - VariableProjector vp(*this,keep_vec); - return vp.ProjectFormula(f); - } - - /** Compute an underapproximation of every node in a tree rooted at "root", - based on a previously computed counterexample. The underapproximation - may contain free variables that are implicitly existentially quantified. - */ - - RPFP::Term RPFP::ComputeUnderapprox(Node *root, int persist){ - /* if terminated underapprox is empty set (false) */ - bool show_model = false; - if(show_model) - std::cout << dualModel << std::endl; - if(!root->Outgoing){ - root->Underapprox.SetEmpty(); - return ctx.bool_val(true); - } - /* if not used in cex, underapprox is empty set (false) */ - if(Empty(root)){ - root->Underapprox.SetEmpty(); - return ctx.bool_val(true); - } - /* compute underapprox of children first */ - std::vector &chs = root->Outgoing->Children; - std::vector chu(chs.size()); - for(unsigned i = 0; i < chs.size(); i++) - chu[i] = ComputeUnderapprox(chs[i],persist); - - Term b; std::vector v; - RedVars(root, b, v); - /* underapproximate the edge formula */ - hash_set dont_cares; - dont_cares.insert(b); - resolve_ite_memo.clear(); - timer_start("UnderapproxFormula"); - Term dual = root->Outgoing->dual.null() ? ctx.bool_val(true) : root->Outgoing->dual; - Term eu = UnderapproxFormula(dual,dont_cares); - timer_stop("UnderapproxFormula"); - /* combine with children */ - chu.push_back(eu); - eu = conjoin(chu); - /* project onto appropriate variables */ - eu = ProjectFormula(v,eu); - eu = eu.simplify(); - -#if 0 - /* check the result is consistent */ - { - hash_map memo; - int res = SubtermTruth(memo, eu); - if(res != 1) - throw "inconsistent projection"; - } -#endif - - /* rename to appropriate variable names */ - hash_map memo; - for (unsigned i = 0; i < v.size(); i++) - memo[v[i]] = root->Annotation.IndParams[i]; /* copy names from annotation */ - Term funder = SubstRec(memo, eu); - root->Underapprox = CreateRelation(root->Annotation.IndParams,funder); -#if 0 - if(persist) - Z3_persist_ast(ctx,root->Underapprox.Formula,persist); -#endif - return eu; - } - - void RPFP::FixCurrentState(Edge *edge){ - hash_set dont_cares; - resolve_ite_memo.clear(); - timer_start("UnderapproxFormula"); - Term dual = edge->dual.null() ? ctx.bool_val(true) : edge->dual; - Term eu = UnderapproxFormula(dual,dont_cares); - timer_stop("UnderapproxFormula"); - ConstrainEdgeLocalized(edge,eu); - } - - void RPFP::GetGroundLitsUnderQuants(hash_set *memo, const Term &f, std::vector &res, int under){ - if(memo[under].find(f) != memo[under].end()) - return; - memo[under].insert(f); - if (f.is_app()) { - if (!under && !f.has_quantifiers()) - return; - decl_kind k = f.decl().get_decl_kind(); - if (k == And || k == Or || k == Implies || k == Iff) { - int num_args = f.num_args(); - for (int i = 0; i < num_args; i++) - GetGroundLitsUnderQuants(memo, f.arg(i), res, under); - return; - } - } - else if (f.is_quantifier()){ -#if 0 - // treat closed quantified formula as a literal 'cause we hate nested quantifiers - if(under && IsClosedFormula(f)) - res.push_back(f); - else -#endif - GetGroundLitsUnderQuants(memo,f.body(),res,1); - return; - } - if(f.is_var()){ - // std::cout << "foo!\n"; - return; - } - if(under && f.is_ground()) - res.push_back(f); - } - - RPFP::Term RPFP::StrengthenFormulaByCaseSplitting(const Term &f, std::vector &case_lits){ - hash_set memo[2]; - std::vector lits; - GetGroundLitsUnderQuants(memo, f, lits, 0); - hash_set lits_hash; - for(unsigned i = 0; i < lits.size(); i++) - lits_hash.insert(lits[i]); - hash_map subst; - hash_map stt_memo; - std::vector conjuncts; - for(unsigned i = 0; i < lits.size(); i++){ - const expr &lit = lits[i]; - if(lits_hash.find(NegateLit(lit)) == lits_hash.end()){ - case_lits.push_back(lit); - bool tval = false; - expr atom = lit; - if(lit.is_app() && lit.decl().get_decl_kind() == Not){ - tval = true; - atom = lit.arg(0); - } - expr etval = ctx.bool_val(tval); - if(atom.is_quantifier()) - subst[atom] = etval; // this is a bit desperate, since we can't eval quants - else { - int b = SubtermTruth(stt_memo,atom); - if(b == (tval ? 1 : 0)) - subst[atom] = etval; - else { - if(b == 0 || b == 1){ - etval = ctx.bool_val(b ? true : false); - subst[atom] = etval; - conjuncts.push_back(b ? atom : !atom); - } - } - } - } - } - expr g = f; - if(!subst.empty()){ - g = SubstRec(subst,f); - if(conjuncts.size()) - g = g && ctx.make(And,conjuncts); - g = g.simplify(); - } -#if 1 - expr g_old = g; - g = RemoveRedundancy(g); - bool changed = !eq(g,g_old); - g = g.simplify(); - if(changed) { // a second pass can get some more simplification - g = RemoveRedundancy(g); - g = g.simplify(); - } -#else - g = RemoveRedundancy(g); - g = g.simplify(); -#endif - g = AdjustQuantifiers(g); - return g; - } - - RPFP::Term RPFP::ModelValueAsConstraint(const Term &t) { - if (t.is_array()) { - ArrayValue arr; - Term e = dualModel.eval(t); - EvalArrayTerm(e, arr); - if (arr.defined) { - std::vector cs; - for (std::map::iterator it = arr.entries.begin(), en = arr.entries.end(); it != en; ++it) { - expr foo = select(t, expr(ctx, it->first)) == expr(ctx, it->second); - cs.push_back(foo); - } - return conjoin(cs); - } - } - else { - expr r = dualModel.get_const_interp(t.decl()); - if (!r.null()) { - expr res = t == expr(ctx, r); - return res; - } - } - return ctx.bool_val(true); - } - - void RPFP::EvalNodeAsConstraint(Node *p, Transformer &res) - { - Term b; std::vector v; - RedVars(p, b, v); - std::vector args; - for(unsigned i = 0; i < v.size(); i++){ - expr val = ModelValueAsConstraint(v[i]); - if(!eq(val,ctx.bool_val(true))) - args.push_back(val); - } - expr cnst = conjoin(args); - hash_map memo; - for (unsigned i = 0; i < v.size(); i++) - memo[v[i]] = p->Annotation.IndParams[i]; /* copy names from annotation */ - Term funder = SubstRec(memo, cnst); - res = CreateRelation(p->Annotation.IndParams,funder); - } - -#if 0 - void RPFP::GreedyReduce(solver &s, std::vector &conjuncts){ - // verify - s.push(); - expr conj = ctx.make(And,conjuncts); - s.add(conj); - check_result res = s.check(); - if(res != unsat) - throw "should be unsat"; - s.pop(1); - - for(unsigned i = 0; i < conjuncts.size(); ){ - std::swap(conjuncts[i],conjuncts.back()); - expr save = conjuncts.back(); - conjuncts.pop_back(); - s.push(); - expr conj = ctx.make(And,conjuncts); - s.add(conj); - check_result res = s.check(); - s.pop(1); - if(res != unsat){ - conjuncts.push_back(save); - std::swap(conjuncts[i],conjuncts.back()); - i++; - } - } - } -#endif - - void RPFP::GreedyReduce(solver &s, std::vector &conjuncts){ - std::vector lits(conjuncts.size()); - for(unsigned i = 0; i < lits.size(); i++){ - func_decl pred = ctx.fresh_func_decl("@alit", ctx.bool_sort()); - lits[i] = pred(); - s.add(ctx.make(Implies,lits[i],conjuncts[i])); - } - - // verify - check_result res = s.check(lits.size(), VEC2PTR(lits)); - if(res != unsat){ - // add the axioms in the off chance they are useful - const std::vector &theory = ls->get_axioms(); - for(unsigned i = 0; i < theory.size(); i++) - s.add(theory[i]); - for(int k = 0; k < 100; k++) // keep trying, maybe MBQI will do something! - if(s.check(lits.size(), VEC2PTR(lits)) == unsat) - goto is_unsat; - throw "should be unsat"; - } - is_unsat: - for(unsigned i = 0; i < conjuncts.size(); ){ - std::swap(conjuncts[i],conjuncts.back()); - std::swap(lits[i],lits.back()); - check_result res = s.check(lits.size()-1, VEC2PTR(lits)); - if(res != unsat){ - std::swap(conjuncts[i],conjuncts.back()); - std::swap(lits[i],lits.back()); - i++; - } - else { - conjuncts.pop_back(); - lits.pop_back(); - } - } - } - - void foobar(){ - } - - void RPFP::GreedyReduceNodes(std::vector &nodes){ - std::vector lits; - for(unsigned i = 0; i < nodes.size(); i++){ - Term b; std::vector v; - RedVars(nodes[i], b, v); - lits.push_back(!b); - expr bv = dualModel.eval(b); - if(eq(bv,ctx.bool_val(true))){ - check_result res = slvr_check(lits.size(), VEC2PTR(lits)); - if(res == unsat) - lits.pop_back(); - else - foobar(); - } - } - } - - check_result RPFP::CheckWithConstrainedNodes(std::vector &posnodes,std::vector &negnodes){ - timer_start("Check"); - std::vector lits; - for(unsigned i = 0; i < posnodes.size(); i++){ - Term b; std::vector v; - RedVars(posnodes[i], b, v); - lits.push_back(b); - } - for(unsigned i = 0; i < negnodes.size(); i++){ - Term b; std::vector v; - RedVars(negnodes[i], b, v); - lits.push_back(!b); - } - check_result res = slvr_check(lits.size(), VEC2PTR(lits)); - if(res == unsat && posnodes.size()){ - lits.resize(posnodes.size()); - res = slvr_check(lits.size(), VEC2PTR(lits)); - } - dualModel = slvr().get_model(); -#if 0 - if(!dualModel.null()){ - std::cout << "posnodes called:\n"; - for(unsigned i = 0; i < posnodes.size(); i++) - if(!Empty(posnodes[i])) - std::cout << posnodes[i]->Name.name() << "\n"; - std::cout << "negnodes called:\n"; - for(unsigned i = 0; i < negnodes.size(); i++) - if(!Empty(negnodes[i])) - std::cout << negnodes[i]->Name.name() << "\n"; - } -#endif - timer_stop("Check"); - return res; - } - - - void RPFP_caching::FilterCore(std::vector &core, std::vector &full_core){ - hash_set core_set; - std::copy(full_core.begin(),full_core.end(),std::inserter(core_set,core_set.begin())); - std::vector new_core; - for(unsigned i = 0; i < core.size(); i++) - if(core_set.find(core[i]) != core_set.end()) - new_core.push_back(core[i]); - core.swap(new_core); - } - - void RPFP_caching::GreedyReduceCache(std::vector &assumps, std::vector &core){ - std::vector lits = assumps, full_core; - std::copy(core.begin(),core.end(),std::inserter(lits,lits.end())); - - // verify - check_result res = CheckCore(lits,full_core); - if(res != unsat){ - // add the axioms in the off chance they are useful - const std::vector &theory = ls->get_axioms(); - for(unsigned i = 0; i < theory.size(); i++) - GetAssumptionLits(theory[i],assumps); - lits = assumps; - std::copy(core.begin(),core.end(),std::inserter(lits,lits.end())); - - for(int k = 0; k < 4; k++) // keep trying, maybe MBQI will do something! - if((res = CheckCore(lits,full_core)) == unsat) - goto is_unsat; - throw greedy_reduce_failed(); - } - is_unsat: - FilterCore(core,full_core); - - std::vector dummy; - if(CheckCore(full_core,dummy) != unsat) - throw "should be unsat"; - - for(unsigned i = 0; i < core.size(); ){ - expr temp = core[i]; - std::swap(core[i],core.back()); - core.pop_back(); - lits.resize(assumps.size()); - std::copy(core.begin(),core.end(),std::inserter(lits,lits.end())); - res = CheckCore(lits,full_core); - if(res != unsat){ - core.push_back(temp); - std::swap(core[i],core.back()); - i++; - } - } - } - - expr RPFP::NegateLit(const expr &f){ - if(f.is_app() && f.decl().get_decl_kind() == Not) - return f.arg(0); - else - return !f; - } - - void RPFP::NegateLits(std::vector &lits){ - for(unsigned i = 0; i < lits.size(); i++){ - expr &f = lits[i]; - if(f.is_app() && f.decl().get_decl_kind() == Not) - f = f.arg(0); - else - f = !f; - } - } - - expr RPFP::SimplifyOr(std::vector &lits){ - if(lits.size() == 0) - return ctx.bool_val(false); - if(lits.size() == 1) - return lits[0]; - return ctx.make(Or,lits); - } - - expr RPFP::SimplifyAnd(std::vector &lits){ - if(lits.size() == 0) - return ctx.bool_val(true); - if(lits.size() == 1) - return lits[0]; - return ctx.make(And,lits); - } - - - /* This is a wrapper for a solver that is intended to compute - implicants from models. It works around a problem in Z3 with - models in the non-extensional array theory. It does this by - naming all of the store terms in a formula. That is, (store ...) - is replaced by "name" with an added constraint name = (store - ...). This allows us to determine from the model whether an array - equality is true or false (it is false if the two sides are - mapped to different function symbols, even if they have the same - contents). - */ - - struct implicant_solver { - RPFP *owner; - solver &aux_solver; - std::vector assumps, namings; - std::vector assump_stack, naming_stack; - hash_map renaming, renaming_memo; - - void add(const expr &e){ - expr t = e; - if(!aux_solver.extensional_array_theory()){ - unsigned i = namings.size(); - t = owner->ExtractStores(renaming_memo,t,namings,renaming); - for(; i < namings.size(); i++) - aux_solver.add(namings[i]); - } - assumps.push_back(t); - aux_solver.add(t); - } - - void push() { - assump_stack.push_back(assumps.size()); - naming_stack.push_back(namings.size()); - aux_solver.push(); - } - - // When we pop the solver, we have to re-add any namings that were lost - - void pop(int n) { - aux_solver.pop(n); - int new_assumps = assump_stack[assump_stack.size()-n]; - int new_namings = naming_stack[naming_stack.size()-n]; - for(unsigned i = new_namings; i < namings.size(); i++) - aux_solver.add(namings[i]); - assumps.resize(new_assumps); - namings.resize(new_namings); - assump_stack.resize(assump_stack.size()-1); - naming_stack.resize(naming_stack.size()-1); - } - - check_result check() { - return aux_solver.check(); - } - - model get_model() { - return aux_solver.get_model(); - } - - expr get_implicant() { - owner->dualModel = aux_solver.get_model(); - expr dual = owner->ctx.make(And,assumps); - bool ext = aux_solver.extensional_array_theory(); - expr eu = owner->UnderapproxFullFormula(dual,ext); - // if we renamed store terms, we have to undo - if(!ext) - eu = owner->SubstRec(renaming,eu); - return eu; - } - - implicant_solver(RPFP *_owner, solver &_aux_solver) - : owner(_owner), aux_solver(_aux_solver) - {} - }; - - // set up edge constraint in aux solver - void RPFP::AddEdgeToSolver(implicant_solver &aux_solver, Edge *edge){ - if(!edge->dual.null()) - aux_solver.add(edge->dual); - for(unsigned i = 0; i < edge->constraints.size(); i++){ - expr tl = edge->constraints[i]; - aux_solver.add(tl); - } - } - - void RPFP::AddEdgeToSolver(Edge *edge){ - if(!edge->dual.null()) - aux_solver.add(edge->dual); - for(unsigned i = 0; i < edge->constraints.size(); i++){ - expr tl = edge->constraints[i]; - aux_solver.add(tl); - } - } - - static int by_case_counter = 0; - - void RPFP::InterpolateByCases(Node *root, Node *node){ - timer_start("InterpolateByCases"); - bool axioms_added = false; - hash_set axioms_needed; - const std::vector &theory = ls->get_axioms(); - for(unsigned i = 0; i < theory.size(); i++) - axioms_needed.insert(theory[i]); - implicant_solver is(this,aux_solver); - is.push(); - AddEdgeToSolver(is,node->Outgoing); - node->Annotation.SetEmpty(); - hash_set *core = new hash_set; - core->insert(node->Outgoing->dual); - expr prev_annot = ctx.bool_val(false); - expr prev_impl = ctx.bool_val(false); - int repeated_case_count = 0; - while(1){ - by_case_counter++; - is.push(); - expr annot = !GetAnnotation(node); - Transformer old_annot = node->Annotation; - is.add(annot); - if(is.check() == unsat){ - is.pop(1); - break; - } - is.pop(1); - Push(); - expr the_impl = is.get_implicant(); - if(eq(the_impl,prev_impl)){ - // std::cout << "got old implicant\n"; - repeated_case_count++; - } - prev_impl = the_impl; - ConstrainEdgeLocalized(node->Outgoing,the_impl); - ConstrainEdgeLocalized(node->Outgoing,!GetAnnotation(node)); //TODO: need this? - - { - check_result foo = Check(root); - if(foo != unsat){ - Pop(1); - is.pop(1); - delete core; - timer_stop("InterpolateByCases"); - throw ReallyBad(); - // slvr().print("should_be_unsat.smt2"); - // throw "should be unsat"; - } - std::vector assumps, axioms_to_add; - slvr().get_proof().get_assumptions(assumps); - for(unsigned i = 0; i < assumps.size(); i++){ - (*core).insert(assumps[i]); - if(axioms_needed.find(assumps[i]) != axioms_needed.end()){ - axioms_to_add.push_back(assumps[i]); - axioms_needed.erase(assumps[i]); - } - } - // AddToProofCore(*core); - - try { - SolveSingleNode(root,node); - } - catch (char const *msg){ - // This happens if interpolation fails - Pop(1); - is.pop(1); - delete core; - timer_stop("InterpolateByCases"); - throw msg; - } - { - expr itp = GetAnnotation(node); - dualModel = is.get_model(); // TODO: what does this mean? - std::vector case_lits; - itp = StrengthenFormulaByCaseSplitting(itp, case_lits); - SetAnnotation(node,itp); - node->Annotation.Formula = node->Annotation.Formula.simplify(); - } - - for(unsigned i = 0; i < axioms_to_add.size(); i++) - is.add(axioms_to_add[i]); - -#define TEST_BAD -#ifdef TEST_BAD - { - static int bad_count = 0, num_bads = 1; - if(bad_count >= num_bads){ - bad_count = 0; - num_bads = num_bads * 2; - Pop(1); - is.pop(1); - delete core; - timer_stop("InterpolateByCases"); - throw Bad(); - } - bad_count++; - } -#endif - } - - if(node->Annotation.IsEmpty() || eq(node->Annotation.Formula,prev_annot) || (repeated_case_count > 0 && !axioms_added) || (repeated_case_count >= 10)){ - //looks_bad: - if(!axioms_added){ - // add the axioms in the off chance they are useful - const std::vector &theory = ls->get_axioms(); - for(unsigned i = 0; i < theory.size(); i++) - is.add(theory[i]); - axioms_added = true; - } - else { - //#define KILL_ON_BAD_INTERPOLANT -#ifdef KILL_ON_BAD_INTERPOLANT - std::cout << "bad in InterpolateByCase -- core:\n"; -#if 0 - std::vector assumps; - slvr().get_proof().get_assumptions(assumps); - for(unsigned i = 0; i < assumps.size(); i++) - assumps[i].show(); -#endif - std::cout << "checking for inconsistency\n"; - std::cout << "model:\n"; - is.get_model().show(); - expr impl = is.get_implicant(); - std::vector conjuncts; - CollectConjuncts(impl,conjuncts,true); - std::cout << "impl:\n"; - for(unsigned i = 0; i < conjuncts.size(); i++) - conjuncts[i].show(); - std::cout << "annot:\n"; - annot.show(); - is.add(annot); - for(unsigned i = 0; i < conjuncts.size(); i++) - is.add(conjuncts[i]); - if(is.check() == unsat){ - std::cout << "inconsistent!\n"; - std::vector is_assumps; - is.aux_solver.get_proof().get_assumptions(is_assumps); - std::cout << "core:\n"; - for(unsigned i = 0; i < is_assumps.size(); i++) - is_assumps[i].show(); - } - else { - std::cout << "consistent!\n"; - is.aux_solver.print("should_be_inconsistent.smt2"); - } - std::cout << "by_case_counter = " << by_case_counter << "\n"; - throw "ack!"; -#endif - Pop(1); - is.pop(1); - delete core; - timer_stop("InterpolateByCases"); - throw ReallyBad(); - } - } - Pop(1); - prev_annot = node->Annotation.Formula; - node->Annotation.UnionWith(old_annot); - } - if(proof_core) - delete proof_core; // shouldn't happen - proof_core = core; - is.pop(1); - timer_stop("InterpolateByCases"); - } - - void RPFP::Generalize(Node *root, Node *node){ - timer_start("Generalize"); - aux_solver.push(); - AddEdgeToSolver(node->Outgoing); - expr fmla = GetAnnotation(node); - std::vector conjuncts; - CollectConjuncts(fmla,conjuncts,false); - GreedyReduce(aux_solver,conjuncts); // try to remove conjuncts one at a tme - aux_solver.pop(1); - NegateLits(conjuncts); - SetAnnotation(node,SimplifyOr(conjuncts)); - timer_stop("Generalize"); - } - - RPFP_caching::edge_solver &RPFP_caching::SolverForEdge(Edge *edge, bool models, bool axioms){ - edge_solver &es = edge_solvers[edge]; - uptr &p = es.slvr; - if(!p.get()){ - scoped_no_proof no_proofs_please(ctx.m()); // no proofs - p.set(new solver(ctx,true,models)); // no models - if(axioms){ - RPFP::LogicSolver *ls = edge->owner->ls; - const std::vector &axs = ls->get_axioms(); - for(unsigned i = 0; i < axs.size(); i++) - p.get()->add(axs[i]); - } - } - return es; - } - - - // caching version of above - void RPFP_caching::GeneralizeCache(Edge *edge){ - timer_start("Generalize"); - scoped_solver_for_edge ssfe(this,edge); - Node *node = edge->Parent; - std::vector assumps, core, conjuncts; - AssertEdgeCache(edge,assumps); - for(unsigned i = 0; i < edge->Children.size(); i++){ - expr as = GetAnnotation(edge->Children[i]); - std::vector clauses; - if(!as.is_true()){ - CollectConjuncts(as.arg(1),clauses); - for(unsigned j = 0; j < clauses.size(); j++) - GetAssumptionLits(as.arg(0) || clauses[j],assumps); - } - } - expr fmla = GetAnnotation(node); - std::vector lits; - if(fmla.is_true()){ - timer_stop("Generalize"); - return; - } - assumps.push_back(fmla.arg(0).arg(0)); - CollectConjuncts(!fmla.arg(1),lits); -#if 0 - for(unsigned i = 0; i < lits.size(); i++){ - const expr &lit = lits[i]; - if(lit.is_app() && lit.decl().get_decl_kind() == Equal){ - lits[i] = ctx.make(Leq,lit.arg(0),lit.arg(1)); - lits.push_back(ctx.make(Leq,lit.arg(1),lit.arg(0))); - } - } -#endif - hash_map lit_map; - for(unsigned i = 0; i < lits.size(); i++) - GetAssumptionLits(lits[i],core,&lit_map); - GreedyReduceCache(assumps,core); - for(unsigned i = 0; i < core.size(); i++) - conjuncts.push_back(lit_map[core[i]]); - NegateLits(conjuncts); - SetAnnotation(node,SimplifyOr(conjuncts)); - timer_stop("Generalize"); - } - - // caching version of above - bool RPFP_caching::PropagateCache(Edge *edge){ - timer_start("PropagateCache"); - scoped_solver_for_edge ssfe(this,edge); - bool some = false; - { - std::vector candidates, skip; - Node *node = edge->Parent; - CollectConjuncts(node->Annotation.Formula,skip); - for(unsigned i = 0; i < edge->Children.size(); i++){ - Node *child = edge->Children[i]; - if(child->map == node->map){ - CollectConjuncts(child->Annotation.Formula,candidates); - break; - } - } - if(candidates.empty()) goto done; - hash_set skip_set; - std::copy(skip.begin(),skip.end(),std::inserter(skip_set,skip_set.begin())); - std::vector new_candidates; - for(unsigned i = 0; i < candidates.size(); i++) - if(skip_set.find(candidates[i]) == skip_set.end()) - new_candidates.push_back(candidates[i]); - candidates.swap(new_candidates); - if(candidates.empty()) goto done; - std::vector assumps, core, conjuncts; - AssertEdgeCache(edge,assumps); - for(unsigned i = 0; i < edge->Children.size(); i++){ - expr ass = GetAnnotation(edge->Children[i]); - if(eq(ass,ctx.bool_val(true))) - continue; - std::vector clauses; - CollectConjuncts(ass.arg(1),clauses); - for(unsigned j = 0; j < clauses.size(); j++) - GetAssumptionLits(ass.arg(0) || clauses[j],assumps); - } - for(unsigned i = 0; i < candidates.size(); i++){ - unsigned old_size = assumps.size(); - node->Annotation.Formula = candidates[i]; - expr fmla = GetAnnotation(node); - assumps.push_back(fmla.arg(0).arg(0)); - GetAssumptionLits(!fmla.arg(1),assumps); - std::vector full_core; - check_result res = CheckCore(assumps,full_core); - if(res == unsat) - conjuncts.push_back(candidates[i]); - assumps.resize(old_size); - } - if(conjuncts.empty()) - goto done; - SetAnnotation(node,SimplifyAnd(conjuncts)); - some = true; - } - done: - timer_stop("PropagateCache"); - return some; - } - - - /** Push a scope. Assertions made after Push can be undone by Pop. */ - - void RPFP::Push() - { - stack.push_back(stack_entry()); - slvr_push(); - } - - /** Pop a scope (see Push). Note, you cannot pop axioms. */ - - void RPFP::Pop(int num_scopes) - { - slvr_pop(num_scopes); - for (int i = 0; i < num_scopes; i++) - { - stack_entry &back = stack.back(); - for(std::list::iterator it = back.edges.begin(), en = back.edges.end(); it != en; ++it) - (*it)->dual = expr(ctx,nullptr); - for(std::list::iterator it = back.nodes.begin(), en = back.nodes.end(); it != en; ++it) - (*it)->dual = expr(ctx,nullptr); - for(std::list >::iterator it = back.constraints.begin(), en = back.constraints.end(); it != en; ++it) - (*it).first->constraints.pop_back(); - stack.pop_back(); - } - } - - /** Erase the proof by performing a Pop, Push and re-assertion of - all the popped constraints */ - - void RPFP::PopPush(){ - slvr_pop(1); - slvr_push(); - stack_entry &back = stack.back(); - for(std::list::iterator it = back.edges.begin(), en = back.edges.end(); it != en; ++it) - slvr_add((*it)->dual); - for(std::list::iterator it = back.nodes.begin(), en = back.nodes.end(); it != en; ++it) - slvr_add((*it)->dual); - for(std::list >::iterator it = back.constraints.begin(), en = back.constraints.end(); it != en; ++it) - slvr_add((*it).second); - } - - - - // This returns a new FuncDel with same sort as top-level function - // of term t, but with numeric suffix appended to name. - - Z3User::FuncDecl Z3User::SuffixFuncDecl(const Term &t, int n) - { - std::string name = t.decl().name().str() + "_" + string_of_int(n); - std::vector sorts; - int nargs = t.num_args(); - sorts.reserve(nargs); - for(int i = 0; i < nargs; i++) - sorts.push_back(t.arg(i).get_sort()); - return ctx.function(name.c_str(), nargs, VEC2PTR(sorts), t.get_sort()); - } - - Z3User::FuncDecl Z3User::RenumberPred(const FuncDecl &f, int n) - { - std::string name = f.name().str(); - name = name.substr(0,name.rfind('_')) + "_" + string_of_int(n); - int arity = f.arity(); - std::vector domain; - domain.reserve(arity); - for(int i = 0; i < arity; i++) - domain.push_back(f.domain(i)); - return ctx.function(name.c_str(), arity, VEC2PTR(domain), f.range()); - } - - Z3User::FuncDecl Z3User::NumberPred(const FuncDecl &f, int n) - { - std::string name = f.name().str(); - name = name + "_" + string_of_int(n); - int arity = f.arity(); - std::vector domain; - domain.reserve(arity); - for(int i = 0; i < arity; i++) - domain.push_back(f.domain(i)); - return ctx.function(name.c_str(), arity, VEC2PTR(domain), f.range()); - } - - // Scan the clause body for occurrences of the predicate unknowns - - RPFP::Term RPFP::ScanBody(hash_map &memo, - const Term &t, - hash_map &pmap, - std::vector &parms, - std::vector &nodes) - { - if(memo.find(t) != memo.end()) - return memo[t]; - Term res(ctx); - if (t.is_app()) { - func_decl f = t.decl(); - if(pmap.find(f) != pmap.end()){ - nodes.push_back(pmap[f]); - f = SuffixFuncDecl(t,parms.size()); - parms.push_back(f); - } - int nargs = t.num_args(); - std::vector args; - args.reserve(nargs); - for(int i = 0; i < nargs; i++) - args.push_back(ScanBody(memo,t.arg(i),pmap,parms,nodes)); - res = f(nargs, VEC2PTR(args)); - } - else if (t.is_quantifier()) - res = CloneQuantifier(t,ScanBody(memo,t.body(),pmap,parms,nodes)); - else - res = t; - memo[t] = res; - return res; - } - - // return the func_del of an app if it is uninterpreted - - bool Z3User::get_relation(const Term &t, func_decl &R){ - if(!t.is_app()) - return false; - R = t.decl(); - return R.get_decl_kind() == Uninterpreted; - } - - // return true if term is an individual variable - // TODO: have to check that it is not a background symbol - - bool Z3User::is_variable(const Term &t){ - if(!t.is_app()) - return t.is_var(); - return t.decl().get_decl_kind() == Uninterpreted - && t.num_args() == 0; - } - - RPFP::Term RPFP::RemoveLabelsRec(hash_map &memo, const Term &t, - std::vector &lbls){ - if(memo.find(t) != memo.end()) - return memo[t]; - Term res(ctx); - if (t.is_app()){ - func_decl f = t.decl(); - std::vector names; - bool pos; - if(t.is_label(pos,names)){ - res = RemoveLabelsRec(memo,t.arg(0),lbls); - for(unsigned i = 0; i < names.size(); i++) - lbls.push_back(label_struct(names[i],res,pos)); - } - else { - int nargs = t.num_args(); - std::vector args; - args.reserve(nargs); - for(int i = 0; i < nargs; i++) - args.push_back(RemoveLabelsRec(memo,t.arg(i),lbls)); - res = f(nargs, VEC2PTR(args)); - } - } - else if (t.is_quantifier()) - res = CloneQuantifier(t,RemoveLabelsRec(memo,t.body(),lbls)); - else - res = t; - memo[t] = res; - return res; - } - - RPFP::Term RPFP::RemoveLabels(const Term &t, std::vector &lbls){ - hash_map memo ; - return RemoveLabelsRec(memo,t,lbls); - } - - RPFP::Term RPFP::SubstBoundRec(hash_map > &memo, hash_map &subst, int level, const Term &t) - { - std::pair foo(t,expr(ctx)); - std::pair::iterator, bool> bar = memo[level].insert(foo); - Term &res = bar.first->second; - if(!bar.second) return res; - if (t.is_app()) - { - func_decl f = t.decl(); - std::vector args; - int nargs = t.num_args(); - args.reserve(nargs); - if(nargs == 0 && f.get_decl_kind() == Uninterpreted) - ls->declare_constant(f); // keep track of background constants - for(int i = 0; i < nargs; i++) - args.push_back(SubstBoundRec(memo, subst, level, t.arg(i))); - res = f(args.size(), VEC2PTR(args)); - } - else if (t.is_quantifier()){ - int bound = t.get_quantifier_num_bound(); - std::vector pats; - t.get_patterns(pats); - for(unsigned i = 0; i < pats.size(); i++) - pats[i] = SubstBoundRec(memo, subst, level + bound, pats[i]); - res = clone_quantifier(t, SubstBoundRec(memo, subst, level + bound, t.body()), pats); - } - else if (t.is_var()) { - int idx = t.get_index_value(); - if(idx >= level && subst.find(idx-level) != subst.end()){ - res = subst[idx-level]; - } - else res = t; - } - else res = t; - return res; - } - - RPFP::Term RPFP::SubstBound(hash_map &subst, const Term &t){ - hash_map > memo; - return SubstBoundRec(memo, subst, 0, t); - } - - // Eliminate the deBruijn indices from level to level+num-1 - Z3User::Term Z3User::DeleteBoundRec(hash_map > &memo, int level, int num, const Term &t) - { - std::pair foo(t,expr(ctx)); - std::pair::iterator, bool> bar = memo[level].insert(foo); - Term &res = bar.first->second; - if(!bar.second) return res; - if (t.is_app()) - { - func_decl f = t.decl(); - std::vector args; - int nargs = t.num_args(); - args.reserve(nargs); - for(int i = 0; i < nargs; i++) - args.push_back(DeleteBoundRec(memo, level, num, t.arg(i))); - res = f(args.size(), VEC2PTR(args)); - } - else if (t.is_quantifier()){ - int bound = t.get_quantifier_num_bound(); - std::vector pats; - t.get_patterns(pats); - for(unsigned i = 0; i < pats.size(); i++) - pats[i] = DeleteBoundRec(memo, level + bound, num, pats[i]); - res = clone_quantifier(t, DeleteBoundRec(memo, level + bound, num, t.body()), pats); - } - else if (t.is_var()) { - int idx = t.get_index_value(); - if(idx >= level){ - res = ctx.make_var(idx-num,t.get_sort()); - } - else res = t; - } - else res = t; - return res; - } - - Z3User::Term Z3User::DeleteBound(int level, int num, const Term &t){ - hash_map > memo; - return DeleteBoundRec(memo, level, num, t); - } - - int Z3User::MaxIndex(hash_map &memo, const Term &t) - { - std::pair foo(t,-1); - std::pair::iterator, bool> bar = memo.insert(foo); - int &res = bar.first->second; - if(!bar.second) return res; - if (t.is_app()){ - func_decl f = t.decl(); - int nargs = t.num_args(); - for(int i = 0; i < nargs; i++){ - int m = MaxIndex(memo, t.arg(i)); - if(m > res) - res = m; - } - } - else if (t.is_quantifier()){ - int bound = t.get_quantifier_num_bound(); - res = MaxIndex(memo,t.body()) - bound; - } - else if (t.is_var()) { - res = t.get_index_value(); - } - return res; - } - - bool Z3User::IsClosedFormula(const Term &t){ - hash_map memo; - return MaxIndex(memo,t) < 0; - } - - - /** Convert a collection of clauses to Nodes and Edges in the RPFP. - - Predicate unknowns are uninterpreted predicates not - occurring in the background theory. - - Clauses are of the form - - B => P(t_1,...,t_k) - - where P is a predicate unknown and predicate unknowns - occur only positivey in H and only under existential - quantifiers in prenex form. - - Each predicate unknown maps to a node. Each clause maps to - an edge. Let C be a clause B => P(t_1,...,t_k) where the - sequence of predicate unknowns occurring in B (in order - of occurrence) is P_1..P_n. The clause maps to a transformer - T where: - - T.Relparams = P_1..P_n - T.Indparams = x_1...x+k - T.Formula = B /\ t_1 = x_1 /\ ... /\ t_k = x_k - - Throws exception bad_clause(msg,i) if a clause i is - in the wrong form. - - */ - - - static bool canonical_clause(const expr &clause){ - if(clause.decl().get_decl_kind() != Implies) - return false; - expr arg = clause.arg(1); - return arg.is_app() && (arg.decl().get_decl_kind() == False || - arg.decl().get_decl_kind() == Uninterpreted); - } - -#define USE_QE_LITE - - void RPFP::FromClauses(const std::vector &unskolemized_clauses, const std::vector *bounds){ - hash_map pmap; - func_decl fail_pred = ctx.fresh_func_decl("@Fail", ctx.bool_sort()); - - std::vector clauses(unskolemized_clauses); - // first, skolemize the clauses - -#ifndef USE_QE_LITE - for(unsigned i = 0; i < clauses.size(); i++){ - expr &t = clauses[i]; - if (t.is_quantifier() && t.is_quantifier_forall()) { - int bound = t.get_quantifier_num_bound(); - std::vector sorts; - std::vector names; - hash_map subst; - for(int j = 0; j < bound; j++){ - sort the_sort = t.get_quantifier_bound_sort(j); - symbol name = t.get_quantifier_bound_name(j); - expr skolem = ctx.constant(symbol(ctx,name),sort(ctx,the_sort)); - subst[bound-1-j] = skolem; - } - t = SubstBound(subst,t.body()); - } - } -#else - std::vector > substs(clauses.size()); -#endif - - // create the nodes from the heads of the clauses - - for(unsigned i = 0; i < clauses.size(); i++){ - Term &clause = clauses[i]; - -#ifdef USE_QE_LITE - Term &t = clause; - if (t.is_quantifier() && t.is_quantifier_forall()) { - int bound = t.get_quantifier_num_bound(); - std::vector sorts; - std::vector names; - for(int j = 0; j < bound; j++){ - sort the_sort = t.get_quantifier_bound_sort(j); - symbol name = t.get_quantifier_bound_name(j); - expr skolem = ctx.constant(symbol(ctx,name),sort(ctx,the_sort)); - substs[i][bound-1-j] = skolem; - } - clause = t.body(); - } - -#endif - - if(clause.is_app() && clause.decl().get_decl_kind() == Uninterpreted) - clause = implies(ctx.bool_val(true),clause); - if(!canonical_clause(clause)) - clause = implies((!clause).simplify(),ctx.bool_val(false)); - Term head = clause.arg(1); - func_decl R(ctx); - bool is_query = false; - if (eq(head,ctx.bool_val(false))){ - R = fail_pred; - // R = ctx.constant("@Fail", ctx.bool_sort()).decl(); - is_query = true; - } - else if(!get_relation(head,R)) - throw bad_clause("rhs must be a predicate application",i); - if(pmap.find(R) == pmap.end()){ - - // If the node doesn't exitst, create it. The Indparams - // are arbitrary, but we use the rhs arguments if they - // are variables for mnomonic value. - - hash_set seen; - std::vector Indparams; - for(unsigned j = 0; j < head.num_args(); j++){ - Term arg = head.arg(j); - if(!is_variable(arg) || seen.find(arg) != seen.end()){ - std::string name = std::string("@a_") + string_of_int(j); - arg = ctx.constant(name.c_str(),arg.get_sort()); - } - seen.insert(arg); - Indparams.push_back(arg); - } -#ifdef USE_QE_LITE - { - hash_map > sb_memo; - for(unsigned j = 0; j < Indparams.size(); j++) - Indparams[j] = SubstBoundRec(sb_memo, substs[i], 0, Indparams[j]); - } -#endif - Node *node = CreateNode(R(Indparams.size(),VEC2PTR(Indparams))); - //nodes.push_back(node); - pmap[R] = node; - if (is_query) - node->Bound = CreateRelation(std::vector(), ctx.bool_val(false)); - node->recursion_bound = bounds ? 0 : UINT_MAX; - } - } - - bool some_labels = false; - - // create the edges - - for(unsigned i = 0; i < clauses.size(); i++){ - Term clause = clauses[i]; - Term body = clause.arg(0); - Term head = clause.arg(1); - func_decl R(ctx); - if (eq(head,ctx.bool_val(false))) - R = fail_pred; - //R = ctx.constant("@Fail", ctx.bool_sort()).decl(); - else get_relation(head,R); - Node *Parent = pmap[R]; - std::vector Indparams; - hash_set seen; - for(unsigned j = 0; j < head.num_args(); j++){ - Term arg = head.arg(j); - if(!is_variable(arg) || seen.find(arg) != seen.end()){ - std::string name = std::string("@a_") + string_of_int(j); - Term var = ctx.constant(name.c_str(),arg.get_sort()); - body = body && (arg == var); - arg = var; - } - seen.insert(arg); - Indparams.push_back(arg); - } - - // We extract the relparams positionally - - std::vector Relparams; - hash_map scan_memo; - std::vector Children; - body = ScanBody(scan_memo,body,pmap,Relparams,Children); - Term labeled = body; - std::vector lbls; // TODO: throw this away for now - body = RemoveLabels(body,lbls); - if(!eq(labeled,body)) - some_labels = true; // remember if there are labels, as we then can't do qe_lite - // body = IneqToEq(body); // UFO converts x=y to (x<=y & x >= y). Undo this. - body = body.simplify(); - -#ifdef USE_QE_LITE - std::set idxs; - if(!some_labels){ // can't do qe_lite if we have to reconstruct labels - for(unsigned j = 0; j < Indparams.size(); j++) - if(Indparams[j].is_var()) - idxs.insert(Indparams[j].get_index_value()); - body = body.qe_lite(idxs,false); - } - hash_map > sb_memo; - body = SubstBoundRec(sb_memo,substs[i],0,body); - if(some_labels) - labeled = SubstBoundRec(sb_memo,substs[i],0,labeled); - for(unsigned j = 0; j < Indparams.size(); j++) - Indparams[j] = SubstBoundRec(sb_memo, substs[i], 0, Indparams[j]); -#endif - - // Create the edge - Transformer T = CreateTransformer(Relparams,Indparams,body); - Edge *edge = CreateEdge(Parent,T,Children); - edge->labeled = labeled;; // remember for label extraction - if(bounds) - Parent->recursion_bound = std::max(Parent->recursion_bound,(*bounds)[i]); - // edges.push_back(edge); - } - - // undo hoisting of expressions out of loops - RemoveDeadNodes(); - Unhoist(); - // FuseEdges(); - } - - - // The following mess is used to undo hoisting of expressions outside loops by compilers - - expr RPFP::UnhoistPullRec(hash_map & memo, const expr &w, hash_map & init_defs, hash_map & const_params, hash_map &const_params_inv, std::vector &new_params){ - if(memo.find(w) != memo.end()) - return memo[w]; - expr res; - if(init_defs.find(w) != init_defs.end()){ - expr d = init_defs[w]; - std::vector vars; - hash_set get_vars_memo; - GetVarsRec(get_vars_memo,d,vars); - hash_map map; - for(unsigned j = 0; j < vars.size(); j++){ - expr x = vars[j]; - map[x] = UnhoistPullRec(memo,x,init_defs,const_params,const_params_inv,new_params); - } - expr defn = SubstRec(map,d); - res = defn; - } - else if(const_params_inv.find(w) == const_params_inv.end()){ - std::string old_name = w.decl().name().str(); - func_decl fresh = ctx.fresh_func_decl(old_name.c_str(), w.get_sort()); - expr y = fresh(); - const_params[y] = w; - const_params_inv[w] = y; - new_params.push_back(y); - res = y; - } - else - res = const_params_inv[w]; - memo[w] = res; - return res; - } - - void RPFP::AddParamsToTransformer(Transformer &trans, const std::vector ¶ms){ - std::copy(params.begin(),params.end(),std::inserter(trans.IndParams,trans.IndParams.end())); - } - - expr RPFP::AddParamsToApp(const expr &app, const func_decl &new_decl, const std::vector ¶ms){ - int n = app.num_args(); - std::vector args(n); - for (int i = 0; i < n; i++) - args[i] = app.arg(i); - std::copy(params.begin(),params.end(),std::inserter(args,args.end())); - return new_decl(args); - } - - expr RPFP::GetRelRec(hash_set &memo, const expr &t, const func_decl &rel){ - if(memo.find(t) != memo.end()) - return expr(); - memo.insert(t); - if (t.is_app()) - { - func_decl f = t.decl(); - if(f == rel) - return t; - int nargs = t.num_args(); - for(int i = 0; i < nargs; i++){ - expr res = GetRelRec(memo,t.arg(i),rel); - if(!res.null()) - return res; - } - } - else if (t.is_quantifier()) - return GetRelRec(memo,t.body(),rel); - return expr(); - } - - expr RPFP::GetRel(Edge *edge, int child_idx){ - func_decl &rel = edge->F.RelParams[child_idx]; - hash_set memo; - return GetRelRec(memo,edge->F.Formula,rel); - } - - void RPFP::GetDefsRec(const expr &cnst, hash_map &defs){ - if(cnst.is_app()){ - switch(cnst.decl().get_decl_kind()){ - case And: { - int n = cnst.num_args(); - for(int i = 0; i < n; i++) - GetDefsRec(cnst.arg(i),defs); - break; - } - case Equal: { - expr lhs = cnst.arg(0); - expr rhs = cnst.arg(1); - if(IsVar(lhs)) - defs[lhs] = rhs; - break; - } - default: - break; - } - } - } - - void RPFP::GetDefs(const expr &cnst, hash_map &defs){ - // GetDefsRec(IneqToEq(cnst),defs); - GetDefsRec(cnst,defs); - } - - bool RPFP::IsVar(const expr &t){ - return t.is_app() && t.num_args() == 0 && t.decl().get_decl_kind() == Uninterpreted; - } - - void RPFP::GetVarsRec(hash_set &memo, const expr &t, std::vector &vars){ - if(memo.find(t) != memo.end()) - return; - memo.insert(t); - if (t.is_app()) - { - if(IsVar(t)){ - vars.push_back(t); - return; - } - int nargs = t.num_args(); - for(int i = 0; i < nargs; i++){ - GetVarsRec(memo,t.arg(i),vars); - } - } - else if (t.is_quantifier()) - GetVarsRec(memo,t.body(),vars); - } - - void RPFP::AddParamsToNode(Node *node, const std::vector ¶ms){ - int arity = node->Annotation.IndParams.size(); - std::vector domain; - domain.reserve(arity + params.size()); - for(int i = 0; i < arity; i++) - domain.push_back(node->Annotation.IndParams[i].get_sort()); - for(unsigned i = 0; i < params.size(); i++) - domain.push_back(params[i].get_sort()); - std::string old_name = node->Name.name().str(); - func_decl fresh = ctx.fresh_func_decl(old_name.c_str(), domain, ctx.bool_sort()); - node->Name = fresh; - AddParamsToTransformer(node->Annotation,params); - AddParamsToTransformer(node->Bound,params); - AddParamsToTransformer(node->Underapprox,params); - } - - void RPFP::UnhoistLoop(Edge *loop_edge, Edge *init_edge){ - loop_edge->F.Formula = IneqToEq(loop_edge->F.Formula); - init_edge->F.Formula = IneqToEq(init_edge->F.Formula); - expr pre = GetRel(loop_edge,0); - if(pre.null()) - return; // this means the loop got simplified away - int nparams = loop_edge->F.IndParams.size(); - hash_map const_params, const_params_inv; - std::vector work_list; - // find the parameters that are constant in the loop - for(int i = 0; i < nparams; i++){ - if(eq(pre.arg(i),loop_edge->F.IndParams[i])){ - const_params[pre.arg(i)] = init_edge->F.IndParams[i]; - const_params_inv[init_edge->F.IndParams[i]] = pre.arg(i); - work_list.push_back(pre.arg(i)); - } - } - // get the definitions in the initialization - hash_map defs,memo,subst; - GetDefs(init_edge->F.Formula,defs); - // try to pull them inside the loop - std::vector new_params; - for(unsigned i = 0; i < work_list.size(); i++){ - expr v = work_list[i]; - expr w = const_params[v]; - expr def = UnhoistPullRec(memo,w,defs,const_params,const_params_inv,new_params); - if(!eq(def,v)) - subst[v] = def; - } - // do the substitutions - if(subst.empty()) - return; - subst[pre] = pre; // don't substitute inside the precondition itself - loop_edge->F.Formula = SubstRec(subst,loop_edge->F.Formula); - loop_edge->F.Formula = ElimIte(loop_edge->F.Formula); - init_edge->F.Formula = ElimIte(init_edge->F.Formula); - // add the new parameters - if(new_params.empty()) - return; - Node *parent = loop_edge->Parent; - AddParamsToNode(parent,new_params); - AddParamsToTransformer(loop_edge->F,new_params); - AddParamsToTransformer(init_edge->F,new_params); - std::vector &incoming = parent->Incoming; - for(unsigned i = 0; i < incoming.size(); i++){ - Edge *in_edge = incoming[i]; - std::vector &chs = in_edge->Children; - for(unsigned j = 0; j < chs.size(); j++) - if(chs[j] == parent){ - expr lit = GetRel(in_edge,j); - expr new_lit = AddParamsToApp(lit,parent->Name,new_params); - func_decl fd = SuffixFuncDecl(new_lit,j); - int nargs = new_lit.num_args(); - std::vector args; - args.reserve(nargs); - for(int k = 0; k < nargs; k++) - args.push_back(new_lit.arg(k)); - new_lit = fd(nargs, VEC2PTR(args)); - in_edge->F.RelParams[j] = fd; - hash_map map; - map[lit] = new_lit; - in_edge->F.Formula = SubstRec(map,in_edge->F.Formula); - } - } - } - - void RPFP::Unhoist(){ - hash_map > outgoing; - for(unsigned i = 0; i < edges.size(); i++) - outgoing[edges[i]->Parent].push_back(edges[i]); - for(unsigned i = 0; i < nodes.size(); i++){ - Node *node = nodes[i]; - std::vector &outs = outgoing[node]; - // if we're not a simple loop with one entry, give up - if(outs.size() == 2){ - for(int j = 0; j < 2; j++){ - Edge *loop_edge = outs[j]; - Edge *init_edge = outs[1-j]; - if(loop_edge->Children.size() == 1 && loop_edge->Children[0] == loop_edge->Parent){ - UnhoistLoop(loop_edge,init_edge); - break; - } - } - } - } - } - - void RPFP::FuseEdges(){ - hash_map > outgoing; - for(unsigned i = 0; i < edges.size(); i++){ - outgoing[edges[i]->Parent].push_back(edges[i]); - } - hash_set edges_to_delete; - for(unsigned i = 0; i < nodes.size(); i++){ - Node *node = nodes[i]; - std::vector &outs = outgoing[node]; - if(outs.size() > 1 && outs.size() <= 16){ - std::vector trs(outs.size()); - for(unsigned j = 0; j < outs.size(); j++) - trs[j] = &outs[j]->F; - Transformer tr = Fuse(trs); - std::vector chs; - for(unsigned j = 0; j < outs.size(); j++) - for(unsigned k = 0; k < outs[j]->Children.size(); k++) - chs.push_back(outs[j]->Children[k]); - CreateEdge(node,tr,chs); - for(unsigned j = 0; j < outs.size(); j++) - edges_to_delete.insert(outs[j]); - } - } - std::vector new_edges; - hash_set all_nodes; - for(unsigned j = 0; j < edges.size(); j++){ - if(edges_to_delete.find(edges[j]) == edges_to_delete.end()){ -#if 0 - if(all_nodes.find(edges[j]->Parent) != all_nodes.end()) - throw "help!"; - all_nodes.insert(edges[j]->Parent); -#endif - new_edges.push_back(edges[j]); - } - else - delete edges[j]; - } - edges.swap(new_edges); - } - - void RPFP::MarkLiveNodes(hash_map > &outgoing, hash_set &live_nodes, Node *node){ - if(live_nodes.find(node) != live_nodes.end()) - return; - live_nodes.insert(node); - std::vector &outs = outgoing[node]; - for(unsigned i = 0; i < outs.size(); i++) - for(unsigned j = 0; j < outs[i]->Children.size(); j++) - MarkLiveNodes(outgoing, live_nodes,outs[i]->Children[j]); - } - - void RPFP::RemoveDeadNodes(){ - hash_map > outgoing; - for(unsigned i = 0; i < edges.size(); i++) - outgoing[edges[i]->Parent].push_back(edges[i]); - hash_set live_nodes; - for(unsigned i = 0; i < nodes.size(); i++) - if(!nodes[i]->Bound.IsFull()) - MarkLiveNodes(outgoing,live_nodes,nodes[i]); - std::vector new_edges; - for(unsigned j = 0; j < edges.size(); j++){ - if(live_nodes.find(edges[j]->Parent) != live_nodes.end()) - new_edges.push_back(edges[j]); - else { - Edge *edge = edges[j]; - for(unsigned int i = 0; i < edge->Children.size(); i++){ - std::vector &ic = edge->Children[i]->Incoming; - for(std::vector::iterator it = ic.begin(), en = ic.end(); it != en; ++it){ - if(*it == edge){ - ic.erase(it); - break; - } - } - } - delete edge; - } - } - edges.swap(new_edges); - std::vector new_nodes; - for(unsigned j = 0; j < nodes.size(); j++){ - if(live_nodes.find(nodes[j]) != live_nodes.end()) - new_nodes.push_back(nodes[j]); - else - delete nodes[j]; - } - nodes.swap(new_nodes); - } - - void RPFP::WriteSolution(std::ostream &s){ - for(unsigned i = 0; i < nodes.size(); i++){ - Node *node = nodes[i]; - Term asgn = (node->Name)(node->Annotation.IndParams) == node->Annotation.Formula; - s << asgn << std::endl; - } - } - - void RPFP::WriteEdgeVars(Edge *e, hash_map &memo, const Term &t, std::ostream &s) - { - std::pair foo(t,0); - std::pair::iterator, bool> bar = memo.insert(foo); - // int &res = bar.first->second; - if(!bar.second) return; - hash_map::iterator it = e->varMap.find(t); - if (it != e->varMap.end()){ - return; - } - if (t.is_app()) - { - func_decl f = t.decl(); - // int idx; - int nargs = t.num_args(); - for(int i = 0; i < nargs; i++) - WriteEdgeVars(e, memo, t.arg(i),s); - if (nargs == 0 && f.get_decl_kind() == Uninterpreted && !ls->is_constant(f)){ - Term rename = HideVariable(t,e->number); - Term value = dualModel.eval(rename); - s << " (= " << t << " " << value << ")\n"; - } - } - else if (t.is_quantifier()) - WriteEdgeVars(e,memo,t.body(),s); - return; - } - - void RPFP::WriteEdgeAssignment(std::ostream &s, Edge *e){ - s << "(\n"; - hash_map memo; - WriteEdgeVars(e, memo, e->F.Formula ,s); - s << ")\n"; - } - - void RPFP::WriteCounterexample(std::ostream &s, Node *node){ - for(unsigned i = 0; i < node->Outgoing->Children.size(); i++){ - Node *child = node->Outgoing->Children[i]; - if(!Empty(child)) - WriteCounterexample(s,child); - } - s << "(" << node->number << " : " << EvalNode(node) << " <- "; - for(unsigned i = 0; i < node->Outgoing->Children.size(); i++){ - Node *child = node->Outgoing->Children[i]; - if(!Empty(child)) - s << " " << node->Outgoing->Children[i]->number; - } - s << ")" << std::endl; - WriteEdgeAssignment(s,node->Outgoing); - } - - RPFP::Term RPFP::ToRuleRec(Edge *e, hash_map &memo, const Term &t, std::vector &quants) - { - std::pair foo(t,expr(ctx)); - std::pair::iterator, bool> bar = memo.insert(foo); - Term &res = bar.first->second; - if(!bar.second) return res; - if (t.is_app()) - { - func_decl f = t.decl(); - // int idx; - std::vector args; - int nargs = t.num_args(); - args.reserve(nargs); - for(int i = 0; i < nargs; i++) - args.push_back(ToRuleRec(e, memo, t.arg(i),quants)); - hash_map::iterator rit = e->relMap.find(f); - if(rit != e->relMap.end()){ - Node* child = e->Children[rit->second]; - FuncDecl op = child->Name; - res = op(args.size(), VEC2PTR(args)); - } - else { - res = f(args.size(), VEC2PTR(args)); - if(nargs == 0 && t.decl().get_decl_kind() == Uninterpreted) - quants.push_back(t); - } - } - else if (t.is_quantifier()) - { - Term body = ToRuleRec(e,memo,t.body(),quants); - res = CloneQuantifier(t,body); - } - else res = t; - return res; - } - - - void RPFP::ToClauses(std::vector &cnsts, FileFormat format){ - cnsts.resize(edges.size()); - for(unsigned i = 0; i < edges.size(); i++){ - Edge *edge = edges[i]; - SetEdgeMaps(edge); - std::vector quants; - hash_map memo; - Term lhs = ToRuleRec(edge, memo, edge->F.Formula,quants); - Term rhs = (edge->Parent->Name)(edge->F.IndParams.size(),&edge->F.IndParams[0]); - for(unsigned j = 0; j < edge->F.IndParams.size(); j++) - ToRuleRec(edge,memo,edge->F.IndParams[j],quants); // just to get quants - Term cnst = implies(lhs,rhs); -#if 0 - for(unsigned i = 0; i < quants.size(); i++){ - std::cout << expr(ctx,(Z3_ast)quants[i]) << " : " << sort(ctx,Z3_get_sort(ctx,(Z3_ast)quants[i])) << std::endl; - } -#endif - if(format != DualityFormat) - cnst= forall(quants,cnst); - cnsts[i] = cnst; - } - // int num_rules = cnsts.size(); - - for(unsigned i = 0; i < nodes.size(); i++){ - Node *node = nodes[i]; - if(!node->Bound.IsFull()){ - Term lhs = (node->Name)(node->Bound.IndParams) && !node->Bound.Formula; - Term cnst = implies(lhs,ctx.bool_val(false)); - if(format != DualityFormat){ - std::vector quants; - for(unsigned j = 0; j < node->Bound.IndParams.size(); j++) - quants.push_back(node->Bound.IndParams[j]); - if(format == HornFormat) - cnst= exists(quants,!cnst); - else - cnst= forall(quants, cnst); - } - cnsts.push_back(cnst); - } - } - - } - - - bool RPFP::proof_core_contains(const expr &e){ - return proof_core->find(e) != proof_core->end(); - } - - bool RPFP_caching::proof_core_contains(const expr &e){ - std::vector foo; - GetAssumptionLits(e,foo); - for(unsigned i = 0; i < foo.size(); i++) - if(proof_core->find(foo[i]) != proof_core->end()) - return true; - return false; - } - - bool RPFP::EdgeUsedInProof(Edge *edge){ - ComputeProofCore(); - if(!edge->dual.null() && proof_core_contains(edge->dual)) - return true; - for(unsigned i = 0; i < edge->constraints.size(); i++) - if(proof_core_contains(edge->constraints[i])) - return true; - return false; - } - - RPFP::~RPFP(){ - ClearProofCore(); - for(unsigned i = 0; i < nodes.size(); i++) - delete nodes[i]; - for(unsigned i = 0; i < edges.size(); i++) - delete edges[i]; - } -} - -#if 0 -void show_ast(expr *a){ - std::cout << *a; -} -#endif diff --git a/src/duality/duality_solver.cpp b/src/duality/duality_solver.cpp deleted file mode 100644 index 7782f4a8b..000000000 --- a/src/duality/duality_solver.cpp +++ /dev/null @@ -1,3601 +0,0 @@ -/*++ - Copyright (c) 2012 Microsoft Corporation - - Module Name: - - duality_solver.h - - Abstract: - - implements relational post-fixedpoint problem - (RPFP) solver - - Author: - - Ken McMillan (kenmcmil) - - Revision History: - - - --*/ - -#ifdef _WINDOWS -#pragma warning(disable:4996) -#pragma warning(disable:4800) -#pragma warning(disable:4267) -#endif - -#include "duality/duality.h" -#include "duality/duality_profiling.h" - -#include -#include -#include -#include -#include -#include - -// TODO: make these official options or get rid of them - -#define NEW_CAND_SEL -// #define LOCALIZE_CONJECTURES -// #define CANDS_FROM_UPDATES -#define CANDS_FROM_COVER_FAIL -#define DEPTH_FIRST_EXPAND -#define MINIMIZE_CANDIDATES -// #define MINIMIZE_CANDIDATES_HARDER -#define BOUNDED -// #define CHECK_CANDS_FROM_IND_SET -#define UNDERAPPROX_NODES -#define NEW_EXPAND -#define EARLY_EXPAND -// #define TOP_DOWN -// #define EFFORT_BOUNDED_STRAT -#define SKIP_UNDERAPPROX_NODES -// #define KEEP_EXPANSIONS -// #define USE_CACHING_RPFP -// #define PROPAGATE_BEFORE_CHECK -#define NEW_STRATIFIED_INLINING - -#define USE_RPFP_CLONE -#define USE_NEW_GEN_CANDS - -//#define NO_PROPAGATE -//#define NO_GENERALIZE -//#define NO_DECISIONS - -namespace Duality { - - // TODO: must be a better place for this... - static char string_of_int_buffer[20]; - - static const char *string_of_int(int n){ - sprintf(string_of_int_buffer,"%d",n); - return string_of_int_buffer; - } - - /** Generic object for producing diagnostic output. */ - - class Reporter { - protected: - RPFP *rpfp; - public: - Reporter(RPFP *_rpfp){ - rpfp = _rpfp; - } - virtual void Extend(RPFP::Node *node){} - virtual void Update(RPFP::Node *node, const RPFP::Transformer &update, bool eager){} - virtual void Bound(RPFP::Node *node){} - virtual void Expand(RPFP::Edge *edge){} - virtual void AddCover(RPFP::Node *covered, std::vector &covering){} - virtual void RemoveCover(RPFP::Node *covered, RPFP::Node *covering){} - virtual void Conjecture(RPFP::Node *node, const RPFP::Transformer &t){} - virtual void Forcing(RPFP::Node *covered, RPFP::Node *covering){} - virtual void Dominates(RPFP::Node *node, RPFP::Node *other){} - virtual void InductionFailure(RPFP::Edge *edge, const std::vector &children){} - virtual void UpdateUnderapprox(RPFP::Node *node, const RPFP::Transformer &update){} - virtual void Reject(RPFP::Edge *edge, const std::vector &Children){} - virtual void Message(const std::string &msg){} - virtual void Depth(int){} - virtual ~Reporter(){} - }; - - Reporter *CreateStdoutReporter(RPFP *rpfp); - Reporter *CreateConjectureFileReporter(RPFP *rpfp, const std::string &fname); - - /** Object we throw in case of catastrophe. */ - - struct InternalError { - std::string msg; - InternalError(const std::string & _msg) - : msg(_msg) {} - }; - - - /** This is the main solver. It takes an arbitrary (possibly cyclic) - RPFP and either annotates it with a solution, or returns a - counterexample derivation in the form of an embedded RPFP tree. */ - - class Duality : public Solver { - - public: - Duality(RPFP *_rpfp) - : ctx(_rpfp->ctx), - slvr(_rpfp->slvr()), - nodes(_rpfp->nodes), - edges(_rpfp->edges) - { - rpfp = _rpfp; - reporter = nullptr; - conj_reporter = nullptr; - heuristic = nullptr; - unwinding = nullptr; - FullExpand = false; - NoConj = false; - FeasibleEdges = true; - UseUnderapprox = true; - Report = false; - StratifiedInlining = false; - RecursionBound = -1; - BatchExpand = false; - { - scoped_no_proof no_proofs_please(ctx.m()); -#ifdef USE_RPFP_CLONE - clone_rpfp = new RPFP_caching(rpfp->ls); - clone_rpfp->Clone(rpfp); -#endif -#ifdef USE_NEW_GEN_CANDS - gen_cands_rpfp = new RPFP_caching(rpfp->ls); - gen_cands_rpfp->Clone(rpfp); -#endif - } - } - - ~Duality() override { -#ifdef USE_RPFP_CLONE - delete clone_rpfp; -#endif -#ifdef USE_NEW_GEN_CANDS - delete gen_cands_rpfp; -#endif - if(unwinding) delete unwinding; - } - -#ifdef USE_RPFP_CLONE - RPFP_caching *clone_rpfp; -#endif -#ifdef USE_NEW_GEN_CANDS - RPFP_caching *gen_cands_rpfp; -#endif - - - typedef RPFP::Node Node; - typedef RPFP::Edge Edge; - - /** This struct represents a candidate for extending the - unwinding. It consists of an edge to instantiate - and a vector of children for the new instance. */ - - struct Candidate { - Edge *edge; std::vector - Children; - }; - - /** Comparison operator, allowing us to sort Nodes - by their number field. */ - - struct lnode - { - bool operator()(const Node* s1, const Node* s2) const - { - return s1->number < s2->number; - } - }; - - typedef std::set Unexpanded; // sorted set of Nodes - - /** This class provides a heuristic for expanding a derivation - tree. */ - - class Heuristic { - RPFP *rpfp; - - /** Heuristic score for unwinding nodes. Currently this - counts the number of updates. */ - struct score { - int updates; - score() : updates(0) {} - }; - hash_map scores; - - public: - Heuristic(RPFP *_rpfp){ - rpfp = _rpfp; - } - - virtual ~Heuristic(){} - - virtual void Update(RPFP::Node *node){ - scores[node].updates++; - } - - /** Heuristic choice of nodes to expand. Takes a set "choices" - and returns a subset "best". We currently choose the - nodes with the fewest updates. - */ -#if 0 - virtual void ChooseExpand(const std::set &choices, std::set &best){ - int best_score = INT_MAX; - for(std::set::iterator it = choices.begin(), en = choices.end(); it != en; ++it){ - Node *node = (*it)->map; - int score = scores[node].updates; - best_score = std::min(best_score,score); - } - for(std::set::iterator it = choices.begin(), en = choices.end(); it != en; ++it) - if(scores[(*it)->map].updates == best_score) - best.insert(*it); - } -#else - virtual void ChooseExpand(const std::set &choices, std::set &best, bool high_priority=false, bool best_only=false){ - if(high_priority) return; - int best_score = INT_MAX; - int worst_score = 0; - for(std::set::iterator it = choices.begin(), en = choices.end(); it != en; ++it){ - Node *node = (*it)->map; - int score = scores[node].updates; - best_score = std::min(best_score,score); - worst_score = std::max(worst_score,score); - } - int cutoff = best_only ? best_score : (best_score + (worst_score-best_score)/2); - for(std::set::iterator it = choices.begin(), en = choices.end(); it != en; ++it) - if(scores[(*it)->map].updates <= cutoff) - best.insert(*it); - } -#endif - - /** Called when done expanding a tree */ - virtual void Done() {} - - /** Ask whether a node should be used/unused in the tree. Returns, - 1 if yes, -1 if no, and 0 if don't care. */ - - virtual int UseNode(Node *node){ - return 0; - } - }; - - /** The Proposer class proposes conjectures eagerly. These can come - from any source, including predicate abstraction, templates, or - previous solver runs. The proposed conjectures are checked - with low effort when the unwinding is expanded. - */ - - class Proposer { - public: - /** Given a node in the unwinding, propose some conjectures */ - virtual std::vector &Propose(Node *node) = 0; - virtual ~Proposer(){}; - }; - - - class Covering; // see below - - // These members represent the state of the algorithm. - - RPFP *rpfp; // the input RPFP - Reporter *reporter; // object for logging - Reporter *conj_reporter; // object for logging conjectures - Heuristic *heuristic; // expansion heuristic - context &ctx; // Z3 context - solver &slvr; // Z3 solver - std::vector &nodes; // Nodes of input RPFP - std::vector &edges; // Edges of input RPFP - std::vector leaves; // leaf nodes of unwinding (unused) - Unexpanded unexpanded; // unexpanded nodes - std::list candidates; // candidates for expansion - // maps children to edges in input RPFP - hash_map > edges_by_child; - // maps each node in input RPFP to its expanded instances - hash_map > insts_of_node; - // maps each node in input RPFP to all its instances - hash_map > all_of_node; - RPFP *unwinding; // the unwinding - Covering *indset; // proposed inductive subset - Counterexample cex; // counterexample - std::list to_expand; - hash_set updated_nodes; - hash_map underapprox_map; // maps underapprox nodes to the nodes they approximate - int last_decisions; - hash_set overapproxes; - std::vector proposers; - std::string ConjectureFile; - bool stratified_inlining_done; - -#ifdef BOUNDED - struct Counter { - unsigned val; - Counter(){val = 0;} - }; - typedef std::map NodeToCounter; - hash_map back_edges; // counts of back edges -#endif - - /** Solve the problem. */ - bool Solve() override { - PreSolve(); - bool res = SolveMain(); // does the actual work - PostSolve(); - return res; - } - - void PreSolve(){ - reporter = Report ? CreateStdoutReporter(rpfp) : new Reporter(rpfp); - conj_reporter = ConjectureFile.empty() ? nullptr : CreateConjectureFileReporter(rpfp,ConjectureFile); -#ifndef LOCALIZE_CONJECTURES - heuristic = !cex.get_tree() ? new Heuristic(rpfp) : new ReplayHeuristic(rpfp,cex); -#else - heuristic = !cex.get_tree() ? (Heuristic *)(new LocalHeuristic(rpfp)) - : (Heuristic *)(new ReplayHeuristic(rpfp,cex)); -#endif - // determine if we are recursion bounded - for(unsigned i = 0; i < rpfp->nodes.size(); i++) - if(rpfp->nodes[i]->recursion_bound < UINT_MAX) - RecursionBound = 0; - cex.clear(); // in case we didn't use it for heuristic - if(unwinding) delete unwinding; - unwinding = new RPFP(rpfp->ls); - unwinding->HornClauses = rpfp->HornClauses; - indset = new Covering(this); - last_decisions = 0; - CreateEdgesByChildMap(); -#ifndef TOP_DOWN - CreateInitialUnwinding(); -#else - CreateLeaves(); - for(unsigned i = 0; i < leaves.size(); i++) - if(!SatisfyUpperBound(leaves[i])) - return false; -#endif - StratifiedLeafCount = -1; - stratified_inlining_done = false; - } - - void PostSolve(){ - // print_profile(std::cout); - delete indset; - delete heuristic; - // delete unwinding; // keep the unwinding for future mining of predicates - delete reporter; - if(conj_reporter) - delete conj_reporter; - for(unsigned i = 0; i < proposers.size(); i++) - delete proposers[i]; - } - - bool RecheckBounds(){ - for(unsigned i = 0; i < unwinding->nodes.size(); i++){ - Node *node = unwinding->nodes[i]; - node->Bound = node->map->Bound; - if(!SatisfyUpperBound(node)) - return false; - } - return true; - } - - void CreateInitialUnwinding(){ - if(!StratifiedInlining){ - CreateLeaves(); - if(FeasibleEdges)NullaryCandidates(); - else InstantiateAllEdges(); - } - else { -#ifdef NEW_STRATIFIED_INLINING - -#else - CreateLeaves(); -#endif - } - - } - - void Cancel() override { - // TODO - } - -#if 0 - virtual void Restart(RPFP *_rpfp){ - rpfp = _rpfp; - delete unwinding; - nodes = _rpfp->nodes; - edges = _rpfp->edges; - leaves.clear(); - unexpanded.clear(); // unexpanded nodes - candidates.clear(); // candidates for expansion - edges_by_child.clear(); - insts_of_node.clear(); - all_of_node.clear(); - to_expand.clear(); - } -#endif - - void LearnFrom(Solver *other_solver) override { - // get the counterexample as a guide - cex.swap(other_solver->GetCounterexample()); - - // propose conjectures based on old unwinding - Duality *old_duality = dynamic_cast(other_solver); - if(old_duality) - proposers.push_back(new HistoryProposer(old_duality,this)); - } - - /** Return a reference to the counterexample */ - Counterexample &GetCounterexample() override { - return cex; - } - - // options - bool FullExpand; // do not use partial expansion of derivation tree - bool NoConj; // do not use conjectures (no forced covering) - bool FeasibleEdges; // use only feasible edges in unwinding - bool UseUnderapprox; // use underapproximations - bool Report; // spew on stdout - bool StratifiedInlining; // Do stratified inlining as preprocessing step - int RecursionBound; // Recursion bound for bounded verification - bool BatchExpand; - bool EnableRestarts; - - bool SetBoolOption(bool &opt, const std::string &value){ - if(value == "0") { - opt = false; - return true; - } - if(value == "1") { - opt = true; - return true; - } - return false; - } - - bool SetIntOption(int &opt, const std::string &value){ - opt = atoi(value.c_str()); - return true; - } - - /** Set options (not currently used) */ - bool SetOption(const std::string &option, const std::string &value) override { - if(option == "full_expand"){ - return SetBoolOption(FullExpand,value); - } - if(option == "no_conj"){ - return SetBoolOption(NoConj,value); - } - if(option == "feasible_edges"){ - return SetBoolOption(FeasibleEdges,value); - } - if(option == "use_underapprox"){ - return SetBoolOption(UseUnderapprox,value); - } - if(option == "report"){ - return SetBoolOption(Report,value); - } - if(option == "stratified_inlining"){ - return SetBoolOption(StratifiedInlining,value); - } - if(option == "batch_expand"){ - return SetBoolOption(BatchExpand,value); - } - if(option == "recursion_bound"){ - return SetIntOption(RecursionBound,value); - } - if(option == "conjecture_file"){ - ConjectureFile = value; - } - if(option == "enable_restarts"){ - return SetBoolOption(EnableRestarts,value); - } - return false; - } - - /** Create an instance of a node in the unwinding. Set its - annotation to true, and mark it unexpanded. */ - Node* CreateNodeInstance(Node *node, int number = 0){ - RPFP::Node *inst = unwinding->CloneNode(node); - inst->Annotation.SetFull(); - if(number < 0) inst->number = number; - unexpanded.insert(inst); - all_of_node[node].push_back(inst); - return inst; - } - - /** Create an instance of an edge in the unwinding, with given - parent and children. */ - void CreateEdgeInstance(Edge *edge, Node *parent, const std::vector &children){ - RPFP::Edge *inst = unwinding->CreateEdge(parent,edge->F,children); - inst->map = edge; - } - - void MakeLeaf(Node *node, bool do_not_expand = false){ - node->Annotation.SetEmpty(); - Edge *e = unwinding->CreateLowerBoundEdge(node); -#ifdef TOP_DOWN - node->Annotation.SetFull(); // allow this node to cover others -#endif - if(StratifiedInlining) - node->Annotation.SetFull(); // allow this node to cover others - else - updated_nodes.insert(node); - e->map = nullptr; - reporter->Extend(node); -#ifdef EARLY_EXPAND - if(!do_not_expand) - TryExpandNode(node); -#endif - // e->F.SetEmpty(); - } - - void MakeOverapprox(Node *node){ - node->Annotation.SetFull(); - Edge *e = unwinding->CreateLowerBoundEdge(node); - overapproxes.insert(node); - e->map = nullptr; - } - - /** We start the unwinding with leaves that under-approximate - each relation with false. */ - void CreateLeaves(){ - unexpanded.clear(); - leaves.clear(); - for(unsigned i = 0; i < nodes.size(); i++){ - RPFP::Node *node = CreateNodeInstance(nodes[i]); - if(0 && nodes[i]->Outgoing->Children.size() == 0) - CreateEdgeInstance(nodes[i]->Outgoing,node,std::vector()); - else { - if(!StratifiedInlining) - MakeLeaf(node); - else { - MakeOverapprox(node); - LeafMap[nodes[i]] = node; - } - } - leaves.push_back(node); - } - } - - /** Create the map from children to edges in the input RPFP. This - is used to generate candidates for expansion. */ - void CreateEdgesByChildMap(){ - edges_by_child.clear(); - for(unsigned i = 0; i < edges.size(); i++){ - Edge *e = edges[i]; - std::set done; - for(unsigned j = 0; j < e->Children.size(); j++){ - Node *c = e->Children[j]; - if(done.find(c) == done.end()) // avoid duplicates - edges_by_child[c].push_back(e); - done.insert(c); - } - } - } - - void NullaryCandidates(){ - for(unsigned i = 0; i < edges.size(); i++){ - RPFP::Edge *edge = edges[i]; - if(edge->Children.size() == 0){ - Candidate cand; - cand.edge = edge; - candidates.push_back(cand); - } - } - } - - void InstantiateAllEdges(){ - hash_map leaf_map; - for(unsigned i = 0; i < leaves.size(); i++){ - leaf_map[leaves[i]->map] = leaves[i]; - insts_of_node[leaves[i]->map].push_back(leaves[i]); - } - unexpanded.clear(); - for(unsigned i = 0; i < edges.size(); i++){ - Edge *edge = edges[i]; - Candidate c; c.edge = edge; - c.Children.resize(edge->Children.size()); - for(unsigned j = 0; j < c.Children.size(); j++) - c.Children[j] = leaf_map[edge->Children[j]]; - Node *new_node; - Extend(c,new_node); -#ifdef EARLY_EXPAND - TryExpandNode(new_node); -#endif - } - for(Unexpanded::iterator it = unexpanded.begin(), en = unexpanded.end(); it != en; ++it) - indset->Add(*it); - for(unsigned i = 0; i < leaves.size(); i++){ - std::vector &foo = insts_of_node[leaves[i]->map]; - foo.erase(foo.begin()); - } - } - - bool ProducedBySI(Edge *edge, std::vector &children){ - if(LeafMap.find(edge->Parent) == LeafMap.end()) return false; - Node *other = LeafMap[edge->Parent]; - if(other->Outgoing->map != edge) return false; - std::vector &ochs = other->Outgoing->Children; - for(unsigned i = 0; i < children.size(); i++) - if(ochs[i] != children[i]) return false; - return true; - } - - /** Add a candidate for expansion, but not if Stratified inlining has already - produced it */ - - void AddCandidate(Edge *edge, std::vector &children){ - if(StratifiedInlining && ProducedBySI(edge,children)) - return; - candidates.push_back(Candidate()); - candidates.back().edge = edge; - candidates.back().Children = children; - } - - /** Generate candidates for expansion, given a vector of candidate - sets for each argument position. This recursively produces - the cross product. - */ - void GenCandidatesRec(int pos, Edge *edge, - const std::vector > &vec, - std::vector &children){ - if(pos == (int)vec.size()){ - AddCandidate(edge,children); - } - else { - for(unsigned i = 0; i < vec[pos].size(); i++){ - children[pos] = vec[pos][i]; - GenCandidatesRec(pos+1,edge,vec,children); - } - } - } - - /** Setup for above recursion. */ - void GenCandidates(int pos, Edge *edge, - const std::vector > &vec){ - std::vector children(vec.size()); - GenCandidatesRec(0,edge,vec,children); - } - - /** Expand a node. We find all the candidates for expansion using - this node and other already expanded nodes. This is a little - tricky, since a node may be used for multiple argument - positions of an edge, and we don't want to produce duplicates. - */ - -#ifndef NEW_EXPAND - void ExpandNode(Node *node){ - std::vector &nedges = edges_by_child[node->map]; - for(unsigned i = 0; i < nedges.size(); i++){ - Edge *edge = nedges[i]; - for(unsigned npos = 0; npos < edge->Children.size(); ++npos){ - if(edge->Children[npos] == node->map){ - std::vector > vec(edge->Children.size()); - vec[npos].push_back(node); - for(unsigned j = 0; j < edge->Children.size(); j++){ - if(j != npos){ - std::vector &insts = insts_of_node[edge->Children[j]]; - for(unsigned k = 0; k < insts.size(); k++) - if(indset->Candidate(insts[k])) - vec[j].push_back(insts[k]); - } - if(j < npos && edge->Children[j] == node->map) - vec[j].push_back(node); - } - GenCandidates(0,edge,vec); - } - } - } - unexpanded.erase(node); - insts_of_node[node->map].push_back(node); - } -#else - /** If the current proposed solution is not inductive, - use the induction failure to generate candidates for extension. */ - void ExpandNode(Node *node){ - unexpanded.erase(node); - insts_of_node[node->map].push_back(node); - timer_start("GenCandIndFailUsing"); - std::vector &nedges = edges_by_child[node->map]; - for(unsigned i = 0; i < nedges.size(); i++){ - Edge *edge = nedges[i]; - slvr.push(); - RPFP *checker = new RPFP(rpfp->ls); - Node *root = CheckerJustForEdge(edge,checker,true); - if(root){ - expr using_cond = ctx.bool_val(false); - for(unsigned npos = 0; npos < edge->Children.size(); ++npos) - if(edge->Children[npos] == node->map) - using_cond = using_cond || checker->Localize(root->Outgoing->Children[npos]->Outgoing,NodeMarker(node)); - slvr.add(using_cond); - if(checker->Check(root) != unsat){ - Candidate candidate; - ExtractCandidateFromCex(edge,checker,root,candidate); - reporter->InductionFailure(edge,candidate.Children); - candidates.push_back(candidate); - } - } - slvr.pop(1); - delete checker; - } - timer_stop("GenCandIndFailUsing"); - } -#endif - - void ExpandNodeFromOther(Node *node, Node *other){ - std::vector &in = other->Incoming; - for(unsigned i = 0; i < in.size(); i++){ - Edge *edge = in[i]; - Candidate cand; - cand.edge = edge->map; - cand.Children = edge->Children; - for(unsigned j = 0; j < cand.Children.size(); j++) - if(cand.Children[j] == other) - cand.Children[j] = node; - candidates.push_front(cand); - } - // unexpanded.erase(node); - // insts_of_node[node->map].push_back(node); - } - - /** Expand a node based on some uncovered node it dominates. - This pushes cahdidates onto the *front* of the candidate - queue, so these expansions are done depth-first. */ - bool ExpandNodeFromCoverFail(Node *node){ - if(!node->Outgoing || node->Outgoing->Children.size() == 0) - return false; - Node *other = indset->GetSimilarNode(node); - if(!other) - return false; -#ifdef UNDERAPPROX_NODES - Node *under_node = CreateUnderapproxNode(node); - underapprox_map[under_node] = node; - indset->CoverByNode(node,under_node); - ExpandNodeFromOther(under_node,other); - ExpandNode(under_node); -#else - ExpandNodeFromOther(node,other); - unexpanded.erase(node); - insts_of_node[node->map].push_back(node); -#endif - return true; - } - - - /** Make a boolean variable to act as a "marker" for a node. */ - expr NodeMarker(Node *node){ - std::string name = std::string("@m_") + string_of_int(node->number); - return ctx.constant(name.c_str(),ctx.bool_sort()); - } - - /** Make a boolean variable to act as a "marker" for a pair of nodes. */ - expr NodeMarker(Node *node1, Node *node2){ - std::string name = std::string("@m_") + string_of_int(node1->number); - name += std::string("_") + string_of_int(node2->number); - return ctx.constant(name.c_str(),ctx.bool_sort()); - } - - /** Union the annotation of dst into src. If with_markers is - true, we conjoin the annotation formula of dst with its - marker. This allows us to discover which disjunct is - true in a satisfying assignment. */ - void UnionAnnotations(RPFP::Transformer &dst, Node *src, bool with_markers = false){ - if(!with_markers) - dst.UnionWith(src->Annotation); - else { - RPFP::Transformer t = src->Annotation; - t.Formula = t.Formula && NodeMarker(src); - dst.UnionWith(t); - } - } - - void GenNodeSolutionFromIndSet(Node *node, RPFP::Transformer &annot, bool with_markers = false){ - annot.SetEmpty(); - std::vector &insts = insts_of_node[node]; - for(unsigned j = 0; j < insts.size(); j++) - if(indset->Contains(insts[j])) - UnionAnnotations(annot,insts[j],with_markers); - annot.Simplify(); - } - - bool NodeSolutionFromIndSetFull(Node *node){ - std::vector &insts = insts_of_node[node]; - for(unsigned j = 0; j < insts.size(); j++) - if(indset->Contains(insts[j])) - if(insts[j]->Annotation.IsFull()) - return true; - return false; - } - - bool recursionBounded; - - /** See if the solution might be bounded. */ - void TestRecursionBounded(){ - recursionBounded = false; - if(RecursionBound == -1) - return; - for(unsigned i = 0; i < nodes.size(); i++){ - Node *node = nodes[i]; - std::vector &insts = insts_of_node[node]; - for(unsigned j = 0; j < insts.size(); j++) - if(indset->Contains(insts[j])) - if(NodePastRecursionBound(insts[j],true)) - recursionBounded = true; - } - } - - bool IsResultRecursionBounded() override { - return recursionBounded; - } - - /** Generate a proposed solution of the input RPFP from - the unwinding, by unioning the instances of each node. */ - void GenSolutionFromIndSet(bool with_markers = false){ - for(unsigned i = 0; i < nodes.size(); i++){ - Node *node = nodes[i]; - GenNodeSolutionFromIndSet(node,node->Annotation,with_markers); - } - } - -#ifdef BOUNDED - bool NodePastRecursionBound(Node *node, bool report = false){ - if(RecursionBound < 0) return false; - NodeToCounter &backs = back_edges[node]; - for(NodeToCounter::iterator it = backs.begin(), en = backs.end(); it != en; ++it){ - if(it->second.val > it->first->recursion_bound){ - if(report){ - std::ostringstream os; - os << "cut off " << it->first->Name.name() << " at depth " << it->second.val; - reporter->Message(os.str()); - } - return true; - } - } - return false; - } -#endif - - /** Test whether a given extension candidate actually represents - an induction failure. Right now we approximate this: if - the resulting node in the unwinding could be labeled false, - it clearly is not an induction failure. */ - - bool CandidateFeasible(const Candidate &cand){ - if(!FeasibleEdges) return true; - timer_start("CandidateFeasible"); - RPFP *checker = new RPFP(rpfp->ls); - // std::cout << "Checking feasibility of extension " << cand.edge->Parent->number << std::endl; - checker->Push(); - std::vector chs(cand.Children.size()); - Node *root = checker->CloneNode(cand.edge->Parent); -#ifdef BOUNDED - for(unsigned i = 0; i < cand.Children.size(); i++) - if(NodePastRecursionBound(cand.Children[i])){ - timer_stop("CandidateFeasible"); - return false; - } -#endif -#ifdef NEW_CAND_SEL - GenNodeSolutionFromIndSet(cand.edge->Parent,root->Bound); -#else - root->Bound.SetEmpty(); -#endif - checker->AssertNode(root); - for(unsigned i = 0; i < cand.Children.size(); i++) - chs[i] = checker->CloneNode(cand.Children[i]); - Edge *e = checker->CreateEdge(root,cand.edge->F,chs); - checker->AssertEdge(e,0,true); - // std::cout << "Checking SAT: " << e->dual << std::endl; - bool res = checker->Check(root) != unsat; - // std::cout << "Result: " << res << std::endl; - if(!res)reporter->Reject(cand.edge,cand.Children); - checker->Pop(1); - delete checker; - timer_stop("CandidateFeasible"); - return res; - } - - - hash_map TopoSort; - int TopoSortCounter; - std::vector SortedEdges; - - void DoTopoSortRec(Node *node){ - if(TopoSort.find(node) != TopoSort.end()) - return; - TopoSort[node] = INT_MAX; // just to break cycles - Edge *edge = node->Outgoing; // note, this is just *one* outgoing edge - if(edge){ - std::vector &chs = edge->Children; - for(unsigned i = 0; i < chs.size(); i++) - DoTopoSortRec(chs[i]); - } - TopoSort[node] = TopoSortCounter++; - SortedEdges.push_back(edge); - } - - void DoTopoSort(){ - TopoSort.clear(); - SortedEdges.clear(); - TopoSortCounter = 0; - for(unsigned i = 0; i < nodes.size(); i++) - DoTopoSortRec(nodes[i]); - } - - - int StratifiedLeafCount; - -#ifdef NEW_STRATIFIED_INLINING - - /** Stratified inlining builds an initial layered unwinding before - switching to the LAWI strategy. Currently the number of layers - is one. Only nodes that are the targets of back edges are - consider to be leaves. This assumes we have already computed a - topological sort. - */ - - bool DoStratifiedInlining(){ - if(stratified_inlining_done) - return true; - stratified_inlining_done = true; - DoTopoSort(); - int depth = 1; // TODO: make this an option - std::vector > unfolding_levels(depth+1); - for(int level = 1; level <= depth; level++) - for(unsigned i = 0; i < SortedEdges.size(); i++){ - Edge *edge = SortedEdges[i]; - Node *parent = edge->Parent; - std::vector &chs = edge->Children; - std::vector my_chs(chs.size()); - for(unsigned j = 0; j < chs.size(); j++){ - Node *child = chs[j]; - int ch_level = TopoSort[child] >= TopoSort[parent] ? level-1 : level; - if(unfolding_levels[ch_level].find(child) == unfolding_levels[ch_level].end()){ - if(ch_level == 0) - unfolding_levels[0][child] = CreateLeaf(child); - else - throw InternalError("in levelized unwinding"); - } - my_chs[j] = unfolding_levels[ch_level][child]; - } - Candidate cand; cand.edge = edge; cand.Children = my_chs; - Node *new_node; - bool ok = Extend(cand,new_node); - MarkExpanded(new_node); // we don't expand here -- just mark it done - if(!ok) return false; // got a counterexample - unfolding_levels[level][parent] = new_node; - } - return true; - } - - Node *CreateLeaf(Node *node){ - RPFP::Node *nchild = CreateNodeInstance(node); - MakeLeaf(nchild, /* do_not_expand = */ true); - nchild->Annotation.SetEmpty(); - return nchild; - } - - void MarkExpanded(Node *node){ - if(unexpanded.find(node) != unexpanded.end()){ - unexpanded.erase(node); - insts_of_node[node->map].push_back(node); - } - } - -#else - - /** In stratified inlining, we build the unwinding from the bottom - down, trying to satisfy the node bounds. We do this as a pre-pass, - limiting the expansion. If we get a counterexample, we are done, - else we continue as usual expanding the unwinding upward. - */ - - bool DoStratifiedInlining(){ - timer_start("StratifiedInlining"); - DoTopoSort(); - for(unsigned i = 0; i < leaves.size(); i++){ - Node *node = leaves[i]; - bool res = SatisfyUpperBound(node); - if(!res){ - timer_stop("StratifiedInlining"); - return false; - } - } - // don't leave any dangling nodes! -#ifndef EFFORT_BOUNDED_STRAT - for(unsigned i = 0; i < leaves.size(); i++) - if(!leaves[i]->Outgoing) - MakeLeaf(leaves[i],true); -#endif - timer_stop("StratifiedInlining"); - return true; - } - -#endif - - /** Here, we do the downward expansion for stratified inlining */ - - hash_map LeafMap, StratifiedLeafMap; - - Edge *GetNodeOutgoing(Node *node, int last_decs = 0){ - if(overapproxes.find(node) == overapproxes.end()) return node->Outgoing; /* already expanded */ - overapproxes.erase(node); -#ifdef EFFORT_BOUNDED_STRAT - if(last_decs > 5000){ - // RPFP::Transformer save = node->Annotation; - node->Annotation.SetEmpty(); - Edge *e = unwinding->CreateLowerBoundEdge(node); - // node->Annotation = save; - insts_of_node[node->map].push_back(node); - // std::cout << "made leaf: " << node->number << std::endl; - return e; - } -#endif - Edge *edge = node->map->Outgoing; - std::vector &chs = edge->Children; - - // make sure we don't create a covered node in this process! - - for(unsigned i = 0; i < chs.size(); i++){ - Node *child = chs[i]; - if(TopoSort[child] < TopoSort[node->map]){ - Node *leaf = LeafMap[child]; - if(!indset->Contains(leaf)){ - node->Outgoing->F.Formula = ctx.bool_val(false); // make this a proper leaf, else bogus cex - return node->Outgoing; - } - } - } - - std::vector nchs(chs.size()); - for(unsigned i = 0; i < chs.size(); i++){ - Node *child = chs[i]; - if(TopoSort[child] < TopoSort[node->map]){ - Node *leaf = LeafMap[child]; - nchs[i] = leaf; - if(unexpanded.find(leaf) != unexpanded.end()){ - unexpanded.erase(leaf); - insts_of_node[child].push_back(leaf); - } - } - else { - if(StratifiedLeafMap.find(child) == StratifiedLeafMap.end()){ - RPFP::Node *nchild = CreateNodeInstance(child,StratifiedLeafCount--); - MakeLeaf(nchild); - nchild->Annotation.SetEmpty(); - StratifiedLeafMap[child] = nchild; - indset->SetDominated(nchild); - } - nchs[i] = StratifiedLeafMap[child]; - } - } - CreateEdgeInstance(edge,node,nchs); - reporter->Extend(node); - return node->Outgoing; - } - - void SetHeuristicOldNode(Node *node){ - LocalHeuristic *h = dynamic_cast(heuristic); - if(h) - h->SetOldNode(node); - } - - bool SolveMain(){ - timer_start("SolveMain"); - bool res = SolveMainInt(); // does the actual work - timer_stop("SolveMain"); - return res; - } - - /** This does the actual solving work. We try to generate - candidates for extension. If we succed, we extend the - unwinding. If we fail, we have a solution. */ - bool SolveMainInt(){ - if(StratifiedInlining && !DoStratifiedInlining()) - return false; -#ifdef BOUNDED - DoTopoSort(); -#endif - while(true){ - timer_start("ProduceCandidatesForExtension"); - ProduceCandidatesForExtension(); - timer_stop("ProduceCandidatesForExtension"); - if(candidates.empty()){ - GenSolutionFromIndSet(); - TestRecursionBounded(); - return true; - } - Candidate cand = candidates.front(); - candidates.pop_front(); - if(CandidateFeasible(cand)){ - Node *new_node; - if(!Extend(cand,new_node)) - return false; -#ifdef EARLY_EXPAND - TryExpandNode(new_node); -#endif - } - } - } - - // hack: put something local into the underapproximation formula - // without this, interpolants can be pretty bad - void AddThing(expr &conj){ - std::string name = "@thing"; - expr thing = ctx.constant(name.c_str(),ctx.bool_sort()); - if(conj.is_app() && conj.decl().get_decl_kind() == And){ - std::vector conjs(conj.num_args()+1); - for(unsigned i = 0; i+1 < conjs.size(); i++) - conjs[i] = conj.arg(i); - conjs[conjs.size()-1] = thing; - conj = rpfp->conjoin(conjs); - } - } - - Node *CreateUnderapproxNode(Node *node){ - // cex.get_tree()->ComputeUnderapprox(cex.get_root(),0); - RPFP::Node *under_node = CreateNodeInstance(node->map /* ,StratifiedLeafCount-- */); - under_node->Annotation.IntersectWith(cex.get_root()->Underapprox); - AddThing(under_node->Annotation.Formula); - Edge *e = unwinding->CreateLowerBoundEdge(under_node); - under_node->Annotation.SetFull(); // allow this node to cover others - back_edges[under_node] = back_edges[node]; - e->map = nullptr; - reporter->Extend(under_node); - return under_node; - } - - /** Try to prove a conjecture about a node. If successful - update the unwinding annotation appropriately. */ - bool ProveConjecture(Node *node, const RPFP::Transformer &t,Node *other = nullptr, Counterexample *_cex = nullptr){ - reporter->Conjecture(node,t); - timer_start("ProveConjecture"); - RPFP::Transformer save = node->Bound; - node->Bound.IntersectWith(t); - -#ifndef LOCALIZE_CONJECTURES - bool ok = SatisfyUpperBound(node); -#else - SetHeuristicOldNode(other); - bool ok = SatisfyUpperBound(node); - SetHeuristicOldNode(0); -#endif - - if(ok){ - timer_stop("ProveConjecture"); - return true; - } -#ifdef UNDERAPPROX_NODES - if(UseUnderapprox && last_decisions > 500){ - std::cout << "making an underapprox\n"; - ExpandNodeFromCoverFail(node); - } -#endif - if(_cex) (*_cex).swap(cex); // return the cex if asked - cex.clear(); // throw away the useless cex - node->Bound = save; // put back original bound - timer_stop("ProveConjecture"); - return false; - } - - /** If a node is part of the inductive subset, expand it. - We ask the inductive subset to exclude the node if possible. - */ - void TryExpandNode(RPFP::Node *node){ - if(indset->Close(node)) return; - if(!NoConj && indset->Conjecture(node)){ -#ifdef UNDERAPPROX_NODES - /* TODO: temporary fix. this prevents an infinite loop in case - the node is covered by multiple others. This should be - removed when covering by a set is implemented. - */ - if(indset->Contains(node)){ - unexpanded.erase(node); - insts_of_node[node->map].push_back(node); - } -#endif - return; - } -#ifdef UNDERAPPROX_NODES - if(!indset->Contains(node)) - return; // could be covered by an underapprox node -#endif - indset->Add(node); -#if defined(CANDS_FROM_COVER_FAIL) && !defined(UNDERAPPROX_NODES) - if(ExpandNodeFromCoverFail(node)) - return; -#endif - ExpandNode(node); - } - - /** Make the conjunction of markers for all (expanded) instances of - a node in the input RPFP. */ - expr AllNodeMarkers(Node *node){ - expr res = ctx.bool_val(true); - std::vector &insts = insts_of_node[node]; - for(int k = insts.size()-1; k >= 0; k--) - res = res && NodeMarker(insts[k]); - return res; - } - - void RuleOutNodesPastBound(Node *node, RPFP::Transformer &t){ -#ifdef BOUNDED - if(RecursionBound < 0)return; - std::vector &insts = insts_of_node[node]; - for(unsigned i = 0; i < insts.size(); i++) - if(NodePastRecursionBound(insts[i])) - t.Formula = t.Formula && !NodeMarker(insts[i]); -#endif - } - - - void GenNodeSolutionWithMarkersAux(Node *node, RPFP::Transformer &annot, expr &marker_disjunction, Node *other_node){ -#ifdef BOUNDED - if(RecursionBound >= 0 && NodePastRecursionBound(node)) - return; -#endif - RPFP::Transformer temp = node->Annotation; - expr marker = (!other_node) ? NodeMarker(node) : NodeMarker(node, other_node); - temp.Formula = (!marker || temp.Formula); - annot.IntersectWith(temp); - marker_disjunction = marker_disjunction || marker; - } - - bool GenNodeSolutionWithMarkers(Node *node, RPFP::Transformer &annot, bool expanded_only = false, Node *other_node = nullptr){ - bool res = false; - annot.SetFull(); - expr marker_disjunction = ctx.bool_val(false); - std::vector &insts = expanded_only ? insts_of_node[node] : all_of_node[node]; - for(unsigned j = 0; j < insts.size(); j++){ - Node *node = insts[j]; - if(indset->Contains(insts[j])){ - GenNodeSolutionWithMarkersAux(node, annot, marker_disjunction, other_node); res = true; - } - } - annot.Formula = annot.Formula && marker_disjunction; - annot.Simplify(); - return res; - } - - /** Make a checker to determine if an edge in the input RPFP - is satisfied. */ - Node *CheckerJustForEdge(Edge *edge, RPFP *checker, bool expanded_only = false){ - Node *root = checker->CloneNode(edge->Parent); - GenNodeSolutionFromIndSet(edge->Parent, root->Bound); - if(root->Bound.IsFull()) - return nullptr; - checker->AssertNode(root); - std::vector cs; - for(unsigned j = 0; j < edge->Children.size(); j++){ - Node *oc = edge->Children[j]; - Node *nc = checker->CloneNode(oc); - if(!GenNodeSolutionWithMarkers(oc,nc->Annotation,expanded_only)) - return nullptr; - Edge *e = checker->CreateLowerBoundEdge(nc); - checker->AssertEdge(e); - cs.push_back(nc); - } - checker->AssertEdge(checker->CreateEdge(root,edge->F,cs)); - return root; - } - -#ifndef MINIMIZE_CANDIDATES_HARDER - -#if 0 - /** Make a checker to detheermine if an edge in the input RPFP - is satisfied. */ - Node *CheckerForEdge(Edge *edge, RPFP *checker){ - Node *root = checker->CloneNode(edge->Parent); - root->Bound = edge->Parent->Annotation; - root->Bound.Formula = (!AllNodeMarkers(edge->Parent)) || root->Bound.Formula; - checker->AssertNode(root); - std::vector cs; - for(unsigned j = 0; j < edge->Children.size(); j++){ - Node *oc = edge->Children[j]; - Node *nc = checker->CloneNode(oc); - nc->Annotation = oc->Annotation; - RuleOutNodesPastBound(oc,nc->Annotation); - Edge *e = checker->CreateLowerBoundEdge(nc); - checker->AssertEdge(e); - cs.push_back(nc); - } - checker->AssertEdge(checker->CreateEdge(root,edge->F,cs)); - return root; - } - -#else - /** Make a checker to determine if an edge in the input RPFP - is satisfied. */ - Node *CheckerForEdge(Edge *edge, RPFP *checker){ - Node *root = checker->CloneNode(edge->Parent); - GenNodeSolutionFromIndSet(edge->Parent, root->Bound); -#if 0 - if(root->Bound.IsFull()) - return = 0; -#endif - checker->AssertNode(root); - std::vector cs; - for(unsigned j = 0; j < edge->Children.size(); j++){ - Node *oc = edge->Children[j]; - Node *nc = checker->CloneNode(oc); - GenNodeSolutionWithMarkers(oc,nc->Annotation,true); - Edge *e = checker->CreateLowerBoundEdge(nc); - checker->AssertEdge(e); - cs.push_back(nc); - } - checker->AssertEdge(checker->CreateEdge(root,edge->F,cs)); - return root; - } -#endif - - /** If an edge is not satisfied, produce an extension candidate - using instances of its children that violate the parent annotation. - We find these using the marker predicates. */ - void ExtractCandidateFromCex(Edge *edge, RPFP *checker, Node *root, Candidate &candidate){ - candidate.edge = edge; - for(unsigned j = 0; j < edge->Children.size(); j++){ - Node *node = root->Outgoing->Children[j]; - Edge *lb = node->Outgoing; - std::vector &insts = insts_of_node[edge->Children[j]]; -#ifndef MINIMIZE_CANDIDATES - for(int k = insts.size()-1; k >= 0; k--) -#else - for(unsigned k = 0; k < insts.size(); k++) -#endif - { - Node *inst = insts[k]; - if(indset->Contains(inst)){ - if(checker->Empty(node) || - eq(lb ? checker->Eval(lb,NodeMarker(inst)) : checker->dualModel.eval(NodeMarker(inst,node)),ctx.bool_val(true))){ - candidate.Children.push_back(inst); - goto next_child; - } - } - } - throw InternalError("No candidate from induction failure"); - next_child:; - } - } -#else - - - /** Make a checker to determine if an edge in the input RPFP - is satisfied. */ - Node *CheckerForEdge(Edge *edge, RPFP *checker){ - Node *root = checker->CloneNode(edge->Parent); - GenNodeSolutionFromIndSet(edge->Parent, root->Bound); - if(root->Bound.IsFull()) - return = 0; - checker->AssertNode(root); - std::vector cs; - for(unsigned j = 0; j < edge->Children.size(); j++){ - Node *oc = edge->Children[j]; - Node *nc = checker->CloneNode(oc); - GenNodeSolutionWithMarkers(oc,nc->Annotation,true); - Edge *e = checker->CreateLowerBoundEdge(nc); - checker->AssertEdge(e); - cs.push_back(nc); - } - checker->AssertEdge(checker->CreateEdge(root,edge->F,cs)); - return root; - } - - /** If an edge is not satisfied, produce an extension candidate - using instances of its children that violate the parent annotation. - We find these using the marker predicates. */ - void ExtractCandidateFromCex(Edge *edge, RPFP *checker, Node *root, Candidate &candidate){ - candidate.edge = edge; - std::vector assumps; - for(unsigned j = 0; j < edge->Children.size(); j++){ - Edge *lb = root->Outgoing->Children[j]->Outgoing; - std::vector &insts = insts_of_node[edge->Children[j]]; - for(unsigned k = 0; k < insts.size(); k++) - { - Node *inst = insts[k]; - expr marker = NodeMarker(inst); - if(indset->Contains(inst)){ - if(checker->Empty(lb->Parent) || - eq(checker->Eval(lb,marker),ctx.bool_val(true))){ - candidate.Children.push_back(inst); - assumps.push_back(checker->Localize(lb,marker)); - goto next_child; - } - assumps.push_back(checker->Localize(lb,marker)); - if(checker->CheckUpdateModel(root,assumps) != unsat){ - candidate.Children.push_back(inst); - goto next_child; - } - assumps.pop_back(); - } - } - throw InternalError("No candidate from induction failure"); - next_child:; - } - } - -#endif - - - Node *CheckerForEdgeClone(Edge *edge, RPFP_caching *checker){ - Edge *gen_cands_edge = checker->GetEdgeClone(edge); - Node *root = gen_cands_edge->Parent; - root->Outgoing = gen_cands_edge; - GenNodeSolutionFromIndSet(edge->Parent, root->Bound); -#if 0 - if(root->Bound.IsFull()) - return = 0; -#endif - checker->AssertNode(root); - for(unsigned j = 0; j < edge->Children.size(); j++){ - Node *oc = edge->Children[j]; - Node *nc = gen_cands_edge->Children[j]; - GenNodeSolutionWithMarkers(oc,nc->Annotation,true,nc); - } - checker->AssertEdge(gen_cands_edge,1,true); - return root; - } - - /** If the current proposed solution is not inductive, - use the induction failure to generate candidates for extension. */ - void GenCandidatesFromInductionFailure(bool full_scan = false){ - timer_start("GenCandIndFail"); - GenSolutionFromIndSet(true /* add markers */); - for(unsigned i = 0; i < edges.size(); i++){ - Edge *edge = edges[i]; - if(!full_scan && updated_nodes.find(edge->Parent) == updated_nodes.end()) - continue; -#ifndef USE_NEW_GEN_CANDS - slvr.push(); - RPFP *checker = new RPFP(rpfp->ls); - Node *root = CheckerForEdge(edge,checker); - if(checker->Check(root) != unsat){ - Candidate candidate; - ExtractCandidateFromCex(edge,checker,root,candidate); - reporter->InductionFailure(edge,candidate.Children); - candidates.push_back(candidate); - } - slvr.pop(1); - delete checker; -#else - if(!NodeSolutionFromIndSetFull(edge->Parent)){ - RPFP_caching::scoped_solver_for_edge ssfe(gen_cands_rpfp,edge,true /* models */, true /*axioms*/); - gen_cands_rpfp->Push(); - Node *root = CheckerForEdgeClone(edge,gen_cands_rpfp); - if(gen_cands_rpfp->Check(root) != unsat){ - Candidate candidate; - ExtractCandidateFromCex(edge,gen_cands_rpfp,root,candidate); - reporter->InductionFailure(edge,candidate.Children); - candidates.push_back(candidate); - } - gen_cands_rpfp->Pop(1); - } -#endif - } - updated_nodes.clear(); - timer_stop("GenCandIndFail"); -#ifdef CHECK_CANDS_FROM_IND_SET - for(std::list::iterator it = candidates.begin(), en = candidates.end(); it != en; ++it){ - if(!CandidateFeasible(*it)) - throw "produced infeasible candidate"; - } -#endif - if(!full_scan && candidates.empty()){ - reporter->Message("No candidates from updates. Trying full scan."); - GenCandidatesFromInductionFailure(true); - } - } - -#ifdef CANDS_FROM_UPDATES - /** If the given edge is not inductive in the current proposed solution, - use the induction failure to generate candidates for extension. */ - void GenCandidatesFromEdgeInductionFailure(RPFP::Edge *edge){ - GenSolutionFromIndSet(true /* add markers */); - for(unsigned i = 0; i < edges.size(); i++){ - slvr.push(); - Edge *edge = edges[i]; - RPFP *checker = new RPFP(rpfp->ls); - Node *root = CheckerForEdge(edge,checker); - if(checker->Check(root) != unsat){ - Candidate candidate; - ExtractCandidateFromCex(edge,checker,root,candidate); - reporter->InductionFailure(edge,candidate.Children); - candidates.push_back(candidate); - } - slvr.pop(1); - delete checker; - } - } -#endif - - /** Find the unexpanded nodes in the inductive subset. */ - void FindNodesToExpand(){ - for(Unexpanded::iterator it = unexpanded.begin(), en = unexpanded.end(); it != en; ++it){ - Node *node = *it; - if(indset->Candidate(node)) - to_expand.push_back(node); - } - } - - /** Try to create some extension candidates from the unexpanded - nodes. */ - void ProduceSomeCandidates(){ - while(candidates.empty() && !to_expand.empty()){ - Node *node = to_expand.front(); - to_expand.pop_front(); - TryExpandNode(node); - } - } - - std::list postponed_candidates; - - /** Try to produce some extension candidates, first from unexpanded - nides, and if this fails, from induction failure. */ - void ProduceCandidatesForExtension(){ - if(candidates.empty()) - ProduceSomeCandidates(); - while(candidates.empty()){ - FindNodesToExpand(); - if(to_expand.empty()) break; - ProduceSomeCandidates(); - } - if(candidates.empty()){ -#ifdef DEPTH_FIRST_EXPAND - if(postponed_candidates.empty()){ - GenCandidatesFromInductionFailure(); - postponed_candidates.swap(candidates); - } - if(!postponed_candidates.empty()){ - candidates.push_back(postponed_candidates.front()); - postponed_candidates.pop_front(); - } -#else - GenCandidatesFromInductionFailure(); -#endif - } - } - - bool Update(Node *node, const RPFP::Transformer &fact, bool eager=false){ - if(!node->Annotation.SubsetEq(fact)){ - reporter->Update(node,fact,eager); - if(conj_reporter) - conj_reporter->Update(node,fact,eager); - indset->Update(node,fact); - updated_nodes.insert(node->map); - node->Annotation.IntersectWith(fact); - return true; - } - return false; - } - - bool UpdateNodeToNode(Node *node, Node *top){ - return Update(node,top->Annotation); - } - - /** Update the unwinding solution, using an interpolant for the - derivation tree. */ - void UpdateWithInterpolant(Node *node, RPFP *tree, Node *top){ - if(top->Outgoing) - for(unsigned i = 0; i < top->Outgoing->Children.size(); i++) - UpdateWithInterpolant(node->Outgoing->Children[i],tree,top->Outgoing->Children[i]); - UpdateNodeToNode(node, top); - heuristic->Update(node); - } - - /** Update unwinding lower bounds, using a counterexample. */ - - void UpdateWithCounterexample(Node *node, RPFP *tree, Node *top){ - if(top->Outgoing) - for(unsigned i = 0; i < top->Outgoing->Children.size(); i++) - UpdateWithCounterexample(node->Outgoing->Children[i],tree,top->Outgoing->Children[i]); - if(!top->Underapprox.SubsetEq(node->Underapprox)){ - reporter->UpdateUnderapprox(node,top->Underapprox); - // indset->Update(node,top->Annotation); - node->Underapprox.UnionWith(top->Underapprox); - heuristic->Update(node); - } - } - - /** Try to update the unwinding to satisfy the upper bound of a - node. */ - bool SatisfyUpperBound(Node *node){ - if(node->Bound.IsFull()) return true; -#ifdef PROPAGATE_BEFORE_CHECK - Propagate(); -#endif - reporter->Bound(node); - int start_decs = rpfp->CumulativeDecisions(); - DerivationTree *dtp = new DerivationTreeSlow(this,unwinding,reporter,heuristic,FullExpand); - DerivationTree &dt = *dtp; - bool res = dt.Derive(unwinding,node,UseUnderapprox); - int end_decs = rpfp->CumulativeDecisions(); - // std::cout << "decisions: " << (end_decs - start_decs) << std::endl; - last_decisions = end_decs - start_decs; - if(res){ - cex.set(dt.tree,dt.top); // note tree is now owned by cex - if(UseUnderapprox){ - UpdateWithCounterexample(node,dt.tree,dt.top); - } - } - else { - UpdateWithInterpolant(node,dt.tree,dt.top); - delete dt.tree; - } - delete dtp; - return !res; - } - - /* For a given nod in the unwinding, get conjectures from the - proposers and check them locally. Update the node with any true - conjectures. - */ - - void DoEagerDeduction(Node *node){ - for(unsigned i = 0; i < proposers.size(); i++){ - const std::vector &conjectures = proposers[i]->Propose(node); - for(unsigned j = 0; j < conjectures.size(); j++){ - const RPFP::Transformer &conjecture = conjectures[j]; - RPFP::Transformer bound(conjecture); - std::vector conj_vec; - unwinding->CollectConjuncts(bound.Formula,conj_vec); - for(unsigned k = 0; k < conj_vec.size(); k++){ - bound.Formula = conj_vec[k]; - if(CheckEdgeCaching(node->Outgoing,bound) == unsat) - Update(node,bound, /* eager = */ true); - //else - //std::cout << "conjecture failed\n"; - } - } - } - } - - - check_result CheckEdge(RPFP *checker, Edge *edge){ - Node *root = edge->Parent; - checker->Push(); - checker->AssertNode(root); - checker->AssertEdge(edge,1,true); - check_result res = checker->Check(root); - checker->Pop(1); - return res; - } - - check_result CheckEdgeCaching(Edge *unwinding_edge, const RPFP::Transformer &bound){ - - // use a dedicated solver for this edge - // TODO: can this mess be hidden somehow? - - RPFP_caching *checker = gen_cands_rpfp; // TODO: a good choice? - Edge *edge = unwinding_edge->map; // get the edge in the original RPFP - RPFP_caching::scoped_solver_for_edge ssfe(checker,edge,true /* models */, true /*axioms*/); - Edge *checker_edge = checker->GetEdgeClone(edge); - - // copy the annotations and bound to the clone - Node *root = checker_edge->Parent; - root->Bound = bound; - for(unsigned j = 0; j < checker_edge->Children.size(); j++){ - Node *oc = unwinding_edge->Children[j]; - Node *nc = checker_edge->Children[j]; - nc->Annotation = oc->Annotation; - } - - return CheckEdge(checker,checker_edge); - } - - - /* If the counterexample derivation is partial due to - use of underapproximations, complete it. */ - - void BuildFullCex(Node *node){ - DerivationTree dt(this,unwinding,reporter,heuristic,FullExpand); - bool res = dt.Derive(unwinding,node,UseUnderapprox,true); // build full tree - if(!res) throw "Duality internal error in BuildFullCex"; - cex.set(dt.tree,dt.top); - } - - void UpdateBackEdges(Node *node){ -#ifdef BOUNDED - std::vector &chs = node->Outgoing->Children; - for(unsigned i = 0; i < chs.size(); i++){ - Node *child = chs[i]; - bool is_back = TopoSort[child->map] >= TopoSort[node->map]; - NodeToCounter &nov = back_edges[node]; - NodeToCounter chv = back_edges[child]; - if(is_back) - chv[child->map].val++; - for(NodeToCounter::iterator it = chv.begin(), en = chv.end(); it != en; ++it){ - Node *back = it->first; - Counter &c = nov[back]; - c.val = std::max(c.val,it->second.val); - } - } -#endif - } - - /** Extend the unwinding, keeping it solved. */ - bool Extend(Candidate &cand, Node *&node){ - timer_start("Extend"); - node = CreateNodeInstance(cand.edge->Parent); - CreateEdgeInstance(cand.edge,node,cand.Children); - UpdateBackEdges(node); - reporter->Extend(node); - DoEagerDeduction(node); // first be eager... - bool res = SatisfyUpperBound(node); // then be lazy - if(res) indset->CloseDescendants(node); - else { -#ifdef UNDERAPPROX_NODES - ExpandUnderapproxNodes(cex.get_tree(), cex.get_root()); -#endif - if(UseUnderapprox) BuildFullCex(node); - timer_stop("Extend"); - return res; - } - timer_stop("Extend"); - return res; - } - - void ExpandUnderapproxNodes(RPFP *tree, Node *root){ - Node *node = root->map; - if(underapprox_map.find(node) != underapprox_map.end()){ - RPFP::Transformer cnst = root->Annotation; - tree->EvalNodeAsConstraint(root, cnst); - cnst.Complement(); - Node *orig = underapprox_map[node]; - RPFP::Transformer save = orig->Bound; - orig->Bound = cnst; - DerivationTree dt(this,unwinding,reporter,heuristic,FullExpand); - bool res = dt.Derive(unwinding,orig,UseUnderapprox,true,tree); - if(!res){ - UpdateWithInterpolant(orig,dt.tree,dt.top); - throw "bogus underapprox!"; - } - ExpandUnderapproxNodes(tree,dt.top); - } - else if(root->Outgoing){ - std::vector &chs = root->Outgoing->Children; - for(unsigned i = 0; i < chs.size(); i++) - ExpandUnderapproxNodes(tree,chs[i]); - } - } - - // Propagate conjuncts up the unwinding - void Propagate(){ - reporter->Message("beginning propagation"); - timer_start("Propagate"); - std::vector sorted_nodes = unwinding->nodes; - std::sort(sorted_nodes.begin(),sorted_nodes.end(),std::less()); // sorts by sequence number - hash_map > facts; - for(unsigned i = 0; i < sorted_nodes.size(); i++){ - Node *node = sorted_nodes[i]; - std::set &node_facts = facts[node->map]; - if(!(node->Outgoing && indset->Contains(node))) - continue; - std::vector conj_vec; - unwinding->CollectConjuncts(node->Annotation.Formula,conj_vec); - std::set conjs; - std::copy(conj_vec.begin(),conj_vec.end(),std::inserter(conjs,conjs.begin())); - if(!node_facts.empty()){ - RPFP *checker = new RPFP(rpfp->ls); - slvr.push(); - Node *root = checker->CloneNode(node); - Edge *edge = node->Outgoing; - // checker->AssertNode(root); - std::vector cs; - for(unsigned j = 0; j < edge->Children.size(); j++){ - Node *oc = edge->Children[j]; - Node *nc = checker->CloneNode(oc); - nc->Annotation = oc->Annotation; // is this needed? - cs.push_back(nc); - } - Edge *checker_edge = checker->CreateEdge(root,edge->F,cs); - checker->AssertEdge(checker_edge, 0, true, false); - std::vector propagated; - for(std::set ::iterator it = node_facts.begin(), en = node_facts.end(); it != en;){ - const expr &fact = *it; - if(conjs.find(fact) == conjs.end()){ - root->Bound.Formula = fact; - slvr.push(); - checker->AssertNode(root); - check_result res = checker->Check(root); - slvr.pop(); - if(res != unsat){ - std::set ::iterator victim = it; - ++it; - node_facts.erase(victim); // if it ain't true, nix it - continue; - } - propagated.push_back(fact); - } - ++it; - } - slvr.pop(); - for(unsigned i = 0; i < propagated.size(); i++){ - root->Annotation.Formula = propagated[i]; - UpdateNodeToNode(node,root); - } - delete checker; - } - for(std::set ::iterator it = conjs.begin(), en = conjs.end(); it != en; ++it){ - expr foo = *it; - node_facts.insert(foo); - } - } - timer_stop("Propagate"); - } - - - /** This class represents a derivation tree. */ - class DerivationTree { - public: - - virtual ~DerivationTree(){} - - DerivationTree(Duality *_duality, RPFP *rpfp, Reporter *_reporter, Heuristic *_heuristic, bool _full_expand) - : slvr(rpfp->slvr()), - ctx(rpfp->ctx) - { - duality = _duality; - reporter = _reporter; - heuristic = _heuristic; - full_expand = _full_expand; - } - - Duality *duality; - Reporter *reporter; - Heuristic *heuristic; - solver &slvr; - context &ctx; - RPFP *tree; - RPFP::Node *top; - std::list leaves; - bool full_expand; - bool underapprox; - bool constrained; - bool false_approx; - std::vector underapprox_core; - int start_decs, last_decs; - - /* We build derivation trees in one of three modes: - - 1) In normal mode, we build the full tree without considering - underapproximations. - - 2) In underapprox mode, we use underapproximations to cut off - the tree construction. THis means the resulting tree may not - be complete. - - 3) In constrained mode, we build the full tree but use - underapproximations as upper bounds. This mode is used to - complete the partial derivation constructed in underapprox - mode. - */ - - bool Derive(RPFP *rpfp, RPFP::Node *root, bool _underapprox, bool _constrained = false, RPFP *_tree = nullptr){ - underapprox = _underapprox; - constrained = _constrained; - false_approx = true; - timer_start("Derive"); -#ifndef USE_CACHING_RPFP - tree = _tree ? _tree : new RPFP(rpfp->ls); -#else - RPFP::LogicSolver *cache_ls = new RPFP::iZ3LogicSolver(ctx); - cache_ls->slvr->push(); - tree = _tree ? _tree : new RPFP_caching(cache_ls); -#endif - tree->HornClauses = rpfp->HornClauses; - tree->Push(); // so we can clear out the solver later when finished - top = CreateApproximatedInstance(root); - tree->AssertNode(top); // assert the negation of the top-level spec - timer_start("Build"); - bool res = Build(); - heuristic->Done(); - timer_stop("Build"); - timer_start("Pop"); - tree->Pop(1); - timer_stop("Pop"); -#ifdef USE_CACHING_RPFP - cache_ls->slvr->pop(1); - delete cache_ls; - tree->ls = rpfp->ls; -#endif - timer_stop("Derive"); - return res; - } - -#define WITH_CHILDREN - - void InitializeApproximatedInstance(RPFP::Node *to){ - to->Annotation = to->map->Annotation; -#ifndef WITH_CHILDREN - tree->CreateLowerBoundEdge(to); -#endif - leaves.push_back(to); - } - - Node *CreateApproximatedInstance(RPFP::Node *from){ - Node *to = tree->CloneNode(from); - InitializeApproximatedInstance(to); - return to; - } - - bool CheckWithUnderapprox(){ - timer_start("CheckWithUnderapprox"); - std::vector leaves_vector(leaves.size()); - std::copy(leaves.begin(),leaves.end(),leaves_vector.begin()); - check_result res = tree->Check(top,leaves_vector); - timer_stop("CheckWithUnderapprox"); - return res != unsat; - } - - virtual bool Build(){ -#ifdef EFFORT_BOUNDED_STRAT - start_decs = tree->CumulativeDecisions(); -#endif - while(ExpandSomeNodes(true)); // do high-priority expansions - while (true) - { -#ifndef WITH_CHILDREN - timer_start("asserting leaves"); - timer_start("pushing"); - tree->Push(); - timer_stop("pushing"); - for(std::list::iterator it = leaves.begin(), en = leaves.end(); it != en; ++it) - tree->AssertEdge((*it)->Outgoing,1); // assert the overapproximation, and keep it past pop - timer_stop("asserting leaves"); - lbool res = tree->Solve(top, 2); // incremental solve, keep interpolants for two pops - timer_start("popping leaves"); - tree->Pop(1); - timer_stop("popping leaves"); -#else - lbool res; - if((underapprox || false_approx) && top->Outgoing && CheckWithUnderapprox()){ - if(constrained) goto expand_some_nodes; // in constrained mode, keep expanding - goto we_are_sat; // else if underapprox is sat, we stop - } - // tree->Check(top); - res = tree->Solve(top, 1); // incremental solve, keep interpolants for one pop -#endif - if (res == l_false) - return false; - - expand_some_nodes: - if(ExpandSomeNodes()) - continue; - - we_are_sat: - if(underapprox && !constrained){ - timer_start("ComputeUnderapprox"); - tree->ComputeUnderapprox(top,1); - timer_stop("ComputeUnderapprox"); - } - else { -#ifdef UNDERAPPROX_NODES -#ifndef SKIP_UNDERAPPROX_NODES - timer_start("ComputeUnderapprox"); - tree->ComputeUnderapprox(top,1); - timer_stop("ComputeUnderapprox"); -#endif -#endif - } - return true; - } - } - - virtual void ExpandNode(RPFP::Node *p){ - // tree->RemoveEdge(p->Outgoing); - Edge *ne = p->Outgoing; - if(ne) { - // reporter->Message("Recycling edge..."); - std::vector &cs = ne->Children; - for(unsigned i = 0; i < cs.size(); i++) - InitializeApproximatedInstance(cs[i]); - // ne->dual = expr(); - } - else { - Edge *edge = duality->GetNodeOutgoing(p->map,last_decs); - std::vector &cs = edge->Children; - std::vector children(cs.size()); - for(unsigned i = 0; i < cs.size(); i++) - children[i] = CreateApproximatedInstance(cs[i]); - ne = tree->CreateEdge(p, p->map->Outgoing->F, children); - ne->map = p->map->Outgoing->map; - } -#ifndef WITH_CHILDREN - tree->AssertEdge(ne); // assert the edge in the solver -#else - tree->AssertEdge(ne,0,!full_expand,(underapprox || false_approx)); // assert the edge in the solver -#endif - reporter->Expand(ne); - } - -#define UNDERAPPROXCORE -#ifndef UNDERAPPROXCORE - void ExpansionChoices(std::set &best){ - std::set choices; - for(std::list::iterator it = leaves.begin(), en = leaves.end(); it != en; ++it) - if (!tree->Empty(*it)) // if used in the counter-model - choices.insert(*it); - heuristic->ChooseExpand(choices, best); - } -#else -#if 0 - - void ExpansionChoices(std::set &best){ - std::vector unused_set, used_set; - std::set choices; - for(std::list::iterator it = leaves.begin(), en = leaves.end(); it != en; ++it){ - Node *n = *it; - if (!tree->Empty(n)) - used_set.push_back(n); - else - unused_set.push_back(n); - } - if(tree->Check(top,unused_set) == unsat) - throw "error in ExpansionChoices"; - for(unsigned i = 0; i < used_set.size(); i++){ - Node *n = used_set[i]; - unused_set.push_back(n); - if(!top->Outgoing || tree->Check(top,unused_set) == unsat){ - unused_set.pop_back(); - choices.insert(n); - } - else - std::cout << "Using underapprox of " << n->number << std::endl; - } - heuristic->ChooseExpand(choices, best); - } -#else - void ExpansionChoicesFull(std::set &best, bool high_priority, bool best_only = false){ - std::set choices; - for(std::list::iterator it = leaves.begin(), en = leaves.end(); it != en; ++it) - if (high_priority || !tree->Empty(*it)) // if used in the counter-model - choices.insert(*it); - heuristic->ChooseExpand(choices, best, high_priority, best_only); - } - - void ExpansionChoicesRec(std::vector &unused_set, std::vector &used_set, - std::set &choices, int from, int to){ - if(from == to) return; - int orig_unused = unused_set.size(); - unused_set.resize(orig_unused + (to - from)); - std::copy(used_set.begin()+from,used_set.begin()+to,unused_set.begin()+orig_unused); - if(!top->Outgoing || tree->Check(top,unused_set) == unsat){ - unused_set.resize(orig_unused); - if(to - from == 1){ -#if 1 - std::cout << "Not using underapprox of " << used_set[from] ->number << std::endl; -#endif - choices.insert(used_set[from]); - } - else { - int mid = from + (to - from)/2; - ExpansionChoicesRec(unused_set, used_set, choices, from, mid); - ExpansionChoicesRec(unused_set, used_set, choices, mid, to); - } - } - else { -#if 1 - std::cout << "Using underapprox of "; - for(int i = from; i < to; i++){ - std::cout << used_set[i]->number << " "; - if(used_set[i]->map->Underapprox.IsEmpty()) - std::cout << "(false!) "; - } - std::cout << std::endl; -#endif - } - } - - std::set old_choices; - - void ExpansionChoices(std::set &best, bool high_priority, bool best_only = false){ - if(!underapprox || constrained || high_priority){ - ExpansionChoicesFull(best, high_priority,best_only); - return; - } - std::vector unused_set, used_set; - std::set choices; - for(std::list::iterator it = leaves.begin(), en = leaves.end(); it != en; ++it){ - Node *n = *it; - if (!tree->Empty(n)){ - if(old_choices.find(n) != old_choices.end() || n->map->Underapprox.IsEmpty()) - choices.insert(n); - else - used_set.push_back(n); - } - else - unused_set.push_back(n); - } - if(tree->Check(top,unused_set) == unsat) - throw "error in ExpansionChoices"; - ExpansionChoicesRec(unused_set, used_set, choices, 0, used_set.size()); - old_choices = choices; - heuristic->ChooseExpand(choices, best, high_priority); - } -#endif -#endif - - bool ExpandSomeNodes(bool high_priority = false, int max = INT_MAX){ -#ifdef EFFORT_BOUNDED_STRAT - last_decs = tree->CumulativeDecisions() - start_decs; -#endif - timer_start("ExpandSomeNodes"); - timer_start("ExpansionChoices"); - std::set choices; - ExpansionChoices(choices,high_priority,max != INT_MAX); - timer_stop("ExpansionChoices"); - std::list leaves_copy = leaves; // copy so can modify orig - leaves.clear(); - int count = 0; - for(std::list::iterator it = leaves_copy.begin(), en = leaves_copy.end(); it != en; ++it){ - if(choices.find(*it) != choices.end() && count < max){ - count++; - ExpandNode(*it); - } - else leaves.push_back(*it); - } - timer_stop("ExpandSomeNodes"); - return !choices.empty(); - } - - void RemoveExpansion(RPFP::Node *p){ - Edge *edge = p->Outgoing; - Node *parent = edge->Parent; -#ifndef KEEP_EXPANSIONS - std::vector cs = edge->Children; - tree->DeleteEdge(edge); - for(unsigned i = 0; i < cs.size(); i++) - tree->DeleteNode(cs[i]); -#endif - leaves.push_back(parent); - } - - // remove all the descendants of tree root (but not root itself) - void RemoveTree(RPFP *tree, RPFP::Node *root){ - Edge *edge = root->Outgoing; - std::vector cs = edge->Children; - tree->DeleteEdge(edge); - for(unsigned i = 0; i < cs.size(); i++){ - RemoveTree(tree,cs[i]); - tree->DeleteNode(cs[i]); - } - } - }; - - class DerivationTreeSlow : public DerivationTree { - public: - - struct stack_entry { - unsigned level; // SMT solver stack level - std::vector expansions; - }; - - std::vector stack; - - hash_map updates; - - int restart_interval; - - DerivationTreeSlow(Duality *_duality, RPFP *rpfp, Reporter *_reporter, Heuristic *_heuristic, bool _full_expand) - : DerivationTree(_duality, rpfp, _reporter, _heuristic, _full_expand) { - stack.push_back(stack_entry()); - } - - struct DoRestart {}; - - bool Build() override { - restart_interval = 3; - while (true) { - try { - return BuildMain(); - } - catch (const DoRestart &) { - // clear the statck and try again - updated_nodes.clear(); - while(stack.size() > 1) - PopLevel(); - reporter->Message("restarted"); - restart_interval += 1; - } - } - } - - - // When we check, try to use the same children that were used in the - // previous counterexample. - check_result Check(){ -#if 0 - std::vector posnodes, negnodes; - std::vector &expansions = stack.back().expansions; - for(unsigned i = 0; i < expansions.size(); i++){ - Node *node = expansions[i]; - std::vector &chs = node->Outgoing->Children; - for(unsigned j = 0; j < chs.size(); j++){ - Node *ch = chs[j]; - int use = heuristic->UseNode(ch); - if(use == 1) - posnodes.push_back(ch); - else if (use == -1) - negnodes.push_back(ch); - } - } - if(!(posnodes.empty() && negnodes.empty())){ - check_result res = tree->CheckWithConstrainedNodes(posnodes,negnodes); - if(res != unsat){ - reporter->Message("matched previous counterexample"); - return res; - } - } -#endif - return tree->Check(top); - } - - bool BuildMain(){ - - stack.back().level = tree->slvr().get_scope_level(); - bool was_sat = true; - int update_failures = 0; - int total_updates = 0; - - while (true) - { - lbool res; - - unsigned slvr_level = tree->slvr().get_scope_level(); - if(slvr_level != stack.back().level) - throw "stacks out of sync!"; - reporter->Depth(stack.size()); - - // res = tree->Solve(top, 1); // incremental solve, keep interpolants for one pop - check_result foo = Check(); - res = foo == unsat ? l_false : l_true; - - if (res == l_false) { - if (stack.empty()) // should never happen - return false; - - { - std::vector &expansions = stack.back().expansions; - int update_count = 0; - for(unsigned i = 0; i < expansions.size(); i++){ - Node *node = expansions[i]; - try { - tree->SolveSingleNode(top,node); -#ifdef NO_GENERALIZE - node->Annotation.Formula = tree->RemoveRedundancy(node->Annotation.Formula).simplify(); -#else - if(expansions.size() == 1 && NodeTooComplicated(node)) - SimplifyNode(node); - else - node->Annotation.Formula = tree->RemoveRedundancy(node->Annotation.Formula).simplify(); - Generalize(node); -#endif - } - catch(const RPFP::Bad &){ - // bad interpolants can get us here - throw DoRestart(); - } - catch(const RPFP::ReallyBad &){ - // this could be caused by incompleteness - for(unsigned i = 0; i < expansions.size(); i++){ - Node *node = expansions[i]; - node->map->Annotation.SetFull(); - std::vector &chs = node->map->Outgoing->Children; - for(unsigned j = 0; j < chs.size(); j++) - chs[j]->Annotation.SetFull(); - reporter->Message("incompleteness: cleared annotation and child annotations"); - } - throw DoRestart(); - } - catch(char const *msg){ - // bad interpolants can get us here - reporter->Message(std::string("interpolation failure:") + msg); - throw DoRestart(); - } - catch(const RPFP::greedy_reduce_failed &){ - // if we couldn't reduce, just continue (maybe should restart?) - reporter->Message("interpolant verification failed"); - } - if(RecordUpdate(node)){ - update_count++; - total_updates++; - } - else - heuristic->Update(node->map); // make it less likely to expand this node in future - } -#if 1 - if(duality->EnableRestarts) - if(total_updates >= restart_interval) - throw DoRestart(); -#endif - if(update_count == 0){ - if(was_sat){ - update_failures++; - if(update_failures > 10){ - for(unsigned i = 0; i < expansions.size(); i++){ - Node *node = expansions[i]; - node->map->Annotation.SetFull(); - reporter->Message("incompleteness: cleared annotation"); - } - throw DoRestart(); - } - } - reporter->Message("backtracked without learning"); - } - else update_failures = 0; - } - tree->ComputeProofCore(); // need to compute the proof core before popping solver - bool propagated = false; - while(1) { - bool prev_level_used = LevelUsedInProof(stack.size()-2); // need to compute this before pop - PopLevel(); - if(stack.size() == 1)break; - if(prev_level_used){ - Node *node = stack.back().expansions[0]; -#ifndef NO_PROPAGATE - if(!Propagate(node)) break; -#endif - if(!RecordUpdate(node)) break; // shouldn't happen! - RemoveUpdateNodesAtCurrentLevel(); // this level is about to be deleted -- remove its children from update list - propagated = true; - continue; - } - if(propagated) break; // propagation invalidates the proof core, so disable non-chron backtrack - RemoveUpdateNodesAtCurrentLevel(); // this level is about to be deleted -- remove its children from update list - std::vector &unused_ex = stack.back().expansions; - for(unsigned i = 0; i < unused_ex.size(); i++) - heuristic->Update(unused_ex[i]->map); // make it less likely to expand this node in future - } - HandleUpdatedNodes(); - if(stack.size() == 1){ - if(top->Outgoing) - tree->DeleteEdge(top->Outgoing); // in case we kept the tree - return false; - } - was_sat = false; - } - else { - was_sat = true; - tree->Push(); - std::vector &expansions = stack.back().expansions; -#ifndef NO_DECISIONS -#if 0 - if(expansions.size() > 0) - tree->GreedyReduceNodes(expansions[0]->Outgoing->Children); // try to reduce number of children -#endif - for(unsigned i = 0; i < expansions.size(); i++){ - tree->FixCurrentState(expansions[i]->Outgoing); - } -#endif -#if 0 - if(tree->slvr().check() == unsat) - throw "help!"; -#endif - int expand_max = 1; - if(0&&duality->BatchExpand){ - int thing = stack.size() / 10; // * 0.1; - expand_max = std::max(1,thing); - if(expand_max > 1) - std::cout << "foo!\n"; - } - - if(ExpandSomeNodes(false,expand_max)) - continue; - tree->Pop(1); - node_order.clear(); - while(stack.size() > 1){ - tree->Pop(1); - std::vector &expansions = stack.back().expansions; - for(unsigned i = 0; i < expansions.size(); i++) - node_order.push_back(expansions[i]); - stack.pop_back(); - } -#if 0 - Reduce(); -#endif - return true; - } - } - } - - std::vector node_order; - - void Reduce(){ - tree->Push(); - // tree->AssertNode(top); // assert the negation of the top-level spec - for(int i = node_order.size()-1; i >= 0; --i){ - Edge *edge = node_order[i]->Outgoing; - if(edge){ - for(unsigned j = 0; j < edge->Children.size(); j++){ - Node *ch = edge->Children[j]; - if(!ch->Outgoing) - ch->Annotation.SetEmpty(); - } - tree->AssertEdge(edge,0,true); - } - } - tree->GreedyReduceNodes(node_order); // try to reduce the counterexample size - tree->Pop(1); - } - - void PopLevel(){ - std::vector &expansions = stack.back().expansions; - tree->Pop(1); - hash_set leaves_to_remove; - for(unsigned i = 0; i < expansions.size(); i++){ - Node *node = expansions[i]; - // if(node != top) - //tree->ConstrainParent(node->Incoming[0],node); - std::vector &cs = node->Outgoing->Children; - for(unsigned i = 0; i < cs.size(); i++){ - leaves_to_remove.insert(cs[i]); - UnmapNode(cs[i]); - if(std::find(updated_nodes.begin(),updated_nodes.end(),cs[i]) != updated_nodes.end()) - throw "help!"; - } - } - RemoveLeaves(leaves_to_remove); // have to do this before actually deleting the children - for(unsigned i = 0; i < expansions.size(); i++){ - Node *node = expansions[i]; - RemoveExpansion(node); - } - stack.pop_back(); - } - - bool NodeTooComplicated(Node *node){ - int ops = tree->CountOperators(node->Annotation.Formula); - if(ops > 10) return true; - node->Annotation.Formula = tree->RemoveRedundancy(node->Annotation.Formula).simplify(); - return tree->CountOperators(node->Annotation.Formula) > 3; - } - - void SimplifyNode(Node *node){ - // have to destroy the old proof to get a new interpolant - timer_start("SimplifyNode"); - tree->PopPush(); - try { - tree->InterpolateByCases(top,node); - } - catch(const RPFP::Bad&){ - timer_stop("SimplifyNode"); - throw RPFP::Bad(); - } - timer_stop("SimplifyNode"); - } - - bool LevelUsedInProof(unsigned level){ - std::vector &expansions = stack[level].expansions; - for(unsigned i = 0; i < expansions.size(); i++) - if(tree->EdgeUsedInProof(expansions[i]->Outgoing)) - return true; - return false; - } - - void RemoveUpdateNodesAtCurrentLevel() { - for(std::list::iterator it = updated_nodes.begin(), en = updated_nodes.end(); it != en;){ - Node *node = *it; - if(AtCurrentStackLevel(node->Incoming[0]->Parent)){ - std::list::iterator victim = it; - ++it; - updated_nodes.erase(victim); - } - else - ++it; - } - } - - void RemoveLeaves(hash_set &leaves_to_remove){ - std::list leaves_copy; - leaves_copy.swap(leaves); - for(std::list::iterator it = leaves_copy.begin(), en = leaves_copy.end(); it != en; ++it){ - if(leaves_to_remove.find(*it) == leaves_to_remove.end()) - leaves.push_back(*it); - } - } - - hash_map > node_map; - std::list updated_nodes; - - void ExpandNode(RPFP::Node *p) override { - stack.push_back(stack_entry()); - stack.back().level = tree->slvr().get_scope_level(); - stack.back().expansions.push_back(p); - DerivationTree::ExpandNode(p); - std::vector &new_nodes = p->Outgoing->Children; - for(unsigned i = 0; i < new_nodes.size(); i++){ - Node *n = new_nodes[i]; - node_map[n->map].push_back(n); - } - } - - bool RecordUpdate(Node *node){ - bool res = duality->UpdateNodeToNode(node->map,node); - if(res){ - std::vector to_update = node_map[node->map]; - for(unsigned i = 0; i < to_update.size(); i++){ - Node *node2 = to_update[i]; - // maintain invariant that no nodes on updated list are created at current stack level - if(node2 == node || !(node->Incoming.size() > 0 && AtCurrentStackLevel(node2->Incoming[0]->Parent))){ - updated_nodes.push_back(node2); - if(node2 != node) - node2->Annotation = node->Annotation; - } - } - } - return res; - } - - void HandleUpdatedNodes(){ - for(std::list::iterator it = updated_nodes.begin(), en = updated_nodes.end(); it != en;){ - Node *node = *it; - node->Annotation = node->map->Annotation; - if(node->Incoming.size() > 0) - tree->ConstrainParent(node->Incoming[0],node); - if(AtCurrentStackLevel(node->Incoming[0]->Parent)){ - std::list::iterator victim = it; - ++it; - updated_nodes.erase(victim); - } - else - ++it; - } - } - - bool AtCurrentStackLevel(Node *node){ - std::vector vec = stack.back().expansions; - for(unsigned i = 0; i < vec.size(); i++) - if(vec[i] == node) - return true; - return false; - } - - void UnmapNode(Node *node){ - std::vector &vec = node_map[node->map]; - for(unsigned i = 0; i < vec.size(); i++){ - if(vec[i] == node){ - std::swap(vec[i],vec.back()); - vec.pop_back(); - return; - } - } - throw "can't unmap node"; - } - - void Generalize(Node *node){ -#ifndef USE_RPFP_CLONE - tree->Generalize(top,node); -#else - RPFP_caching *clone_rpfp = duality->clone_rpfp; - if(!node->Outgoing->map) return; - Edge *clone_edge = clone_rpfp->GetEdgeClone(node->Outgoing->map); - Node *clone_node = clone_edge->Parent; - clone_node->Annotation = node->Annotation; - for(unsigned i = 0; i < clone_edge->Children.size(); i++) - clone_edge->Children[i]->Annotation = node->map->Outgoing->Children[i]->Annotation; - clone_rpfp->GeneralizeCache(clone_edge); - node->Annotation = clone_node->Annotation; -#endif - } - - bool Propagate(Node *node){ -#ifdef USE_RPFP_CLONE - RPFP_caching *clone_rpfp = duality->clone_rpfp; - Edge *clone_edge = clone_rpfp->GetEdgeClone(node->Outgoing->map); - Node *clone_node = clone_edge->Parent; - clone_node->Annotation = node->map->Annotation; - for(unsigned i = 0; i < clone_edge->Children.size(); i++) - clone_edge->Children[i]->Annotation = node->map->Outgoing->Children[i]->Annotation; - bool res = clone_rpfp->PropagateCache(clone_edge); - if(res) - node->Annotation = clone_node->Annotation; - return res; -#else - return false; -#endif - } - - }; - - - class Covering { - - struct cover_info { - Node *covered_by; - std::list covers; - bool dominated; - std::set dominates; - cover_info(){ - covered_by = nullptr; - dominated = false; - } - }; - - typedef hash_map cover_map; - cover_map cm; - Duality *parent; - bool some_updates; - -#define NO_CONJ_ON_SIMPLE_LOOPS -#ifdef NO_CONJ_ON_SIMPLE_LOOPS - hash_set simple_loops; -#endif - - Node *&covered_by(Node *node){ - return cm[node].covered_by; - } - - std::list &covers(Node *node){ - return cm[node].covers; - } - - std::vector &insts_of_node(Node *node){ - return parent->insts_of_node[node]; - } - - Reporter *reporter(){ - return parent->reporter; - } - - std::set &dominates(Node *x){ - return cm[x].dominates; - } - - bool dominates(Node *x, Node *y){ - std::set &d = cm[x].dominates; - return d.find(y) != d.end(); - } - - bool &dominated(Node *x){ - return cm[x].dominated; - } - - public: - - Covering(Duality *_parent){ - parent = _parent; - some_updates = false; - -#ifdef NO_CONJ_ON_SIMPLE_LOOPS - hash_map > outgoing; - for(unsigned i = 0; i < parent->rpfp->edges.size(); i++) - outgoing[parent->rpfp->edges[i]->Parent].push_back(parent->rpfp->edges[i]); - for(unsigned i = 0; i < parent->rpfp->nodes.size(); i++){ - Node * node = parent->rpfp->nodes[i]; - std::vector &outs = outgoing[node]; - if(outs.size() == 2){ - for(int j = 0; j < 2; j++){ - Edge *loop_edge = outs[j]; - if(loop_edge->Children.size() == 1 && loop_edge->Children[0] == loop_edge->Parent) - simple_loops.insert(node); - } - } - } -#endif - - } - - bool IsCoveredRec(hash_set &memo, Node *node){ - if(memo.find(node) != memo.end()) - return false; - memo.insert(node); - if(covered_by(node)) return true; - for(unsigned i = 0; i < node->Outgoing->Children.size(); i++) - if(IsCoveredRec(memo,node->Outgoing->Children[i])) - return true; - return false; - } - - bool IsCovered(Node *node){ - hash_set memo; - return IsCoveredRec(memo,node); - } - -#ifndef UNDERAPPROX_NODES - void RemoveCoveringsBy(Node *node){ - std::list &cs = covers(node); - for(std::list::iterator it = cs.begin(), en = cs.end(); it != en; it++){ - covered_by(*it) = 0; - reporter()->RemoveCover(*it,node); - } - cs.clear(); - } -#else - void RemoveCoveringsBy(Node *node){ - std::vector &cs = parent->all_of_node[node->map]; - for(std::vector::iterator it = cs.begin(), en = cs.end(); it != en; it++){ - Node *other = *it; - if(covered_by(other) && CoverOrder(node,other)){ - covered_by(other) = nullptr; - reporter()->RemoveCover(*it,node); - } - } - } -#endif - - void RemoveAscendantCoveringsRec(hash_set &memo, Node *node){ - if(memo.find(node) != memo.end()) - return; - memo.insert(node); - RemoveCoveringsBy(node); - for(std::vector::iterator it = node->Incoming.begin(), en = node->Incoming.end(); it != en; ++it) - RemoveAscendantCoveringsRec(memo,(*it)->Parent); - } - - void RemoveAscendantCoverings(Node *node){ - hash_set memo; - RemoveAscendantCoveringsRec(memo,node); - } - - bool CoverOrder(Node *covering, Node *covered){ -#ifdef UNDERAPPROX_NODES - if(parent->underapprox_map.find(covered) != parent->underapprox_map.end()) - return false; - if(parent->underapprox_map.find(covering) != parent->underapprox_map.end()) - return covering->number < covered->number || parent->underapprox_map[covering] == covered; -#endif - return covering->number < covered->number; - } - - bool CheckCover(Node *covered, Node *covering){ - return - CoverOrder(covering,covered) - && covered->Annotation.SubsetEq(covering->Annotation) - && !IsCovered(covering); - } - - bool CoverByNode(Node *covered, Node *covering){ - if(CheckCover(covered,covering)){ - covered_by(covered) = covering; - covers(covering).push_back(covered); - std::vector others; others.push_back(covering); - reporter()->AddCover(covered,others); - RemoveAscendantCoverings(covered); - return true; - } - else - return false; - } - -#ifdef UNDERAPPROX_NODES - bool CoverByAll(Node *covered){ - RPFP::Transformer all = covered->Annotation; - all.SetEmpty(); - std::vector &insts = parent->insts_of_node[covered->map]; - std::vector others; - for(unsigned i = 0; i < insts.size(); i++){ - Node *covering = insts[i]; - if(CoverOrder(covering,covered) && !IsCovered(covering)){ - others.push_back(covering); - all.UnionWith(covering->Annotation); - } - } - if(others.size() && covered->Annotation.SubsetEq(all)){ - covered_by(covered) = covered; // anything non-null will do - reporter()->AddCover(covered,others); - RemoveAscendantCoverings(covered); - return true; - } - else - return false; - } -#endif - - bool Close(Node *node){ - if(covered_by(node)) - return true; -#ifndef UNDERAPPROX_NODES - std::vector &insts = insts_of_node(node->map); - for(unsigned i = 0; i < insts.size(); i++) - if(CoverByNode(node,insts[i])) - return true; -#else - if(CoverByAll(node)) - return true; -#endif - return false; - } - - bool CloseDescendantsRec(hash_set &memo, Node *node){ - if(memo.find(node) != memo.end()) - return false; - for(unsigned i = 0; i < node->Outgoing->Children.size(); i++) - if(CloseDescendantsRec(memo,node->Outgoing->Children[i])) - return true; - if(Close(node)) - return true; - memo.insert(node); - return false; - } - - bool CloseDescendants(Node *node){ - timer_start("CloseDescendants"); - hash_set memo; - bool res = CloseDescendantsRec(memo,node); - timer_stop("CloseDescendants"); - return res; - } - - bool Contains(Node *node){ - timer_start("Contains"); - bool res = !IsCovered(node); - timer_stop("Contains"); - return res; - } - - bool Candidate(Node *node){ - timer_start("Candidate"); - bool res = !IsCovered(node) && !dominated(node); - timer_stop("Candidate"); - return res; - } - - void SetDominated(Node *node){ - dominated(node) = true; - } - - bool CouldCover(Node *covered, Node *covering){ -#ifdef NO_CONJ_ON_SIMPLE_LOOPS - // Forsimple loops, we rely on propagation, not covering - if(simple_loops.find(covered->map) != simple_loops.end()) - return false; -#endif -#ifdef UNDERAPPROX_NODES - // if(parent->underapprox_map.find(covering) != parent->underapprox_map.end()) - // return parent->underapprox_map[covering] == covered; -#endif - if(CoverOrder(covering,covered) - && !IsCovered(covering)){ - RPFP::Transformer f(covering->Annotation); f.SetEmpty(); -#if defined(TOP_DOWN) || defined(EFFORT_BOUNDED_STRAT) - if(parent->StratifiedInlining) - return true; -#endif - return !covering->Annotation.SubsetEq(f); - } - return false; - } - - bool ContainsCex(Node *node, Counterexample &cex){ - expr val = cex.get_tree()->Eval(cex.get_root()->Outgoing,node->Annotation.Formula); - return eq(val,parent->ctx.bool_val(true)); - } - - /** We conjecture that the annotations of similar nodes may be - true of this one. We start with later nodes, on the - principle that their annotations are likely weaker. We save - a counterexample -- if annotations of other nodes are true - in this counterexample, we don't need to check them. - */ - -#ifndef UNDERAPPROX_NODES - bool Conjecture(Node *node){ - std::vector &insts = insts_of_node(node->map); - Counterexample cex; - for(int i = insts.size() - 1; i >= 0; i--){ - Node *other = insts[i]; - if(CouldCover(node,other)){ - reporter()->Forcing(node,other); - if(cex.get_tree() && !ContainsCex(other,cex)) - continue; - cex.clear(); - if(parent->ProveConjecture(node,other->Annotation,other,&cex)) - if(CloseDescendants(node)) - return true; - } - } - cex.clear(); - return false; - } -#else - bool Conjecture(Node *node){ - std::vector &insts = insts_of_node(node->map); - Counterexample cex; - RPFP::Transformer Bound = node->Annotation; - Bound.SetEmpty(); - bool some_other = false; - for(int i = insts.size() - 1; i >= 0; i--){ - Node *other = insts[i]; - if(CouldCover(node,other)){ - reporter()->Forcing(node,other); - Bound.UnionWith(other->Annotation); - some_other = true; - } - } - if(some_other && parent->ProveConjecture(node,Bound)){ - CloseDescendants(node); - return true; - } - return false; - } -#endif - - void Update(Node *node, const RPFP::Transformer &update){ - RemoveCoveringsBy(node); - some_updates = true; - } - -#ifndef UNDERAPPROX_NODES - Node *GetSimilarNode(Node *node){ - if(!some_updates) - return 0; - std::vector &insts = insts_of_node(node->map); - for(int i = insts.size()-1; i >= 0; i--){ - Node *other = insts[i]; - if(dominates(node,other)) - if(CoverOrder(other,node) - && !IsCovered(other)) - return other; - } - return 0; - } -#else - Node *GetSimilarNode(Node *node){ - if(!some_updates) - return nullptr; - std::vector &insts = insts_of_node(node->map); - for(int i = insts.size() - 1; i >= 0; i--){ - Node *other = insts[i]; - if(CoverOrder(other,node) - && !IsCovered(other)) - return other; - } - return nullptr; - } -#endif - - bool Dominates(Node * node, Node *other){ - if(node == other) return false; - if(other->Outgoing->map == nullptr) return true; - if(node->Outgoing->map == other->Outgoing->map){ - assert(node->Outgoing->Children.size() == other->Outgoing->Children.size()); - for(unsigned i = 0; i < node->Outgoing->Children.size(); i++){ - Node *nc = node->Outgoing->Children[i]; - Node *oc = other->Outgoing->Children[i]; - if(!(nc == oc || oc->Outgoing->map ==nullptr || dominates(nc,oc))) - return false; - } - return true; - } - return false; - } - - void Add(Node *node){ - std::vector &insts = insts_of_node(node->map); - for(unsigned i = 0; i < insts.size(); i++){ - Node *other = insts[i]; - if(Dominates(node,other)){ - cm[node].dominates.insert(other); - cm[other].dominated = true; - reporter()->Dominates(node, other); - } - } - } - - }; - - /* This expansion heuristic makes use of a previuosly obtained - counterexample as a guide. This is for use in abstraction - refinement schemes.*/ - - class ReplayHeuristic : public Heuristic { - - Counterexample old_cex; - public: - ReplayHeuristic(RPFP *_rpfp, Counterexample &_old_cex) - : Heuristic(_rpfp) - { - old_cex.swap(_old_cex); // take ownership from caller - } - - ~ReplayHeuristic() override { - } - - // Maps nodes of derivation tree into old cex - hash_map cex_map; - - void Done() override { - cex_map.clear(); - old_cex.clear(); - } - - void ShowNodeAndChildren(Node *n){ - std::cout << n->Name.name() << ": "; - std::vector &chs = n->Outgoing->Children; - for(unsigned i = 0; i < chs.size(); i++) - std::cout << chs[i]->Name.name() << " " ; - std::cout << std::endl; - } - - // HACK: When matching relation names, we drop suffixes used to - // make the names unique between runs. For compatibility - // with boggie, we drop suffixes beginning with @@ - std::string BaseName(const std::string &name){ - int pos = name.find("@@"); - if(pos >= 1) - return name.substr(0,pos); - return name; - } - - Node *MatchNode(Node *node){ - if(cex_map.find(node) == cex_map.end()){ // try to match an unmatched node - Node *parent = node->Incoming[0]->Parent; // assumes we are a tree! - if(cex_map.find(parent) == cex_map.end()) - throw "catastrophe in ReplayHeuristic::ChooseExpand"; - Node *old_parent = cex_map[parent]; - std::vector &chs = parent->Outgoing->Children; - if(old_parent && old_parent->Outgoing){ - std::vector &old_chs = old_parent->Outgoing->Children; - for(unsigned i = 0, j=0; i < chs.size(); i++){ - if(j < old_chs.size() && BaseName(chs[i]->Name.name().str()) == BaseName(old_chs[j]->Name.name().str())) - cex_map[chs[i]] = old_chs[j++]; - else { - std::cerr << "WARNING: duality: unmatched child: " << chs[i]->Name.name() << std::endl; - cex_map[chs[i]] = 0; - } - } - goto matching_done; - } - for(unsigned i = 0; i < chs.size(); i++) - cex_map[chs[i]] = 0; - } - matching_done: - return cex_map[node]; - } - - int UseNode(Node *node) override { - if (!old_cex.get_tree()) - return 0; - Node *old_node = MatchNode(node); - if(!old_node) - return 0; - return old_cex.get_tree()->Empty(old_node) ? -1 : 1; - } - - void ChooseExpand(const std::set &choices, std::set &best, bool high_priority, bool best_only) override { - if(cex_map.empty()) - cex_map[*(choices.begin())] = old_cex.get_root(); // match the root nodes - if(!high_priority || !old_cex.get_tree()){ - Heuristic::ChooseExpand(choices,best,false); - return; - } - // first, try to match the derivatino tree nodes to the old cex - std::set matched, unmatched; - for(std::set::iterator it = choices.begin(), en = choices.end(); it != en; ++it){ - Node *node = (*it); - Node *old_node = MatchNode(node); - if(!old_node) - unmatched.insert(node); - else if(old_cex.get_tree()->Empty(old_node)) - unmatched.insert(node); - else - matched.insert(node); - } - if (matched.empty() && !high_priority) - Heuristic::ChooseExpand(unmatched,best,false); - else - Heuristic::ChooseExpand(matched,best,false); - } - }; - - - class LocalHeuristic : public Heuristic { - - RPFP::Node *old_node; - public: - LocalHeuristic(RPFP *_rpfp) - : Heuristic(_rpfp) - { - old_node = nullptr; - } - - void SetOldNode(RPFP::Node *_old_node){ - old_node = _old_node; - cex_map.clear(); - } - - // Maps nodes of derivation tree into old subtree - hash_map cex_map; - - void ChooseExpand(const std::set &choices, std::set &best, bool, bool) override { - if(old_node == nullptr){ - Heuristic::ChooseExpand(choices,best); - return; - } - // first, try to match the derivatino tree nodes to the old cex - std::set matched, unmatched; - for(std::set::iterator it = choices.begin(), en = choices.end(); it != en; ++it){ - Node *node = (*it); - if(cex_map.empty()) - cex_map[node] = old_node; // match the root nodes - if(cex_map.find(node) == cex_map.end()){ // try to match an unmatched node - Node *parent = node->Incoming[0]->Parent; // assumes we are a tree! - if(cex_map.find(parent) == cex_map.end()) - throw "catastrophe in ReplayHeuristic::ChooseExpand"; - Node *old_parent = cex_map[parent]; - std::vector &chs = parent->Outgoing->Children; - if(old_parent && old_parent->Outgoing){ - std::vector &old_chs = old_parent->Outgoing->Children; - if(chs.size() == old_chs.size()){ - for(unsigned i = 0; i < chs.size(); i++) - cex_map[chs[i]] = old_chs[i]; - goto matching_done; - } - else - std::cout << "derivation tree does not match old cex" << std::endl; - } - for(unsigned i = 0; i < chs.size(); i++) - cex_map[chs[i]] = 0; - } - matching_done: - Node *old_node = cex_map[node]; - if(!old_node) - unmatched.insert(node); - else if(old_node != node->map) - unmatched.insert(node); - else - matched.insert(node); - } - Heuristic::ChooseExpand(unmatched,best); - } - }; - - /** This proposer class generates conjectures based on the - unwinding generated by a previous solver. The assumption is - that the provious solver was working on a different - abstraction of the same system. The trick is to adapt the - annotations in the old unwinding to the new predicates. We - start by generating a map from predicates and parameters in - the old problem to the new. - - HACK: mapping is done by cheesy name comparison. - */ - - class HistoryProposer : public Proposer - { - Duality *old_solver; - Duality *new_solver; - hash_map > conjectures; - - public: - /** Construct a history solver. */ - HistoryProposer(Duality *_old_solver, Duality *_new_solver) - : old_solver(_old_solver), new_solver(_new_solver) { - - // tricky: names in the axioms may have changed -- map them - hash_set &old_constants = old_solver->unwinding->ls->get_constants(); - hash_set &new_constants = new_solver->rpfp->ls->get_constants(); - hash_map cmap; - for(hash_set::iterator it = new_constants.begin(), en = new_constants.end(); it != en; ++it) - cmap[GetKey(*it)] = *it; - hash_map bckg_map; - for(hash_set::iterator it = old_constants.begin(), en = old_constants.end(); it != en; ++it){ - func_decl f = new_solver->ctx.translate(*it); // move to new context - if(cmap.find(GetKey(f)) != cmap.end()) - bckg_map[f] = cmap[GetKey(f)]; - // else - // std::cout << "constant not matched\n"; - } - - RPFP *old_unwinding = old_solver->unwinding; - hash_map > pred_match; - - // index all the predicates in the old unwinding - for(unsigned i = 0; i < old_unwinding->nodes.size(); i++){ - Node *node = old_unwinding->nodes[i]; - std::string key = GetKey(node); - pred_match[key].push_back(node); - } - - // match with predicates in the new RPFP - RPFP *rpfp = new_solver->rpfp; - for(unsigned i = 0; i < rpfp->nodes.size(); i++){ - Node *node = rpfp->nodes[i]; - std::string key = GetKey(node); - std::vector &matches = pred_match[key]; - for(unsigned j = 0; j < matches.size(); j++) - MatchNodes(node,matches[j],bckg_map); - } - } - - std::vector &Propose(Node *node) override { - return conjectures[node->map]; - } - - ~HistoryProposer() override { - }; - - private: - void MatchNodes(Node *new_node, Node *old_node, hash_map &bckg_map){ - if(old_node->Annotation.IsFull()) - return; // don't conjecture true! - hash_map var_match; - std::vector &new_params = new_node->Annotation.IndParams; - // Index the new parameters by their keys - for(unsigned i = 0; i < new_params.size(); i++) - var_match[GetKey(new_params[i])] = new_params[i]; - RPFP::Transformer &old = old_node->Annotation; - std::vector from_params = old.IndParams; - for(unsigned j = 0; j < from_params.size(); j++) - from_params[j] = new_solver->ctx.translate(from_params[j]); // get in new context - std::vector to_params = from_params; - for(unsigned j = 0; j < to_params.size(); j++){ - std::string key = GetKey(to_params[j]); - if(var_match.find(key) == var_match.end()){ - // std::cout << "unmatched parameter!\n"; - return; - } - to_params[j] = var_match[key]; - } - expr fmla = new_solver->ctx.translate(old.Formula); // get in new context - fmla = new_solver->rpfp->SubstParams(old.IndParams,to_params,fmla); // substitute parameters - hash_map memo; - fmla = new_solver->rpfp->SubstRec(memo,bckg_map,fmla); // substitute background constants - RPFP::Transformer new_annot = new_node->Annotation; - new_annot.Formula = fmla; - conjectures[new_node].push_back(new_annot); - } - - // We match names by removing suffixes beginning with double at sign - - std::string GetKey(Node *node){ - return GetKey(node->Name); - } - - std::string GetKey(const expr &var){ - return GetKey(var.decl()); - } - - std::string GetKey(const func_decl &f){ - std::string name = f.name().str(); - int idx = name.find("@@"); - if(idx >= 0) - name.erase(idx); - return name; - } - }; - }; - - static int stop_event = -1; - - class StreamReporter : public Reporter { - std::ostream &s; - public: - StreamReporter(RPFP *_rpfp, std::ostream &_s) - : Reporter(_rpfp), s(_s) {event = 0; depth = -1;} - int event; - int depth; - void ev(){ - if(stop_event == event){ - std::cout << "stop!\n"; - } - s << "[" << event++ << "]" ; - } - void Extend(RPFP::Node *node) override { - ev(); s << "node " << node->number << ": " << node->Name.name(); - std::vector &rps = node->Outgoing->Children; - for(unsigned i = 0; i < rps.size(); i++) - s << " " << rps[i]->number; - s << std::endl; - } - void Update(RPFP::Node *node, const RPFP::Transformer &update, bool eager) override { - ev(); s << "update " << node->number << " " << node->Name.name() << ": "; - rpfp->Summarize(update.Formula); - if(depth > 0) s << " (depth=" << depth << ")"; - if(eager) s << " (eager)"; - s << std::endl; - } - void Bound(RPFP::Node *node) override { - ev(); s << "check " << node->number << std::endl; - } - void Expand(RPFP::Edge *edge) override { - RPFP::Node *node = edge->Parent; - ev(); s << "expand " << node->map->number << " " << node->Name.name(); - if(depth > 0) s << " (depth=" << depth << ")"; - s << std::endl; - } - void Depth(int d) override { - depth = d; - } - void AddCover(RPFP::Node *covered, std::vector &covering) override { - ev(); s << "cover " << covered->Name.name() << ": " << covered->number << " by "; - for(unsigned i = 0; i < covering.size(); i++) - s << covering[i]->number << " "; - s << std::endl; - } - void RemoveCover(RPFP::Node *covered, RPFP::Node *covering) override { - ev(); s << "uncover " << covered->Name.name() << ": " << covered->number << " by " << covering->number << std::endl; - } - void Forcing(RPFP::Node *covered, RPFP::Node *covering) override { - ev(); s << "forcing " << covered->Name.name() << ": " << covered->number << " by " << covering->number << std::endl; - } - void Conjecture(RPFP::Node *node, const RPFP::Transformer &t) override { - ev(); s << "conjecture " << node->number << " " << node->Name.name() << ": "; - rpfp->Summarize(t.Formula); - s << std::endl; - } - void Dominates(RPFP::Node *node, RPFP::Node *other) override { - ev(); s << "dominates " << node->Name.name() << ": " << node->number << " > " << other->number << std::endl; - } - void InductionFailure(RPFP::Edge *edge, const std::vector &children) override { - ev(); s << "induction failure: " << edge->Parent->Name.name() << ", children ="; - for(unsigned i = 0; i < children.size(); i++) - s << " " << children[i]->number; - s << std::endl; - } - void UpdateUnderapprox(RPFP::Node *node, const RPFP::Transformer &update) override { - ev(); s << "underapprox " << node->number << " " << node->Name.name() << ": " << update.Formula << std::endl; - } - void Reject(RPFP::Edge *edge, const std::vector &children) override { - ev(); s << "reject " << edge->Parent->number << " " << edge->Parent->Name.name() << ": "; - for(unsigned i = 0; i < children.size(); i++) - s << " " << children[i]->number; - s << std::endl; - } - void Message(const std::string &msg) override { - ev(); s << "msg " << msg << std::endl; - } - - }; - - - class DualityDepthBounded : public Solver { - - Duality *duality; - context &ctx; // Z3 context - solver &slvr; // Z3 solver - - public: - DualityDepthBounded(RPFP *_rpfp) : - ctx(_rpfp->ctx), - slvr(_rpfp->slvr()){ - rpfp = _rpfp; - DepthBoundRPFP(); - duality = alloc(Duality,drpfp); - } - - ~DualityDepthBounded() override { - dealloc(duality); - delete drpfp; - } - - bool Solve() override { - int depth_bound = 10; - bool res; - SetMaxDepthRPFP(depth_bound); - duality->PreSolve(); - while(true){ - res = duality->SolveMain(); - if(!res || GetSolution()) - break; - depth_bound++; - SetMaxDepthRPFP(depth_bound); - res = duality->RecheckBounds(); - if(!res) - break; - } - duality->PostSolve(); - if(!res) - ConvertCex(); - return res; - } - - Counterexample &GetCounterexample() override { - return cex; - } - - bool SetOption(const std::string &option, const std::string &value) override { - return duality->SetOption(option,value); - } - - void LearnFrom(Solver *old_solver) override { - DualityDepthBounded *old = dynamic_cast(old_solver); - if(old){ - duality->LearnFrom(old->duality); - } - } - - bool IsResultRecursionBounded() override { - return duality->IsResultRecursionBounded(); - } - - void Cancel() override { - duality->Cancel(); - } - - typedef RPFP::Node Node; - typedef RPFP::Edge Edge; - RPFP *rpfp, *drpfp; - hash_map db_map, db_rev_map; - hash_map db_edge_rev_map; - std::vector db_saved_bounds; - Counterexample cex; - - expr AddParamToRels(hash_map &memo, hash_map &rmap, const expr &p, const expr &t) { - std::pair foo(t,expr(ctx)); - std::pair::iterator, bool> bar = memo.insert(foo); - expr &res = bar.first->second; - if(!bar.second) return res; - - if (t.is_app()) - { - func_decl f = t.decl(); - std::vector args; - int nargs = t.num_args(); - args.reserve(nargs); - for(int i = 0; i < nargs; i++) - args.push_back(AddParamToRels(memo, rmap, p, t.arg(i))); - hash_map::iterator rit = rmap.find(f); - if(rit != rmap.end()){ - args.push_back(p); - res = (rit->second)(args); - res = ctx.make(And,res,ctx.make(Geq,p,ctx.int_val(0))); - } - else - res = f(args); - } - else if (t.is_quantifier()) - { - expr body = AddParamToRels(memo, rmap, p, t.body()); - res = clone_quantifier(t, body); - } - else res = t; - return res; - } - - - void DepthBoundRPFP(){ - drpfp = new RPFP(rpfp->ls); - expr dvar = ctx.int_const("@depth"); - expr dmax = ctx.int_const("@depth_max"); - for(unsigned i = 0; i < rpfp->nodes.size(); i++){ - Node *node = rpfp->nodes[i]; - std::vector arg_sorts; - const std::vector ¶ms = node->Annotation.IndParams; - for(unsigned j = 0; j < params.size(); j++) - arg_sorts.push_back(params[j].get_sort()); - arg_sorts.push_back(ctx.int_sort()); - std::string new_name = std::string("@db@") + node->Name.name().str(); - func_decl f = ctx.function(new_name.c_str(),arg_sorts.size(), VEC2PTR(arg_sorts),ctx.bool_sort()); - std::vector args = params; - args.push_back(dvar); - expr pat = f(args); - Node *dnode = drpfp->CreateNode(pat); - db_map[node] = dnode; - db_rev_map[dnode] = node; - expr bound_fmla = node->Bound.Formula; - if(!eq(bound_fmla,ctx.bool_val(true))){ - bound_fmla = implies(dvar == dmax,bound_fmla); - dnode->Bound.Formula = bound_fmla; - } - db_saved_bounds.push_back(bound_fmla); - // dnode->Annotation.Formula = ctx.make(And,node->Annotation.Formula,ctx.make(Geq,dvar,ctx.int_val(0))); - } - for(unsigned i = 0; i < rpfp->edges.size(); i++){ - Edge *edge = rpfp->edges[i]; - std::vector new_children; - std::vector new_relparams; - hash_map rmap; - for(unsigned j = 0; j < edge->Children.size(); j++){ - Node *ch = edge->Children[j]; - Node *nch = db_map[ch]; - func_decl f = nch->Name; - func_decl sf = drpfp->NumberPred(f,j); - new_children.push_back(nch); - new_relparams.push_back(sf); - rmap[edge->F.RelParams[j]] = sf; - } - std::vector new_indparams = edge->F.IndParams; - new_indparams.push_back(dvar); - hash_map memo; - expr new_fmla = AddParamToRels(memo,rmap,ctx.make(Sub,dvar,ctx.int_val(1)),edge->F.Formula); - RPFP::Transformer new_t = drpfp->CreateTransformer(new_relparams,new_indparams,new_fmla); - Node *new_parent = db_map[edge->Parent]; - db_edge_rev_map[drpfp->CreateEdge(new_parent,new_t,new_children)] = edge; - } - } - - void SetMaxDepthRPFP(int depth){ - hash_map subst; - expr dmax = ctx.int_const("@depth_max"); - subst[dmax] = ctx.int_val(depth); - for(unsigned i = 0; i < drpfp->nodes.size(); i++){ - Node *node = drpfp->nodes[i]; - expr fmla = db_saved_bounds[i]; - fmla = drpfp->SubstRec(subst,fmla); - node->Bound.Formula = fmla; - } - } - - void ConvertCex(){ - cex.clear(); - RPFP *tree = new RPFP(rpfp->ls); - Node *root; - Counterexample &dctx = duality->GetCounterexample(); - hash_map ctx_node_map; - for(unsigned i = 0; i < dctx.get_tree()->nodes.size(); i++){ - Node *dnode = dctx.get_tree()->nodes[i]; - Node *onode = db_rev_map[dnode->map->map]; - Node *node = tree->CloneNode(onode); - node->number = dnode->number; // numbers have to match for model to make sense - ctx_node_map[dnode] = node; - if(dnode == dctx.get_root()) - root = node; - } - for(unsigned i = 0; i < dctx.get_tree()->edges.size(); i++){ - Edge *dedge = dctx.get_tree()->edges[i]; - Edge *oedge = db_edge_rev_map[dedge->map]; - Node *parent = ctx_node_map[dedge->Parent]; - std::vector chs; - for(unsigned j = 0; j < dedge->Children.size(); j++) - chs.push_back(ctx_node_map[dedge->Children[j]]); - Edge *edge = tree->CreateEdge(parent,oedge->F,chs); - edge->number = dedge->number; // numbers have to match for model to make sense - edge->map = oedge; - } - tree->dualModel = dctx.get_tree()->dualModel; - cex.set(tree,root); - } - - bool GetSolution(){ - for(unsigned i = 0; i < rpfp->nodes.size(); i++) - if(!drpfp->nodes[i]->Annotation.SubsetEq(rpfp->nodes[i]->Bound)) - return false; - expr dvar = ctx.int_const("@depth"); - hash_map subst; - subst[dvar] = ctx.int_val(INT_MAX); - for(unsigned i = 0; i < rpfp->nodes.size(); i++){ - expr fmla = drpfp->nodes[i]->Annotation.Formula; - fmla = drpfp->SubstRec(subst,fmla); - fmla = fmla.simplify(); - rpfp->nodes[i]->Annotation.Formula = fmla; - } - return true; - } - - void UndoDepthBoundRPFP(){ -#if 0 - if(cex.get_tree()){ - // here, need to map the cex back... - } - // also need to map the proof back, but we don't... -#endif - } - }; - - Solver *Solver::Create(const std::string &solver_class, RPFP *rpfp){ - // Solver *s = alloc(DualityDepthBounded,rpfp); - Solver *s = alloc(Duality,rpfp); - return s; - } - - Reporter *CreateStdoutReporter(RPFP *rpfp){ - return new StreamReporter(rpfp, std::cout); - } - - class ConjectureFileReporter : public Reporter { - std::ofstream s; - public: - ConjectureFileReporter(RPFP *_rpfp, const std::string &fname) - : Reporter(_rpfp), s(fname.c_str()) {} - void Update(RPFP::Node *node, const RPFP::Transformer &update, bool eager) override { - s << "(define-fun " << node->Name.name() << " ("; - for(unsigned i = 0; i < update.IndParams.size(); i++){ - if(i != 0) - s << " "; - s << "(" << update.IndParams[i] << " " << update.IndParams[i].get_sort() << ")"; - } - s << ") Bool \n"; - s << update.Formula << ")\n"; - s << std::endl; - } - }; - - Reporter *CreateConjectureFileReporter(RPFP *rpfp, const std::string &fname){ - return new ConjectureFileReporter(rpfp, fname); - } - -} - diff --git a/src/duality/duality_wrapper.cpp b/src/duality/duality_wrapper.cpp deleted file mode 100644 index 17adbdcea..000000000 --- a/src/duality/duality_wrapper.cpp +++ /dev/null @@ -1,744 +0,0 @@ -/*++ - Copyright (c) 2012 Microsoft Corporation - - Module Name: - - wrapper.cpp - - Abstract: - - wrap various objects in the style expected by duality - - Author: - - Ken McMillan (kenmcmil) - - Revision History: - - - --*/ - -#ifdef _WINDOWS -#pragma warning(disable:4996) -#pragma warning(disable:4800) -#pragma warning(disable:4267) -#pragma warning(disable:4101) -#endif - -#include "duality/duality_wrapper.h" -#include -#include "smt/smt_solver.h" -#include "interp/iz3interp.h" -#include "util/statistics.h" -#include "ast/expr_abstract.h" -#include "util/stopwatch.h" -#include "model/model_smt2_pp.h" -#include "qe/qe_lite.h" - -namespace Duality { - - solver::solver(Duality::context& c, bool _extensional, bool models) : object(c), the_model(c) { - params_ref p; - p.set_bool("proof", true); // this is currently useless - if(models) - p.set_bool("model", true); - p.set_bool("unsat_core", true); - bool mbqi = c.get_config().get().get_bool("mbqi",true); - p.set_bool("mbqi",mbqi); // just to test - p.set_str("mbqi.id","itp"); // use mbqi for quantifiers in interpolants - p.set_uint("mbqi.max_iterations",1); // use mbqi for quantifiers in interpolants - extensional = mbqi && (true || _extensional); - if(extensional) - p.set_bool("array.extensional",true); - scoped_ptr sf = mk_smt_solver_factory(); - m_solver = (*sf)(m(), p, true, true, true, ::symbol::null); - m_solver->updt_params(p); // why do we have to do this? - canceled = false; - m_mode = m().proof_mode(); - } - - expr context::constant(const std::string &name, const sort &ty){ - symbol s = str_symbol(name.c_str()); - return cook(m().mk_const(m().mk_const_decl(s, ty))); - } - - expr context::make(decl_kind op, int n, ::expr **args){ - switch(op) { - case True: return mki(m_basic_fid,OP_TRUE,n,args); - case False: return mki(m_basic_fid,OP_FALSE,n,args); - case Equal: return mki(m_basic_fid,OP_EQ,n,args); - case Distinct: return mki(m_basic_fid,OP_DISTINCT,n,args); - case Ite: return mki(m_basic_fid,OP_ITE,n,args); - case And: return mki(m_basic_fid,OP_AND,n,args); - case Or: return mki(m_basic_fid,OP_OR,n,args); - case Iff: return mki(m_basic_fid,OP_IFF,n,args); - case Xor: return mki(m_basic_fid,OP_XOR,n,args); - case Not: return mki(m_basic_fid,OP_NOT,n,args); - case Implies: return mki(m_basic_fid,OP_IMPLIES,n,args); - case Oeq: return mki(m_basic_fid,OP_OEQ,n,args); - case Interp: return mki(m_basic_fid,OP_INTERP,n,args); - case Leq: return mki(m_arith_fid,OP_LE,n,args); - case Geq: return mki(m_arith_fid,OP_GE,n,args); - case Lt: return mki(m_arith_fid,OP_LT,n,args); - case Gt: return mki(m_arith_fid,OP_GT,n,args); - case Plus: return mki(m_arith_fid,OP_ADD,n,args); - case Sub: return mki(m_arith_fid,OP_SUB,n,args); - case Uminus: return mki(m_arith_fid,OP_UMINUS,n,args); - case Times: return mki(m_arith_fid,OP_MUL,n,args); - case Div: return mki(m_arith_fid,OP_DIV,n,args); - case Idiv: return mki(m_arith_fid,OP_IDIV,n,args); - case Rem: return mki(m_arith_fid,OP_REM,n,args); - case Mod: return mki(m_arith_fid,OP_MOD,n,args); - case Power: return mki(m_arith_fid,OP_POWER,n,args); - case ToReal: return mki(m_arith_fid,OP_TO_REAL,n,args); - case ToInt: return mki(m_arith_fid,OP_TO_INT,n,args); - case IsInt: return mki(m_arith_fid,OP_IS_INT,n,args); - case Store: return mki(m_array_fid,OP_STORE,n,args); - case Select: return mki(m_array_fid,OP_SELECT,n,args); - case ConstArray: return mki(m_array_fid,OP_CONST_ARRAY,n,args); - case ArrayDefault: return mki(m_array_fid,OP_ARRAY_DEFAULT,n,args); - case ArrayMap: return mki(m_array_fid,OP_ARRAY_MAP,n,args); - case SetUnion: return mki(m_array_fid,OP_SET_UNION,n,args); - case SetIntersect: return mki(m_array_fid,OP_SET_INTERSECT,n,args); - case SetDifference: return mki(m_array_fid,OP_SET_DIFFERENCE,n,args); - case SetComplement: return mki(m_array_fid,OP_SET_COMPLEMENT,n,args); - case SetSubSet: return mki(m_array_fid,OP_SET_SUBSET,n,args); - case AsArray: return mki(m_array_fid,OP_AS_ARRAY,n,args); - default: - assert(0); - return expr(*this); - } - } - - expr context::mki(family_id fid, ::decl_kind dk, int n, ::expr **args){ - return cook(m().mk_app(fid, dk, 0, nullptr, n, (::expr **)args)); - } - - expr context::make(decl_kind op, const std::vector &args){ - static std::vector< ::expr*> a(10); - if(a.size() < args.size()) - a.resize(args.size()); - for(unsigned i = 0; i < args.size(); i++) - a[i] = to_expr(args[i].raw()); - return make(op,args.size(), args.size() ? VEC2PTR(a) : nullptr); - } - - expr context::make(decl_kind op){ - return make(op,0,nullptr); - } - - expr context::make(decl_kind op, const expr &arg0){ - ::expr *a = to_expr(arg0.raw()); - return make(op,1,&a); - } - - expr context::make(decl_kind op, const expr &arg0, const expr &arg1){ - ::expr *args[2]; - args[0] = to_expr(arg0.raw()); - args[1] = to_expr(arg1.raw()); - return make(op,2,args); - } - - expr context::make(decl_kind op, const expr &arg0, const expr &arg1, const expr &arg2){ - ::expr *args[3]; - args[0] = to_expr(arg0.raw()); - args[1] = to_expr(arg1.raw()); - args[2] = to_expr(arg2.raw()); - return make(op,3,args); - } - - expr context::make_quant(decl_kind op, const std::vector &bvs, const expr &body){ - if(bvs.size() == 0) return body; - std::vector< ::expr *> foo(bvs.size()); - - - std::vector< ::symbol> names; - std::vector< ::sort *> types; - std::vector< ::expr *> bound_asts; - unsigned num_bound = bvs.size(); - - for (unsigned i = 0; i < num_bound; ++i) { - app* a = to_app(bvs[i].raw()); - ::symbol s(to_app(a)->get_decl()->get_name()); - names.push_back(s); - types.push_back(m().get_sort(a)); - bound_asts.push_back(a); - } - expr_ref abs_body(m()); - expr_abstract(m(), 0, num_bound, VEC2PTR(bound_asts), to_expr(body.raw()), abs_body); - expr_ref result(m()); - result = m().mk_quantifier( - op == Forall, - names.size(), VEC2PTR(types), VEC2PTR(names), abs_body.get(), - 0, - ::symbol(), - ::symbol(), - 0, nullptr, - 0, nullptr - ); - return cook(result.get()); - } - - expr context::make_quant(decl_kind op, const std::vector &_sorts, const std::vector &_names, const expr &body){ - if(_sorts.size() == 0) return body; - - - std::vector< ::symbol> names; - std::vector< ::sort *> types; - std::vector< ::expr *> bound_asts; - unsigned num_bound = _sorts.size(); - - for (unsigned i = 0; i < num_bound; ++i) { - names.push_back(_names[i]); - types.push_back(to_sort(_sorts[i].raw())); - } - expr_ref result(m()); - result = m().mk_quantifier( - op == Forall, - names.size(), VEC2PTR(types), VEC2PTR(names), to_expr(body.raw()), - 0, - ::symbol(), - ::symbol(), - 0, nullptr, - 0, nullptr - ); - return cook(result.get()); - } - - - decl_kind func_decl::get_decl_kind() const { - return ctx().get_decl_kind(*this); - } - - decl_kind context::get_decl_kind(const func_decl &t){ - ::func_decl *d = to_func_decl(t.raw()); - if (null_family_id == d->get_family_id()) - return Uninterpreted; - // return (opr)d->get_decl_kind(); - if (m_basic_fid == d->get_family_id()) { - switch(d->get_decl_kind()) { - case OP_TRUE: return True; - case OP_FALSE: return False; - case OP_EQ: return Equal; - case OP_DISTINCT: return Distinct; - case OP_ITE: return Ite; - case OP_AND: return And; - case OP_OR: return Or; - case OP_IFF: return Iff; - case OP_XOR: return Xor; - case OP_NOT: return Not; - case OP_IMPLIES: return Implies; - case OP_OEQ: return Oeq; - case OP_INTERP: return Interp; - default: - return OtherBasic; - } - } - if (m_arith_fid == d->get_family_id()) { - switch(d->get_decl_kind()) { - case OP_LE: return Leq; - case OP_GE: return Geq; - case OP_LT: return Lt; - case OP_GT: return Gt; - case OP_ADD: return Plus; - case OP_SUB: return Sub; - case OP_UMINUS: return Uminus; - case OP_MUL: return Times; - case OP_DIV: return Div; - case OP_IDIV: return Idiv; - case OP_REM: return Rem; - case OP_MOD: return Mod; - case OP_POWER: return Power; - case OP_TO_REAL: return ToReal; - case OP_TO_INT: return ToInt; - case OP_IS_INT: return IsInt; - default: - return OtherArith; - } - } - if (m_array_fid == d->get_family_id()) { - switch(d->get_decl_kind()) { - case OP_STORE: return Store; - case OP_SELECT: return Select; - case OP_CONST_ARRAY: return ConstArray; - case OP_ARRAY_DEFAULT: return ArrayDefault; - case OP_ARRAY_MAP: return ArrayMap; - case OP_SET_UNION: return SetUnion; - case OP_SET_INTERSECT: return SetIntersect; - case OP_SET_DIFFERENCE: return SetDifference; - case OP_SET_COMPLEMENT: return SetComplement; - case OP_SET_SUBSET: return SetSubSet; - case OP_AS_ARRAY: return AsArray; - default: - return OtherArray; - } - } - - return Other; - } - - - sort_kind context::get_sort_kind(const sort &s){ - family_id fid = to_sort(s.raw())->get_family_id(); - ::decl_kind k = to_sort(s.raw())->get_decl_kind(); - if (m().is_uninterp(to_sort(s.raw()))) { - return UninterpretedSort; - } - else if (fid == m_basic_fid && k == BOOL_SORT) { - return BoolSort; - } - else if (fid == m_arith_fid && k == INT_SORT) { - return IntSort; - } - else if (fid == m_arith_fid && k == REAL_SORT) { - return RealSort; - } - else if (fid == m_array_fid && k == ARRAY_SORT) { - return ArraySort; - } - else { - return UnknownSort; - } - } - - expr func_decl::operator()(unsigned n, expr const * args) const { - std::vector< ::expr *> _args(n); - for(unsigned i = 0; i < n; i++) - _args[i] = to_expr(args[i].raw()); - return ctx().cook(m().mk_app(to_func_decl(raw()),n,VEC2PTR(_args))); - } - - int solver::get_num_decisions(){ - ::statistics st; - m_solver->collect_statistics(st); - std::ostringstream ss; - st.display(ss); - std::string stats = ss.str(); - int pos = stats.find("decisions:"); - if(pos < 0) return 0; // for some reason, decisions are not reported if there are none - pos += 10; - int end = stats.find('\n',pos); - std::string val = stats.substr(pos,end-pos); - return atoi(val.c_str()); - } - - void context::print_expr(std::ostream &s, const ast &e){ - s << mk_pp(e.raw(), m()); - } - - - expr expr::simplify(const params &_p) const { - ::expr * a = to_expr(raw()); - params_ref p = _p.get(); - th_rewriter m_rw(m(), p); - expr_ref result(m()); - m_rw(a, result); - return ctx().cook(result); - } - - expr expr::simplify() const { - params p; - return simplify(p); - } - - expr context::make_var(int idx, const sort &s){ - ::sort * a = to_sort(s.raw()); - return cook(m().mk_var(idx,a)); - } - - - expr expr::qe_lite() const { - ::qe_lite qe(m(), params_ref()); - expr_ref result(to_expr(raw()),m()); - proof_ref pf(m()); - qe(result,pf); - return ctx().cook(result); - } - - expr expr::qe_lite(const std::set &idxs, bool index_of_bound) const { - ::qe_lite qe(m(), params_ref()); - expr_ref result(to_expr(raw()),m()); - proof_ref pf(m()); - uint_set uis; - for(std::set::const_iterator it=idxs.begin(), en = idxs.end(); it != en; ++it) - uis.insert(*it); - qe(uis,index_of_bound,result); - return ctx().cook(result); - } - - expr clone_quantifier(const expr &q, const expr &b){ - return q.ctx().cook(q.m().update_quantifier(to_quantifier(q.raw()), to_expr(b.raw()))); - } - - expr clone_quantifier(const expr &q, const expr &b, const std::vector &patterns){ - quantifier *thing = to_quantifier(q.raw()); - bool is_forall = thing->is_forall(); - unsigned num_patterns = patterns.size(); - std::vector< ::expr *> _patterns(num_patterns); - for(unsigned i = 0; i < num_patterns; i++) - _patterns[i] = to_expr(patterns[i].raw()); - return q.ctx().cook(q.m().update_quantifier(thing, is_forall, num_patterns, VEC2PTR(_patterns), to_expr(b.raw()))); - } - - expr clone_quantifier(decl_kind dk, const expr &q, const expr &b){ - quantifier *thing = to_quantifier(q.raw()); - bool is_forall = dk == Forall; - return q.ctx().cook(q.m().update_quantifier(thing, is_forall, to_expr(b.raw()))); - } - - void expr::get_patterns(std::vector &pats) const { - quantifier *thing = to_quantifier(raw()); - unsigned num_patterns = thing->get_num_patterns(); - :: expr * const *it = thing->get_patterns(); - pats.resize(num_patterns); - for(unsigned i = 0; i < num_patterns; i++) - pats[i] = expr(ctx(),it[i]); - } - - - unsigned func_decl::arity() const { - return (to_func_decl(raw())->get_arity()); - } - - sort func_decl::domain(unsigned i) const { - return sort(ctx(),(to_func_decl(raw())->get_domain(i))); - } - - sort func_decl::range() const { - return sort(ctx(),(to_func_decl(raw())->get_range())); - } - - func_decl context::fresh_func_decl(char const * prefix, const std::vector &domain, sort const & range){ - std::vector < ::sort * > _domain(domain.size()); - for(unsigned i = 0; i < domain.size(); i++) - _domain[i] = to_sort(domain[i].raw()); - ::func_decl* d = m().mk_fresh_func_decl(prefix, - _domain.size(), - VEC2PTR(_domain), - to_sort(range.raw())); - return func_decl(*this,d); - } - - func_decl context::fresh_func_decl(char const * prefix, sort const & range){ - ::func_decl* d = m().mk_fresh_func_decl(prefix, - 0, - nullptr, - to_sort(range.raw())); - return func_decl(*this,d); - } - - - -#if 0 - - - lbool interpolating_solver::interpolate( - const std::vector &assumptions, - std::vector &interpolants, - model &model, - Z3_literals &labels, - bool incremental) - { - Z3_model _model = 0; - Z3_literals _labels = 0; - Z3_lbool lb; - std::vector _assumptions(assumptions.size()); - std::vector _interpolants(assumptions.size()-1); - for(unsigned i = 0; i < assumptions.size(); i++) - _assumptions[i] = assumptions[i]; - std::vector _theory(theory.size()); - for(unsigned i = 0; i < theory.size(); i++) - _theory[i] = theory[i]; - - lb = Z3_interpolate( - ctx(), - _assumptions.size(), - VEC2PTR(_assumptions), - 0, - 0, - VEC2PTR(_interpolants), - &_model, - &_labels, - incremental, - _theory.size(), - VEC2PTR(_theory)); - - if(lb == Z3_L_FALSE){ - interpolants.resize(_interpolants.size()); - for (unsigned i = 0; i < _interpolants.size(); ++i) { - interpolants[i] = expr(ctx(),_interpolants[i]); - } - } - - if (_model) { - model = iz3wrapper::model(ctx(), _model); - } - - if(_labels){ - labels = _labels; - } - - return lb; - } - -#endif - - static int linearize_assumptions(int num, - TermTree *assumptions, - std::vector > &linear_assumptions, - std::vector &parents){ - for(unsigned i = 0; i < assumptions->getChildren().size(); i++) - num = linearize_assumptions(num, assumptions->getChildren()[i], linear_assumptions, parents); - // linear_assumptions[num].push_back(assumptions->getTerm()); - for(unsigned i = 0; i < assumptions->getChildren().size(); i++) - parents[assumptions->getChildren()[i]->getNumber()] = num; - parents[num] = SHRT_MAX; // in case we have no parent - linear_assumptions[num].push_back(assumptions->getTerm()); - std::vector &ts = assumptions->getTerms(); - for(unsigned i = 0; i < ts.size(); i++) - linear_assumptions[num].push_back(ts[i]); - return num + 1; - } - - static int unlinearize_interpolants(int num, - TermTree* assumptions, - const std::vector &interpolant, - TermTree * &tree_interpolant) - { - std::vector chs(assumptions->getChildren().size()); - for(unsigned i = 0; i < assumptions->getChildren().size(); i++) - num = unlinearize_interpolants(num, assumptions->getChildren()[i], interpolant,chs[i]); - expr f; - if(num < (int)interpolant.size()) // last interpolant is missing, presumed false - f = interpolant[num]; - tree_interpolant = new TermTree(f,chs); - return num + 1; - } - - - lbool interpolating_solver::interpolate_tree(TermTree *assumptions, - TermTree *&interpolant, - model &model, - literals &labels, - bool incremental - ) - - { - int size = assumptions->number(0); - std::vector > linear_assumptions(size); - std::vector parents(size); - linearize_assumptions(0,assumptions,linear_assumptions,parents); - - ptr_vector< ::ast> _interpolants(size-1); - vector >_assumptions(size); - for(int i = 0; i < size; i++) - for(unsigned j = 0; j < linear_assumptions[i].size(); j++) - _assumptions[i].push_back(linear_assumptions[i][j]); - ::vector _parents; _parents.resize(parents.size()); - for(unsigned i = 0; i < parents.size(); i++) - _parents[i] = parents[i]; - ptr_vector< ::ast> _theory(theory.size()); - for(unsigned i = 0; i < theory.size(); i++) - _theory[i] = theory[i]; - - - if(!incremental){ - push(); - for(unsigned i = 0; i < linear_assumptions.size(); i++) - for(unsigned j = 0; j < linear_assumptions[i].size(); j++) - add(linear_assumptions[i][j]); - } - - check_result res = unsat; - - if(!m_solver->get_proof()) - res = check(); - - if(res == unsat){ - - interpolation_options_struct opts; - if(weak_mode) - opts.set("weak","1"); - - ::ast *proof = m_solver->get_proof(); - try { - iz3interpolate(m(),proof,_assumptions,_parents,_interpolants,_theory,&opts); - } - // If there's an interpolation bug, throw a char * - // exception so duality can catch it and restart. - catch (const interpolation_failure &f) { - throw f.msg(); - } - - std::vector linearized_interpolants(_interpolants.size()); - for(unsigned i = 0; i < _interpolants.size(); i++) - linearized_interpolants[i] = expr(ctx(),_interpolants[i]); - - // since iz3interpolant returns interpolants with one ref count, we decrement here - for(unsigned i = 0; i < _interpolants.size(); i++) - m().dec_ref(_interpolants[i]); - - unlinearize_interpolants(0,assumptions,linearized_interpolants,interpolant); - interpolant->setTerm(ctx().bool_val(false)); - } - - model_ref _m; - m_solver->get_model(_m); - model = Duality::model(ctx(),_m.get()); - -#if 0 - if(_labels){ - labels = _labels; - } -#endif - - if(!incremental) - pop(); - - return (res == unsat) ? l_false : ((res == sat) ? l_true : l_undef); - - } - - - void interpolating_solver::SetWeakInterpolants(bool weak){ - weak_mode = weak; - } - - - void interpolating_solver::SetPrintToFile(const std::string &filename){ - print_filename = filename; - } - - void interpolating_solver::AssertInterpolationAxiom(const expr & t){ - add(t); - theory.push_back(t); - } - - - void interpolating_solver::RemoveInterpolationAxiom(const expr & t){ - // theory.remove(t); - } - - - const char *interpolating_solver::profile(){ - // return Z3_interpolation_profile(ctx()); - return ""; - } - - - static void get_assumptions_rec(stl_ext::hash_set &memo, const proof &pf, std::vector &assumps){ - if(memo.find(pf) != memo.end())return; - memo.insert(pf); - pfrule dk = pf.rule(); - if(dk == PR_ASSERTED){ - expr con = pf.conc(); - assumps.push_back(con); - } - else { - unsigned nprems = pf.num_prems(); - for(unsigned i = 0; i < nprems; i++){ - proof arg = pf.prem(i); - get_assumptions_rec(memo,arg,assumps); - } - } - } - - void proof::get_assumptions(std::vector &assumps){ - stl_ext::hash_set memo; - get_assumptions_rec(memo,*this,assumps); - } - - - void ast::show() const{ - std::cout << mk_pp(raw(), m()) << std::endl; - } - - void model::show() const { - model_smt2_pp(std::cout, m(), *m_model, 0); - std::cout << std::endl; - } - - void model::show_hash() const { - std::ostringstream ss; - model_smt2_pp(ss, m(), *m_model, 0); - hash_space::hash hasher; - unsigned h = hasher(ss.str()); - std::cout << "model hash: " << h << "\n"; - } - - void solver::show() { - unsigned n = m_solver->get_num_assertions(); - if(!n) - return; - ast_smt_pp pp(m()); - for (unsigned i = 0; i < n-1; ++i) - pp.add_assumption(m_solver->get_assertion(i)); - pp.display_smt2(std::cout, m_solver->get_assertion(n-1)); - } - - void solver::print(const char *filename) { - std::ofstream f(filename); - unsigned n = m_solver->get_num_assertions(); - if(!n) - return; - ast_smt_pp pp(m()); - for (unsigned i = 0; i < n-1; ++i) - pp.add_assumption(m_solver->get_assertion(i)); - pp.display_smt2(f, m_solver->get_assertion(n-1)); - } - - - void solver::show_assertion_ids() { -#if 0 - unsigned n = m_solver->get_num_assertions(); - std::cerr << "assertion ids: "; - for (unsigned i = 0; i < n-1; ++i) - std::cerr << " " << m_solver->get_assertion(i)->get_id(); - std::cerr << "\n"; -#else - unsigned n = m_solver->get_num_assertions(); - std::cerr << "assertion ids hash: "; - unsigned h = 0; - for (unsigned i = 0; i < n-1; ++i) - h += m_solver->get_assertion(i)->get_id(); - std::cerr << h << "\n"; -#endif - } - - void include_ast_show(ast &a){ - a.show(); - } - - void include_model_show(model &a){ - a.show(); - } - - void show_ast(::ast *a, ast_manager &m) { - std::cout << mk_pp(a, m) << std::endl; - } - - bool expr::is_label (bool &pos,std::vector &names) const { - buffer< ::symbol> _names; - bool res = m().is_label(to_expr(raw()),pos,_names); - if(res) - for(unsigned i = 0; i < _names.size(); i++) - names.push_back(symbol(ctx(),_names[i])); - return res; - } - - double current_time() - { - static stopwatch sw; - static bool started = false; - if(!started){ - sw.start(); - started = true; - } - return sw.get_current_seconds(); - } - -} - - - - diff --git a/src/duality/duality_wrapper.h b/src/duality/duality_wrapper.h deleted file mode 100644 index 69f821a08..000000000 --- a/src/duality/duality_wrapper.h +++ /dev/null @@ -1,1489 +0,0 @@ -/*++ - Copyright (c) 2012 Microsoft Corporation - - Module Name: - - duality_wrapper.h - - Abstract: - - wrap various Z3 classes in the style expected by duality - - Author: - - Ken McMillan (kenmcmil) - - Revision History: - - - --*/ -#ifndef DUALITY_WRAPPER_H_ -#define DUALITY_WRAPPER_H_ - -#include -#include -#include -#include -#include -#include -#include -#include "util/version.h" -#include - -#include "interp/iz3hash.h" -#include "model/model.h" -#include "solver/solver.h" - -#include "ast/well_sorted.h" -#include "ast/arith_decl_plugin.h" -#include "ast/bv_decl_plugin.h" -#include "ast/datatype_decl_plugin.h" -#include "ast/array_decl_plugin.h" -#include "ast/ast_translation.h" -#include "ast/ast_pp.h" -#include "ast/ast_ll_pp.h" -#include "ast/ast_smt_pp.h" -#include "ast/ast_smt2_pp.h" -#include "ast/rewriter/th_rewriter.h" -#include "ast/rewriter/var_subst.h" -#include "ast/expr_substitution.h" -#include "ast/pp.h" -#include "util/scoped_ctrl_c.h" -#include "util/cancel_eh.h" -#include "util/scoped_timer.h" -#include "ast/scoped_proof.h" - -namespace Duality { - - class exception; - class config; - class context; - class symbol; - class params; - class ast; - class sort; - class func_decl; - class expr; - class solver; - class goal; - class tactic; - class probe; - class model; - class func_interp; - class func_entry; - class statistics; - class apply_result; - class fixedpoint; - class literals; - - /** - Duality global configuration object. - */ - - class config { - params_ref m_params; - config & operator=(config const & s); - public: - config(config const & s) : m_params(s.m_params) {} - config(const params_ref &_params) : m_params(_params) {} - config() { } // TODO: create a new params object here - ~config() { } - void set(char const * param, char const * value) { m_params.set_str(param,value); } - void set(char const * param, bool value) { m_params.set_bool(param,value); } - void set(char const * param, int value) { m_params.set_uint(param,value); } - params_ref &get() {return m_params;} - const params_ref &get() const {return m_params;} - }; - - enum decl_kind { - True, - False, - And, - Or, - Not, - Iff, - Ite, - Equal, - Implies, - Distinct, - Xor, - Oeq, - Interp, - Leq, - Geq, - Lt, - Gt, - Plus, - Sub, - Uminus, - Times, - Div, - Idiv, - Rem, - Mod, - Power, - ToReal, - ToInt, - IsInt, - Select, - Store, - ConstArray, - ArrayDefault, - ArrayMap, - SetUnion, - SetIntersect, - SetDifference, - SetComplement, - SetSubSet, - AsArray, - Numeral, - Forall, - Exists, - Variable, - Uninterpreted, - OtherBasic, - OtherArith, - OtherArray, - Other - }; - - enum sort_kind {BoolSort,IntSort,RealSort,ArraySort,UninterpretedSort,UnknownSort}; - - /** - A context has an ast manager global configuration options, etc. - */ - - class context { - protected: - ast_manager &mgr; - config m_config; - - family_id m_basic_fid; - family_id m_array_fid; - family_id m_arith_fid; - family_id m_bv_fid; - family_id m_dt_fid; - family_id m_datalog_fid; - arith_util m_arith_util; - - public: - context(ast_manager &_manager, const config &_config) : mgr(_manager), m_config(_config), m_arith_util(_manager) { - m_basic_fid = m().get_basic_family_id(); - m_arith_fid = m().mk_family_id("arith"); - m_bv_fid = m().mk_family_id("bv"); - m_array_fid = m().mk_family_id("array"); - m_dt_fid = m().mk_family_id("datatype"); - m_datalog_fid = m().mk_family_id("datalog_relation"); - } - ~context() { } - - ast_manager &m() const {return *(ast_manager *)&mgr;} - - void set(char const * param, char const * value) { m_config.set(param,value); } - void set(char const * param, bool value) { m_config.set(param,value); } - void set(char const * param, int value) { m_config.set(param,value); } - config &get_config() {return m_config;} - - symbol str_symbol(char const * s); - symbol int_symbol(int n); - - sort bool_sort(); - sort int_sort(); - sort real_sort(); - sort bv_sort(unsigned sz); - sort array_sort(const sort & d, const sort & r); - - func_decl function(symbol const & name, unsigned arity, sort const * domain, sort const & range); - func_decl function(char const * name, unsigned arity, sort const * domain, sort const & range); - func_decl function(char const * name, sort const & domain, sort const & range); - func_decl function(char const * name, sort const & d1, sort const & d2, sort const & range); - func_decl function(char const * name, sort const & d1, sort const & d2, sort const & d3, sort const & range); - func_decl function(char const * name, sort const & d1, sort const & d2, sort const & d3, sort const & d4, sort const & range); - func_decl function(char const * name, sort const & d1, sort const & d2, sort const & d3, sort const & d4, sort const & d5, sort const & range); - func_decl fresh_func_decl(char const * name, const std::vector &domain, sort const & range); - func_decl fresh_func_decl(char const * name, sort const & range); - - expr constant(symbol const & name, sort const & s); - expr constant(char const * name, sort const & s); - expr constant(const std::string &name, sort const & s); - expr bool_const(char const * name); - expr int_const(char const * name); - expr real_const(char const * name); - expr bv_const(char const * name, unsigned sz); - - expr bool_val(bool b); - - expr int_val(int n); - expr int_val(unsigned n); - expr int_val(char const * n); - - expr real_val(int n, int d); - expr real_val(int n); - expr real_val(unsigned n); - expr real_val(char const * n); - - expr bv_val(int n, unsigned sz); - expr bv_val(unsigned n, unsigned sz); - expr bv_val(char const * n, unsigned sz); - - expr num_val(int n, sort const & s); - - expr mki(family_id fid, ::decl_kind dk, int n, ::expr **args); - expr make(decl_kind op, int n, ::expr **args); - expr make(decl_kind op, const std::vector &args); - expr make(decl_kind op); - expr make(decl_kind op, const expr &arg0); - expr make(decl_kind op, const expr &arg0, const expr &arg1); - expr make(decl_kind op, const expr &arg0, const expr &arg1, const expr &arg2); - - expr make_quant(decl_kind op, const std::vector &bvs, const expr &body); - expr make_quant(decl_kind op, const std::vector &_sorts, const std::vector &_names, const expr &body); - expr make_var(int idx, const sort &s); - - decl_kind get_decl_kind(const func_decl &t); - - sort_kind get_sort_kind(const sort &s); - - expr translate(const expr &e); - func_decl translate(const func_decl &); - - void print_expr(std::ostream &s, const ast &e); - - fixedpoint mk_fixedpoint(); - - expr cook(::expr *a); - std::vector cook(ptr_vector< ::expr> v); - ::expr *uncook(const expr &a); - }; - - template - class z3array { - T * m_array; - unsigned m_size; - z3array(z3array const & s); - z3array & operator=(z3array const & s); - public: - z3array(unsigned sz):m_size(sz) { m_array = new T[sz]; } - ~z3array() { delete[] m_array; } - unsigned size() const { return m_size; } - T & operator[](unsigned i) { assert(i < m_size); return m_array[i]; } - T const & operator[](unsigned i) const { assert(i < m_size); return m_array[i]; } - T const * ptr() const { return m_array; } - T * ptr() { return m_array; } - }; - - class object { - protected: - context * m_ctx; - public: - object(): m_ctx((context *)nullptr) {} - object(context & c):m_ctx(&c) {} - object(object const & s):m_ctx(s.m_ctx) {} - context & ctx() const { return *m_ctx; } - friend void check_context(object const & a, object const & b) { assert(a.m_ctx == b.m_ctx); } - ast_manager &m() const {return m_ctx->m();} - }; - - class symbol : public object { - ::symbol m_sym; - public: - symbol(context & c, ::symbol s):object(c), m_sym(s) {} - symbol(symbol const & s):object(s), m_sym(s.m_sym) {} - symbol & operator=(symbol const & s) { m_ctx = s.m_ctx; m_sym = s.m_sym; return *this; } - operator ::symbol() const {return m_sym;} - std::string str() const { - if (m_sym.is_numerical()) { - std::ostringstream buffer; - buffer << m_sym.get_num(); - return buffer.str(); - } - else { - return m_sym.bare_str(); - } - } - friend std::ostream & operator<<(std::ostream & out, symbol const & s) { - return out << s.str(); - } - friend bool operator==(const symbol &x, const symbol &y) { - return x.m_sym == y.m_sym; - } - }; - - class params : public config {}; - - /** Wrapper around an ast pointer */ - class ast_i : public object { - protected: - ::ast *_ast; - public: - ::ast * const &raw() const {return _ast;} - ast_i(context & c, ::ast *a = nullptr) : object(c) {_ast = a;} - - ast_i(){_ast = nullptr;} - bool eq(const ast_i &other) const { - return _ast == other._ast; - } - bool lt(const ast_i &other) const { - return _ast < other._ast; - } - friend bool operator==(const ast_i &x, const ast_i&y){ - return x.eq(y); - } - friend bool operator!=(const ast_i &x, const ast_i&y){ - return !x.eq(y); - } - friend bool operator<(const ast_i &x, const ast_i&y){ - return x.lt(y); - } - size_t hash() const {return (size_t)_ast;} - bool null() const {return !_ast;} - }; - - /** Reference counting verison of above */ - class ast : public ast_i { - public: - operator ::ast*() const { return raw(); } - friend bool eq(ast const & a, ast const & b) { return a.raw() == b.raw(); } - - - ast(context &c, ::ast *a = nullptr) : ast_i(c,a) { - if(_ast) - m().inc_ref(a); - } - - ast() {} - - ast(const ast &other) : ast_i(other) { - if(_ast) - m().inc_ref(_ast); - } - - ast &operator=(const ast &other) { - if(_ast) - m().dec_ref(_ast); - _ast = other._ast; - m_ctx = other.m_ctx; - if(_ast) - m().inc_ref(_ast); - return *this; - } - - ~ast(){ - if(_ast) - m().dec_ref(_ast); - } - - void show() const; - - }; - - class sort : public ast { - public: - sort(context & c):ast(c) {} - sort(context & c, ::sort *s):ast(c, s) {} - sort(sort const & s):ast(s) {} - operator ::sort*() const { return to_sort(raw()); } - sort & operator=(sort const & s) { return static_cast(ast::operator=(s)); } - - bool is_bool() const { return m().is_bool(*this); } - bool is_int() const { return ctx().get_sort_kind(*this) == IntSort; } - bool is_real() const { return ctx().get_sort_kind(*this) == RealSort; } - bool is_arith() const; - bool is_array() const { return ctx().get_sort_kind(*this) == ArraySort; } - bool is_datatype() const; - bool is_relation() const; - bool is_finite_domain() const; - - - sort array_domain() const; - sort array_range() const; - - friend std::ostream & operator<<(std::ostream & out, sort const & m){ - m.ctx().print_expr(out,m); - return out; - } - }; - - - class func_decl : public ast { - public: - func_decl() : ast() {} - func_decl(context & c):ast(c) {} - func_decl(context & c, ::func_decl *n):ast(c, n) {} - func_decl(func_decl const & s):ast(s) {} - operator ::func_decl*() const { return to_func_decl(*this); } - func_decl & operator=(func_decl const & s) { return static_cast(ast::operator=(s)); } - - unsigned arity() const; - sort domain(unsigned i) const; - sort range() const; - symbol name() const {return symbol(ctx(),to_func_decl(raw())->get_name());} - decl_kind get_decl_kind() const; - - bool is_const() const { return arity() == 0; } - - expr operator()(unsigned n, expr const * args) const; - expr operator()(const std::vector &args) const; - expr operator()() const; - expr operator()(expr const & a) const; - expr operator()(int a) const; - expr operator()(expr const & a1, expr const & a2) const; - expr operator()(expr const & a1, int a2) const; - expr operator()(int a1, expr const & a2) const; - expr operator()(expr const & a1, expr const & a2, expr const & a3) const; - expr operator()(expr const & a1, expr const & a2, expr const & a3, expr const & a4) const; - expr operator()(expr const & a1, expr const & a2, expr const & a3, expr const & a4, expr const & a5) const; - - func_decl get_func_decl_parameter(unsigned idx){ - return func_decl(ctx(),to_func_decl(to_func_decl(raw())->get_parameters()[idx].get_ast())); - } - - }; - - class expr : public ast { - public: - expr() : ast() {} - expr(context & c):ast(c) {} - expr(context & c, ::ast *n):ast(c, n) {} - expr(expr const & n):ast(n) {} - expr & operator=(expr const & n) { return static_cast(ast::operator=(n)); } - operator ::expr*() const { return to_expr(raw()); } - unsigned get_id() const {return to_expr(raw())->get_id();} - - sort get_sort() const { return sort(ctx(),m().get_sort(to_expr(raw()))); } - - bool is_bool() const { return get_sort().is_bool(); } - bool is_int() const { return get_sort().is_int(); } - bool is_real() const { return get_sort().is_real(); } - bool is_arith() const { return get_sort().is_arith(); } - bool is_array() const { return get_sort().is_array(); } - bool is_datatype() const { return get_sort().is_datatype(); } - bool is_relation() const { return get_sort().is_relation(); } - bool is_finite_domain() const { return get_sort().is_finite_domain(); } - bool is_true() const {return is_app() && decl().get_decl_kind() == True; } - - bool is_numeral() const { - return is_app() && decl().get_decl_kind() == OtherArith && m().is_unique_value(to_expr(raw())); - } - bool is_app() const {return raw()->get_kind() == AST_APP;} - bool is_quantifier() const {return raw()->get_kind() == AST_QUANTIFIER;} - bool is_var() const {return raw()->get_kind() == AST_VAR;} - bool is_label (bool &pos,std::vector &names) const ; - bool is_ground() const {return to_app(raw())->is_ground();} - bool has_quantifiers() const {return to_app(raw())->has_quantifiers();} - bool has_free(int idx) const { - used_vars proc; - proc.process(to_expr(raw())); - return proc.contains(idx); - } - unsigned get_max_var_idx_plus_1() const { - used_vars proc; - proc.process(to_expr(raw())); - return proc.get_max_found_var_idx_plus_1(); - } - - // operator Z3_app() const { assert(is_app()); return reinterpret_cast(m_ast); } - func_decl decl() const {return func_decl(ctx(),to_app(raw())->get_decl());} - unsigned num_args() const { - ast_kind dk = raw()->get_kind(); - switch(dk){ - case AST_APP: - return to_app(raw())->get_num_args(); - case AST_QUANTIFIER: - return 1; - case AST_VAR: - return 0; - default:; - } - SASSERT(0); - return 0; - } - expr arg(unsigned i) const { - ast_kind dk = raw()->get_kind(); - switch(dk){ - case AST_APP: - return ctx().cook(to_app(raw())->get_arg(i)); - case AST_QUANTIFIER: - return ctx().cook(to_quantifier(raw())->get_expr()); - default:; - } - assert(0); - return expr(); - } - - expr body() const { - return ctx().cook(to_quantifier(raw())->get_expr()); - } - - friend expr operator!(expr const & a) { - // ::expr *e = a; - return expr(a.ctx(),a.m().mk_app(a.m().get_basic_family_id(),OP_NOT,a)); - } - - friend expr operator&&(expr const & a, expr const & b) { - return expr(a.ctx(),a.m().mk_app(a.m().get_basic_family_id(),OP_AND,a,b)); - } - - friend expr operator||(expr const & a, expr const & b) { - return expr(a.ctx(),a.m().mk_app(a.m().get_basic_family_id(),OP_OR,a,b)); - } - - friend expr implies(expr const & a, expr const & b) { - return expr(a.ctx(),a.m().mk_app(a.m().get_basic_family_id(),OP_IMPLIES,a,b)); - } - - friend expr operator==(expr const & a, expr const & b) { - return expr(a.ctx(),a.m().mk_app(a.m().get_basic_family_id(),OP_EQ,a,b)); - } - - friend expr operator!=(expr const & a, expr const & b) { - return expr(a.ctx(),a.m().mk_app(a.m().get_basic_family_id(),OP_DISTINCT,a,b)); - } - - friend expr operator+(expr const & a, expr const & b) { - return a.ctx().make(Plus,a,b); // expr(a.ctx(),a.m().mk_app(a.m().get_basic_family_id(),OP_ADD,a,b)); - } - - friend expr operator*(expr const & a, expr const & b) { - return a.ctx().make(Times,a,b); // expr(a.ctx(),a.m().mk_app(a.m().get_basic_family_id(),OP_MUL,a,b)); - } - - friend expr operator/(expr const & a, expr const & b) { - return a.ctx().make(Div,a,b); // expr(a.ctx(),a.m().mk_app(a.m().get_basic_family_id(),OP_DIV,a,b)); - } - - friend expr operator-(expr const & a) { - return a.ctx().make(Uminus,a); // expr(a.ctx(),a.m().mk_app(a.m().get_basic_family_id(),OP_UMINUS,a)); - } - - friend expr operator-(expr const & a, expr const & b) { - return a.ctx().make(Sub,a,b); // expr(a.ctx(),a.m().mk_app(a.ctx().m_arith_fid,OP_SUB,a,b)); - } - - friend expr operator<=(expr const & a, expr const & b) { - return a.ctx().make(Leq,a,b); // expr(a.ctx(),a.m().mk_app(a.m().get_basic_family_id(),OP_LE,a,b)); - } - - friend expr operator>=(expr const & a, expr const & b) { - return a.ctx().make(Geq,a,b); //expr(a.ctx(),a.m().mk_app(a.m().get_basic_family_id(),OP_GE,a,b)); - } - - friend expr operator<(expr const & a, expr const & b) { - return a.ctx().make(Lt,a,b); expr(a.ctx(),a.m().mk_app(a.m().get_basic_family_id(),OP_LT,a,b)); - } - - friend expr operator>(expr const & a, expr const & b) { - return a.ctx().make(Gt,a,b); expr(a.ctx(),a.m().mk_app(a.m().get_basic_family_id(),OP_GT,a,b)); - } - - expr simplify() const; - - expr simplify(params const & p) const; - - expr qe_lite() const; - - expr qe_lite(const std::set &idxs, bool index_of_bound) const; - - friend expr clone_quantifier(const expr &, const expr &); - - friend expr clone_quantifier(const expr &q, const expr &b, const std::vector &patterns); - - friend expr clone_quantifier(decl_kind, const expr &, const expr &); - - friend std::ostream & operator<<(std::ostream & out, expr const & m){ - m.ctx().print_expr(out,m); - return out; - } - - void get_patterns(std::vector &pats) const ; - - unsigned get_quantifier_num_bound() const { - return to_quantifier(raw())->get_num_decls(); - } - - unsigned get_index_value() const { - var* va = to_var(raw()); - return va->get_idx(); - } - - bool is_quantifier_forall() const { - return to_quantifier(raw())->is_forall(); - } - - sort get_quantifier_bound_sort(unsigned n) const { - return sort(ctx(),to_quantifier(raw())->get_decl_sort(n)); - } - - symbol get_quantifier_bound_name(unsigned n) const { - return symbol(ctx(),to_quantifier(raw())->get_decl_names()[n]); - } - - friend expr forall(const std::vector &quants, const expr &body); - - friend expr exists(const std::vector &quants, const expr &body); - - }; - - - typedef ::decl_kind pfrule; - - class proof : public ast { - public: - proof(context & c):ast(c) {} - proof(context & c, ::proof *s):ast(c, s) {} - proof(proof const & s):ast(s) {} - operator ::proof*() const { return to_app(raw()); } - proof & operator=(proof const & s) { return static_cast(ast::operator=(s)); } - - pfrule rule() const { - ::func_decl *d = to_app(raw())->get_decl(); - return d->get_decl_kind(); - } - - unsigned num_prems() const { - return to_app(raw())->get_num_args() - 1; - } - - expr conc() const { - return ctx().cook(to_app(raw())->get_arg(num_prems())); - } - - proof prem(unsigned i) const { - return proof(ctx(),to_app(to_app(raw())->get_arg(i))); - } - - void get_assumptions(std::vector &assumps); - }; - -#if 0 - -#if Z3_MAJOR_VERSION > 4 || Z3_MAJOR_VERSION == 4 && Z3_MINOR_VERSION >= 3 - template - class ast_vector_tpl : public object { - Z3_ast_vector m_vector; - void init(Z3_ast_vector v) { Z3_ast_vector_inc_ref(ctx(), v); m_vector = v; } - public: - ast_vector_tpl(context & c):object(c) { init(Z3_mk_ast_vector(c)); } - ast_vector_tpl(context & c, Z3_ast_vector v):object(c) { init(v); } - ast_vector_tpl(ast_vector_tpl const & s):object(s), m_vector(s.m_vector) { Z3_ast_vector_inc_ref(ctx(), m_vector); } - ~ast_vector_tpl() { /* Z3_ast_vector_dec_ref(ctx(), m_vector); */ } - operator Z3_ast_vector() const { return m_vector; } - unsigned size() const { return Z3_ast_vector_size(ctx(), m_vector); } - T operator[](unsigned i) const { Z3_ast r = Z3_ast_vector_get(ctx(), m_vector, i); check_error(); return cast_ast()(ctx(), r); } - void push_back(T const & e) { Z3_ast_vector_push(ctx(), m_vector, e); check_error(); } - void resize(unsigned sz) { Z3_ast_vector_resize(ctx(), m_vector, sz); check_error(); } - T back() const { return operator[](size() - 1); } - void pop_back() { assert(size() > 0); resize(size() - 1); } - bool empty() const { return size() == 0; } - ast_vector_tpl & operator=(ast_vector_tpl const & s) { - Z3_ast_vector_inc_ref(s.ctx(), s.m_vector); - // Z3_ast_vector_dec_ref(ctx(), m_vector); - m_ctx = s.m_ctx; - m_vector = s.m_vector; - return *this; - } - friend std::ostream & operator<<(std::ostream & out, ast_vector_tpl const & v) { out << Z3_ast_vector_to_string(v.ctx(), v); return out; } - }; - - typedef ast_vector_tpl ast_vector; - typedef ast_vector_tpl expr_vector; - typedef ast_vector_tpl sort_vector; - typedef ast_vector_tpl func_decl_vector; - -#endif - -#endif - - class func_interp : public object { - ::func_interp * m_interp; - void init(::func_interp * e) { - m_interp = e; - } - public: - func_interp(context & c, ::func_interp * e):object(c) { init(e); } - func_interp(func_interp const & s):object(s) { init(s.m_interp); } - ~func_interp() { } - operator ::func_interp *() const { return m_interp; } - func_interp & operator=(func_interp const & s) { - m_ctx = s.m_ctx; - m_interp = s.m_interp; - return *this; - } - unsigned num_entries() const { return m_interp->num_entries(); } - expr get_arg(unsigned ent, unsigned arg) const { - return expr(ctx(),m_interp->get_entry(ent)->get_arg(arg)); - } - expr get_value(unsigned ent) const { - return expr(ctx(),m_interp->get_entry(ent)->get_result()); - } - expr else_value() const { - return expr(ctx(),m_interp->get_else()); - } - }; - - - - class model : public object { - model_ref m_model; - void init(::model *m) { - m_model = m; - } - public: - model(context & c, ::model * m = nullptr):object(c), m_model(m) { } - model(model const & s):object(s), m_model(s.m_model) { } - ~model() { } - operator ::model *() const { return m_model.get(); } - model & operator=(model const & s) { - // ::model *_inc_ref(s.ctx(), s.m_model); - // ::model *_dec_ref(ctx(), m_model); - m_ctx = s.m_ctx; - m_model = s.m_model.get(); - return *this; - } - model & operator=(::model *s) { - m_model = s; - return *this; - } - bool null() const {return !m_model;} - - expr eval(expr const & n, bool model_completion=true) const { - ::model * _m = m_model.get(); - expr_ref result(ctx().m()); - _m->eval(n, result, model_completion); - return expr(ctx(), result); - } - - void show() const; - void show_hash() const; - - unsigned num_consts() const {return m_model.get()->get_num_constants();} - unsigned num_funcs() const {return m_model.get()->get_num_functions();} - func_decl get_const_decl(unsigned i) const {return func_decl(ctx(),m_model.get()->get_constant(i));} - func_decl get_func_decl(unsigned i) const {return func_decl(ctx(),m_model.get()->get_function(i));} - unsigned size() const; - func_decl operator[](unsigned i) const; - - expr get_const_interp(const func_decl & f) const { - return ctx().cook(m_model->get_const_interp(to_func_decl(f.raw()))); - } - - func_interp get_func_interp(const func_decl & f) const { - return func_interp(ctx(),m_model->get_func_interp(to_func_decl(f.raw()))); - } - -#if 0 - friend std::ostream & operator<<(std::ostream & out, model const & m) { out << Z3_model_to_string(m.ctx(), m); return out; } -#endif - }; - -#if 0 - class stats : public object { - Z3_stats m_stats; - void init(Z3_stats e) { - m_stats = e; - Z3_stats_inc_ref(ctx(), m_stats); - } - public: - stats(context & c):object(c), m_stats(0) {} - stats(context & c, Z3_stats e):object(c) { init(e); } - stats(stats const & s):object(s) { init(s.m_stats); } - ~stats() { if (m_stats) Z3_stats_dec_ref(ctx(), m_stats); } - operator Z3_stats() const { return m_stats; } - stats & operator=(stats const & s) { - Z3_stats_inc_ref(s.ctx(), s.m_stats); - if (m_stats) Z3_stats_dec_ref(ctx(), m_stats); - m_ctx = s.m_ctx; - m_stats = s.m_stats; - return *this; - } - unsigned size() const { return Z3_stats_size(ctx(), m_stats); } - std::string key(unsigned i) const { Z3_string s = Z3_stats_get_key(ctx(), m_stats, i); check_error(); return s; } - bool is_uint(unsigned i) const { Z3_bool r = Z3_stats_is_uint(ctx(), m_stats, i); check_error(); return r != 0; } - bool is_double(unsigned i) const { Z3_bool r = Z3_stats_is_double(ctx(), m_stats, i); check_error(); return r != 0; } - unsigned uint_value(unsigned i) const { unsigned r = Z3_stats_get_uint_value(ctx(), m_stats, i); check_error(); return r; } - double double_value(unsigned i) const { double r = Z3_stats_get_double_value(ctx(), m_stats, i); check_error(); return r; } - friend std::ostream & operator<<(std::ostream & out, stats const & s) { out << Z3_stats_to_string(s.ctx(), s); return out; } - }; -#endif - - enum check_result { - unsat, sat, unknown - }; - - class fixedpoint : public object { - - public: - void get_rules(std::vector &rules); - void get_assertions(std::vector &rules); - void register_relation(const func_decl &rela); - void add_rule(const expr &clause, const symbol &name); - void assert_cnst(const expr &cnst); - }; - - inline std::ostream & operator<<(std::ostream & out, check_result r) { - if (r == unsat) out << "unsat"; - else if (r == sat) out << "sat"; - else out << "unknown"; - return out; - } - - inline check_result to_check_result(lbool l) { - if (l == l_true) return sat; - else if (l == l_false) return unsat; - return unknown; - } - - class solver : public object { - protected: - ::solver *m_solver; - model the_model; - bool canceled; - proof_gen_mode m_mode; - bool extensional; - public: - solver(context & c, bool extensional = false, bool models = true); - solver(context & c, ::solver *s):object(c),the_model(c) { m_solver = s; canceled = false;} - solver(solver const & s):object(s), the_model(s.the_model) { m_solver = s.m_solver; canceled = false;} - ~solver() { - if(m_solver) - dealloc(m_solver); - } - operator ::solver*() const { return m_solver; } - solver & operator=(solver const & s) { - m_ctx = s.m_ctx; - m_solver = s.m_solver; - the_model = s.the_model; - m_mode = s.m_mode; - return *this; - } - struct cancel_exception {}; - void checkpoint(){ - if(canceled) - throw(cancel_exception()); - } - // void set(params const & p) { Z3_solver_set_params(ctx(), m_solver, p); check_error(); } - void push() { scoped_proof_mode spm(m(),m_mode); m_solver->push(); } - void pop(unsigned n = 1) { scoped_proof_mode spm(m(),m_mode); m_solver->pop(n); } - // void reset() { Z3_solver_reset(ctx(), m_solver); check_error(); } - void add(expr const & e) { scoped_proof_mode spm(m(),m_mode); m_solver->assert_expr(e); } - check_result check() { - scoped_proof_mode spm(m(),m_mode); - checkpoint(); - lbool r = m_solver->check_sat(0,nullptr); - model_ref m; - m_solver->get_model(m); - the_model = m.get(); - return to_check_result(r); - } - check_result check_keep_model(unsigned n, expr * const assumptions, unsigned *core_size = nullptr, expr *core = nullptr) { - scoped_proof_mode spm(m(),m_mode); - model old_model(the_model); - check_result res = check(n,assumptions,core_size,core); - if(the_model == nullptr) - the_model = old_model; - return res; - } - check_result check(unsigned n, expr * const assumptions, unsigned *core_size = nullptr, expr *core = nullptr) { - scoped_proof_mode spm(m(),m_mode); - checkpoint(); - std::vector< ::expr *> _assumptions(n); - for (unsigned i = 0; i < n; i++) { - _assumptions[i] = to_expr(assumptions[i]); - } - the_model = nullptr; - lbool r = m_solver->check_sat(n, VEC2PTR(_assumptions)); - - if(core_size && core){ - ptr_vector< ::expr> _core; - m_solver->get_unsat_core(_core); - *core_size = _core.size(); - for(unsigned i = 0; i < *core_size; i++) - core[i] = expr(ctx(),_core[i]); - } - - model_ref m; - m_solver->get_model(m); - the_model = m.get(); - - return to_check_result(r); - } -#if 0 - check_result check(expr_vector assumptions) { - scoped_proof_mode spm(m(),m_mode); - unsigned n = assumptions.size(); - z3array _assumptions(n); - for (unsigned i = 0; i < n; i++) { - check_context(*this, assumptions[i]); - _assumptions[i] = assumptions[i]; - } - Z3_lbool r = Z3_check_assumptions(ctx(), m_solver, n, _assumptions.ptr()); - check_error(); - return to_check_result(r); - } -#endif - model get_model() const { return model(ctx(), the_model); } - // std::string reason_unknown() const { Z3_string r = Z3_solver_get_reason_unknown(ctx(), m_solver); check_error(); return r; } - // stats statistics() const { Z3_stats r = Z3_solver_get_statistics(ctx(), m_solver); check_error(); return stats(ctx(), r); } -#if 0 - expr_vector unsat_core() const { Z3_ast_vector r = Z3_solver_get_unsat_core(ctx(), m_solver); check_error(); return expr_vector(ctx(), r); } - expr_vector assertions() const { Z3_ast_vector r = Z3_solver_get_assertions(ctx(), m_solver); check_error(); return expr_vector(ctx(), r); } -#endif - // expr proof() const { Z3_ast r = Z3_solver_proof(ctx(), m_solver); check_error(); return expr(ctx(), r); } - // friend std::ostream & operator<<(std::ostream & out, solver const & s) { out << Z3_solver_to_string(s.ctx(), s); return out; } - int get_num_decisions(); - - void cancel(){ - scoped_proof_mode spm(m(),m_mode); - canceled = true; - m().limit().cancel(); - } - - unsigned get_scope_level(){ scoped_proof_mode spm(m(),m_mode); return m_solver->get_scope_level();} - - void show(); - void print(const char *filename); - void show_assertion_ids(); - - proof get_proof(){ - scoped_proof_mode spm(m(),m_mode); - return proof(ctx(),m_solver->get_proof()); - } - - bool extensional_array_theory() {return extensional;} - }; - -#if 0 - class goal : public object { - Z3_goal m_goal; - void init(Z3_goal s) { - m_goal = s; - Z3_goal_inc_ref(ctx(), s); - } - public: - goal(context & c, bool models=true, bool unsat_cores=false, bool proofs=false):object(c) { init(Z3_mk_goal(c, models, unsat_cores, proofs)); } - goal(context & c, Z3_goal s):object(c) { init(s); } - goal(goal const & s):object(s) { init(s.m_goal); } - ~goal() { Z3_goal_dec_ref(ctx(), m_goal); } - operator Z3_goal() const { return m_goal; } - goal & operator=(goal const & s) { - Z3_goal_inc_ref(s.ctx(), s.m_goal); - Z3_goal_dec_ref(ctx(), m_goal); - m_ctx = s.m_ctx; - m_goal = s.m_goal; - return *this; - } - void add(expr const & f) { check_context(*this, f); Z3_goal_assert(ctx(), m_goal, f); check_error(); } - unsigned size() const { return Z3_goal_size(ctx(), m_goal); } - expr operator[](unsigned i) const { Z3_ast r = Z3_goal_formula(ctx(), m_goal, i); check_error(); return expr(ctx(), r); } - Z3_goal_prec precision() const { return Z3_goal_precision(ctx(), m_goal); } - bool inconsistent() const { return Z3_goal_inconsistent(ctx(), m_goal) != 0; } - unsigned depth() const { return Z3_goal_depth(ctx(), m_goal); } - void reset() { Z3_goal_reset(ctx(), m_goal); } - unsigned num_exprs() const { Z3_goal_num_exprs(ctx(), m_goal); } - bool is_decided_sat() const { return Z3_goal_is_decided_sat(ctx(), m_goal) != 0; } - bool is_decided_unsat() const { return Z3_goal_is_decided_unsat(ctx(), m_goal) != 0; } - friend std::ostream & operator<<(std::ostream & out, goal const & g) { out << Z3_goal_to_string(g.ctx(), g); return out; } - }; - - class apply_result : public object { - Z3_apply_result m_apply_result; - void init(Z3_apply_result s) { - m_apply_result = s; - Z3_apply_result_inc_ref(ctx(), s); - } - public: - apply_result(context & c, Z3_apply_result s):object(c) { init(s); } - apply_result(apply_result const & s):object(s) { init(s.m_apply_result); } - ~apply_result() { Z3_apply_result_dec_ref(ctx(), m_apply_result); } - operator Z3_apply_result() const { return m_apply_result; } - apply_result & operator=(apply_result const & s) { - Z3_apply_result_inc_ref(s.ctx(), s.m_apply_result); - Z3_apply_result_dec_ref(ctx(), m_apply_result); - m_ctx = s.m_ctx; - m_apply_result = s.m_apply_result; - return *this; - } - unsigned size() const { return Z3_apply_result_get_num_subgoals(ctx(), m_apply_result); } - goal operator[](unsigned i) const { Z3_goal r = Z3_apply_result_get_subgoal(ctx(), m_apply_result, i); check_error(); return goal(ctx(), r); } - goal operator[](int i) const { assert(i >= 0); return this->operator[](static_cast(i)); } - model convert_model(model const & m, unsigned i = 0) const { - check_context(*this, m); - Z3_model new_m = Z3_apply_result_convert_model(ctx(), m_apply_result, i, m); - check_error(); - return model(ctx(), new_m); - } - friend std::ostream & operator<<(std::ostream & out, apply_result const & r) { out << Z3_apply_result_to_string(r.ctx(), r); return out; } - }; - - class tactic : public object { - Z3_tactic m_tactic; - void init(Z3_tactic s) { - m_tactic = s; - Z3_tactic_inc_ref(ctx(), s); - } - public: - tactic(context & c, char const * name):object(c) { Z3_tactic r = Z3_mk_tactic(c, name); check_error(); init(r); } - tactic(context & c, Z3_tactic s):object(c) { init(s); } - tactic(tactic const & s):object(s) { init(s.m_tactic); } - ~tactic() { Z3_tactic_dec_ref(ctx(), m_tactic); } - operator Z3_tactic() const { return m_tactic; } - tactic & operator=(tactic const & s) { - Z3_tactic_inc_ref(s.ctx(), s.m_tactic); - Z3_tactic_dec_ref(ctx(), m_tactic); - m_ctx = s.m_ctx; - m_tactic = s.m_tactic; - return *this; - } - solver mk_solver() const { Z3_solver r = Z3_mk_solver_from_tactic(ctx(), m_tactic); check_error(); return solver(ctx(), r); } - apply_result apply(goal const & g) const { - check_context(*this, g); - Z3_apply_result r = Z3_tactic_apply(ctx(), m_tactic, g); - check_error(); - return apply_result(ctx(), r); - } - apply_result operator()(goal const & g) const { - return apply(g); - } - std::string help() const { char const * r = Z3_tactic_get_help(ctx(), m_tactic); check_error(); return r; } - friend tactic operator&(tactic const & t1, tactic const & t2) { - check_context(t1, t2); - Z3_tactic r = Z3_tactic_and_then(t1.ctx(), t1, t2); - t1.check_error(); - return tactic(t1.ctx(), r); - } - friend tactic operator|(tactic const & t1, tactic const & t2) { - check_context(t1, t2); - Z3_tactic r = Z3_tactic_or_else(t1.ctx(), t1, t2); - t1.check_error(); - return tactic(t1.ctx(), r); - } - friend tactic repeat(tactic const & t, unsigned max=UINT_MAX) { - Z3_tactic r = Z3_tactic_repeat(t.ctx(), t, max); - t.check_error(); - return tactic(t.ctx(), r); - } - friend tactic with(tactic const & t, params const & p) { - Z3_tactic r = Z3_tactic_using_params(t.ctx(), t, p); - t.check_error(); - return tactic(t.ctx(), r); - } - friend tactic try_for(tactic const & t, unsigned ms) { - Z3_tactic r = Z3_tactic_try_for(t.ctx(), t, ms); - t.check_error(); - return tactic(t.ctx(), r); - } - }; - - class probe : public object { - Z3_probe m_probe; - void init(Z3_probe s) { - m_probe = s; - Z3_probe_inc_ref(ctx(), s); - } - public: - probe(context & c, char const * name):object(c) { Z3_probe r = Z3_mk_probe(c, name); check_error(); init(r); } - probe(context & c, double val):object(c) { Z3_probe r = Z3_probe_const(c, val); check_error(); init(r); } - probe(context & c, Z3_probe s):object(c) { init(s); } - probe(probe const & s):object(s) { init(s.m_probe); } - ~probe() { Z3_probe_dec_ref(ctx(), m_probe); } - operator Z3_probe() const { return m_probe; } - probe & operator=(probe const & s) { - Z3_probe_inc_ref(s.ctx(), s.m_probe); - Z3_probe_dec_ref(ctx(), m_probe); - m_ctx = s.m_ctx; - m_probe = s.m_probe; - return *this; - } - double apply(goal const & g) const { double r = Z3_probe_apply(ctx(), m_probe, g); check_error(); return r; } - double operator()(goal const & g) const { return apply(g); } - friend probe operator<=(probe const & p1, probe const & p2) { - check_context(p1, p2); Z3_probe r = Z3_probe_le(p1.ctx(), p1, p2); p1.check_error(); return probe(p1.ctx(), r); - } - friend probe operator<=(probe const & p1, double p2) { return p1 <= probe(p1.ctx(), p2); } - friend probe operator<=(double p1, probe const & p2) { return probe(p2.ctx(), p1) <= p2; } - friend probe operator>=(probe const & p1, probe const & p2) { - check_context(p1, p2); Z3_probe r = Z3_probe_ge(p1.ctx(), p1, p2); p1.check_error(); return probe(p1.ctx(), r); - } - friend probe operator>=(probe const & p1, double p2) { return p1 >= probe(p1.ctx(), p2); } - friend probe operator>=(double p1, probe const & p2) { return probe(p2.ctx(), p1) >= p2; } - friend probe operator<(probe const & p1, probe const & p2) { - check_context(p1, p2); Z3_probe r = Z3_probe_lt(p1.ctx(), p1, p2); p1.check_error(); return probe(p1.ctx(), r); - } - friend probe operator<(probe const & p1, double p2) { return p1 < probe(p1.ctx(), p2); } - friend probe operator<(double p1, probe const & p2) { return probe(p2.ctx(), p1) < p2; } - friend probe operator>(probe const & p1, probe const & p2) { - check_context(p1, p2); Z3_probe r = Z3_probe_gt(p1.ctx(), p1, p2); p1.check_error(); return probe(p1.ctx(), r); - } - friend probe operator>(probe const & p1, double p2) { return p1 > probe(p1.ctx(), p2); } - friend probe operator>(double p1, probe const & p2) { return probe(p2.ctx(), p1) > p2; } - friend probe operator==(probe const & p1, probe const & p2) { - check_context(p1, p2); Z3_probe r = Z3_probe_eq(p1.ctx(), p1, p2); p1.check_error(); return probe(p1.ctx(), r); - } - friend probe operator==(probe const & p1, double p2) { return p1 == probe(p1.ctx(), p2); } - friend probe operator==(double p1, probe const & p2) { return probe(p2.ctx(), p1) == p2; } - friend probe operator&&(probe const & p1, probe const & p2) { - check_context(p1, p2); Z3_probe r = Z3_probe_and(p1.ctx(), p1, p2); p1.check_error(); return probe(p1.ctx(), r); - } - friend probe operator||(probe const & p1, probe const & p2) { - check_context(p1, p2); Z3_probe r = Z3_probe_or(p1.ctx(), p1, p2); p1.check_error(); return probe(p1.ctx(), r); - } - friend probe operator!(probe const & p) { - Z3_probe r = Z3_probe_not(p.ctx(), p); p.check_error(); return probe(p.ctx(), r); - } - }; - - inline tactic fail_if(probe const & p) { - Z3_tactic r = Z3_tactic_fail_if(p.ctx(), p); - p.check_error(); - return tactic(p.ctx(), r); - } - inline tactic when(probe const & p, tactic const & t) { - check_context(p, t); - Z3_tactic r = Z3_tactic_when(t.ctx(), p, t); - t.check_error(); - return tactic(t.ctx(), r); - } - inline tactic cond(probe const & p, tactic const & t1, tactic const & t2) { - check_context(p, t1); check_context(p, t2); - Z3_tactic r = Z3_tactic_cond(t1.ctx(), p, t1, t2); - t1.check_error(); - return tactic(t1.ctx(), r); - } - -#endif - - inline expr context::bool_val(bool b){return b ? make(True) : make(False);} - - inline symbol context::str_symbol(char const * s) { ::symbol r = ::symbol(s); return symbol(*this, r); } - inline symbol context::int_symbol(int n) { ::symbol r = ::symbol(n); return symbol(*this, r); } - - inline sort context::bool_sort() { - ::sort *s = m().mk_sort(m_basic_fid, BOOL_SORT); - return sort(*this, s); - } - inline sort context::int_sort() { - ::sort *s = m().mk_sort(m_arith_fid, INT_SORT); - return sort(*this, s); - } - inline sort context::real_sort() { - ::sort *s = m().mk_sort(m_arith_fid, REAL_SORT); - return sort(*this, s); - } - inline sort context::array_sort(const sort & d, const sort & r) { - parameter params[2] = { parameter(d), parameter(to_sort(r)) }; - ::sort * s = m().mk_sort(m_array_fid, ARRAY_SORT, 2, params); - return sort(*this, s); - } - - - inline func_decl context::function(symbol const & name, unsigned arity, sort const * domain, sort const & range) { - std::vector< ::sort *> sv(arity); - for(unsigned i = 0; i < arity; i++) - sv[i] = domain[i]; - ::func_decl* d = m().mk_func_decl(name,arity, VEC2PTR(sv),range); - return func_decl(*this,d); - } - - inline func_decl context::function(char const * name, unsigned arity, sort const * domain, sort const & range) { - return function(str_symbol(name), arity, domain, range); - } - - inline func_decl context::function(char const * name, sort const & domain, sort const & range) { - sort args[1] = { domain }; - return function(name, 1, args, range); - } - - inline func_decl context::function(char const * name, sort const & d1, sort const & d2, sort const & range) { - sort args[2] = { d1, d2 }; - return function(name, 2, args, range); - } - - inline func_decl context::function(char const * name, sort const & d1, sort const & d2, sort const & d3, sort const & range) { - sort args[3] = { d1, d2, d3 }; - return function(name, 3, args, range); - } - - inline func_decl context::function(char const * name, sort const & d1, sort const & d2, sort const & d3, sort const & d4, sort const & range) { - sort args[4] = { d1, d2, d3, d4 }; - return function(name, 4, args, range); - } - - inline func_decl context::function(char const * name, sort const & d1, sort const & d2, sort const & d3, sort const & d4, sort const & d5, sort const & range) { - sort args[5] = { d1, d2, d3, d4, d5 }; - return function(name, 5, args, range); - } - - - inline expr context::constant(symbol const & name, sort const & s) { - ::expr *r = m().mk_const(m().mk_const_decl(name, s)); - return expr(*this, r); - } - inline expr context::constant(char const * name, sort const & s) { return constant(str_symbol(name), s); } - inline expr context::bool_const(char const * name) { return constant(name, bool_sort()); } - inline expr context::int_const(char const * name) { return constant(name, int_sort()); } - inline expr context::real_const(char const * name) { return constant(name, real_sort()); } - inline expr context::bv_const(char const * name, unsigned sz) { return constant(name, bv_sort(sz)); } - - inline expr func_decl::operator()(const std::vector &args) const { - return operator()(args.size(), VEC2PTR(args)); - } - inline expr func_decl::operator()() const { - return operator()(0,nullptr); - } - inline expr func_decl::operator()(expr const & a) const { - return operator()(1,&a); - } - inline expr func_decl::operator()(expr const & a1, expr const & a2) const { - expr args[2] = {a1,a2}; - return operator()(2,args); - } - inline expr func_decl::operator()(expr const & a1, expr const & a2, expr const & a3) const { - expr args[3] = {a1,a2,a3}; - return operator()(3,args); - } - inline expr func_decl::operator()(expr const & a1, expr const & a2, expr const & a3, expr const & a4) const { - expr args[4] = {a1,a2,a3,a4}; - return operator()(4,args); - } - inline expr func_decl::operator()(expr const & a1, expr const & a2, expr const & a3, expr const & a4, expr const & a5) const { - expr args[5] = {a1,a2,a3,a4,a5}; - return operator()(5,args); - } - - - inline expr select(expr const & a, expr const & i) { return a.ctx().make(Select,a,i); } - inline expr store(expr const & a, expr const & i, expr const & v) { return a.ctx().make(Store,a,i,v); } - - inline expr forall(const std::vector &quants, const expr &body){ - return body.ctx().make_quant(Forall,quants,body); - } - - inline expr exists(const std::vector &quants, const expr &body){ - return body.ctx().make_quant(Exists,quants,body); - } - - inline expr context::int_val(int n){ - :: sort *r = m().mk_sort(m_arith_fid, INT_SORT); - return cook(m_arith_util.mk_numeral(rational(n),r)); - } - - - class literals : public object { - }; - - class TermTree { - public: - - TermTree(const expr &_term){ - term = _term; - } - - TermTree(const expr &_term, const std::vector &_children){ - term = _term; - children = _children; - } - - inline expr getTerm(){return term;} - - inline std::vector &getTerms(){return terms;} - - inline std::vector &getChildren(){ - return children; - } - - inline int number(int from){ - for(unsigned i = 0; i < children.size(); i++) - from = children[i]->number(from); - num = from; - return from + 1; - } - - inline int getNumber(){ - return num; - } - - inline void setTerm(const expr &t){term = t;} - - inline void addTerm(const expr &t){terms.push_back(t);} - - inline void setChildren(const std::vector & _children){ - children = _children; - } - - inline void setNumber(int _num){ - num = _num; - } - - ~TermTree(){ - for(unsigned i = 0; i < children.size(); i++) - delete children[i]; - } - - private: - expr term; - std::vector terms; - std::vector children; - int num; - }; - - typedef context interpolating_context; - - class interpolating_solver : public solver { - public: - interpolating_solver(context &ctx, bool models = true) - : solver(ctx, true, models) - { - weak_mode = false; - } - - public: - lbool interpolate(const std::vector &assumptions, - std::vector &interpolants, - model &_model, - literals &lits, - bool incremental - ); - - lbool interpolate_tree(TermTree *assumptions, - TermTree *&interpolants, - model &_model, - literals &lits, - bool incremental - ); - - bool read_interpolation_problem(const std::string &file_name, - std::vector &assumptions, - std::vector &theory, - std::string &error_message - ); - - void write_interpolation_problem(const std::string &file_name, - const std::vector &assumptions, - const std::vector &theory - ); - - void AssertInterpolationAxiom(const expr &expr); - void RemoveInterpolationAxiom(const expr &expr); - - void SetWeakInterpolants(bool weak); - void SetPrintToFile(const std::string &file_name); - - const std::vector &GetInterpolationAxioms() {return theory;} - const char *profile(); - - private: - bool weak_mode; - std::string print_filename; - std::vector theory; - }; - - - inline expr context::cook(::expr *a) {return expr(*this,a);} - - inline std::vector context::cook(ptr_vector< ::expr> v) { - std::vector _v(v.size()); - for(unsigned i = 0; i < v.size(); i++) - _v[i] = cook(v[i]); - return _v; - } - - inline ::expr *context::uncook(const expr &a) { - m().inc_ref(a.raw()); - return to_expr(a.raw()); - } - - inline expr context::translate(const expr &e) { - ::expr *f = to_expr(e.raw()); - if(&e.ctx().m() != &m()) // same ast manager -> no translation - throw "ast manager mismatch"; - return cook(f); - } - - inline func_decl context::translate(const func_decl &e) { - ::func_decl *f = to_func_decl(e.raw()); - if(&e.ctx().m() != &m()) // same ast manager -> no translation - throw "ast manager mismatch"; - return func_decl(*this,f); - } - - typedef double clock_t; - clock_t current_time(); - inline void output_time(std::ostream &os, clock_t time){os << time;} - - template class uptr { - public: - X *ptr; - uptr(){ptr = nullptr;} - void set(X *_ptr){ - if(ptr) delete ptr; - ptr = _ptr; - } - X *get(){ return ptr;} - ~uptr(){ - if(ptr) delete ptr; - } - }; - -}; - -// to make Duality::ast hashable -namespace hash_space { - template <> - class hash { - public: - size_t operator()(const Duality::ast &s) const { - return s.raw()->get_id(); - } - }; -} - - -// to make Duality::ast usable in ordered collections -namespace std { - template <> - class less { - public: - bool operator()(const Duality::ast &s, const Duality::ast &t) const { - // return s.raw() < t.raw(); - return s.raw()->get_id() < t.raw()->get_id(); - } - }; -} - -// to make Duality::ast usable in ordered collections -namespace std { - template <> - class less { - public: - bool operator()(const Duality::expr &s, const Duality::expr &t) const { - // return s.raw() < t.raw(); - return s.raw()->get_id() < t.raw()->get_id(); - } - }; -} - -// to make Duality::func_decl hashable -namespace hash_space { - template <> - class hash { - public: - size_t operator()(const Duality::func_decl &s) const { - return s.raw()->get_id(); - } - }; -} - - -// to make Duality::func_decl usable in ordered collections -namespace std { - template <> - class less { - public: - bool operator()(const Duality::func_decl &s, const Duality::func_decl &t) const { - // return s.raw() < t.raw(); - return s.raw()->get_id() < t.raw()->get_id(); - } - }; -} - -#endif diff --git a/src/interp/CMakeLists.txt b/src/interp/CMakeLists.txt deleted file mode 100644 index c3d8e3d5e..000000000 --- a/src/interp/CMakeLists.txt +++ /dev/null @@ -1,18 +0,0 @@ -z3_add_component(interp - SOURCES - iz3base.cpp - iz3checker.cpp - iz3interp.cpp - iz3mgr.cpp - iz3pp.cpp - iz3profiling.cpp - iz3proof.cpp - iz3proof_itp.cpp - iz3scopes.cpp - iz3translate.cpp - iz3translate_direct.cpp - COMPONENT_DEPENDENCIES - solver - PYG_FILES - interp_params.pyg -) diff --git a/src/interp/interp_params.pyg b/src/interp/interp_params.pyg deleted file mode 100644 index 3116a18db..000000000 --- a/src/interp/interp_params.pyg +++ /dev/null @@ -1,6 +0,0 @@ -def_module_params('interp', - description='interpolation parameters', - export=True, - params=(('profile', BOOL, False, '(INTERP) profile interpolation'), - ('check', BOOL, False, '(INTERP) check interpolants'), - )) diff --git a/src/interp/iz3base.cpp b/src/interp/iz3base.cpp deleted file mode 100644 index 773f328ab..000000000 --- a/src/interp/iz3base.cpp +++ /dev/null @@ -1,372 +0,0 @@ -/*++ - Copyright (c) 2011 Microsoft Corporation - - Module Name: - - iz3base.cpp - - Abstract: - - Base class for interpolators. Includes an AST manager and a scoping - object as bases. - - Author: - - Ken McMillan (kenmcmil) - - Revision History: - - --*/ - -#ifdef _WINDOWS -#pragma warning(disable:4996) -#pragma warning(disable:4800) -#pragma warning(disable:4267) -#pragma warning(disable:4101) -#endif - -#include "interp/iz3base.h" -#include -#include -#include -#include -#include "solver/solver.h" -#include "../smt/smt_solver.h" - - -using namespace stl_ext; - - -iz3base::range &iz3base::ast_range(ast t){ - return ast_ranges_hash[t].rng; -} - -iz3base::range &iz3base::sym_range(symb d){ - return sym_range_hash[d]; -} - -void iz3base::add_frame_range(int frame, ast t){ - range &rng = ast_range(t); - if(!in_range(frame,rng)){ - range_add(frame,rng); - for(int i = 0, n = num_args(t); i < n; ++i) - add_frame_range(frame,arg(t,i)); - if(op(t) == Uninterpreted) - range_add(frame,sym_range(sym(t))); - } -} - -#if 1 -iz3base::range &iz3base::ast_scope(ast t){ - ranges &rngs = ast_ranges_hash[t]; - range &rng = rngs.scp; - if(!rngs.scope_computed){ // not computed yet - rng = range_full(); - for(int i = 0, n = num_args(t); i < n; ++i) - rng = range_glb(rng,ast_scope(arg(t,i))); - if(op(t) == Uninterpreted) - if(parents.empty() || num_args(t) == 0) // in tree mode, all function syms are global - rng = range_glb(rng,sym_range(sym(t))); - rngs.scope_computed = true; - } - return rng; -} -#else -iz3base::range &iz3base::ast_scope(ast t){ - ranges &rngs = ast_ranges_hash[t]; - if(rngs.scope_computed) return rngs.scp; - range rng = range_full(); - for(int i = 0, n = num_args(t); i < n; ++i) - rng = range_glb(rng,ast_scope(arg(t,i))); - if(op(t) == Uninterpreted) - if(parents.empty() || num_args(t) == 0) // in tree mode, all function syms are global - rng = range_glb(rng,sym_range(sym(t))); - rngs = ast_ranges_hash[t]; - rngs.scope_computed = true; - rngs.scp = rng; - return rngs.scp; -} -#endif - -void iz3base::print(const std::string &filename){ - ast t = make(And,cnsts); - std::ofstream f(filename.c_str()); - print_sat_problem(f,t); - f.close(); -} - - -void iz3base::gather_conjuncts_rec(ast n, std::vector &conjuncts, stl_ext::hash_set &memo){ - if(memo.find(n) == memo.end()){ - memo.insert(n); - if(op(n) == And){ - int nargs = num_args(n); - for(int i = 0; i < nargs; i++) - gather_conjuncts_rec(arg(n,i),conjuncts,memo); - } - else - conjuncts.push_back(n); - } -} - -void iz3base::gather_conjuncts(ast n, std::vector &conjuncts){ - hash_set memo; - gather_conjuncts_rec(n,conjuncts,memo); -} - -bool iz3base::is_literal(ast n){ - if(is_not(n))n = arg(n,0); - if(is_true(n) || is_false(n)) return false; - if(op(n) == And) return false; - return true; -} - -iz3base::ast iz3base::simplify_and(std::vector &conjuncts){ - hash_set memo; - for(unsigned i = 0; i < conjuncts.size(); i++){ - if(is_false(conjuncts[i])) - return conjuncts[i]; - if(is_true(conjuncts[i]) || memo.find(conjuncts[i]) != memo.end()){ - std::swap(conjuncts[i],conjuncts.back()); - conjuncts.pop_back(); - } - else if(memo.find(mk_not(conjuncts[i])) != memo.end()) - return mk_false(); // contradiction! - else - memo.insert(conjuncts[i]); - } - if(conjuncts.empty())return mk_true(); - return make(And,conjuncts); -} - -iz3base::ast iz3base::simplify_with_lit_rec(ast n, ast lit, stl_ext::hash_map &memo, int depth){ - if(is_not(n))return mk_not(simplify_with_lit_rec(mk_not(n),lit,memo,depth)); - if(n == lit) return mk_true(); - ast not_lit = mk_not(lit); - if(n == not_lit) return mk_false(); - if(op(n) != And || depth <= 0) return n; - std::pair foo(n,ast()); - std::pair::iterator,bool> bar = memo.insert(foo); - ast &res = bar.first->second; - if(!bar.second) return res; - int nargs = num_args(n); - std::vector args(nargs); - for(int i = 0; i < nargs; i++) - args[i] = simplify_with_lit_rec(arg(n,i),lit,memo,depth-1); - res = simplify_and(args); - return res; -} - -iz3base::ast iz3base::simplify_with_lit(ast n, ast lit){ - hash_map memo; - return simplify_with_lit_rec(n,lit,memo,1); -} - -iz3base::ast iz3base::simplify(ast n){ - if(is_not(n)) return mk_not(simplify(mk_not(n))); - std::pair memo_obj(n,ast()); - std::pair::iterator,bool> memo = simplify_memo.insert(memo_obj); - ast &res = memo.first->second; - if(!memo.second) return res; - switch(op(n)){ - case And: { - std::vector conjuncts; - gather_conjuncts(n,conjuncts); - for(unsigned i = 0; i < conjuncts.size(); i++) - conjuncts[i] = simplify(conjuncts[i]); -#if 0 - for(unsigned i = 0; i < conjuncts.size(); i++) - if(is_literal(conjuncts[i])) - for(unsigned j = 0; j < conjuncts.size(); j++) - if(j != i) - conjuncts[j] = simplify_with_lit(conjuncts[j],conjuncts[i]); -#endif - res = simplify_and(conjuncts); - } - break; - case Equal: { - ast x = arg(n,0); - ast y = arg(n,1); - if(ast_id(x) > ast_id(y)) - std::swap(x,y); - res = make(Equal,x,y); - break; - } - default: - res = n; - } - return res; -} - -void iz3base::initialize(const std::vector &_parts, const std::vector &_parents, const std::vector &_theory){ - cnsts = _parts; - theory = _theory; - for(unsigned i = 0; i < cnsts.size(); i++) - add_frame_range(i, cnsts[i]); - for(unsigned i = 0; i < _theory.size(); i++){ - add_frame_range(SHRT_MIN, _theory[i]); - add_frame_range(SHRT_MAX, _theory[i]); - } - for(unsigned i = 0; i < cnsts.size(); i++) - frame_map[cnsts[i]] = i; - for(unsigned i = 0; i < theory.size(); i++) - frame_map[theory[i]] = INT_MAX; -} - -void iz3base::initialize(const std::vector > &_parts, const std::vector &_parents, const std::vector &_theory){ - cnsts.resize(_parts.size()); - theory = _theory; - for(unsigned i = 0; i < _parts.size(); i++) - for(unsigned j = 0; j < _parts[i].size(); j++){ - cnsts[i] = make(And,_parts[i]); - add_frame_range(i, _parts[i][j]); - frame_map[_parts[i][j]] = i; - } - for(unsigned i = 0; i < _theory.size(); i++){ - add_frame_range(SHRT_MIN, _theory[i]); - add_frame_range(SHRT_MAX, _theory[i]); - frame_map[theory[i]] = INT_MAX; - } -} - -void iz3base::check_interp(const std::vector &itps, std::vector &theory){ -#if 0 - Z3_config config = Z3_mk_config(); - Z3_context vctx = Z3_mk_context(config); - int frames = cnsts.size(); - std::vector foocnsts(cnsts); - for(unsigned i = 0; i < frames; i++) - foocnsts[i] = Z3_mk_implies(ctx,Z3_mk_true(ctx),cnsts[i]); - Z3_write_interpolation_problem(ctx,frames,&foocnsts[0],0, "temp_lemma.smt", theory.size(), &theory[0]); - int vframes,*vparents; - Z3_ast *vcnsts; - const char *verror; - bool ok = Z3_read_interpolation_problem(vctx,&vframes,&vcnsts,0,"temp_lemma.smt",&verror); - assert(ok); - std::vector vvcnsts(vframes); - std::copy(vcnsts,vcnsts+vframes,vvcnsts.begin()); - std::vector vitps(itps.size()); - for(unsigned i = 0; i < itps.size(); i++) - vitps[i] = Z3_mk_implies(ctx,Z3_mk_true(ctx),itps[i]); - Z3_write_interpolation_problem(ctx,itps.size(),&vitps[0],0,"temp_interp.smt"); - int iframes,*iparents; - Z3_ast *icnsts; - const char *ierror; - ok = Z3_read_interpolation_problem(vctx,&iframes,&icnsts,0,"temp_interp.smt",&ierror); - assert(ok); - const char *error = 0; - bool iok = Z3_check_interpolant(vctx, frames, &vvcnsts[0], parents.size() ? &parents[0] : 0, icnsts, &error); - assert(iok); -#endif -} - -bool iz3base::is_sat(const std::vector &q, ast &_proof, std::vector &vars){ - - params_ref p; - p.set_bool("proof", true); // this is currently useless - p.set_bool("model", true); - p.set_bool("unsat_core", true); - scoped_ptr sf = mk_smt_solver_factory(); - scoped_ptr< ::solver > solver = (*sf)(m(), p, true, true, true, ::symbol::null); - ::solver &s = *solver.get(); - - for(unsigned i = 0; i < q.size(); i++) - s.assert_expr(to_expr(q[i].raw())); - lbool res = s.check_sat(0,nullptr); - if (m().canceled()) { - throw iz3_exception(Z3_CANCELED_MSG); - } - if(res == l_false){ - ::ast *proof = s.get_proof(); - _proof = cook(proof); - } - else if(vars.size()) { - model_ref _m; - s.get_model(_m); - if (!_m.get()) { - SASSERT(l_undef == res); - throw iz3_exception("interpolation cannot proceed without a model"); - } - for(unsigned i = 0; i < vars.size(); i++){ - expr_ref r(m()); - _m.get()->eval(to_expr(vars[i].raw()),r,true); - vars[i] = cook(r.get()); - } - } - solver = nullptr; - return res != l_false; -} - - -void iz3base::find_children(const stl_ext::hash_set &cnsts_set, - const ast &tree, - std::vector &cnsts, - std::vector &parents, - std::vector &conjuncts, - std::vector &children, - std::vector &pos_map, - bool merge - ){ - std::vector my_children; - std::vector my_conjuncts; - if(op(tree) == Interp){ // if we've hit an interpolation position... - find_children(cnsts_set,arg(tree,0),cnsts,parents,my_conjuncts,my_children,pos_map,merge); - if(my_conjuncts.empty()) - my_conjuncts.push_back(mk_true()); // need at least one conjunct - int root = cnsts.size() + my_conjuncts.size() - 1; - for(unsigned i = 0; i < my_conjuncts.size(); i++){ - parents.push_back(root); - cnsts.push_back(my_conjuncts[i]); - } - for(unsigned i = 0; i < my_children.size(); i++) - parents[my_children[i]] = root; - children.push_back(root); - pos_map.push_back(root); - } - else { - if(op(tree) == And){ - int nargs = num_args(tree); - for(int i = 0; i < nargs; i++) - find_children(cnsts_set,arg(tree,i),cnsts,parents,my_conjuncts,my_children,pos_map,merge); - } - if(cnsts_set.find(tree) != cnsts_set.end()){ - if(merge && !my_conjuncts.empty()) - my_conjuncts.back() = mk_and(my_conjuncts.back(),tree); - else - my_conjuncts.push_back(tree); - } - for(unsigned i = 0; i < my_children.size(); i++) - children.push_back(my_children[i]); - for(unsigned i = 0; i < my_conjuncts.size(); i++) - conjuncts.push_back(my_conjuncts[i]); - } -} - -void iz3base::to_parents_vec_representation(const std::vector &_cnsts, - const ast &tree, - std::vector &cnsts, - std::vector &parents, - std::vector &theory, - std::vector &pos_map, - bool merge - ){ - std::vector my_children; - std::vector my_conjuncts; - hash_set cnsts_set; - for(unsigned i = 0; i < _cnsts.size(); i++) - cnsts_set.insert(_cnsts[i]); - ast _tree = (op(tree) != Interp) ? make(Interp,tree) : tree; - find_children(cnsts_set,_tree,cnsts,parents,my_conjuncts,my_children,pos_map,merge); - if(op(tree) != Interp) pos_map.pop_back(); - parents[parents.size()-1] = SHRT_MAX; - - // rest of the constraints are the background theory - - hash_set used_set; - for(unsigned i = 0; i < cnsts.size(); i++) - used_set.insert(cnsts[i]); - for(unsigned i = 0; i < _cnsts.size(); i++) - if(used_set.find(_cnsts[i]) == used_set.end()) - theory.push_back(_cnsts[i]); -} - diff --git a/src/interp/iz3base.h b/src/interp/iz3base.h deleted file mode 100755 index 15f613730..000000000 --- a/src/interp/iz3base.h +++ /dev/null @@ -1,195 +0,0 @@ -/*++ - Copyright (c) 2011 Microsoft Corporation - - Module Name: - - iz3base.h - - Abstract: - - Base class for interpolators. Includes an AST manager and a scoping - object as bases. - - Author: - - Ken McMillan (kenmcmil) - - Revision History: - - --*/ - -#ifndef IZ3BASE_H -#define IZ3BASE_H - -#include "interp/iz3mgr.h" -#include "interp/iz3scopes.h" - -namespace hash_space { - template <> - class hash { - public: - size_t operator()(func_decl * const &s) const { - return (size_t) s; - } - }; -} - -/* Base class for interpolators. Includes an AST manager and a scoping - object as bases. */ - -class iz3base : public iz3mgr, public scopes { - - public: - - /** Get the range in which an expression occurs. This is the - smallest subtree containing all occurrences of the - expression. */ - range &ast_range(ast); - - /** Get the scope of an expression. This is the set of tree nodes in - which all of the expression's symbols are in scope. */ - range &ast_scope(ast); - - /** Get the range of a symbol. This is the smallest subtree containing - all occurrences of the symbol. */ - range &sym_range(symb); - - /** Is an expression local (in scope in some frame)? */ - - bool is_local(ast node){ - return !range_is_empty(ast_scope(node)); - } - - /** Simplify an expression */ - - ast simplify(ast); - - /** Constructor */ - - iz3base(ast_manager &_m_manager, - const std::vector &_cnsts, - const std::vector &_parents, - const std::vector &_theory) - : iz3mgr(_m_manager), scopes(_parents) { - initialize(_cnsts,_parents,_theory); - weak = false; - } - - iz3base(const iz3mgr& other, - const std::vector &_cnsts, - const std::vector &_parents, - const std::vector &_theory) - : iz3mgr(other), scopes(_parents) { - initialize(_cnsts,_parents,_theory); - weak = false; - } - - iz3base(const iz3mgr& other, - const std::vector > &_cnsts, - const std::vector &_parents, - const std::vector &_theory) - : iz3mgr(other), scopes(_parents) { - initialize(_cnsts,_parents,_theory); - weak = false; - } - - iz3base(const iz3mgr& other) - : iz3mgr(other), scopes() { - weak = false; - } - - /* Set our options */ - void set_option(const std::string &name, const std::string &value){ - if(name == "weak" && value == "1") weak = true; - } - - /* Are we doing weak interpolants? */ - bool weak_mode(){return weak;} - - /** Print interpolation problem to an SMTLIB format file */ - void print(const std::string &filename); - - /** Check correctness of a solutino to this problem. */ - void check_interp(const std::vector &itps, std::vector &theory); - - /** For convenience -- is this formula SAT? */ - bool is_sat(const std::vector &consts, ast &_proof, std::vector &vars); - - /** Interpolator for clauses, to be implemented */ - virtual void interpolate_clause(std::vector &lits, std::vector &itps){ - throw iz3_exception("no interpolator"); - } - - ast get_proof_check_assump(range &rng){ - std::vector cs(theory); - cs.push_back(cnsts[rng.hi]); - return make(And,cs); - } - - int frame_of_assertion(const ast &ass){ - stl_ext::hash_map::iterator it = frame_map.find(ass); - if(it == frame_map.end()) - throw iz3_exception("unknown assertion"); - return it->second; - } - - - void to_parents_vec_representation(const std::vector &_cnsts, - const ast &tree, - std::vector &cnsts, - std::vector &parents, - std::vector &theory, - std::vector &pos_map, - bool merge = false - ); - - protected: - std::vector cnsts; - std::vector theory; - - private: - - struct ranges { - range rng; - range scp; - bool scope_computed; - ranges(){scope_computed = false;} - }; - - stl_ext::hash_map sym_range_hash; - stl_ext::hash_map ast_ranges_hash; - stl_ext::hash_map simplify_memo; - stl_ext::hash_map frame_map; // map assertions to frames - - // int frames; // number of frames - - protected: - void add_frame_range(int frame, ast t); - - private: - void initialize(const std::vector &_parts, const std::vector &_parents, const std::vector &_theory); - - void initialize(const std::vector > &_parts, const std::vector &_parents, const std::vector &_theory); - - bool is_literal(ast n); - void gather_conjuncts_rec(ast n, std::vector &conjuncts, stl_ext::hash_set &memo); - void gather_conjuncts(ast n, std::vector &conjuncts); - ast simplify_and(std::vector &conjuncts); - ast simplify_with_lit_rec(ast n, ast lit, stl_ext::hash_map &memo, int depth); - ast simplify_with_lit(ast n, ast lit); - void find_children(const stl_ext::hash_set &cnsts_set, - const ast &tree, - std::vector &cnsts, - std::vector &parents, - std::vector &conjuncts, - std::vector &children, - std::vector &pos_map, - bool merge - ); - bool weak; - -}; - - - -#endif diff --git a/src/interp/iz3checker.cpp b/src/interp/iz3checker.cpp deleted file mode 100644 index 511342819..000000000 --- a/src/interp/iz3checker.cpp +++ /dev/null @@ -1,227 +0,0 @@ -/*++ - Copyright (c) 2011 Microsoft Corporation - - Module Name: - - iz3checker.cpp - - Abstract: - - check correctness of interpolant - - Author: - - Ken McMillan (kenmcmil) - - Revision History: - - --*/ - -#ifdef _WINDOWS -#pragma warning(disable:4996) -#pragma warning(disable:4800) -#pragma warning(disable:4267) -#pragma warning(disable:4101) -#endif - -#include "interp/iz3base.h" -#include "interp/iz3checker.h" - -#include -#include -#include -#include -#include -#include -#include - - -using namespace stl_ext; - -struct iz3checker : iz3base { - - /* HACK: for tree interpolants, we assume that uninterpreted functions - are global. This is because in the current state of the tree interpolation - code, symbols that appear in sibling sub-trees have to be global, and - we have no way to eliminate such function symbols. When tree interpolation is - fixed, we can tree function symbols the same as constant symbols. */ - - bool is_tree; - - void support(const ast &t, std::set &res, hash_set &memo){ - if(memo.find(t) != memo.end()) return; - memo.insert(t); - - int nargs = num_args(t); - for(int i = 0; i < nargs; i++) - support(arg(t,i),res,memo); - - switch(op(t)){ - case Uninterpreted: - if(nargs == 0 || !is_tree) { - std::string name = string_of_symbol(sym(t)); - res.insert(name); - } - break; - case Forall: - case Exists: - support(get_quantifier_body(t),res,memo); - break; - default:; - } - } - - bool check(solver *s, std::ostream &err, - const std::vector &cnsts, - const std::vector &parents, - const std::vector &itp, - const std::vector &theory){ - - is_tree = !parents.empty(); - int num = cnsts.size(); - std::vector > children(num); - - for(int i = 0; i < num-1; i++){ - if(parents.size()) - children[parents[i]].push_back(i); - else - children[i+1].push_back(i); - } - - for(int i = 0; i < num; i++){ - s->push(); - for(unsigned j = 0; j < theory.size(); j++) - s->assert_expr(to_expr(theory[j].raw())); - s->assert_expr(to_expr(cnsts[i].raw())); - std::vector &cs = children[i]; - for(unsigned j = 0; j < cs.size(); j++) - s->assert_expr(to_expr(itp[cs[j]].raw())); - if(i != num-1) - s->assert_expr(to_expr(mk_not(itp[i]).raw())); - lbool result = s->check_sat(0,nullptr); - if(result != l_false){ - err << "interpolant " << i << " is incorrect"; - - s->pop(1); - for(unsigned j = 0; j < theory.size(); j++) - s->assert_expr(to_expr(theory[j].raw())); - for(unsigned j = 0; j < cnsts.size(); j++) - if(in_range(j,range_downward(i))) - s->assert_expr(to_expr(cnsts[j].raw())); - if(i != num-1) - s->assert_expr(to_expr(mk_not(itp[i]).raw())); - lbool result = s->check_sat(0,nullptr); - if(result != l_false) - err << "interpolant " << i << " is not implied by its downeard closurn"; - - return false; - } - s->pop(1); - } - - std::vector > supports(num); - for(int i = 0; i < num; i++){ - hash_set memo; - support(cnsts[i],supports[i],memo); - } - for(int i = 0; i < num-1; i++){ - std::vector Bside(num); - for(int j = num-1; j >= 0; j--) - Bside[j] = j != i; - for(int j = num-1; j >= 0; j--) - if(!Bside[j]){ - std::vector &cs = children[i]; - for(unsigned k = 0; k < cs.size(); k++) - Bside[cs[k]] = false; - } - std::set Asup, Bsup,common,Isup,bad; - for(int j = num-1; j >= 0; j--){ - std::set &side = Bside[j] ? Bsup : Asup; - side.insert(supports[j].begin(),supports[j].end()); - } - std::set_intersection(Asup.begin(),Asup.end(),Bsup.begin(),Bsup.end(),std::inserter(common,common.begin())); - { - hash_set tmemo; - for(unsigned j = 0; j < theory.size(); j++) - support(theory[j],common,tmemo); // all theory symbols allowed in interps - } - hash_set memo; - support(itp[i],Isup,memo); - std::set_difference(Isup.begin(),Isup.end(),common.begin(),common.end(),std::inserter(bad,bad.begin())); - if(!bad.empty()){ - err << "bad symbols in interpolant " << i << ":"; - std::copy(bad.begin(),bad.end(),std::ostream_iterator(err,",")); - return false; - } - } - return true; - } - - bool check(solver *s, std::ostream &err, - const std::vector &_cnsts, - const ast &tree, - const std::vector &itp){ - - std::vector pos_map; - - // convert to the parents vector representation - - to_parents_vec_representation(_cnsts, tree, cnsts, parents, theory, pos_map); - - //use the parents vector representation to compute interpolant - return check(s,err,cnsts,parents,itp,theory); - } - - iz3checker(ast_manager &_m) - : iz3base(_m) { - } - - iz3checker(iz3mgr &_m) - : iz3base(_m) { - } - -}; - -template -std::vector to_std_vector(const ::vector &v){ - std::vector _v(v.size()); - for(unsigned i = 0; i < v.size(); i++) - _v[i] = v[i]; - return _v; -} - - -bool iz3check(ast_manager &_m_manager, - solver *s, - std::ostream &err, - const ptr_vector &cnsts, - const ::vector &parents, - const ptr_vector &interps, - const ptr_vector &theory) -{ - iz3checker chk(_m_manager); - return chk.check(s,err,chk.cook(cnsts),to_std_vector(parents),chk.cook(interps),chk.cook(theory)); -} - -bool iz3check(iz3mgr &mgr, - solver *s, - std::ostream &err, - const std::vector &cnsts, - const std::vector &parents, - const std::vector &interps, - const std::vector &theory) -{ - iz3checker chk(mgr); - return chk.check(s,err,cnsts,parents,interps,theory); -} - -bool iz3check(ast_manager &_m_manager, - solver *s, - std::ostream &err, - const ptr_vector &_cnsts, - ast *tree, - const ptr_vector &interps) -{ - iz3checker chk(_m_manager); - return chk.check(s,err,chk.cook(_cnsts),chk.cook(tree),chk.cook(interps)); -} diff --git a/src/interp/iz3checker.h b/src/interp/iz3checker.h deleted file mode 100644 index d89db3011..000000000 --- a/src/interp/iz3checker.h +++ /dev/null @@ -1,49 +0,0 @@ -/*++ - Copyright (c) 2011 Microsoft Corporation - - Module Name: - - iz3checker.h - - Abstract: - - check correctness of an interpolant - - Author: - - Ken McMillan (kenmcmil) - - Revision History: - - --*/ - -#ifndef IZ3_CHECKER_H -#define IZ3_CHECKER_H - -#include "interp/iz3mgr.h" -#include "solver/solver.h" - -bool iz3check(ast_manager &_m_manager, - solver *s, - std::ostream &err, - const ptr_vector &cnsts, - const ::vector &parents, - const ptr_vector &interps, - const ptr_vector &theory); - -bool iz3check(ast_manager &_m_manager, - solver *s, - std::ostream &err, - const ptr_vector &cnsts, - ast *tree, - const ptr_vector &interps); - -bool iz3check(iz3mgr &mgr, - solver *s, - std::ostream &err, - const std::vector &cnsts, - const std::vector &parents, - const std::vector &interps, - const ptr_vector &theory); - -#endif diff --git a/src/interp/iz3exception.h b/src/interp/iz3exception.h deleted file mode 100644 index b3f841565..000000000 --- a/src/interp/iz3exception.h +++ /dev/null @@ -1,28 +0,0 @@ -/*++ -Copyright (c) 2015 Microsoft Corporation - -Module Name: - - iz3exception.h - -Abstract: - - Base class for exceptions raised by interpolation routines - -Author: - -Notes: - ---*/ -#ifndef _IZ3EXCEPTION_H_ -#define _IZ3EXCEPTION_H_ - -#include "util/z3_exception.h" -#include "util/error_codes.h" - -class iz3_exception: public default_exception { -public: - iz3_exception(const std::string &msg): default_exception(msg) {} -}; - -#endif diff --git a/src/interp/iz3hash.h b/src/interp/iz3hash.h deleted file mode 100644 index f85242ed1..000000000 --- a/src/interp/iz3hash.h +++ /dev/null @@ -1,479 +0,0 @@ -/*++ - Copyright (c) 2011 Microsoft Corporation - - Module Name: - - iz3hash.h - - Abstract: - - Simple implementation of bucket-list hash tables conforming to SGI - hash_map and hash_set interfaces. Just enough members are - implemented to support iz3 and duality. - - iz3 and duality need this package because they assume that insert - preserves iterators and references to elements, which is not true - of the hashtable packages in util. - - This package lives in namespace hash_space. Specializations of - class "hash" should be made in this namespace. - - Author: - - Ken McMillan (kenmcmil) - - Revision History: - - --*/ - -#ifndef IZ3_HASH_H -#define IZ3_HASH_H - -#ifdef _WINDOWS -#pragma warning(disable:4267) -#endif - -#include -#include -#include -#include "util/hash.h" - -#define stl_ext hash_space - -namespace hash_space { - - template class hash {}; - - - template <> - class hash { - public: - size_t operator()(const int &s) const { - return s; - } - }; - - template <> - class hash { - public: - size_t operator()(const std::string &s) const { - return string_hash(s.c_str(), s.size(), 0); - } - }; - - template <> - class hash > { - public: - size_t operator()(const std::pair &p) const { - return p.first + p.second; - } - }; - - template - class hash > { - public: - size_t operator()(const std::pair &p) const { - return (size_t)p.first + (size_t)p.second; - } - }; - - enum { num_primes = 29 }; - - static const unsigned long primes[num_primes] = - { - 7ul, - 53ul, - 97ul, - 193ul, - 389ul, - 769ul, - 1543ul, - 3079ul, - 6151ul, - 12289ul, - 24593ul, - 49157ul, - 98317ul, - 196613ul, - 393241ul, - 786433ul, - 1572869ul, - 3145739ul, - 6291469ul, - 12582917ul, - 25165843ul, - 50331653ul, - 100663319ul, - 201326611ul, - 402653189ul, - 805306457ul, - 1610612741ul, - 3221225473ul, - 4294967291ul - }; - - inline unsigned long next_prime(unsigned long n) { - const unsigned long* to = primes + (int)num_primes; - for(const unsigned long* p = primes; p < to; p++) - if(*p >= n) return *p; - return primes[num_primes-1]; - } - - template - class hashtable - { - public: - - typedef Value &reference; - typedef const Value &const_reference; - - struct Entry - { - Entry* next; - Value val; - - Entry(const Value &_val) : val(_val) {next = nullptr;} - }; - - - struct iterator - { - Entry* ent; - hashtable* tab; - - typedef std::forward_iterator_tag iterator_category; - typedef Value value_type; - typedef std::ptrdiff_t difference_type; - typedef size_t size_type; - typedef Value& reference; - typedef Value* pointer; - - iterator(Entry* _ent, hashtable* _tab) : ent(_ent), tab(_tab) { } - - iterator() { } - - Value &operator*() const { return ent->val; } - - Value *operator->() const { return &(operator*()); } - - iterator &operator++() { - Entry *old = ent; - ent = ent->next; - if (!ent) { - size_t bucket = tab->get_bucket(old->val); - while (!ent && ++bucket < tab->buckets.size()) - ent = tab->buckets[bucket]; - } - return *this; - } - - iterator operator++(int) { - iterator tmp = *this; - operator++(); - return tmp; - } - - - bool operator==(const iterator& it) const { - return ent == it.ent; - } - - bool operator!=(const iterator& it) const { - return ent != it.ent; - } - }; - - struct const_iterator - { - const Entry* ent; - const hashtable* tab; - - typedef std::forward_iterator_tag iterator_category; - typedef Value value_type; - typedef std::ptrdiff_t difference_type; - typedef size_t size_type; - typedef const Value& reference; - typedef const Value* pointer; - - const_iterator(const Entry* _ent, const hashtable* _tab) : ent(_ent), tab(_tab) { } - - const_iterator() { } - - const Value &operator*() const { return ent->val; } - - const Value *operator->() const { return &(operator*()); } - - const_iterator &operator++() { - Entry *old = ent; - ent = ent->next; - if (!ent) { - size_t bucket = tab->get_bucket(old->val); - while (!ent && ++bucket < tab->buckets.size()) - ent = tab->buckets[bucket]; - } - return *this; - } - - const_iterator operator++(int) { - const_iterator tmp = *this; - operator++(); - return tmp; - } - - - bool operator==(const const_iterator& it) const { - return ent == it.ent; - } - - bool operator!=(const const_iterator& it) const { - return ent != it.ent; - } - }; - - private: - - typedef std::vector Table; - - Table buckets; - size_t entries; - HashFun hash_fun ; - GetKey get_key; - KeyEqFun key_eq_fun; - - public: - - hashtable(size_t init_size) : buckets(init_size,(Entry *)nullptr) { - entries = 0; - } - - hashtable(const hashtable& other) { - dup(other); - } - - hashtable& operator= (const hashtable& other) { - if (&other != this) - dup(other); - return *this; - } - - ~hashtable() { - clear(); - } - - size_t size() const { - return entries; - } - - bool empty() const { - return size() == 0; - } - - void swap(hashtable& other) { - buckets.swap(other.buckets); - std::swap(entries, other.entries); - } - - iterator begin() { - for (size_t i = 0; i < buckets.size(); ++i) - if (buckets[i]) - return iterator(buckets[i], this); - return end(); - } - - iterator end() { - return iterator(nullptr, this); - } - - const_iterator begin() const { - for (size_t i = 0; i < buckets.size(); ++i) - if (buckets[i]) - return const_iterator(buckets[i], this); - return end(); - } - - const_iterator end() const { - return const_iterator(nullptr, this); - } - - size_t get_bucket(const Value& val, size_t n) const { - return hash_fun(get_key(val)) % n; - } - - size_t get_key_bucket(const Key& key) const { - return hash_fun(key) % buckets.size(); - } - - size_t get_bucket(const Value& val) const { - return get_bucket(val,buckets.size()); - } - - Entry *lookup(const Value& val, bool ins = false) - { - resize(entries + 1); - - size_t n = get_bucket(val); - Entry* from = buckets[n]; - - for (Entry* ent = from; ent; ent = ent->next) - if (key_eq_fun(get_key(ent->val), get_key(val))) - return ent; - - if(!ins) return nullptr; - - Entry* tmp = new Entry(val); - tmp->next = from; - buckets[n] = tmp; - ++entries; - return tmp; - } - - Entry *lookup_key(const Key& key) const - { - size_t n = get_key_bucket(key); - Entry* from = buckets[n]; - - for (Entry* ent = from; ent; ent = ent->next) - if (key_eq_fun(get_key(ent->val), key)) - return ent; - - return nullptr; - } - - const_iterator find(const Key& key) const { - return const_iterator(lookup_key(key),this); - } - - iterator find(const Key& key) { - return iterator(lookup_key(key),this); - } - - std::pair insert(const Value& val){ - size_t old_entries = entries; - Entry *ent = lookup(val,true); - return std::pair(iterator(ent,this),entries > old_entries); - } - - iterator insert(const iterator &it, const Value& val){ - Entry *ent = lookup(val,true); - return iterator(ent,this); - } - - size_t erase(const Key& key) - { - Entry** p = &(buckets[get_key_bucket(key)]); - size_t count = 0; - while(*p){ - Entry *q = *p; - if (key_eq_fun(get_key(q->val), key)) { - ++count; - *p = q->next; - delete q; - } - else - p = &(q->next); - } - entries -= count; - return count; - } - - void resize(size_t new_size) { - const size_t old_n = buckets.size(); - if (new_size <= old_n) return; - const size_t n = next_prime(new_size); - if (n <= old_n) return; - Table tmp(n, (Entry*)nullptr); - for (size_t i = 0; i < old_n; ++i) { - Entry* ent = buckets[i]; - while (ent) { - size_t new_bucket = get_bucket(ent->val, n); - buckets[i] = ent->next; - ent->next = tmp[new_bucket]; - tmp[new_bucket] = ent; - ent = buckets[i]; - } - } - buckets.swap(tmp); - } - - void clear() - { - for (size_t i = 0; i < buckets.size(); ++i) { - for (Entry* ent = buckets[i]; ent != nullptr;) { - Entry* next = ent->next; - delete ent; - ent = next; - } - buckets[i] = nullptr; - } - entries = 0; - } - - void dup(const hashtable& other) - { - buckets.resize(other.buckets.size()); - for (size_t i = 0; i < other.buckets.size(); ++i) { - Entry** to = &buckets[i]; - for (Entry* from = other.buckets[i]; from; from = from->next) - to = &((*to = new Entry(from->val))->next); - } - entries = other.entries; - } - }; - - template - class equal { - public: - bool operator()(const T& x, const T &y) const { - return x == y; - } - }; - - template - class identity { - public: - const T &operator()(const T &x) const { - return x; - } - }; - - template - class proj1 { - public: - const T &operator()(const std::pair &x) const { - return x.first; - } - }; - - template , - class EqFun = equal > - class hash_set - : public hashtable,EqFun> { - - public: - - typedef Element value_type; - - hash_set() - : hashtable,EqFun>(7) {} - }; - - template , - class EqFun = equal > - class hash_map - : public hashtable,Key,HashFun,proj1,EqFun> { - - public: - - hash_map() - : hashtable,Key,HashFun,proj1,EqFun>(7) {} - - Value &operator[](const Key& key) { - std::pair kvp(key,Value()); - return - hashtable,Key,HashFun,proj1,EqFun>:: - lookup(kvp,true)->val.second; - } - }; - -} -#endif diff --git a/src/interp/iz3interp.cpp b/src/interp/iz3interp.cpp deleted file mode 100644 index 41c968bd8..000000000 --- a/src/interp/iz3interp.cpp +++ /dev/null @@ -1,578 +0,0 @@ -/*++ - Copyright (c) 2011 Microsoft Corporation - - Module Name: - - iz3interp.cpp - - Abstract: - - Interpolation based on proof translation. - - Author: - - Ken McMillan (kenmcmil) - - Revision History: - - --*/ - -/* Copyright 2011 Microsoft Research. */ - -#ifdef _WINDOWS -#pragma warning(disable:4996) -#pragma warning(disable:4800) -#pragma warning(disable:4267) -#pragma warning(disable:4101) -#endif - -#include -#include -#include -#include -#include -#include - -#include "interp/iz3profiling.h" -#include "interp/iz3translate.h" -#include "interp/iz3proof.h" -#include "interp/iz3hash.h" -#include "interp/iz3interp.h" - -#include "ast/scoped_proof.h" - - -using namespace stl_ext; - - - -#if 1 - -struct frame_reducer : public iz3mgr { - - int frames; - hash_map frame_map; - std::vector assertions_map; - std::vector orig_parents_copy; - std::vector used_frames; - - - frame_reducer(const iz3mgr &other) - : iz3mgr(other) {} - - void get_proof_assumptions_rec(z3pf proof, hash_set &memo, std::vector &used_frames){ - if(memo.find(proof) != memo.end())return; - memo.insert(proof); - pfrule dk = pr(proof); - if(dk == PR_ASSERTED){ - ast con = conc(proof); - if(frame_map.find(con) != frame_map.end()){ // false for theory facts - int frame = frame_map[con]; - used_frames[frame] = true; - } - } - else { - unsigned nprems = num_prems(proof); - for(unsigned i = 0; i < nprems; i++){ - z3pf arg = prem(proof,i); - get_proof_assumptions_rec(arg,memo,used_frames); - } - } - } - - void get_frames(const std::vector >&z3_preds, - const std::vector &orig_parents, - std::vector >&assertions, - std::vector &parents, - z3pf proof){ - frames = z3_preds.size(); - orig_parents_copy = orig_parents; - for(unsigned i = 0; i < z3_preds.size(); i++) - for(unsigned j = 0; j < z3_preds[i].size(); j++) - frame_map[z3_preds[i][j]] = i; - used_frames.resize(frames); - hash_set memo; - get_proof_assumptions_rec(proof,memo,used_frames); - std::vector assertions_back_map(frames); - - // if multiple children of a tree node are used, we can't delete it - std::vector used_children; - used_children.reserve(frames); - for(int i = 0; i < frames; i++) - used_children.push_back(0); - for(int i = 0; i < frames; i++) - if(orig_parents[i] != SHRT_MAX) - if(used_frames[i] || used_children[i]){ - if(used_children[i] > 1) - used_frames[i] = true; - used_children[orig_parents[i]]++; - } - - for(unsigned i = 0; i < z3_preds.size(); i++) - if(used_frames[i] || i == z3_preds.size() - 1){ - assertions.push_back(z3_preds[i]); - assertions_map.push_back(i); - assertions_back_map[i] = assertions.size() - 1; - } - - if(orig_parents.size()){ - parents.resize(assertions.size()); - for(unsigned i = 0; i < assertions.size(); i++){ - int p = orig_parents[assertions_map[i]]; - while(p != SHRT_MAX && !used_frames[p]) - p = orig_parents[p]; - parents[i] = p == SHRT_MAX ? p : assertions_back_map[p]; - } - } - - // std::cout << "used frames = " << frames << "\n"; - } - - void fix_interpolants(std::vector &interpolants){ - std::vector unfixed = interpolants; - interpolants.resize(frames - 1); - for(int i = 0; i < frames - 1; i++) - interpolants[i] = mk_true(); - for(unsigned i = 0; i < unfixed.size(); i++) - interpolants[assertions_map[i]] = unfixed[i]; - for(int i = 0; i < frames-2; i++){ - int p = orig_parents_copy.size() == 0 ? i+1 : orig_parents_copy[i]; - if(p < frames - 1 && !used_frames[p]) - interpolants[p] = mk_and(interpolants[i],interpolants[p]); - } - } -}; - -#else -struct frame_reducer { - - - - frame_reducer(context _ctx){ - } - - void get_frames(const std::vector &z3_preds, - const std::vector &orig_parents, - std::vector &assertions, - std::vector &parents, - ast proof){ - assertions = z3_preds; - parents = orig_parents; - } - - void fix_interpolants(std::vector &interpolants){ - } -}; - -#endif - - - -template -struct killme { - T *p; - killme(){p = nullptr;} - void set(T *_p) {p = _p;} - ~killme(){ - if(p) - delete p; - } -}; - - -class iz3interp : public iz3base { -public: - - killme sp_killer; - killme tr_killer; - - bool is_linear(std::vector &parents){ - for(int i = 0; i < ((int)parents.size())-1; i++) - if(parents[i] != i+1) - return false; - return true; - } - - void test_secondary(const std::vector &cnsts, - const std::vector &parents, - std::vector &interps - ){ - throw iz3_exception("secondary interpolating prover not supported"); - } - - void proof_to_interpolant(z3pf proof, - const std::vector > &cnsts, - const std::vector &parents, - std::vector &interps, - const std::vector &theory, - interpolation_options_struct *options = nullptr - ){ -#if 0 - test_secondary(cnsts,parents,interps); - return; -#endif - - profiling::timer_start("Interpolation prep"); - - // get rid of frames not used in proof - - std::vector > cnsts_vec; - std::vector parents_vec; - frame_reducer fr(*this); - fr.get_frames(cnsts,parents,cnsts_vec,parents_vec,proof); - - int num = cnsts_vec.size(); - std::vector interps_vec(num-1); - - // if this is really a sequence problem, we can make it easier - if(is_linear(parents_vec)) - parents_vec.clear(); - - // secondary prover no longer supported - iz3secondary *sp = nullptr; - -#define BINARY_INTERPOLATION -#ifndef BINARY_INTERPOLATION - // create a translator - iz3translation *tr = iz3translation::create(*this,sp,cnsts_vec,parents_vec,theory); - tr_killer.set(tr); - - // set the translation options, if needed - if(options) - for(hash_map::iterator it = options->map.begin(), en = options->map.end(); it != en; ++it) - tr->set_option(it->first, it->second); - - // create a proof object to hold the translation - iz3proof pf(tr); - - profiling::timer_stop("Interpolation prep"); - - // translate into an interpolatable proof - profiling::timer_start("Proof translation"); - try { - tr->translate(proof,pf); - } - catch (const char *msg) { - throw interpolation_failure(msg); - } - catch (const iz3translation::unsupported & ex) { - TRACE("iz3", tout << "unsupported " << "\n";); - throw interpolation_error(); - } - catch (const iz3proof::proof_error & ex) { - TRACE("iz3", tout << "proof error " << "\n";); - throw interpolation_error(); - } - profiling::timer_stop("Proof translation"); - - // translate the proof into interpolants - profiling::timer_start("Proof interpolation"); - for(int i = 0; i < num-1; i++){ - interps_vec[i] = pf.interpolate(tr->range_downward(i),tr->weak_mode()); - interps_vec[i] = tr->quantify(interps_vec[i],tr->range_downward(i)); - } - profiling::timer_stop("Proof interpolation"); -#else - iz3base the_base(*this,cnsts_vec,parents_vec,theory); - - profiling::timer_stop("Interpolation prep"); - - for(int i = 0; i < num-1; i++){ - range rng = the_base.range_downward(i); - std::vector > cnsts_vec_vec(2); - for(unsigned j = 0; j < cnsts_vec.size(); j++){ - bool is_A = the_base.in_range(j,rng); - for(unsigned k = 0; k < cnsts_vec[j].size(); k++) - cnsts_vec_vec[is_A ? 0 : 1].push_back(cnsts_vec[j][k]); - } - - killme tr_killer_i; - iz3translation *tr = iz3translation::create(*this,sp,cnsts_vec_vec,std::vector(),theory); - tr_killer_i.set(tr); - - // set the translation options, if needed - if(options) - for(hash_map::iterator it = options->map.begin(), en = options->map.end(); it != en; ++it) - tr->set_option(it->first, it->second); - - // create a proof object to hold the translation - iz3proof pf(tr); - - // translate into an interpolatable proof - profiling::timer_start("Proof translation"); - try { - tr->translate(proof,pf); - } - catch (const char *msg) { - throw interpolation_failure(msg); - } - catch (const iz3translation::unsupported & ex) { - TRACE("iz3", tout << "unsupported " << "\n";); - throw interpolation_error(); - } - catch (const iz3proof::proof_error &) { - TRACE("iz3", tout << "proof error\n";); - throw interpolation_error(); - } - profiling::timer_stop("Proof translation"); - - // translate the proof into interpolants - profiling::timer_start("Proof interpolation"); - interps_vec[i] = pf.interpolate(tr->range_downward(0),tr->weak_mode()); - interps_vec[i] = tr->quantify(interps_vec[i],tr->range_downward(0)); - profiling::timer_stop("Proof interpolation"); - } -#endif - // put back in the removed frames - fr.fix_interpolants(interps_vec); - - interps = interps_vec; - - } - - - void proof_to_interpolant(z3pf proof, - std::vector &cnsts, - const std::vector &parents, - std::vector &interps, - const std::vector &theory, - interpolation_options_struct *options = nullptr - ){ - std::vector > cnsts_vec(cnsts.size()); - for(unsigned i = 0; i < cnsts.size(); i++) - cnsts_vec[i].push_back(cnsts[i]); - proof_to_interpolant(proof,cnsts_vec,parents,interps,theory,options); - } - - // same as above, but represents the tree using an ast - - void proof_to_interpolant(const z3pf &proof, - const std::vector &_cnsts, - const ast &tree, - std::vector &interps, - interpolation_options_struct *options = nullptr - ){ - std::vector pos_map; - - // convert to the parents vector representation - - to_parents_vec_representation(_cnsts, tree, cnsts, parents, theory, pos_map); - - //use the parents vector representation to compute interpolant - proof_to_interpolant(proof,cnsts,parents,interps,theory,options); - - // get the interps for the tree positions - std::vector _interps = interps; - interps.resize(pos_map.size()); - for(unsigned i = 0; i < pos_map.size(); i++){ - unsigned j = pos_map[i]; - interps[i] = j < _interps.size() ? _interps[j] : mk_false(); - } - } - - bool has_interp(hash_map &memo, const ast &t){ - if(memo.find(t) != memo.end()) - return memo[t]; - bool res = false; - if(op(t) == Interp) - res = true; - else if(op(t) == And){ - int nargs = num_args(t); - for(int i = 0; i < nargs; i++) - res |= has_interp(memo, arg(t,i)); - } - memo[t] = res; - return res; - } - - void collect_conjuncts(std::vector &cnsts, hash_map &memo, const ast &t){ - if(!has_interp(memo,t)) - cnsts.push_back(t); - else { - int nargs = num_args(t); - for(int i = 0; i < nargs; i++) - collect_conjuncts(cnsts, memo, arg(t,i)); - } - } - - void assert_conjuncts(solver &s, std::vector &cnsts, const ast &t){ - hash_map memo; - collect_conjuncts(cnsts,memo,t); - for(unsigned i = 0; i < cnsts.size(); i++) - s.assert_expr(to_expr(cnsts[i].raw())); - } - - void get_proof_assumptions(z3pf proof, std::vector &cnsts, hash_set &memo){ - if(memo.find(proof) != memo.end())return; - memo.insert(proof); - pfrule dk = pr(proof); - if(dk == PR_ASSERTED) - cnsts.push_back(conc(proof)); - else { - unsigned nprems = num_prems(proof); - for(unsigned i = 0; i < nprems; i++){ - z3pf arg = prem(proof,i); - get_proof_assumptions(arg,cnsts,memo); - } - } - } - - iz3interp(ast_manager &_m_manager) - : iz3base(_m_manager) {} -}; - - - -void iz3interpolate(ast_manager &_m_manager, - ast *proof, - const ptr_vector &cnsts, - const ::vector &parents, - ptr_vector &interps, - const ptr_vector &theory, - interpolation_options_struct * options) -{ - iz3interp itp(_m_manager); - if(options) - options->apply(itp); - std::vector _cnsts(cnsts.size()); - std::vector _parents(parents.size()); - std::vector _interps; - std::vector _theory(theory.size()); - for(unsigned i = 0; i < cnsts.size(); i++) - _cnsts[i] = itp.cook(cnsts[i]); - for(unsigned i = 0; i < parents.size(); i++) - _parents[i] = parents[i]; - for(unsigned i = 0; i < theory.size(); i++) - _theory[i] = itp.cook(theory[i]); - iz3mgr::ast _proof = itp.cook(proof); - itp.proof_to_interpolant(_proof,_cnsts,_parents,_interps,_theory,options); - interps.resize(_interps.size()); - for(unsigned i = 0; i < interps.size(); i++) - interps[i] = itp.uncook(_interps[i]); -} - -void iz3interpolate(ast_manager &_m_manager, - ast *proof, - const ::vector > &cnsts, - const ::vector &parents, - ptr_vector &interps, - const ptr_vector &theory, - interpolation_options_struct * options) -{ - iz3interp itp(_m_manager); - if(options) - options->apply(itp); - std::vector > _cnsts(cnsts.size()); - std::vector _parents(parents.size()); - std::vector _interps; - std::vector _theory(theory.size()); - for(unsigned i = 0; i < cnsts.size(); i++) - for(unsigned j = 0; j < cnsts[i].size(); j++) - _cnsts[i].push_back(itp.cook(cnsts[i][j])); - for(unsigned i = 0; i < parents.size(); i++) - _parents[i] = parents[i]; - for(unsigned i = 0; i < theory.size(); i++) - _theory[i] = itp.cook(theory[i]); - iz3mgr::ast _proof = itp.cook(proof); - itp.proof_to_interpolant(_proof,_cnsts,_parents,_interps,_theory,options); - interps.resize(_interps.size()); - for(unsigned i = 0; i < interps.size(); i++) - interps[i] = itp.uncook(_interps[i]); -} - -void iz3interpolate(ast_manager &_m_manager, - ast *proof, - const ptr_vector &cnsts, - ast *tree, - ptr_vector &interps, - interpolation_options_struct * options) -{ - iz3interp itp(_m_manager); - if(options) - options->apply(itp); - std::vector _cnsts(cnsts.size()); - std::vector _interps; - for(unsigned i = 0; i < cnsts.size(); i++) - _cnsts[i] = itp.cook(cnsts[i]); - iz3mgr::ast _proof = itp.cook(proof); - iz3mgr::ast _tree = itp.cook(tree); - - // if consts isn't provided, we can reconstruct it - if(_cnsts.empty()){ - hash_set memo; - itp.get_proof_assumptions(_proof,_cnsts,memo); - } - - itp.proof_to_interpolant(_proof,_cnsts,_tree,_interps,options); - interps.resize(_interps.size()); - for(unsigned i = 0; i < interps.size(); i++) - interps[i] = itp.uncook(_interps[i]); -} - -lbool iz3interpolate(ast_manager &_m_manager, - solver &s, - ast *tree, - ptr_vector &cnsts, - ptr_vector &interps, - model_ref &m, - interpolation_options_struct * options) -{ - iz3interp itp(_m_manager); - if(options) - options->apply(itp); - iz3mgr::ast _tree = itp.cook(tree); - std::vector _cnsts; - itp.assert_conjuncts(s,_cnsts,_tree); - profiling::timer_start("solving"); - lbool res = s.check_sat(0,nullptr); - profiling::timer_stop("solving"); - if(res == l_false){ - ast *proof = s.get_proof(); - iz3mgr::ast _proof = itp.cook(proof); - std::vector _interps; - itp.proof_to_interpolant(_proof,_cnsts,_tree,_interps,options); - interps.resize(_interps.size()); - for(unsigned i = 0; i < interps.size(); i++) - interps[i] = itp.uncook(_interps[i]); - } - else if(m){ - s.get_model(m); - } - cnsts.resize(_cnsts.size()); - for(unsigned i = 0; i < cnsts.size(); i++) - cnsts[i] = itp.uncook(_cnsts[i]); - return res; -} - - - -void interpolation_options_struct::apply(iz3base &b){ - for(stl_ext::hash_map::iterator it = map.begin(), en = map.end(); - it != en; - ++it) - b.set_option((*it).first,(*it).second); -} - -// On linux and mac, unlimit stack space so we get recursion - -#if defined(_WINDOWS) || defined(_CYGWIN) || defined(_MINGW) - -#else - -#include -#include - -class iz3stack_unlimiter { -public: - iz3stack_unlimiter() { - struct rlimit rl = {RLIM_INFINITY, RLIM_INFINITY}; - setrlimit(RLIMIT_STACK, &rl); - // nothing to be done if above fails - } -}; - -// initializing this will unlimit stack - -iz3stack_unlimiter the_iz3stack_unlimiter; - -#endif diff --git a/src/interp/iz3interp.h b/src/interp/iz3interp.h deleted file mode 100644 index 909703bed..000000000 --- a/src/interp/iz3interp.h +++ /dev/null @@ -1,123 +0,0 @@ -/*++ - Copyright (c) 2011 Microsoft Corporation - - Module Name: - - iz3interp.h - - Abstract: - - Interpolation based on proof translation. - - Author: - - Ken McMillan (kenmcmil) - - Revision History: - - --*/ - -#ifndef IZ3_INTERP_H -#define IZ3_INTERP_H - -#include "interp/iz3hash.h" -#include "interp/iz3exception.h" -#include "solver/solver.h" - -class iz3base; - -struct interpolation_options_struct { - stl_ext::hash_map map; -public: - void set(const std::string &name, const std::string &value){ - map[name] = value; - } - void apply(iz3base &b); -}; - -/** This object is thrown if a tree interpolation problem is mal-formed */ -struct iz3_bad_tree: public iz3_exception { - iz3_bad_tree(): iz3_exception("iz3_bad_tree") {} -}; - -/** This object is thrown when iz3 fails due to an incompleteness in - the secondary solver. */ -struct iz3_incompleteness: public iz3_exception { - iz3_incompleteness(): iz3_exception("iz3_incompleteness") {} -}; - -// This is thrown if there is some bug in the -// interpolation procedure -class interpolation_failure : public default_exception { - public: - interpolation_failure(const char *msg) - : default_exception(msg) - { - } -}; - -// This is thrown if we cannot derive an interpolant from a proof -// because it contains unsupported theories or if the proof contains -// errors -class interpolation_error : public default_exception { - public: - interpolation_error() - : default_exception("theory not supported by interpolation or bad proof" ) - { - } -}; - -typedef interpolation_options_struct *interpolation_options; - -/* Compute an interpolant from a proof. This version uses the parents vector - representation, for compatibility with the old API. */ - -void iz3interpolate(ast_manager &_m_manager, - ast *proof, - const ptr_vector &cnsts, - const ::vector &parents, - ptr_vector &interps, - const ptr_vector &theory, - interpolation_options_struct * options = nullptr); - -/* Same as above, but each constraint is a vector of formulas. */ - -void iz3interpolate(ast_manager &_m_manager, - ast *proof, - const vector > &cnsts, - const ::vector &parents, - ptr_vector &interps, - const ptr_vector &theory, - interpolation_options_struct * options = nullptr); - -/* Compute an interpolant from a proof. This version uses the ast - representation, for compatibility with the new API. Here, cnsts is - a vector of all the assertions in the proof. This can be - over-approximated by the set of all assertions in the - solver. However, if it is empty it will be reconstructed from the - proof, so it can be considered a hint. */ - -void iz3interpolate(ast_manager &_m_manager, - ast *proof, - const ptr_vector &cnsts, - ast *tree, - ptr_vector &interps, - interpolation_options_struct * options); - - -/* Compute an interpolant from an ast representing an interpolation - problem, if unsat, else return a model (if enabled). Uses the - given solver to produce the proof/model. Also returns a vector - of the constraints in the problem, helpful for checking correctness. -*/ - -lbool iz3interpolate(ast_manager &_m_manager, - solver &s, - ast *tree, - ptr_vector &cnsts, - ptr_vector &interps, - model_ref &m, - interpolation_options_struct * options); - - -#endif diff --git a/src/interp/iz3mgr.cpp b/src/interp/iz3mgr.cpp deleted file mode 100644 index bb37d7f48..000000000 --- a/src/interp/iz3mgr.cpp +++ /dev/null @@ -1,969 +0,0 @@ -/*++ - Copyright (c) 2011 Microsoft Corporation - - Module Name: - - iz3mgr.cpp - - Abstract: - - A wrapper around an ast manager, providing convenience methods. - - Author: - - Ken McMillan (kenmcmil) - - Revision History: - - --*/ - - -#ifdef _WINDOWS -#pragma warning(disable:4996) -#pragma warning(disable:4800) -#pragma warning(disable:4267) -#pragma warning(disable:4101) -#pragma warning(disable:4805) -#pragma warning(disable:4800) -#endif - -#include "interp/iz3mgr.h" - -#include -#include -#include -#include -#include - -#include "ast/expr_abstract.h" -#include "util/params.h" -#include "ast/used_vars.h" - - -using namespace stl_ext; - - -std::ostream &operator <<(std::ostream &s, const iz3mgr::ast &a){ - return s; -} - - -iz3mgr::ast iz3mgr::make_var(const std::string &name, type ty){ - symbol s = symbol(name.c_str()); - return cook(m().mk_const(m().mk_const_decl(s, ty))); -} - -iz3mgr::ast iz3mgr::make(opr op, int n, raw_ast **args){ - switch(op) { - case True: return mki(m_basic_fid,OP_TRUE,n,args); - case False: return mki(m_basic_fid,OP_FALSE,n,args); - case Equal: return mki(m_basic_fid,OP_EQ,n,args); - case Distinct: return mki(m_basic_fid,OP_DISTINCT,n,args); - case Ite: return mki(m_basic_fid,OP_ITE,n,args); - case And: return mki(m_basic_fid,OP_AND,n,args); - case Or: return mki(m_basic_fid,OP_OR,n,args); - case Iff: return mki(m_basic_fid,OP_IFF,n,args); - case Xor: return mki(m_basic_fid,OP_XOR,n,args); - case Not: return mki(m_basic_fid,OP_NOT,n,args); - case Implies: return mki(m_basic_fid,OP_IMPLIES,n,args); - case Oeq: return mki(m_basic_fid,OP_OEQ,n,args); - case Interp: return mki(m_basic_fid,OP_INTERP,n,args); - case Leq: return mki(m_arith_fid,OP_LE,n,args); - case Geq: return mki(m_arith_fid,OP_GE,n,args); - case Lt: return mki(m_arith_fid,OP_LT,n,args); - case Gt: return mki(m_arith_fid,OP_GT,n,args); - case Plus: return mki(m_arith_fid,OP_ADD,n,args); - case Sub: return mki(m_arith_fid,OP_SUB,n,args); - case Uminus: return mki(m_arith_fid,OP_UMINUS,n,args); - case Times: return mki(m_arith_fid,OP_MUL,n,args); - case Div: return mki(m_arith_fid,OP_DIV,n,args); - case Idiv: return mki(m_arith_fid,OP_IDIV,n,args); - case Rem: return mki(m_arith_fid,OP_REM,n,args); - case Mod: return mki(m_arith_fid,OP_MOD,n,args); - case Power: return mki(m_arith_fid,OP_POWER,n,args); - case ToReal: return mki(m_arith_fid,OP_TO_REAL,n,args); - case ToInt: return mki(m_arith_fid,OP_TO_INT,n,args); - case IsInt: return mki(m_arith_fid,OP_IS_INT,n,args); - case Store: return mki(m_array_fid,OP_STORE,n,args); - case Select: return mki(m_array_fid,OP_SELECT,n,args); - case ConstArray: return mki(m_array_fid,OP_CONST_ARRAY,n,args); - case ArrayDefault: return mki(m_array_fid,OP_ARRAY_DEFAULT,n,args); - case ArrayMap: return mki(m_array_fid,OP_ARRAY_MAP,n,args); - case SetUnion: return mki(m_array_fid,OP_SET_UNION,n,args); - case SetIntersect: return mki(m_array_fid,OP_SET_INTERSECT,n,args); - case SetDifference: return mki(m_array_fid,OP_SET_DIFFERENCE,n,args); - case SetComplement: return mki(m_array_fid,OP_SET_COMPLEMENT,n,args); - case SetSubSet: return mki(m_array_fid,OP_SET_SUBSET,n,args); - case AsArray: return mki(m_array_fid,OP_AS_ARRAY,n,args); - default: - assert(0); - return ast(); - } -} - -iz3mgr::ast iz3mgr::mki(family_id fid, decl_kind dk, int n, raw_ast **args){ - return cook(m().mk_app(fid, dk, 0, nullptr, n, (expr **)args)); -} - -iz3mgr::ast iz3mgr::make(opr op, const std::vector &args){ - static std::vector a(10); - if(a.size() < args.size()) - a.resize(args.size()); - for(unsigned i = 0; i < args.size(); i++) - a[i] = args[i].raw(); - return make(op,args.size(), args.size() ? &a[0] : nullptr); -} - -iz3mgr::ast iz3mgr::make(opr op){ - return make(op,0,nullptr); -} - -iz3mgr::ast iz3mgr::make(opr op, const ast &arg0){ - raw_ast *a = arg0.raw(); - return make(op,1,&a); -} - -iz3mgr::ast iz3mgr::make(opr op, const ast &arg0, const ast &arg1){ - raw_ast *args[2]; - args[0] = arg0.raw(); - args[1] = arg1.raw(); - return make(op,2,args); -} - -iz3mgr::ast iz3mgr::make(opr op, const ast &arg0, const ast &arg1, const ast &arg2){ - raw_ast *args[3]; - args[0] = arg0.raw(); - args[1] = arg1.raw(); - args[2] = arg2.raw(); - return make(op,3,args); -} - -iz3mgr::ast iz3mgr::make(symb sym, int n, raw_ast **args){ - return cook(m().mk_app(sym, n, (expr **) args)); -} - -iz3mgr::ast iz3mgr::make(symb sym, const std::vector &args){ - static std::vector a(10); - if(a.size() < args.size()) - a.resize(args.size()); - for(unsigned i = 0; i < args.size(); i++) - a[i] = args[i].raw(); - return make(sym,args.size(), args.size() ? &a[0] : nullptr); -} - -iz3mgr::ast iz3mgr::make(symb sym){ - return make(sym,0,nullptr); -} - -iz3mgr::ast iz3mgr::make(symb sym, const ast &arg0){ - raw_ast *a = arg0.raw(); - return make(sym,1,&a); -} - -iz3mgr::ast iz3mgr::make(symb sym, const ast &arg0, const ast &arg1){ - raw_ast *args[2]; - args[0] = arg0.raw(); - args[1] = arg1.raw(); - return make(sym,2,args); -} - -iz3mgr::ast iz3mgr::make(symb sym, const ast &arg0, const ast &arg1, const ast &arg2){ - raw_ast *args[3]; - args[0] = arg0.raw(); - args[1] = arg1.raw(); - args[2] = arg2.raw(); - return make(sym,3,args); -} - -iz3mgr::ast iz3mgr::make_quant(opr op, const std::vector &bvs, ast &body){ - if(bvs.size() == 0) return body; - std::vector foo(bvs.size()); - - - std::vector names; - std::vector types; - std::vector bound_asts; - unsigned num_bound = bvs.size(); - - for (unsigned i = 0; i < num_bound; ++i) { - app* a = to_app(bvs[i].raw()); - symbol s(to_app(a)->get_decl()->get_name()); - names.push_back(s); - types.push_back(m().get_sort(a)); - bound_asts.push_back(a); - } - expr_ref abs_body(m()); - expr_abstract(m(), 0, num_bound, &bound_asts[0], to_expr(body.raw()), abs_body); - expr_ref result(m()); - result = m().mk_quantifier( - op == Forall, - names.size(), &types[0], &names[0], abs_body.get(), - 0, - symbol("itp"), - symbol(), - 0, nullptr, - 0, nullptr - ); - return cook(result.get()); -} - -// FIXME replace this with existing Z3 functionality - -iz3mgr::ast iz3mgr::clone(const ast &t, const std::vector &_args){ - if(_args.size() == 0) - return t; - - ast_manager& m = m_manager; - expr* a = to_expr(t.raw()); - static std::vector rargs(10); - if(rargs.size() < _args.size()) - rargs.resize(_args.size()); - for(unsigned i = 0; i < _args.size(); i++) - rargs[i] = _args[i].raw(); - expr* const* args = (expr **)&rargs[0]; - switch(a->get_kind()) { - case AST_APP: { - app* e = to_app(a); - if (e->get_num_args() != _args.size()) { - assert(0); - } - else { - a = m.mk_app(e->get_decl(), _args.size(), args); - } - break; - } - case AST_QUANTIFIER: { - if (_args.size() != 1) { - assert(0); - } - else { - a = m.update_quantifier(to_quantifier(a), args[0]); - } - break; - } - default: - break; - } - return cook(a); -} - - -void iz3mgr::show(ast t){ - if(t.null()){ - std::cout << "(null)" << std::endl; - } - params_ref p; - p.set_bool("flat_assoc",false); - std::cout << mk_pp(t.raw(), m(), p) << std::endl; -} - -void iz3mgr::show_symb(symb s){ - std::cout << mk_pp(s, m()) << std::endl; -} - -void iz3mgr::print_expr(std::ostream &s, const ast &e){ - params_ref p; - p.set_bool("flat_assoc",false); - s << mk_pp(e.raw(), m(), p); -} - - -void iz3mgr::print_clause(std::ostream &s, std::vector &cls){ - s << "("; - for(unsigned i = 0; i < cls.size(); i++){ - if(i > 0) s << ","; - print_expr(s,cls[i]); - } - s << ")"; -} - -void iz3mgr::show_clause(std::vector &cls){ - print_clause(std::cout,cls); - std::cout << std::endl; -} - -void iz3mgr::print_lit(ast lit){ - ast abslit = is_not(lit) ? arg(lit,0) : lit; - int f = op(abslit); - if(f == And || f == Or || f == Iff){ - if(is_not(lit)) std::cout << "~"; - std::cout << "[" << abslit << "]"; - } - else - std::cout << lit; -} - - -static int pretty_cols = 79; -static int pretty_indent_chars = 2; - -static int pretty_find_delim(const std::string &s, int pos){ - int level = 0; - int end = s.size(); - for(; pos < end; pos++){ - int ch = s[pos]; - if(ch == '(')level++; - if(ch == ')')level--; - if(level < 0 || (level == 0 && ch == ','))break; - } - return pos; -} - -static void pretty_newline(std::ostream &f, int indent){ - f << std::endl; - for(int i = 0; i < indent; i++) - f << " "; -} - -void iz3mgr::pretty_print(std::ostream &f, const std::string &s){ - int cur_indent = 0; - int indent = 0; - int col = 0; - int pos = 0; - while(pos < (int)s.size()){ - int delim = pretty_find_delim(s,pos); - if(s[pos] != ')' && s[pos] != ',' && cur_indent > indent){ - pretty_newline(f,indent); - cur_indent = indent; - col = indent; - continue; - } - if (col + delim - pos > pretty_cols) { - if (col > indent) { - pretty_newline(f,indent); - cur_indent = indent; - col = indent; - continue; - } - int paren = s.find('(',pos); - if(paren != (int)std::string::npos){ - int chars = paren - pos + 1; - f << s.substr(pos,chars); - indent += pretty_indent_chars; - if(col) pretty_newline(f,indent); - cur_indent = indent; - pos += chars; - col = indent; - continue; - } - } - int chars = delim - pos + 1; - f << s.substr(pos,chars); - pos += chars; - col += chars; - if(s[delim] == ')') - indent -= pretty_indent_chars; - } -} - - -iz3mgr::opr iz3mgr::op(const ast &t){ - ast_kind dk = t.raw()->get_kind(); - switch(dk){ - case AST_APP: { - expr * e = to_expr(t.raw()); - func_decl *d = to_app(t.raw())->get_decl(); - if (null_family_id == d->get_family_id()) - return Uninterpreted; - // return (opr)d->get_decl_kind(); - if (m_basic_fid == d->get_family_id()) { - switch(d->get_decl_kind()) { - case OP_TRUE: return True; - case OP_FALSE: return False; - case OP_EQ: return Equal; - case OP_DISTINCT: return Distinct; - case OP_ITE: return Ite; - case OP_AND: return And; - case OP_OR: return Or; - case OP_IFF: return Iff; - case OP_XOR: return Xor; - case OP_NOT: return Not; - case OP_IMPLIES: return Implies; - case OP_OEQ: return Oeq; - case OP_INTERP: return Interp; - default: - return Other; - } - } - if (m_arith_fid == d->get_family_id()) { - switch(d->get_decl_kind()) { - case OP_LE: return Leq; - case OP_GE: return Geq; - case OP_LT: return Lt; - case OP_GT: return Gt; - case OP_ADD: return Plus; - case OP_SUB: return Sub; - case OP_UMINUS: return Uminus; - case OP_MUL: return Times; - case OP_DIV: return Div; - case OP_IDIV: return Idiv; - case OP_REM: return Rem; - case OP_MOD: return Mod; - case OP_POWER: return Power; - case OP_TO_REAL: return ToReal; - case OP_TO_INT: return ToInt; - case OP_IS_INT: return IsInt; - default: - if (m().is_unique_value(e)) - return Numeral; - return Other; - } - } - if (m_array_fid == d->get_family_id()) { - switch(d->get_decl_kind()) { - case OP_STORE: return Store; - case OP_SELECT: return Select; - case OP_CONST_ARRAY: return ConstArray; - case OP_ARRAY_DEFAULT: return ArrayDefault; - case OP_ARRAY_MAP: return ArrayMap; - case OP_SET_UNION: return SetUnion; - case OP_SET_INTERSECT: return SetIntersect; - case OP_SET_DIFFERENCE: return SetDifference; - case OP_SET_COMPLEMENT: return SetComplement; - case OP_SET_SUBSET: return SetSubSet; - case OP_AS_ARRAY: return AsArray; - default: - return Other; - } - } - - return Other; - } - - - case AST_QUANTIFIER: - return to_quantifier(t.raw())->is_forall() ? Forall : Exists; - case AST_VAR: - return Variable; - default:; - } - return Other; -} - - -iz3mgr::pfrule iz3mgr::pr(const ast &t){ - func_decl *d = to_app(t.raw())->get_decl(); - assert(m_basic_fid == d->get_family_id()); - return d->get_decl_kind(); -} - -void iz3mgr::print_sat_problem(std::ostream &out, const ast &t){ - ast_smt_pp pp(m()); - pp.set_simplify_implies(false); - pp.display_smt2(out, to_expr(t.raw())); -} - -iz3mgr::ast iz3mgr::z3_simplify(const ast &e){ - ::expr * a = to_expr(e.raw()); - params_ref p; - th_rewriter m_rw(m(), p); - expr_ref result(m()); - m_rw(a, result); - return cook(result); -} - -iz3mgr::ast iz3mgr::z3_really_simplify(const ast &e){ - ::expr * a = to_expr(e.raw()); - params_ref simp_params; - simp_params.set_bool(":som",true); - simp_params.set_bool(":sort-sums",true); - th_rewriter m_rw(m(), simp_params); - expr_ref result(m()); - m_rw(a, result); - return cook(result); -} - - -#if 0 -static rational lcm(const rational &x, const rational &y){ - int a = x.numerator(); - int b = y.numerator(); - return rational(a * b / gcd(a, b)); -} -#endif - -static rational extract_lcd(std::vector &res){ - if(res.size() == 0) return rational(1); // shouldn't happen - rational lcd = denominator(res[0]); - for(unsigned i = 1; i < res.size(); i++) - lcd = lcm(lcd,denominator(res[i])); - for(unsigned i = 0; i < res.size(); i++) - res[i] *= lcd; - return lcd; -} - -void iz3mgr::get_farkas_coeffs(const ast &proof, std::vector& coeffs){ - std::vector rats; - get_farkas_coeffs(proof,rats); - coeffs.resize(rats.size()); - for(unsigned i = 0; i < rats.size(); i++){ - class sort *is = m().mk_sort(m_arith_fid, INT_SORT); - ast coeff = cook(m_arith_util.mk_numeral(rats[i],is)); - coeffs[i] = coeff; - } -} - -static void abs_rat(std::vector &rats){ - // check that they are all non-neg -- if neg, take abs val and warn! - for(unsigned i = 0; i < rats.size(); i++) - if(rats[i].is_neg()){ - // std::cout << "negative Farkas coeff!\n"; - rats[i] = -rats[i]; - } -} - -bool iz3mgr::is_farkas_coefficient_negative(const ast &proof, int n){ - rational r; - symb s = sym(proof); - bool ok = s->get_parameter(n+2).is_rational(r); - if(!ok) - throw iz3_exception("Bad Farkas coefficient"); - return r.is_neg(); -} - -void iz3mgr::get_farkas_coeffs(const ast &proof, std::vector& rats){ - symb s = sym(proof); - int numps = s->get_num_parameters(); - rats.resize(numps-2); -#if 0 - if(num_prems(proof) < numps-2){ - std::cout << "bad farkas rule: " << num_prems(proof) << " premises should be " << numps-2 << "\n"; - } -#endif - for(int i = 2; i < numps; i++){ - rational r; - bool ok = s->get_parameter(i).is_rational(r); - if(!ok) - throw iz3_exception("Bad Farkas coefficient"); -#if 0 - { - ast con = conc(prem(proof,i-2)); - ast temp = make_real(r); // for debugging - opr o = is_not(con) ? op(arg(con,0)) : op(con); - if(is_not(con) ? (o == Leq || o == Lt) : (o == Geq || o == Gt)) - r = -r; - } -#endif - rats[i-2] = r; - } -#if 0 - if(rats.size() != 0 && rats[0].is_neg()){ - for(unsigned i = 0; i < rats.size(); i++){ - assert(rats[i].is_neg()); - rats[i] = -rats[i]; - } - } -#endif - abs_rat(rats); - extract_lcd(rats); -} - -void iz3mgr::get_broken_gcd_test_coeffs(const ast &proof, std::vector& rats){ - symb s = sym(proof); - int numps = s->get_num_parameters(); - rats.resize(numps-2); - for(int i = 2; i < numps; i++){ - rational r; - bool ok = s->get_parameter(i).is_rational(r); - if(!ok) - throw "Bad Farkas coefficient"; - rats[i-2] = r; - } - extract_lcd(rats); -} - -void iz3mgr::get_assign_bounds_coeffs(const ast &proof, std::vector& coeffs){ - std::vector rats; - get_assign_bounds_coeffs(proof,rats); - coeffs.resize(rats.size()); - for(unsigned i = 0; i < rats.size(); i++){ - coeffs[i] = make_int(rats[i]); - } -} - -void iz3mgr::get_assign_bounds_coeffs(const ast &proof, std::vector& rats){ - symb s = sym(proof); - int numps = s->get_num_parameters(); - rats.resize(numps-1); - rats[0] = rational(1); - ast conseq = arg(conc(proof),0); - opr conseq_o = is_not(conseq) ? op(arg(conseq,0)) : op(conseq); - bool conseq_neg = is_not(conseq) ? (conseq_o == Leq || conseq_o == Lt) : (conseq_o == Geq || conseq_o == Gt); - for(int i = 2; i < numps; i++){ - rational r; - bool ok = s->get_parameter(i).is_rational(r); - if(!ok) - throw iz3_exception("Bad Farkas coefficient"); - { - ast con = arg(conc(proof),i-1); - ast temp = make_real(r); // for debugging - opr o = is_not(con) ? op(arg(con,0)) : op(con); - if(is_not(con) ? (o == Leq || o == Lt) : (o == Geq || o == Gt)) - r = -r; - if(conseq_neg) - r = -r; - } - rats[i-1] = r; - } -#if 0 - if(rats[1].is_neg()){ // work around bug -- if all coeffs negative, negate them - for(unsigned i = 1; i < rats.size(); i++){ - if(!rats[i].is_neg()) - throw iz3_exception("Bad Farkas coefficients"); - rats[i] = -rats[i]; - } - } -#endif - abs_rat(rats); - extract_lcd(rats); -} - -void iz3mgr::get_gomory_cut_coeffs(const ast &proof, std::vector& coeffs){ - std::vector rats; - get_gomory_cut_coeffs(proof,rats); - coeffs.resize(rats.size()); - for(unsigned i = 0; i < rats.size(); i++){ - coeffs[i] = make_int(rats[i]); - } -} - -void iz3mgr::get_gomory_cut_coeffs(const ast &proof, std::vector& rats){ - symb s = sym(proof); - int numps = s->get_num_parameters(); - rats.resize(numps-2); - for(int i = 2; i < numps; i++){ - rational r; - bool ok = s->get_parameter(i).is_rational(r); - if(!ok) - throw "Bad Farkas coefficient"; - rats[i-2] = r; - } - abs_rat(rats); - extract_lcd(rats); -} - -void iz3mgr::get_assign_bounds_rule_coeffs(const ast &proof, std::vector& coeffs){ - std::vector rats; - get_assign_bounds_rule_coeffs(proof,rats); - coeffs.resize(rats.size()); - for(unsigned i = 0; i < rats.size(); i++){ - coeffs[i] = make_int(rats[i]); - } -} - -void iz3mgr::get_assign_bounds_rule_coeffs(const ast &proof, std::vector& rats){ - symb s = sym(proof); - int numps = s->get_num_parameters(); - rats.resize(numps-1); - rats[0] = rational(1); - ast conseq = arg(conc(proof),0); - opr conseq_o = is_not(conseq) ? op(arg(conseq,0)) : op(conseq); - bool conseq_neg = is_not(conseq) ? (conseq_o == Leq || conseq_o == Lt) : (conseq_o == Geq || conseq_o == Gt); - for(int i = 2; i < numps; i++){ - rational r; - bool ok = s->get_parameter(i).is_rational(r); - if(!ok) - throw iz3_exception("Bad Farkas coefficient"); - { - ast con = conc(prem(proof,i-2)); - ast temp = make_real(r); // for debugging - opr o = is_not(con) ? op(arg(con,0)) : op(con); - if(is_not(con) ? (o == Leq || o == Lt) : (o == Geq || o == Gt)) - r = -r; - if(conseq_neg) - r = -r; - } - rats[i-1] = r; - } -#if 0 - if(rats[1].is_neg()){ // work around bug -- if all coeffs negative, negate them - for(unsigned i = 1; i < rats.size(); i++){ - if(!rats[i].is_neg()) - throw iz3_exception("Bad Farkas coefficients"); - rats[i] = -rats[i]; - } - } -#endif - abs_rat(rats); - extract_lcd(rats); -} - -/** Set P to P + cQ, where P and Q are linear inequalities. Assumes P is 0 <= y or 0 < y. */ - -void iz3mgr::linear_comb(ast &P, const ast &c, const ast &Q, bool round_off){ - ast Qrhs; - bool qstrict = false; - if(is_not(Q)){ - ast nQ = arg(Q,0); - switch(op(nQ)){ - case Gt: - Qrhs = make(Sub,arg(nQ,1),arg(nQ,0)); - break; - case Lt: - Qrhs = make(Sub,arg(nQ,0),arg(nQ,1)); - break; - case Geq: - Qrhs = make(Sub,arg(nQ,1),arg(nQ,0)); - qstrict = true; - break; - case Leq: - Qrhs = make(Sub,arg(nQ,0),arg(nQ,1)); - qstrict = true; - break; - default: - throw iz3_exception("not an inequality"); - } - } - else { - switch(op(Q)){ - case Leq: - Qrhs = make(Sub,arg(Q,1),arg(Q,0)); - break; - case Geq: - Qrhs = make(Sub,arg(Q,0),arg(Q,1)); - break; - case Lt: - Qrhs = make(Sub,arg(Q,1),arg(Q,0)); - qstrict = true; - break; - case Gt: - Qrhs = make(Sub,arg(Q,0),arg(Q,1)); - qstrict = true; - break; - default: - throw iz3_exception("not an inequality"); - } - } - bool pstrict = op(P) == Lt; - if (round_off && get_type(Qrhs) != int_type()) - round_off = false; - if(qstrict && round_off && (pstrict || !(c == make_int(rational(1))))){ - Qrhs = make(Sub,Qrhs,make_int(rational(1))); - qstrict = false; - } - Qrhs = make(Times,c,Qrhs); - bool strict = pstrict || qstrict; - if(strict) - P = make(Lt,arg(P,0),make(Plus,arg(P,1),Qrhs)); - else - P = make(Leq,arg(P,0),make(Plus,arg(P,1),Qrhs)); -} - -iz3mgr::ast iz3mgr::sum_inequalities(const std::vector &coeffs, const std::vector &ineqs, bool round_off){ - ast zero = make_int("0"); - ast thing = make(Leq,zero,zero); - for(unsigned i = 0; i < ineqs.size(); i++){ - linear_comb(thing,coeffs[i],ineqs[i], round_off); - } - thing = simplify_ineq(thing); - return thing; -} - -void iz3mgr::mk_idiv(const ast& t, const rational &d, ast &whole, ast &frac){ - opr o = op(t); - if(o == Plus){ - int nargs = num_args(t); - for(int i = 0; i < nargs; i++) - mk_idiv(arg(t,i),d,whole,frac); - return; - } - else if(o == Times){ - rational coeff; - if(is_numeral(arg(t,0),coeff)){ - if(gcd(coeff,d) == d){ - whole = make(Plus,whole,make(Times,make_int(coeff/d),arg(t,1))); - return; - } - } - } - frac = make(Plus,frac,t); -} - -iz3mgr::ast iz3mgr::mk_idiv(const ast& q, const rational &d){ - ast t = z3_simplify(q); - if(d == rational(1)) - return t; - else { - ast whole = make_int("0"); - ast frac = whole; - mk_idiv(t,d,whole,frac); - return z3_simplify(make(Plus,whole,make(Idiv,z3_simplify(frac),make_int(d)))); - } -} - -iz3mgr::ast iz3mgr::mk_idiv(const ast& t, const ast &d){ - rational r; - if(is_numeral(d,r)) - return mk_idiv(t,r); - return make(Idiv,t,d); -} - - -// does variable occur in expression? -int iz3mgr::occurs_in1(stl_ext::hash_map &occurs_in_memo,ast var, ast e){ - std::pair foo(e,false); - std::pair::iterator,bool> bar = occurs_in_memo.insert(foo); - bool &res = bar.first->second; - if(bar.second){ - if(e == var) res = true; - int nargs = num_args(e); - for(int i = 0; i < nargs; i++) - res |= occurs_in1(occurs_in_memo,var,arg(e,i)); - } - return res; -} - -int iz3mgr::occurs_in(ast var, ast e){ - hash_map memo; - return occurs_in1(memo,var,e); -} - - -bool iz3mgr::solve_arith(const ast &v, const ast &x, const ast &y, ast &res){ - if(occurs_in(v,y)) - return false; - if(op(x) == Plus){ - int n = num_args(x); - for(int i = 0; i < n; i++){ - if(arg(x,i) == v){ - res = z3_simplify(make(Sub, y, make(Sub, x, v))); - return true; - } - } - } - return false; -} - -// find a controlling equality for a given variable v in a term -// a controlling equality is of the form v = t, which, being -// false would force the formula to have the specifid truth value -// returns t, or null if no such - -iz3mgr::ast iz3mgr::cont_eq(stl_ext::hash_set &cont_eq_memo, bool truth, ast v, ast e){ - if(is_not(e)) return cont_eq(cont_eq_memo, !truth,v,arg(e,0)); - if(cont_eq_memo.find(e) != cont_eq_memo.end()) - return ast(); - cont_eq_memo.insert(e); - if(!truth && op(e) == Equal){ - if(arg(e,0) == v && !occurs_in(v,arg(e,1))) return(arg(e,1)); - if(arg(e,1) == v && !occurs_in(v,arg(e,0))) return(arg(e,0)); - ast res; - if(solve_arith(v,arg(e,0),arg(e,1),res)) return res; - if(solve_arith(v,arg(e,1),arg(e,0),res)) return res; - } - if((!truth && op(e) == And) || (truth && op(e) == Or)){ - int nargs = num_args(e); - for(int i = 0; i < nargs; i++){ - ast res = cont_eq(cont_eq_memo, truth, v, arg(e,i)); - if(!res.null()) return res; - } - } - if(truth && op(e) == Implies){ - ast res = cont_eq(cont_eq_memo, !truth, v, arg(e,0)); - if(!res.null()) return res; - res = cont_eq(cont_eq_memo, truth, v, arg(e,1)); - if(!res.null()) return res; - } - return ast(); -} - -// substitute a term t for unbound occurrences of variable v in e - -iz3mgr::ast iz3mgr::subst(stl_ext::hash_map &subst_memo, ast var, ast t, ast e){ - if(e == var) return t; - std::pair foo(e,ast()); - std::pair::iterator,bool> bar = subst_memo.insert(foo); - ast &res = bar.first->second; - if(bar.second){ - int nargs = num_args(e); - std::vector args(nargs); - for(int i = 0; i < nargs; i++) - args[i] = subst(subst_memo,var,t,arg(e,i)); - opr f = op(e); - if(f == Equal && args[0] == args[1]) res = mk_true(); - else res = clone(e,args); - } - return res; -} - -iz3mgr::ast iz3mgr::subst(ast var, ast t, ast e){ - hash_map memo; - return subst(memo,var,t,e); -} - -iz3mgr::ast iz3mgr::subst(stl_ext::hash_map &subst_memo,ast e){ - std::pair foo(e,ast()); - std::pair::iterator,bool> bar = subst_memo.insert(foo); - ast &res = bar.first->second; - if(bar.second){ - int nargs = num_args(e); - std::vector args(nargs); - for(int i = 0; i < nargs; i++) - args[i] = subst(subst_memo,arg(e,i)); - opr f = op(e); - if(f == Equal && args[0] == args[1]) res = mk_true(); - else res = clone(e,args); - } - return res; -} - -// apply a quantifier to a formula, with some optimizations -// 1) bound variable does not occur -> no quantifier -// 2) bound variable must be equal to some term -> substitute - -iz3mgr::ast iz3mgr::apply_quant(opr quantifier, ast var, ast e){ - if((quantifier == Forall && op(e) == And) - || (quantifier == Exists && op(e) == Or)){ - int n = num_args(e); - std::vector args(n); - for(int i = 0; i < n; i++) - args[i] = apply_quant(quantifier,var,arg(e,i)); - return make(op(e),args); - } - if(!occurs_in(var,e))return e; - hash_set cont_eq_memo; - ast cterm = cont_eq(cont_eq_memo, quantifier == Forall, var, e); - if(!cterm.null()){ - return subst(var,cterm,e); - } - std::vector bvs; bvs.push_back(var); - return make_quant(quantifier,bvs,e); -} - -#if 0 -void iz3mgr::get_bound_substitutes(stl_ext::hash_map &memo, const ast &e, const ast &var, std::vector &substs){ - std::pair foo(e,false); - std::pair::iterator,bool> bar = memo.insert(foo); - if(bar.second){ - if(op(e) == - } - - } -#endif - -unsigned iz3mgr::num_free_variables(const ast &e){ - used_vars uv; - uv(to_expr(e.raw())); - return uv.get_num_vars(); -} - -iz3mgr::ast iz3mgr::close_universally (ast e){ - used_vars uv; - uv(to_expr(e.raw())); - std::vector bvs; - stl_ext::hash_map subst_memo; - for (unsigned i = 0; i < uv.get_max_found_var_idx_plus_1(); i++){ - if (uv.get(i)) { - std::ostringstream os; - os << "%%" << i; - ast c = make_var(os.str(),uv.get(i)); - ast v = cook(m().mk_var(i,uv.get(i))); - subst_memo[v] = c; - bvs.push_back(c); - } - } - e = subst(subst_memo,e); - for (unsigned i = 0; i < bvs.size(); i++) - e = apply_quant(Forall,bvs[i],e); - return e; -} diff --git a/src/interp/iz3mgr.h b/src/interp/iz3mgr.h deleted file mode 100644 index 49552f92f..000000000 --- a/src/interp/iz3mgr.h +++ /dev/null @@ -1,738 +0,0 @@ -/*++ - Copyright (c) 2011 Microsoft Corporation - - Module Name: - - iz3mgr.h - - Abstract: - - A wrapper around an ast manager, providing convenience methods. - - Author: - - Ken McMillan (kenmcmil) - - Revision History: - - --*/ - -#ifndef IZ3MGR_H -#define IZ3MGR_H - - -#include -#include -#include - -#include "interp/iz3hash.h" -#include "interp/iz3exception.h" - -#include "ast/well_sorted.h" -#include "ast/arith_decl_plugin.h" -#include "ast/bv_decl_plugin.h" -#include "ast/datatype_decl_plugin.h" -#include "ast/array_decl_plugin.h" -#include "ast/ast_translation.h" -#include "ast/ast_pp.h" -#include "ast/ast_ll_pp.h" -#include "ast/ast_smt_pp.h" -#include "ast/ast_smt2_pp.h" -#include "ast/rewriter/th_rewriter.h" -#include "ast/rewriter/var_subst.h" -#include "ast/expr_substitution.h" -#include "ast/pp.h" -#include "util/scoped_ctrl_c.h" -#include "util/cancel_eh.h" -#include "util/scoped_timer.h" - -/* A wrapper around an ast manager, providing convenience methods. */ - -/** Shorthands for some built-in operators. */ - - - -// rename this to keep it accessible, as we use ast for something else -typedef ast raw_ast; - -/** Wrapper around an ast pointer */ -class ast_i { -protected: - raw_ast *_ast; -public: - raw_ast * const &raw() const {return _ast;} - ast_i(raw_ast *a){_ast = a;} - - ast_i(){_ast = nullptr;} - bool eq(const ast_i &other) const { - return _ast == other._ast; - } - bool lt(const ast_i &other) const { - return _ast->get_id() < other._ast->get_id(); - } - friend bool operator==(const ast_i &x, const ast_i&y){ - return x.eq(y); - } - friend bool operator!=(const ast_i &x, const ast_i&y){ - return !x.eq(y); - } - friend bool operator<(const ast_i &x, const ast_i&y){ - return x.lt(y); - } - size_t hash() const {return _ast->get_id();} - bool null() const {return !_ast;} -}; - -/** Reference counting verison of above */ -class ast_r : public ast_i { - ast_manager *_m; -public: - ast_r(ast_manager *m, raw_ast *a) : ast_i(a) { - _m = m; - m->inc_ref(a); - } - - ast_r() {_m = nullptr;} - - ast_r(const ast_r &other) : ast_i(other) { - _m = other._m; - if (_m) _m->inc_ref(_ast); - } - - ast_r &operator=(const ast_r &other) { - if(_ast) - _m->dec_ref(_ast); - _ast = other._ast; - _m = other._m; - if (_m) _m->inc_ref(_ast); - return *this; - } - - ~ast_r() { - if(_ast) - _m->dec_ref(_ast); - } - - ast_manager *mgr() const {return _m;} - -}; - -// to make ast_r hashable -namespace hash_space { - template <> - class hash { - public: - size_t operator()(const ast_r &s) const { - return s.raw()->get_id(); - } - }; -} - - -// to make ast_r usable in ordered collections -namespace std { - template <> - class less { - public: - bool operator()(const ast_r &s, const ast_r &t) const { - // return s.raw() < t.raw(); - return s.raw()->get_id() < t.raw()->get_id(); - } - }; -} - - -/** Wrapper around an AST manager, providing convenience methods. */ - -class iz3mgr { - - public: - typedef ast_r ast; - // typedef decl_kind opr; - typedef func_decl *symb; - typedef sort *type; - typedef ast_r z3pf; - typedef decl_kind pfrule; - - enum opr { - True, - False, - And, - Or, - Not, - Iff, - Ite, - Equal, - Implies, - Distinct, - Xor, - Oeq, - Interp, - Leq, - Geq, - Lt, - Gt, - Plus, - Sub, - Uminus, - Times, - Div, - Idiv, - Rem, - Mod, - Power, - ToReal, - ToInt, - IsInt, - Select, - Store, - ConstArray, - ArrayDefault, - ArrayMap, - SetUnion, - SetIntersect, - SetDifference, - SetComplement, - SetSubSet, - AsArray, - Numeral, - Forall, - Exists, - Variable, - Uninterpreted, - Other - }; - - opr op(const ast &t); - - unsigned ast_id(const ast &x) - { - return to_expr(x.raw())->get_id(); - } - - /** Overloads for constructing ast. */ - - ast make_var(const std::string &name, type ty); - ast make(opr op, const std::vector &args); - ast make(opr op); - ast make(opr op, const ast &arg0); - ast make(opr op, const ast &arg0, const ast &arg1); - ast make(opr op, const ast &arg0, const ast &arg1, const ast &arg2); - ast make(symb sym, const std::vector &args); - ast make(symb sym); - ast make(symb sym, const ast &arg0); - ast make(symb sym, const ast &arg0, const ast &arg1); - ast make(symb sym, const ast &arg0, const ast &arg1, const ast &arg2); - ast make_quant(opr op, const std::vector &bvs, ast &body); - ast clone(const ast &t, const std::vector &args); - - ast_manager &m() {return m_manager;} - - ast cook(raw_ast *a) {return ast(&m_manager,a);} - - std::vector cook(ptr_vector v) { - std::vector _v(v.size()); - for(unsigned i = 0; i < v.size(); i++) - _v[i] = cook(v[i]); - return _v; - } - - raw_ast *uncook(const ast &a) { - m_manager.inc_ref(a.raw()); - return a.raw(); - } - - /** Methods for destructing ast. */ - - - int num_args(const ast& t){ - ast_kind dk = t.raw()->get_kind(); - switch(dk){ - case AST_APP: - return to_app(t.raw())->get_num_args(); - case AST_QUANTIFIER: - return 1; - case AST_VAR: - return 0; - default:; - } - assert(0); - return 0; - } - - ast arg(const ast &t, int i){ - ast_kind dk = t.raw()->get_kind(); - switch(dk){ - case AST_APP: - return cook(to_app(t.raw())->get_arg(i)); - case AST_QUANTIFIER: - return cook(to_quantifier(t.raw())->get_expr()); - default:; - } - assert(0); - return ast(); - } - - void get_args(const ast &t, std::vector &res){ - res.resize(num_args(t)); - for(unsigned i = 0; i < res.size(); i++) - res[i] = arg(t,i); - } - - std::vector args(const ast &t){ - std::vector res; - get_args(t,res); - return res; - } - - symb sym(const ast& t){ - raw_ast *_ast = t.raw(); - return is_app(_ast) ? to_app(_ast)->get_decl() : nullptr; - } - - std::string string_of_symbol(symb s){ - symbol _s = s->get_name(); - if (_s.is_numerical()) { - std::ostringstream buffer; - buffer << _s.get_num(); - return buffer.str(); - } - else { - return _s.bare_str(); - } - } - - type get_type(const ast& t){ - return m().get_sort(to_expr(t.raw())); - } - - std::string string_of_numeral(const ast& t){ - rational r; - expr* e = to_expr(t.raw()); - assert(e); - if (m_arith_util.is_numeral(e, r)) - return r.to_string(); - assert(0); - return "NaN"; - } - - bool is_numeral(const ast& t, rational &r){ - expr* e = to_expr(t.raw()); - assert(e); - return m_arith_util.is_numeral(e, r); - } - - rational get_coeff(const ast& t){ - rational res; - if(op(t) == Times && is_numeral(arg(t,0),res)) - return res; - return rational(1); - } - - ast get_linear_var(const ast& t){ - rational res; - if(op(t) == Times && is_numeral(arg(t,0),res)) - return arg(t,1); - return t; - } - - int get_quantifier_num_bound(const ast &t) { - return to_quantifier(t.raw())->get_num_decls(); - } - - std::string get_quantifier_bound_name(const ast &t, unsigned i) { - return to_quantifier(t.raw())->get_decl_names()[i].bare_str(); - } - - type get_quantifier_bound_type(const ast &t, unsigned i) { - return to_quantifier(t.raw())->get_decl_sort(i); - } - - ast get_quantifier_body(const ast &t) { - return cook(to_quantifier(t.raw())->get_expr()); - } - - unsigned get_variable_index_value(const ast &t) { - var* va = to_var(t.raw()); - return va->get_idx(); - } - - bool is_bool_type(type t){ - family_id fid = to_sort(t)->get_family_id(); - decl_kind k = to_sort(t)->get_decl_kind(); - return fid == m().get_basic_family_id() && k == BOOL_SORT; - } - - bool is_array_type(type t){ - family_id fid = to_sort(t)->get_family_id(); - decl_kind k = to_sort(t)->get_decl_kind(); - return fid == m_array_fid && k == ARRAY_SORT; - } - - type get_range_type(symb s){ - return to_func_decl(s)->get_range(); - } - - int get_num_parameters(const symb &s){ - return to_func_decl(s)->get_num_parameters(); - } - - ast get_ast_parameter(const symb &s, int idx){ - return cook(to_func_decl(s)->get_parameters()[idx].get_ast()); - } - - enum lemma_theory {ArithTheory,ArrayTheory,UnknownTheory}; - - lemma_theory get_theory_lemma_theory(const ast &proof){ - symb s = sym(proof); - ::symbol p0; - bool ok = s->get_parameter(0).is_symbol(p0); - if(!ok) return UnknownTheory; - std::string foo(p0.bare_str()); - if(foo == "arith") - return ArithTheory; - if(foo == "array") - return ArrayTheory; - return UnknownTheory; - } - - enum lemma_kind {FarkasKind,Leq2EqKind,Eq2LeqKind,GCDTestKind,AssignBoundsKind,EqPropagateKind,GomoryCutKind,ArithMysteryKind,UnknownKind}; - - lemma_kind get_theory_lemma_kind(const ast &proof){ - symb s = sym(proof); - if(s->get_num_parameters() < 2) { - return ArithMysteryKind; // Bad -- Z3 hasn't told us - } - ::symbol p0; - bool ok = s->get_parameter(1).is_symbol(p0); - if(!ok) return UnknownKind; - std::string foo(p0.bare_str()); - if(foo == "farkas") - return FarkasKind; - if(foo == "triangle-eq") - return is_not(arg(conc(proof),0)) ? Eq2LeqKind : Leq2EqKind; - if(foo == "gcd-test") - return GCDTestKind; - if(foo == "assign-bounds") - return AssignBoundsKind; - if(foo == "eq-propagate") - return EqPropagateKind; - if(foo == "gomory-cut") - return GomoryCutKind; - return UnknownKind; - } - - void get_farkas_coeffs(const ast &proof, std::vector& coeffs); - - void get_farkas_coeffs(const ast &proof, std::vector& rats); - - void get_broken_gcd_test_coeffs(const ast &proof, std::vector& rats); - - void get_assign_bounds_coeffs(const ast &proof, std::vector& rats); - - void get_assign_bounds_coeffs(const ast &proof, std::vector& rats); - - void get_assign_bounds_rule_coeffs(const ast &proof, std::vector& rats); - - void get_assign_bounds_rule_coeffs(const ast &proof, std::vector& rats); - - void get_gomory_cut_coeffs(const ast &proof, std::vector& rats); - - void get_gomory_cut_coeffs(const ast &proof, std::vector& rats); - - bool is_farkas_coefficient_negative(const ast &proof, int n); - - bool is_true(const ast& t){ - return op(t) == True; - } - - bool is_false(const ast& t){ - return op(t) == False; - } - - bool is_iff(const ast& t){ - return op(t) == Iff; - } - - bool is_or(const ast& t){ - return op(t) == Or; - } - - bool is_not(const ast& t){ - return op(t) == Not; - } - - /** Simplify an expression using z3 simplifier */ - - ast z3_simplify(const ast& e); - - /** Simplify, sorting sums */ - ast z3_really_simplify(const ast &e); - - - // Some constructors that simplify things - - ast mk_not(const ast& x){ - opr o = op(x); - if(o == True) return make(False); - if(o == False) return make(True); - if(o == Not) return arg(x,0); - return make(Not,x); - } - - ast mk_and(const ast& x, const ast& y){ - opr ox = op(x); - opr oy = op(y); - if(ox == True) return y; - if(oy == True) return x; - if(ox == False) return x; - if(oy == False) return y; - if(x == y) return x; - return make(And,x,y); - } - - ast mk_or(const ast& x, const ast& y){ - opr ox = op(x); - opr oy = op(y); - if(ox == False) return y; - if(oy == False) return x; - if(ox == True) return x; - if(oy == True) return y; - if(x == y) return x; - return make(Or,x,y); - } - - ast mk_implies(const ast& x, const ast& y){ - opr ox = op(x); - opr oy = op(y); - if(ox == True) return y; - if(oy == False) return mk_not(x); - if(ox == False) return mk_true(); - if(oy == True) return y; - if(x == y) return mk_true(); - return make(Implies,x,y); - } - - ast mk_or(const std::vector &x){ - ast res = mk_false(); - for(unsigned i = 0; i < x.size(); i++) - res = mk_or(res,x[i]); - return res; - } - - ast mk_and(const std::vector &x){ - std::vector conjs; - for(unsigned i = 0; i < x.size(); i++){ - const ast &e = x[i]; - opr o = op(e); - if(o == False) - return mk_false(); - if(o != True) - conjs.push_back(e); - } - if(conjs.size() == 0) - return mk_true(); - if(conjs.size() == 1) - return conjs[0]; - return make(And,conjs); - } - - ast mk_equal(const ast& x, const ast& y){ - if(x == y) return make(True); - opr ox = op(x); - opr oy = op(y); - if(ox == True) return y; - if(oy == True) return x; - if(ox == False) return mk_not(y); - if(oy == False) return mk_not(x); - if(ox == False && oy == True) return make(False); - if(oy == False && ox == True) return make(False); - return make(Equal,x,y); - } - - ast z3_ite(const ast& x, const ast& y, const ast& z){ - opr ox = op(x); - opr oy = op(y); - opr oz = op(z); - if(ox == True) return y; - if(ox == False) return z; - if(y == z) return y; - if(oy == True && oz == False) return x; - if(oz == True && oy == False) return mk_not(x); - return make(Ite,x,y,z); - } - - ast make_int(const std::string &s) { - sort *r = m().mk_sort(m_arith_fid, INT_SORT); - return cook(m_arith_util.mk_numeral(rational(s.c_str()),r)); - } - - ast make_int(const rational &s) { - sort *r = m().mk_sort(m_arith_fid, INT_SORT); - return cook(m_arith_util.mk_numeral(s,r)); - } - - ast make_real(const std::string &s) { - sort *r = m().mk_sort(m_arith_fid, REAL_SORT); - return cook(m_arith_util.mk_numeral(rational(s.c_str()),r)); - } - - ast make_real(const rational &s) { - sort *r = m().mk_sort(m_arith_fid, REAL_SORT); - return cook(m_arith_util.mk_numeral(s,r)); - } - - ast mk_false() { return make(False); } - - ast mk_true() { return make(True); } - - ast mk_fresh_constant(char const * prefix, type s){ - return cook(m().mk_fresh_const(prefix, s)); - } - - type bool_type() { - ::sort *s = m().mk_sort(m_basic_fid, BOOL_SORT); - return s; - } - - type int_type() { - ::sort *s = m().mk_sort(m_arith_fid, INT_SORT); - return s; - } - - type real_type() { - ::sort *s = m().mk_sort(m_arith_fid, REAL_SORT); - return s; - } - - type array_type(type d, type r) { - parameter params[2] = { parameter(d), parameter(to_sort(r)) }; - ::sort * s = m().mk_sort(m_array_fid, ARRAY_SORT, 2, params); - return s; - } - - symb function(const std::string &str_name, unsigned arity, type *domain, type range) { - ::symbol name = ::symbol(str_name.c_str()); - std::vector< ::sort *> sv(arity); - for(unsigned i = 0; i < arity; i++) - sv[i] = domain[i]; - ::func_decl* d = m().mk_func_decl(name,arity,&sv[0],range); - return d; - } - - void linear_comb(ast &P, const ast &c, const ast &Q, bool round_off = false); - - ast sum_inequalities(const std::vector &coeffs, const std::vector &ineqs, bool round_off = false); - - ast simplify_ineq(const ast &ineq){ - ast res = make(op(ineq),arg(ineq,0),z3_simplify(arg(ineq,1))); - return res; - } - - void mk_idiv(const ast& t, const rational &d, ast &whole, ast &frac); - - ast mk_idiv(const ast& t, const rational &d); - - ast mk_idiv(const ast& t, const ast &d); - - /** methods for destructing proof terms */ - - pfrule pr(const z3pf &t); - - int num_prems(const z3pf &t){return to_app(t.raw())->get_num_args()-1;} - - z3pf prem(const z3pf &t, int n){return arg(t,n);} - - z3pf conc(const z3pf &t){return arg(t,num_prems(t));} - - - /* quantifier handling */ - - // substitute a term t for unbound occurrences of variable v in e - - ast subst(ast var, ast t, ast e); - - // apply a substitution defined by a map - ast subst(stl_ext::hash_map &map, ast e); - - // apply a quantifier to a formula, with some optimizations - // 1) bound variable does not occur -> no quantifier - // 2) bound variable must be equal to some term -> substitute - - ast apply_quant(opr quantifier, ast var, ast e); - - // Universally quantify all the free variables in a formula. - // Makes up names for the quntifiers. - - ast close_universally (ast e); - - unsigned num_free_variables(const ast &e); - - /** For debugging */ - void show(ast); - - void show_symb(symb s); - - /** Constructor */ - - void print_lit(ast lit); - - void print_expr(std::ostream &s, const ast &e); - - void print_clause(std::ostream &s, std::vector &cls); - - void print_sat_problem(std::ostream &out, const ast &t); - - void show_clause(std::vector &cls); - - static void pretty_print(std::ostream &f, const std::string &s); - - iz3mgr(ast_manager &_m_manager) - : m_manager(_m_manager), - m_arith_util(_m_manager) - { - m_basic_fid = m().get_basic_family_id(); - m_arith_fid = m().mk_family_id("arith"); - m_bv_fid = m().mk_family_id("bv"); - m_array_fid = m().mk_family_id("array"); - m_dt_fid = m().mk_family_id("datatype"); - m_datalog_fid = m().mk_family_id("datalog_relation"); - } - - iz3mgr(const iz3mgr& other) - : m_manager(other.m_manager), - m_arith_util(other.m_manager) - { - m_basic_fid = m().get_basic_family_id(); - m_arith_fid = m().mk_family_id("arith"); - m_bv_fid = m().mk_family_id("bv"); - m_array_fid = m().mk_family_id("array"); - m_dt_fid = m().mk_family_id("datatype"); - m_datalog_fid = m().mk_family_id("datalog_relation"); - } - - protected: - ast_manager &m_manager; - int occurs_in(ast var, ast e); - - private: - ast mki(family_id fid, decl_kind sk, int n, raw_ast **args); - ast make(opr op, int n, raw_ast **args); - ast make(symb sym, int n, raw_ast **args); - int occurs_in1(stl_ext::hash_map &occurs_in_memo, ast var, ast e); - bool solve_arith(const ast &v, const ast &x, const ast &y, ast &res); - ast cont_eq(stl_ext::hash_set &cont_eq_memo, bool truth, ast v, ast e); - ast subst(stl_ext::hash_map &subst_memo, ast var, ast t, ast e); - - - family_id m_basic_fid; - family_id m_array_fid; - family_id m_arith_fid; - family_id m_bv_fid; - family_id m_dt_fid; - family_id m_datalog_fid; - arith_util m_arith_util; -}; - -#endif - diff --git a/src/interp/iz3pp.cpp b/src/interp/iz3pp.cpp deleted file mode 100644 index 787fa4ec7..000000000 --- a/src/interp/iz3pp.cpp +++ /dev/null @@ -1,185 +0,0 @@ -/*++ - Copyright (c) 2013 Microsoft Corporation - - Module Name: - - iz3pp.cpp - - Abstract: - - Pretty-print interpolation problems - - Author: - - Ken McMillan (kenmcmil) - - Revision History: - - --*/ - -/* Copyright 2011 Microsoft Research. */ -#include -#include -#include -#include -#include -#include -#include - -#include "interp/iz3mgr.h" -#include "interp/iz3pp.h" -#include "ast/func_decl_dependencies.h" -#include "ast/for_each_expr.h" -#include "ast/ast_smt_pp.h" -#include "ast/ast_smt2_pp.h" -#include "ast/expr_functors.h" -#include "ast/expr_abstract.h" - - -using namespace stl_ext; - -// We promise not to use this for hash_map with range destructor -namespace stl_ext { - template <> - class hash { - public: - size_t operator()(const expr *p) const { - return (size_t) p; - } - }; -} - - -// TBD: algebraic data-types declarations will not be printed. -class free_func_visitor { - ast_manager& m; - func_decl_set m_funcs; - obj_hashtable m_sorts; -public: - free_func_visitor(ast_manager& m): m(m) {} - void operator()(var * n) { } - void operator()(app * n) { - m_funcs.insert(n->get_decl()); - class sort* s = m.get_sort(n); - if (s->get_family_id() == null_family_id) { - m_sorts.insert(s); - } - } - void operator()(quantifier * n) { } - func_decl_set& funcs() { return m_funcs; } - obj_hashtable& sorts() { return m_sorts; } -}; - -class iz3pp_helper : public iz3mgr { -public: - - void print_tree(const ast &tree, hash_map &cnames, std::ostream &out){ - hash_map::iterator foo = cnames.find(to_expr(tree.raw())); - if(foo != cnames.end()){ - symbol nm = foo->second; - if (is_smt2_quoted_symbol(nm)) { - out << mk_smt2_quoted_symbol(nm); - } - else { - out << nm; - } - } - else if(op(tree) == And){ - out << "(and"; - int nargs = num_args(tree); - for(int i = 0; i < nargs; i++){ - out << " "; - print_tree(arg(tree,i), cnames, out); - } - out << ")"; - } - else if(op(tree) == Interp){ - out << "(interp "; - print_tree(arg(tree,0), cnames, out); - out << ")"; - } - else throw iz3pp_bad_tree(); - } - - - iz3pp_helper(ast_manager &_m_manager) - : iz3mgr(_m_manager) {} -}; - -void iz3pp(ast_manager &m, - const ptr_vector &cnsts_vec, - expr *tree, - std::ostream& out) { - - unsigned sz = cnsts_vec.size(); - expr* const* cnsts = &cnsts_vec[0]; - - out << "(set-option :produce-interpolants true)\n"; - - free_func_visitor visitor(m); - expr_mark visited; - bool print_low_level = true; // m_params.print_low_level_smt2(); - -#define PP(_e_) if (print_low_level) out << mk_smt_pp(_e_, m); else ast_smt2_pp(out, _e_, env); - - smt2_pp_environment_dbg env(m); - - for (unsigned i = 0; i < sz; ++i) { - expr* e = cnsts[i]; - for_each_expr(visitor, visited, e); - } - - // name all the constraints - hash_map cnames; - int ctr = 1; - for(unsigned i = 0; i < sz; i++){ - symbol nm; - std::ostringstream s; - s << "f!" << (ctr++); - cnames[cnsts[i]] = symbol(s.str().c_str()); - } - - func_decl_set &funcs = visitor.funcs(); - func_decl_set::iterator it = funcs.begin(), end = funcs.end(); - - obj_hashtable& sorts = visitor.sorts(); - obj_hashtable::iterator sit = sorts.begin(), send = sorts.end(); - - - - for (; sit != send; ++sit) { - PP(*sit); - } - - for (; it != end; ++it) { - func_decl* f = *it; - if(f->get_family_id() == null_family_id){ - PP(f); - out << "\n"; - } - } - - for (unsigned i = 0; i < sz; ++i) { - out << "(assert "; - expr* r = cnsts[i]; - symbol nm = cnames[r]; - out << "(! "; - PP(r); - out << " :named "; - if (is_smt2_quoted_symbol(nm)) { - out << mk_smt2_quoted_symbol(nm); - } - else { - out << nm; - } - out << ")"; - out << ")\n"; - } - out << "(check-sat)\n"; - out << "(get-interpolant "; - iz3pp_helper pp(m); - pp.print_tree(pp.cook(tree),cnames,out); - out << ")\n"; -} - - diff --git a/src/interp/iz3pp.h b/src/interp/iz3pp.h deleted file mode 100644 index 7b3405f9b..000000000 --- a/src/interp/iz3pp.h +++ /dev/null @@ -1,36 +0,0 @@ -/*++ - Copyright (c) 2013 Microsoft Corporation - - Module Name: - - iz3pp.cpp - - Abstract: - - Pretty-print interpolation problems - - Author: - - Ken McMillan (kenmcmil) - - Revision History: - - --*/ - -#ifndef IZ3_PP_H -#define IZ3_PP_H - -#include "interp/iz3mgr.h" - -/** Exception thrown in case of mal-formed tree interpoloation - specification */ - -struct iz3pp_bad_tree: public iz3_exception { - iz3pp_bad_tree(): iz3_exception("iz3pp_bad_tree") {} -}; - -void iz3pp(ast_manager &m, - const ptr_vector &cnsts_vec, - expr *tree, - std::ostream& out); -#endif diff --git a/src/interp/iz3profiling.cpp b/src/interp/iz3profiling.cpp deleted file mode 100644 index ba4fd0206..000000000 --- a/src/interp/iz3profiling.cpp +++ /dev/null @@ -1,153 +0,0 @@ -/*++ - Copyright (c) 2011 Microsoft Corporation - - Module Name: - - iz3profiling.h - - Abstract: - - Some routines for measuring performance. - - Author: - - Ken McMillan (kenmcmil) - - Revision History: - - --*/ - -#ifdef _WINDOWS -#pragma warning(disable:4996) -#pragma warning(disable:4800) -#pragma warning(disable:4267) -#pragma warning(disable:4101) -#endif - -#include "interp/iz3profiling.h" - -#include -#include -#include -#include -#include -#include "util/stopwatch.h" - - -// FIXME fill in these stubs - -#define clock_t double - -static double current_time() -{ - static stopwatch sw; - static bool started = false; - if(!started){ - sw.start(); - started = true; - } - return sw.get_current_seconds(); -} - -static void output_time(std::ostream &os, clock_t time){ - os << time; -} - - -namespace profiling { - - void show_time(){ - output_time(std::cout,current_time()); - std::cout << "\n"; - } - - typedef std::map nmap; - - struct node { - std::string name; - clock_t time; - clock_t start_time; - nmap sub; - struct node *parent; - - node(); - } top; - - node::node(){ - time = 0; - parent = nullptr; - } - - struct node *current; - - struct init { - init(){ - top.name = "TOTAL"; - current = ⊤ - } - } initializer; - - struct time_entry { - clock_t t; - time_entry(){t = 0;}; - void add(clock_t incr){t += incr;} - }; - - struct ltstr - { - bool operator()(const char* s1, const char* s2) const - { - return strcmp(s1, s2) < 0; - } - }; - - typedef std::map tmap; - - static std::ostream *pfs; - - void print_node(node &top, int indent, tmap &totals){ - for(int i = 0; i < indent; i++) (*pfs) << " "; - (*pfs) << top.name; - int dots = 70 - 2 * indent - top.name.size(); - for(int i = 0; i second,indent+1,totals); - } - - void print(std::ostream &os) { - pfs = &os; - top.time = 0; - for(nmap::iterator it = top.sub.begin(); it != top.sub.end(); it++) - top.time += it->second.time; - tmap totals; - print_node(top,0,totals); - (*pfs) << "TOTALS:" << std::endl; - for(tmap::iterator it = totals.begin(); it != totals.end(); it++){ - (*pfs) << (it->first) << " "; - output_time(*pfs, it->second.t); - (*pfs) << std::endl; - } - } - - void timer_start(const char *name){ - node &child = current->sub[name]; - if(child.name.empty()){ // a new node - child.parent = current; - child.name = name; - } - child.start_time = current_time(); - current = &child; - } - - void timer_stop(const char *name){ - if(current->name != name || !current->parent){ - std::cerr << "imbalanced timer_start and timer_stop"; - exit(1); - } - current->time += (current_time() - current->start_time); - current = current->parent; - } -} diff --git a/src/interp/iz3profiling.h b/src/interp/iz3profiling.h deleted file mode 100755 index 6b9b07f25..000000000 --- a/src/interp/iz3profiling.h +++ /dev/null @@ -1,37 +0,0 @@ -/*++ - Copyright (c) 2011 Microsoft Corporation - - Module Name: - - iz3profiling.h - - Abstract: - - Some routines for measuring performance. - - Author: - - Ken McMillan (kenmcmil) - - Revision History: - - --*/ - -#ifndef IZ3PROFILING_H -#define IZ3PROFILING_H - -#include - -namespace profiling { - /** Start a timer with given name */ - void timer_start(const char *); - /** Stop a timer with given name */ - void timer_stop(const char *); - /** Print out timings */ - void print(std::ostream &s); - /** Show the current time. */ - void show_time(); -} - -#endif - diff --git a/src/interp/iz3proof.cpp b/src/interp/iz3proof.cpp deleted file mode 100755 index bc046ceff..000000000 --- a/src/interp/iz3proof.cpp +++ /dev/null @@ -1,628 +0,0 @@ -/*++ - Copyright (c) 2011 Microsoft Corporation - - Module Name: - - iz3proof.cpp - - Abstract: - - This class defines a simple interpolating proof system. - - Author: - - Ken McMillan (kenmcmil) - - Revision History: - - --*/ - - -#ifdef _WINDOWS -#pragma warning(disable:4996) -#pragma warning(disable:4800) -#pragma warning(disable:4267) -#pragma warning(disable:4101) -#endif - -#include "interp/iz3proof.h" -#include "interp/iz3profiling.h" - -#include -#include -#include -#include - -// #define FACTOR_INTERPS -// #define CHECK_PROOFS - - -void iz3proof::resolve(ast pivot, std::vector &cls1, const std::vector &cls2){ -#ifdef CHECK_PROOFS - std::vector orig_cls1 = cls1; -#endif - ast neg_pivot = pv->mk_not(pivot); - bool found_pivot1 = false, found_pivot2 = false; - for(unsigned i = 0; i < cls1.size(); i++){ - if(cls1[i] == neg_pivot){ - cls1[i] = cls1.back(); - cls1.pop_back(); - found_pivot1 = true; - break; - } - } - { - std::set memo; - memo.insert(cls1.begin(),cls1.end()); - for(unsigned j = 0; j < cls2.size(); j++){ - if(cls2[j] == pivot) - found_pivot2 = true; - else - if(memo.find(cls2[j]) == memo.end()) - cls1.push_back(cls2[j]); - } - } - if(found_pivot1 && found_pivot2) - return; - -#ifdef CHECK_PROOFS - std::cerr << "resolution anomaly: " << nodes.size()-1 << "\n"; -#if 0 - std::cerr << "pivot: "; {pv->print_lit(pivot); std::cout << "\n";} - std::cerr << "left clause:\n"; - for(unsigned i = 0; i < orig_cls1.size(); i++) - {pv->print_lit(orig_cls1[i]); std::cout << "\n";} - std::cerr << "right clause:\n"; - for(unsigned i = 0; i < cls2.size(); i++) - {pv->print_lit(cls2[i]); std::cout << "\n";} - throw proof_error(); -#endif -#endif -} - -iz3proof::node iz3proof::make_resolution(ast pivot, node premise1, node premise2) -{ - if(nodes[premise1].rl == Hypothesis) return premise2; // resolve with hyp is noop - if(nodes[premise2].rl == Hypothesis) return premise1; - node res = make_node(); - node_struct &n = nodes[res]; - n.rl = Resolution; - n.aux = pivot; - n.premises.resize(2); - n.premises[0] = (premise1); - n.premises[1] = (premise2); -#ifdef CHECK_PROOFS - n.conclusion = nodes[premise1].conclusion; - resolve(pivot,n.conclusion,nodes[premise2].conclusion); - n.frame = 1; -#else - n.frame = 0; // compute conclusion lazily -#endif - return res; -} - -iz3proof::node iz3proof::resolve_lemmas(ast pivot, node premise1, node premise2) -{ - std::vector lits(nodes[premise1].conclusion), itp; // no interpolant - resolve(pivot,lits,nodes[premise2].conclusion); - return make_lemma(lits,itp); -} - - -iz3proof::node iz3proof::make_assumption(int frame, const std::vector &assumption){ -#if 0 - std::cout << "assumption: \n"; - for(unsigned i = 0; i < assumption.size(); i++) - pv->show(assumption[i]); - std::cout << "\n"; -#endif - node res = make_node(); - node_struct &n = nodes[res]; - n.rl = Assumption; - n.conclusion.resize(1); - n.conclusion = assumption; - n.frame = frame; - return res; -} - -iz3proof::node iz3proof::make_hypothesis(ast hypothesis){ - node res = make_node(); - node_struct &n = nodes[res]; - n.rl = Hypothesis; - n.conclusion.resize(2); - n.conclusion[0] = hypothesis; - n.conclusion[1] = pv->mk_not(hypothesis); - return res; -} - -iz3proof::node iz3proof::make_theory(const std::vector &conclusion, std::vector premises){ - node res = make_node(); - node_struct &n = nodes[res]; - n.rl = Theory; - n.conclusion = conclusion; - n.premises = premises; - return res; -} - -iz3proof::node iz3proof::make_axiom(const std::vector &conclusion){ - node res = make_node(); - node_struct &n = nodes[res]; - n.rl = Axiom; - n.conclusion = conclusion; - return res; -} - -iz3proof::node iz3proof::make_contra(node prem, const std::vector &conclusion){ - node res = make_node(); - node_struct &n = nodes[res]; - n.rl = Contra; - n.conclusion = conclusion; -#ifdef CHECK_PROOFS - //if(!(conclusion == nodes[prem].conclusion)){ - //std::cerr << "internal error: proof error\n"; - //assert(0 && "proof error"); - //} -#endif - n.premises.push_back(prem); - return res; -} - - -iz3proof::node iz3proof::make_lemma(const std::vector &conclusion, const std::vector &interpolation){ - node res = make_node(); - node_struct &n = nodes[res]; - n.rl = Lemma; - n.conclusion = conclusion; - n.frame = interps.size(); - interps.push_back(interpolation); - return res; -} - -/** Make a Reflexivity node. This rule produces |- x = x */ - -iz3proof::node iz3proof::make_reflexivity(ast con){ - node res = make_node(); - node_struct &n = nodes[res]; - n.rl = Reflexivity; - n.conclusion.push_back(con); - return res; -} - -/** Make a Symmetry node. This takes a derivation of |- x = y and - produces | y = x */ - -iz3proof::node iz3proof::make_symmetry(ast con, node prem){ - node res = make_node(); - node_struct &n = nodes[res]; - n.rl = Reflexivity; - n.conclusion.push_back(con); - n.premises.push_back(prem); - return res; -} - -/** Make a transitivity node. This takes derivations of |- x = y - and |- y = z produces | x = z */ - -iz3proof::node iz3proof::make_transitivity(ast con, node prem1, node prem2){ - node res = make_node(); - node_struct &n = nodes[res]; - n.rl = Transitivity; - n.conclusion.push_back(con); - n.premises.push_back(prem1); - n.premises.push_back(prem2); - return res; -} - - -/** Make a congruence node. This takes derivations of |- x_i = y_i - and produces |- f(x_1,...,x_n) = f(y_1,...,y_n) */ - -iz3proof::node iz3proof::make_congruence(ast con, const std::vector &prems){ - node res = make_node(); - node_struct &n = nodes[res]; - n.rl = Congruence; - n.conclusion.push_back(con); - n.premises = prems; - return res; -} - - -/** Make an equality contradicition node. This takes |- x = y - and |- !(x = y) and produces false. */ - -iz3proof::node iz3proof::make_eqcontra(node prem1, node prem2){ - node res = make_node(); - node_struct &n = nodes[res]; - n.rl = EqContra; - n.premises.push_back(prem1); - n.premises.push_back(prem2); - return res; -} - -iz3proof::node iz3proof::copy_rec(stl_ext::hash_map &memo, iz3proof &src, node n){ - stl_ext::hash_map::iterator it = memo.find(n); - if(it != memo.end()) return (*it).second; - node_struct &ns = src.nodes[n]; - std::vector prems(ns.premises.size()); - for(unsigned i = 0; i < prems.size(); i++) - prems[i] = copy_rec(memo,src,ns.premises[i]); - nodes.push_back(ns); - nodes.back().premises.swap(prems); - if(ns.rl == Lemma){ - nodes.back().frame = interps.size(); - interps.push_back(src.interps[ns.frame]); - } - int res = nodes.size()-1; - memo[n] = res; - return res; -} - -iz3proof::node iz3proof::copy(iz3proof &src, node n){ - stl_ext::hash_map memo; - return copy_rec(memo, src, n); -} - -bool iz3proof::pred_in_A(ast id){ - return weak - ? pv->ranges_intersect(pv->ast_range(id),rng) : - pv->range_contained(pv->ast_range(id),rng); -} - -bool iz3proof::term_in_B(ast id){ - prover::range r = pv->ast_scope(id); - if(weak) { - if(pv->range_min(r) == SHRT_MIN) - return !pv->range_contained(r,rng); - else - return !pv->ranges_intersect(r,rng); - } - else - return !pv->range_contained(r,rng); -} - -bool iz3proof::frame_in_A(int frame){ - return pv->in_range(frame,rng); -} - -bool iz3proof::lit_in_B(ast lit){ - return - b_lits.find(lit) != b_lits.end() - || b_lits.find(pv->mk_not(lit)) != b_lits.end(); -} - -iz3proof::ast iz3proof::my_or(ast x, ast y){ - return pv->mk_not(pv->mk_and(pv->mk_not(x),pv->mk_not(y))); -} - -iz3proof::ast iz3proof::get_A_lits(std::vector &cls){ - ast foo = pv->mk_false(); - for(unsigned i = 0; i < cls.size(); i++){ - ast lit = cls[i]; - if(b_lits.find(pv->mk_not(lit)) == b_lits.end()){ - if(pv->range_max(pv->ast_scope(lit)) == pv->range_min(pv->ast_scope(lit))){ - std::cout << "bad lit: " << pv->range_max(rng) << " : " << pv->range_max(pv->ast_scope(lit)) << " : " << (pv->ast_id(lit)) << " : "; - pv->show(lit); - } - foo = my_or(foo,lit); - } - } - return foo; -} - -iz3proof::ast iz3proof::get_B_lits(std::vector &cls){ - ast foo = pv->mk_false(); - for(unsigned i = 0; i < cls.size(); i++){ - ast lit = cls[i]; - if(b_lits.find(pv->mk_not(lit)) != b_lits.end()) - foo = my_or(foo,lit); - } - return foo; -} - -void iz3proof::set_of_B_lits(std::vector &cls, std::set &res){ - for(unsigned i = 0; i < cls.size(); i++){ - ast lit = cls[i]; - if(b_lits.find(pv->mk_not(lit)) != b_lits.end()) - res.insert(lit); - } -} - -void iz3proof::set_of_A_lits(std::vector &cls, std::set &res){ - for(unsigned i = 0; i < cls.size(); i++){ - ast lit = cls[i]; - if(b_lits.find(pv->mk_not(lit)) == b_lits.end()) - res.insert(lit); - } -} - -void iz3proof::find_B_lits(){ - b_lits.clear(); - for(unsigned i = 0; i < nodes.size(); i++){ - node_struct &n = nodes[i]; - std::vector &cls = n.conclusion; - if(n.rl == Assumption){ - if(weak) goto lemma; - if(!frame_in_A(n.frame)) - for(unsigned j = 0; j < cls.size(); j++) - b_lits.insert(cls[j]); - } - else if(n.rl == Lemma) { - lemma: - for(unsigned j = 0; j < cls.size(); j++) - if(term_in_B(cls[j])) - b_lits.insert(cls[j]); - } - } -} - -iz3proof::ast iz3proof::disj_of_set(std::set &s){ - ast res = pv->mk_false(); - for(std::set::iterator it = s.begin(), en = s.end(); it != en; ++it) - res = my_or(*it,res); - return res; -} - -void iz3proof::mk_and_factor(int p1, int p2, int i, std::vector &itps, std::vector > &disjs){ -#ifdef FACTOR_INTERPS - std::set &d1 = disjs[p1]; - std::set &d2 = disjs[p2]; - if(!weak){ - if(pv->is_true(itps[p1])){ - itps[i] = itps[p2]; - disjs[i] = disjs[p2]; - } - else if(pv->is_true(itps[p2])){ - itps[i] = itps[p1]; - disjs[i] = disjs[p1]; - } - else { - std::set p1only,p2only; - std::insert_iterator > p1o(p1only,p1only.begin()); - std::insert_iterator > p2o(p2only,p2only.begin()); - std::insert_iterator > dio(disjs[i],disjs[i].begin()); - std::set_difference(d1.begin(),d1.end(),d2.begin(),d2.end(),p1o); - std::set_difference(d2.begin(),d2.end(),d1.begin(),d1.end(),p2o); - std::set_intersection(d1.begin(),d1.end(),d2.begin(),d2.end(),dio); - ast p1i = my_or(itps[p1],disj_of_set(p1only)); - ast p2i = my_or(itps[p2],disj_of_set(p2only)); - itps[i] = pv->mk_and(p1i,p2i); - } - } - else { - itps[i] = pv->mk_and(itps[p1],itps[p2]); - std::insert_iterator > dio(disjs[i],disjs[i].begin()); - std::set_union(d1.begin(),d1.end(),d2.begin(),d2.end(),dio); - } -#endif -} - -void iz3proof::mk_or_factor(int p1, int p2, int i, std::vector &itps, std::vector > &disjs){ -#ifdef FACTOR_INTERPS - std::set &d1 = disjs[p1]; - std::set &d2 = disjs[p2]; - if(weak){ - if(pv->is_false(itps[p1])){ - itps[i] = itps[p2]; - disjs[i] = disjs[p2]; - } - else if(pv->is_false(itps[p2])){ - itps[i] = itps[p1]; - disjs[i] = disjs[p1]; - } - else { - std::set p1only,p2only; - std::insert_iterator > p1o(p1only,p1only.begin()); - std::insert_iterator > p2o(p2only,p2only.begin()); - std::insert_iterator > dio(disjs[i],disjs[i].begin()); - std::set_difference(d1.begin(),d1.end(),d2.begin(),d2.end(),p1o); - std::set_difference(d2.begin(),d2.end(),d1.begin(),d1.end(),p2o); - std::set_intersection(d1.begin(),d1.end(),d2.begin(),d2.end(),dio); - ast p1i = pv->mk_and(itps[p1],pv->mk_not(disj_of_set(p1only))); - ast p2i = pv->mk_and(itps[p2],pv->mk_not(disj_of_set(p2only))); - itps[i] = my_or(p1i,p2i); - } - } - else { - itps[i] = my_or(itps[p1],itps[p2]); - std::insert_iterator > dio(disjs[i],disjs[i].begin()); - std::set_union(d1.begin(),d1.end(),d2.begin(),d2.end(),dio); - } -#endif -} - -void iz3proof::interpolate_lemma(node_struct &n){ - if(interps[n.frame].size()) - return; // already computed - pv->interpolate_clause(n.conclusion,interps[n.frame]); -} - -iz3proof::ast iz3proof::interpolate(const prover::range &_rng, bool _weak -#ifdef CHECK_PROOFS - , ast assump - , std::vector *parents -#endif - ){ - // std::cout << "proof size: " << nodes.size() << "\n"; - rng = _rng; - weak = _weak; -#ifdef CHECK_PROOFS - if(nodes[nodes.size()-1].conclusion.size() != 0) - std::cerr << "internal error: proof conclusion is not empty clause\n"; - if(!child_interps.size()){ - child_interps.resize(nodes.size()); - for(unsigned j = 0; j < nodes.size(); j++) - child_interps[j] = pv->mk_true(); - } -#endif - std::vector itps(nodes.size()); -#ifdef FACTOR_INTERPS - std::vector > disjs(nodes.size()); -#endif - profiling::timer_start("Blits"); - find_B_lits(); - profiling::timer_stop("Blits"); - profiling::timer_start("interp_proof"); - // strengthen(); - for(unsigned i = 0; i < nodes.size(); i++){ - node_struct &n = nodes[i]; - ast &q = itps[i]; - switch(n.rl){ - case Assumption: { - - if(frame_in_A(n.frame)){ - /* HypC-A */ - if(!weak) -#ifdef FACTOR_INTERPS - { - q = pv->mk_false(); - set_of_B_lits(n.conclusion,disjs[i]); - } -#else - q = get_B_lits(n.conclusion); -#endif - else - q = pv->mk_false(); - } - else { - /* HypEq-B */ - if(!weak) - q = pv->mk_true(); - else -#ifdef FACTOR_INTERPS - { - q = pv->mk_true(); - set_of_A_lits(n.conclusion,disjs[i]); - } -#else - q = pv->mk_not(get_A_lits(n.conclusion)); -#endif - } - break; - } - case Resolution: { - ast p = n.aux; - p = pv->is_not(p) ? pv->mk_not(p) : p; // should be positive, but just in case - if(lit_in_B(p)) -#ifdef FACTOR_INTERPS - mk_and_factor(n.premises[0],n.premises[1],i,itps,disjs); -#else - q = pv->mk_and(itps[n.premises[0]],itps[n.premises[1]]); -#endif - else -#ifdef FACTOR_INTERPS - mk_or_factor(n.premises[0],n.premises[1],i,itps,disjs); -#else - q = my_or(itps[n.premises[0]],itps[n.premises[1]]); -#endif - break; - } - case Lemma: { - interpolate_lemma(n); // make sure lemma interpolants have been computed - q = interps[n.frame][pv->range_max(rng)]; - break; - } - case Contra: { - q = itps[n.premises[0]]; -#ifdef FACTOR_INTERPS - disjs[i] = disjs[n.premises[0]]; -#endif - break; - } - default: - assert(0 && "rule not allowed in interpolated proof"); - } -#ifdef CHECK_PROOFS - int this_frame = pv->range_max(rng); - if(0 && this_frame == 39) { - std::vector alits; - ast s = pv->mk_true(); - for(unsigned j = 0; j < n.conclusion.size(); j++) - if(pred_in_A(n.conclusion[j])){ - int scpmax = pv->range_max(pv->ast_scope(n.conclusion[j])); - if(scpmax == this_frame) - s = pv->mk_and(s,pv->mk_not(n.conclusion[j])); - } - ast ci = child_interps[i]; - s = pv->mk_and(pv->mk_and(s,pv->mk_and(assump,pv->mk_not(q))),ci); - if(pv->is_sat(s)){ - std::cout << "interpolation invariant violated at step " << i << "\n"; - assert(0 && "interpolation invariant violated"); - } - } - if((*parents)[this_frame] == 39) - child_interps[i] = pv->mk_and(child_interps[i],q); -#endif - } - ast &bar = itps[nodes.size()-1]; -#ifdef FACTOR_INTERPS - if(!weak) - bar = my_or(bar,disj_of_set(disjs[nodes.size()-1])); - else - bar = pv->mk_and(bar,pv->mk_not(disj_of_set(disjs[nodes.size()-1]))); -#endif - profiling::timer_stop("interp_proof"); - profiling::timer_start("simplifying"); - bar = pv->simplify(bar); - profiling::timer_stop("simplifying"); - return bar; -} - - -void iz3proof::print(std::ostream &s, int id){ - node_struct &n = nodes[id]; - switch(n.rl){ - case Assumption: - s << "Assumption("; - pv->print_clause(s,n.conclusion); - s << ")"; - break; - case Hypothesis: - s << "Hyp("; pv->print_expr(s,n.conclusion[0]); s << ")"; break; - case Reflexivity: - s << "Refl("; pv->print_expr(s,n.conclusion[0]); s << ")"; break; - case Symmetry: - s << "Symm("; print(s,n.premises[0]); s << ")"; break; - case Transitivity: - s << "Trans("; print(s,n.premises[0]); s << ","; print(s,n.premises[1]); s << ")"; break; - case Congruence: - s << "Cong("; pv->print_expr(s,n.conclusion[0]); - for(unsigned i = 0; i < n.premises.size(); i++){ - s << ","; - print(s,n.premises[i]); - } - s << ")"; break; - case EqContra: - s << "EqContra("; print(s,n.premises[0]); s << ","; print(s,n.premises[1]); s << ")"; break; - case Resolution: - s << "Res("; - pv->print_expr(s,n.aux); s << ","; - print(s,n.premises[0]); s << ","; print(s,n.premises[1]); s << ")"; - break; - case Lemma: - s << "Lemma("; - pv->print_clause(s,n.conclusion); - for(unsigned i = 0; i < n.premises.size(); i++){ - s << ","; - print(s,n.premises[i]); - } - s << ")"; - break; - case Contra: - s << "Contra("; - print(s,n.premises[0]); - s << ")"; - break; - default:; - } -} - - -void iz3proof::show(int id){ - std::ostringstream ss; - print(ss,id); - iz3base::pretty_print(std::cout,ss.str()); - // std::cout << ss.str(); - std::cout << "\n"; -} - - diff --git a/src/interp/iz3proof.h b/src/interp/iz3proof.h deleted file mode 100644 index a7dcb9b75..000000000 --- a/src/interp/iz3proof.h +++ /dev/null @@ -1,274 +0,0 @@ -/*++ - Copyright (c) 2011 Microsoft Corporation - - Module Name: - - iz3proof.h - - Abstract: - - This class defines a simple interpolating proof system. - - Author: - - Ken McMillan (kenmcmil) - - Revision History: - - --*/ - -#ifndef IZ3PROOF_H -#define IZ3PROOF_H - -#include - -#include "interp/iz3base.h" -#include "interp/iz3secondary.h" - -// #define CHECK_PROOFS - -/** This class defines a simple proof system. - - A proof is a dag consisting of "nodes". The children of each node - are its "premises". Each node has a "conclusion" that is a clause, - represented as a vector of literals. - - The literals are represented by abstract syntax trees. Operations - on these, including computation of scopes are provided by iz3base. - - A proof can be interpolated, provided it is restricted to the - rules Resolution, Assumption, Contra and Lemma, and that all - clauses are strict (i.e., each literal in each clause is local). - -*/ - -class iz3proof { - public: - /** The type of proof nodes (nodes in the derivation tree). */ - typedef int node; - - /** Enumeration of proof rules. */ - enum rule {Resolution,Assumption,Hypothesis,Theory,Axiom,Contra,Lemma,Reflexivity,Symmetry,Transitivity,Congruence,EqContra}; - - /** Interface to prover. */ - typedef iz3base prover; - - /** Ast type. */ - typedef prover::ast ast; - - /** Object thrown in case of a proof error. */ - struct proof_error: public iz3_exception { - proof_error(): iz3_exception("proof_error") {} - }; - - /* Null proof node */ - static const node null = -1; - - /** Make a resolution node with given pivot liter and premises. - The conclusion of premise1 should contain the negation of the - pivot literal, while the conclusion of premise2 should containe the - pivot literal. - */ - node make_resolution(ast pivot, node premise1, node premise2); - - /** Make an assumption node. The given clause is assumed in the given frame. */ - node make_assumption(int frame, const std::vector &assumption); - - /** Make a hypothesis node. If phi is the hypothesis, this is - effectively phi |- phi. */ - node make_hypothesis(ast hypothesis); - - /** Make a theory node. This can be any inference valid in the theory. */ - node make_theory(const std::vector &conclusion, std::vector premises); - - /** Make an axiom node. The conclusion must be an instance of an axiom. */ - node make_axiom(const std::vector &conclusion); - - /** Make a Contra node. This rule takes a derivation of the form - Gamma |- False and produces |- \/~Gamma. */ - - node make_contra(node prem, const std::vector &conclusion); - - /** Make a lemma node. A lemma node must have an interpolation. */ - node make_lemma(const std::vector &conclusion, const std::vector &interpolation); - - /** Make a Reflexivity node. This rule produces |- x = x */ - - node make_reflexivity(ast con); - - /** Make a Symmetry node. This takes a derivation of |- x = y and - produces | y = x */ - - node make_symmetry(ast con, node prem); - - /** Make a transitivity node. This takes derivations of |- x = y - and |- y = z produces | x = z */ - - node make_transitivity(ast con, node prem1, node prem2); - - /** Make a congruence node. This takes derivations of |- x_i = y_i - and produces |- f(x_1,...,x_n) = f(y_1,...,y_n) */ - - node make_congruence(ast con, const std::vector &prems); - - /** Make an equality contradicition node. This takes |- x = y - and |- !(x = y) and produces false. */ - - node make_eqcontra(node prem1, node prem2); - - /** Get the rule of a node in a proof. */ - rule get_rule(node n){ - return nodes[n].rl; - } - - /** Get the pivot of a resolution node. */ - ast get_pivot(node n){ - return nodes[n].aux; - } - - /** Get the frame of an assumption node. */ - int get_frame(node n){ - return nodes[n].frame; - } - - /** Get the number of literals of the conclusion of a node. */ - int get_num_conclusion_lits(node n){ - return get_conclusion(n).size(); - } - - /** Get the nth literal of the conclusion of a node. */ - ast get_nth_conclusion_lit(node n, int i){ - return get_conclusion(n)[i]; - } - - /** Get the conclusion of a node. */ - void get_conclusion(node n, std::vector &result){ - result = get_conclusion(n); - } - - /** Get the number of premises of a node. */ - int get_num_premises(node n){ - return nodes[n].premises.size(); - } - - /** Get the nth premise of a node. */ - int get_nth_premise(node n, int i){ - return nodes[n].premises[i]; - } - - /** Get all the premises of a node. */ - void get_premises(node n, std::vector &result){ - result = nodes[n].premises; - } - - /** Create a new proof node, replacing the premises of an old - one. */ - - node clone(node n, std::vector &premises){ - if(premises == nodes[n].premises) - return n; - nodes.push_back(nodes[n]); - nodes.back().premises = premises; - return nodes.size()-1; - } - - /** Copy a proof node from src */ - node copy(iz3proof &src, node n); - - /** Resolve two lemmas on a given literal. */ - - node resolve_lemmas(ast pivot, node left, node right); - - /** Swap two proofs. */ - void swap(iz3proof &other){ - std::swap(pv,other.pv); - nodes.swap(other.nodes); - interps.swap(other.interps); - } - - /** Compute an interpolant for a proof, where the "A" side is defined by - the given range of frames. Parameter "weak", when true, uses different - interpolation system that resutls in generally weaker interpolants. - */ - ast interpolate(const prover::range &_rng, bool weak = false -#ifdef CHECK_PROOFS - , Z3_ast assump = (Z3_ast)0, std::vector *parents = 0 - -#endif - ); - - /** print proof node to a stream */ - - void print(std::ostream &s, node n); - - /** show proof node on stdout */ - void show(node n); - - /** Construct a proof, with a given prover. */ - iz3proof(prover *p){ - pv = p; - } - - /** Default constructor */ - iz3proof(){pv = nullptr;} - - - protected: - - struct node_struct { - rule rl; - ast aux; - int frame; - std::vector conclusion; - std::vector premises; - }; - - std::vector nodes; - std::vector > interps; // interpolations of lemmas - prover *pv; - - node make_node(){ - nodes.push_back(node_struct()); - return nodes.size()-1; - } - - void resolve(ast pivot, std::vector &cls1, const std::vector &cls2); - - node copy_rec(stl_ext::hash_map &memo, iz3proof &src, node n); - - void interpolate_lemma(node_struct &n); - - // lazily compute the result of resolution - // the node member "frame" indicates result is computed - const std::vector &get_conclusion(node x){ - node_struct &n = nodes[x]; - if(n.rl == Resolution && !n.frame){ - n.conclusion = get_conclusion(n.premises[0]); - resolve(n.aux,n.conclusion,get_conclusion(n.premises[1])); - n.frame = 1; - } - return n.conclusion; - } - - prover::range rng; - bool weak; - stl_ext::hash_set b_lits; - ast my_or(ast x, ast y); -#ifdef CHECK_PROOFS - std::vector child_interps; -#endif - bool pred_in_A(ast id); - bool term_in_B(ast id); - bool frame_in_A(int frame); - bool lit_in_B(ast lit); - ast get_A_lits(std::vector &cls); - ast get_B_lits(std::vector &cls); - void find_B_lits(); - ast disj_of_set(std::set &s); - void mk_or_factor(int p1, int p2, int i, std::vector &itps, std::vector > &disjs); - void mk_and_factor(int p1, int p2, int i, std::vector &itps, std::vector > &disjs); - void set_of_B_lits(std::vector &cls, std::set &res); - void set_of_A_lits(std::vector &cls, std::set &res); -}; - -#endif diff --git a/src/interp/iz3proof_itp.cpp b/src/interp/iz3proof_itp.cpp deleted file mode 100755 index bbeb8d072..000000000 --- a/src/interp/iz3proof_itp.cpp +++ /dev/null @@ -1,3117 +0,0 @@ -/*++ - Copyright (c) 2011 Microsoft Corporation - - Module Name: - - iz3proof.cpp - - Abstract: - - This class defines a simple interpolating proof system. - - Author: - - Ken McMillan (kenmcmil) - - Revision History: - - --*/ - -#ifdef _WINDOWS -#pragma warning(disable:4996) -#pragma warning(disable:4800) -#pragma warning(disable:4267) -#pragma warning(disable:4101) -#endif - -#include "interp/iz3proof_itp.h" - -using namespace stl_ext; - -// #define INVARIANT_CHECKING - -class iz3proof_itp_impl : public iz3proof_itp { - - prover *pv; - prover::range rng; - bool weak; - - enum LitType {LitA,LitB,LitMixed}; - - hash_map placeholders; - - // These symbols represent deduction rules - - /* This symbol represents a proof by contradiction. That is, - contra(p,l1 /\ ... /\ lk) takes a proof p of - - l1,...,lk |- false - - and returns a proof of - - |- ~l1,...,~l2 - */ - symb contra; - - /* The summation rule. The term sum(p,c,i) takes a proof p of an - inequality i', an integer coefficient c and an inequality i, and - yields a proof of i' + ci. */ - symb sum; - - /* Proof rotation. The proof term rotate(q,p) takes a - proof p of: - - Gamma, q |- false - - and yields a proof of: - - Gamma |- ~q - */ - symb rotate_sum; - - /* Inequalities to equality. leq2eq(p, q, r) takes a proof - p of ~x=y, a proof q of x <= y and a proof r of y <= x - and yields a proof of false. */ - symb leq2eq; - - /* Equality to inequality. eq2leq(p, q) takes a proof p of x=y, and - a proof q ~(x <= y) and yields a proof of false. */ - symb eq2leq; - - /* Proof term cong(p,q) takes a proof p of x=y and a proof - q of t != t and returns a proof of false. */ - symb cong; - - - /* Excluded middle. exmid(phi,p,q) takes a proof p of phi and a - proof q of ~\phi and returns a proof of false. */ - symb exmid; - - /* Symmetry. symm(p) takes a proof p of x=y and produces - a proof of y=x. */ - symb symm; - - /* Modus ponens. modpon(p,e,q) takes proofs p of P, e of P=Q - and q of ~Q and returns a proof of false. */ - symb modpon; - - /* This oprerator represents a concatenation of rewrites. The term - a=b;c=d represents an A rewrite from a to b, followed by a B - rewrite from b to c, followed by an A rewrite from c to d. - */ - symb concat; - - /* This represents a lack of a proof */ - ast no_proof; - - // This is used to represent an infinitessimal value - ast epsilon; - - // Represents the top position of a term - ast top_pos; - - // add_pos(i,pos) represents position pos if the ith argument - symb add_pos; - - // rewrite proof rules - - /* rewrite_A(pos,cond,x=y) derives A |- cond => t[x]_p = t[y]_p - where t is an arbitrary term */ - symb rewrite_A; - - /* rewrite_B(pos,cond,x=y) derives B |- cond => t[x]_p = t[y]_p, - where t is an arbitrary term */ - symb rewrite_B; - - /* a normalization step is of the form (lhs=rhs) : proof, where "proof" - is a proof of lhs=rhs and lhs is a mixed term. If rhs is a mixed term - then it must have a greater index than lhs. */ - symb normal_step; - - /* A chain of normalization steps is either "true" (the null chain) - or normal_chain( ), where step is a normalization step - and tail is a normalization chain. The lhs of must have - a less term index than any lhs in the chain. Moreover, the rhs of - may not occur as the lhs of step in . If we wish to - add lhs=rhs to the beginning of and rhs=rhs' occurs in - we must apply transitivity, transforming to lhs=rhs'. */ - - symb normal_chain; - - /* If p is a proof of Q and c is a normalization chain, then normal(p,c) - is a proof of Q(c) (that is, Q with all substitutions in c performed). */ - - symb normal; - - /** Stand-ins for quantifiers */ - - symb sforall, sexists; - - - ast get_placeholder(ast t){ - hash_map::iterator it = placeholders.find(t); - if(it != placeholders.end()) - return it->second; - ast &res = placeholders[t]; - res = mk_fresh_constant("@p",get_type(t)); -#if 0 - std::cout << "placeholder "; - print_expr(std::cout,res); - std::cout << " = "; - print_expr(std::cout,t); - std::cout << std::endl; -#endif - return res; - } - - ast make_contra_node(const ast &pf, const std::vector &lits, int pfok = -1){ - if(lits.size() == 0) - return pf; - std::vector reslits; - reslits.push_back(make(contra,pf,mk_false())); - for(unsigned i = 0; i < lits.size(); i++){ - ast bar; - if(pfok & (1 << i)) bar = make(rotate_sum,lits[i],pf); - else bar = no_proof; - ast foo = make(contra,bar,lits[i]); - reslits.push_back(foo); - } - return make(And,reslits); - } - - LitType get_term_type(const ast &lit){ - prover::range r = pv->ast_scope(lit); - if(pv->range_is_empty(r)) - return LitMixed; - if(weak) { - if(pv->range_min(r) == SHRT_MIN) - return pv->range_contained(r,rng) ? LitA : LitB; - else - return pv->ranges_intersect(r,rng) ? LitA : LitB; - } - else - return pv->range_contained(r,rng) ? LitA : LitB; - } - - bool term_common(const ast &t){ - prover::range r = pv->ast_scope(t); - return pv->ranges_intersect(r,rng) && !pv->range_contained(r,rng); - } - - bool term_in_vocab(LitType ty, const ast &lit){ - prover::range r = pv->ast_scope(lit); - if(ty == LitA){ - return pv->ranges_intersect(r,rng); - } - return !pv->range_contained(r,rng); - } - - /** Make a resolution node with given pivot literal and premises. - The conclusion of premise1 should contain the negation of the - pivot literal, while the conclusion of premise2 should contain the - pivot literal. - */ - node make_resolution(ast pivot, const std::vector &conc, node premise1, node premise2) override { - LitType lt = get_term_type(pivot); - if(lt == LitA) - return my_or(premise1,premise2); - if(lt == LitB) - return my_and(premise1,premise2); - - /* the mixed case is a bit complicated */ - - static int non_local_count = 0; - ast res = resolve_arith(pivot,conc,premise1,premise2); -#ifdef INVARIANT_CHECKING - check_contra(conc,res); -#endif - non_local_count++; - return res; - } - - - /* Handles the case of resolution on a mixed arith atom. */ - - ast resolve_arith(const ast &pivot, const std::vector &conc, node premise1, node premise2){ - ast atom = get_lit_atom(pivot); - hash_map memo; - ast neg_pivot_lit = mk_not(atom); - if(op(pivot) != Not) - std::swap(premise1,premise2); - if(op(pivot) == Equal && op(arg(pivot,0)) == Select && op(arg(pivot,1)) == Select){ - neg_pivot_lit = mk_not(neg_pivot_lit); - std::swap(premise1,premise2); - } - return resolve_arith_rec1(memo, neg_pivot_lit, premise1, premise2); - } - - - ast apply_coeff(const ast &coeff, const ast &t){ -#if 0 - rational r; - if(!is_integer(coeff,r)) - throw iz3_exception("ack!"); - ast n = make_int(r.numerator()); - ast res = make(Times,n,t); - if(!r.is_int()) { - ast d = make_int(r.numerator()); - res = mk_idiv(res,d); - } - return res; -#endif - return make(Times,coeff,t); - } - - ast sum_ineq(const ast &coeff1, const ast &ineq1, const ast &coeff2, const ast &ineq2){ - opr sum_op = Leq; - if(op(ineq1) == Lt || op(ineq2) == Lt) - sum_op = Lt; - ast sum_sides[2]; - for(int i = 0; i < 2; i++){ - sum_sides[i] = make(Plus,apply_coeff(coeff1,arg(ineq1,i)),apply_coeff(coeff2,arg(ineq2,i))); - sum_sides[i] = z3_simplify(sum_sides[i]); - } - return make(sum_op,sum_sides[0],sum_sides[1]); - } - - - void collect_contra_resolvents(int from, const ast &pivot1, const ast &pivot, const ast &conj, std::vector &res){ - int nargs = num_args(conj); - for(int i = from; i < nargs; i++){ - ast f = arg(conj,i); - if(!(f == pivot)){ - ast ph = get_placeholder(mk_not(arg(pivot1,1))); - ast pf = arg(pivot1,0); - ast thing = pf == no_proof ? no_proof : subst_term_and_simp(ph,pf,arg(f,0)); - ast newf = make(contra,thing,arg(f,1)); - res.push_back(newf); - } - } - } - - bool is_negative_equality(const ast &e){ - if(op(e) == Not){ - opr o = op(arg(e,0)); - return o == Equal || o == Iff; - } - return false; - } - - int count_negative_equalities(const std::vector &resolvent){ - int res = 0; - for(unsigned i = 0; i < resolvent.size(); i++) - if(is_negative_equality(arg(resolvent[i],1))) - res++; - return res; - } - - ast resolve_contra_nf(const ast &pivot1, const ast &conj1, - const ast &pivot2, const ast &conj2){ - std::vector resolvent; - collect_contra_resolvents(0,pivot1,pivot2,conj2,resolvent); - collect_contra_resolvents(1,pivot2,pivot1,conj1,resolvent); - if(count_negative_equalities(resolvent) > 1) - throw proof_error(); - if(resolvent.size() == 1) // we have proved a contradiction - return simplify(arg(resolvent[0],0)); // this is the proof -- get interpolant - return make(And,resolvent); - } - - ast resolve_contra(const ast &pivot1, const ast &conj1, - const ast &pivot2, const ast &conj2){ - if(arg(pivot1,0) != no_proof) - return resolve_contra_nf(pivot1, conj1, pivot2, conj2); - if(arg(pivot2,0) != no_proof) - return resolve_contra_nf(pivot2, conj2, pivot1, conj1); - return resolve_with_quantifier(pivot1, conj1, pivot2, conj2); - } - - - bool is_contra_itp(const ast &pivot1, ast itp2, ast &pivot2){ - if(op(itp2) == And){ - int nargs = num_args(itp2); - for(int i = 1; i < nargs; i++){ - ast foo = arg(itp2,i); - if(op(foo) == Uninterpreted && sym(foo) == contra){ - if(arg(foo,1) == pivot1){ - pivot2 = foo; - return true; - } - } - else break; - } - } - return false; - } - - ast resolve_arith_rec2(hash_map &memo, const ast &pivot1, const ast &conj1, const ast &itp2){ - ast &res = memo[itp2]; - if(!res.null()) - return res; - - ast pivot2; - if(is_contra_itp(mk_not(arg(pivot1,1)),itp2,pivot2)) - res = resolve_contra(pivot1,conj1,pivot2,itp2); - else { - switch(op(itp2)){ - case Or: - case And: - case Implies: { - unsigned nargs = num_args(itp2); - std::vector args; args.resize(nargs); - for(unsigned i = 0; i < nargs; i++) - args[i] = resolve_arith_rec2(memo, pivot1, conj1, arg(itp2,i)); - ast foo = itp2; // get rid of const - res = clone(foo,args); - break; - } - default: - { - opr o = op(itp2); - if(o == Uninterpreted){ - symb s = sym(itp2); - if(s == sforall || s == sexists) - res = make(s,arg(itp2,0),resolve_arith_rec2(memo, pivot1, conj1, arg(itp2,1))); - else - res = itp2; - } - else { - res = itp2; - } - } - } - } - return res; - } - - - ast resolve_arith_rec1(hash_map &memo, const ast &neg_pivot_lit, const ast &itp1, const ast &itp2){ - ast &res = memo[itp1]; - if(!res.null()) - return res; - ast pivot1; - if(is_contra_itp(neg_pivot_lit,itp1,pivot1)){ - hash_map memo2; - res = resolve_arith_rec2(memo2,pivot1,itp1,itp2); - } - else { - switch(op(itp1)){ - case Or: - case And: - case Implies: { - unsigned nargs = num_args(itp1); - std::vector args; args.resize(nargs); - for(unsigned i = 0; i < nargs; i++) - args[i] = resolve_arith_rec1(memo, neg_pivot_lit, arg(itp1,i), itp2); - ast foo = itp1; // get rid of const - res = clone(foo,args); - break; - } - default: - { - opr o = op(itp1); - if(o == Uninterpreted){ - symb s = sym(itp1); - if(s == sforall || s == sexists) - res = make(s,arg(itp1,0),resolve_arith_rec1(memo, neg_pivot_lit, arg(itp1,1), itp2)); - else - res = itp1; - } - else { - res = itp1; - } - } - } - } - return res; - } - - void check_contra(hash_set &memo, hash_set &neg_lits, const ast &foo){ - if(memo.find(foo) != memo.end()) - return; - memo.insert(foo); - if(op(foo) == Uninterpreted && sym(foo) == contra){ - ast neg_lit = arg(foo,1); - if(!is_false(neg_lit) && neg_lits.find(neg_lit) == neg_lits.end()) - throw iz3_exception("lost a literal"); - return; - } - else { - switch(op(foo)){ - case Or: - case And: - case Implies: { - unsigned nargs = num_args(foo); - std::vector args; args.resize(nargs); - for(unsigned i = 0; i < nargs; i++) - check_contra(memo, neg_lits, arg(foo,i)); - break; - } - default: break; - } - } - } - - void check_contra(const std::vector &neg_lits, const ast &foo){ - hash_set memo; - hash_set neg_lits_set; - for(unsigned i = 0; i < neg_lits.size(); i++) - if(get_term_type(neg_lits[i]) == LitMixed) - neg_lits_set.insert(mk_not(neg_lits[i])); - check_contra(memo,neg_lits_set,foo); - } - - hash_map subst_memo; // memo of subst function - - ast subst_term_and_simp(const ast &var, const ast &t, const ast &e){ - subst_memo.clear(); - return subst_term_and_simp_rec(var,t,e); - } - - ast subst_term_and_simp_rec(const ast &var, const ast &t, const ast &e){ - if(e == var) return t; - std::pair foo(e,ast()); - std::pair::iterator,bool> bar = subst_memo.insert(foo); - ast &res = bar.first->second; - if(bar.second){ - if(op(e) == Uninterpreted){ - symb g = sym(e); - if(g == rotate_sum){ - if(var == get_placeholder(arg(e,0))){ - res = e; - } - else - res = make(rotate_sum,arg(e,0),subst_term_and_simp_rec(var,t,arg(e,1))); - return res; - } - if(g == concat){ - res = e; - return res; - } - } - int nargs = num_args(e); - std::vector args(nargs); - for(int i = 0; i < nargs; i++) - args[i] = subst_term_and_simp_rec(var,t,arg(e,i)); - opr f = op(e); - if(f == Equal && args[0] == args[1]) res = mk_true(); - else if(f == And) res = my_and(args); - else if(f == Or) res = my_or(args); - else if(f == Idiv) res = mk_idiv(args[0],args[1]); - else res = clone(e,args); - } - return res; - } - - /* This is where the real work happens. Here, we simplify the - proof obtained by cut elimination, obtaining an interpolant. */ - - struct cannot_simplify: public iz3_exception { - cannot_simplify(): iz3_exception("cannot_simplify") {} - }; - hash_map simplify_memo; - - ast simplify(const ast &t){ - ast res = normalize(simplify_rec(t)); -#ifdef BOGUS_QUANTS - if(localization_vars.size()) - res = add_quants(z3_simplify(res)); -#endif - return res; - } - - ast simplify_rec(const ast &e){ - std::pair foo(e,ast()); - std::pair::iterator,bool> bar = simplify_memo.insert(foo); - ast &res = bar.first->second; - if(bar.second){ - int nargs = num_args(e); - std::vector args(nargs); - bool placeholder_arg = false; - symb g = sym(e); - if(g == concat){ - res = e; - return res; - } - for(int i = 0; i < nargs; i++){ - if(i == 0 && g == rotate_sum) - args[i] = arg(e,i); - else - args[i] = simplify_rec(arg(e,i)); - placeholder_arg |= is_placeholder(args[i]); - } - try { - TRACE("duality", print_expr(tout, e); tout << "\n";); - opr f = op(e); - if(f == Equal && args[0] == args[1]) res = mk_true(); - else if(f == And) res = my_and(args); - else if(f == Or) - res = my_or(args); - else if(f == Idiv) res = mk_idiv(args[0],args[1]); - else if(f == Uninterpreted && !placeholder_arg){ - if(g == rotate_sum) res = simplify_rotate(args); - else if(g == symm) res = simplify_symm(args); - else if(g == modpon) res = simplify_modpon(args); - else if(g == sum) res = simplify_sum(args); - else if(g == exmid) res = simplify_exmid(args); - else if(g == cong) res = simplify_cong(args); -#if 0 - else if(g == modpon) res = simplify_modpon(args); - else if(g == leq2eq) res = simplify_leq2eq(args); - else if(g == eq2leq) res = simplify_eq2leq(args); -#endif - else res = clone(e,args); - } - else res = clone(e,args); - } - catch (const cannot_simplify &){ - if(g == sum) - res = clone(e,args); - else - throw "interpolation failure"; - } - } - return res; - } - - - ast simplify_rotate(const std::vector &args){ - const ast &pf = args[1]; - ast pl = get_placeholder(args[0]); - if(op(pf) == Uninterpreted){ - symb g = sym(pf); - if(g == sum) return simplify_rotate_sum(pl,pf); - if(g == leq2eq) return simplify_rotate_leq2eq(pl,args[0],pf); - if(g == eq2leq) return simplify_rotate_eq2leq(pl,args[0],pf); - if(g == cong) return simplify_rotate_cong(pl,args[0],pf); - if(g == modpon) return simplify_rotate_modpon(pl,args[0],pf); - // if(g == symm) return simplify_rotate_symm(pl,args[0],pf); - } - if(op(pf) == Leq) - throw iz3_exception("foo!"); - throw cannot_simplify(); - } - - bool is_normal_ineq(const ast &ineq){ - if(sym(ineq) == normal) - return is_ineq(arg(ineq,0)); - return is_ineq(ineq); - } - - ast destruct_cond_ineq(const ast &ineq, ast &Aproves, ast &Bproves){ - ast res = ineq; - opr o = op(res); - if(o == And){ - Aproves = my_and(Aproves,arg(res,0)); - res = arg(res,1); - o = op(res); - } - if(o == Implies){ - Bproves = my_and(Bproves,arg(res,0)); - res = arg(res,1); - } - return res; - } - - ast distribute_coeff(const ast &coeff, const ast &s){ - if(sym(s) == sum){ - if(sym(arg(s,2)) == sum) - return make(sum, - distribute_coeff(coeff,arg(s,0)), - make_int(rational(1)), - distribute_coeff(make(Times,coeff,arg(s,1)), arg(s,2))); - else - return make(sum, - distribute_coeff(coeff,arg(s,0)), - make(Times,coeff,arg(s,1)), - arg(s,2)); - } - if(op(s) == Leq && arg(s,1) == make_int(rational(0)) && arg(s,2) == make_int(rational(0))) - return s; - return make(sum,make(Leq,make_int(rational(0)),make_int(rational(0))),coeff,s); - } - - ast simplify_sum(std::vector &args){ - if(args[1] != make_int(rational(1))){ - if(sym(args[2]) == sum) - return make(sum,args[0],make_int(rational(1)),distribute_coeff(args[1],args[2])); - } - ast Aproves = mk_true(), Bproves = mk_true(); - ast ineq = destruct_cond_ineq(args[0],Aproves,Bproves); - if(!is_normal_ineq(ineq)) throw cannot_simplify(); - sum_cond_ineq(ineq,args[1],args[2],Aproves,Bproves); - return my_and(Aproves,my_implies(Bproves,ineq)); - } - - ast simplify_rotate_sum(const ast &pl, const ast &pf){ - ast Aproves = mk_true(), Bproves = mk_true(); - ast ineq = make(Leq,make_int("0"),make_int("0")); - ineq = rotate_sum_rec(pl,pf,Aproves,Bproves,ineq); - if(is_true(Aproves) && is_true(Bproves)) - return ineq; - return my_and(Aproves,my_implies(Bproves,ineq)); - } - - bool is_rewrite_chain(const ast &chain){ - return sym(chain) == concat; - } - -#if 0 - ast ineq_from_chain_simple(const ast &chain, ast &cond){ - if(is_true(chain)) - return chain; - ast last = chain_last(chain); - ast rest = chain_rest(chain); - if(is_true(rest) && is_rewrite_side(LitA,last) - && is_true(rewrite_lhs(last))){ - cond = my_and(cond,rewrite_cond(last)); - return rewrite_rhs(last); - } - if(is_rewrite_side(LitB,last) && is_true(rewrite_cond(last))) - return ineq_from_chain_simple(rest,cond); - return chain; - } -#endif - - ast ineq_from_chain(const ast &chain, ast &Aproves, ast &Bproves){ - if(is_rewrite_chain(chain)) - return rewrite_chain_to_normal_ineq(chain,Aproves,Bproves); - return chain; - } - - - void sum_cond_ineq(ast &ineq, const ast &coeff2, const ast &ineq2, ast &Aproves, ast &Bproves){ - opr o = op(ineq2); - if(o == And){ - sum_cond_ineq(ineq,coeff2,arg(ineq2,1),Aproves,Bproves); - Aproves = my_and(Aproves,arg(ineq2,0)); - } - else if(o == Implies){ - sum_cond_ineq(ineq,coeff2,arg(ineq2,1),Aproves,Bproves); - Bproves = my_and(Bproves,arg(ineq2,0)); - } - else { - ast the_ineq = ineq_from_chain(ineq2,Aproves,Bproves); - if(sym(ineq) == normal || sym(the_ineq) == normal){ - sum_normal_ineq(ineq,coeff2,the_ineq,Aproves,Bproves); - return; - } - if(is_ineq(the_ineq)) - linear_comb(ineq,coeff2,the_ineq); - else - throw cannot_simplify(); - } - } - - void destruct_normal(const ast &pf, ast &p, ast &n){ - if(sym(pf) == normal){ - p = arg(pf,0); - n = arg(pf,1); - } - else { - p = pf; - n = mk_true(); - } - } - - void sum_normal_ineq(ast &ineq, const ast &coeff2, const ast &ineq2, ast &Aproves, ast &Bproves){ - ast in1,in2,n1,n2; - destruct_normal(ineq,in1,n1); - destruct_normal(ineq2,in2,n2); - ast dummy1, dummy2; - sum_cond_ineq(in1,coeff2,in2,dummy1,dummy2); - n1 = merge_normal_chains(n1,n2, Aproves, Bproves); - ineq = is_true(n1) ? in1 : make_normal(in1,n1); - } - - bool is_ineq(const ast &ineq){ - opr o = op(ineq); - if(o == Not) o = op(arg(ineq,0)); - return o == Leq || o == Lt || o == Geq || o == Gt; - } - - // divide both sides of inequality by a non-negative integer divisor - ast idiv_ineq(const ast &ineq1, const ast &divisor){ - if(sym(ineq1) == normal){ - ast in1,n1; - destruct_normal(ineq1,in1,n1); - in1 = idiv_ineq(in1,divisor); - return make_normal(in1,n1); - } - if(divisor == make_int(rational(1))) - return ineq1; - ast ineq = ineq1; - if(op(ineq) == Lt) - ineq = simplify_ineq(make(Leq,arg(ineq,0),make(Sub,arg(ineq,1),make_int("1")))); - return make(op(ineq),mk_idiv(arg(ineq,0),divisor),mk_idiv(arg(ineq,1),divisor)); - } - - ast rotate_sum_rec(const ast &pl, const ast &pf, ast &Aproves, ast &Bproves, ast &ineq){ - if(pf == pl){ - if(sym(ineq) == normal) - return ineq; - return simplify_ineq(ineq); - } - if(op(pf) == Uninterpreted && sym(pf) == sum){ - if(arg(pf,2) == pl){ - sum_cond_ineq(ineq,make_int("1"),arg(pf,0),Aproves,Bproves); - ineq = idiv_ineq(ineq,arg(pf,1)); - return ineq; - } - sum_cond_ineq(ineq,arg(pf,1),arg(pf,2),Aproves,Bproves); - return rotate_sum_rec(pl,arg(pf,0),Aproves,Bproves,ineq); - } - throw cannot_simplify(); - } - - ast simplify_rotate_leq2eq(const ast &pl, const ast &neg_equality, const ast &pf){ - if(pl == arg(pf,0)){ - ast equality = arg(neg_equality,0); - ast x = arg(equality,0); - ast y = arg(equality,1); - ast Aproves1 = mk_true(), Bproves1 = mk_true(); - ast pf1 = destruct_cond_ineq(arg(pf,1), Aproves1, Bproves1); - ast pf2 = destruct_cond_ineq(arg(pf,2), Aproves1, Bproves1); - ast xleqy = round_ineq(ineq_from_chain(pf1,Aproves1,Bproves1)); - ast yleqx = round_ineq(ineq_from_chain(pf2,Aproves1,Bproves1)); - ast ineq1 = make(Leq,make_int("0"),make_int("0")); - sum_cond_ineq(ineq1,make_int("-1"),xleqy,Aproves1,Bproves1); - sum_cond_ineq(ineq1,make_int("-1"),yleqx,Aproves1,Bproves1); - ast Acond = my_implies(Aproves1,my_and(Bproves1,z3_simplify(ineq1))); - ast Aproves2 = mk_true(), Bproves2 = mk_true(); - ast ineq2 = make(Leq,make_int("0"),make_int("0")); - sum_cond_ineq(ineq2,make_int("1"),xleqy,Aproves2,Bproves2); - sum_cond_ineq(ineq2,make_int("1"),yleqx,Aproves2,Bproves2); - ast Bcond = my_implies(Bproves1,my_and(Aproves1,z3_simplify(ineq2))); - // if(!is_true(Aproves1) || !is_true(Bproves1)) - // std::cout << "foo!\n";; - if(y == make_int(rational(0)) && op(x) == Plus && num_args(x) == 2){ - if(get_term_type(arg(x,0)) == LitA){ - ast iter = z3_simplify(make(Plus,arg(x,0),get_ineq_rhs(xleqy))); - ast rewrite1 = make_rewrite(LitA,pos_add(0,top_pos),Acond,make(Equal,arg(x,0),iter)); - iter = make(Plus,iter,arg(x,1)); - ast rewrite2 = make_rewrite(LitB,top_pos,Bcond,make(Equal,iter,y)); - return chain_cons(chain_cons(mk_true(),rewrite1),rewrite2); - } - if(get_term_type(arg(x,1)) == LitA){ - ast iter = z3_simplify(make(Plus,arg(x,1),get_ineq_rhs(xleqy))); - ast rewrite1 = make_rewrite(LitA,pos_add(1,top_pos),Acond,make(Equal,arg(x,1),iter)); - iter = make(Plus,arg(x,0),iter); - ast rewrite2 = make_rewrite(LitB,top_pos,Bcond,make(Equal,iter,y)); - return chain_cons(chain_cons(mk_true(),rewrite1),rewrite2); - } - } - if(get_term_type(x) == LitA){ - ast iter = z3_simplify(make(Plus,x,get_ineq_rhs(xleqy))); - ast rewrite1 = make_rewrite(LitA,top_pos,Acond,make(Equal,x,iter)); - ast rewrite2 = make_rewrite(LitB,top_pos,Bcond,make(Equal,iter,y)); - return chain_cons(chain_cons(mk_true(),rewrite1),rewrite2); - } - if(get_term_type(y) == LitA){ - ast iter = z3_simplify(make(Plus,y,get_ineq_rhs(yleqx))); - ast rewrite2 = make_rewrite(LitA,top_pos,Acond,make(Equal,iter,y)); - ast rewrite1 = make_rewrite(LitB,top_pos,Bcond,make(Equal,x,iter)); - return chain_cons(chain_cons(mk_true(),rewrite1),rewrite2); - } - throw cannot_simplify(); - } - throw cannot_simplify(); - } - - ast round_ineq(const ast &ineq){ - if(sym(ineq) == normal) - return make_normal(round_ineq(arg(ineq,0)),arg(ineq,1)); - if(!is_ineq(ineq)) - throw cannot_simplify(); - ast res = simplify_ineq(ineq); - if(op(res) == Lt) - res = make(Leq,arg(res,0),make(Sub,arg(res,1),make_int("1"))); - return res; - } - - ast unmixed_eq2ineq(const ast &lhs, const ast &rhs, opr comp_op, const ast &equa, ast &cond){ - ast ineqs= chain_ineqs(comp_op,LitA,equa,lhs,rhs); // chain must be from lhs to rhs - cond = my_and(cond,chain_conditions(LitA,equa)); - ast Bconds = z3_simplify(chain_conditions(LitB,equa)); - if(is_true(Bconds) && op(ineqs) != And) - return my_implies(cond,ineqs); - if(op(ineqs) != And) - return my_and(Bconds,my_implies(cond,ineqs)); - throw iz3_exception("help!"); - } - - ast add_mixed_eq2ineq(const ast &lhs, const ast &rhs, const ast &equa, const ast &itp){ - if(is_true(equa)) - return itp; - std::vector args(3); - args[0] = itp; - args[1] = make_int("1"); - ast ineq = make(Leq,make_int(rational(0)),make_int(rational(0))); - args[2] = make_normal(ineq,cons_normal(fix_normal(lhs,rhs,equa),mk_true())); - return simplify_sum(args); - } - - - ast simplify_rotate_eq2leq(const ast &pl, const ast &neg_equality, const ast &pf){ - if(pl == arg(pf,1)){ - TRACE("duality", print_expr(tout, pl); print_expr(tout << "\n", neg_equality); print_expr(tout << "\n", pf); tout << "\n";); - ast cond = mk_true(); - ast equa = sep_cond(arg(pf,0),cond); - if(is_equivrel_chain(equa)){ - ast lhs,rhs; eq_from_ineq(arg(neg_equality,0),lhs,rhs); // get inequality we need to prove - if(!rewrites_from_to(equa,lhs,rhs)){ - lhs = arg(arg(neg_equality,0),0); // the equality proved is ambiguous, sadly - rhs = arg(arg(neg_equality,0),1); - } - LitType lhst = get_term_type(lhs), rhst = get_term_type(rhs); - if(lhst != LitMixed && rhst != LitMixed) - return unmixed_eq2ineq(lhs, rhs, op(arg(neg_equality,0)), equa, cond); - else { - ast left, left_term, middle, right_term, right; - left = get_left_movers(equa,lhs,middle,left_term); - middle = get_right_movers(middle,rhs,right,right_term); - ast itp = unmixed_eq2ineq(left_term, right_term, op(arg(neg_equality,0)), middle, cond); - // itp = my_implies(cond,itp); - itp = add_mixed_eq2ineq(lhs, left_term, left, itp); - itp = add_mixed_eq2ineq(right_term, rhs, right, itp); - return itp; - } - } - } - throw iz3_exception("help!"); - } - - void reverse_modpon(std::vector &args){ - std::vector sargs(1); sargs[0] = args[1]; - args[1] = simplify_symm(sargs); - if(is_equivrel_chain(args[2])) - args[1] = down_chain(args[1]); - std::swap(args[0],args[2]); - } - - ast simplify_rotate_modpon(const ast &pl, const ast &neg_equality, const ast &pf){ - std::vector args; args.resize(3); - args[0] = arg(pf,0); - args[1] = arg(pf,1); - args[2] = arg(pf,2); - if(pl == args[0]) - reverse_modpon(args); - if(pl == args[2]){ - ast cond = mk_true(); - ast chain = simplify_modpon_fwd(args, cond); - return my_implies(cond,chain); - } - throw cannot_simplify(); - } - - ast get_ineq_rhs(const ast &ineq2){ - opr o = op(ineq2); - if(o == Implies) - return get_ineq_rhs(arg(ineq2,1)); - else if(o == Leq || o == Lt) - return arg(ineq2,1); - throw cannot_simplify(); - } - - ast simplify_rotate_cong(const ast &pl, const ast &neg_equality, const ast &pf){ - if(pl == arg(pf,2)){ - if(op(arg(pf,0)) == True) - return mk_true(); - rational pos; - if(is_numeral(arg(pf,1),pos)){ - int ipos = pos.get_unsigned(); - ast cond = mk_true(); - ast equa = sep_cond(arg(pf,0),cond); -#if 0 - if(op(equa) == Equal){ - ast pe = mk_not(neg_equality); - ast lhs = subst_in_arg_pos(ipos,arg(equa,0),arg(pe,0)); - ast rhs = subst_in_arg_pos(ipos,arg(equa,1),arg(pe,1)); - ast res = make(Equal,lhs,rhs); - return my_implies(cond,res); - } -#endif - ast res = chain_pos_add(ipos,equa); - return my_implies(cond,res); - } - } - throw cannot_simplify(); - } - - ast simplify_symm(const std::vector &args){ - if(op(args[0]) == True) - return mk_true(); - ast cond = mk_true(); - ast equa = sep_cond(args[0],cond); - if(is_equivrel_chain(equa)) - return my_implies(cond,reverse_chain(equa)); - if(is_negation_chain(equa)) - return commute_negation_chain(equa); - throw cannot_simplify(); - } - - ast simplify_modpon_fwd(const std::vector &args, ast &cond){ - ast P = sep_cond(args[0],cond); - ast PeqQ = sep_cond(args[1],cond); - ast chain; - if(is_equivrel_chain(P)){ - try { - ast split[2]; - split_chain(PeqQ,split); - chain = reverse_chain(split[0]); - chain = concat_rewrite_chain(chain,P); - chain = concat_rewrite_chain(chain,split[1]); - } - catch(const cannot_split &){ - static int this_count = 0; - this_count++; - ast tail, pref = get_head_chain(PeqQ,tail,false); // pref is x=y, tail is x=y -> x'=y' - ast split[2]; split_chain(tail,split); // rewrites from x to x' and y to y' - ast head = chain_last(pref); - ast prem = make_rewrite(rewrite_side(head),top_pos,rewrite_cond(head),make(Iff,mk_true(),mk_not(rewrite_lhs(head)))); - ast back_chain = chain_cons(mk_true(),prem); - back_chain = concat_rewrite_chain(back_chain,chain_pos_add(0,reverse_chain(chain_rest(pref)))); - ast cond = contra_chain(back_chain,P); - if(is_rewrite_side(LitA,head)) - cond = mk_not(cond); - ast fwd_rewrite = make_rewrite(rewrite_side(head),top_pos,cond,rewrite_rhs(head)); - P = chain_cons(mk_true(),fwd_rewrite); - chain = reverse_chain(split[0]); - chain = concat_rewrite_chain(chain,P); - chain = concat_rewrite_chain(chain,split[1]); - } - } - else { // if not an equivalence, must be of form T <-> pred - chain = concat_rewrite_chain(P,PeqQ); - } - return chain; - } - - struct subterm_normals_failed: public iz3_exception { - subterm_normals_failed(): iz3_exception("subterm_normals_failed") {} - }; - - void get_subterm_normals(const ast &ineq1, const ast &ineq2, const ast &chain, ast &normals, - const ast &pos, hash_set &memo, ast &Aproves, ast &Bproves){ - opr o1 = op(ineq1); - opr o2 = op(ineq2); - if(o1 == Not || o1 == Leq || o1 == Lt || o1 == Geq || o1 == Gt || o1 == Plus || o1 == Times){ - int n = num_args(ineq1); - if(o2 != o1 || num_args(ineq2) != n) - throw iz3_exception("bad inequality rewriting"); - for(int i = 0; i < n; i++){ - ast new_pos = add_pos_to_end(pos,i); - get_subterm_normals(arg(ineq1,i), arg(ineq2,i), chain, normals, new_pos, memo, Aproves, Bproves); - } - } - else if(get_term_type(ineq2) == LitMixed){ - if(memo.find(ineq2) == memo.end()){ - memo.insert(ineq2); - ast sub_chain = extract_rewrites(chain,pos); - if(is_true(sub_chain)) - throw iz3_exception("bad inequality rewriting"); - ast new_normal = make_normal_step(ineq2,ineq1,reverse_chain(sub_chain)); - normals = merge_normal_chains(normals,cons_normal(new_normal,mk_true()), Aproves, Bproves); - } - } - else if(!(ineq1 == ineq2)) - throw subterm_normals_failed(); - } - - ast rewrites_to_normals(const ast &ineq1, const ast &chain, ast &normals, ast &Aproves, ast &Bproves, ast &Aineqs){ - if(is_true(chain)) - return ineq1; - ast last = chain_last(chain); - ast rest = chain_rest(chain); - ast new_ineq1 = rewrites_to_normals(ineq1, rest, normals, Aproves, Bproves, Aineqs); - ast p1 = rewrite_pos(last); - ast term1; - ast coeff = arith_rewrite_coeff(new_ineq1,p1,term1); - ast res = subst_in_pos(new_ineq1,rewrite_pos(last),rewrite_rhs(last)); - ast rpos; - pos_diff(p1,rewrite_pos(last),rpos); - ast term2 = subst_in_pos(term1,rpos,rewrite_rhs(last)); - if(get_term_type(term1) != LitMixed && get_term_type(term2) != LitMixed){ - if(is_rewrite_side(LitA,last)) - linear_comb(Aineqs,coeff,make(Leq,make_int(rational(0)),make(Sub,term2,term1))); - } - else { - ast pf = extract_rewrites(make(concat,mk_true(),last),p1); - ast new_normal = fix_normal(term1,term2,pf); - normals = merge_normal_chains(normals,cons_normal(new_normal,mk_true()), Aproves, Bproves); - } - return res; - } - - ast arith_rewrite_coeff(const ast &ineq, ast &p1, ast &term){ - ast coeff = make_int(rational(1)); - if(p1 == top_pos){ - term = ineq; - return coeff; - } - int argpos = pos_arg(p1); - opr o = op(ineq); - switch(o){ - case Leq: - case Lt: - coeff = argpos ? make_int(rational(1)) : make_int(rational(-1)); - break; - case Geq: - case Gt: - coeff = argpos ? make_int(rational(-1)) : make_int(rational(1)); - break; - case Not: - coeff = make_int(rational(-1)); - case Plus: - break; - case Times: - coeff = arg(ineq,0); - break; - default: - p1 = top_pos; - term = ineq; - return coeff; - } - p1 = arg(p1,1); - ast res = arith_rewrite_coeff(arg(ineq,argpos),p1,term); - p1 = pos_add(argpos,p1); - return coeff == make_int(rational(1)) ? res : make(Times,coeff,res); - } - - ast rewrite_chain_to_normal_ineq(const ast &chain, ast &Aproves, ast &Bproves){ - ast tail, pref = get_head_chain(chain,tail,false); // pref is x=y, tail is x=y -> x'=y' - ast head = chain_last(pref); - ast ineq1 = rewrite_rhs(head); - ast ineq2 = apply_rewrite_chain(ineq1,tail); - ast nc = mk_true(); - hash_set memo; - ast itp = make(Leq,make_int(rational(0)),make_int(rational(0))); - ast Aproves_save = Aproves, Bproves_save = Bproves; try { - get_subterm_normals(ineq1,ineq2,tail,nc,top_pos,memo, Aproves, Bproves); - } - catch (const subterm_normals_failed &){ Aproves = Aproves_save; Bproves = Bproves_save; nc = mk_true(); - rewrites_to_normals(ineq1, tail, nc, Aproves, Bproves, itp); - } - if(is_rewrite_side(LitA,head)){ - linear_comb(itp,make_int("1"),ineq1); // make sure it is normal form - //itp = ineq1; - ast mc = z3_simplify(chain_side_proves(LitB,pref)); - Bproves = my_and(Bproves,mc); - } - else { - ast mc = z3_simplify(chain_side_proves(LitA,pref)); - Aproves = my_and(Aproves,mc); - } - if(is_true(nc)) - return itp; - return make_normal(itp,nc); - } - - /* Given a chain rewrite chain deriving not P and a rewrite chain deriving P, return an interpolant. */ - ast contra_chain(const ast &neg_chain, const ast &pos_chain){ - // equality is a special case. we use the derivation of x=y to rewrite not(x=y) to not(y=y) - if(is_equivrel_chain(pos_chain)){ - ast tail, pref = get_head_chain(neg_chain,tail); // pref is not(x=y), tail is not(x,y) -> not(x',y') - ast split[2]; split_chain(down_chain(tail),split); // rewrites from x to x' and y to y' - ast chain = split[0]; - chain = concat_rewrite_chain(chain,pos_chain); // rewrites from x to y' - chain = concat_rewrite_chain(chain,reverse_chain(split[1])); // rewrites from x to y - chain = concat_rewrite_chain(pref,chain_pos_add(0,chain_pos_add(0,chain))); // rewrites t -> not(y=y) - ast head = chain_last(pref); - if(is_rewrite_side(LitB,head)){ - ast condition = chain_conditions(LitB,chain); - return my_and(my_implies(chain_conditions(LitA,chain),chain_formulas(LitA,chain)),condition); - } - else { - ast condition = chain_conditions(LitA,chain); - return my_and(chain_conditions(LitB,chain),my_implies(condition,mk_not(chain_formulas(LitB,chain)))); - } - // ast chain = concat_rewrite_chain(neg_chain,chain_pos_add(0,chain_pos_add(0,pos_chain))); - // return my_and(my_implies(chain_conditions(LitA,chain),chain_formulas(LitA,chain)),chain_conditions(LitB,chain)); - } - // otherwise, we reverse the derivation of t = P and use it to rewrite not(P) to not(t) - ast chain = concat_rewrite_chain(neg_chain,chain_pos_add(0,reverse_chain(pos_chain))); - return my_and(my_implies(chain_conditions(LitA,chain),chain_formulas(LitA,chain)),chain_conditions(LitB,chain)); - } - - ast simplify_modpon(const std::vector &args){ - ast Aproves = mk_true(), Bproves = mk_true(); - ast chain = simplify_modpon_fwd(args,Bproves); - ast Q2 = destruct_cond_ineq(args[2],Aproves,Bproves); - ast interp; - if(is_normal_ineq(Q2)){ // inequalities are special - ast nQ2 = rewrite_chain_to_normal_ineq(chain,Aproves,Bproves); - sum_cond_ineq(nQ2,make_int(rational(1)),Q2,Aproves,Bproves); - interp = normalize(nQ2); - } - else - interp = is_negation_chain(chain) ? contra_chain(chain,Q2) : contra_chain(Q2,chain); - return my_and(Aproves,my_implies(Bproves,interp)); - } - - - ast simplify_exmid(const std::vector &args){ - if(is_equivrel(args[0])){ - ast Aproves = mk_true(), Bproves = mk_true(); - ast chain = destruct_cond_ineq(args[1],Aproves,Bproves); - ast Q2 = destruct_cond_ineq(args[2],Aproves,Bproves); - ast interp = contra_chain(Q2,chain); - return my_and(Aproves,my_implies(Bproves,interp)); - } - throw iz3_exception("bad exmid"); - } - - ast simplify_cong(const std::vector &args){ - ast Aproves = mk_true(), Bproves = mk_true(); - ast chain = destruct_cond_ineq(args[0],Aproves,Bproves); - rational pos; - if(is_numeral(args[1],pos)){ - int ipos = pos.get_unsigned(); - chain = chain_pos_add(ipos,chain); - ast Q2 = destruct_cond_ineq(args[2],Aproves,Bproves); - ast interp = contra_chain(Q2,chain); - return my_and(Aproves,my_implies(Bproves,interp)); - } - throw iz3_exception("bad cong"); - } - - bool is_equivrel(const ast &p){ - opr o = op(p); - return o == Equal || o == Iff; - } - - struct rewrites_failed: public iz3_exception { - rewrites_failed(): iz3_exception("rewrites_failed") {} - }; - - /* Suppose p in Lang(B) and A |- p -> q and B |- q -> r. Return a z in Lang(B) such that - B |- p -> z and A |- z -> q. Collect any side conditions in "rules". */ - - ast commute_rewrites(const ast &p, const ast &q, const ast &r, ast &rules){ - if(q == r) - return p; - if(p == q) - return r; - else { - ast rew = make(Equal,q,r); - if(get_term_type(rew) == LitB){ - apply_common_rewrites(p,p,q,rules); // A rewrites must be over comon vocab - return r; - } - } - if(sym(p) != sym(q) || sym(q) != sym(r)) - throw rewrites_failed(); - int nargs = num_args(p); - if(nargs != num_args(q) || nargs != num_args(r)) - throw rewrites_failed(); - std::vector args; args.resize(nargs); - for(int i = 0; i < nargs; i++) - args[i] = commute_rewrites(arg(p,i),arg(q,i),arg(r,i),rules); - return clone(p,args); - } - - ast apply_common_rewrites(const ast &p, const ast &q, const ast &r, ast &rules){ - if(q == r) - return p; - ast rew = make(Equal,q,r); - if(term_common(rew)){ - if(p != q) - throw rewrites_failed(); - rules = my_and(rules,rew); - return r; - } - if(sym(p) != sym(q) || sym(q) != sym(r)) - return p; - int nargs = num_args(p); - if(nargs != num_args(q) || nargs != num_args(r)) - return p; - std::vector args; args.resize(nargs); - for(int i = 0; i < nargs; i++) - args[i] = apply_common_rewrites(arg(p,i),arg(q,i),arg(r,i),rules); - return clone(p,args); - } - - ast apply_all_rewrites(const ast &p, const ast &q, const ast &r){ - if(q == r) - return p; - if(p == q) - return r; - if(sym(p) != sym(q) || sym(q) != sym(r)) - throw rewrites_failed(); - int nargs = num_args(p); - if(nargs != num_args(q) || nargs != num_args(r)) - throw rewrites_failed(); - std::vector args; args.resize(nargs); - for(int i = 0; i < nargs; i++) - args[i] = apply_all_rewrites(arg(p,i),arg(q,i),arg(r,i)); - return clone(p,args); - } - - ast delta(const ast &x, const ast &y){ - if(op(x) != op(y) || (op(x) == Uninterpreted && sym(x) != sym(y)) || num_args(x) != num_args(y)) - return make(Equal,x,y); - ast res = mk_true(); - int nargs = num_args(x); - for(int i = 0; i < nargs; i++) - res = my_and(res,delta(arg(x,i),arg(y,i))); - return res; - } - - bool diff_rec(LitType t, const ast &p, const ast &q, ast &pd, ast &qd){ - if(p == q) - return false; - if(term_in_vocab(t,p) && term_in_vocab(t,q)){ - pd = p; - qd = q; - return true; - } - else { - if(sym(p) != sym(q)) return false; - int nargs = num_args(p); - if(num_args(q) != nargs) return false; - for(int i = 0; i < nargs; i++) - if(diff_rec(t,arg(p,i),arg(q,i),pd,qd)) - return true; - return false; - } - } - - void diff(LitType t, const ast &p, const ast &q, ast &pd, ast &qd){ - if(!diff_rec(t,p,q,pd,qd)) - throw cannot_simplify(); - } - - bool apply_diff_rec(LitType t, const ast &inp, const ast &p, const ast &q, ast &out){ - if(p == q) - return false; - if(term_in_vocab(t,p) && term_in_vocab(t,q)){ - if(inp != p) - throw cannot_simplify(); - out = q; - return true; - } - else { - int nargs = num_args(p); - if(sym(p) != sym(q)) throw cannot_simplify(); - if(num_args(q) != nargs) throw cannot_simplify(); - if(sym(p) != sym(inp)) throw cannot_simplify(); - if(num_args(inp) != nargs) throw cannot_simplify(); - for(int i = 0; i < nargs; i++) - if(apply_diff_rec(t,arg(inp,i),arg(p,i),arg(q,i),out)) - return true; - return false; - } - } - - ast apply_diff(LitType t, const ast &inp, const ast &p, const ast &q){ - ast out; - if(!apply_diff_rec(t,inp,p,q,out)) - throw cannot_simplify(); - return out; - } - - bool merge_A_rewrites(const ast &A1, const ast &A2, ast &merged) { - if(arg(A1,1) == arg(A2,0)){ - merged = make(op(A1),arg(A1,0),arg(A2,1)); - return true; - } - ast diff1l, diff1r, diff2l, diff2r,diffBl,diffBr; - diff(LitA,arg(A1,0),arg(A1,1),diff1l,diff1r); - diff(LitA,arg(A2,0),arg(A2,1),diff2l,diff2r); - diff(LitB,arg(A1,1),arg(A2,0),diffBl,diffBr); - if(!term_common(diff2l) && !term_common(diffBr)){ - ast A1r = apply_diff(LitB,arg(A2,1),arg(A2,0),arg(A1,1)); - merged = make(op(A1),arg(A1,0),A1r); - return true; - } - if(!term_common(diff1r) && !term_common(diffBl)){ - ast A2l = apply_diff(LitB,arg(A1,0),arg(A1,1),arg(A2,0)); - merged = make(op(A1),A2l,arg(A2,1)); - return true; - } - return false; - } - - void collect_A_rewrites(const ast &t, std::vector &res){ - if(is_true(t)) - return; - if(sym(t) == concat){ - res.push_back(arg(t,0)); - collect_A_rewrites(arg(t,0),res); - return; - } - res.push_back(t); - } - - ast concat_A_rewrites(const std::vector &rew){ - if(rew.size() == 0) - return mk_true(); - ast res = rew[0]; - for(unsigned i = 1; i < rew.size(); i++) - res = make(concat,res,rew[i]); - return res; - } - - ast merge_concat_rewrites(const ast &A1, const ast &A2){ - std::vector rew; - collect_A_rewrites(A1,rew); - int first = rew.size(), last = first; // range that might need merging - collect_A_rewrites(A2,rew); - while(first > 0 && first < (int)rew.size() && first <= last){ - ast merged; - if(merge_A_rewrites(rew[first-1],rew[first],merged)){ - rew[first] = merged; - first--; - rew.erase(rew.begin()+first); - last--; - if(first >= last) last = first+1; - } - else - first++; - } - return concat_A_rewrites(rew); - } - - ast sep_cond(const ast &t, ast &cond){ - if(op(t) == Implies){ - cond = my_and(cond,arg(t,0)); - return arg(t,1); - } - return t; - } - - - /* operations on term positions */ - - /** Finds the difference between two positions. If p1 < p2 (p1 is a - position below p2), returns -1 and sets diff to p2-p1 (the psath - from position p2 to position p1). If p2 < p1 (p2 is a position - below p1), returns 1 and sets diff to p1-p2 (the psath from - position p1 to position p2). If equal, return 0 and set diff to - top_pos. Else (if p1 and p2 are independent) returns 2 and - leaves diff unchanged. */ - - int pos_diff(const ast &p1, const ast &p2, ast &diff){ - if(p1 == top_pos && p2 != top_pos){ - diff = p2; - return 1; - } - if(p2 == top_pos && p1 != top_pos){ - diff = p1; - return -1; - } - if(p1 == top_pos && p2 == top_pos){ - diff = p1; - return 0; - } - if(arg(p1,0) == arg(p2,0)) // same argument position, recur - return pos_diff(arg(p1,1),arg(p2,1),diff); - return 2; - } - - /* return the position of pos in the argth argument */ - ast pos_add(int arg, const ast &pos){ - return make(add_pos,make_int(rational(arg)),pos); - } - - ast add_pos_to_end(const ast &pos, int i){ - if(pos == top_pos) - return pos_add(i,pos); - return make(add_pos,arg(pos,0),add_pos_to_end(arg(pos,1),i)); - } - - /* return the argument number of position, if not top */ - int pos_arg(const ast &pos){ - rational r; - if(is_numeral(arg(pos,0),r)) - return r.get_unsigned(); - throw iz3_exception("bad position!"); - } - - /* substitute y into position pos in x */ - ast subst_in_pos(const ast &x, const ast &pos, const ast &y){ - if(pos == top_pos) - return y; - int p = pos_arg(pos); - int nargs = num_args(x); - if(p >= 0 && p < nargs){ - std::vector args(nargs); - for(int i = 0; i < nargs; i++) - args[i] = i == p ? subst_in_pos(arg(x,i),arg(pos,1),y) : arg(x,i); - return clone(x,args); - } - throw iz3_exception("bad term position!"); - } - - ast diff_chain(LitType t, const ast &pos, const ast &x, const ast &y, const ast &prefix){ - int nargs = num_args(x); - if(x == y) return prefix; - if(sym(x) == sym(y) && nargs == num_args(y)){ - ast res = prefix; - for(int i = 0; i < nargs; i++) - res = diff_chain(t,pos_add(i,pos),arg(x,i),arg(y,i),res); - return res; - } - return chain_cons(prefix,make_rewrite(t,pos,mk_true(),make_equiv_rel(x,y))); - } - - /* operations on rewrites */ - ast make_rewrite(LitType t, const ast &pos, const ast &cond, const ast &equality){ -#if 0 - if(pos == top_pos && op(equality) == Iff && !is_true(arg(equality,0))) - throw iz3_exception("bad rewrite"); -#endif - if(!is_equivrel(equality)) - throw iz3_exception("bad rewrite"); - return make(t == LitA ? rewrite_A : rewrite_B, pos, cond, equality); - } - - ast rewrite_pos(const ast &rew){ - return arg(rew,0); - } - - ast rewrite_cond(const ast &rew){ - return arg(rew,1); - } - - ast rewrite_equ(const ast &rew){ - return arg(rew,2); - } - - ast rewrite_lhs(const ast &rew){ - return arg(arg(rew,2),0); - } - - ast rewrite_rhs(const ast &rew){ - return arg(arg(rew,2),1); - } - - /* operations on rewrite chains */ - - ast chain_cons(const ast &chain, const ast &elem){ - return make(concat,chain,elem); - } - - ast chain_rest(const ast &chain){ - return arg(chain,0); - } - - ast chain_last(const ast &chain){ - return arg(chain,1); - } - - ast rewrite_update_rhs(const ast &rew, const ast &pos, const ast &new_rhs, const ast &new_cond){ - ast foo = subst_in_pos(rewrite_rhs(rew),pos,new_rhs); - ast equality = arg(rew,2); - return make(sym(rew),rewrite_pos(rew),my_and(rewrite_cond(rew),new_cond),make(op(equality),arg(equality,0),foo)); - } - - ast rewrite_update_lhs(const ast &rew, const ast &pos, const ast &new_lhs, const ast &new_cond){ - ast foo = subst_in_pos(rewrite_lhs(rew),pos,new_lhs); - ast equality = arg(rew,2); - return make(sym(rew),rewrite_pos(rew),my_and(rewrite_cond(rew),new_cond),make(op(equality),foo,arg(equality,1))); - } - - bool is_common_rewrite(const ast &rew){ - return term_common(arg(rew,2)); - } - - bool is_right_mover(const ast &rew){ - return term_common(rewrite_lhs(rew)) && !term_common(rewrite_rhs(rew)); - } - - bool is_left_mover(const ast &rew){ - return term_common(rewrite_rhs(rew)) && !term_common(rewrite_lhs(rew)); - } - - bool same_side(const ast &rew1, const ast &rew2){ - return sym(rew1) == sym(rew2); - } - - bool is_rewrite_side(LitType t, const ast &rew){ - if(t == LitA) - return sym(rew) == rewrite_A; - return sym(rew) == rewrite_B; - } - - LitType rewrite_side(const ast &rew){ - return (sym(rew) == rewrite_A) ? LitA : LitB; - } - - ast rewrite_to_formula(const ast &rew){ - return my_implies(arg(rew,1),arg(rew,2)); - } - - // make rewrite rew condition on rewrite cond - ast rewrite_conditional(const ast &cond, const ast &rew){ - ast cf = rewrite_to_formula(cond); - return make(sym(rew),arg(rew,0),my_and(arg(rew,1),cf),arg(rew,2)); - } - - ast reverse_rewrite(const ast &rew){ - ast equ = arg(rew,2); - return make(sym(rew),arg(rew,0),arg(rew,1),make(op(equ),arg(equ,1),arg(equ,0))); - } - - ast rewrite_pos_add(int apos, const ast &rew){ - return make(sym(rew),pos_add(apos,arg(rew,0)),arg(rew,1),arg(rew,2)); - } - - ast rewrite_pos_set(const ast &pos, const ast &rew){ - return make(sym(rew),pos,arg(rew,1),arg(rew,2)); - } - - ast rewrite_up(const ast &rew){ - return make(sym(rew),arg(arg(rew,0),1),arg(rew,1),arg(rew,2)); - } - - /** Adds a rewrite to a chain of rewrites, keeping the chain in - normal form. An empty chain is represented by true.*/ - - ast add_rewrite_to_chain(const ast &chain, const ast &rewrite){ - if(is_true(chain)) - return chain_cons(chain,rewrite); - ast last = chain_last(chain); - ast rest = chain_rest(chain); - if(same_side(last,rewrite)){ - ast p1 = rewrite_pos(last); - ast p2 = rewrite_pos(rewrite); - ast diff; - switch(pos_diff(p1,p2,diff)){ - case 1: { - ast absorb = rewrite_update_rhs(last,diff,rewrite_rhs(rewrite),rewrite_cond(rewrite)); - return add_rewrite_to_chain(rest,absorb); - } - case 0: - case -1: { - ast absorb = rewrite_update_lhs(rewrite,diff,rewrite_lhs(last),rewrite_cond(last)); - return add_rewrite_to_chain(rest,absorb); - } - default: {// independent case - bool rm = is_right_mover(last); - bool lm = is_left_mover(rewrite); - if((lm && !rm) || (rm && !lm)) - return chain_swap(rest,last,rewrite); - } - } - } - else { - if(is_left_mover(rewrite)){ - if(is_common_rewrite(last)) - return add_rewrite_to_chain(chain_cons(rest,flip_rewrite(last)),rewrite); - if(!is_left_mover(last)) - return chain_swap(rest,last,rewrite); - } - if(is_right_mover(last)){ - if(is_common_rewrite(rewrite)) - return add_rewrite_to_chain(chain,flip_rewrite(rewrite)); - if(!is_right_mover(rewrite)) - return chain_swap(rest,last,rewrite); - } - } - return chain_cons(chain,rewrite); - } - - ast chain_swap(const ast &rest, const ast &last, const ast &rewrite){ - return chain_cons(add_rewrite_to_chain(rest,rewrite),last); - } - - ast flip_rewrite(const ast &rew){ - symb flip_sym = (sym(rew) == rewrite_A) ? rewrite_B : rewrite_A; - ast cf = rewrite_to_formula(rew); - return make(flip_sym,arg(rew,0),my_implies(arg(rew,1),cf),arg(rew,2)); - } - - /** concatenates two rewrite chains, keeping result in normal form. */ - - ast concat_rewrite_chain(const ast &chain1, const ast &chain2){ - if(is_true(chain2)) return chain1; - if(is_true(chain1)) return chain2; - ast foo = concat_rewrite_chain(chain1,chain_rest(chain2)); - return add_rewrite_to_chain(foo,chain_last(chain2)); - } - - /** reverse a chain of rewrites */ - - ast reverse_chain_rec(const ast &chain, const ast &prefix){ - if(is_true(chain)) - return prefix; - ast last = reverse_rewrite(chain_last(chain)); - ast rest = chain_rest(chain); - return reverse_chain_rec(rest,chain_cons(prefix,last)); - } - - ast reverse_chain(const ast &chain){ - return reverse_chain_rec(chain,mk_true()); - } - - bool is_equivrel_chain(const ast &chain){ - if(is_true(chain)) - return true; - ast last = chain_last(chain); - ast rest = chain_rest(chain); - if(is_true(rest)) - return !is_true(rewrite_lhs(last)); - return is_equivrel_chain(rest); - } - - bool is_negation_chain(const ast &chain){ - if(is_true(chain)) - return false; - ast last = chain_last(chain); - ast rest = chain_rest(chain); - if(is_true(rest)) - return op(rewrite_rhs(last)) == Not; - return is_negation_chain(rest); - } - - ast commute_negation_chain(const ast &chain){ - if(is_true(chain)) - return chain; - ast last = chain_last(chain); - ast rest = chain_rest(chain); - if(is_true(rest)){ - ast old = rewrite_rhs(last); - if(!(op(old) == Not)) - throw iz3_exception("bad negative equality chain"); - ast equ = arg(old,0); - if(!is_equivrel(equ)) - throw iz3_exception("bad negative equality chain"); - last = rewrite_update_rhs(last,top_pos,make(Not,make(op(equ),arg(equ,1),arg(equ,0))),make(True)); - return chain_cons(rest,last); - } - ast pos = rewrite_pos(last); - if(pos == top_pos) - throw iz3_exception("bad negative equality chain"); - int idx = pos_arg(pos); - if(idx != 0) - throw iz3_exception("bad negative equality chain"); - pos = arg(pos,1); - if(pos == top_pos){ - ast lhs = rewrite_lhs(last); - ast rhs = rewrite_rhs(last); - if(op(lhs) != Equal || op(rhs) != Equal) - throw iz3_exception("bad negative equality chain"); - last = make_rewrite(rewrite_side(last),rewrite_pos(last),rewrite_cond(last), - make(Iff,make(Equal,arg(lhs,1),arg(lhs,0)),make(Equal,arg(rhs,1),arg(rhs,0)))); - } - else { - idx = pos_arg(pos); - if(idx == 0) - idx = 1; - else if(idx == 1) - idx = 0; - else - throw iz3_exception("bad negative equality chain"); - pos = pos_add(0,pos_add(idx,arg(pos,1))); - last = make_rewrite(rewrite_side(last),pos,rewrite_cond(last),rewrite_equ(last)); - } - return chain_cons(commute_negation_chain(rest),last); - } - - // split a rewrite chain into head and tail at last top-level rewrite - ast get_head_chain(const ast &chain, ast &tail, bool is_not = true){ - ast last = chain_last(chain); - ast rest = chain_rest(chain); - ast pos = rewrite_pos(last); - if(pos == top_pos || (is_not && arg(pos,1) == top_pos)){ - tail = mk_true(); - return chain; - } - if(is_true(rest)) - throw iz3_exception("bad rewrite chain"); - ast head = get_head_chain(rest,tail,is_not); - tail = chain_cons(tail,last); - return head; - } - - bool has_mixed_summands(const ast &e){ - if(op(e) == Plus){ - int nargs = num_args(e); - for(int i = 0; i < nargs; i++) - if(has_mixed_summands(arg(e,i))) - return true; - return false; - } - return get_term_type(e) == LitMixed; - } - - // split a rewrite chain into head and tail at last sum with no mixed sumands - ast get_right_movers(const ast &chain, const ast &rhs, ast &tail, ast &mid){ - if(is_true(chain) || !has_mixed_summands(rhs)){ - mid = rhs; - tail = mk_true(); - return chain; - } - ast last = chain_last(chain); - ast rest = chain_rest(chain); - ast mm = subst_in_pos(rhs,rewrite_pos(last),rewrite_lhs(last)); - ast res = get_right_movers(rest,mm,tail,mid); - tail = chain_cons(tail,last); - return res; - } - - // split a rewrite chain into head and tail at first sum with no mixed sumands - ast get_left_movers(const ast &chain, const ast &lhs, ast &tail, ast &mid){ - if(is_true(chain)){ - mid = lhs; - if(!has_mixed_summands(lhs)){ - tail = mk_true(); - return chain; - } - return ast(); - } - ast last = chain_last(chain); - ast rest = chain_rest(chain); - ast res = get_left_movers(rest,lhs,tail,mid); - if(res.null()){ - mid = subst_in_pos(mid,rewrite_pos(last),rewrite_rhs(last)); - if(get_term_type(mid) != LitMixed){ - tail = mk_true(); - return chain; - } - return ast(); - } - tail = chain_cons(tail,last); - return res; - } - - - struct cannot_split: public iz3_exception { - cannot_split(): iz3_exception("cannot_split") {} - }; - - /** Split a chain of rewrites two chains, operating on positions 0 and 1. - Fail if any rewrite in the chain operates on top position. */ - void split_chain_rec(const ast &chain, ast *res){ - if(is_true(chain)) - return; - ast last = chain_last(chain); - ast rest = chain_rest(chain); - split_chain_rec(rest,res); - ast pos = rewrite_pos(last); - if(pos == top_pos){ - if(rewrite_lhs(last) == rewrite_rhs(last)) - return; // skip if it's a noop - throw cannot_split(); - } - int arg = pos_arg(pos); - if(arg<0 || arg > 1) - throw cannot_split(); - res[arg] = chain_cons(res[arg],rewrite_up(last)); - } - - void split_chain(const ast &chain, ast *res){ - res[0] = res[1] = mk_true(); - split_chain_rec(chain,res); - } - - ast extract_rewrites(const ast &chain, const ast &pos){ - if(is_true(chain)) - return chain; - ast last = chain_last(chain); - ast rest = chain_rest(chain); - ast new_rest = extract_rewrites(rest,pos); - ast p1 = rewrite_pos(last); - ast diff; - switch(pos_diff(p1,pos,diff)){ - case -1: { - ast new_last = rewrite_pos_set(diff, last); - return chain_cons(new_rest,new_last); - } - case 1: - if(rewrite_lhs(last) != rewrite_rhs(last)) - throw iz3_exception("bad rewrite chain"); - break; - default:; - } - return new_rest; - } - - ast down_chain(const ast &chain){ - ast split[2]; - split_chain(chain,split); - return split[0]; - } - - ast chain_conditions(LitType t, const ast &chain){ - if(is_true(chain)) - return mk_true(); - ast last = chain_last(chain); - ast rest = chain_rest(chain); - ast cond = chain_conditions(t,rest); - if(is_rewrite_side(t,last)) - cond = my_and(cond,rewrite_cond(last)); - return cond; - } - - ast chain_formulas(LitType t, const ast &chain){ - if(is_true(chain)) - return mk_true(); - ast last = chain_last(chain); - ast rest = chain_rest(chain); - ast cond = chain_formulas(t,rest); - if(is_rewrite_side(t,last)) - cond = my_and(cond,rewrite_equ(last)); - return cond; - } - - - bool rewrites_from_to(const ast &chain, const ast &lhs, const ast &rhs){ - if(is_true(chain)) - return lhs == rhs; - ast last = chain_last(chain); - ast rest = chain_rest(chain); - ast mid = subst_in_pos(rhs,rewrite_pos(last),rewrite_lhs(last)); - return rewrites_from_to(rest,lhs,mid); - } - - struct bad_ineq_inference: public iz3_exception { - bad_ineq_inference(): iz3_exception("bad_ineq_inference") {} - }; - - ast chain_ineqs(opr comp_op, LitType t, const ast &chain, const ast &lhs, const ast &rhs){ - if(is_true(chain)){ - if (lhs != rhs) { - TRACE("duality", print_expr(tout, lhs); tout << " "; print_expr(tout, rhs); tout << "\n";); - throw bad_ineq_inference(); - } - return make(Leq,make_int(rational(0)),make_int(rational(0))); - } - TRACE("duality", print_expr(tout, chain); print_expr(tout << "\n", lhs); tout << " "; print_expr(tout, rhs); tout << "\n";); - ast last = chain_last(chain); - ast rest = chain_rest(chain); - ast mid = subst_in_pos(rhs,rewrite_pos(last),rewrite_lhs(last)); - ast cond = chain_ineqs(comp_op,t,rest,lhs,mid); - if(is_rewrite_side(t,last)){ - ast diff; - if(comp_op == Leq) diff = make(Sub,rhs,mid); - else diff = make(Sub,mid,rhs); - ast foo = make(Leq,make_int("0"),z3_simplify(diff)); - if(is_true(cond)) - cond = foo; - else { - linear_comb(cond,make_int(rational(1)),foo); - cond = simplify_ineq(cond); - } - } - return cond; - } - - ast ineq_to_lhs(const ast &ineq){ - ast s = make(Leq,make_int(rational(0)),make_int(rational(0))); - linear_comb(s,make_int(rational(1)),ineq); - return simplify_ineq(s); - } - - void eq_from_ineq(const ast &ineq, ast &lhs, ast &rhs){ - // ast s = ineq_to_lhs(ineq); - // ast srhs = arg(s,1); - ast srhs = arg(ineq,0); - if(op(srhs) == Plus && num_args(srhs) == 2 && arg(ineq,1) == make_int(rational(0))){ - lhs = arg(srhs,0); - rhs = arg(srhs,1); - // if(op(lhs) == Times) - // std::swap(lhs,rhs); - if(op(rhs) == Times){ - rhs = arg(rhs,1); - // if(op(ineq) == Leq) - // std::swap(lhs,rhs); - return; - } - } - if(op(ineq) == Leq || op(ineq) == Geq){ - lhs = srhs; - rhs = arg(ineq,1); - return; - } - throw iz3_exception("bad ineq"); - } - - ast chain_pos_add(int arg, const ast &chain){ - if(is_true(chain)) - return mk_true(); - ast last = rewrite_pos_add(arg,chain_last(chain)); - ast rest = chain_pos_add(arg,chain_rest(chain)); - return chain_cons(rest,last); - } - - ast apply_rewrite_chain(const ast &t, const ast &chain){ - if(is_true(chain)) - return t; - ast last = chain_last(chain); - ast rest = chain_rest(chain); - ast mid = apply_rewrite_chain(t,rest); - ast res = subst_in_pos(mid,rewrite_pos(last),rewrite_rhs(last)); - return res; - } - - ast drop_rewrites(LitType t, const ast &chain, ast &remainder){ - if(!is_true(chain)){ - ast last = chain_last(chain); - ast rest = chain_rest(chain); - if(is_rewrite_side(t,last)){ - ast res = drop_rewrites(t,rest,remainder); - remainder = chain_cons(remainder,last); - return res; - } - } - remainder = mk_true(); - return chain; - } - - // Normalization chains - - ast cons_normal(const ast &first, const ast &rest){ - return make(normal_chain,first,rest); - } - - ast normal_first(const ast &t){ - return arg(t,0); - } - - ast normal_rest(const ast &t){ - return arg(t,1); - } - - ast normal_lhs(const ast &t){ - return arg(arg(t,0),0); - } - - ast normal_rhs(const ast &t){ - return arg(arg(t,0),1); - } - - ast normal_proof(const ast &t){ - return arg(t,1); - } - - ast make_normal_step(const ast &lhs, const ast &rhs, const ast &proof){ - return make(normal_step,make_equiv(lhs,rhs),proof); - } - - ast make_normal(const ast &ineq, const ast &nrml){ - if(!is_ineq(ineq)) - throw iz3_exception("what?"); - return make(normal,ineq,nrml); - } - - ast fix_normal(const ast &lhs, const ast &rhs, const ast &proof){ - LitType lhst = get_term_type(lhs); - LitType rhst = get_term_type(rhs); - if(lhst == LitMixed && (rhst != LitMixed || ast_id(lhs) < ast_id(rhs))) - return make_normal_step(lhs,rhs,proof); - if(rhst == LitMixed && (lhst != LitMixed || ast_id(rhs) < ast_id(lhs))) - return make_normal_step(rhs,lhs,reverse_chain(proof)); - throw iz3_exception("help!"); - } - - ast chain_side_proves(LitType side, const ast &chain){ - LitType other_side = side == LitA ? LitB : LitA; - return my_and(chain_conditions(other_side,chain),my_implies(chain_conditions(side,chain),chain_formulas(side,chain))); - } - - // Merge two normalization chains - ast merge_normal_chains_rec(const ast &chain1, const ast &chain2, hash_map &trans, ast &Aproves, ast &Bproves){ - if(is_true(chain1)) - return chain2; - if(is_true(chain2)) - return chain1; - ast f1 = normal_first(chain1); - ast f2 = normal_first(chain2); - ast lhs1 = normal_lhs(f1); - ast lhs2 = normal_lhs(f2); - int id1 = ast_id(lhs1); - int id2 = ast_id(lhs2); - if(id1 < id2) - return cons_normal(f1,merge_normal_chains_rec(normal_rest(chain1),chain2,trans,Aproves,Bproves)); - if(id2 < id1) - return cons_normal(f2,merge_normal_chains_rec(chain1,normal_rest(chain2),trans,Aproves,Bproves)); - ast rhs1 = normal_rhs(f1); - ast rhs2 = normal_rhs(f2); - LitType t1 = get_term_type(rhs1); - LitType t2 = get_term_type(rhs2); - int tid1 = ast_id(rhs1); - int tid2 = ast_id(rhs2); - ast pf1 = normal_proof(f1); - ast pf2 = normal_proof(f2); - ast new_normal; - if(t1 == LitMixed && (t2 != LitMixed || tid2 > tid1)){ - ast new_proof = concat_rewrite_chain(reverse_chain(pf1),pf2); - new_normal = f2; - trans[rhs1] = make_normal_step(rhs1,rhs2,new_proof); - } - else if(t2 == LitMixed && (t1 != LitMixed || tid1 > tid2)) - return merge_normal_chains_rec(chain2,chain1,trans,Aproves,Bproves); - else if(t1 == LitA && t2 == LitB){ - ast new_proof = concat_rewrite_chain(reverse_chain(pf1),pf2); - ast Bproof, Aproof = drop_rewrites(LitB,new_proof,Bproof); - ast mcA = chain_side_proves(LitB,Aproof); - Bproves = my_and(Bproves,mcA); - ast mcB = chain_side_proves(LitA,Bproof); - Aproves = my_and(Aproves,mcB); - ast rep = apply_rewrite_chain(rhs1,Aproof); - new_proof = concat_rewrite_chain(pf1,Aproof); - new_normal = make_normal_step(lhs1,rep,new_proof); - ast A_normal = make_normal_step(rhs1,rep,Aproof); - ast res = cons_normal(new_normal,merge_normal_chains_rec(normal_rest(chain1),normal_rest(chain2),trans,Aproves,Bproves)); - res = merge_normal_chains_rec(res,cons_normal(A_normal,make(True)),trans,Aproves,Bproves); - return res; - } - else if(t1 == LitB && t2 == LitA) - return merge_normal_chains_rec(chain2,chain1,trans,Aproves,Bproves); - else if(t1 == LitA) { - ast new_proof = concat_rewrite_chain(reverse_chain(pf1),pf2); - ast mc = chain_side_proves(LitB,new_proof); - Bproves = my_and(Bproves,mc); - new_normal = f1; // choice is arbitrary - } - else { /* t1 = t2 = LitB */ - ast new_proof = concat_rewrite_chain(reverse_chain(pf1),pf2); - ast mc = chain_side_proves(LitA,new_proof); - Aproves = my_and(Aproves,mc); - new_normal = f1; // choice is arbitrary - } - return cons_normal(new_normal,merge_normal_chains_rec(normal_rest(chain1),normal_rest(chain2),trans,Aproves,Bproves)); - } - - ast trans_normal_chain(const ast &chain, hash_map &trans){ - if(is_true(chain)) - return chain; - ast f = normal_first(chain); - ast r = normal_rest(chain); - r = trans_normal_chain(r,trans); - ast rhs = normal_rhs(f); - hash_map::iterator it = trans.find(rhs); - ast new_normal; - if(it != trans.end() && get_term_type(normal_lhs(f)) == LitMixed){ - const ast &f2 = it->second; - ast pf = concat_rewrite_chain(normal_proof(f),normal_proof(f2)); - new_normal = make_normal_step(normal_lhs(f),normal_rhs(f2),pf); - } - else - new_normal = f; - if(get_term_type(normal_lhs(f)) == LitMixed) - trans[normal_lhs(f)] = new_normal; - return cons_normal(new_normal,r); - } - - ast merge_normal_chains(const ast &chain1, const ast &chain2, ast &Aproves, ast &Bproves){ - hash_map trans; - ast res = merge_normal_chains_rec(chain1,chain2,trans,Aproves,Bproves); - res = trans_normal_chain(res,trans); - return res; - } - - bool destruct_cond_ineq(ast t, ast &Aproves, ast &Bproves, ast&ineq){ - if(op(t) == And){ - Aproves = arg(t,0); - t = arg(t,1); - } - else - Aproves = mk_true(); - if(op(t) == Implies){ - Bproves = arg(t,0); - t = arg(t,1); - } - else - Bproves = mk_true(); - if(is_normal_ineq(t)){ - ineq = t; - return true; - } - return false; - } - - ast cons_cond_ineq(const ast &Aproves, const ast &Bproves, const ast &ineq){ - return my_and(Aproves,my_implies(Bproves,ineq)); - } - - ast normalize(const ast &ct){ - ast Aproves,Bproves,t; - if(!destruct_cond_ineq(ct,Aproves,Bproves,t)) - return ct; - if(sym(t) != normal) - return ct; - ast chain = arg(t,1); - hash_map map; - for(ast c = chain; !is_true(c); c = normal_rest(c)){ - ast first = normal_first(c); - ast lhs = normal_lhs(first); - ast rhs = normal_rhs(first); - map[lhs] = rhs; - } - ast res = subst(map,arg(t,0)); - return cons_cond_ineq(Aproves,Bproves,res); - } - - /** Make an assumption node. The given clause is assumed in the given frame. */ - node make_assumption(int frame, const std::vector &assumption) override { - if(!weak){ - if(pv->in_range(frame,rng)){ - std::vector itp_clause; - for(unsigned i = 0; i < assumption.size(); i++) - if(get_term_type(assumption[i]) != LitA) - itp_clause.push_back(assumption[i]); - ast res = my_or(itp_clause); - return res; - } - else { - return mk_true(); - } - } - else { - if(pv->in_range(frame,rng)){ - return mk_false(); - } - else { - std::vector itp_clause; - for(unsigned i = 0; i < assumption.size(); i++) - if(get_term_type(assumption[i]) != LitB) - itp_clause.push_back(assumption[i]); - ast res = my_or(itp_clause); - return mk_not(res); - } - } - } - - ast make_local_rewrite(LitType t, const ast &p){ - ast rew = is_equivrel(p) ? p : make(Iff,mk_true(),p); -#if 0 - if(op(rew) == Iff && !is_true(arg(rew,0))) - return diff_chain(t,top_pos,arg(rew,0),arg(rew,1), mk_true()); -#endif - return chain_cons(mk_true(),make_rewrite(t, top_pos, mk_true(), rew)); - } - - ast triv_interp(const symb &rule, const std::vector &premises, int mask_in){ - std::vector ps; ps.resize(premises.size()); - std::vector conjs; - int mask = 0; - for(unsigned i = 0; i < ps.size(); i++){ - ast p = premises[i]; - LitType t = get_term_type(p); - switch(t){ - case LitA: - case LitB: - ps[i] = make_local_rewrite(t,p); - break; - default: - ps[i] = get_placeholder(p); // can only prove consequent! - if(mask_in & (1 << i)) - mask |= (1 << conjs.size()); - conjs.push_back(p); - } - } - ast ref = make(rule,ps); - ast res = make_contra_node(ref,conjs,mask); - return res; - } - - ast triv_interp(const symb &rule, const ast &p0, const ast &p1, const ast &p2, int mask){ - std::vector ps; ps.resize(3); - ps[0] = p0; - ps[1] = p1; - ps[2] = p2; - return triv_interp(rule,ps,mask); - } - - /** Make a modus-ponens node. This takes derivations of |- x - and |- x = y and produces |- y */ - - node make_mp(const ast &p_eq_q, const ast &prem1, const ast &prem2) override { - - /* Interpolate the axiom p, p=q -> q */ - ast p = arg(p_eq_q,0); - ast q = arg(p_eq_q,1); - ast itp; - if(get_term_type(p_eq_q) == LitMixed){ - int mask = 1 << 2; - if(op(p) == Not && is_equivrel(arg(p,0))) - mask |= 1; // we may need to run this rule backward if first premise is negative equality - itp = triv_interp(modpon,p,p_eq_q,mk_not(q),mask); - } - else { - if(get_term_type(p) == LitA){ - if(get_term_type(q) == LitA){ - if(op(q) == Or) - itp = make_assumption(rng.hi,args(q)); - else - itp = mk_false(); - } - else { - if(get_term_type(p_eq_q) == LitA) - itp = q; - else - throw proof_error(); - } - } - else { - if(get_term_type(q) == LitA){ - if(get_term_type(make(Equal,p,q)) == LitA) - itp = mk_not(p); - else - throw proof_error(); - } - else - itp = mk_true(); - } - } - - /* Resolve it with the premises */ - std::vector conc; conc.push_back(q); conc.push_back(mk_not(p_eq_q)); - itp = make_resolution(p,conc,itp,prem1); - conc.pop_back(); - itp = make_resolution(p_eq_q,conc,itp,prem2); - return itp; - } - - ast capture_localization(ast e){ - // #define CAPTURE_LOCALIZATION -#ifdef CAPTURE_LOCALIZATION - for(int i = localization_vars.size() - 1; i >= 0; i--){ - LocVar &lv = localization_vars[i]; - if(occurs_in(lv.var,e)){ - symb q = (pv->in_range(lv.frame,rng)) ? sexists : sforall; - e = make(q,make(Equal,lv.var,lv.term),e); // use Equal because it is polymorphic - } - } -#endif - return e; - } - - /** Make an axiom node. The conclusion must be an instance of an axiom. */ - node make_axiom(const std::vector &conclusion, prover::range frng) override { - int nargs = conclusion.size(); - std::vector largs(nargs); - std::vector eqs; - std::vector pfs; - - for(int i = 0; i < nargs; i++){ - ast argpf; - ast lit = conclusion[i]; - largs[i] = localize_term(lit,frng,argpf); - frng = pv->range_glb(frng,pv->ast_scope(largs[i])); - if(largs[i] != lit){ - eqs.push_back(make_equiv(largs[i],lit)); - pfs.push_back(argpf); - } - } - - int frame = pv->range_max(frng); - ast itp = make_assumption(frame,largs); - - for(unsigned i = 0; i < eqs.size(); i++) - itp = make_mp(eqs[i],itp,pfs[i]); - return capture_localization(itp); - } - - node make_axiom(const std::vector &conclusion) override { - return make_axiom(conclusion,pv->range_full()); - } - - /** Make a Contra node. This rule takes a derivation of the form - Gamma |- False and produces |- \/~Gamma. */ - - node make_contra(node prem, const std::vector &conclusion) override { - return prem; - } - - /** Make hypothesis. Creates a node of the form P |- P. */ - - node make_hypothesis(const ast &P) override { - if(is_not(P)) - return make_hypothesis(arg(P,0)); - switch(get_term_type(P)){ - case LitA: - return mk_false(); - case LitB: - return mk_true(); - default: // mixed hypothesis - switch(op(P)){ - case Geq: - case Leq: - case Gt: - case Lt: { - ast zleqz = make(Leq,make_int("0"),make_int("0")); - ast fark1 = make(sum,zleqz,make_int("1"),get_placeholder(P)); - ast fark2 = make(sum,fark1,make_int("1"),get_placeholder(mk_not(P))); - ast res = make(And,make(contra,fark2,mk_false()), - make(contra,get_placeholder(mk_not(P)),P), - make(contra,get_placeholder(P),mk_not(P))); - return res; - } - default: { - ast em = make(exmid,P,get_placeholder(P),get_placeholder(mk_not(P))); - ast res = make(And,make(contra,em,mk_false()), - make(contra,get_placeholder(mk_not(P)),P), - make(contra,get_placeholder(P),mk_not(P))); - return res; - } - } - } - } - - /** Make a Reflexivity node. This rule produces |- x = x */ - - node make_reflexivity(ast con) override { - if(get_term_type(con) == LitA) - return mk_false(); - if(get_term_type(con) == LitB) - return mk_true(); - ast itp = make(And,make(contra,no_proof,mk_false()), - make(contra,mk_true(),mk_not(con))); - return itp; - } - - /** Make a Symmetry node. This takes a derivation of |- x = y and - produces | y = x. Ditto for ~(x=y) */ - - node make_symmetry(ast con, const ast &premcon, node prem) override { -#if 0 - ast x = arg(con,0); - ast y = arg(con,1); - ast p = make(op(con),y,x); -#endif - if(get_term_type(con) != LitMixed) - return prem; // symmetry shmymmetry... - ast em = make(exmid,con,make(symm,get_placeholder(premcon)),get_placeholder(mk_not(con))); - ast itp = make(And,make(contra,em,mk_false()), - make(contra,make(symm,get_placeholder(mk_not(con))),premcon), - make(contra,make(symm,get_placeholder(premcon)),mk_not(con))); - - std::vector conc; conc.push_back(con); - itp = make_resolution(premcon,conc,itp,prem); - return itp; - } - - ast make_equiv_rel(const ast &x, const ast &y){ - if(is_bool_type(get_type(x))) - return make(Iff,x,y); - return make(Equal,x,y); - } - - /** Make a transitivity node. This takes derivations of |- x = y - and |- y = z produces | x = z */ - - node make_transitivity(const ast &x, const ast &y, const ast &z, node prem1, node prem2) override { - - /* Interpolate the axiom x=y,y=z,-> x=z */ - ast p = make_equiv_rel(x,y); - ast q = make_equiv_rel(y,z); - ast r = make_equiv_rel(x,z); - ast equiv = make(Iff,p,r); - ast itp; - - itp = make_congruence(q,equiv,prem2); - itp = make_mp(equiv,prem1,itp); - - return itp; - - } - - /** Make a congruence node. This takes derivations of |- x_i = y_i - and produces |- f(x_1,...,x_n) = f(y_1,...,y_n) */ - - node make_congruence(const ast &p, const ast &con, const ast &prem1) override { - ast x = arg(p,0), y = arg(p,1); - ast itp; - LitType con_t = get_term_type(con); - if(get_term_type(p) == LitA){ - if(con_t == LitA) - itp = mk_false(); - else if(con_t == LitB) - itp = p; - else - itp = make_mixed_congruence(x, y, p, con, prem1); - } - else { - if(con_t == LitA) - itp = mk_not(p); - else{ - if(con_t == LitB) - itp = mk_true(); - else - itp = make_mixed_congruence(x, y, p, con, prem1); - } - } - std::vector conc; conc.push_back(con); - itp = make_resolution(p,conc,itp,prem1); - return itp; - } - - int find_congruence_position(const ast &p, const ast &con){ - // find the argument position of x and y - const ast &x = arg(p,0); - const ast &y = arg(p,1); - int nargs = num_args(arg(con,0)); - for(int i = 0; i < nargs; i++) - if(x == arg(arg(con,0),i) && y == arg(arg(con,1),i)) - return i; - throw proof_error(); - } - - /** Make a congruence node. This takes derivations of |- x_i1 = y_i1, |- x_i2 = y_i2,... - and produces |- f(...x_i1...x_i2...) = f(...y_i1...y_i2...) */ - - node make_congruence(const std::vector &p, const ast &con, const std::vector &prems) override { - if(p.size() == 0) - throw proof_error(); - if(p.size() == 1) - return make_congruence(p[0],con,prems[0]); - ast thing = con; - ast res = mk_true(); - for(unsigned i = 0; i < p.size(); i++){ - int pos = find_congruence_position(p[i],thing); - ast next = subst_in_arg_pos(pos,arg(p[i],1),arg(thing,0)); - ast goal = make(op(thing),arg(thing,0),next); - ast equa = make_congruence(p[i],goal,prems[i]); - if(i == 0) - res = equa; - else { - ast trace = make(op(con),arg(con,0),arg(thing,0)); - ast equiv = make(Iff,trace,make(op(trace),arg(trace,0),next)); - ast foo = make_congruence(goal,equiv,equa); - res = make_mp(equiv,res,foo); - } - thing = make(op(thing),next,arg(thing,1)); - } - return res; - } - - /* Interpolate a mixed congruence axiom. */ - - virtual ast make_mixed_congruence(const ast &x, const ast &y, const ast &p, const ast &con, const ast &prem1){ - ast foo = p; - std::vector conjs; - LitType t = get_term_type(foo); - switch(t){ - case LitA: - case LitB: - foo = make_local_rewrite(t,foo); - break; - case LitMixed: - conjs.push_back(foo); - foo = get_placeholder(foo); - } - // find the argument position of x and y - int pos = -1; - int nargs = num_args(arg(con,0)); - for(int i = 0; i < nargs; i++) - if(x == arg(arg(con,0),i) && y == arg(arg(con,1),i)) - pos = i; - if(pos == -1) - throw proof_error(); - ast bar = make(cong,foo,make_int(rational(pos)),get_placeholder(mk_not(con))); - conjs.push_back(mk_not(con)); - return make_contra_node(bar,conjs); - } - - ast subst_in_arg_pos(int pos, ast term, ast app){ - std::vector args; - get_args(app,args); - args[pos] = term; - return clone(app,args); - } - - /** Make a farkas proof node. */ - - node make_farkas(ast con, const std::vector &prems, const std::vector &prem_cons, - const std::vector &coeffs) override { - - /* Compute the interpolant for the clause */ - - ast zero = make_int("0"); - std::vector conjs; - ast thing = make(Leq,zero,zero); - for(unsigned i = 0; i < prem_cons.size(); i++){ - const ast &lit = prem_cons[i]; - if(get_term_type(lit) == LitA) - // Farkas rule seems to assume strict integer inequalities are rounded - linear_comb(thing,coeffs[i],lit,true /*round_off*/); - } - thing = simplify_ineq(thing); - for(unsigned i = 0; i < prem_cons.size(); i++){ - const ast &lit = prem_cons[i]; - if(get_term_type(lit) == LitMixed){ - thing = make(sum,thing,coeffs[i],get_placeholder(lit)); - conjs.push_back(lit); - } - } - thing = make_contra_node(thing,conjs); - - /* Resolve it with the premises */ - std::vector conc; conc.resize(prem_cons.size()); - for(unsigned i = 0; i < prem_cons.size(); i++) - conc[prem_cons.size()-i-1] = prem_cons[i]; - for(unsigned i = 0; i < prem_cons.size(); i++){ - thing = make_resolution(prem_cons[i],conc,thing,prems[i]); - conc.pop_back(); - } - return thing; - } - - /** Set P to P + cQ, where P and Q are linear inequalities. Assumes P is 0 <= y or 0 < y. */ - - void linear_comb(ast &P, const ast &c, const ast &Q, bool round_off = false){ - ast Qrhs; - bool qstrict = false; - if(is_not(Q)){ - ast nQ = arg(Q,0); - switch(op(nQ)){ - case Gt: - Qrhs = make(Sub,arg(nQ,1),arg(nQ,0)); - break; - case Lt: - Qrhs = make(Sub,arg(nQ,0),arg(nQ,1)); - break; - case Geq: - Qrhs = make(Sub,arg(nQ,1),arg(nQ,0)); - qstrict = true; - break; - case Leq: - Qrhs = make(Sub,arg(nQ,0),arg(nQ,1)); - qstrict = true; - break; - default: - throw proof_error(); - } - } - else { - switch(op(Q)){ - case Leq: - Qrhs = make(Sub,arg(Q,1),arg(Q,0)); - break; - case Geq: - Qrhs = make(Sub,arg(Q,0),arg(Q,1)); - break; - case Lt: - Qrhs = make(Sub,arg(Q,1),arg(Q,0)); - qstrict = true; - break; - case Gt: - Qrhs = make(Sub,arg(Q,0),arg(Q,1)); - qstrict = true; - break; - default: - throw proof_error(); - } - } -#if 0 - bool pstrict = op(P) == Lt, strict = pstrict || qstrict; - if(pstrict && qstrict && round_off) - Qrhs = make(Sub,Qrhs,make_int(rational(1))); -#else - if (round_off && get_type(Qrhs) != int_type()) - round_off = false; - bool pstrict = op(P) == Lt; - if(qstrict && round_off && (pstrict || !(c == make_int(rational(1))))){ - Qrhs = make(Sub,Qrhs,make_int(rational(1))); - qstrict = false; - } - Qrhs = make(Times,c,Qrhs); - bool strict = pstrict || qstrict; -#endif - if(strict) - P = make(Lt,arg(P,0),make(Plus,arg(P,1),Qrhs)); - else - P = make(Leq,arg(P,0),make(Plus,arg(P,1),Qrhs)); - } - - /* Make an axiom instance of the form |- x<=y, y<= x -> x =y */ - node make_leq2eq(ast x, ast y, const ast &xleqy, const ast &yleqx) override { - ast con = make(Equal,x,y); - ast itp; - switch(get_term_type(con)){ - case LitA: - itp = mk_false(); - break; - case LitB: - itp = mk_true(); - break; - default: { // mixed equality - if(get_term_type(x) == LitMixed || get_term_type(y) == LitMixed){ - if(y == make_int(rational(0)) && op(x) == Plus && num_args(x) == 2){ - // std::cerr << "WARNING: untested case in leq2eq\n"; - } - else { - // std::cerr << "WARNING: mixed term in leq2eq\n"; - std::vector lits; - lits.push_back(con); - lits.push_back(make(Not,xleqy)); - lits.push_back(make(Not,yleqx)); - return make_axiom(lits); - } - } - std::vector conjs; conjs.resize(3); - conjs[0] = mk_not(con); - conjs[1] = xleqy; - conjs[2] = yleqx; - itp = make_contra_node(make(leq2eq, - get_placeholder(mk_not(con)), - get_placeholder(xleqy), - get_placeholder(yleqx)), - conjs,1); - } - } - return itp; - } - - /* Make an axiom instance of the form |- x = y -> x <= y */ - node make_eq2leq(ast x, ast y, const ast &xleqy) override { - ast itp; - switch(get_term_type(xleqy)){ - case LitA: - itp = mk_false(); - break; - case LitB: - itp = mk_true(); - break; - default: { // mixed equality - std::vector conjs; conjs.resize(2); - conjs[0] = make(Equal,x,y); - conjs[1] = mk_not(xleqy); - itp = make(eq2leq,get_placeholder(conjs[0]),get_placeholder(conjs[1])); - itp = make_contra_node(itp,conjs,2); - } - } - return itp; - } - - - /* Make an inference of the form t <= c |- t/d <= floor(c/d) where t - is an affine term divisble by d and c is an integer constant */ - node make_cut_rule(const ast &tleqc, const ast &d, const ast &con, const ast &prem) override { - ast itp = mk_false(); - switch(get_term_type(con)){ - case LitA: - itp = mk_false(); - break; - case LitB: - itp = mk_true(); - break; - default: { - std::vector conjs; conjs.resize(2); - conjs[0] = tleqc; - conjs[1] = mk_not(con); - itp = make(sum,get_placeholder(conjs[0]),d,get_placeholder(conjs[1])); - itp = make_contra_node(itp,conjs); - } - } - std::vector conc; conc.push_back(con); - itp = make_resolution(tleqc,conc,itp,prem); - return itp; - } - - - - // create a fresh variable for localization - ast fresh_localization_var(const ast &term, int frame){ - std::ostringstream s; - s << "%" << (localization_vars.size()); - ast var = make_var(s.str().c_str(),get_type(term)); - pv->sym_range(sym(var)) = pv->range_full(); // make this variable global - localization_vars.push_back(LocVar(var,term,frame)); - return var; - } - - struct LocVar { // localization vars - ast var; // a fresh variable - ast term; // term it represents - int frame; // frame in which it's defined - LocVar(ast v, ast t, int f){var=v;term=t;frame=f;} - }; - - std::vector localization_vars; // localization vars in order of creation - - struct locmaps { - hash_map localization_map; // maps terms to their localization vars - hash_map localization_pf_map; // maps terms to proofs of their localizations - }; - - hash_map localization_maps_per_range; - - /* "localize" a term e to a given frame range, creating new symbols to - represent non-local subterms. This returns the localized version e_l, - as well as a proof thet e_l = l. - */ - - ast make_refl(const ast &e){ - if(get_term_type(e) == LitA) - return mk_false(); - return mk_true(); // TODO: is this right? - } - - - ast make_equiv(const ast &x, const ast &y){ - if(get_type(x) == bool_type()) - return make(Iff,x,y); - else - return make(Equal,x,y); - } - - bool range_is_global(const prover::range &r){ - if(pv->range_contained(r,rng)) - return false; - if(!pv->ranges_intersect(r,rng)) - return false; - return true; - } - - ast localize_term(ast e, const prover::range &rng, ast &pf){ - - // we need to memoize this function separately for A, B and global - prover::range map_range = rng; - if(range_is_global(map_range)) - map_range = pv->range_full(); - locmaps &maps = localization_maps_per_range[map_range]; - hash_map &localization_map = maps.localization_map; - hash_map &localization_pf_map = maps.localization_pf_map; - - ast orig_e = e; - pf = make_refl(e); // proof that e = e - - // prover::range erng = - pv->ast_scope(e); -#if 0 - if(!(erng.lo > erng.hi) && pv->ranges_intersect(pv->ast_scope(e),rng)){ - return e; // this term occurs in range, so it's O.K. - } -#endif - - hash_map::iterator it = localization_map.find(e); - - if(it != localization_map.end() && is_bool_type(get_type(e)) - && !pv->ranges_intersect(pv->ast_scope(it->second),rng)) - it = localization_map.end(); // prevent quantifiers over booleans - - if(it != localization_map.end()){ - pf = localization_pf_map[e]; - e = it->second; - } - - else { - // if it is non-local, we must first localize the arguments to - // the range of its function symbol - - int nargs = num_args(e); - if(nargs > 0 /* && (!is_local(e) || flo <= hi || fhi >= lo) */){ - prover::range frng = rng; - opr o = op(e); - if(o == Uninterpreted){ - symb f = sym(e); - prover::range srng = pv->sym_range(f); - if(pv->ranges_intersect(srng,rng)) // localize to desired range if possible - frng = pv->range_glb(srng,rng); - else - frng = srng; // this term will be localized - } - else if(o == Plus || o == Times){ // don't want bound variables inside arith ops - // std::cout << "WARNING: non-local arithmetic\n"; - // frng = erng; // this term will be localized - } - else if(o == Select){ // treat the array term like a function symbol - prover::range srng = pv->ast_scope(arg(e,0)); - if(!(srng.lo > srng.hi) && pv->ranges_intersect(srng,rng)) // localize to desired range if possible - frng = pv->range_glb(srng,rng); - else - frng = srng; // this term will be localized - } - std::vector largs(nargs); - std::vector eqs; - std::vector pfs; - for(int i = 0; i < nargs; i++){ - ast argpf; - largs[i] = localize_term(arg(e,i),frng,argpf); - frng = pv->range_glb(frng,pv->ast_scope(largs[i])); - if(largs[i] != arg(e,i)){ - eqs.push_back(make_equiv(largs[i],arg(e,i))); - pfs.push_back(argpf); - } - } - - e = clone(e,largs); - if(pfs.size()) - pf = make_congruence(eqs,make_equiv(e,orig_e),pfs); - // assert(is_local(e)); - } - - localization_pf_map[orig_e] = pf; - localization_map[orig_e] = e; - } - - if(pv->ranges_intersect(pv->ast_scope(e),rng)) - return e; // this term occurs in range, so it's O.K. - - if(is_array_type(get_type(e))) - std::cerr << "WARNING: array quantifier\n"; - - // choose a frame for the constraint that is close to range - int frame = pv->range_near(pv->ast_scope(e),rng); - - ast new_var = fresh_localization_var(e,frame); - localization_map[orig_e] = new_var; - std::vector foo; foo.push_back(make_equiv(new_var,e)); - ast bar = make_assumption(frame,foo); - pf = make_transitivity(new_var,e,orig_e,bar,pf); - localization_pf_map[orig_e] = pf; - - // HACK: try to bias this term in the future - if(!pv->range_is_full(rng)){ - prover::range rf = pv->range_full(); - locmaps &fmaps = localization_maps_per_range[rf]; - hash_map &flocalization_map = fmaps.localization_map; - hash_map &flocalization_pf_map = fmaps.localization_pf_map; - // if(flocalization_map.find(orig_e) == flocalization_map.end()) - { - flocalization_map[orig_e] = new_var; - flocalization_pf_map[orig_e] = pf; - } - } - - - return new_var; - } - - ast delete_quant(hash_map &memo, const ast &v, const ast &e){ - std::pair foo(e,ast()); - std::pair::iterator,bool> bar = memo.insert(foo); - ast &res = bar.first->second; - if(bar.second){ - opr o = op(e); - switch(o){ - case Or: - case And: - case Implies: { - unsigned nargs = num_args(e); - std::vector args; args.resize(nargs); - for(unsigned i = 0; i < nargs; i++) - args[i] = delete_quant(memo, v, arg(e,i)); - res = make(o,args); - break; - } - case Uninterpreted: { - symb s = sym(e); - ast w = arg(arg(e,0),0); - if(s == sforall || s == sexists){ - res = delete_quant(memo,v,arg(e,1)); - if(w != v) - res = make(s,w,res); - break; - } - } - default: - res = e; - } - } - return res; - } - - ast insert_quants(hash_map &memo, const ast &e){ - std::pair foo(e,ast()); - std::pair::iterator,bool> bar = memo.insert(foo); - ast &res = bar.first->second; - if(bar.second){ - opr o = op(e); - switch(o){ - case Or: - case And: - case Implies: { - unsigned nargs = num_args(e); - std::vector args; args.resize(nargs); - for(unsigned i = 0; i < nargs; i++) - args[i] = insert_quants(memo, arg(e,i)); - res = make(o,args); - break; - } - case Uninterpreted: { - symb s = sym(e); - if(s == sforall || s == sexists){ - opr q = (s == sforall) ? Forall : Exists; - ast v = arg(arg(e,0),0); - hash_map dmemo; - ast body = delete_quant(dmemo,v,arg(e,1)); - body = insert_quants(memo,body); - res = apply_quant(q,v,body); - break; - } - } - default: - res = e; - } - } - return res; - } - - ast add_quants(ast e){ -#ifdef CAPTURE_LOCALIZATION - if(!localization_vars.empty()){ - hash_map memo; - e = insert_quants(memo,e); - } -#else - for(int i = localization_vars.size() - 1; i >= 0; i--){ - LocVar &lv = localization_vars[i]; - opr quantifier = (pv->in_range(lv.frame,rng)) ? Exists : Forall; - e = apply_quant(quantifier,lv.var,e); - } -#endif - return e; - } - - node make_resolution(ast pivot, node premise1, node premise2) { - std::vector lits; - return make_resolution(pivot,lits,premise1,premise2); - } - - /* Return an interpolant from a proof of false */ - ast interpolate(const node &pf) override { - // proof of false must be a formula, with quantified symbols -#ifndef BOGUS_QUANTS - return close_universally(add_quants(z3_simplify(pf))); -#else - return close_universally(z3_simplify(pf)); -#endif - } - - ast resolve_with_quantifier(const ast &pivot1, const ast &conj1, - const ast &pivot2, const ast &conj2){ - if(is_not(arg(pivot1,1))) - return resolve_with_quantifier(pivot2,conj2,pivot1,conj1); - ast eqpf; - ast P = arg(pivot1,1); - ast Ploc = localize_term(P, rng, eqpf); - ast pPloc = make_hypothesis(Ploc); - ast pP = make_mp(make(Iff,Ploc,P),pPloc,eqpf); - ast rP = make_resolution(P,conj1,pP); - ast nP = mk_not(P); - ast nPloc = mk_not(Ploc); - ast neqpf = make_congruence(make(Iff,Ploc,P),make(Iff,nPloc,nP),eqpf); - ast npPloc = make_hypothesis(nPloc); - ast npP = make_mp(make(Iff,nPloc,nP),npPloc,neqpf); - ast nrP = make_resolution(nP,conj2,npP); - ast res = make_resolution(Ploc,rP,nrP); - return capture_localization(res); - } - - ast get_contra_coeff(const ast &f){ - ast c = arg(f,0); - // if(!is_not(arg(f,1))) - // c = make(Uminus,c); - return c; - } - - ast my_or(const ast &a, const ast &b){ - return mk_or(a,b); - } - - ast my_and(const ast &a, const ast &b){ - return mk_and(a,b); - } - - ast my_implies(const ast &a, const ast &b){ - return mk_implies(a,b); - } - - ast my_or(const std::vector &a){ - return mk_or(a); - } - - ast my_and(const std::vector &a){ - return mk_and(a); - } - - ast get_lit_atom(const ast &l){ - if(op(l) == Not) - return arg(l,0); - return l; - } - - bool is_placeholder(const ast &e){ - if(op(e) == Uninterpreted){ - std::string name = string_of_symbol(sym(e)); - if(name.size() > 2 && name[0] == '@' && name[1] == 'p') - return true; - } - return false; - } - -public: - iz3proof_itp_impl(prover *p, const prover::range &r, bool w) - : iz3proof_itp(*p) - { - pv = p; - rng = r; - weak = false ; //w; - type boolintbooldom[3] = {bool_type(),int_type(),bool_type()}; - type booldom[1] = {bool_type()}; - type boolbooldom[2] = {bool_type(),bool_type()}; - type boolboolbooldom[3] = {bool_type(),bool_type(),bool_type()}; - type intbooldom[2] = {int_type(),bool_type()}; - contra = function("@contra",2,boolbooldom,bool_type()); - m().inc_ref(contra); - sum = function("@sum",3,boolintbooldom,bool_type()); - m().inc_ref(sum); - rotate_sum = function("@rotsum",2,boolbooldom,bool_type()); - m().inc_ref(rotate_sum); - leq2eq = function("@leq2eq",3,boolboolbooldom,bool_type()); - m().inc_ref(leq2eq); - eq2leq = function("@eq2leq",2,boolbooldom,bool_type()); - m().inc_ref(eq2leq); - cong = function("@cong",3,boolintbooldom,bool_type()); - m().inc_ref(cong); - exmid = function("@exmid",3,boolboolbooldom,bool_type()); - m().inc_ref(exmid); - symm = function("@symm",1,booldom,bool_type()); - m().inc_ref(symm); - epsilon = make_var("@eps",int_type()); - modpon = function("@mp",3,boolboolbooldom,bool_type()); - m().inc_ref(modpon); - no_proof = make_var("@nop",bool_type()); - concat = function("@concat",2,boolbooldom,bool_type()); - m().inc_ref(concat); - top_pos = make_var("@top_pos",bool_type()); - add_pos = function("@add_pos",2,intbooldom,bool_type()); - m().inc_ref(add_pos); - rewrite_A = function("@rewrite_A",3,boolboolbooldom,bool_type()); - m().inc_ref(rewrite_A); - rewrite_B = function("@rewrite_B",3,boolboolbooldom,bool_type()); - m().inc_ref(rewrite_B); - normal_step = function("@normal_step",2,boolbooldom,bool_type()); - m().inc_ref(normal_step); - normal_chain = function("@normal_chain",2,boolbooldom,bool_type()); - m().inc_ref(normal_chain); - normal = function("@normal",2,boolbooldom,bool_type()); - m().inc_ref(normal); - sforall = function("@sforall",2,boolbooldom,bool_type()); - m().inc_ref(sforall); - sexists = function("@sexists",2,boolbooldom,bool_type()); - m().inc_ref(sexists); - } - - ~iz3proof_itp_impl() override { - m().dec_ref(contra); - m().dec_ref(sum); - m().dec_ref(rotate_sum); - m().dec_ref(leq2eq); - m().dec_ref(eq2leq); - m().dec_ref(cong); - m().dec_ref(exmid); - m().dec_ref(symm); - m().dec_ref(modpon); - m().dec_ref(concat); - m().dec_ref(add_pos); - m().dec_ref(rewrite_A); - m().dec_ref(rewrite_B); - m().dec_ref(normal_step); - m().dec_ref(normal_chain); - m().dec_ref(normal); - m().dec_ref(sforall); - m().dec_ref(sexists); - } -}; - -iz3proof_itp *iz3proof_itp::create(prover *p, const prover::range &r, bool w){ - return new iz3proof_itp_impl(p,r,w); -} - diff --git a/src/interp/iz3proof_itp.h b/src/interp/iz3proof_itp.h deleted file mode 100644 index c9a36e9b1..000000000 --- a/src/interp/iz3proof_itp.h +++ /dev/null @@ -1,143 +0,0 @@ -/*++ - Copyright (c) 2011 Microsoft Corporation - - Module Name: - - iz3proof.h - - Abstract: - - This class defines a simple interpolating proof system. - - Author: - - Ken McMillan (kenmcmil) - - Revision History: - - --*/ - -#ifndef IZ3PROOF_ITP_H -#define IZ3PROOF_ITP_H - -#include - -#include "interp/iz3base.h" -#include "interp/iz3secondary.h" - -// #define CHECK_PROOFS - -/** This class defines a simple proof system. - - As opposed to iz3proof, this class directly computes interpolants, - so the proof representation is just the interpolant itself. - -*/ - -class iz3proof_itp : public iz3mgr { - public: - - /** Enumeration of proof rules. */ - enum rule {Resolution,Assumption,Hypothesis,Theory,Axiom,Contra,Lemma,Reflexivity,Symmetry,Transitivity,Congruence,EqContra}; - - /** Interface to prover. */ - typedef iz3base prover; - - /** Ast type. */ - typedef prover::ast ast; - - /** The type of proof nodes (just interpolants). */ - typedef ast node; - - /** Object thrown in case of a proof error. */ - struct proof_error: public iz3_exception { - proof_error(): iz3_exception("proof_error") {} - }; - - - /** Make a resolution node with given pivot literal and premises. - The conclusion of premise1 should contain the negation of the - pivot literal, while the conclusion of premise2 should containe the - pivot literal. - */ - virtual node make_resolution(ast pivot, const std::vector &conc, node premise1, node premise2) = 0; - - /** Make an assumption node. The given clause is assumed in the given frame. */ - virtual node make_assumption(int frame, const std::vector &assumption) = 0; - - /** Make a hypothesis node. If phi is the hypothesis, this is - effectively phi |- phi. */ - virtual node make_hypothesis(const ast &hypothesis) = 0; - - /** Make an axiom node. The conclusion must be an instance of an axiom. */ - virtual node make_axiom(const std::vector &conclusion) = 0; - - /** Make an axiom node. The conclusion must be an instance of an axiom. Localize axiom instance to range*/ - virtual node make_axiom(const std::vector &conclusion, prover::range) = 0; - - /** Make a Contra node. This rule takes a derivation of the form - Gamma |- False and produces |- \/~Gamma. */ - - virtual node make_contra(node prem, const std::vector &conclusion) = 0; - - /** Make a Reflexivity node. This rule produces |- x = x */ - - virtual node make_reflexivity(ast con) = 0; - - /** Make a Symmetry node. This takes a derivation of |- x = y and - produces | y = x */ - - virtual node make_symmetry(ast con, const ast &premcon, node prem) = 0; - - /** Make a transitivity node. This takes derivations of |- x = y - and |- y = z produces | x = z */ - - virtual node make_transitivity(const ast &x, const ast &y, const ast &z, node prem1, node prem2) = 0; - - /** Make a congruence node. This takes a derivation of |- x_i = y_i - and produces |- f(...x_i,...) = f(...,y_i,...) */ - - virtual node make_congruence(const ast &xi_eq_yi, const ast &con, const ast &prem1) = 0; - - /** Make a congruence node. This takes derivations of |- x_i1 = y_i1, |- x_i2 = y_i2,... - and produces |- f(...x_i1...x_i2...) = f(...y_i1...y_i2...) */ - - virtual node make_congruence(const std::vector &xi_eq_yi, const ast &con, const std::vector &prems) = 0; - - /** Make a modus-ponens node. This takes derivations of |- x - and |- x = y and produces |- y */ - - virtual node make_mp(const ast &x_eq_y, const ast &prem1, const ast &prem2) = 0; - - /** Make a farkas proof node. */ - - virtual node make_farkas(ast con, const std::vector &prems, const std::vector &prem_cons, const std::vector &coeffs) = 0; - - /* Make an axiom instance of the form |- x<=y, y<= x -> x =y */ - virtual node make_leq2eq(ast x, ast y, const ast &xleqy, const ast &yleqx) = 0; - - /* Make an axiom instance of the form |- x = y -> x <= y */ - virtual node make_eq2leq(ast x, ast y, const ast &xeqy) = 0; - - /* Make an inference of the form t <= c |- t/d <= floor(c/d) where t - is an affine term divisble by d and c is an integer constant */ - virtual node make_cut_rule(const ast &tleqc, const ast &d, const ast &con, const ast &prem) = 0; - - /* Return an interpolant from a proof of false */ - virtual ast interpolate(const node &pf) = 0; - - /** Create proof object to construct an interpolant. */ - static iz3proof_itp *create(prover *p, const prover::range &r, bool _weak); - - protected: - iz3proof_itp(iz3mgr &m) - : iz3mgr(m) - { - } - - public: - virtual ~iz3proof_itp(){ - } -}; - -#endif diff --git a/src/interp/iz3scopes.cpp b/src/interp/iz3scopes.cpp deleted file mode 100755 index e3a28abdd..000000000 --- a/src/interp/iz3scopes.cpp +++ /dev/null @@ -1,321 +0,0 @@ -/*++ - Copyright (c) 2011 Microsoft Corporation - - Module Name: - - iz3scopes.cpp - - Abstract: - - Calculations with scopes, for both sequence and tree interpolation. - - Author: - - Ken McMillan (kenmcmil) - - Revision History: - - --*/ - -#include - -#include - -#include "interp/iz3scopes.h" - - -/** computes the least common ancestor of two nodes in the tree, or SHRT_MAX if none */ -int scopes::tree_lca(int n1, int n2){ - if(!tree_mode()) - return std::max(n1,n2); - if(n1 == SHRT_MIN) return n2; - if(n2 == SHRT_MIN) return n1; - if(n1 == SHRT_MAX || n2 == SHRT_MAX) return SHRT_MAX; - while(n1 != n2){ - if(n1 == SHRT_MAX || n2 == SHRT_MAX) return SHRT_MAX; - assert(n1 >= 0 && n2 >= 0 && n1 < (int)parents.size() && n2 < (int)parents.size()); - if(n1 < n2) n1 = parents[n1]; - else n2 = parents[n2]; - } - return n1; -} - -/** computes the greatest common descendant two nodes in the tree, or SHRT_MIN if none */ -int scopes::tree_gcd(int n1, int n2){ - if(!tree_mode()) - return std::min(n1,n2); - int foo = tree_lca(n1,n2); - if(foo == n1) return n2; - if(foo == n2) return n1; - return SHRT_MIN; -} - -#ifndef FULL_TREE - -/** test whether a tree node is contained in a range */ -bool scopes::in_range(int n, const range &rng){ - return tree_lca(rng.lo,n) == n && tree_gcd(rng.hi,n) == n; -} - -/** test whether two ranges of tree nodes intersect */ -bool scopes::ranges_intersect(const range &rng1, const range &rng2){ - return tree_lca(rng1.lo,rng2.hi) == rng2.hi && tree_lca(rng1.hi,rng2.lo) == rng1.hi; -} - - -bool scopes::range_contained(const range &rng1, const range &rng2){ - return tree_lca(rng2.lo,rng1.lo) == rng1.lo - && tree_lca(rng1.hi,rng2.hi) == rng2.hi; -} - -scopes::range scopes::range_lub(const range &rng1, const range &rng2){ - range res; - res.lo = tree_gcd(rng1.lo,rng2.lo); - res.hi = tree_lca(rng1.hi,rng2.hi); - return res; -} - -scopes::range scopes::range_glb(const range &rng1, const range &rng2){ - range res; - res.lo = tree_lca(rng1.lo,rng2.lo); - res.hi = tree_gcd(rng1.hi,rng2.hi); - return res; -} - -#else - - -namespace std { - template <> - class hash { - public: - size_t operator()(const scopes::range_lo &p) const { - return p.lo + (size_t)p.next; - } - }; -} - -template <> inline -size_t stdext::hash_value(const scopes::range_lo& p) -{ - std::hash h; - return h(p); -} - -namespace std { - template <> - class less { - public: - bool operator()(const scopes::range_lo &x, const scopes::range_lo &y) const { - return x.lo < y.lo || x.lo == y.lo && (size_t)x.next < (size_t)y.next; - } - }; -} - - -struct range_op { - scopes::range_lo *x, *y; - int hi; - range_op(scopes::range_lo *_x, scopes::range_lo *_y, int _hi){ - x = _x; y = _y; hi = _hi; - } -}; - -namespace std { - template <> - class hash { - public: - size_t operator()(const range_op &p) const { - return (size_t) p.x + (size_t)p.y + p.hi; - } - }; -} - -template <> inline -size_t stdext::hash_value(const range_op& p) -{ - std::hash h; - return h(p); -} - -namespace std { - template <> - class less { - public: - bool operator()(const range_op &x, const range_op &y) const { - return (size_t)x.x < (size_t)y.x || x.x == y.x && - ((size_t)x.y < (size_t)y.y || x.y == y.y && x.hi < y.hi); - } - }; -} - -struct range_tables { - hash_map unique; - hash_map lub; - hash_map glb; -}; - - -scopes::range_lo *scopes::find_range_lo(int lo, range_lo *next){ - range_lo foo(lo,next); - std::pair baz(foo,(range_lo *)0); - std::pair::iterator,bool> bar = rt->unique.insert(baz); - if(bar.second) - bar.first->second = new range_lo(lo,next); - return bar.first->second; - //std::pair::iterator,bool> bar = rt->unique.insert(foo); - // const range_lo *baz = &*(bar.first); - // return (range_lo *)baz; // coerce const -} - -scopes::range_lo *scopes::range_lub_lo(range_lo *rng1, range_lo *rng2){ - if(!rng1) return rng2; - if(!rng2) return rng1; - if(rng1->lo > rng2->lo) - std::swap(rng1,rng2); - std::pair foo(range_op(rng1,rng2,0),(range_lo *)0); - std::pair::iterator,bool> bar = rt->lub.insert(foo); - range_lo *&res = bar.first->second; - if(!bar.second) return res; - if(!(rng1->next && rng1->next->lo <= rng2->lo)){ - for(int lo = rng1->lo; lo <= rng2->lo; lo = parents[lo]) - if(lo == rng2->lo) - {rng2 = rng2->next; break;} - } - range_lo *baz = range_lub_lo(rng1->next,rng2); - res = find_range_lo(rng1->lo,baz); - return res; -} - - -scopes::range_lo *scopes::range_glb_lo(range_lo *rng1, range_lo *rng2, int hi){ - if(!rng1) return rng1; - if(!rng2) return rng2; - if(rng1->lo > rng2->lo) - std::swap(rng1,rng2); - std::pair cand(range_op(rng1,rng2,hi),(range_lo *)0); - std::pair::iterator,bool> bar = rt->glb.insert(cand); - range_lo *&res = bar.first->second; - if(!bar.second) return res; - range_lo *foo; - if(!(rng1->next && rng1->next->lo <= rng2->lo)){ - int lim = hi; - if(rng1->next) lim = std::min(lim,rng1->next->lo); - int a = rng1->lo, b = rng2->lo; - while(a != b && b <= lim){ - a = parents[a]; - if(a > b)std::swap(a,b); - } - if(a == b && b <= lim){ - foo = range_glb_lo(rng1->next,rng2->next,hi); - foo = find_range_lo(b,foo); - } - else - foo = range_glb_lo(rng2,rng1->next,hi); - } - else foo = range_glb_lo(rng1->next,rng2,hi); - res = foo; - return res; -} - -/** computes the lub (smallest containing subtree) of two ranges */ -scopes::range scopes::range_lub(const range &rng1, const range &rng2){ - int hi = tree_lca(rng1.hi,rng2.hi); - if(hi == SHRT_MAX) return range_full(); - range_lo *lo = range_lub_lo(rng1.lo,rng2.lo); - return range(hi,lo); -} - -/** computes the glb (intersection) of two ranges */ -scopes::range scopes::range_glb(const range &rng1, const range &rng2){ - if(rng1.hi == SHRT_MAX) return rng2; - if(rng2.hi == SHRT_MAX) return rng1; - int hi = tree_gcd(rng1.hi,rng2.hi); - range_lo *lo = hi == SHRT_MIN ? 0 : range_glb_lo(rng1.lo,rng2.lo,hi); - if(!lo) hi = SHRT_MIN; - return range(hi,lo); -} - -/** is this range empty? */ -bool scopes::range_is_empty(const range &rng){ - return rng.hi == SHRT_MIN; -} - -/** return an empty range */ -scopes::range scopes::range_empty(){ - return range(SHRT_MIN,0); -} - -/** return a full range */ -scopes::range scopes::range_full(){ - return range(SHRT_MAX,0); -} - -/** return the maximal element of a range */ -int scopes::range_max(const range &rng){ - return rng.hi; -} - -/** return a minimal (not necessarily unique) element of a range */ -int scopes::range_min(const range &rng){ - if(rng.hi == SHRT_MAX) return SHRT_MIN; - return rng.lo ? rng.lo->lo : SHRT_MAX; -} - - -/** return range consisting of downward closure of a point */ -scopes::range scopes::range_downward(int _hi){ - std::vector descendants(parents.size()); - for(int i = descendants.size() - 1; i >= 0 ; i--) - descendants[i] = i == _hi || parents[i] < parents.size() && descendants[parents[i]]; - for(unsigned i = 0; i < descendants.size() - 1; i++) - if(parents[i] < parents.size()) - descendants[parents[i]] = false; - range_lo *foo = 0; - for(int i = descendants.size() - 1; i >= 0; --i) - if(descendants[i]) foo = find_range_lo(i,foo); - return range(_hi,foo); -} - -/** add an element to a range */ -void scopes::range_add(int i, range &n){ - range foo = range(i, find_range_lo(i,0)); - n = range_lub(foo,n); -} - -/** Choose an element of rng1 that is near to rng2 */ -int scopes::range_near(const range &rng1, const range &rng2){ - - int frame; - int thing = tree_lca(rng1.hi,rng2.hi); - if(thing != rng1.hi) return rng1.hi; - range line = range(rng1.hi,find_range_lo(rng2.hi,(range_lo *)0)); - line = range_glb(line,rng1); - return range_min(line); -} - - -/** test whether a tree node is contained in a range */ -bool scopes::in_range(int n, const range &rng){ - range r = range_empty(); - range_add(n,r); - r = range_glb(rng,r); - return !range_is_empty(r); -} - -/** test whether two ranges of tree nodes intersect */ -bool scopes::ranges_intersect(const range &rng1, const range &rng2){ - range r = range_glb(rng1,rng2); - return !range_is_empty(r); -} - - -bool scopes::range_contained(const range &rng1, const range &rng2){ - range r = range_glb(rng1,rng2); - return r.hi == rng1.hi && r.lo == rng1.lo; -} - - -#endif - - diff --git a/src/interp/iz3scopes.h b/src/interp/iz3scopes.h deleted file mode 100755 index ece30dc25..000000000 --- a/src/interp/iz3scopes.h +++ /dev/null @@ -1,222 +0,0 @@ -/*++ - Copyright (c) 2011 Microsoft Corporation - - Module Name: - - iz3scopes.h - - Abstract: - - Calculations with scopes, for both sequence and tree interpolation. - - Author: - - Ken McMillan (kenmcmil) - - Revision History: - - --*/ - - -#ifndef IZ3SOPES_H -#define IZ3SOPES_H - -#include -#include -#include "interp/iz3hash.h" - -class scopes { - - public: - /** Construct from parents vector. */ - scopes(const std::vector &_parents){ - parents = _parents; - } - - scopes(){ - } - - void initialize(const std::vector &_parents){ - parents = _parents; - } - - /** The parents vector defining the tree structure */ - std::vector parents; - - // #define FULL_TREE -#ifndef FULL_TREE - struct range { - range(){ - lo = SHRT_MAX; - hi = SHRT_MIN; - } - short lo, hi; - }; - - /** computes the lub (smallest containing subtree) of two ranges */ - range range_lub(const range &rng1, const range &rng2); - - /** computes the glb (intersection) of two ranges */ - range range_glb(const range &rng1, const range &rng2); - - /** is this range empty? */ - bool range_is_empty(const range &rng){ - return rng.hi < rng.lo; - } - - /** is this range full? */ - bool range_is_full(const range &rng){ - return rng.lo == SHRT_MIN && rng.hi == SHRT_MAX; - } - - /** return an empty range */ - range range_empty(){ - range res; - res.lo = SHRT_MAX; - res.hi = SHRT_MIN; - return res; - } - - /** return an empty range */ - range range_full(){ - range res; - res.lo = SHRT_MIN; - res.hi = SHRT_MAX; - return res; - } - - /** return the maximal element of a range */ - int range_max(const range &rng){ - return rng.hi; - } - - /** return a minimal (not necessarily unique) element of a range */ - int range_min(const range &rng){ - return rng.lo; - } - - /** return range consisting of downward closure of a point */ - range range_downward(int _hi){ - range foo; - foo.lo = SHRT_MIN; - foo.hi = _hi; - return foo; - } - - void range_add(int i, range &n){ -#if 0 - if(i < n.lo) n.lo = i; - if(i > n.hi) n.hi = i; -#else - range rng; rng.lo = i; rng.hi = i; - n = range_lub(rng,n); -#endif - } - - /** Choose an element of rng1 that is near to rng2 */ - int range_near(const range &rng1, const range &rng2){ - int frame; - int thing = tree_lca(rng1.lo,rng2.hi); - if(thing == rng1.lo) frame = rng1.lo; - else frame = tree_gcd(thing,rng1.hi); - return frame; - } -#else - - struct range_lo { - int lo; - range_lo *next; - range_lo(int _lo, range_lo *_next){ - lo = _lo; - next = _next; - } - }; - - struct range { - int hi; - range_lo *lo; - range(int _hi, range_lo *_lo){ - hi = _hi; - lo = _lo; - } - range(){ - hi = SHRT_MIN; - lo = 0; - } - }; - - range_tables *rt; - - /** computes the lub (smallest containing subtree) of two ranges */ - range range_lub(const range &rng1, const range &rng2); - - /** computes the glb (intersection) of two ranges */ - range range_glb(const range &rng1, const range &rng2); - - /** is this range empty? */ - bool range_is_empty(const range &rng); - - /** return an empty range */ - range range_empty(); - - /** return a full range */ - range range_full(); - - /** return the maximal element of a range */ - int range_max(const range &rng); - - /** return a minimal (not necessarily unique) element of a range */ - int range_min(const range &rng); - - /** return range consisting of downward closure of a point */ - range range_downward(int _hi); - - /** add an element to a range */ - void range_add(int i, range &n); - - /** Choose an element of rng1 that is near to rng2 */ - int range_near(const range &rng1, const range &rng2); - - range_lo *find_range_lo(int lo, range_lo *next); - range_lo *range_lub_lo(range_lo *rng1, range_lo *rng2); - range_lo *range_glb_lo(range_lo *rng1, range_lo *rng2, int lim); - -#endif - - /** test whether a tree node is contained in a range */ - bool in_range(int n, const range &rng); - - /** test whether two ranges of tree nodes intersect */ - bool ranges_intersect(const range &rng1, const range &rng2); - - /** test whether range rng1 contained in range rng2 */ - bool range_contained(const range &rng1, const range &rng2); - - private: - int tree_lca(int n1, int n2); - int tree_gcd(int n1, int n2); - bool tree_mode(){return parents.size() != 0;} - - - -}; - -// let us hash on ranges - -#ifndef FULL_TREE -namespace hash_space { - template <> - class hash { - public: - size_t operator()(const scopes::range &p) const { - return (size_t)p.lo + (size_t)p.hi; - } - }; -} - -inline bool operator==(const scopes::range &x, const scopes::range &y){ - return x.lo == y.lo && x.hi == y.hi; -} -#endif - -#endif diff --git a/src/interp/iz3secondary.h b/src/interp/iz3secondary.h deleted file mode 100755 index a5a949b54..000000000 --- a/src/interp/iz3secondary.h +++ /dev/null @@ -1,40 +0,0 @@ -/*++ - Copyright (c) 2011 Microsoft Corporation - - Module Name: - - iz3secondary - - Abstract: - - Interface for secondary provers. - - Author: - - Ken McMillan (kenmcmil) - - Revision History: - - --*/ - - -#ifndef IZ3SECONDARY_H -#define IZ3SECONDARY_H - -/** Interface class for secondary provers. */ - -#include "interp/iz3base.h" -#include - -class iz3secondary : public iz3mgr { - public: - virtual int interpolate(const std::vector &frames, std::vector &interpolants) = 0; - virtual ~iz3secondary(){} - - protected: - iz3secondary(const iz3mgr &mgr) : iz3mgr(mgr) {} -}; - - - -#endif diff --git a/src/interp/iz3translate.cpp b/src/interp/iz3translate.cpp deleted file mode 100644 index 44bac0643..000000000 --- a/src/interp/iz3translate.cpp +++ /dev/null @@ -1,2200 +0,0 @@ -/*++ - Copyright (c) 2011 Microsoft Corporation - - Module Name: - - iz3translate.cpp - - Abstract: - - Translate a Z3 proof to in interpolated proof. - - Author: - - Ken McMillan (kenmcmil) - - Revision History: - - --*/ - -#ifdef _WINDOWS -#pragma warning(disable:4996) -#pragma warning(disable:4800) -#pragma warning(disable:4267) -#pragma warning(disable:4101) -#endif - -#include "interp/iz3translate.h" -#include "interp/iz3proof.h" -#include "interp/iz3profiling.h" -#include "interp/iz3interp.h" -#include "interp/iz3proof_itp.h" -#include "ast/ast_pp.h" - -#include -#include -#include -#include -#include -#include -#include - -//using std::vector; -using namespace stl_ext; - - - -/* This translator goes directly from Z3 proofs to interpolated - proofs without an intermediate representation. No secondary - prover is used. -*/ - - -#define throw_unsupported(_e_) { TRACE("iz3", tout << expr_ref((expr*)_e_.raw(), *_e_.mgr()) << "\n";); throw unsupported(_e_); } - -class iz3translation_full : public iz3translation { -public: - - - typedef iz3proof_itp Iproof; - - Iproof *iproof; - - /* Here we have lots of hash tables for memoizing various methods and - other such global data structures. - */ - - typedef hash_map AstToInt; - AstToInt locality; // memoizes locality of Z3 proof terms - - typedef std::pair EquivEntry; - typedef hash_map EquivTab; - EquivTab equivs; // maps non-local terms to equivalent local terms, with proof - - typedef hash_set AstHashSet; - AstHashSet equivs_visited; // proofs already checked for equivalences - - typedef std::pair, hash_map > AstToIpf; - AstToIpf translation; // Z3 proof nodes to Iproof nodes - - int frames; // number of frames - - typedef std::set AstSet; - typedef hash_map AstToAstSet; - AstToAstSet hyp_map; // map proof terms to hypothesis set - - struct LocVar { // localization vars - ast var; // a fresh variable - ast term; // term it represents - int frame; // frame in which it's defined - LocVar(ast v, ast t, int f){var=v;term=t;frame=f;} - }; - - std::vector localization_vars; // localization vars in order of creation - typedef hash_map AstToAst; - AstToAst localization_map; // maps terms to their localization vars - - typedef hash_map AstToBool; - AstToBool occurs_in_memo; // memo of occurs_in function - - AstHashSet cont_eq_memo; // memo of cont_eq function - - AstToAst subst_memo; // memo of subst function - - symb commute; - -public: - - -#define from_ast(x) (x) - - // #define NEW_LOCALITY - -#ifdef NEW_LOCALITY - range rng; // the range of frames in the "A" part of the interpolant -#endif - - /* To handle skolemization, we have to scan the proof for skolem - symbols and assign each to a frame. THe assignment is heuristic. - */ - - int scan_skolems_rec(hash_map &memo, const ast &proof, int frame){ - std::pair foo(proof,INT_MAX); - std::pair bar = memo.insert(foo); - int &res = bar.first->second; - if(!bar.second) return res; - pfrule dk = pr(proof); - if(dk == PR_ASSERTED){ - ast ass = conc(proof); - res = frame_of_assertion(ass); - } - else if(dk == PR_SKOLEMIZE){ - ast quanted = arg(conc(proof),0); - if(op(quanted) == Not) - quanted = arg(quanted,0); - // range r = ast_range(quanted); - // if(range_is_empty(r)) - range r = ast_scope(quanted); - if(range_is_empty(r)) - throw iz3_exception("can't skolemize"); - if(frame == INT_MAX || !in_range(frame,r)) - frame = range_max(r); // this is desperation -- may fail - if(frame >= frames) frame = frames - 1; - add_frame_range(frame,arg(conc(proof),1)); - r = ast_scope(arg(conc(proof),1)); - } - else if(dk==PR_MODUS_PONENS_OEQ){ - frame = scan_skolems_rec(memo,prem(proof,0),frame); - scan_skolems_rec(memo,prem(proof,1),frame); - } - else { - unsigned nprems = num_prems(proof); - for(unsigned i = 0; i < nprems; i++){ - int bar = scan_skolems_rec(memo,prem(proof,i),frame); - if(res == INT_MAX || res == bar) res = bar; - else if(bar != INT_MAX) res = -1; - } - } - return res; - } - - void scan_skolems(const ast &proof) { - hash_map memo; - scan_skolems_rec(memo,proof, INT_MAX); - } - - // determine locality of a proof term - // return frame of derivation if local, or -1 if not - // result INT_MAX means the proof term is a tautology - // memoized in hash_map "locality" - - int get_locality_rec(ast proof){ - std::pair foo(proof,INT_MAX); - std::pair bar = locality.insert(foo); - int &res = bar.first->second; - if(!bar.second) return res; - pfrule dk = pr(proof); - if(dk == PR_ASSERTED){ - ast ass = conc(proof); - res = frame_of_assertion(ass); -#ifdef NEW_LOCALITY - if(in_range(res,rng)) - res = range_max(rng); - else - res = frames-1; -#endif - } - else if(dk == PR_QUANT_INST){ - std::vector lits; - ast con = conc(proof); - get_Z3_lits(con, lits); - iproof->make_axiom(lits); - } -#ifdef LOCALIZATION_KLUDGE - else if(dk == PR_MODUS_PONENS && pr(prem(proof,0)) == PR_QUANT_INST - && get_locality_rec(prem(proof,1)) == INT_MAX){ - std::vector lits; - ast con = conc(proof); - get_Z3_lits(con, lits); - iproof->make_axiom(lits); - } -#endif - else { - unsigned nprems = num_prems(proof); - for(unsigned i = 0; i < nprems; i++){ - ast arg = prem(proof,i); - int bar = get_locality_rec(arg); - if(res == INT_MAX || res == bar) res = bar; - else if(bar != INT_MAX) res = -1; - } - } - return res; - } - - - int get_locality(ast proof){ - // if(lia_z3_axioms_only) return -1; - int res = get_locality_rec(proof); - if(res != -1){ - ast con = conc(proof); - range rng = ast_scope(con); - - // hack: if a clause contains "true", it reduces to "true", - // which means we won't compute the range correctly. we handle - // this case by computing the ranges of the literals separately - - if(is_true(con)){ - std::vector lits; - get_Z3_lits(conc(proof),lits); - for(unsigned i = 0; i < lits.size(); i++) - rng = range_glb(rng,ast_scope(lits[i])); - } - - if(!range_is_empty(rng)){ - AstSet &hyps = get_hyps(proof); - for(AstSet::iterator it = hyps.begin(), en = hyps.end(); it != en; ++it){ - ast hyp = *it; - rng = range_glb(rng,ast_scope(hyp)); - } - } - - // if(!range_is_empty(rng)){ - // if (num_free_variables(con) > 0) - // rng = range_empty(); - // } - - if(res == INT_MAX){ - if(range_is_empty(rng)) - res = -1; - else res = range_max(rng); - } - else { - if(!in_range(res,rng)) - res = -1; - } - } - return res; - } - - - AstSet &get_hyps(ast proof){ - std::pair foo(proof,AstSet()); - std::pair bar = hyp_map.insert(foo); - AstSet &res = bar.first->second; - if(!bar.second) return res; - pfrule dk = pr(proof); - if(dk == PR_HYPOTHESIS){ - ast con = conc(proof); - res.insert(con); - } - else { - unsigned nprems = num_prems(proof); - for(unsigned i = 0; i < nprems; i++){ - ast arg = prem(proof,i); - AstSet &arg_hyps = get_hyps(arg); - res.insert(arg_hyps.begin(),arg_hyps.end()); - } - if(dk == PR_LEMMA){ - ast con = conc(proof); - res.erase(mk_not(con)); - if(is_or(con)){ - int clause_size = num_args(con); - for(int i = 0; i < clause_size; i++){ - ast neglit = mk_not(arg(con,i)); - res.erase(neglit); - } - } - } - } -#if 0 - AstSet::iterator it = res.begin(), en = res.end(); - if(it != en){ - AstSet::iterator old = it; - ++it; - for(; it != en; ++it, ++old) - if(!(*old < *it)) - std::cout << "foo!"; - } -#endif - return res; - } - - // Find all the judgements of the form p <-> q, where - // p is local and q is non-local, recording them in "equivs" - // the map equivs_visited is used to record the already visited proof terms - - void find_equivs(ast proof){ - if(equivs_visited.find(proof) != equivs_visited.end()) - return; - equivs_visited.insert(proof); - unsigned nprems = num_prems(proof); - for(unsigned i = 0; i < nprems; i++) // do all the sub_terms - find_equivs(prem(proof,i)); - ast con = conc(proof); // get the conclusion - if(is_iff(con)){ - ast iff = con; - for(int i = 0; i < 2; i++) - if(!is_local(arg(iff,i)) && is_local(arg(iff,1-i))){ - std::pair > foo(arg(iff,i),std::pair(arg(iff,1-i),proof)); - equivs.insert(foo); - } - } - } - - // get the lits of a Z3 clause - void get_Z3_lits(ast t, std::vector &lits){ - opr dk = op(t); - if(dk == False) - return; // false = empty clause - if(dk == Or){ - unsigned nargs = num_args(t); - lits.resize(nargs); - for(unsigned i = 0; i < nargs; i++) // do all the sub_terms - lits[i] = arg(t,i); - } - else { - lits.push_back(t); - } - } - - // resolve two clauses represented as vectors of lits. replace first clause - void resolve(ast pivot, std::vector &cls1, std::vector &cls2){ - ast neg_pivot = mk_not(pivot); - for(unsigned i = 0; i < cls1.size(); i++){ - if(cls1[i] == pivot){ - cls1[i] = cls1.back(); - cls1.pop_back(); - bool found_pivot2 = false; - for(unsigned j = 0; j < cls2.size(); j++){ - if(cls2[j] == neg_pivot) - found_pivot2 = true; - else - cls1.push_back(cls2[j]); - } - (void)found_pivot2; - assert(found_pivot2); - return; - } - } - assert(0 && "resolve failed"); - } - - // get lits resulting from unit resolution up to and including "position" - // TODO: this is quadratic -- fix it - void do_unit_resolution(ast proof, int position, std::vector &lits){ - ast orig_clause = conc(prem(proof,0)); - get_Z3_lits(orig_clause,lits); - for(int i = 1; i <= position; i++){ - std::vector unit(1); - unit[0] = conc(prem(proof,i)); - resolve(mk_not(unit[0]),lits,unit); - } - } - -#if 0 - // clear the localization variables - void clear_localization(){ - localization_vars.clear(); - localization_map.clear(); - } - - // create a fresh variable for localization - ast fresh_localization_var(ast term, int frame){ - std::ostringstream s; - s << "%" << (localization_vars.size()); - ast var = make_var(s.str().c_str(),get_type(term)); - sym_range(sym(var)) = range_full(); // make this variable global - localization_vars.push_back(LocVar(var,term,frame)); - return var; - } - - - // "localize" a term to a given frame range by - // creating new symbols to represent non-local subterms - - ast localize_term(ast e, const range &rng){ - if(ranges_intersect(ast_scope(e),rng)) - return e; // this term occurs in range, so it's O.K. - AstToAst::iterator it = localization_map.find(e); - if(it != localization_map.end()) - return it->second; - - // if is is non-local, we must first localize the arguments to - // the range of its function symbol - - int nargs = num_args(e); - if(nargs > 0 /* && (!is_local(e) || flo <= hi || fhi >= lo) */){ - range frng = rng; - if(op(e) == Uninterpreted){ - symb f = sym(e); - range srng = sym_range(f); - if(ranges_intersect(srng,rng)) // localize to desired range if possible - frng = range_glb(srng,rng); - } - std::vector largs(nargs); - for(int i = 0; i < nargs; i++){ - largs[i] = localize_term(arg(e,i),frng); - frng = range_glb(frng,ast_scope(largs[i])); - } - e = clone(e,largs); - assert(is_local(e)); - } - - - if(ranges_intersect(ast_scope(e),rng)) - return e; // this term occurs in range, so it's O.K. - - // choose a frame for the constraint that is close to range - int frame = range_near(ast_scope(e),rng); - - ast new_var = fresh_localization_var(e,frame); - localization_map[e] = new_var; - ast cnst = make(Equal,new_var,e); - // antes.push_back(std::pair(cnst,frame)); - return new_var; - } - - // some patterm matching functions - - // match logical or with nargs arguments - // assumes AIG form - bool match_or(ast e, ast *args, int nargs){ - if(op(e) != Or) return false; - int n = num_args(e); - if(n != nargs) return false; - for(int i = 0; i < nargs; i++) - args[i] = arg(e,i); - return true; - } - - // match operator f with exactly nargs arguments - bool match_op(ast e, opr f, ast *args, int nargs){ - if(op(e) != f) return false; - int n = num_args(e); - if(n != nargs) return false; - for(int i = 0; i < nargs; i++) - args[i] = arg(e,i); - return true; - } - - // see if the given formula can be interpreted as - // an axiom instance (e.g., an array axiom instance). - // if so, add it to "antes" in an appropriate frame. - // this may require "localization" - - void get_axiom_instance(ast e){ - - // "store" axiom - // (or (= w q) (= (select (store a1 w y) q) (select a1 q))) - // std::cout << "ax: "; show(e); - ast lits[2],eq_ops_l[2],eq_ops_r[2],sel_ops[2], sto_ops[3], sel_ops2[2] ; - if(match_or(e,lits,2)) - if(match_op(lits[0],Equal,eq_ops_l,2)) - if(match_op(lits[1],Equal,eq_ops_r,2)) - for(int i = 0; i < 2; i++){ // try the second equality both ways - if(match_op(eq_ops_r[0],Select,sel_ops,2)) - if(match_op(sel_ops[0],Store,sto_ops,3)) - if(match_op(eq_ops_r[1],Select,sel_ops2,2)) - for(int j = 0; j < 2; j++){ // try the first equality both ways - if(eq_ops_l[0] == sto_ops[1] - && eq_ops_l[1] == sel_ops[1] - && eq_ops_l[1] == sel_ops2[1] - && sto_ops[0] == sel_ops2[0]) - if(is_local(sel_ops[0])) // store term must be local - { - ast sto = sel_ops[0]; - ast addr = localize_term(eq_ops_l[1],ast_scope(sto)); - ast res = make(Or, - make(Equal,eq_ops_l[0],addr), - make(Equal, - make(Select,sto,addr), - make(Select,sel_ops2[0],addr))); - // int frame = range_min(ast_scope(res)); TODO - // antes.push_back(std::pair(res,frame)); - return; - } - std::swap(eq_ops_l[0],eq_ops_l[1]); - } - std::swap(eq_ops_r[0],eq_ops_r[1]); - } - } - - // a quantifier instantation looks like (~ forall x. P) \/ P[z/x] - // we need to find a time frame for P, then localize P[z/x] in this frame - - void get_quantifier_instance(ast e){ - ast disjs[2]; - if(match_or(e,disjs,2)){ - if(is_local(disjs[0])){ - ast res = localize_term(disjs[1], ast_scope(disjs[0])); - // int frame = range_min(ast_scope(res)); TODO - // antes.push_back(std::pair(res,frame)); - return; - } - } - } - - ast get_judgement(ast proof){ - ast con = from_ast(conc(proof)); - AstSet &hyps = get_hyps(proof); - std::vector hyps_vec; - for(AstSet::iterator it = hyps.begin(), en = hyps.end(); it != en; ++it) - hyps_vec.push_back(*it); - if(hyps_vec.size() == 0) return con; - con = make(Or,mk_not(make(And,hyps_vec)),con); - return con; - } - - // does variable occur in expression? - int occurs_in1(ast var, ast e){ - std::pair foo(e,false); - std::pair bar = occurs_in_memo.insert(foo); - bool &res = bar.first->second; - if(bar.second){ - if(e == var) res = true; - int nargs = num_args(e); - for(int i = 0; i < nargs; i++) - res |= occurs_in1(var,arg(e,i)); - } - return res; - } - - int occurs_in(ast var, ast e){ - occurs_in_memo.clear(); - return occurs_in1(var,e); - } - - // find a controlling equality for a given variable v in a term - // a controlling equality is of the form v = t, which, being - // false would force the formula to have the specifid truth value - // returns t, or null if no such - - ast cont_eq(bool truth, ast v, ast e){ - if(is_not(e)) return cont_eq(!truth,v,arg(e,0)); - if(cont_eq_memo.find(e) != cont_eq_memo.end()) - return ast(); - cont_eq_memo.insert(e); - if(!truth && op(e) == Equal){ - if(arg(e,0) == v) return(arg(e,1)); - if(arg(e,1) == v) return(arg(e,0)); - } - if((!truth && op(e) == And) || (truth && op(e) == Or)){ - int nargs = num_args(e); - for(int i = 0; i < nargs; i++){ - ast res = cont_eq(truth, v, arg(e,i)); - if(!res.null()) return res; - } - } - return ast(); - } - - // substitute a term t for unbound occurrences of variable v in e - - ast subst(ast var, ast t, ast e){ - if(e == var) return t; - std::pair foo(e,ast()); - std::pair bar = subst_memo.insert(foo); - ast &res = bar.first->second; - if(bar.second){ - int nargs = num_args(e); - std::vector args(nargs); - for(int i = 0; i < nargs; i++) - args[i] = subst(var,t,arg(e,i)); - opr f = op(e); - if(f == Equal && args[0] == args[1]) res = mk_true(); - else res = clone(e,args); - } - return res; - } - - // apply a quantifier to a formula, with some optimizations - // 1) bound variable does not occur -> no quantifier - // 2) bound variable must be equal to some term -> substitute - - ast apply_quant(opr quantifier, ast var, ast e){ - if(!occurs_in(var,e))return e; - cont_eq_memo.clear(); - ast cterm = cont_eq(quantifier == Forall, var, e); - if(!cterm.null()){ - subst_memo.clear(); - return subst(var,cterm,e); - } - std::vector bvs; bvs.push_back(var); - return make_quant(quantifier,bvs,e); - } - - // add quantifiers over the localization vars - // to an interpolant for frames lo-hi - - ast add_quants(ast e, int lo, int hi){ - for(int i = localization_vars.size() - 1; i >= 0; i--){ - LocVar &lv = localization_vars[i]; - opr quantifier = (lv.frame >= lo && lv.frame <= hi) ? Exists : Forall; - e = apply_quant(quantifier,lv.var,e); - } - return e; - } - - int get_lits_locality(std::vector &lits){ - range rng = range_full(); - for(std::vector::iterator it = lits.begin(), en = lits.end(); it != en; ++it){ - ast lit = *it; - rng = range_glb(rng,ast_scope(lit)); - } - if(range_is_empty(rng)) return -1; - int hi = range_max(rng); - if(hi >= frames) return frames - 1; - return hi; - } -#endif - - int num_lits(ast ast){ - opr dk = op(ast); - if(dk == False) - return 0; - if(dk == Or){ - unsigned nargs = num_args(ast); - int n = 0; - for(unsigned i = 0; i < nargs; i++) // do all the sub_terms - n += num_lits(arg(ast,i)); - return n; - } - else - return 1; - } - - void symbols_out_of_scope_rec(hash_set &memo, hash_set &symb_memo, int frame, const ast &t){ - if(memo.find(t) != memo.end()) - return; - memo.insert(t); - if(op(t) == Uninterpreted){ - symb s = sym(t); - range r = sym_range(s); - if(!in_range(frame,r) && symb_memo.find(s) == symb_memo.end()){ - std::cout << string_of_symbol(s) << "\n"; - symb_memo.insert(s); - } - } - int nargs = num_args(t); - for(int i = 0; i < nargs; i++) - symbols_out_of_scope_rec(memo,symb_memo,frame,arg(t,i)); - } - - void symbols_out_of_scope(int frame, const ast &t){ - hash_set memo; - hash_set symb_memo; - symbols_out_of_scope_rec(memo,symb_memo,frame,t); - } - - void conc_symbols_out_of_scope(int frame, const ast &t){ - symbols_out_of_scope(frame,conc(t)); - } - - std::vector lit_trace; - hash_set marked_proofs; - - bool proof_has_lit(const ast &proof, const ast &lit){ - AstSet &hyps = get_hyps(proof); - if(hyps.find(mk_not(lit)) != hyps.end()) - return true; - std::vector lits; - ast con = conc(proof); - get_Z3_lits(con, lits); - for(unsigned i = 0; i < lits.size(); i++) - if(lits[i] == lit) - return true; - return false; - } - - - void trace_lit_rec(const ast &lit, const ast &proof, AstHashSet &memo){ - if(memo.find(proof) == memo.end()){ - memo.insert(proof); - AstSet &hyps = get_hyps(proof); - std::vector lits; - for(AstSet::iterator it = hyps.begin(), en = hyps.end(); it != en; ++it) - lits.push_back(mk_not(*it)); - ast con = conc(proof); - get_Z3_lits(con, lits); - for(unsigned i = 0; i < lits.size(); i++){ - if(lits[i] == lit){ - print_expr(std::cout,proof); - std::cout << "\n"; - marked_proofs.insert(proof); - pfrule dk = pr(proof); - if(dk == PR_UNIT_RESOLUTION || dk == PR_LEMMA){ - unsigned nprems = num_prems(proof); - for(unsigned i = 0; i < nprems; i++){ - ast arg = prem(proof,i); - trace_lit_rec(lit,arg,memo); - } - } - else - lit_trace.push_back(proof); - } - } - } - } - - ast traced_lit; - - int trace_lit(const ast &lit, const ast &proof){ - marked_proofs.clear(); - lit_trace.clear(); - traced_lit = lit; - AstHashSet memo; - trace_lit_rec(lit,proof,memo); - return lit_trace.size(); - } - - bool is_literal_or_lit_iff(const ast &lit){ - if(my_is_literal(lit)) return true; - if(op(lit) == Iff){ - return my_is_literal(arg(lit,0)) && my_is_literal(arg(lit,1)); - } - return false; - } - - bool my_is_literal(const ast &lit){ - ast abslit = is_not(lit) ? arg(lit,0) : lit; - int f = op(abslit); - return !(f == And || f == Or || f == Iff); - } - - hash_map asts_by_id; - - void print_lit(const ast &lit){ - ast abslit = is_not(lit) ? arg(lit,0) : lit; - if(!is_literal_or_lit_iff(lit)){ - if(is_not(lit)) std::cout << "~"; - int id = ast_id(abslit); - asts_by_id[id] = abslit; - std::cout << "[" << id << "]"; - } - else - print_expr(std::cout,lit); - } - - void expand(int id){ - if(asts_by_id.find(id) == asts_by_id.end()) - std::cout << "undefined\n"; - else { - ast lit = asts_by_id[id]; - std::string s = string_of_symbol(sym(lit)); - std::cout << "(" << s; - unsigned nargs = num_args(lit); - for(unsigned i = 0; i < nargs; i++){ - std::cout << " "; - print_lit(arg(lit,i)); - } - std::cout << ")\n";; - } - } - - void show_lit(const ast &lit){ - print_lit(lit); - std::cout << "\n"; - } - - void print_z3_lit(const ast &a){ - print_lit(from_ast(a)); - } - - void show_z3_lit(const ast &a){ - print_z3_lit(a); - std::cout << "\n"; - } - - - void show_con(const ast &proof, bool brief){ - if(!traced_lit.null() && proof_has_lit(proof,traced_lit)) - std::cout << "(*) "; - ast con = conc(proof); - AstSet &hyps = get_hyps(proof); - int count = 0; - for(AstSet::iterator it = hyps.begin(), en = hyps.end(); it != en; ++it){ - if(brief && ++count > 5){ - std::cout << "... "; - break; - } - print_lit(*it); - std::cout << " "; - } - std::cout << "|- "; - std::vector lits; - get_Z3_lits(con,lits); - for(unsigned i = 0; i < lits.size(); i++){ - print_lit(lits[i]); - std::cout << " "; - } - range r = ast_scope(con); - std::cout << " {" << r.lo << "," << r.hi << "}"; - std::cout << "\n"; - } - - void show_step(const ast &proof){ - std::cout << "\n"; - unsigned nprems = num_prems(proof); - for(unsigned i = 0; i < nprems; i++){ - std::cout << "(" << i << ") "; - ast arg = prem(proof,i); - show_con(arg,true); - } - std::cout << "|------ "; - std::cout << string_of_symbol(sym(proof)) << "\n"; - show_con(proof,false); - } - - void show_marked( const ast &proof){ - std::cout << "\n"; - unsigned nprems = num_prems(proof); - for(unsigned i = 0; i < nprems; i++){ - ast arg = prem(proof,i); - if(!traced_lit.null() && proof_has_lit(arg,traced_lit)){ - std::cout << "(" << i << ") "; - show_con(arg,true); - } - } - } - - std::vector pfhist; - int pfhist_pos; - - void pfgoto(const ast &proof){ - if(pfhist.size() == 0) - pfhist_pos = 0; - else pfhist_pos++; - pfhist.resize(pfhist_pos); - pfhist.push_back(proof); - show_step(proof); - } - - - void pfback(){ - if(pfhist_pos > 0){ - pfhist_pos--; - show_step(pfhist[pfhist_pos]); - } - } - - void pffwd(){ - if(pfhist_pos < ((int)pfhist.size()) - 1){ - pfhist_pos++; - show_step(pfhist[pfhist_pos]); - } - } - - void pfprem(int i){ - if(pfhist.size() > 0){ - ast proof = pfhist[pfhist_pos]; - unsigned nprems = num_prems(proof); - if(i >= 0 && i < (int)nprems) - pfgoto(prem(proof,i)); - } - } - - - - // translate a unit resolution sequence - Iproof::node translate_ur(ast proof){ - ast prem0 = prem(proof,0); - Iproof::node itp = translate_main(prem0,true); - std::vector clause; - ast conc0 = conc(prem0); - int nprems = num_prems(proof); - if(nprems == 2 && conc0 == mk_not(conc(prem(proof,1)))) - clause.push_back(conc0); - else - get_Z3_lits(conc0,clause); - for(int position = 1; position < nprems; position++){ - ast ante = prem(proof,position); - ast pnode = conc(ante); - ast pnode_abs = !is_not(pnode) ? pnode : mk_not(pnode); - Iproof::node neg = itp; - Iproof::node pos = translate_main(ante, false); - if(is_not(pnode)){ - pnode = mk_not(pnode); - std::swap(neg,pos); - } - std::vector unit(1); - unit[0] = conc(ante); - resolve(mk_not(conc(ante)),clause,unit); - itp = iproof->make_resolution(pnode,clause,neg,pos); - } - return itp; - } - - // get an inequality in the form 0 <= t where t is a linear term - ast rhs_normalize_inequality(const ast &ineq){ - ast zero = make_int("0"); - ast thing = make(Leq,zero,zero); - linear_comb(thing,make_int("1"),ineq); - thing = simplify_ineq(thing); - return thing; - } - - bool check_farkas(const std::vector &prems, const ast &con){ - ast zero = make_int("0"); - ast thing = make(Leq,zero,zero); - for(unsigned i = 0; i < prems.size(); i++) - linear_comb(thing,make_int(rational(1)),prems[i]); - linear_comb(thing,make_int(rational(-1)),con); - thing = simplify_ineq(thing); - return arg(thing,1) == make_int(rational(0)); - } - - // get an inequality in the form t <= c or t < c, there t is affine and c constant - ast normalize_inequality(const ast &ineq){ - ast zero = make_int("0"); - ast thing = make(Leq,zero,zero); - linear_comb(thing,make_int("1"),ineq); - thing = simplify_ineq(thing); - ast lhs = arg(thing,0); - ast rhs = arg(thing,1); - opr o = op(rhs); - if(o != Numeral){ - if(op(rhs) == Plus){ - int nargs = num_args(rhs); - ast const_term = zero; - int i = 0; - if(nargs > 0 && op(arg(rhs,0)) == Numeral){ - const_term = arg(rhs,0); - i++; - } - if(i < nargs){ - std::vector non_const; - for(; i < nargs; i++) - non_const.push_back(arg(rhs,i)); - lhs = make(Sub,lhs,make(Plus,non_const)); - } - rhs = const_term; - } - else { - lhs = make(Sub,lhs,make(Plus,rhs)); - rhs = zero; - } - lhs = z3_simplify(lhs); - rhs = z3_simplify(rhs); - thing = make(op(thing),lhs,rhs); - } - return thing; - } - - void get_linear_coefficients(const ast &t, std::vector &coeffs){ - if(op(t) == Plus){ - int nargs = num_args(t); - for(int i = 0; i < nargs; i++) - coeffs.push_back(get_coeff(arg(t,i))); - } - else - coeffs.push_back(get_coeff(t)); - } - - /* given an affine term t, get the GCD of the coefficients in t. */ - ast gcd_of_coefficients(const ast &t){ - std::vector coeffs; - get_linear_coefficients(t,coeffs); - if(coeffs.size() == 0) - return make_int("1"); // arbitrary - rational d = abs(coeffs[0]); - for(unsigned i = 1; i < coeffs.size(); i++){ - d = gcd(d,coeffs[i]); - } - return make_int(d); - } - - ast get_bounded_variable(const ast &ineq, bool &lb){ - ast nineq = normalize_inequality(ineq); - ast lhs = arg(nineq,0); - lhs.raw(); - switch(op(lhs)){ - case Uninterpreted: - lb = false; - return lhs; - case Times: - if(arg(lhs,0) == make_int(rational(1))) - lb = false; - else if(arg(lhs,0) == make_int(rational(-1))) - lb = true; - else - throw_unsupported(lhs); - return arg(lhs,1); - default: - throw_unsupported(lhs); - } - } - - rational get_term_coefficient(const ast &t1, const ast &v){ - ast t = arg(normalize_inequality(t1),0); - if(op(t) == Plus){ - int nargs = num_args(t); - for(int i = 0; i < nargs; i++){ - if(get_linear_var(arg(t,i)) == v) - return get_coeff(arg(t,i)); - } - } - else - if(get_linear_var(t) == v) - return get_coeff(t); - return rational(0); - } - - - Iproof::node GCDtoDivRule(const ast &proof, bool pol, std::vector &coeffs, std::vector &prems, ast &cut_con){ - // gather the summands of the desired polarity - std::vector my_prems; - std::vector my_coeffs; - std::vector my_prem_cons; - for(unsigned i = pol ? 0 : 1; i < coeffs.size(); i+= 2){ - rational &c = coeffs[i]; - if(c.is_pos()){ - my_prems.push_back(prems[i]); - my_coeffs.push_back(make_int(c)); - my_prem_cons.push_back(conc(prem(proof,i))); - } - else if(c.is_neg()){ - int j = (i % 2 == 0) ? i + 1 : i - 1; - my_prems.push_back(prems[j]); - my_coeffs.push_back(make_int(-coeffs[j])); - my_prem_cons.push_back(conc(prem(proof,j))); - } - } - ast my_con = sum_inequalities(my_coeffs,my_prem_cons); - - // handle generalized GCD test. sadly, we dont' get the coefficients... - if(coeffs[0].is_zero()){ - bool lb; - int xtra_prem = 0; - ast bv = get_bounded_variable(conc(prem(proof,0)),lb); - rational bv_coeff = get_term_coefficient(my_con,bv); - if(bv_coeff.is_pos() != lb) - xtra_prem = 1; - if(bv_coeff.is_neg()) - bv_coeff = -bv_coeff; - - my_prems.push_back(prems[xtra_prem]); - my_coeffs.push_back(make_int(bv_coeff)); - my_prem_cons.push_back(conc(prem(proof,xtra_prem))); - my_con = sum_inequalities(my_coeffs,my_prem_cons); - } - - my_con = normalize_inequality(my_con); - Iproof::node hyp = iproof->make_hypothesis(mk_not(my_con)); - my_prems.push_back(hyp); - my_coeffs.push_back(make_int("1")); - my_prem_cons.push_back(mk_not(my_con)); - Iproof::node res = iproof->make_farkas(mk_false(),my_prems,my_prem_cons,my_coeffs); - - ast t = arg(my_con,0); - ast c = arg(my_con,1); - ast d = gcd_of_coefficients(t); - t = z3_simplify(mk_idiv(t,d)); - c = z3_simplify(mk_idiv(c,d)); - cut_con = make(op(my_con),t,c); - return iproof->make_cut_rule(my_con,d,cut_con,res); - } - - - rational get_first_coefficient(const ast &t, ast &v){ - if(op(t) == Plus){ - unsigned best_id = UINT_MAX; - rational best_coeff(0); - int nargs = num_args(t); - for(int i = 0; i < nargs; i++) - if(op(arg(t,i)) != Numeral){ - ast lv = get_linear_var(arg(t,i)); - unsigned id = ast_id(lv); - if(id < best_id) { - v = lv; - best_id = id; - best_coeff = get_coeff(arg(t,i)); - } - } - return best_coeff; - } - else - if(op(t) != Numeral){ - v = get_linear_var(t); - return(get_coeff(t)); - } - return rational(0); - } - - ast divide_inequalities(const ast &x, const ast&y){ - ast xvar, yvar; - rational xcoeff = get_first_coefficient(arg(x,0),xvar); - rational ycoeff = get_first_coefficient(arg(y,0),yvar); - if(xcoeff == rational(0) || ycoeff == rational(0) || xvar != yvar) - throw_unsupported(x); // can be caused by non-linear arithmetic - rational ratio = xcoeff/ycoeff; - if(denominator(ratio) != rational(1)) - throw_unsupported(y); // can this ever happen? - return make_int(ratio); // better be integer! - } - - ast AssignBounds2Farkas(const ast &proof, const ast &con){ - std::vector farkas_coeffs; - get_assign_bounds_coeffs(proof,farkas_coeffs); - int nargs = num_args(con); - if(nargs != (int)(farkas_coeffs.size())) - throw_unsupported(proof); // should never happen -#if 0 - if(farkas_coeffs[0] != make_int(rational(1))) - farkas_coeffs[0] = make_int(rational(1)); -#else - std::vector lits, lit_coeffs; - for(int i = 1; i < nargs; i++){ - lits.push_back(mk_not(arg(con,i))); - lit_coeffs.push_back(farkas_coeffs[i]); - } - ast sum = normalize_inequality(sum_inequalities(lit_coeffs,lits)); - ast conseq = normalize_inequality(arg(con,0)); - ast d = divide_inequalities(sum,conseq); -#if 0 - if(d != farkas_coeffs[0]) - std::cout << "wow!\n"; -#endif - farkas_coeffs[0] = d; -#endif - std::vector my_coeffs; - std::vector my_cons; - for(int i = 1; i < nargs; i++){ - my_cons.push_back(mk_not(arg(con,i))); - my_coeffs.push_back(farkas_coeffs[i]); - } - ast farkas_con = normalize_inequality(sum_inequalities(my_coeffs,my_cons,true /* round_off */)); - my_cons.push_back(mk_not(farkas_con)); - my_coeffs.push_back(make_int("1")); - std::vector my_hyps; - my_hyps.reserve(nargs); - for(int i = 0; i < nargs; i++) - my_hyps.push_back(iproof->make_hypothesis(my_cons[i])); - ast res = iproof->make_farkas(mk_false(),my_hyps,my_cons,my_coeffs); - res = iproof->make_cut_rule(farkas_con,farkas_coeffs[0],arg(con,0),res); - return res; - } - - ast AssignBoundsRule2Farkas(const ast &proof, const ast &con, std::vector prems){ - std::vector farkas_coeffs; - get_assign_bounds_rule_coeffs(proof,farkas_coeffs); - int nargs = num_prems(proof)+1; - if(nargs != (int)(farkas_coeffs.size())) - throw iz3_exception("bad assign-bounds theory lemma"); -#if 0 - if(farkas_coeffs[0] != make_int(rational(1))) - farkas_coeffs[0] = make_int(rational(1)); -#else - std::vector lits, lit_coeffs; - for(int i = 1; i < nargs; i++){ - lits.push_back(conc(prem(proof,i-1))); - lit_coeffs.push_back(farkas_coeffs[i]); - } - ast sum = normalize_inequality(sum_inequalities(lit_coeffs,lits)); - ast conseq = normalize_inequality(con); - ast d = divide_inequalities(sum,conseq); -#if 0 - if(d != farkas_coeffs[0]) - std::cout << "wow!\n"; -#endif - farkas_coeffs[0] = d; -#endif - std::vector my_coeffs; - std::vector my_cons; - for(int i = 1; i < nargs; i++){ - my_cons.push_back(conc(prem(proof,i-1))); - my_coeffs.push_back(farkas_coeffs[i]); - } - ast farkas_con = normalize_inequality(sum_inequalities(my_coeffs,my_cons,true /* round_off */)); - std::vector my_hyps; - for(int i = 1; i < nargs; i++) - my_hyps.push_back(prems[i-1]); - my_cons.push_back(mk_not(farkas_con)); - my_coeffs.push_back(make_int("1")); - my_hyps.push_back(iproof->make_hypothesis(mk_not(farkas_con))); - ast res = iproof->make_farkas(mk_false(),my_hyps,my_cons,my_coeffs); - res = iproof->make_cut_rule(farkas_con,farkas_coeffs[0],conc(proof),res); - return res; - } - - ast GomoryCutRule2Farkas(const ast &proof, const ast &con, std::vector prems){ - std::vector my_prems = prems; - std::vector my_coeffs; - std::vector my_prem_cons; - get_gomory_cut_coeffs(proof,my_coeffs); - int nargs = num_prems(proof); - if(nargs != (int)(my_coeffs.size())) - throw "bad gomory-cut theory lemma"; - my_prem_cons.reserve(nargs); - for(int i = 0; i < nargs; i++) - my_prem_cons.push_back(conc(prem(proof,i))); - ast my_con = normalize_inequality(sum_inequalities(my_coeffs,my_prem_cons)); - Iproof::node hyp = iproof->make_hypothesis(mk_not(my_con)); - my_prems.push_back(hyp); - my_coeffs.push_back(make_int("1")); - my_prem_cons.push_back(mk_not(my_con)); - Iproof::node res = iproof->make_farkas(mk_false(),my_prems,my_prem_cons,my_coeffs); - ast t = arg(my_con,0); - ast c = arg(my_con,1); - ast d = gcd_of_coefficients(t); - /* - t = z3_simplify(mk_idiv(t,d)); - c = z3_simplify(mk_idiv(c,d)); - ast cut_con = make(op(my_con),t,c); - */ - ast cut_con = con; - return iproof->make_cut_rule(my_con,d,cut_con,res); - } - - Iproof::node RewriteClause(Iproof::node clause, const ast &rew){ - if(pr(rew) == PR_MONOTONICITY){ - int nequivs = num_prems(rew); - for(int i = 0; i < nequivs; i++){ - Iproof::node equiv_pf = translate_main(prem(rew,i),false); - ast equiv = conc(prem(rew,i)); - clause = iproof->make_mp(equiv,clause,equiv_pf); - } - return clause; - } - if(pr(rew) == PR_TRANSITIVITY){ - clause = RewriteClause(clause,prem(rew,0)); - clause = RewriteClause(clause,prem(rew,1)); - return clause; - } - if(pr(rew) == PR_REWRITE){ - return clause; // just hope the rewrite does nothing! - } - throw_unsupported(rew); - } - - - // Following code is for elimination of "commutativity" axiom - - Iproof::node make_commuted_modus_ponens(const ast &proof, const std::vector &args){ - ast pf = arg(args[1],0); - ast comm_equiv = arg(args[1],1); // equivalence relation with possible commutations - ast P = conc(prem(proof,0)); - ast Q = conc(proof); - Iproof::node P_pf = args[0]; - ast P_comm = arg(comm_equiv,0); - ast Q_comm = arg(comm_equiv,1); - if(P != P_comm) - P_pf = iproof->make_symmetry(P_comm,P,P_pf); - Iproof::node res = iproof->make_mp(comm_equiv,P_pf,pf); - if(Q != Q_comm) - res = iproof->make_symmetry(Q,Q_comm,res); - return res; - } - - Iproof::node make_commuted_monotonicity(const ast &proof, const std::vector &args){ - ast pf = arg(args[0],0); - ast comm_equiv = arg(args[0],1); // equivalence relation with possible commutations - ast con = make(Iff,make(Not,arg(comm_equiv,0)),make(Not,arg(comm_equiv,1))); - std::vector eqs; eqs.push_back(comm_equiv); - std::vector pfs; pfs.push_back(pf); - ast res = iproof->make_congruence(eqs,con,pfs); - res = make(commute,res,con); - return res; - } - - Iproof::node make_commuted_symmetry(const ast &proof, const std::vector &args){ - ast pf = arg(args[0],0); - ast comm_equiv = arg(args[0],1); // equivalence relation with possible commutations - ast con = make(Iff,arg(comm_equiv,1),arg(comm_equiv,0)); - ast res = iproof->make_symmetry(con,comm_equiv,pf); - res = make(commute,res,con); - return res; - } - - void unpack_commuted(const ast &proof, const ast &cm, ast &pf, ast &comm_equiv){ - if(sym(cm) == commute){ - pf = arg(cm,0); - comm_equiv = arg(cm,1); - } - else { - pf = cm; - comm_equiv = conc(proof); - } - } - - Iproof::node make_commuted_transitivity(const ast &proof, const std::vector &args){ - ast pf[2], comm_equiv[2]; - for(int i = 0; i < 2; i++) - unpack_commuted(prem(proof,i),args[i],pf[i],comm_equiv[i]); - if(!(arg(comm_equiv[0],1) == arg(comm_equiv[1],0))){ - ast tw = twist(prem(proof,1)); - ast np = translate_main(tw,false); - unpack_commuted(tw,np,pf[1],comm_equiv[1]); - } - ast con = make(Iff,arg(comm_equiv[0],0),arg(comm_equiv[1],1)); - ast res = iproof->make_transitivity(arg(comm_equiv[0],0),arg(comm_equiv[0],1),arg(comm_equiv[1],1),pf[0],pf[1]); - res = make(commute,res,con); - return res; - } - - ast commute_equality(const ast &eq){ - return make(Equal,arg(eq,1),arg(eq,0)); - } - - ast commute_equality_iff(const ast &con){ - if(op(con) != Iff || op(arg(con,0)) != Equal) - throw_unsupported(con); - return make(Iff,commute_equality(arg(con,0)),commute_equality(arg(con,1))); - } - - // convert a proof of a=b <-> c=d into a proof of b=a <-> d=c - // TODO: memoize this? - ast twist(const ast &proof){ - pfrule dk = pr(proof); - ast con = commute_equality_iff(conc(proof)); - int n = num_prems(proof); - std::vector prs(n); - if(dk == PR_MONOTONICITY){ - for(int i = 0; i < n; i++) - prs[i] = prem(proof,i); - } - else - for(int i = 0; i < n; i++) - prs[i] = twist(prem(proof,i)); - switch(dk){ - case PR_MONOTONICITY: - case PR_SYMMETRY: - case PR_TRANSITIVITY: - case PR_COMMUTATIVITY: - prs.push_back(con); - return clone(proof,prs); - default: - throw_unsupported(proof); - } - } - - struct TermLt { - iz3mgr &m; - bool operator()(const ast &x, const ast &y){ - unsigned xid = m.ast_id(x); - unsigned yid = m.ast_id(y); - return xid < yid; - } - TermLt(iz3mgr &_m) : m(_m) {} - }; - - void SortTerms(std::vector &terms){ - TermLt foo(*this); - std::sort(terms.begin(),terms.end(),foo); - } - - ast SortSum(const ast &t){ - if(!(op(t) == Plus)) - return t; - int nargs = num_args(t); - if(nargs < 2) return t; - std::vector args(nargs); - for(int i = 0; i < nargs; i++) - args[i] = arg(t,i); - SortTerms(args); - return make(Plus,args); - } - - void get_sum_as_vector(const ast &t, std::vector &coeffs, std::vector &vars){ - if(!(op(t) == Plus)){ - coeffs.push_back(get_coeff(t)); - vars.push_back(get_linear_var(t)); - } - else { - int nargs = num_args(t); - for(int i = 0; i < nargs; i++) - get_sum_as_vector(arg(t,i),coeffs,vars); - } - } - - ast replace_summands_with_fresh_vars(const ast &t, hash_map &map){ - if(op(t) == Plus){ - int nargs = num_args(t); - std::vector args(nargs); - for(int i = 0; i < nargs; i++) - args[i] = replace_summands_with_fresh_vars(arg(t,i),map); - return make(Plus,args); - } - if(op(t) == Times) - return make(Times,arg(t,0),replace_summands_with_fresh_vars(arg(t,1),map)); - if(map.find(t) == map.end()) - map[t] = mk_fresh_constant("@s",get_type(t)); - return map[t]; - } - - rational lcd(const std::vector &rats){ - rational res = rational(1); - for(unsigned i = 0; i < rats.size(); i++){ - res = lcm(res,denominator(rats[i])); - } - return res; - } - - Iproof::node reconstruct_farkas_with_dual(const std::vector &prems, const std::vector &pfs, const ast &con){ - int nprems = prems.size(); - std::vector npcons(nprems); - hash_map pain_map; // not needed - for(int i = 0; i < nprems; i++){ - npcons[i] = painfully_normalize_ineq(conc(prems[i]),pain_map); - if(op(npcons[i]) == Lt){ - ast constval = z3_simplify(make(Sub,arg(npcons[i],1),make_int(rational(1)))); - npcons[i] = make(Leq,arg(npcons[i],0),constval); - } - } - ast ncon = painfully_normalize_ineq(mk_not(con),pain_map); - npcons.push_back(ncon); - - hash_map dual_map; - std::vector cvec, vars_seen; - m().enable_int_real_coercions(true); - ast rhs = make_real(rational(0)); - for(unsigned i = 0; i < npcons.size(); i++){ - ast c= mk_fresh_constant("@c",real_type()); - cvec.push_back(c); - ast lhs = arg(npcons[i],0); - std::vector coeffs; - std::vector vars; - get_sum_as_vector(lhs,coeffs,vars); - for(unsigned j = 0; j < coeffs.size(); j++){ - rational coeff = coeffs[j]; - ast var = vars[j]; - if(dual_map.find(var) == dual_map.end()){ - dual_map[var] = make_real(rational(0)); - vars_seen.push_back(var); - } - ast foo = make(Plus,dual_map[var],make(Times,make_real(coeff),c)); - dual_map[var] = foo; - } - rhs = make(Plus,rhs,make(Times,c,arg(npcons[i],1))); - } - std::vector cnstrs; - for(unsigned i = 0; i < vars_seen.size(); i++) - cnstrs.push_back(make(Equal,dual_map[vars_seen[i]],make_real(rational(0)))); - cnstrs.push_back(make(Leq,rhs,make_real(rational(0)))); - for(unsigned i = 0; i < cvec.size() - 1; i++) - cnstrs.push_back(make(Geq,cvec[i],make_real(rational(0)))); - cnstrs.push_back(make(Equal,cvec.back(),make_real(rational(1)))); - ast new_proof; - - // greedily reduce the core - for(unsigned i = 0; i < cvec.size() - 1; i++){ - std::vector dummy; - cnstrs.push_back(make(Equal,cvec[i],make_real(rational(0)))); - if(!is_sat(cnstrs,new_proof,dummy)) - cnstrs.pop_back(); - } - - std::vector vals = cvec; - if(!is_sat(cnstrs,new_proof,vals)) - throw iz3_exception("Proof error!"); - std::vector rat_farkas_coeffs; - for(unsigned i = 0; i < cvec.size(); i++){ - ast bar = vals[i]; - rational r; - if(is_numeral(bar,r)) - rat_farkas_coeffs.push_back(r); - else - throw iz3_exception("Proof error!"); - } - rational the_lcd = lcd(rat_farkas_coeffs); - std::vector farkas_coeffs; - std::vector my_prems; - std::vector my_pcons; - for(unsigned i = 0; i < prems.size(); i++){ - ast fc = make_int(rat_farkas_coeffs[i] * the_lcd); - if(!(fc == make_int(rational(0)))){ - farkas_coeffs.push_back(fc); - my_prems.push_back(pfs[i]); - my_pcons.push_back(conc(prems[i])); - } - } - farkas_coeffs.push_back(make_int(the_lcd)); - my_prems.push_back(iproof->make_hypothesis(mk_not(con))); - my_pcons.push_back(mk_not(con)); - - Iproof::node res = iproof->make_farkas(mk_false(),my_prems,my_pcons,farkas_coeffs); - return res; - } - - ast painfully_normalize_ineq(const ast &ineq, hash_map &map){ - ast res = normalize_inequality(ineq); - ast lhs = arg(res,0); - lhs = replace_summands_with_fresh_vars(lhs,map); - res = make(op(res),SortSum(lhs),arg(res,1)); - return res; - } - - Iproof::node painfully_reconstruct_farkas(const std::vector &prems, const std::vector &pfs, const ast &con){ - int nprems = prems.size(); - std::vector pcons(nprems),npcons(nprems); - hash_map pcon_to_pf, npcon_to_pcon, pain_map; - for(int i = 0; i < nprems; i++){ - pcons[i] = conc(prems[i]); - npcons[i] = painfully_normalize_ineq(pcons[i],pain_map); - pcon_to_pf[npcons[i]] = pfs[i]; - npcon_to_pcon[npcons[i]] = pcons[i]; - } - // ast leq = make(Leq,arg(con,0),arg(con,1)); - ast ncon = painfully_normalize_ineq(mk_not(con),pain_map); - pcons.push_back(mk_not(con)); - npcons.push_back(ncon); - // ast assumps = make(And,pcons); - ast new_proof; - std::vector dummy; - if(is_sat(npcons,new_proof,dummy)) - throw iz3_exception("Proof error!"); - pfrule dk = pr(new_proof); - int nnp = num_prems(new_proof); - std::vector my_prems; - std::vector farkas_coeffs, my_pcons; - - if(dk == PR_TH_LEMMA - && get_theory_lemma_theory(new_proof) == ArithTheory - && get_theory_lemma_kind(new_proof) == FarkasKind) - get_farkas_coeffs(new_proof,farkas_coeffs); - else if(dk == PR_UNIT_RESOLUTION && nnp == 2){ - for(int i = 0; i < nprems; i++) - farkas_coeffs.push_back(make_int(rational(1))); - } - else - return reconstruct_farkas_with_dual(prems,pfs,con); - - for(int i = 0; i < nnp; i++){ - ast p = conc(prem(new_proof,i)); - p = really_normalize_ineq(p); - if(pcon_to_pf.find(p) != pcon_to_pf.end()){ - my_prems.push_back(pcon_to_pf[p]); - my_pcons.push_back(npcon_to_pcon[p]); - } - else if(p == ncon){ - my_prems.push_back(iproof->make_hypothesis(mk_not(con))); - my_pcons.push_back(mk_not(con)); - } - else - return reconstruct_farkas_with_dual(prems,pfs,con); - } - Iproof::node res = iproof->make_farkas(mk_false(),my_prems,my_pcons,farkas_coeffs); - return res; - } - - - - ast really_normalize_ineq(const ast &ineq){ - ast res = normalize_inequality(ineq); - res = make(op(res),SortSum(arg(res,0)),arg(res,1)); - return res; - } - - Iproof::node reconstruct_farkas(const std::vector &prems, const std::vector &pfs, const ast &con){ - int nprems = prems.size(); - std::vector pcons(nprems),npcons(nprems); - hash_map pcon_to_pf, npcon_to_pcon; - for(int i = 0; i < nprems; i++){ - pcons[i] = conc(prems[i]); - npcons[i] = really_normalize_ineq(pcons[i]); - pcon_to_pf[npcons[i]] = pfs[i]; - npcon_to_pcon[npcons[i]] = pcons[i]; - } - // ast leq = make(Leq,arg(con,0),arg(con,1)); - ast ncon = really_normalize_ineq(mk_not(con)); - pcons.push_back(mk_not(con)); - npcons.push_back(ncon); - // ast assumps = make(And,pcons); - ast new_proof; - std::vector dummy; - if(is_sat(npcons,new_proof,dummy)) - throw iz3_exception("Proof error!"); - pfrule dk = pr(new_proof); - int nnp = num_prems(new_proof); - std::vector my_prems; - std::vector farkas_coeffs, my_pcons; - - if(dk == PR_TH_LEMMA - && get_theory_lemma_theory(new_proof) == ArithTheory - && get_theory_lemma_kind(new_proof) == FarkasKind) - get_farkas_coeffs(new_proof,farkas_coeffs); - else if(dk == PR_UNIT_RESOLUTION && nnp == 2){ - for(int i = 0; i < nprems; i++) - farkas_coeffs.push_back(make_int(rational(1))); - } - else - return painfully_reconstruct_farkas(prems,pfs,con); - - for(int i = 0; i < nnp; i++){ - ast p = conc(prem(new_proof,i)); - p = really_normalize_ineq(p); - if(pcon_to_pf.find(p) != pcon_to_pf.end()){ - my_prems.push_back(pcon_to_pf[p]); - my_pcons.push_back(npcon_to_pcon[p]); - } - else if(p == ncon){ - my_prems.push_back(iproof->make_hypothesis(mk_not(con))); - my_pcons.push_back(mk_not(con)); - } - else - return painfully_reconstruct_farkas(prems,pfs,con); - } - Iproof::node res = iproof->make_farkas(mk_false(),my_prems,my_pcons,farkas_coeffs); - return res; - } - - bool is_eq_propagate(const ast &proof){ - return pr(proof) == PR_TH_LEMMA && get_theory_lemma_theory(proof) == ArithTheory && get_theory_lemma_kind(proof) == EqPropagateKind; - } - - ast EqPropagate(const ast &con, const std::vector &prems, const std::vector &args){ - Iproof::node fps[2]; - ast ineq_con[2]; - for(int i = 0; i < 2; i++){ - opr o = i == 0 ? Leq : Geq; - ineq_con[i] = make(o, arg(con,0), arg(con,1)); - fps[i] = reconstruct_farkas(prems,args,ineq_con[i]); - } - ast res = iproof->make_leq2eq(arg(con,0), arg(con,1), ineq_con[0], ineq_con[1]); - std::vector dummy_clause; - for(int i = 0; i < 2; i++) - res = iproof->make_resolution(ineq_con[i],dummy_clause,res,fps[i]); - return res; - } - - ast ArithMysteryRule(const ast &con, const std::vector &prems, const std::vector &args){ - // Hope for the best! - Iproof::node guess = reconstruct_farkas(prems,args,con); - return guess; - } - - struct CannotCombineEqPropagate {}; - - void CombineEqPropagateRec(const ast &proof, std::vector &prems, std::vector &args, ast &eqprem){ - if(pr(proof) == PR_TRANSITIVITY && is_eq_propagate(prem(proof,1))){ - CombineEqPropagateRec(prem(proof,0), prems, args, eqprem); - ast dummy; - CombineEqPropagateRec(prem(proof,1), prems, args, dummy); - return; - } - if(is_eq_propagate(proof)){ - int nprems = num_prems(proof); - for(int i = 0; i < nprems; i++){ - prems.push_back(prem(proof,i)); - ast ppf = translate_main(prem(proof,i),false); - args.push_back(ppf); - } - return; - } - eqprem = proof; - } - - ast CombineEqPropagate(const ast &proof){ - std::vector prems, args; - ast eq1; - CombineEqPropagateRec(proof, prems, args, eq1); - ast eq2con = conc(proof); - if(!eq1.null()) - eq2con = make(Equal,arg(conc(eq1),1),arg(conc(proof),1)); - ast eq2 = EqPropagate(eq2con,prems,args); - if(!eq1.null()){ - Iproof::node foo = translate_main(eq1,false); - eq2 = iproof->make_transitivity(arg(conc(eq1),0), arg(conc(eq1),1), arg(conc(proof),1), foo, eq2); - } - return eq2; - } - - bool get_store_array(const ast &t, ast &res){ - if(op(t) == Store){ - res = t; - return true; - } - int nargs = num_args(t); - for(int i = 0; i < nargs; i++) - if(get_store_array(arg(t,i),res)) - return true; - return false; - } - - // translate a Z3 proof term into interpolating proof system - - Iproof::node translate_main(ast proof, bool expect_clause = true){ - AstToIpf &tr = translation; - hash_map &trc = expect_clause ? tr.first : tr.second; - std::pair foo(proof,Iproof::node()); - std::pair::iterator, bool> bar = trc.insert(foo); - Iproof::node &res = bar.first->second; - if(!bar.second) return res; - - // Try the locality rule first - - int frame = get_locality(proof); - if(frame != -1){ - ast e = from_ast(conc(proof)); - if(frame >= frames) frame = frames - 1; - std::vector foo; - if(expect_clause) - get_Z3_lits(conc(proof),foo); - else - foo.push_back(e); - AstSet &hyps = get_hyps(proof); - for(AstSet::iterator it = hyps.begin(), en = hyps.end(); it != en; ++it) - foo.push_back(mk_not(*it)); - res = iproof->make_assumption(frame,foo); - return res; - } - - // If the proof is not local, break it down by proof rule - - pfrule dk = pr(proof); - unsigned nprems = num_prems(proof); - if(dk == PR_UNIT_RESOLUTION){ - res = translate_ur(proof); - } - else if(dk == PR_LEMMA){ - ast contra = prem(proof,0); // this is a proof of false from some hyps - res = translate_main(contra); - if(!expect_clause){ - std::vector foo; // the negations of the hyps form a clause - foo.push_back(from_ast(conc(proof))); - AstSet &hyps = get_hyps(proof); - for(AstSet::iterator it = hyps.begin(), en = hyps.end(); it != en; ++it) - foo.push_back(mk_not(*it)); - res = iproof->make_contra(res,foo); - } - } - else { - std::vector lits; - ast con = conc(proof); - if(expect_clause) - get_Z3_lits(con, lits); - else - lits.push_back(from_ast(con)); - - // pattern match some idioms - if(dk == PR_MODUS_PONENS && pr(prem(proof,0)) == PR_QUANT_INST){ - if(get_locality_rec(prem(proof,1)) == INT_MAX) { - res = iproof->make_axiom(lits); - return res; - } - } - if(dk == PR_MODUS_PONENS && expect_clause && op(con) == Or && op(conc(prem(proof,0))) == Or){ - Iproof::node clause = translate_main(prem(proof,0),true); - res = RewriteClause(clause,prem(proof,1)); - return res; - } - -#if 0 - if(dk == PR_MODUS_PONENS && expect_clause && op(con) == Or) - std::cout << "foo!\n"; -#endif - - // no idea why this shows up - if(dk == PR_MODUS_PONENS_OEQ){ - if(conc(prem(proof,0)) == con){ - res = translate_main(prem(proof,0),expect_clause); - return res; - } - if(expect_clause && op(con) == Or){ // skolemization does this - Iproof::node clause = translate_main(prem(proof,0),true); - res = RewriteClause(clause,prem(proof,1)); - return res; - } - } - -#if 0 - if(1 && dk == PR_TRANSITIVITY && pr(prem(proof,1)) == PR_COMMUTATIVITY){ - Iproof::node clause = translate_main(prem(proof,0),true); - res = make(commute,clause,conc(prem(proof,0))); // HACK -- we depend on Iproof::node being same as ast. - return res; - } - - if(1 && dk == PR_TRANSITIVITY && pr(prem(proof,0)) == PR_COMMUTATIVITY){ - Iproof::node clause = translate_main(prem(proof,1),true); - res = make(commute,clause,conc(prem(proof,1))); // HACK -- we depend on Iproof::node being same as ast. - return res; - } -#endif - - if(dk == PR_TRANSITIVITY && is_eq_propagate(prem(proof,1))){ - try { - res = CombineEqPropagate(proof); - return res; - } - catch(const CannotCombineEqPropagate &){ - } - } - - /* this is the symmetry rule for ~=, that is, takes x ~= y and yields y ~= x. - the proof idiom uses commutativity, monotonicity and mp, but we replace it here - with symmtrey and resolution, that is, we prove y = x |- x = y, then resolve - with the proof of ~(x=y) to get ~y=x. */ - if(dk == PR_MODUS_PONENS && pr(prem(proof,1)) == PR_MONOTONICITY && pr(prem(prem(proof,1),0)) == PR_COMMUTATIVITY && num_prems(prem(proof,1)) == 1){ - Iproof::node ante = translate_main(prem(proof,0),false); - ast eq0 = arg(conc(prem(prem(proof,1),0)),0); - ast eq1 = arg(conc(prem(prem(proof,1),0)),1); - Iproof::node eq1hy = iproof->make_hypothesis(eq1); - Iproof::node eq0pf = iproof->make_symmetry(eq0,eq1,eq1hy); - std::vector clause; // just a dummy - res = iproof->make_resolution(eq0,clause,ante,eq0pf); - return res; - } - - /* This idiom takes ~P and Q=P, yielding ~Q. It uses a "rewrite" - (Q=false) = ~Q. We eliminate the rewrite by using symmetry, - congruence and modus ponens. */ - - if(dk == PR_MODUS_PONENS && pr(prem(proof,1)) == PR_REWRITE && pr(prem(proof,0)) == PR_TRANSITIVITY && pr(prem(prem(proof,0),1)) == PR_IFF_FALSE){ - if(op(con) == Not && arg(con,0) == arg(conc(prem(proof,0)),0)){ - Iproof::node ante1 = translate_main(prem(prem(proof,0),0),false); - Iproof::node ante2 = translate_main(prem(prem(prem(proof,0),1),0),false); - ast ante1_con = conc(prem(prem(proof,0),0)); - ast eq0 = arg(ante1_con,0); - ast eq1 = arg(ante1_con,1); - ast symm_con = make(Iff,eq1,eq0); - Iproof::node ante1s = iproof->make_symmetry(symm_con,ante1_con,ante1); - ast cong_con = make(Iff,make(Not,eq1),make(Not,eq0)); - Iproof::node ante1sc = iproof->make_congruence(symm_con,cong_con,ante1s); - res = iproof->make_mp(cong_con,ante2,ante1sc); - return res; - } - } - - - // translate all the premises - std::vector args(nprems); - for(unsigned i = 0; i < nprems; i++) - args[i] = translate_main(prem(proof,i),false); - - for(unsigned i = 0; i < nprems; i++) - if(sym(args[i]) == commute - && !(dk == PR_TRANSITIVITY || dk == PR_MODUS_PONENS || dk == PR_SYMMETRY || (dk == PR_MONOTONICITY && op(arg(con,0)) == Not))) - throw_unsupported(proof); - - switch(dk){ - case PR_TRANSITIVITY: { - if(sym(args[0]) == commute || sym(args[1]) == commute) - res = make_commuted_transitivity(proof,args); - else { - // assume the premises are x = y, y = z - ast x = arg(conc(prem(proof,0)),0); - ast y = arg(conc(prem(proof,0)),1); - ast z = arg(conc(prem(proof,1)),1); - res = iproof->make_transitivity(x,y,z,args[0],args[1]); - } - break; - } - case PR_TRANSITIVITY_STAR: { - // assume the premises are x = y, y = z, z = u, u = v, .. - - ast x = arg(conc(prem(proof,0)),0); - ast y = arg(conc(prem(proof,0)),1); - ast z = arg(conc(prem(proof,1)),1); - res = iproof->make_transitivity(x,y,z,args[0],args[1]); - - for (unsigned i = 2; i < nprems; ++i) { - y = z; - z = arg(conc(prem(proof,i)),1); - res = iproof->make_transitivity(x,y,z,res,args[i]); - } - break; - } - case PR_QUANT_INTRO: - case PR_MONOTONICITY: - { - std::vector eqs; eqs.resize(args.size()); - for(unsigned i = 0; i < args.size(); i++) - eqs[i] = conc(prem(proof,i)); - if(op(arg(con,0)) == Not && sym(args[0]) == commute) - res = make_commuted_monotonicity(proof,args); - else - res = iproof->make_congruence(eqs,con,args); - break; - } - case PR_REFLEXIVITY: { - res = iproof->make_reflexivity(con); - break; - } - case PR_SYMMETRY: { - if(sym(args[0]) == commute) - res = make_commuted_symmetry(proof,args); - else - res = iproof->make_symmetry(con,conc(prem(proof,0)),args[0]); - break; - } - case PR_MODUS_PONENS: { - if(sym(args[1]) == commute) - res = make_commuted_modus_ponens(proof,args); - else - res = iproof->make_mp(conc(prem(proof,1)),args[0],args[1]); - break; - } - case PR_TH_LEMMA: { - switch(get_theory_lemma_theory(proof)){ - case ArithTheory: - switch(get_theory_lemma_kind(proof)){ - case FarkasKind: { - std::vector farkas_coeffs, prem_cons; - get_farkas_coeffs(proof,farkas_coeffs); - if(nprems == 0) {// axiom, not rule - int nargs = num_args(con); - if(farkas_coeffs.size() != (unsigned)nargs){ - pfgoto(proof); - throw_unsupported(proof); - } - for(int i = 0; i < nargs; i++){ - ast lit = mk_not(arg(con,i)); - prem_cons.push_back(lit); - args.push_back(iproof->make_hypothesis(lit)); - } - } - else { // rule version (proves false) - prem_cons.resize(nprems); - for(unsigned i = 0; i < nprems; i++) - prem_cons[i] = conc(prem(proof,i)); - } - res = iproof->make_farkas(con,args,prem_cons,farkas_coeffs); - break; - } - case Leq2EqKind: { - // conc should be (or x = y (not (leq x y)) (not(leq y z)) ) - ast xeqy = arg(conc(proof),0); - ast x = arg(xeqy,0); - ast y = arg(xeqy,1); - res = iproof->make_leq2eq(x,y,arg(arg(conc(proof),1),0),arg(arg(conc(proof),2),0)); - break; - } - case Eq2LeqKind: { - // conc should be (or (not (= x y)) (leq x y)) - ast xeqy = arg(arg(conc(proof),0),0); - ast xleqy = arg(conc(proof),1); - ast x = arg(xeqy,0); - ast y = arg(xeqy,1); - res = iproof->make_eq2leq(x,y,xleqy); - break; - } - case GCDTestKind: { - std::vector farkas_coeffs; - get_broken_gcd_test_coeffs(proof,farkas_coeffs); - if(farkas_coeffs.size() != nprems){ - pfgoto(proof); - throw_unsupported(proof); - } - std::vector my_prems; my_prems.resize(2); - std::vector my_prem_cons; my_prem_cons.resize(2); - std::vector my_farkas_coeffs; my_farkas_coeffs.resize(2); - my_prems[0] = GCDtoDivRule(proof, true, farkas_coeffs, args, my_prem_cons[0]); - my_prems[1] = GCDtoDivRule(proof, false, farkas_coeffs, args, my_prem_cons[1]); - ast con = mk_false(); - my_farkas_coeffs[0] = my_farkas_coeffs[1] = make_int("1"); - res = iproof->make_farkas(con,my_prems,my_prem_cons,my_farkas_coeffs); - break; - } - case AssignBoundsKind: { - if(args.size() > 0) - res = AssignBoundsRule2Farkas(proof, conc(proof), args); - else - res = AssignBounds2Farkas(proof,conc(proof)); - break; - } - case GomoryCutKind: { - if(args.size() > 0) - res = GomoryCutRule2Farkas(proof, conc(proof), args); - else - throw_unsupported(proof); - break; - } - case EqPropagateKind: { - std::vector prems(nprems); - for(unsigned i = 0; i < nprems; i++) - prems[i] = prem(proof,i); - res = EqPropagate(con,prems,args); - break; - } - case ArithMysteryKind: { - // Z3 hasn't told us what kind of lemma this is -- maybe we can guess - std::vector prems(nprems); - for(unsigned i = 0; i < nprems; i++) - prems[i] = prem(proof,i); - res = ArithMysteryRule(con,prems,args); - break; - } - default: - throw_unsupported(proof); - } - break; - case ArrayTheory: {// nothing fancy for this - ast store_array; - if(get_store_array(con,store_array)) - res = iproof->make_axiom(lits,ast_scope(store_array)); - else - res = iproof->make_axiom(lits); // for array extensionality axiom - break; - } - default: - throw_unsupported(proof); - } - break; - } - case PR_HYPOTHESIS: { - res = iproof->make_hypothesis(conc(proof)); - break; - } - case PR_QUANT_INST: { - res = iproof->make_axiom(lits); - break; - } - case PR_DEF_AXIOM: { // this should only happen for formulas resulting from quantifier instantiation - res = iproof->make_axiom(lits); - break; - } - case PR_IFF_TRUE: { // turns p into p <-> true, noop for us - res = args[0]; - break; - } - case PR_IFF_FALSE: { // turns ~p into p <-> false, noop for us - if(is_local(con)) - res = args[0]; - else - throw_unsupported(proof); - break; - } - case PR_COMMUTATIVITY: { - ast comm_equiv = make(op(con),arg(con,0),arg(con,0)); - ast pf = iproof->make_reflexivity(comm_equiv); - res = make(commute,pf,comm_equiv); - break; - } - case PR_NOT_OR_ELIM: - case PR_AND_ELIM: { - std::vector rule_ax, res_conc; - ast piv = conc(prem(proof,0)); - rule_ax.push_back(make(Not,piv)); - rule_ax.push_back(con); - ast pf = iproof->make_axiom(rule_ax); - res_conc.push_back(con); - res = iproof->make_resolution(piv,res_conc,pf,args[0]); - break; - } - default: - IF_VERBOSE(0, verbose_stream() << "Unsupported proof rule: " << expr_ref((expr*)proof.raw(), *proof.mgr()) << "\n";); - // pfgoto(proof); - // SASSERT(0 && "translate_main: unsupported proof rule"); - throw_unsupported(proof); - } - } - - return res; - } - - void clear_translation(){ - translation.first.clear(); - translation.second.clear(); - } - - // We actually compute the interpolant here and then produce a proof consisting of just a lemma - - iz3proof::node translate(ast proof, iz3proof &dst) override { - std::vector itps; - scan_skolems(proof); - for(int i = 0; i < frames -1; i++){ -#ifdef NEW_LOCALITY - rng = range_downward(i); - locality.clear(); -#endif - iproof = iz3proof_itp::create(this,range_downward(i),weak_mode()); - try { - Iproof::node ipf = translate_main(proof); - ast itp = iproof->interpolate(ipf); - itps.push_back(itp); - delete iproof; - clear_translation(); - } - catch (const iz3proof_itp::proof_error &) { - delete iproof; - clear_translation(); - throw iz3proof::proof_error(); - } - catch (const unsupported &exc) { - delete iproof; - clear_translation(); - throw exc; - } - } - // Very simple proof -- lemma of the empty clause with computed interpolation - iz3proof::node Ipf = dst.make_lemma(std::vector(),itps); // builds result in dst - return Ipf; - } - - iz3translation_full(iz3mgr &mgr, - iz3secondary *_secondary, - const std::vector > &cnsts, - const std::vector &parents, - const std::vector &theory) - : iz3translation(mgr, cnsts, parents, theory) - { - frames = cnsts.size(); - traced_lit = ast(); - type boolbooldom[2] = {bool_type(),bool_type()}; - commute = function("@commute",2,boolbooldom,bool_type()); - m().inc_ref(commute); - } - - ~iz3translation_full() override { - m().dec_ref(commute); - } -}; - - - - -#ifdef IZ3_TRANSLATE_FULL - -iz3translation *iz3translation::create(iz3mgr &mgr, - iz3secondary *secondary, - const std::vector > &cnsts, - const std::vector &parents, - const std::vector &theory){ - return new iz3translation_full(mgr,secondary,cnsts,parents,theory); -} - - -#if 1 - -// This is just to make sure certain methods are compiled, so we can call then from the debugger. - -void iz3translation_full_trace_lit(iz3translation_full *p, iz3mgr::ast lit, iz3mgr::ast proof){ - p->trace_lit(lit, proof); -} - -void iz3translation_full_show_step(iz3translation_full *p, iz3mgr::ast proof){ - p->show_step(proof); -} - -void iz3translation_full_show_marked(iz3translation_full *p, iz3mgr::ast proof){ - p->show_marked(proof); -} - -void iz3translation_full_show_lit(iz3translation_full *p, iz3mgr::ast lit){ - p->show_lit(lit); -} - -void iz3translation_full_show_z3_lit(iz3translation_full *p, iz3mgr::ast a){ - p->show_z3_lit(a); -} - -void iz3translation_full_pfgoto(iz3translation_full *p, iz3mgr::ast proof){ - p->pfgoto(proof); -} - - -void iz3translation_full_pfback(iz3translation_full *p ){ - p->pfback(); -} - -void iz3translation_full_pffwd(iz3translation_full *p ){ - p->pffwd(); -} - -void iz3translation_full_pfprem(iz3translation_full *p, int i){ - p->pfprem(i); -} - -void iz3translation_full_expand(iz3translation_full *p, int i){ - p->expand(i); -} - -void iz3translation_full_symbols_out_of_scope(iz3translation_full *p, int i, const iz3mgr::ast &t){ - p->symbols_out_of_scope(i,t); -} - -void iz3translation_full_conc_symbols_out_of_scope(iz3translation_full *p, int i, const iz3mgr::ast &t){ - p->conc_symbols_out_of_scope(i,t); -} - -struct stdio_fixer { - stdio_fixer(){ - std::cout.rdbuf()->pubsetbuf(nullptr,0); - } - -} my_stdio_fixer; - -#endif - -#endif - - diff --git a/src/interp/iz3translate.h b/src/interp/iz3translate.h deleted file mode 100755 index d80c3b3fe..000000000 --- a/src/interp/iz3translate.h +++ /dev/null @@ -1,63 +0,0 @@ -/*++ - Copyright (c) 2011 Microsoft Corporation - - Module Name: - - iz3translate.h - - Abstract: - - Interface for proof translations from Z3 proofs to interpolatable - proofs. - - Author: - - Ken McMillan (kenmcmil) - - Revision History: - - --*/ - - -#ifndef IZ3TRANSLATION_H -#define IZ3TRANSLATION_H - -#include "interp/iz3proof.h" -#include "interp/iz3secondary.h" - -// This is a interface class for translation from Z3 proof terms to -// an interpolatable proof - -class iz3translation : public iz3base { - public: - virtual iz3proof::node translate(ast, iz3proof &) = 0; - virtual ast quantify(ast e, const range &rng){return e;} - virtual ~iz3translation(){} - - /** This is thrown when the proof cannot be translated. */ - struct unsupported: public iz3_exception { - raw_ast* m_ast; - unsupported(ast const& a): iz3_exception("unsupported"), m_ast(a.raw()) { } - }; - - static iz3translation *create(iz3mgr &mgr, - iz3secondary *secondary, - const std::vector > &frames, - const std::vector &parents, - const std::vector &theory); - - protected: - iz3translation(iz3mgr &mgr, - const std::vector > &_cnsts, - const std::vector &_parents, - const std::vector &_theory) - : iz3base(mgr,_cnsts,_parents,_theory) {} -}; - -// To use a secondary prover, define IZ3_TRANSLATE_DIRECT instead of this -#define IZ3_TRANSLATE_FULL - -#endif - - - diff --git a/src/interp/iz3translate_direct.cpp b/src/interp/iz3translate_direct.cpp deleted file mode 100644 index 9efb1a383..000000000 --- a/src/interp/iz3translate_direct.cpp +++ /dev/null @@ -1,1717 +0,0 @@ -/*++ - Copyright (c) 2011 Microsoft Corporation - - Module Name: - - iz3translate_direct.cpp - - Abstract: - - Translate a Z3 proof into the interpolating proof calculus. - Translation is direct, without transformations on the target proof - representation. - - Author: - - Ken McMillan (kenmcmil) - - Revision History: - - --*/ - - -#ifdef _WINDOWS -#pragma warning(disable:4996) -#pragma warning(disable:4800) -#pragma warning(disable:4267) -#pragma warning(disable:4101) -#pragma warning(disable:4390) -#endif - -#include "interp/iz3translate.h" -#include "interp/iz3proof.h" -#include "interp/iz3profiling.h" -#include "interp/iz3interp.h" - -#include -#include -#include -#include -#include -#include -#include - -//using std::vector; -using namespace stl_ext; - -/* This can introduce an address dependency if the range type of hash_map has - a destructor. Since the code in this file is not used and only here for - historical comparisons, we allow this non-determinism. -*/ -namespace stl_ext { - template - class hash { - public: - size_t operator()(const T *p) const { - return (size_t) p; - } - }; -} - -static int lemma_count = 0; -#if 0 -static int nll_lemma_count = 0; -#endif -#define SHOW_LEMMA_COUNT -1 - -// One half of a resolution. We need this to distinguish -// between resolving as a clause and as a unit clause. -// if pivot == conclusion(proof) it is unit. - -struct Z3_resolvent { - iz3base::ast proof; - bool is_unit; - iz3base::ast pivot; - Z3_resolvent(const iz3base::ast &_proof, bool _is_unit, const iz3base::ast &_pivot){ - proof = _proof; - is_unit = _is_unit; - pivot = _pivot; - } -}; - -namespace hash_space { - template <> - class hash { - public: - size_t operator()(const Z3_resolvent &p) const { - return (p.proof.hash() + p.pivot.hash()); - } - }; -} - - -bool operator==(const Z3_resolvent &x, const Z3_resolvent &y) { - return x.proof == y.proof && x.pivot == y.pivot; -} - - - -typedef std::vector ResolventAppSet; - -struct non_local_lits { - ResolventAppSet proofs; // the proof nodes being raised - non_local_lits(ResolventAppSet &_proofs){ - proofs.swap(_proofs); - } -}; - -namespace hash_space { - template <> - class hash { - public: - size_t operator()(const non_local_lits &p) const { - size_t h = 0; - for(ResolventAppSet::const_iterator it = p.proofs.begin(), en = p.proofs.end(); it != en; ++it) - h += (size_t)*it; - return h; - } - }; -} - - -bool operator==(const non_local_lits &x, const non_local_lits &y) { - ResolventAppSet::const_iterator itx = x.proofs.begin(); - ResolventAppSet::const_iterator ity = y.proofs.begin(); - while(true){ - if(ity == y.proofs.end()) return itx == x.proofs.end(); - if(itx == x.proofs.end()) return ity == y.proofs.end(); - if(*itx != *ity) return false; - ++itx; ++ity; - } -} - - -/* This translator goes directly from Z3 proofs to interpolatable - proofs without an intermediate representation as an iz3proof. */ - -class iz3translation_direct : public iz3translation { -public: - - typedef ast Zproof; // type of non-interpolating proofs - typedef iz3proof Iproof; // type of interpolating proofs - - /* Here we have lots of hash tables for memoizing various methods and - other such global data structures. - */ - - typedef hash_map AstToInt; - AstToInt locality; // memoizes locality of Z3 proof terms - - typedef std::pair EquivEntry; - typedef hash_map EquivTab; - EquivTab equivs; // maps non-local terms to equivalent local terms, with proof - - typedef hash_set AstHashSet; - AstHashSet equivs_visited; // proofs already checked for equivalences - - - typedef std::pair, hash_map > AstToIpf; - AstToIpf translation; // Zproof nodes to Iproof nodes - - AstHashSet antes_added; // Z3 proof terms whose antecedents have been added to the list - std::vector > antes; // list of antecedent/frame pairs - std::vector local_antes; // list of local antecedents - - Iproof *iproof; // the interpolating proof we are constructing - - int frames; // number of frames - - typedef std::set AstSet; - typedef hash_map AstToAstSet; - AstToAstSet hyp_map; // map proof terms to hypothesis set - - struct LocVar { // localization vars - ast var; // a fresh variable - ast term; // term it represents - int frame; // frame in which it's defined - LocVar(ast v, ast t, int f){var=v;term=t;frame=f;} - }; - - std::vector localization_vars; // localization vars in order of creation - typedef hash_map AstToAst; - AstToAst localization_map; // maps terms to their localization vars - - typedef hash_map AstToBool; - - - - iz3secondary *secondary; // the secondary prover - - // Unique table for sets of non-local resolutions - hash_map non_local_lits_unique; - - // Unique table for resolvents - hash_map Z3_resolvent_unique; - - // Translation memo for case of non-local resolutions - hash_map non_local_translation; - -public: - - -#define from_ast(x) (x) - - // determine locality of a proof term - // return frame of derivation if local, or -1 if not - // result INT_MAX means the proof term is a tautology - // memoized in hash_map "locality" - - int get_locality_rec(ast proof){ - std::pair foo(proof,INT_MAX); - std::pair bar = locality.insert(foo); - int &res = bar.first->second; - if(!bar.second) return res; - if(pr(proof) == PR_ASSERTED){ - ast ass = conc(proof); - res = frame_of_assertion(ass); - } - else { - unsigned nprems = num_prems(proof); - for(unsigned i = 0; i < nprems; i++){ - ast arg = prem(proof,i); - int bar = get_locality_rec(arg); - if(res == INT_MAX || res == bar) res = bar; - else if(bar != INT_MAX) res = -1; - } - } - return res; - } - - - int get_locality(ast proof){ - // if(lia_z3_axioms_only) return -1; - int res = get_locality_rec(proof); - if(res != -1){ - ast con = conc(proof); - range rng = ast_scope(con); - - // hack: if a clause contains "true", it reduces to "true", - // which means we won't compute the range correctly. we handle - // this case by computing the ranges of the literals separately - - if(is_true(con)){ - std::vector lits; - get_Z3_lits(conc(proof),lits); - for(unsigned i = 0; i < lits.size(); i++) - rng = range_glb(rng,ast_scope(lits[i])); - } - - if(!range_is_empty(rng)){ - AstSet &hyps = get_hyps(proof); - for(AstSet::iterator it = hyps.begin(), en = hyps.end(); it != en; ++it){ - ast hyp = *it; - rng = range_glb(rng,ast_scope(hyp)); - } - } - - if(res == INT_MAX){ - if(range_is_empty(rng)) - res = -1; - else res = range_max(rng); - } - else { - if(!in_range(res,rng)) - res = -1; - } - } - return res; - } - - AstSet &get_hyps(ast proof){ - std::pair foo(proof,AstSet()); - std::pair bar = hyp_map.insert(foo); - AstSet &res = bar.first->second; - if(!bar.second) return res; - pfrule dk = pr(proof); - if(dk == PR_HYPOTHESIS){ - ast con = conc(proof); - res.insert(con); - } - else { - unsigned nprems = num_prems(proof); - for(unsigned i = 0; i < nprems; i++){ - ast arg = prem(proof,i); - AstSet &arg_hyps = get_hyps(arg); - res.insert(arg_hyps.begin(),arg_hyps.end()); - } - if(dk == PR_LEMMA){ - ast con = conc(proof); - res.erase(mk_not(con)); - if(is_or(con)){ - int clause_size = num_args(con); - for(int i = 0; i < clause_size; i++){ - ast neglit = mk_not(arg(con,i)); - res.erase(neglit); - } - } - } - } -#if 0 - AstSet::iterator it = res.begin(), en = res.end(); - if(it != en){ - AstSet::iterator old = it; - ++it; - for(; it != en; ++it, ++old) - if(!(*old < *it)) - std::cout << "foo!"; - } -#endif - return res; - } - - - // Find all the judgements of the form p <-> q, where - // p is local and q is non-local, recording them in "equivs" - // the map equivs_visited is used to record the already visited proof terms - - void find_equivs(ast proof){ - if(equivs_visited.find(proof) != equivs_visited.end()) - return; - equivs_visited.insert(proof); - unsigned nprems = num_prems(proof); - for(unsigned i = 0; i < nprems; i++) // do all the sub_terms - find_equivs(prem(proof,i)); - ast con = conc(proof); // get the conclusion - if(is_iff(con)){ - ast iff = con; - for(int i = 0; i < 2; i++) - if(!is_local(arg(iff,i)) && is_local(arg(iff,1-i))){ - std::pair > foo(arg(iff,i),std::pair(arg(iff,1-i),proof)); - equivs.insert(foo); - } - } - } - - // get the lits of a Z3 clause as secondary prover terms - void get_Z3_lits(ast t, std::vector &lits){ - opr dk = op(t); - if(dk == False) - return; // false = empty clause - if(dk == Or){ - unsigned nargs = num_args(t); - lits.resize(nargs); - for(unsigned i = 0; i < nargs; i++) // do all the sub_terms - lits[i] = arg(t,i); - } - else { - lits.push_back(t); - } - } - - // resolve two clauses represented as vectors of lits. replace first clause - void resolve(ast pivot, std::vector &cls1, std::vector &cls2){ - ast neg_pivot = mk_not(pivot); - for(unsigned i = 0; i < cls1.size(); i++){ - if(cls1[i] == pivot){ - cls1[i] = cls1.back(); - cls1.pop_back(); - bool found_pivot2 = false; - for(unsigned j = 0; j < cls2.size(); j++){ - if(cls2[j] == neg_pivot) - found_pivot2 = true; - else - cls1.push_back(cls2[j]); - } - (void)found_pivot2; - assert(found_pivot2); - return; - } - } - assert(0 && "resolve failed"); - } - - // get lits resulting from unit resolution up to and including "position" - // TODO: this is quadratic -- fix it - void do_unit_resolution(ast proof, int position, std::vector &lits){ - ast orig_clause = conc(prem(proof,0)); - get_Z3_lits(orig_clause,lits); - for(int i = 1; i <= position; i++){ - std::vector unit(1); - unit[0] = conc(prem(proof,i)); - resolve(mk_not(unit[0]),lits,unit); - } - } - - - // clear the localization variables - void clear_localization(){ - localization_vars.clear(); - localization_map.clear(); - } - - // create a fresh variable for localization - ast fresh_localization_var(ast term, int frame){ - std::ostringstream s; - s << "%" << (localization_vars.size()); - ast var = make_var(s.str().c_str(),get_type(term)); - sym_range(sym(var)) = range_full(); // make this variable global - localization_vars.push_back(LocVar(var,term,frame)); - return var; - } - - - // "localize" a term to a given frame range by - // creating new symbols to represent non-local subterms - - ast localize_term(ast e, const range &rng){ - if(ranges_intersect(ast_scope(e),rng)) - return e; // this term occurs in range, so it's O.K. - AstToAst::iterator it = localization_map.find(e); - if(it != localization_map.end()) - return it->second; - - // if is is non-local, we must first localize the arguments to - // the range of its function symbol - - int nargs = num_args(e); - if(nargs > 0 /* && (!is_local(e) || flo <= hi || fhi >= lo) */){ - range frng = rng; - if(op(e) == Uninterpreted){ - symb f = sym(e); - range srng = sym_range(f); - if(ranges_intersect(srng,rng)) // localize to desired range if possible - frng = range_glb(srng,rng); - } - std::vector largs(nargs); - for(int i = 0; i < nargs; i++){ - largs[i] = localize_term(arg(e,i),frng); - frng = range_glb(frng,ast_scope(largs[i])); - } - e = clone(e,largs); - assert(is_local(e)); - } - - - if(ranges_intersect(ast_scope(e),rng)) - return e; // this term occurs in range, so it's O.K. - - // choose a frame for the constraint that is close to range - int frame = range_near(ast_scope(e),rng); - - ast new_var = fresh_localization_var(e,frame); - localization_map[e] = new_var; - ast cnst = make(Equal,new_var,e); - antes.push_back(std::pair(cnst,frame)); - return new_var; - } - - // some patterm matching functions - - // match logical or with nargs arguments - // assumes AIG form - bool match_or(ast e, ast *args, int nargs){ - if(op(e) != Or) return false; - int n = num_args(e); - if(n != nargs) return false; - for(int i = 0; i < nargs; i++) - args[i] = arg(e,i); - return true; - } - - // match operator f with exactly nargs arguments - bool match_op(ast e, opr f, ast *args, int nargs){ - if(op(e) != f) return false; - int n = num_args(e); - if(n != nargs) return false; - for(int i = 0; i < nargs; i++) - args[i] = arg(e,i); - return true; - } - - // see if the given formula can be interpreted as - // an axiom instance (e.g., an array axiom instance). - // if so, add it to "antes" in an appropriate frame. - // this may require "localization" - - void get_axiom_instance(ast e){ - - // "store" axiom - // (or (= w q) (= (select (store a1 w y) q) (select a1 q))) - // std::cout << "ax: "; show(e); - ast lits[2],eq_ops_l[2],eq_ops_r[2],sel_ops[2], sto_ops[3], sel_ops2[2] ; - if(match_or(e,lits,2)) - if(match_op(lits[0],Equal,eq_ops_l,2)) - if(match_op(lits[1],Equal,eq_ops_r,2)) - for(int i = 0; i < 2; i++){ // try the second equality both ways - if(match_op(eq_ops_r[0],Select,sel_ops,2)) - if(match_op(sel_ops[0],Store,sto_ops,3)) - if(match_op(eq_ops_r[1],Select,sel_ops2,2)) - for(int j = 0; j < 2; j++){ // try the first equality both ways - if(eq_ops_l[0] == sto_ops[1] - && eq_ops_l[1] == sel_ops[1] - && eq_ops_l[1] == sel_ops2[1] - && sto_ops[0] == sel_ops2[0]) - if(is_local(sel_ops[0])) // store term must be local - { - ast sto = sel_ops[0]; - ast addr = localize_term(eq_ops_l[1],ast_scope(sto)); - ast res = make(Or, - make(Equal,eq_ops_l[0],addr), - make(Equal, - make(Select,sto,addr), - make(Select,sel_ops2[0],addr))); - int frame = range_min(ast_scope(res)); - antes.push_back(std::pair(res,frame)); - return; - } - std::swap(eq_ops_l[0],eq_ops_l[1]); - } - std::swap(eq_ops_r[0],eq_ops_r[1]); - } - } - - // a quantifier instantation looks like (~ forall x. P) \/ P[z/x] - // we need to find a time frame for P, then localize P[z/x] in this frame - - void get_quantifier_instance(ast e){ - ast disjs[2]; - if(match_or(e,disjs,2)){ - if(is_local(disjs[0])){ - ast res = localize_term(disjs[1], ast_scope(disjs[0])); - int frame = range_min(ast_scope(res)); - antes.push_back(std::pair(res,frame)); - return; - } - } - } - - ast get_judgement(ast proof){ - ast con = from_ast(conc(proof)); - AstSet &hyps = get_hyps(proof); - std::vector hyps_vec; - for(AstSet::iterator it = hyps.begin(), en = hyps.end(); it != en; ++it) - hyps_vec.push_back(*it); - if(hyps_vec.size() == 0) return con; - con = make(Or,mk_not(make(And,hyps_vec)),con); - return con; - } - - // add the premises of a proof term to the "antes" list - - void add_antes(ast proof){ - if(antes_added.find(proof) != antes_added.end()) return; - antes_added.insert(proof); - int frame = get_locality(proof); - if(frame != -1) - if(1){ - ast e = get_judgement(proof); - if(frame >= frames) frame = frames-1; // can happen if there are no symbols - antes.push_back(std::pair(e,frame)); - return; - } - pfrule dk = pr(proof); - if(dk == PR_ASSERTED){ - ast ass = conc(proof); - frame = frame_of_assertion(ass); - if(frame >= frames) frame = frames-1; // can happen if a theory fact - antes.push_back(std::pair(ass,frame)); - return; - } - if(dk == PR_TH_LEMMA && num_prems(proof) == 0){ - get_axiom_instance(conc(proof)); - } - if(dk == PR_QUANT_INST && num_prems(proof) == 0){ - get_quantifier_instance(conc(proof)); - } - unsigned nprems = num_prems(proof); - for(unsigned i = 0; i < nprems; i++){ - ast arg = prem(proof,i); - add_antes(arg); - } - } - - - // add quantifiers over the localization vars - // to an interpolant for frames lo-hi - - ast add_quants(ast e, int lo, int hi){ - for(int i = localization_vars.size() - 1; i >= 0; i--){ - LocVar &lv = localization_vars[i]; - opr quantifier = (lv.frame >= lo && lv.frame <= hi) ? Exists : Forall; - e = apply_quant(quantifier,lv.var,e); - } - return e; - } - - int get_lits_locality(std::vector &lits){ - range rng = range_full(); - for(std::vector::iterator it = lits.begin(), en = lits.end(); it != en; ++it){ - ast lit = *it; - rng = range_glb(rng,ast_scope(lit)); - } - if(range_is_empty(rng)) return -1; - int hi = range_max(rng); - if(hi >= frames) return frames - 1; - return hi; - } - - - struct invalid_lemma: public iz3_exception { - invalid_lemma(): iz3_exception("invalid_lemma") {} - }; - - - - - // prove a lemma (clause) using current antes list - // return proof of the lemma - // use the secondary prover - - int prove_lemma(std::vector &lits){ - - - // first try localization - if(antes.size() == 0){ - int local_frame = get_lits_locality(lits); - if(local_frame != -1) - return iproof->make_assumption(local_frame,lits); // no proof needed for purely local fact - } - - // group the assumptions by frame - std::vector preds(frames); - for(unsigned i = 0; i < preds.size(); i++) - preds[i] = mk_true(); - for(unsigned i = 0; i < antes.size(); i++){ - int frame = antes[i].second; - preds[frame] = mk_and(preds[frame],antes[i].first); // conjoin it to frame - } - - for(unsigned i = 0; i < lits.size(); i++){ - int frame; - if(!weak_mode()){ - frame = range_max(ast_scope(lits[i])); - if(frame >= frames) frame = frames-1; // could happen if contains no symbols - } - else { - frame = range_min(ast_scope(lits[i])); - if(frame < 0){ - frame = range_max(ast_scope(lits[i])); // could happen if contains no symbols - if(frame >= frames) frame = frames-1; - } - } - preds[frame] = mk_and(preds[frame],mk_not(lits[i])); - } - - - std::vector itps; // holds interpolants - - -#if 1 - ++lemma_count; - // std::cout << "lemma: " << lemma_count << std::endl; - if(lemma_count == SHOW_LEMMA_COUNT){ - for(unsigned i = 0; i < lits.size(); i++) - show_lit(lits[i]); - std::cerr << "lemma written to file lemma.smt:\n"; - iz3base foo(*this,preds,std::vector(),std::vector()); - foo.print("lemma.smt"); - throw invalid_lemma(); - } -#endif - -#if 0 - std::cout << "\nLemma:\n"; - for(unsigned i = 0; i < lits.size(); i++) - show_lit(lits[i]); -#endif - - // interpolate using secondary prover - profiling::timer_start("secondary prover"); - int sat = secondary->interpolate(preds,itps); - profiling::timer_stop("secondary prover"); - - std::cout << "lemma done" << std::endl; - - // if sat, lemma isn't valid, something is wrong - if(sat){ -#if 1 - std::cerr << "invalid lemma written to file invalid_lemma.smt:\n"; - iz3base foo(*this,preds,std::vector(),std::vector()); - foo.print("invalid_lemma.smt"); -#endif - throw iz3_incompleteness(); - } - assert(sat == 0); // if sat, lemma doesn't hold! - - // quantifiy the localization vars - for(unsigned i = 0; i < itps.size(); i++) - itps[i] = add_quants(itps[i],0,i); - - // Make a lemma, storing interpolants - Iproof::node res = iproof->make_lemma(lits,itps); - -#if 0 - std::cout << "Lemma interps\n"; - for(unsigned i = 0; i < itps.size(); i++) - show(itps[i]); -#endif - - // Reset state for the next lemma - antes.clear(); - antes_added.clear(); - clear_localization(); // use a fresh localization for each lemma - - return res; - } - - // sanity check: make sure that any non-local lit is really resolved - // with something in the non_local_lits set - - void check_non_local(ast lit, non_local_lits *nll){ - if(nll) - for(ResolventAppSet::iterator it = nll->proofs.begin(), en = nll->proofs.end(); it != en; ++it){ - ast con = (*it)->pivot; - if(con == mk_not(lit)) return; - } - assert(0 && "bug in non-local resolution handling"); - } - - - void get_local_conclusion_lits(ast proof, bool expect_clause, AstSet &lits){ - std::vector reslits; - if(expect_clause) - get_Z3_lits(conc(proof),reslits); - else reslits.push_back(conc(proof)); - for(unsigned i = 0; i < reslits.size(); i++) - if(is_local(reslits[i])) - lits.insert(reslits[i]); - AstSet &pfhyps = get_hyps(proof); - for(AstSet::iterator hit = pfhyps.begin(), hen = pfhyps.end(); hit != hen; ++hit) - if(is_local(*hit)) - lits.insert(mk_not(*hit)); - } - - - void collect_resolvent_lits(Z3_resolvent *res, const AstSet &hyps, std::vector &lits){ - if(!res->is_unit){ - std::vector reslits; - get_Z3_lits(conc(res->proof),reslits); - for(unsigned i = 0; i < reslits.size(); i++) - if(reslits[i] != res->pivot) - lits.push_back(reslits[i]); - } - AstSet &pfhyps = get_hyps(res->proof); - for(AstSet::iterator hit = pfhyps.begin(), hen = pfhyps.end(); hit != hen; ++hit) - if(hyps.find(*hit) == hyps.end()) - lits.push_back(mk_not(*hit)); - } - - void filter_resolvent_lits(non_local_lits *nll, std::vector &lits){ - std::vector orig_lits; orig_lits.swap(lits); - std::set pivs; - for(ResolventAppSet::iterator it = nll->proofs.begin(), en = nll->proofs.end(); it != en; ++it){ - Z3_resolvent *res = *it; - pivs.insert(res->pivot); - pivs.insert(mk_not(res->pivot)); - } - for(unsigned i = 0; i < orig_lits.size(); i++) - if(pivs.find(orig_lits[i]) == pivs.end()) - lits.push_back(orig_lits[i]); - } - - void collect_all_resolvent_lits(non_local_lits *nll, std::vector &lits){ - if(nll){ - std::vector orig_lits; orig_lits.swap(lits); - std::set pivs; - for(ResolventAppSet::iterator it = nll->proofs.begin(), en = nll->proofs.end(); it != en; ++it){ - Z3_resolvent *res = *it; - pivs.insert(res->pivot); - pivs.insert(mk_not(res->pivot)); - } - for(ResolventAppSet::iterator it = nll->proofs.begin(), en = nll->proofs.end(); it != en; ++it){ - Z3_resolvent *res = *it; - { - std::vector reslits; - if(!res->is_unit) get_Z3_lits(conc(res->proof),reslits); - else reslits.push_back(conc(res->proof)); - for(unsigned i = 0; i < reslits.size(); i++) -#if 0 - if(reslits[i] != res->pivot && pivs.find(reslits[i]) == pivs.end()) -#endif - if(is_local(reslits[i])) - lits.push_back(reslits[i]); - } - } - for(unsigned i = 0; i < orig_lits.size(); i++) - if(pivs.find(orig_lits[i]) == pivs.end()) - lits.push_back(orig_lits[i]); - } - } - - void collect_proof_clause(ast proof, bool expect_clause, std::vector &lits){ - if(expect_clause) - get_Z3_lits(conc(proof),lits); - else - lits.push_back(from_ast(conc(proof))); - AstSet &hyps = get_hyps(proof); - for(AstSet::iterator hit = hyps.begin(), hen = hyps.end(); hit != hen; ++hit) - lits.push_back(mk_not(*hit)); - } - - - // turn a bunch of literals into a lemma, replacing - // non-local lits with their local equivalents - // adds the accumulated antecedents (antes) as - // proof obligations of the lemma - - Iproof::node fix_lemma(std::vector &con_lits, AstSet &hyps, non_local_lits *nll){ - std::vector lits(con_lits); - for(AstSet::iterator it = hyps.begin(), en = hyps.end(); it != en; ++it) - lits.push_back(mk_not(*it)); - if(nll){ - for(ResolventAppSet::iterator it = nll->proofs.begin(), en = nll->proofs.end(); it != en; ++it){ - Z3_resolvent *res = *it; - collect_resolvent_lits(res,hyps,lits); - add_antes(res->proof); - } - filter_resolvent_lits(nll,lits); - } - for(unsigned int i = 0; i < lits.size(); i++){ - EquivTab::iterator it = equivs.find(lits[i]); - if(it != equivs.end()){ - lits[i] = it->second.first; // replace with local equivalent - add_antes(it->second.second); // collect the premises that prove this - } - else { - if(!is_local(lits[i])){ - check_non_local(lits[i],nll); - lits[i] = mk_false(); - } - } - } - // TODO: should check here that derivation is local? - Iproof::node res = prove_lemma(lits); - return res; - } - - int num_lits(ast ast){ - opr dk = op(ast); - if(dk == False) - return 0; - if(dk == Or){ - unsigned nargs = num_args(ast); - int n = 0; - for(unsigned i = 0; i < nargs; i++) // do all the sub_terms - n += num_lits(arg(ast,i)); - return n; - } - else - return 1; - } - - struct non_lit_local_ante: public iz3_exception { - non_lit_local_ante(): iz3_exception("non_lit_local_ante") {} - }; - - bool local_antes_simple; - - bool add_local_antes(ast proof, AstSet &hyps, bool expect_clause = false){ - if(antes_added.find(proof) != antes_added.end()) return true; - antes_added.insert(proof); - ast con = from_ast(conc(proof)); - pfrule dk = pr(proof); - if(is_local(con) || equivs.find(con) != equivs.end()){ - if(!expect_clause || num_lits(conc(proof)) == 1){ - AstSet &this_hyps = get_hyps(proof); - if(std::includes(hyps.begin(),hyps.end(),this_hyps.begin(),this_hyps.end())){ - // if(hyps.find(con) == hyps.end()) -#if 0 - if(/* lemma_count == SHOW_LEMMA_COUNT - 1 && */ !is_literal_or_lit_iff(conc(proof))){ - std::cout << "\nnon-lit local ante\n"; - show_step(proof); - show(conc(proof)); - throw non_lit_local_ante(); - } -#endif - local_antes.push_back(proof); - return true; - } - else - ; //std::cout << "bar!\n"; - } - } - if(dk == PR_ASSERTED - //|| dk == PR_HYPOTHESIS - //|| dk == PR_TH_LEMMA - || dk == PR_QUANT_INST - //|| dk == PR_UNIT_RESOLUTION - //|| dk == PR_LEMMA - ) - return false; - if(dk == PR_HYPOTHESIS && hyps.find(con) != hyps.end()) - ; //std::cout << "blif!\n"; - if(dk == PR_HYPOTHESIS - || dk == PR_LEMMA) - ; //std::cout << "foo!\n"; - if(dk == PR_TH_LEMMA && num_prems(proof) == 0){ - // Check if this is an axiom instance - get_axiom_instance(conc(proof)); - } - - // #define SIMPLE_PROOFS -#ifdef SIMPLE_PROOFS - if(!(dk == PR_TRANSITIVITY - || dk == PR_MONOTONICITY)) - local_antes_simple = false; -#endif - - unsigned nprems = num_prems(proof); - for(unsigned i = 0; i < nprems; i++){ - ast arg = prem(proof,i); - try { - if(!add_local_antes(arg, hyps, dk == PR_UNIT_RESOLUTION && i == 0)) - return false; - } - catch (const non_lit_local_ante &) { - std::cout << "\n"; - show_step(proof); - show(conc(proof)); - throw non_lit_local_ante(); - } - } - return true; - } - - std::vector lit_trace; - hash_set marked_proofs; - - bool proof_has_lit(const ast &proof, const ast &lit){ - AstSet &hyps = get_hyps(proof); - if(hyps.find(mk_not(lit)) != hyps.end()) - return true; - std::vector lits; - ast con = conc(proof); - get_Z3_lits(con, lits); - for(unsigned i = 0; i < lits.size(); i++) - if(lits[i] == lit) - return true; - return false; - } - - - void trace_lit_rec(const ast &lit, const ast &proof, AstHashSet &memo){ - if(memo.find(proof) == memo.end()){ - memo.insert(proof); - AstSet &hyps = get_hyps(proof); - std::vector lits; - for(AstSet::iterator it = hyps.begin(), en = hyps.end(); it != en; ++it) - lits.push_back(mk_not(*it)); - ast con = conc(proof); - get_Z3_lits(con, lits); - for(unsigned i = 0; i < lits.size(); i++){ - if(lits[i] == lit){ - print_expr(std::cout,proof); - std::cout << "\n"; - marked_proofs.insert(proof); - pfrule dk = pr(proof); - if(dk == PR_UNIT_RESOLUTION || dk == PR_LEMMA){ - unsigned nprems = num_prems(proof); - for(unsigned i = 0; i < nprems; i++){ - ast arg = prem(proof,i); - trace_lit_rec(lit,arg,memo); - } - } - else - lit_trace.push_back(proof); - } - } - } - } - - ast traced_lit; - - int trace_lit(const ast &lit, const ast &proof){ - marked_proofs.clear(); - lit_trace.clear(); - traced_lit = lit; - AstHashSet memo; - trace_lit_rec(lit,proof,memo); - return lit_trace.size(); - } - - bool is_literal_or_lit_iff(const ast &lit){ - if(my_is_literal(lit)) return true; - if(op(lit) == Iff){ - return my_is_literal(arg(lit,0)) && my_is_literal(arg(lit,1)); - } - return false; - } - - bool my_is_literal(const ast &lit){ - ast abslit = is_not(lit) ? arg(lit,0) : lit; - int f = op(abslit); - return !(f == And || f == Or || f == Iff); - } - - void print_lit(const ast &lit){ - ast abslit = is_not(lit) ? arg(lit,0) : lit; - if(!is_literal_or_lit_iff(lit)){ - if(is_not(lit)) std::cout << "~"; - std::cout << "["; - print_expr(std::cout,abslit); - std::cout << "]"; - } - else - print_expr(std::cout,lit); - } - - void show_lit(const ast &lit){ - print_lit(lit); - std::cout << "\n"; - } - - void print_z3_lit(const ast &a){ - print_lit(from_ast(a)); - } - - void show_z3_lit(const ast &a){ - print_z3_lit(a); - std::cout << "\n"; - } - - - void show_con(const ast &proof, bool brief){ - if(!traced_lit.null() && proof_has_lit(proof,traced_lit)) - std::cout << "(*) "; - ast con = conc(proof); - AstSet &hyps = get_hyps(proof); - int count = 0; - for(AstSet::iterator it = hyps.begin(), en = hyps.end(); it != en; ++it){ - if(brief && ++count > 5){ - std::cout << "... "; - break; - } - print_lit(*it); - std::cout << " "; - } - std::cout << "|- "; - std::vector lits; - get_Z3_lits(con,lits); - for(unsigned i = 0; i < lits.size(); i++){ - print_lit(lits[i]); - std::cout << " "; - } - std::cout << "\n"; - } - - void show_step(const ast &proof){ - std::cout << "\n"; - unsigned nprems = num_prems(proof); - for(unsigned i = 0; i < nprems; i++){ - std::cout << "(" << i << ") "; - ast arg = prem(proof,i); - show_con(arg,true); - } - std::cout << "|------ "; - std::cout << string_of_symbol(sym(proof)) << "\n"; - show_con(proof,false); - } - - void show_marked( const ast &proof){ - std::cout << "\n"; - unsigned nprems = num_prems(proof); - for(unsigned i = 0; i < nprems; i++){ - ast arg = prem(proof,i); - if(!traced_lit.null() && proof_has_lit(arg,traced_lit)){ - std::cout << "(" << i << ") "; - show_con(arg,true); - } - } - } - - std::vector pfhist; - int pfhist_pos; - - void pfgoto(const ast &proof){ - if(pfhist.size() == 0) - pfhist_pos = 0; - else pfhist_pos++; - pfhist.resize(pfhist_pos); - pfhist.push_back(proof); - show_step(proof); - } - - void show_nll(non_local_lits *nll){ - if(!nll)return; - for(ResolventAppSet::iterator it = nll->proofs.begin(), en = nll->proofs.end(); it != en; ++it){ - Z3_resolvent *res = *it; - show_step(res->proof); - std::cout << "Pivot: "; - show(res->pivot); - std::cout << std::endl; - } - } - - void pfback(){ - if(pfhist_pos > 0){ - pfhist_pos--; - show_step(pfhist[pfhist_pos]); - } - } - - void pffwd(){ - if(pfhist_pos < ((int)pfhist.size()) - 1){ - pfhist_pos++; - show_step(pfhist[pfhist_pos]); - } - } - - void pfprem(int i){ - if(pfhist.size() > 0){ - ast proof = pfhist[pfhist_pos]; - unsigned nprems = num_prems(proof); - if(i >= 0 && i < (int)nprems) - pfgoto(prem(proof,i)); - } - } - - int extract_th_lemma_common(std::vector &lits, non_local_lits *nll, bool lemma_nll = true){ - std::vector la = local_antes; - local_antes.clear(); // clear antecedents for next lemma - antes_added.clear(); - // std::vector lits; - AstSet hyps; // no hyps - for(unsigned i = 0; i < la.size(); i++) - lits.push_back(mk_not(from_ast(conc(la[i])))); - // lits.push_back(from_ast(conc(proof))); - Iproof::node res =fix_lemma(lits,hyps, lemma_nll ? nll : nullptr); - for(unsigned i = 0; i < la.size(); i++){ - Iproof::node q = translate_main(la[i],nll,false); - ast pnode = from_ast(conc(la[i])); - assert(is_local(pnode) || equivs.find(pnode) != equivs.end()); - Iproof::node neg = res; - Iproof::node pos = q; - if(is_not(pnode)){ - pnode = mk_not(pnode); - std::swap(neg,pos); - } - try { - res = iproof->make_resolution(pnode,neg,pos); - } - catch (const iz3proof::proof_error &){ - std::cout << "\nresolution error in theory lemma\n"; - std::cout << "lits:\n"; - for(unsigned j = 0; j < lits.size(); j++) - show_lit(lits[j]); - std::cout << "\nstep:\n"; - show_step(la[i]); - throw invalid_lemma(); - } - } - return res; - } - - Iproof::node extract_simple_proof(const ast &proof, hash_set &leaves){ - if(leaves.find(proof) != leaves.end()) - return iproof->make_hypothesis(conc(proof)); - ast con = from_ast(conc(proof)); - pfrule dk = pr(proof); - unsigned nprems = num_prems(proof); - std::vector args(nprems); - for(unsigned i = 0; i < nprems; i++){ - ast arg = prem(proof,i); - args[i] = extract_simple_proof(arg,leaves); - } - - switch(dk){ - case PR_TRANSITIVITY: - return iproof->make_transitivity(con,args[0],args[1]); - case PR_MONOTONICITY: - return iproof->make_congruence(con,args); - case PR_REFLEXIVITY: - return iproof->make_reflexivity(con); - case PR_SYMMETRY: - return iproof->make_symmetry(con,args[0]); - } - assert(0 && "extract_simple_proof: unknown op"); - return 0; - } - - int extract_th_lemma_simple(const ast &proof, std::vector &lits){ - std::vector la = local_antes; - local_antes.clear(); // clear antecedents for next lemma - antes_added.clear(); - - hash_set leaves; - for(unsigned i = 0; i < la.size(); i++) - leaves.insert(la[i]); - - Iproof::node ipf = extract_simple_proof(proof,leaves); - ast con = from_ast(conc(proof)); - Iproof::node hyp = iproof->make_hypothesis(mk_not(con)); - ipf = iproof->make_eqcontra(ipf,hyp); - - // std::vector lits; - AstSet hyps; // no hyps - for(unsigned i = 0; i < la.size(); i++) - lits.push_back(mk_not(from_ast(conc(la[i])))); - // lits.push_back(from_ast(conc(proof))); - - Iproof::node res = iproof->make_contra(ipf,lits); - - for(unsigned i = 0; i < la.size(); i++){ - Iproof::node q = translate_main(la[i],nullptr,false); - ast pnode = from_ast(conc(la[i])); - assert(is_local(pnode) || equivs.find(pnode) != equivs.end()); - Iproof::node neg = res; - Iproof::node pos = q; - if(is_not(pnode)){ - pnode = mk_not(pnode); - std::swap(neg,pos); - } - try { - res = iproof->make_resolution(pnode,neg,pos); - } - catch (const iz3proof::proof_error &){ - std::cout << "\nresolution error in theory lemma\n"; - std::cout << "lits:\n"; - for(unsigned j = 0; j < lits.size(); j++) - show_lit(lits[j]); - std::cout << "\nstep:\n"; - show_step(la[i]); - throw invalid_lemma(); - } - } - return res; - } - - // #define NEW_EXTRACT_TH_LEMMA - - void get_local_hyps(const ast &proof, std::set &res){ - std::set hyps = get_hyps(proof); - for(std::set::iterator it = hyps.begin(), en = hyps.end(); it != en; ++it){ - ast hyp = *it; - if(is_local(hyp)) - res.insert(hyp); - } - } - - int extract_th_lemma(ast proof, std::vector &lits, non_local_lits *nll){ - pfrule dk = pr(proof); - unsigned nprems = num_prems(proof); -#ifdef NEW_EXTRACT_TH_LEMMA - if(nprems == 0 && !nll) -#else - if(nprems == 0) -#endif - return 0; - if(nprems == 0 && dk == PR_TH_LEMMA) - // Check if this is an axiom instance - get_axiom_instance(conc(proof)); - - local_antes_simple = true; - for(unsigned i = 0; i < nprems; i++){ - ast arg = prem(proof,i); - if(!add_local_antes(arg,get_hyps(proof))){ - local_antes.clear(); // clear antecedents for next lemma - antes_added.clear(); - antes.clear(); - return 0; - } - } -#ifdef NEW_EXTRACT_TH_LEMMA - bool lemma_nll = nprems > 1; - if(nll && !lemma_nll){ - lemma_nll = false; - // std::cout << "lemma count = " << nll_lemma_count << "\n"; - for(ResolventAppSet::iterator it = nll->proofs.begin(), en = nll->proofs.end(); it != en; ++it){ - Z3_resolvent *res = *it; - ast arg = res->proof; - std::set loc_hyps; get_local_hyps(arg,loc_hyps); - if(!add_local_antes(arg,loc_hyps)){ - local_antes.clear(); // clear antecedents for next lemma - antes_added.clear(); - antes.clear(); - return 0; - } - } - collect_all_resolvent_lits(nll,lits); - } - int my_count = nll_lemma_count++; - int res; - try { - res = extract_th_lemma_common(lits,nll,lemma_nll); - } -#if 1 - catch (const invalid_lemma &) { - std::cout << "\n\nlemma: " << my_count; - std::cout << "\n\nproof node: \n"; - show_step(proof); - std::cout << "\n\nnon-local: \n"; - show_nll(nll); - pfgoto(nll->proofs[0]->proof); - show(conc(pfhist.back())); - pfprem(1); - show(conc(pfhist.back())); - pfprem(0); - show(conc(pfhist.back())); - pfprem(0); - show(conc(pfhist.back())); - pfprem(0); - show(conc(pfhist.back())); - std::cout << "\n\nliterals: \n"; - for(int i = 0; i < lits.size(); i++) - show_lit(lits[i]); - throw invalid_lemma(); - } -#endif - - return res; -#else -#ifdef SIMPLE_PROOFS - if(local_antes_simple && !nll) - return extract_th_lemma_simple(proof, lits); -#endif - return extract_th_lemma_common(lits,nll); -#endif - } - - int extract_th_lemma_ur(ast proof, int position, std::vector &lits, non_local_lits *nll){ - for(int i = 0; i <= position; i++){ - ast arg = prem(proof,i); - if(!add_local_antes(arg,get_hyps(proof),i==0)){ - local_antes.clear(); // clear antecedents for next lemma - antes_added.clear(); - antes.clear(); - return 0; - } - } - return extract_th_lemma_common(lits,nll); - } - - // see if any of the pushed resolvents are resolutions - // push the current proof into the latest such - int push_into_resolvent(ast proof, std::vector &lits, non_local_lits *nll, bool expect_clause){ - if(!nll) return 0; - if(num_args(proof) > 1) return 0; - ResolventAppSet resos = nll->proofs; - int pos = resos.size()-1; - for( ResolventAppSet::reverse_iterator it = resos.rbegin(), en = resos.rend(); it != en; ++it, --pos){ - Z3_resolvent *reso = *it; - ast ante = reso->proof; - ast pivot = reso->pivot; - bool is_unit = reso->is_unit; - pfrule dk = pr(ante); - bool pushable = dk == PR_UNIT_RESOLUTION || dk == PR_LEMMA; - if(!pushable && num_args(ante) > 1){ -#if 0 - if (!is_local(conc(ante))) - std::cout << "non-local "; - std::cout << "pushable!\n"; -#endif - pushable = true; - } - if(pushable){ - // remove the resolvent from list and add new clause as resolvent - resos.erase((++it).base()); - for(; pos < (int)resos.size(); pos++){ - Z3_resolvent *r = resos[pos]; - resos[pos] = find_resolvent(r->proof,r->is_unit,mk_not(pivot)); - } - resos.push_back(find_resolvent(proof,!expect_clause,mk_not(pivot))); - non_local_lits *new_nll = find_nll(resos); - try { - int res = translate_main(ante,new_nll,!is_unit); - return res; - } - catch (const invalid_lemma &) { - std::cout << "\n\npushing: \n"; - std::cout << "nproof node: \n"; - show_step(proof); - std::cout << "\n\nold non-local: \n"; - show_nll(nll); - std::cout << "\n\nnew non-local: \n"; - show_nll(new_nll); - throw invalid_lemma(); - } - } - } - return 0; // no pushed resolvents are resolution steps - } - - non_local_lits *find_nll(ResolventAppSet &proofs){ - if(proofs.empty()) - return (non_local_lits *)nullptr; - std::pair foo(non_local_lits(proofs),(non_local_lits *)nullptr); - std::pair::iterator,bool> bar = - non_local_lits_unique.insert(foo); - non_local_lits *&res = bar.first->second; - if(bar.second) - res = new non_local_lits(bar.first->first); - return res; - } - - Z3_resolvent *find_resolvent(ast proof, bool unit, ast pivot){ - std::pair foo(Z3_resolvent(proof,unit,pivot),(Z3_resolvent *)nullptr); - std::pair::iterator,bool> bar = - Z3_resolvent_unique.insert(foo); - Z3_resolvent *&res = bar.first->second; - if(bar.second) - res = new Z3_resolvent(bar.first->first); - return res; - } - - // translate a unit resolution at position pos of given app - int translate_ur(ast proof, int position, non_local_lits *nll){ - ast ante = prem(proof,position); - if(position <= 0) - return translate_main(ante, nll); - ast pnode = conc(ante); - ast pnode_abs = !is_not(pnode) ? pnode : mk_not(pnode); - if(is_local(pnode) || equivs.find(pnode) != equivs.end()){ - Iproof::node neg = translate_ur(proof,position-1,nll); - Iproof::node pos = translate_main(ante, nll, false); - if(is_not(pnode)){ - pnode = mk_not(pnode); - std::swap(neg,pos); - } - try { - return iproof->make_resolution(pnode,neg,pos); - } - catch (const iz3proof::proof_error &){ - std::cout << "resolution error in unit_resolution, position" << position << "\n"; - show_step(proof); - throw invalid_lemma(); - } - } - else { - // non-local pivot we have no local equivalent for - if(true){ - // try pushing the non-local resolution up - pfrule dk = pr(ante); - non_local_lits *old_nll = nll; - if(dk == PR_HYPOTHESIS) - ; //std::cout << "non-local hyp!\n"; // resolving with a hyp is a no-op - else { - ResolventAppSet new_proofs; - if(nll) new_proofs = nll->proofs; - Z3_resolvent *reso = find_resolvent(ante,true,pnode); - new_proofs.push_back(reso); - nll = find_nll(new_proofs); - } - try { - return translate_ur(proof,position-1,nll); - } - catch (const invalid_lemma &) { - if(old_nll != nll){ - std::cout << "\n\nadded_nll: \n"; - std::cout << "nproof node: \n"; - show_step(proof); - std::cout << "\n\new non-local step: \n"; - show_step(nll->proofs.back()->proof); - } - throw invalid_lemma(); - } - - } - else { - // just make a lemma - std::vector lits; - do_unit_resolution(proof,position,lits); - int res; - if(!(res = extract_th_lemma_ur(proof,position,lits,nll))){ - for(int i = 0; i <= position; i++){ - z3pf p = prem(proof,i); - add_antes(p); - } - res = fix_lemma(lits,get_hyps(proof),nll); - } - return res; - } - } - } - - non_local_lits *update_nll(ast proof, bool expect_clause, non_local_lits *nll){ - std::vector lits; - collect_proof_clause(proof,expect_clause,lits); - AstSet litset; - litset.insert(lits.begin(),lits.end()); - ResolventAppSet to_keep; - for(int i = nll->proofs.size()-1; i >= 0; --i){ - ast traced_lit = (nll->proofs[i])->pivot; - ast traced_lit_neg = mk_not(traced_lit); - if(litset.find(traced_lit) != litset.end() || litset.find(traced_lit_neg) != litset.end()){ - to_keep.push_back(nll->proofs[i]); - std::vector reslits; - AstSet dummy; - collect_resolvent_lits(nll->proofs[i],dummy,reslits); - litset.insert(reslits.begin(),reslits.end()); - } - } - if(to_keep.size() == nll->proofs.size()) return nll; - ResolventAppSet new_proofs; - for(int i = to_keep.size() - 1; i >= 0; --i) - new_proofs.push_back(to_keep[i]); - return find_nll(new_proofs); - } - - // translate a Z3 proof term into a secondary prover proof term - - Iproof::node translate_main(ast proof, non_local_lits *nll, bool expect_clause = true){ - non_local_lits *old_nll = nll; - if(nll) nll = update_nll(proof,expect_clause,nll); - AstToIpf &tr = nll ? non_local_translation[nll] : translation; - hash_map &trc = expect_clause ? tr.first : tr.second; - std::pair foo(proof,INT_MAX); - std::pair bar = trc.insert(foo); - int &res = bar.first->second; - if(!bar.second) return res; - - - try { - int frame = get_locality(proof); - if(frame != -1){ - ast e = from_ast(conc(proof)); - if(frame >= frames) frame = frames - 1; - std::vector foo; - if(expect_clause) - get_Z3_lits(conc(proof),foo); - else - foo.push_back(e); - AstSet &hyps = get_hyps(proof); - for(AstSet::iterator it = hyps.begin(), en = hyps.end(); it != en; ++it) - foo.push_back(mk_not(*it)); - res = iproof->make_assumption(frame,foo); - return res; - } - - pfrule dk = pr(proof); - unsigned nprems = num_prems(proof); - if(dk == PR_UNIT_RESOLUTION){ - res = translate_ur(proof, nprems - 1, nll); - } - else if(dk == PR_LEMMA){ - ast contra = prem(proof,0); // this is a proof of false from some hyps - res = translate_main(contra, nll); - if(!expect_clause){ - std::vector foo; // the negations of the hyps form a clause - foo.push_back(from_ast(conc(proof))); - AstSet &hyps = get_hyps(proof); - for(AstSet::iterator it = hyps.begin(), en = hyps.end(); it != en; ++it) - foo.push_back(mk_not(*it)); - res = iproof->make_contra(res,foo); - } - } - else { - std::vector lits; - ast con = conc(proof); - if(expect_clause) - get_Z3_lits(con, lits); - else - lits.push_back(from_ast(con)); -#ifdef NEW_EXTRACT_TH_LEMMA - if(!(res = push_into_resolvent(proof,lits,nll,expect_clause))){ - if(!(res = extract_th_lemma(proof,lits,nll))){ -#else - if(!(res = extract_th_lemma(proof,lits,nll))){ - if(!(res = push_into_resolvent(proof,lits,nll,expect_clause))){ -#endif - // std::cout << "extract theory lemma failed\n"; - add_antes(proof); - res = fix_lemma(lits,get_hyps(proof),nll); - } - } - } -#ifdef CHECK_PROOFS - - if(0){ - AstSet zpf_con_lits, ipf_con_lits; - get_local_conclusion_lits(proof, expect_clause, zpf_con_lits); - if(nll){ - for(unsigned i = 0; i < nll->proofs.size(); i++) - get_local_conclusion_lits(nll->proofs[i]->proof,!nll->proofs[i]->is_unit,zpf_con_lits); - } - std::vector ipf_con; - iproof->get_conclusion(res,ipf_con); - for(unsigned i = 0; i < ipf_con.size(); i++) - ipf_con_lits.insert(ipf_con[i]); - if(!(ipf_con_lits == zpf_con_lits)){ - std::cout << "proof error:\n"; - std::cout << "expected lits:\n"; - for(AstSet::iterator hit = zpf_con_lits.begin(), hen = zpf_con_lits.end(); hit != hen; ++hit) - show_lit(*hit); - std::cout << "got lits:\n"; - for(AstSet::iterator hit = ipf_con_lits.begin(), hen = ipf_con_lits.end(); hit != hen; ++hit) - show_lit(*hit); - std::cout << "\nproof step:"; - show_step(proof); - std::cout << "\n"; - throw invalid_lemma(); - } - } -#endif - - return res; - } - - catch (const invalid_lemma &) { - if(old_nll != nll){ - std::cout << "\n\nupdated nll: \n"; - std::cout << "nproof node: \n"; - show_step(proof); - std::cout << "\n\new non-local: \n"; - show_nll(nll); - } - throw invalid_lemma(); - } - - } - - // Proof translation is in two stages: - // 1) Translate ast proof term to Zproof - // 2) Translate Zproof to Iproof - - Iproof::node translate(ast proof, Iproof &dst) override { - iproof = &dst; - Iproof::node Ipf = translate_main(proof,nullptr); // builds result in dst - return Ipf; - } - - iz3translation_direct(iz3mgr &mgr, - iz3secondary *_secondary, - const std::vector > &cnsts, - const std::vector &parents, - const std::vector &theory) - : iz3translation(mgr, cnsts, parents, theory) - { - secondary = _secondary; - frames = cnsts.size(); - traced_lit = ast(); - } - - ~iz3translation_direct() override { - for(hash_map::iterator - it = non_local_lits_unique.begin(), - en = non_local_lits_unique.end(); - it != en; - ++it) - delete it->second; - - for(hash_map::iterator - it = Z3_resolvent_unique.begin(), - en = Z3_resolvent_unique.end(); - it != en; - ++it) - delete it->second; - } - }; - - - - -#ifdef IZ3_TRANSLATE_DIRECT - - iz3translation *iz3translation::create(iz3mgr &mgr, - iz3secondary *secondary, - const std::vector > &cnsts, - const std::vector &parents, - const std::vector &theory){ - return new iz3translation_direct(mgr,secondary,cnsts,parents,theory); - } - - -#if 1 - - void iz3translation_direct_trace_lit(iz3translation_direct *p, iz3mgr::ast lit, iz3mgr::ast proof){ - p->trace_lit(lit, proof); - } - - void iz3translation_direct_show_step(iz3translation_direct *p, iz3mgr::ast proof){ - p->show_step(proof); - } - - void iz3translation_direct_show_marked(iz3translation_direct *p, iz3mgr::ast proof){ - p->show_marked(proof); - } - - void iz3translation_direct_show_lit(iz3translation_direct *p, iz3mgr::ast lit){ - p->show_lit(lit); - } - - void iz3translation_direct_show_z3_lit(iz3translation_direct *p, iz3mgr::ast a){ - p->show_z3_lit(a); - } - - void iz3translation_direct_pfgoto(iz3translation_direct *p, iz3mgr::ast proof){ - p->pfgoto(proof); - } - - void iz3translation_direct_show_nll(iz3translation_direct *p, non_local_lits *nll){ - p->show_nll(nll); - } - - void iz3translation_direct_pfback(iz3translation_direct *p ){ - p->pfback(); - } - - void iz3translation_direct_pffwd(iz3translation_direct *p ){ - p->pffwd(); - } - - void iz3translation_direct_pfprem(iz3translation_direct *p, int i){ - p->pfprem(i); - } - - - struct stdio_fixer { - stdio_fixer(){ - std::cout.rdbuf()->pubsetbuf(0,0); - } - - } my_stdio_fixer; - -#endif - -#endif - - diff --git a/src/muz/base/dl_context.cpp b/src/muz/base/dl_context.cpp index 54c07da28..cc14de5ce 100644 --- a/src/muz/base/dl_context.cpp +++ b/src/muz/base/dl_context.cpp @@ -188,7 +188,7 @@ namespace datalog { if (m_trail.get_num_scopes() == 0) { throw default_exception("there are no backtracking points to pop to"); } - if (m_engine.get() && get_engine() != DUALITY_ENGINE) { + if (m_engine.get()) { throw default_exception("pop operation is only supported by duality engine"); } m_trail.pop_scope(1); @@ -601,11 +601,6 @@ namespace datalog { m_rule_properties.check_existential_tail(); m_rule_properties.check_for_negated_predicates(); break; - case DUALITY_ENGINE: - m_rule_properties.collect(r); - m_rule_properties.check_existential_tail(); - m_rule_properties.check_for_negated_predicates(); - break; case CLP_ENGINE: m_rule_properties.collect(r); m_rule_properties.check_existential_tail(); @@ -828,9 +823,6 @@ namespace datalog { else if (e == symbol("clp")) { m_engine_type = CLP_ENGINE; } - else if (e == symbol("duality")) { - m_engine_type = DUALITY_ENGINE; - } else if (e == symbol("ddnf")) { m_engine_type = DDNF_ENGINE; } @@ -875,11 +867,6 @@ namespace datalog { case DDNF_ENGINE: flush_add_rules(); break; - case DUALITY_ENGINE: - // this lets us use duality with SAS 2013 abstraction - if(quantify_arrays()) - flush_add_rules(); - break; default: UNREACHABLE(); } diff --git a/src/muz/base/dl_engine_base.h b/src/muz/base/dl_engine_base.h index 576ed7f6b..b9ac6e7b5 100644 --- a/src/muz/base/dl_engine_base.h +++ b/src/muz/base/dl_engine_base.h @@ -32,7 +32,6 @@ namespace datalog { QBMC_ENGINE, TAB_ENGINE, CLP_ENGINE, - DUALITY_ENGINE, DDNF_ENGINE, LAST_ENGINE }; diff --git a/src/muz/duality/CMakeLists.txt b/src/muz/duality/CMakeLists.txt deleted file mode 100644 index f005b88b1..000000000 --- a/src/muz/duality/CMakeLists.txt +++ /dev/null @@ -1,8 +0,0 @@ -z3_add_component(duality_intf - SOURCES - duality_dl_interface.cpp - COMPONENT_DEPENDENCIES - duality - muz - transforms -) diff --git a/src/muz/duality/duality_dl_interface.cpp b/src/muz/duality/duality_dl_interface.cpp deleted file mode 100644 index 60ed1755c..000000000 --- a/src/muz/duality/duality_dl_interface.cpp +++ /dev/null @@ -1,623 +0,0 @@ -/*++ - Copyright (c) 2013 Microsoft Corporation - - Module Name: - - duality_dl_interface.cpp - - Abstract: - - SMT2 interface for Duality - - Author: - - Krystof Hoder (t-khoder) 2011-9-22. - Modified by Ken McMIllan (kenmcmil) 2013-4-18. - - Revision History: - - --*/ - -#include "muz/base/dl_context.h" -#include "muz/transforms/dl_mk_coi_filter.h" -#include "muz/transforms/dl_mk_interp_tail_simplifier.h" -#include "muz/transforms/dl_mk_subsumption_checker.h" -#include "muz/transforms/dl_mk_rule_inliner.h" -#include "muz/base/dl_rule.h" -#include "muz/base/dl_rule_transformer.h" -#include "parsers/smt2/smt2parser.h" -#include "muz/duality/duality_dl_interface.h" -#include "muz/base/dl_rule_set.h" -#include "muz/transforms/dl_mk_slice.h" -#include "muz/transforms/dl_mk_unfold.h" -#include "muz/transforms/dl_mk_coalesce.h" -#include "ast/expr_abstract.h" -#include "model/model_smt2_pp.h" -#include "model/model_v2_pp.h" -#include "muz/base/fixedpoint_params.hpp" -#include "ast/used_vars.h" -#include "ast/func_decl_dependencies.h" -#include "muz/transforms/dl_transforms.h" - -// template class symbol_table; - -#ifdef WIN32 -#pragma warning(disable:4996) -#pragma warning(disable:4800) -#pragma warning(disable:4267) -#pragma warning(disable:4101) -#endif - -#include "duality/duality.h" -#include "duality/duality_profiling.h" - -// using namespace Duality; - -namespace Duality { - - enum DualityStatus {StatusModel, StatusRefutation, StatusUnknown, StatusNull}; - - class duality_data { - public: - context ctx; - RPFP::LogicSolver *ls; - RPFP *rpfp; - - DualityStatus status; - std::vector clauses; - std::vector > clause_labels; - hash_map map; // edges to clauses - Solver *old_rs; - Solver::Counterexample cex; - - duality_data(ast_manager &_m) : ctx(_m,config(params_ref())) { - ls = nullptr; - rpfp = nullptr; - status = StatusNull; - old_rs = nullptr; - } - ~duality_data(){ - if(old_rs) - dealloc(old_rs); - if(rpfp) - dealloc(rpfp); - if(ls) - dealloc(ls); - } - }; - - - dl_interface::dl_interface(datalog::context& dl_ctx) : - engine_base(dl_ctx.get_manager(), "duality"), - m_ctx(dl_ctx) - - { - _d = nullptr; - // dl_ctx.get_manager().toggle_proof_mode(PGM_FINE); - } - - - dl_interface::~dl_interface() { - if(_d) - dealloc(_d); - } - - - // - // Check if the new rules are weaker so that we can - // re-use existing context. - // -#if 0 - void dl_interface::check_reset() { - // TODO - datalog::rule_ref_vector const& new_rules = m_ctx.get_rules().get_rules(); - datalog::rule_ref_vector const& old_rules = m_old_rules.get_rules(); - bool is_subsumed = !old_rules.empty(); - for (unsigned i = 0; is_subsumed && i < new_rules.size(); ++i) { - is_subsumed = false; - for (unsigned j = 0; !is_subsumed && j < old_rules.size(); ++j) { - if (m_ctx.check_subsumes(*old_rules[j], *new_rules[i])) { - is_subsumed = true; - } - } - if (!is_subsumed) { - TRACE("pdr", new_rules[i]->display(m_ctx, tout << "Fresh rule ");); - m_context->reset(); - } - } - m_old_rules.reset(); - m_old_rules.add_rules(new_rules.size(), new_rules.c_ptr()); - } -#endif - - - lbool dl_interface::query(::expr * query) { - - // we restore the initial state in the datalog context - m_ctx.ensure_opened(); - - // if there is old data, get the cex and dispose (later) - duality_data *old_data = _d; - Solver *old_rs = nullptr; - if(old_data){ - old_rs = old_data->old_rs; - old_rs->GetCounterexample().swap(old_data->cex); - } - - scoped_proof generate_proofs_please(m_ctx.get_manager()); - - // make a new problem and solver - _d = alloc(duality_data,m_ctx.get_manager()); - _d->ctx.set("mbqi",m_ctx.get_params().duality_mbqi()); - _d->ls = alloc(RPFP::iZ3LogicSolver,_d->ctx); - _d->rpfp = alloc(RPFP,_d->ls); - - - - expr_ref_vector rules(m_ctx.get_manager()); - svector< ::symbol> names; - unsigned_vector bounds; - // m_ctx.get_rules_as_formulas(rules, names); - - - // If using SAS 2013 abstractiion, we need to perform some transforms - expr_ref query_ref(m_ctx.get_manager()); - if(m_ctx.quantify_arrays()){ - datalog::rule_manager& rm = m_ctx.get_rule_manager(); - rm.mk_query(query, m_ctx.get_rules()); - apply_default_transformation(m_ctx); - datalog::rule_set &rs = m_ctx.get_rules(); - if(m_ctx.get_rules().get_output_predicates().empty()) - query_ref = m_ctx.get_manager().mk_false(); - else { - func_decl_ref query_pred(m_ctx.get_manager()); - query_pred = m_ctx.get_rules().get_output_predicate(); - ptr_vector sorts; - unsigned nargs = query_pred.get()->get_arity(); - expr_ref_vector vars(m_ctx.get_manager()); - for(unsigned i = 0; i < nargs; i++){ - ::sort *s = query_pred.get()->get_domain(i); - vars.push_back(m_ctx.get_manager().mk_var(nargs-1-i,s)); - } - query_ref = m_ctx.get_manager().mk_app(query_pred.get(),nargs,vars.c_ptr()); - query = query_ref.get(); - } - unsigned nrules = rs.get_num_rules(); - for(unsigned i = 0; i < nrules; i++){ - expr_ref f(m_ctx.get_manager()); - rm.to_formula(*rs.get_rule(i), f); - rules.push_back(f); - } - } - else - m_ctx.get_raw_rule_formulas(rules, names, bounds); - - // get all the rules as clauses - std::vector &clauses = _d->clauses; - clauses.clear(); - for (unsigned i = 0; i < rules.size(); ++i) { - expr e(_d->ctx,rules[i].get()); - clauses.push_back(e); - } - - std::vector b_sorts; - std::vector b_names; - used_vars uv; - uv.process(query); - unsigned nuv = uv.get_max_found_var_idx_plus_1(); - for(int i = nuv-1; i >= 0; i--){ // var indices are backward - ::sort * s = uv.get(i); - if(!s) - s = _d->ctx.m().mk_bool_sort(); // missing var, whatever - b_sorts.push_back(sort(_d->ctx,s)); - b_names.push_back(symbol(_d->ctx,::symbol(i))); // names? - } - -#if 0 - // turn the query into a clause - expr q(_d->ctx,m_ctx.bind_variables(query,false)); - - std::vector b_sorts; - std::vector b_names; - if (q.is_quantifier() && !q.is_quantifier_forall()) { - int bound = q.get_quantifier_num_bound(); - for(int j = 0; j < bound; j++){ - b_sorts.push_back(q.get_quantifier_bound_sort(j)); - b_names.push_back(q.get_quantifier_bound_name(j)); - } - q = q.arg(0); - } -#else - expr q(_d->ctx,query); -#endif - - expr qc = implies(q,_d->ctx.bool_val(false)); - qc = _d->ctx.make_quant(Forall,b_sorts,b_names,qc); - clauses.push_back(qc); - bounds.push_back(UINT_MAX); - - // get the background axioms - unsigned num_asserts = m_ctx.get_num_assertions(); - for (unsigned i = 0; i < num_asserts; ++i) { - expr e(_d->ctx,m_ctx.get_assertion(i)); - _d->rpfp->AssertAxiom(e); - } - - // make sure each predicate is the head of at least one clause - func_decl_set heads; - for(unsigned i = 0; i < clauses.size(); i++){ - expr cl = clauses[i]; - - while(true){ - if(cl.is_app()){ - decl_kind k = cl.decl().get_decl_kind(); - if(k == Implies) - cl = cl.arg(1); - else { - heads.insert(cl.decl()); - break; - } - } - else if(cl.is_quantifier()) - cl = cl.body(); - else break; - } - } - ast_ref_vector const &pinned = m_ctx.get_pinned(); - for(unsigned i = 0; i < pinned.size(); i++){ - ::ast *fa = pinned[i]; - if(is_func_decl(fa)){ - ::func_decl *fd = to_func_decl(fa); - if (m_ctx.is_predicate(fd)) { - func_decl f(_d->ctx, fd); - if (!heads.contains(fd)) { - int arity = f.arity(); - std::vector args; - args.reserve(arity); - for (int j = 0; j < arity; j++) - args.push_back(_d->ctx.fresh_func_decl("X", f.domain(j))()); - expr c = implies(_d->ctx.bool_val(false), f(args)); - c = _d->ctx.make_quant(Forall, args, c); - clauses.push_back(c); - bounds.push_back(UINT_MAX); - } - } - } - } - unsigned rb = m_ctx.get_params().duality_recursion_bound(); - std::vector std_bounds; - for(unsigned i = 0; i < bounds.size(); i++){ - unsigned b = bounds[i]; - if (b == UINT_MAX) b = rb; - std_bounds.push_back(b); - } - - // creates 1-1 map between clauses and rpfp edges - _d->rpfp->FromClauses(clauses,&std_bounds); - - // populate the edge-to-clause map - for(unsigned i = 0; i < _d->rpfp->edges.size(); ++i) - _d->map[_d->rpfp->edges[i]] = i; - - // create a solver object - - Solver *rs = Solver::Create("duality", _d->rpfp); - - if(old_rs) - rs->LearnFrom(old_rs); // new solver gets hints from old solver - - // set its options - IF_VERBOSE(1, rs->SetOption("report","1");); - rs->SetOption("full_expand",m_ctx.get_params().duality_full_expand() ? "1" : "0"); - rs->SetOption("no_conj",m_ctx.get_params().duality_no_conj() ? "1" : "0"); - rs->SetOption("feasible_edges",m_ctx.get_params().duality_feasible_edges() ? "1" : "0"); - rs->SetOption("use_underapprox",m_ctx.get_params().duality_use_underapprox() ? "1" : "0"); - rs->SetOption("stratified_inlining",m_ctx.get_params().duality_stratified_inlining() ? "1" : "0"); - rs->SetOption("batch_expand",m_ctx.get_params().duality_batch_expand() ? "1" : "0"); - rs->SetOption("conjecture_file",m_ctx.get_params().duality_conjecture_file()); - rs->SetOption("enable_restarts",m_ctx.get_params().duality_enable_restarts() ? "1" : "0"); -#if 0 - if(rb != UINT_MAX){ - std::ostringstream os; os << rb; - rs->SetOption("recursion_bound", os.str()); - } -#endif - - // Solve! - bool ans; - try { - ans = rs->Solve(); - } - catch (Duality::solver::cancel_exception &exn){ - throw default_exception(Z3_CANCELED_MSG); - } - catch (Duality::Solver::Incompleteness &exn){ - throw default_exception("incompleteness"); - } - - // profile! - - if(m_ctx.get_params().duality_profile()) - print_profile(std::cout); - - // save the result and counterexample if there is one - _d->status = ans ? StatusModel : StatusRefutation; - _d->cex.swap(rs->GetCounterexample()); // take ownership of cex - _d->old_rs = rs; // save this for later hints - - if(old_data){ - dealloc(old_data); // this deallocates the old solver if there is one - } - - // dealloc(rs); this is now owned by data - - // true means the RPFP problem is SAT, so the query is UNSAT - // but we return undef if the UNSAT result is bounded - if(ans){ - if(rs->IsResultRecursionBounded()){ -#if 0 - m_ctx.set_status(datalog::BOUNDED); - return l_undef; -#else - return l_false; -#endif - } - return l_false; - } - return l_true; - } - - expr_ref dl_interface::get_cover_delta(int level, ::func_decl* pred_orig) { - SASSERT(false); - return expr_ref(m_ctx.get_manager()); - } - - void dl_interface::add_cover(int level, ::func_decl* pred, ::expr* property) { - SASSERT(false); - } - - unsigned dl_interface::get_num_levels(::func_decl* pred) { - SASSERT(false); - return 0; - } - - void dl_interface::collect_statistics(::statistics& st) const { - } - - void dl_interface::reset_statistics() { - } - - static hash_set *local_func_decls; - - static void print_proof(dl_interface *d, std::ostream& out, RPFP *tree, RPFP::Node *root) { - context &ctx = d->dd()->ctx; - RPFP::Node &node = *root; - RPFP::Edge &edge = *node.Outgoing; - - // first, prove the children (that are actually used) - - for(unsigned i = 0; i < edge.Children.size(); i++){ - if(!tree->Empty(edge.Children[i])){ - print_proof(d,out,tree,edge.Children[i]); - } - } - - // print the label and the proved fact - - out << "(step s!" << node.number; - out << " (" << node.Name.name(); - for(unsigned i = 0; i < edge.F.IndParams.size(); i++) - out << " " << tree->Eval(&edge,edge.F.IndParams[i]); - out << ")\n"; - - // print the rule number - - out << " rule!" << node.Outgoing->map->number; - - // print the substitution - - out << " (subst\n"; - RPFP::Edge *orig_edge = edge.map; - int orig_clause = d->dd()->map[orig_edge]; - expr &t = d->dd()->clauses[orig_clause]; - if (t.is_quantifier() && t.is_quantifier_forall()) { - int bound = t.get_quantifier_num_bound(); - std::vector sorts; - std::vector names; - hash_map subst; - for(int j = 0; j < bound; j++){ - sort the_sort = t.get_quantifier_bound_sort(j); - symbol name = t.get_quantifier_bound_name(j); - expr skolem = ctx.constant(symbol(ctx,name),sort(ctx,the_sort)); - out << " (= " << skolem << " " << tree->Eval(&edge,skolem) << ")\n"; - expr local_skolem = tree->Localize(&edge,skolem); - (*local_func_decls).insert(local_skolem.decl()); - } - } - out << " )\n"; - - out << " (labels"; - std::vector labels; - tree->GetLabels(&edge,labels); - for(unsigned j = 0; j < labels.size(); j++){ - out << " " << labels[j]; - } - - out << " )\n"; - - // reference the proofs of all the children, in syntactic order - // "true" means the child is not needed - - out << " (ref "; - for(unsigned i = 0; i < edge.Children.size(); i++){ - if(!tree->Empty(edge.Children[i])) - out << " s!" << edge.Children[i]->number; - else - out << " true"; - } - out << " )"; - out << ")\n"; - } - - - void dl_interface::display_certificate(std::ostream& out) const { - ((dl_interface *)this)->display_certificate_non_const(out); - } - - void dl_interface::display_certificate_non_const(std::ostream& out) { - if(_d->status == StatusModel){ - ast_manager &m = m_ctx.get_manager(); - model_ref md = get_model(); - out << "(fixedpoint \n"; - model_smt2_pp(out, m, *md.get(), 0); - out << ")\n"; - } - else if(_d->status == StatusRefutation){ - out << "(derivation\n"; - // negation of the query is the last clause -- prove it - hash_set locals; - local_func_decls = &locals; - print_proof(this,out,_d->cex.get_tree(),_d->cex.get_root()); - out << ")\n"; - out << "(model \n\""; - ::model mod(m_ctx.get_manager()); - model orig_model = _d->cex.get_tree()->dualModel; - for(unsigned i = 0; i < orig_model.num_consts(); i++){ - func_decl cnst = orig_model.get_const_decl(i); - if (locals.find(cnst) == locals.end()) { - expr thing = orig_model.get_const_interp(cnst); - mod.register_decl(to_func_decl(cnst.raw()), to_expr(thing.raw())); - } - } - for(unsigned i = 0; i < orig_model.num_funcs(); i++){ - func_decl cnst = orig_model.get_func_decl(i); - if (locals.find(cnst) == locals.end()) { - func_interp thing = orig_model.get_func_interp(cnst); - ::func_interp *thing_raw = thing; - mod.register_decl(to_func_decl(cnst.raw()), thing_raw->copy()); - } - } - model_v2_pp(out,mod); - out << "\")\n"; - } - } - - expr_ref dl_interface::get_answer() { - SASSERT(false); - return expr_ref(m_ctx.get_manager()); - } - - void dl_interface::cancel() { -#if 0 - if(_d && _d->ls) - _d->ls->cancel(); -#else - // HACK: duality can't cancel at all times, we just exit here - std::cout << "(error \"duality canceled\")\nunknown\n"; - abort(); -#endif - } - - void dl_interface::cleanup() { - } - - void dl_interface::updt_params() { - } - - model_ref dl_interface::get_model() { - ast_manager &m = m_ctx.get_manager(); - model_ref md(alloc(::model, m)); - std::vector &nodes = _d->rpfp->nodes; - expr_ref_vector conjs(m); - for (unsigned i = 0; i < nodes.size(); ++i) { - RPFP::Node *node = nodes[i]; - func_decl &pred = node->Name; - expr_ref prop(m); - prop = to_expr(node->Annotation.Formula); - std::vector ¶ms = node->Annotation.IndParams; - expr_ref q(m); - expr_ref_vector sig_vars(m); - for (unsigned j = 0; j < params.size(); ++j) - sig_vars.push_back(params[params.size()-j-1]); // TODO: why backwards? - expr_abstract(m, 0, sig_vars.size(), sig_vars.c_ptr(), prop, q); - if (params.empty()) { - md->register_decl(pred, q); - } - else { - ::func_interp* fi = alloc(::func_interp, m, params.size()); - fi->set_else(q); - md->register_decl(pred, fi); - } - } - return md; - } - - static proof_ref extract_proof(dl_interface *d, RPFP *tree, RPFP::Node *root) { - context &ctx = d->dd()->ctx; - ast_manager &mgr = ctx.m(); - RPFP::Node &node = *root; - RPFP::Edge &edge = *node.Outgoing; - RPFP::Edge *orig_edge = edge.map; - - // first, prove the children (that are actually used) - - proof_ref_vector prems(mgr); - ::vector substs; - int orig_clause = d->dd()->map[orig_edge]; - expr &t = d->dd()->clauses[orig_clause]; - prems.push_back(mgr.mk_asserted(ctx.uncook(t))); - - substs.push_back(expr_ref_vector(mgr)); - if (t.is_quantifier() && t.is_quantifier_forall()) { - int bound = t.get_quantifier_num_bound(); - std::vector sorts; - std::vector names; - hash_map subst; - for(int j = 0; j < bound; j++){ - sort the_sort = t.get_quantifier_bound_sort(j); - symbol name = t.get_quantifier_bound_name(j); - expr skolem = ctx.constant(symbol(ctx,name),sort(ctx,the_sort)); - expr val = tree->Eval(&edge,skolem); - expr_ref thing(ctx.uncook(val),mgr); - substs[0].push_back(thing); - expr local_skolem = tree->Localize(&edge,skolem); - (*local_func_decls).insert(local_skolem.decl()); - } - } - - svector > pos; - for(unsigned i = 0; i < edge.Children.size(); i++){ - if(!tree->Empty(edge.Children[i])){ - pos.push_back(std::pair(i+1,0)); - proof_ref prem = extract_proof(d,tree,edge.Children[i]); - prems.push_back(prem); - substs.push_back(expr_ref_vector(mgr)); - } - } - - func_decl f = node.Name; - std::vector args; - for(unsigned i = 0; i < edge.F.IndParams.size(); i++) - args.push_back(tree->Eval(&edge,edge.F.IndParams[i])); - expr conc = f(args); - - - ::vector< ::proof *> pprems; - for(unsigned i = 0; i < prems.size(); i++) - pprems.push_back(prems[i].get()); - - proof_ref res(mgr.mk_hyper_resolve(pprems.size(),&pprems[0], ctx.uncook(conc), pos, substs),mgr); - return res; - - } - - proof_ref dl_interface::get_proof() { - if(_d->status == StatusRefutation){ - hash_set locals; - local_func_decls = &locals; - return extract_proof(this,_d->cex.get_tree(),_d->cex.get_root()); - } - else - return proof_ref(m_ctx.get_manager()); - } -} diff --git a/src/muz/duality/duality_dl_interface.h b/src/muz/duality/duality_dl_interface.h deleted file mode 100644 index 8178618ae..000000000 --- a/src/muz/duality/duality_dl_interface.h +++ /dev/null @@ -1,80 +0,0 @@ -/*++ - Copyright (c) 2013 Microsoft Corporation - - Module Name: - - duality_dl_interface.h - - Abstract: - - SMT2 interface for Duality - - Author: - - Krystof Hoder (t-khoder) 2011-9-22. - Modified by Ken McMIllan (kenmcmil) 2013-4-18. - - Revision History: - - --*/ - -#ifndef DUALITY_DL_INTERFACE_H_ -#define DUALITY_DL_INTERFACE_H_ - -#include "util/lbool.h" -#include "muz/base/dl_rule.h" -#include "muz/base/dl_rule_set.h" -#include "muz/base/dl_engine_base.h" -#include "util/statistics.h" - -namespace datalog { - class context; -} - -namespace Duality { - - class duality_data; - - class dl_interface : public datalog::engine_base { - duality_data *_d; - datalog::context &m_ctx; - - public: - dl_interface(datalog::context& ctx); - ~dl_interface() override; - - lbool query(expr* query) override; - - void cancel() override; - - void cleanup() override; - - void display_certificate(std::ostream& out) const override; - - void collect_statistics(statistics& st) const override; - - void reset_statistics() override; - - expr_ref get_answer() override; - - unsigned get_num_levels(func_decl* pred) override; - - expr_ref get_cover_delta(int level, func_decl* pred) override; - - void add_cover(int level, func_decl* pred, expr* property) override; - - void updt_params() override; - - model_ref get_model() override; - - proof_ref get_proof() override; - - duality_data *dd(){return _d;} - - private: - void display_certificate_non_const(std::ostream& out); - }; -} - - -#endif diff --git a/src/muz/fp/CMakeLists.txt b/src/muz/fp/CMakeLists.txt index 0c5f5e915..41262813a 100644 --- a/src/muz/fp/CMakeLists.txt +++ b/src/muz/fp/CMakeLists.txt @@ -8,7 +8,6 @@ z3_add_component(fp bmc clp ddnf - duality_intf muz pdr rel diff --git a/src/muz/fp/dl_register_engine.cpp b/src/muz/fp/dl_register_engine.cpp index 267bfc390..a2270d774 100644 --- a/src/muz/fp/dl_register_engine.cpp +++ b/src/muz/fp/dl_register_engine.cpp @@ -23,7 +23,6 @@ Revision History: #include "muz/rel/rel_context.h" #include "muz/pdr/pdr_dl_interface.h" #include "muz/ddnf/ddnf.h" -#include "muz/duality/duality_dl_interface.h" #include "muz/spacer/spacer_dl_interface.h" namespace datalog { @@ -45,8 +44,6 @@ namespace datalog { return alloc(tab, *m_ctx); case CLP_ENGINE: return alloc(clp, *m_ctx); - case DUALITY_ENGINE: - return alloc(Duality::dl_interface, *m_ctx); case DDNF_ENGINE: return alloc(ddnf, *m_ctx); case LAST_ENGINE: diff --git a/src/smt/smt_internalizer.cpp b/src/smt/smt_internalizer.cpp index c6672c2b8..dc7c32cc1 100644 --- a/src/smt/smt_internalizer.cpp +++ b/src/smt/smt_internalizer.cpp @@ -611,7 +611,6 @@ namespace smt { case OP_XOR: UNREACHABLE(); case OP_OEQ: - case OP_INTERP: UNREACHABLE(); default: break; From 6ecae2b9863c64c824e6d65003b56f0edd5e13fc Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 24 May 2018 09:21:20 -0700 Subject: [PATCH 619/637] fix #1645 Signed-off-by: Nikolaj Bjorner --- src/opt/opt_context.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index e5f4bc133..1ebbc9ebc 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -319,8 +319,7 @@ namespace opt { is_sat = execute_box(); } else { - m_pareto1 = (pri == symbol("pareto")); - is_sat = execute(m_objectives[0], true, false); + is_sat = execute_lex(); } } } @@ -425,7 +424,10 @@ namespace opt { objective const& o = m_objectives[i]; bool is_last = i + 1 == sz; r = execute(o, i + 1 < sz, sc && !is_last && o.m_type != O_MAXSMT); - if (r == l_true && !get_lower_as_num(i).is_finite()) { + if (r == l_true && o.m_type == O_MINIMIZE && !get_lower_as_num(i).is_finite()) { + return r; + } + if (r == l_true && o.m_type == O_MAXIMIZE && !get_upper_as_num(i).is_finite()) { return r; } if (r == l_true && i + 1 < sz) { From da32997f937dc933b638f87ba68dcb6054d3a2ee Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 24 May 2018 10:15:36 -0700 Subject: [PATCH 620/637] fix #1638 Signed-off-by: Nikolaj Bjorner --- src/cmd_context/cmd_context.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/cmd_context/cmd_context.cpp b/src/cmd_context/cmd_context.cpp index e42f884d6..b3ad7dc01 100644 --- a/src/cmd_context/cmd_context.cpp +++ b/src/cmd_context/cmd_context.cpp @@ -1520,6 +1520,9 @@ void cmd_context::check_sat(unsigned num_assumptions, expr * const * assumptions scoped_rlimit _rlimit(m().limit(), rlimit); try { r = m_solver->check_sat(num_assumptions, assumptions); + if (r == l_undef && m().canceled()) { + m_solver->set_reason_unknown(eh); + } } catch (z3_error & ex) { throw ex; From a9ca01d8d3257f1f13ded3d6ebdc3e754a6876fe Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 24 May 2018 13:12:07 -0700 Subject: [PATCH 621/637] deprecating interp Signed-off-by: Nikolaj Bjorner --- RELEASE_NOTES | 4 +- src/api/dotnet/Expr.cs | 8 -- src/api/python/z3/z3.py | 140 ----------------------------- src/muz/base/fixedpoint_params.pyg | 15 +--- 4 files changed, 4 insertions(+), 163 deletions(-) diff --git a/RELEASE_NOTES b/RELEASE_NOTES index a2b526550..7439342de 100644 --- a/RELEASE_NOTES +++ b/RELEASE_NOTES @@ -28,8 +28,10 @@ Version 4.8.0 as lemmas (redundant) and are garbage collected if their glue level is high. - Removed features: + - interpolation API + - duality engine for constrained Horn clauses. - long deprecated API functions have been removed from z3_api.h - + Version 4.7.1 ============= diff --git a/src/api/dotnet/Expr.cs b/src/api/dotnet/Expr.cs index 9310d1e7d..f09eecbdd 100644 --- a/src/api/dotnet/Expr.cs +++ b/src/api/dotnet/Expr.cs @@ -317,14 +317,6 @@ namespace Microsoft.Z3 #endregion - #region Interpolation - /// - /// Indicates whether the term is marked for interpolation. - /// - /// - public bool IsInterpolant { get { return IsApp && FuncDecl.DeclKind == Z3_decl_kind.Z3_OP_INTERP; } } - #endregion - #region Arithmetic Terms /// /// Indicates whether the term is of integer sort. diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index 978141de9..784228120 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -8269,146 +8269,6 @@ def parse_smt2_file(f, sorts={}, decls={}, ctx=None): except Z3Exception as e: _handle_parse_error(e, ctx) -def Interpolant(a,ctx=None): - """Create an interpolation operator. - - The argument is an interpolation pattern (see tree_interpolant). - - >>> x = Int('x') - >>> print(Interpolant(x>0)) - interp(x > 0) - """ - ctx = _get_ctx(_ctx_from_ast_arg_list([a], ctx)) - s = BoolSort(ctx) - a = s.cast(a) - return BoolRef(Z3_mk_interpolant(ctx.ref(), a.as_ast()), ctx) - -def tree_interpolant(pat,p=None,ctx=None): - """Compute interpolant for a tree of formulas. - - The input is an interpolation pattern over a set of formulas C. - The pattern pat is a formula combining the formulas in C using - logical conjunction and the "interp" operator (see Interp). This - interp operator is logically the identity operator. It marks the - sub-formulas of the pattern for which interpolants should be - computed. The interpolant is a map sigma from marked subformulas - to formulas, such that, for each marked subformula phi of pat - (where phi sigma is phi with sigma(psi) substituted for each - subformula psi of phi such that psi in dom(sigma)): - - 1) phi sigma implies sigma(phi), and - - 2) sigma(phi) is in the common uninterpreted vocabulary between - the formulas of C occurring in phi and those not occurring in - phi - - and moreover pat sigma implies false. In the simplest case - an interpolant for the pattern "(and (interp A) B)" maps A - to an interpolant for A /\ B. - - The return value is a vector of formulas representing sigma. This - vector contains sigma(phi) for each marked subformula of pat, in - pre-order traversal. This means that subformulas of phi occur before phi - in the vector. Also, subformulas that occur multiply in pat will - occur multiply in the result vector. - - If pat is satisfiable, raises an object of class ModelRef - that represents a model of pat. - - If neither a proof of unsatisfiability nor a model is obtained - (for example, because of a timeout, or because models are disabled) - then None is returned. - - If parameters p are supplied, these are used in creating the - solver that determines satisfiability. - - >>> x = Int('x') - >>> y = Int('y') - >>> print(tree_interpolant(And(Interpolant(x < 0), Interpolant(y > 2), x == y))) - [Not(x >= 0), Not(y <= 2)] - - # >>> g = And(Interpolant(x<0),x<2) - # >>> try: - # ... print tree_interpolant(g).sexpr() - # ... except ModelRef as m: - # ... print m.sexpr() - (define-fun x () Int - (- 1)) - """ - f = pat - ctx = _get_ctx(_ctx_from_ast_arg_list([f], ctx)) - ptr = (AstVectorObj * 1)() - mptr = (Model * 1)() - if p is None: - p = ParamsRef(ctx) - res = Z3_compute_interpolant(ctx.ref(),f.as_ast(),p.params,ptr,mptr) - if res == Z3_L_FALSE: - return AstVector(ptr[0],ctx) - if mptr[0]: - raise ModelRef(mptr[0], ctx) - return None - -def binary_interpolant(a,b,p=None,ctx=None): - """Compute an interpolant for a binary conjunction. - - If a & b is unsatisfiable, returns an interpolant for a & b. - This is a formula phi such that - - 1) a implies phi - 2) b implies not phi - 3) All the uninterpreted symbols of phi occur in both a and b. - - If a & b is satisfiable, raises an object of class ModelRef - that represents a model of a &b. - - If neither a proof of unsatisfiability nor a model is obtained - (for example, because of a timeout, or because models are disabled) - then None is returned. - - If parameters p are supplied, these are used in creating the - solver that determines satisfiability. - - x = Int('x') - print(binary_interpolant(x<0,x>2)) - Not(x >= 0) - """ - f = And(Interpolant(a),b) - ti = tree_interpolant(f,p,ctx) - return ti[0] if ti is not None else None - -def sequence_interpolant(v,p=None,ctx=None): - """Compute interpolant for a sequence of formulas. - - If len(v) == N, and if the conjunction of the formulas in v is - unsatisfiable, the interpolant is a sequence of formulas w - such that len(w) = N-1 and v[0] implies w[0] and for i in 0..N-1: - - 1) w[i] & v[i+1] implies w[i+1] (or false if i+1 = N) - 2) All uninterpreted symbols in w[i] occur in both v[0]..v[i] - and v[i+1]..v[n] - - Requires len(v) >= 1. - - If a & b is satisfiable, raises an object of class ModelRef - that represents a model of a & b. - - If neither a proof of unsatisfiability nor a model is obtained - (for example, because of a timeout, or because models are disabled) - then None is returned. - - If parameters p are supplied, these are used in creating the - solver that determines satisfiability. - - x = Int('x') - y = Int('y') - print(sequence_interpolant([x < 0, y == x , y > 2])) - [Not(x >= 0), Not(y >= 0)] - """ - f = v[0] - for i in range(1,len(v)): - f = And(Interpolant(f),v[i]) - return tree_interpolant(f,p,ctx) - ######################################### # diff --git a/src/muz/base/fixedpoint_params.pyg b/src/muz/base/fixedpoint_params.pyg index 753a45e06..8d6c750d5 100644 --- a/src/muz/base/fixedpoint_params.pyg +++ b/src/muz/base/fixedpoint_params.pyg @@ -3,7 +3,7 @@ def_module_params('fixedpoint', export=True, params=(('timeout', UINT, UINT_MAX, 'set timeout'), ('engine', SYMBOL, 'auto-config', - 'Select: auto-config, datalog, duality, pdr, bmc, spacer'), + 'Select: auto-config, datalog, spacer, pdr, bmc'), ('datalog.default_table', SYMBOL, 'sparse', 'default table implementation: sparse, hashtable, bitvector, interval'), ('datalog.default_relation', SYMBOL, 'pentagon', @@ -56,18 +56,6 @@ def_module_params('fixedpoint', "table columns, if it would have been empty otherwise"), ('datalog.subsumption', BOOL, True, "if true, removes/filters predicates with total transitions"), - ('duality.full_expand', BOOL, False, 'Fully expand derivation trees'), - ('duality.no_conj', BOOL, False, 'No forced covering (conjectures)'), - ('duality.feasible_edges', BOOL, True, - 'Don\'t expand definitely infeasible edges'), - ('duality.use_underapprox', BOOL, False, 'Use underapproximations'), - ('duality.stratified_inlining', BOOL, False, 'Use stratified inlining'), - ('duality.recursion_bound', UINT, UINT_MAX, - 'Recursion bound for stratified inlining'), - ('duality.profile', BOOL, False, 'profile run time'), - ('duality.mbqi', BOOL, True, 'use model-based quantifier instantiation'), - ('duality.batch_expand', BOOL, False, 'use batch expansion'), - ('duality.conjecture_file', STRING, '', 'save conjectures to file'), ('pdr.bfs_model_search', BOOL, True, "use BFS strategy for expanding model search"), ('pdr.farkas', BOOL, True, @@ -161,7 +149,6 @@ def_module_params('fixedpoint', ('xform.tail_simplifier_pve', BOOL, True, "propagate_variable_equivalences"), ('xform.subsumption_checker', BOOL, True, "Enable subsumption checker (no support for model conversion)"), ('xform.coi', BOOL, True, "use cone of influence simplification"), - ('duality.enable_restarts', BOOL, False, 'DUALITY: enable restarts'), ('spacer.order_children', UINT, 0, 'SPACER: order of enqueuing children in non-linear rules : 0 (original), 1 (reverse)'), ('spacer.eager_reach_check', BOOL, True, 'SPACER: eagerly check if a query is reachable using reachability facts of predecessors'), ('spacer.use_lemma_as_cti', BOOL, False, 'SPACER: use a lemma instead of a CTI in flexible_trace'), From 9f3da32a77263ee6fab4d7f22adc212686137f68 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 24 May 2018 16:28:23 -0700 Subject: [PATCH 622/637] remove interpolation from test_capi Signed-off-by: Nikolaj Bjorner --- examples/c/test_capi.c | 41 ----------------------------------------- 1 file changed, 41 deletions(-) diff --git a/examples/c/test_capi.c b/examples/c/test_capi.c index 6761b3f8d..a6937f293 100644 --- a/examples/c/test_capi.c +++ b/examples/c/test_capi.c @@ -2290,46 +2290,6 @@ void unsat_core_and_proof_example() { Z3_del_context(ctx); } -void interpolation_example() { - Z3_context ctx = mk_context(); - Z3_ast pa = mk_bool_var(ctx, "PredA"); - Z3_ast pb = mk_bool_var(ctx, "PredB"); - Z3_ast pc = mk_bool_var(ctx, "PredC"); - Z3_ast args1[2] = {pa,pb}, args2[2] = {Z3_mk_not(ctx,pb),pc}; - Z3_ast args3[2] = {Z3_mk_interpolant(ctx,Z3_mk_and(ctx,2,args1)),Z3_mk_and(ctx,2,args2)}; - Z3_ast f = Z3_mk_and(ctx,2,args3); - Z3_ast_vector interpolant = 0; - Z3_model m = 0; - Z3_lbool result = Z3_L_UNDEF; - - printf("\ninterpolation_example\n"); - LOG_MSG("interpolation_example"); - - result = Z3_compute_interpolant(ctx,f,0,&interpolant,&m); - - switch (result) { - case Z3_L_FALSE: - printf("unsat\n"); - printf("interpolant: %s\n", Z3_ast_to_string(ctx, Z3_ast_vector_get(ctx, interpolant, 0))); - printf("\n"); - break; - case Z3_L_UNDEF: - printf("unknown\n"); - printf("potential model:\n"); - if (m) Z3_model_inc_ref(ctx, m); - display_model(ctx, stdout, m); - break; - case Z3_L_TRUE: - printf("sat\n"); - if (m) Z3_model_inc_ref(ctx, m); - display_model(ctx, stdout, m); - break; - } - - /* delete logical context */ - if (m) Z3_model_dec_ref(ctx, m); - Z3_del_context(ctx); -} #define MAX_RETRACTABLE_ASSERTIONS 1024 @@ -3014,7 +2974,6 @@ int main() { binary_tree_example(); enum_example(); unsat_core_and_proof_example(); - interpolation_example(); incremental_example1(); reference_counter_example(); smt2parser_example(); From 6b700f1f5f0026b27940ac518519ad03d2ec354d Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Thu, 24 May 2018 20:32:04 -0700 Subject: [PATCH 623/637] remove interpolation from test_capi Signed-off-by: Nikolaj Bjorner --- src/api/c++/z3++.h | 38 -------------------------------------- 1 file changed, 38 deletions(-) diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index eef5d7904..665ffb438 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -147,20 +147,12 @@ namespace z3 { Z3_set_ast_print_mode(m_ctx, Z3_PRINT_SMTLIB2_COMPLIANT); } - void init_interp(config & c) { - m_ctx = Z3_mk_interpolation_context(c); - m_enable_exceptions = true; - Z3_set_error_handler(m_ctx, 0); - Z3_set_ast_print_mode(m_ctx, Z3_PRINT_SMTLIB2_COMPLIANT); - } context(context const & s); context & operator=(context const & s); public: - struct interpolation {}; context() { config c; init(c); } context(config & c) { init(c); } - context(config & c, interpolation) { init_interp(c); } ~context() { Z3_del_context(m_ctx); } operator Z3_context() const { return m_ctx; } @@ -335,11 +327,6 @@ namespace z3 { expr_vector parse_string(char const* s, sort_vector const& sorts, func_decl_vector const& decls); expr_vector parse_file(char const* s, sort_vector const& sorts, func_decl_vector const& decls); - /** - \brief Interpolation support - */ - check_result compute_interpolant(expr const& pat, params const& p, expr_vector& interp, model& m); - expr_vector get_interpolant(expr const& proof, expr const& pat, params const& p); }; @@ -2969,10 +2956,6 @@ namespace z3 { - inline expr interpolant(expr const& a) { - return expr(a.ctx(), Z3_mk_interpolant(a.ctx(), a)); - } - inline expr_vector context::parse_string(char const* s) { Z3_ast_vector r = Z3_parse_smtlib2_string(*this, s, 0, 0, 0, 0, 0, 0); check_error(); @@ -3019,27 +3002,6 @@ namespace z3 { } - inline check_result context::compute_interpolant(expr const& pat, params const& p, expr_vector& i, model& m) { - Z3_ast_vector interp = 0; - Z3_model mdl = 0; - Z3_lbool r = Z3_compute_interpolant(*this, pat, p, &interp, &mdl); - switch (r) { - case Z3_L_FALSE: - i = expr_vector(*this, interp); - break; - case Z3_L_TRUE: - m = model(*this, mdl); - break; - case Z3_L_UNDEF: - break; - } - return to_check_result(r); - } - - inline expr_vector context::get_interpolant(expr const& proof, expr const& pat, params const& p) { - return expr_vector(*this, Z3_get_interpolant(*this, proof, pat, p)); - } - inline expr expr::substitute(expr_vector const& src, expr_vector const& dst) { assert(src.size() == dst.size()); array _src(src.size()); From 3e0506a71bb4ba9f770105374af7f147c34a3ea7 Mon Sep 17 00:00:00 2001 From: Philipp Wendler Date: Fri, 25 May 2018 14:54:44 +0200 Subject: [PATCH 624/637] Set the SONAME field of libz3.so to libz3.so. This fixes a problem when loading libz3java from Java, where the dependency on libz3 is not detected as fulfilled if the latter does not have SONAME set. --- scripts/mk_util.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 1391eee87..87d766e55 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -2460,7 +2460,7 @@ def mk_config(): check_ar() CXX = find_cxx_compiler() CC = find_c_compiler() - SLIBEXTRAFLAGS = '' + SLIBEXTRAFLAGS = '-Wl,-soname,libz3.so' EXE_EXT = '' LIB_EXT = '.a' if GPROF: From 8eeaa27cf34eeba7e8c832e83362e11f439ff282 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 25 May 2018 07:33:43 -0700 Subject: [PATCH 625/637] remove interp from documentation Signed-off-by: Nikolaj Bjorner --- doc/mk_api_doc.py | 1 - src/opt/opt_context.cpp | 9 ++++++--- src/opt/opt_pareto.cpp | 7 ++++--- src/smt/theory_pb.cpp | 2 +- 4 files changed, 11 insertions(+), 8 deletions(-) diff --git a/doc/mk_api_doc.py b/doc/mk_api_doc.py index a1a9e64bd..bfe865e06 100644 --- a/doc/mk_api_doc.py +++ b/doc/mk_api_doc.py @@ -272,7 +272,6 @@ try: cleanup_API(doc_path('../src/api/z3_rcf.h'), temp_path('z3_rcf.h')) cleanup_API(doc_path('../src/api/z3_fixedpoint.h'), temp_path('z3_fixedpoint.h')) cleanup_API(doc_path('../src/api/z3_optimization.h'), temp_path('z3_optimization.h')) - cleanup_API(doc_path('../src/api/z3_interp.h'), temp_path('z3_interp.h')) cleanup_API(doc_path('../src/api/z3_fpa.h'), temp_path('z3_fpa.h')) print("Removed annotations from z3_api.h.") diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index e5f4bc133..004a83a14 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -497,7 +497,7 @@ namespace opt { case O_MINIMIZE: is_ge = !is_ge; case O_MAXIMIZE: - if (mdl->eval(obj.m_term, val) && is_numeral(val, k)) { + if (mdl->eval(obj.m_term, val, true) && is_numeral(val, k)) { if (is_ge) { result = mk_ge(obj.m_term, val); } @@ -517,9 +517,12 @@ namespace opt { for (unsigned i = 0; i < sz; ++i) { terms.push_back(obj.m_terms[i]); coeffs.push_back(obj.m_weights[i]); - if (mdl->eval(obj.m_terms[i], val) && m.is_true(val)) { + if (mdl->eval(obj.m_terms[i], val, true) && m.is_true(val)) { k += obj.m_weights[i]; } + else { + TRACE("opt", tout << val << "\n";); + } } if (is_ge) { result = pb.mk_ge(sz, coeffs.c_ptr(), terms.c_ptr(), k); @@ -1044,7 +1047,7 @@ namespace opt { model_ref mdl = md->copy(); fix_model(mdl); - if (!mdl->eval(term, val)) { + if (!mdl->eval(term, val, true)) { TRACE("opt", tout << "Term does not evaluate " << term << "\n";); return false; } diff --git a/src/opt/opt_pareto.cpp b/src/opt/opt_pareto.cpp index c316e697e..56eed72ac 100644 --- a/src/opt/opt_pareto.cpp +++ b/src/opt/opt_pareto.cpp @@ -20,6 +20,7 @@ Notes: #include "opt/opt_pareto.h" #include "ast/ast_pp.h" +#include "ast/ast_util.h" #include "model/model_smt2_pp.h" namespace opt { @@ -66,8 +67,8 @@ namespace opt { fmls.push_back(cb.mk_ge(i, m_model)); gt.push_back(cb.mk_gt(i, m_model)); } - fmls.push_back(m.mk_or(gt.size(), gt.c_ptr())); - fml = m.mk_and(fmls.size(), fmls.c_ptr()); + fmls.push_back(mk_or(gt)); + fml = mk_and(fmls); IF_VERBOSE(10, verbose_stream() << "dominates: " << fml << "\n";); TRACE("opt", tout << fml << "\n"; model_smt2_pp(tout, m, *m_model, 0);); m_solver->assert_expr(fml); @@ -80,7 +81,7 @@ namespace opt { for (unsigned i = 0; i < sz; ++i) { le.push_back(cb.mk_le(i, m_model)); } - fml = m.mk_not(m.mk_and(le.size(), le.c_ptr())); + fml = m.mk_not(mk_and(le)); IF_VERBOSE(10, verbose_stream() << "not dominated by: " << fml << "\n";); TRACE("opt", tout << fml << "\n";); m_solver->assert_expr(fml); diff --git a/src/smt/theory_pb.cpp b/src/smt/theory_pb.cpp index 9fc33a6a9..d45590bff 100644 --- a/src/smt/theory_pb.cpp +++ b/src/smt/theory_pb.cpp @@ -2007,7 +2007,7 @@ namespace smt { if (m_bound > static_cast(m_active_vars.size())) { return; } - if (m_bound == m_active_vars.size()) { + if (m_bound == static_cast(m_active_vars.size())) { return; } From 7145a9ac41f80551f911a2bf8f78a5500b1636d7 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 25 May 2018 07:38:30 -0700 Subject: [PATCH 626/637] fix #1647 Signed-off-by: Nikolaj Bjorner --- src/opt/opt_context.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 1ebbc9ebc..1ba107b19 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -499,7 +499,7 @@ namespace opt { case O_MINIMIZE: is_ge = !is_ge; case O_MAXIMIZE: - if (mdl->eval(obj.m_term, val) && is_numeral(val, k)) { + if (mdl->eval(obj.m_term, val, true) && is_numeral(val, k)) { if (is_ge) { result = mk_ge(obj.m_term, val); } @@ -519,7 +519,7 @@ namespace opt { for (unsigned i = 0; i < sz; ++i) { terms.push_back(obj.m_terms[i]); coeffs.push_back(obj.m_weights[i]); - if (mdl->eval(obj.m_terms[i], val) && m.is_true(val)) { + if (mdl->eval(obj.m_terms[i], val, true) && m.is_true(val)) { k += obj.m_weights[i]; } } @@ -1046,7 +1046,7 @@ namespace opt { model_ref mdl = md->copy(); fix_model(mdl); - if (!mdl->eval(term, val)) { + if (!mdl->eval(term, val, true)) { TRACE("opt", tout << "Term does not evaluate " << term << "\n";); return false; } From 2b73b7c7f371309f415d1e95f620f5c8a46c135c Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 25 May 2018 08:43:35 -0700 Subject: [PATCH 627/637] Revert "Fix missing SONAME in libz3.so, which breaks loading from Java" --- scripts/mk_util.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 87d766e55..1391eee87 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -2460,7 +2460,7 @@ def mk_config(): check_ar() CXX = find_cxx_compiler() CC = find_c_compiler() - SLIBEXTRAFLAGS = '-Wl,-soname,libz3.so' + SLIBEXTRAFLAGS = '' EXE_EXT = '' LIB_EXT = '.a' if GPROF: From 753b9dd734305bd6211bc8f90e8b558d1775bae2 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 25 May 2018 08:56:13 -0700 Subject: [PATCH 628/637] fix #1650 fix #1648 Signed-off-by: Nikolaj Bjorner --- scripts/mk_util.py | 3 ++- src/ast/rewriter/pb2bv_rewriter.cpp | 16 +++++++++------- src/ast/rewriter/pb2bv_rewriter.h | 2 +- src/tactic/arith/card2bv_tactic.cpp | 2 +- src/tactic/portfolio/pb2bv_solver.cpp | 2 +- src/test/pb2bv.cpp | 13 ++++++++++--- 6 files changed, 24 insertions(+), 14 deletions(-) diff --git a/scripts/mk_util.py b/scripts/mk_util.py index 87d766e55..d51735255 100644 --- a/scripts/mk_util.py +++ b/scripts/mk_util.py @@ -2460,7 +2460,7 @@ def mk_config(): check_ar() CXX = find_cxx_compiler() CC = find_c_compiler() - SLIBEXTRAFLAGS = '-Wl,-soname,libz3.so' + SLIBEXTRAFLAGS = '' EXE_EXT = '' LIB_EXT = '.a' if GPROF: @@ -2511,6 +2511,7 @@ def mk_config(): LDFLAGS = '%s -lrt' % LDFLAGS SLIBFLAGS = '-shared' SLIBEXTRAFLAGS = '%s -lrt' % SLIBEXTRAFLAGS + SLIBEXTRAFLAGS = '%s -Wl,-soname,libz3.so' % SLIBEXTRAFLAGS elif sysname == 'FreeBSD': CXXFLAGS = '%s -D_FREEBSD_' % CXXFLAGS OS_DEFINES = '-D_FREEBSD_' diff --git a/src/ast/rewriter/pb2bv_rewriter.cpp b/src/ast/rewriter/pb2bv_rewriter.cpp index 7da8b2d3f..e4a34fc93 100644 --- a/src/ast/rewriter/pb2bv_rewriter.cpp +++ b/src/ast/rewriter/pb2bv_rewriter.cpp @@ -726,9 +726,9 @@ struct pb2bv_rewriter::imp { } } - bool mk_app(expr* e, expr_ref& r) { + bool mk_app(bool full, expr* e, expr_ref& r) { app* a; - return (is_app(e) && (a = to_app(e), mk_app(false, a->get_decl(), a->get_num_args(), a->get_args(), r))); + return (is_app(e) && (a = to_app(e), mk_app(full, a->get_decl(), a->get_num_args(), a->get_args(), r))); } bool is_pb(expr* x, expr* y) { @@ -844,6 +844,8 @@ struct pb2bv_rewriter::imp { else { result = mk_bv(f, sz, args); } + TRACE("pb", tout << "full: " << full << " " << expr_ref(m.mk_app(f, sz, args), m) << " " << result << "\n"; + ); return true; } @@ -915,9 +917,9 @@ struct pb2bv_rewriter::imp { void keep_cardinality_constraints(bool f) { m_cfg.keep_cardinality_constraints(f); } void set_pb_solver(symbol const& s) { m_cfg.set_pb_solver(s); } void set_at_most1(sorting_network_encoding e) { m_cfg.set_at_most1(e); } - void rewrite(expr* e, expr_ref& r, proof_ref& p) { + void rewrite(bool full, expr* e, expr_ref& r, proof_ref& p) { expr_ref ee(e, m()); - if (m_cfg.m_r.mk_app(e, r)) { + if (m_cfg.m_r.mk_app(full, e, r)) { ee = r; // mp proof? } @@ -980,9 +982,9 @@ struct pb2bv_rewriter::imp { unsigned get_num_steps() const { return m_rw.get_num_steps(); } void cleanup() { m_rw.cleanup(); } - void operator()(expr * e, expr_ref & result, proof_ref & result_proof) { + void operator()(bool full, expr * e, expr_ref & result, proof_ref & result_proof) { // m_rw(e, result, result_proof); - m_rw.rewrite(e, result, result_proof); + m_rw.rewrite(full, e, result, result_proof); } void push() { m_fresh_lim.push_back(m_fresh.size()); @@ -1023,7 +1025,7 @@ ast_manager & pb2bv_rewriter::m() const { return m_imp->m; } unsigned pb2bv_rewriter::get_num_steps() const { return m_imp->get_num_steps(); } void pb2bv_rewriter::cleanup() { ast_manager& mgr = m(); params_ref p = m_imp->m_params; dealloc(m_imp); m_imp = alloc(imp, mgr, p); } func_decl_ref_vector const& pb2bv_rewriter::fresh_constants() const { return m_imp->m_fresh; } -void pb2bv_rewriter::operator()(expr * e, expr_ref & result, proof_ref & result_proof) { (*m_imp)(e, result, result_proof); } +void pb2bv_rewriter::operator()(bool full, expr * e, expr_ref & result, proof_ref & result_proof) { (*m_imp)(full, e, result, result_proof); } void pb2bv_rewriter::push() { m_imp->push(); } void pb2bv_rewriter::pop(unsigned num_scopes) { m_imp->pop(num_scopes); } void pb2bv_rewriter::flush_side_constraints(expr_ref_vector& side_constraints) { m_imp->flush_side_constraints(side_constraints); } diff --git a/src/ast/rewriter/pb2bv_rewriter.h b/src/ast/rewriter/pb2bv_rewriter.h index 9e3785649..3460f08ab 100644 --- a/src/ast/rewriter/pb2bv_rewriter.h +++ b/src/ast/rewriter/pb2bv_rewriter.h @@ -36,7 +36,7 @@ public: unsigned get_num_steps() const; void cleanup(); func_decl_ref_vector const& fresh_constants() const; - void operator()(expr * e, expr_ref & result, proof_ref & result_proof); + void operator()(bool full, expr * e, expr_ref & result, proof_ref & result_proof); void push(); void pop(unsigned num_scopes); void flush_side_constraints(expr_ref_vector& side_constraints); diff --git a/src/tactic/arith/card2bv_tactic.cpp b/src/tactic/arith/card2bv_tactic.cpp index 63d034374..97649cc2f 100644 --- a/src/tactic/arith/card2bv_tactic.cpp +++ b/src/tactic/arith/card2bv_tactic.cpp @@ -71,7 +71,7 @@ public: for (unsigned idx = 0; !g->inconsistent() && idx < g->size(); idx++) { rw1(g->form(idx), new_f1, new_pr1); TRACE("card2bv", tout << "Rewriting " << mk_ismt2_pp(new_f1.get(), m) << std::endl;); - rw2(new_f1, new_f2, new_pr2); + rw2(false, new_f1, new_f2, new_pr2); if (m.proofs_enabled()) { new_pr1 = m.mk_modus_ponens(g->pr(idx), new_pr1); new_pr1 = m.mk_modus_ponens(new_pr1, new_pr2); diff --git a/src/tactic/portfolio/pb2bv_solver.cpp b/src/tactic/portfolio/pb2bv_solver.cpp index 0f2311233..f8794ca41 100644 --- a/src/tactic/portfolio/pb2bv_solver.cpp +++ b/src/tactic/portfolio/pb2bv_solver.cpp @@ -147,7 +147,7 @@ private: expr_ref_vector fmls(m); for (expr* a : m_assertions) { m_th_rewriter(a, fml1, proof); - m_rewriter(fml1, fml, proof); + m_rewriter(false, fml1, fml, proof); m_solver->assert_expr(fml); } m_rewriter.flush_side_constraints(fmls); diff --git a/src/test/pb2bv.cpp b/src/test/pb2bv.cpp index 35c444bae..d58bf61ee 100644 --- a/src/test/pb2bv.cpp +++ b/src/test/pb2bv.cpp @@ -37,7 +37,7 @@ static void test1() { expr_ref fml(m), result(m); proof_ref proof(m); fml = pb.mk_at_least_k(vars.size(), vars.c_ptr(), k); - rw(fml, result, proof); + rw(true, fml, result, proof); std::cout << fml << " |-> " << result << "\n"; } expr_ref_vector lemmas(m); @@ -60,9 +60,10 @@ static void test_semantics(ast_manager& m, expr_ref_vector const& vars, vector(1 << N); ++values) { smt_params fp; smt::kernel solver(m, fp); @@ -86,6 +87,12 @@ static void test_semantics(ast_manager& m, expr_ref_vector const& vars, vector Date: Fri, 25 May 2018 10:27:12 -0700 Subject: [PATCH 629/637] clean up python build files Signed-off-by: Nikolaj Bjorner --- scripts/mk_project.py | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/scripts/mk_project.py b/scripts/mk_project.py index b03ced763..f2720c893 100644 --- a/scripts/mk_project.py +++ b/scripts/mk_project.py @@ -40,8 +40,7 @@ def init_project_def(): add_lib('subpaving_tactic', ['core_tactics', 'subpaving'], 'math/subpaving/tactic') add_lib('aig_tactic', ['tactic'], 'tactic/aig') add_lib('ackermannization', ['model', 'rewriter', 'ast', 'solver', 'tactic'], 'ackermannization') - add_lib('interp', ['solver']) - add_lib('cmd_context', ['solver', 'rewriter', 'interp']) + add_lib('cmd_context', ['solver', 'rewriter']) add_lib('extra_cmds', ['cmd_context', 'subpaving_tactic', 'arith_tactics'], 'cmd_context/extra_cmds') add_lib('smt2parser', ['cmd_context', 'parser_util'], 'parsers/smt2') add_lib('fpa', ['ast', 'util', 'rewriter', 'model'], 'ast/fpa') @@ -56,7 +55,6 @@ def init_project_def(): add_lib('smt_tactic', ['smt'], 'smt/tactic') add_lib('sls_tactic', ['tactic', 'normal_forms', 'core_tactics', 'bv_tactics'], 'tactic/sls') add_lib('qe', ['smt','sat','nlsat','tactic','nlsat_tactic'], 'qe') - add_lib('duality', ['smt', 'interp', 'qe']) add_lib('muz', ['smt', 'sat', 'smt2parser', 'aig_tactic', 'qe'], 'muz/base') add_lib('dataflow', ['muz'], 'muz/dataflow') add_lib('transforms', ['muz', 'hilbert', 'dataflow'], 'muz/transforms') @@ -67,16 +65,15 @@ def init_project_def(): add_lib('tab', ['muz', 'transforms'], 'muz/tab') add_lib('bmc', ['muz', 'transforms'], 'muz/bmc') add_lib('ddnf', ['muz', 'transforms', 'rel'], 'muz/ddnf') - add_lib('duality_intf', ['muz', 'transforms', 'duality'], 'muz/duality') - add_lib('fp', ['muz', 'pdr', 'clp', 'tab', 'rel', 'bmc', 'duality_intf', 'ddnf', 'spacer'], 'muz/fp') + add_lib('fp', ['muz', 'pdr', 'clp', 'tab', 'rel', 'bmc', 'ddnf', 'spacer'], 'muz/fp') add_lib('ufbv_tactic', ['normal_forms', 'core_tactics', 'macros', 'smt_tactic', 'rewriter'], 'tactic/ufbv') add_lib('sat_solver', ['solver', 'core_tactics', 'aig_tactic', 'bv_tactics', 'arith_tactics', 'sat_tactic'], 'sat/sat_solver') add_lib('smtlogic_tactics', ['ackermannization', 'sat_solver', 'arith_tactics', 'bv_tactics', 'nlsat_tactic', 'smt_tactic', 'aig_tactic', 'fp', 'muz','qe'], 'tactic/smtlogics') add_lib('fpa_tactics', ['fpa', 'core_tactics', 'bv_tactics', 'sat_tactic', 'smt_tactic', 'arith_tactics', 'smtlogic_tactics'], 'tactic/fpa') add_lib('portfolio', ['smtlogic_tactics', 'sat_solver', 'ufbv_tactic', 'fpa_tactics', 'aig_tactic', 'fp', 'qe','sls_tactic', 'subpaving_tactic'], 'tactic/portfolio') add_lib('opt', ['smt', 'smtlogic_tactics', 'sls_tactic', 'sat_solver'], 'opt') - API_files = ['z3_api.h', 'z3_ast_containers.h', 'z3_algebraic.h', 'z3_polynomial.h', 'z3_rcf.h', 'z3_fixedpoint.h', 'z3_optimization.h', 'z3_interp.h', 'z3_fpa.h', 'z3_spacer.h'] - add_lib('api', ['portfolio', 'realclosure', 'interp', 'opt'], + API_files = ['z3_api.h', 'z3_ast_containers.h', 'z3_algebraic.h', 'z3_polynomial.h', 'z3_rcf.h', 'z3_fixedpoint.h', 'z3_optimization.h', 'z3_fpa.h', 'z3_spacer.h'] + add_lib('api', ['portfolio', 'realclosure', 'opt'], includes2install=['z3.h', 'z3_v1.h', 'z3_macros.h'] + API_files) add_exe('shell', ['api', 'sat', 'extra_cmds','opt'], exe_name='z3') add_exe('test', ['api', 'fuzzing', 'simplex'], exe_name='test-z3', install=False) From a06926915dbc4925f07bbc7eee95e3115b46774b Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 25 May 2018 10:47:54 -0700 Subject: [PATCH 630/637] remove stale file Signed-off-by: Nikolaj Bjorner --- src/api/api_interp.cpp | 725 ----------------------------------------- 1 file changed, 725 deletions(-) delete mode 100644 src/api/api_interp.cpp diff --git a/src/api/api_interp.cpp b/src/api/api_interp.cpp deleted file mode 100644 index 2b461e991..000000000 --- a/src/api/api_interp.cpp +++ /dev/null @@ -1,725 +0,0 @@ -/*++ - Copyright (c) 2011 Microsoft Corporation - - Module Name: - - api_interp.cpp - - Abstract: - API for interpolation - - Author: - - Ken McMillan - - Revision History: - - --*/ -#include -#include -#include "api/z3.h" -#include "api/api_log_macros.h" -#include "api/api_context.h" -#include "api/api_tactic.h" -#include "api/api_solver.h" -#include "api/api_model.h" -#include "api/api_stats.h" -#include "api/api_ast_vector.h" -#include "solver/tactic2solver.h" -#include "util/scoped_ctrl_c.h" -#include "util/cancel_eh.h" -#include "util/scoped_timer.h" -#include "tactic/portfolio/smt_strategic_solver.h" -#include "smt/smt_solver.h" -#include "smt/smt_implied_equalities.h" -#include "interp/iz3interp.h" -#include "interp/iz3profiling.h" -#include "interp/iz3hash.h" -#include "interp/iz3pp.h" -#include "interp/iz3checker.h" -#include "ast/scoped_proof.h" - -using namespace stl_ext; - -// WARNING: don't make a hash_map with this if the range type -// has a destructor: you'll get an address dependency!!! -namespace stl_ext { - template <> - class hash < Z3_ast > { - public: - size_t operator()(const Z3_ast p) const { - return (size_t)p; - } - }; -} - -typedef interpolation_options_struct *Z3_interpolation_options; - -extern "C" { - - Z3_context Z3_mk_interpolation_context(Z3_config cfg){ - if (!cfg) cfg = Z3_mk_config(); - Z3_set_param_value(cfg, "PROOF", "true"); - Z3_set_param_value(cfg, "MODEL", "true"); - // Z3_set_param_value(cfg, "PRE_SIMPLIFIER","false"); - // Z3_set_param_value(cfg, "SIMPLIFY_CLAUSES","false"); - - Z3_context ctx = Z3_mk_context(cfg); - return ctx; - } - - void Z3_interpolate_proof(Z3_context ctx, - Z3_ast proof, - int num, - Z3_ast *cnsts, - unsigned *parents, - Z3_params options, - Z3_ast *interps, - int num_theory, - Z3_ast *theory) - { - - if (num > 1){ // if we have interpolants to compute - - ptr_vector pre_cnsts_vec(num); // get constraints in a vector - for (int i = 0; i < num; i++){ - ast *a = to_ast(cnsts[i]); - pre_cnsts_vec[i] = a; - } - - ::vector pre_parents_vec; // get parents in a vector - if (parents){ - pre_parents_vec.resize(num); - for (int i = 0; i < num; i++) - pre_parents_vec[i] = parents[i]; - } - - ptr_vector theory_vec; // get background theory in a vector - if (theory){ - theory_vec.resize(num_theory); - for (int i = 0; i < num_theory; i++) - theory_vec[i] = to_ast(theory[i]); - } - - ptr_vector interpolants(num - 1); // make space for result - - ast_manager &_m = mk_c(ctx)->m(); - iz3interpolate(_m, - to_ast(proof), - pre_cnsts_vec, - pre_parents_vec, - interpolants, - theory_vec, - nullptr); // ignore params for now FIXME - - // copy result back - for (unsigned i = 0; i < interpolants.size(); i++){ - mk_c(ctx)->save_ast_trail(interpolants[i]); - interps[i] = of_ast(interpolants[i]); - _m.dec_ref(interpolants[i]); - } - } - } - - static std::ostringstream itp_err; - - int Z3_check_interpolant(Z3_context ctx, - unsigned num, - Z3_ast *cnsts, - unsigned *parents, - Z3_ast *itp, - Z3_string *error, - unsigned num_theory, - Z3_ast *theory){ - - ast_manager &_m = mk_c(ctx)->m(); - itp_err.clear(); - - // need a solver -- make one here, but how? - params_ref p = params_ref::get_empty(); //FIXME - scoped_ptr sf(mk_smt_solver_factory()); - scoped_ptr sp((*(sf))(_m, p, false, true, false, symbol("AUFLIA"))); - - ptr_vector cnsts_vec(num); // get constraints in a vector - for (unsigned i = 0; i < num; i++){ - ast *a = to_ast(cnsts[i]); - cnsts_vec[i] = a; - } - - ptr_vector itp_vec(num); // get interpolants in a vector - for (unsigned i = 0; i < num - 1; i++){ - ast *a = to_ast(itp[i]); - itp_vec[i] = a; - } - - ::vector parents_vec; // get parents in a vector - if (parents){ - parents_vec.resize(num); - for (unsigned i = 0; i < num; i++) - parents_vec[i] = parents[i]; - } - - ptr_vector theory_vec; // get background theory in a vector - if (theory){ - theory_vec.resize(num_theory); - for (unsigned i = 0; i < num_theory; i++) - theory_vec[i] = to_ast(theory[i]); - } - - bool res = iz3check(_m, - sp.get(), - itp_err, - cnsts_vec, - parents_vec, - itp_vec, - theory_vec); - - *error = res ? nullptr : itp_err.str().c_str(); - return res; - } - - - static std::string Z3_profile_string; - - Z3_string Z3_interpolation_profile(Z3_context ctx){ - std::ostringstream f; - profiling::print(f); - Z3_profile_string = f.str(); - return Z3_profile_string.c_str(); - } - - - Z3_interpolation_options - Z3_mk_interpolation_options(){ - return (Z3_interpolation_options) new interpolation_options_struct; - } - - void - Z3_del_interpolation_options(Z3_interpolation_options opts){ - delete opts; - } - - void - Z3_set_interpolation_option(Z3_interpolation_options opts, - Z3_string name, - Z3_string value){ - opts->map[name] = value; - } - - Z3_ast_vector Z3_API Z3_get_interpolant(Z3_context c, Z3_ast pf, Z3_ast pat, Z3_params p){ - Z3_TRY; - LOG_Z3_get_interpolant(c, pf, pat, p); - RESET_ERROR_CODE(); - - Z3_ast_vector_ref * v = alloc(Z3_ast_vector_ref, *mk_c(c), mk_c(c)->m()); - mk_c(c)->save_object(v); - - ast *_pf = to_ast(pf); - ast *_pat = to_ast(pat); - - ptr_vector interp; - ptr_vector cnsts; // to throw away - - ast_manager &_m = mk_c(c)->m(); - - iz3interpolate(_m, - _pf, - cnsts, - _pat, - interp, - (interpolation_options_struct *)nullptr // ignore params for now - ); - - // copy result back - for (unsigned i = 0; i < interp.size(); i++){ - v->m_ast_vector.push_back(interp[i]); - _m.dec_ref(interp[i]); - } - RETURN_Z3(of_ast_vector(v)); - Z3_CATCH_RETURN(nullptr); - } - - Z3_lbool Z3_API Z3_compute_interpolant(Z3_context c, Z3_ast pat, Z3_params p, Z3_ast_vector *out_interp, Z3_model *model){ - Z3_TRY; - LOG_Z3_compute_interpolant(c, pat, p, out_interp, model); - RESET_ERROR_CODE(); - - - // params_ref &_p = to_params(p)->m_params; - params_ref _p; - _p.set_bool("proof", true); // this is currently useless - - scoped_proof_mode spm(mk_c(c)->m(), PGM_ENABLED); - scoped_ptr sf = mk_smt_solver_factory(); - scoped_ptr m_solver((*sf)(mk_c(c)->m(), _p, true, true, true, ::symbol::null)); - m_solver.get()->updt_params(_p); // why do we have to do this? - - - // some boilerplate stolen from Z3_solver_check - unsigned timeout = p?to_params(p)->m_params.get_uint("timeout", mk_c(c)->get_timeout()):UINT_MAX; - unsigned rlimit = p?to_params(p)->m_params.get_uint("rlimit", mk_c(c)->get_rlimit()):0; - bool use_ctrl_c = p?to_params(p)->m_params.get_bool("ctrl_c", false): false; - cancel_eh eh(mk_c(c)->m().limit()); - api::context::set_interruptable si(*(mk_c(c)), eh); - - ast *_pat = to_ast(pat); - - ptr_vector interp; - ptr_vector cnsts; // to throw away - - ast_manager &_m = mk_c(c)->m(); - - model_ref m; - lbool _status; - - { - scoped_ctrl_c ctrlc(eh, false, use_ctrl_c); - scoped_timer timer(timeout, &eh); - scoped_rlimit _rlimit(mk_c(c)->m().limit(), rlimit); - try { - _status = iz3interpolate(_m, - *(m_solver.get()), - _pat, - cnsts, - interp, - m, - nullptr // ignore params for now - ); - } - catch (z3_exception & ex) { - mk_c(c)->handle_exception(ex); - RETURN_Z3_compute_interpolant Z3_L_UNDEF; - } - } - - for (unsigned i = 0; i < cnsts.size(); i++) - _m.dec_ref(cnsts[i]); - - Z3_lbool status = of_lbool(_status); - - Z3_ast_vector_ref *v = nullptr; - *model = nullptr; - - if (_status == l_false){ - // copy result back - v = alloc(Z3_ast_vector_ref, *mk_c(c), mk_c(c)->m()); - mk_c(c)->save_object(v); - for (unsigned i = 0; i < interp.size(); i++){ - v->m_ast_vector.push_back(interp[i]); - _m.dec_ref(interp[i]); - } - } - else { - model_ref mr; - m_solver.get()->get_model(mr); - if(mr.get()){ - Z3_model_ref *tmp_val = alloc(Z3_model_ref, *mk_c(c)); - tmp_val->m_model = mr.get(); - mk_c(c)->save_object(tmp_val); - *model = of_model(tmp_val); - } - } - - *out_interp = of_ast_vector(v); - - RETURN_Z3_compute_interpolant status; - Z3_CATCH_RETURN(Z3_L_UNDEF); - } - - -}; - - -static void tokenize(const std::string &str, std::vector &tokens){ - for (unsigned i = 0; i < str.size();){ - if (str[i] == ' '){ i++; continue; } - unsigned beg = i; - while (i < str.size() && str[i] != ' ')i++; - if (i > beg) - tokens.push_back(str.substr(beg, i - beg)); - } -} - -static void get_file_params(const char *filename, hash_map ¶ms){ - std::ifstream f(filename); - if (f){ - std::string first_line; - std::getline(f, first_line); - // std::cout << "first line: '" << first_line << "'" << std::endl; - if (first_line.size() >= 2 && first_line[0] == ';' && first_line[1] == '!'){ - std::vector tokens; - tokenize(first_line.substr(2, first_line.size() - 2), tokens); - for (unsigned i = 0; i < tokens.size(); i++){ - std::string &tok = tokens[i]; - size_t eqpos = tok.find('='); - if (eqpos != std::string::npos){ - std::string left = tok.substr(0, eqpos); - std::string right = tok.substr(eqpos + 1, tok.size() - eqpos - 1); - params[left] = right; - } - } - } - f.close(); - } -} - -extern "C" { - -#if 0 - static void iZ3_write_seq(Z3_context ctx, int num, Z3_ast *cnsts, const char *filename, int num_theory, Z3_ast *theory){ - int num_fmlas = num+num_theory; - std::vector fmlas(num_fmlas); - if(num_theory) - std::copy(theory,theory+num_theory,fmlas.begin()); - for(int i = 0; i < num_theory; i++) - fmlas[i] = Z3_mk_implies(ctx,Z3_mk_true(ctx),fmlas[i]); - std::copy(cnsts,cnsts+num,fmlas.begin()+num_theory); - Z3_string smt = Z3_benchmark_to_smtlib_string(ctx,"none","AUFLIA","unknown","",num_fmlas-1,&fmlas[0],fmlas[num_fmlas-1]); - std::ofstream f(filename); - if(num_theory) - f << ";! THEORY=" << num_theory << "\n"; - f << smt; - f.close(); - } - - void Z3_write_interpolation_problem(Z3_context ctx, int num, Z3_ast *cnsts, unsigned *parents, const char *filename, int num_theory, Z3_ast *theory){ - if(!parents){ - iZ3_write_seq(ctx,num,cnsts,filename,num_theory,theory); - return; - } - std::vector tcnsts(num); - hash_map syms; - for(int j = 0; j < num - 1; j++){ - std::ostringstream oss; - oss << "$P" << j; - std::string name = oss.str(); - Z3_symbol s = Z3_mk_string_symbol(ctx, name.c_str()); - Z3_ast symbol = Z3_mk_const(ctx, s, Z3_mk_bool_sort(ctx)); - syms[j] = symbol; - tcnsts[j] = Z3_mk_implies(ctx,cnsts[j],symbol); - } - tcnsts[num-1] = Z3_mk_implies(ctx,cnsts[num-1],Z3_mk_false(ctx)); - for(int j = num-2; j >= 0; j--){ - int parent = parents[j]; - // assert(parent >= 0 && parent < num); - tcnsts[parent] = Z3_mk_implies(ctx,syms[j],tcnsts[parent]); - } - iZ3_write_seq(ctx,num,&tcnsts[0],filename,num_theory,theory); - } -#else - - - static Z3_ast and_vec(Z3_context ctx, svector &c){ - return (c.size() > 1) ? Z3_mk_and(ctx, c.size(), &c[0]) : c[0]; - } - - static Z3_ast parents_vector_to_tree(Z3_context ctx, int num, Z3_ast *cnsts, unsigned *parents){ - Z3_ast res; - if (!parents){ - res = Z3_mk_interpolant(ctx, cnsts[0]); - for (int i = 1; i < num - 1; i++){ - Z3_ast bar[2] = { res, cnsts[i] }; - res = Z3_mk_interpolant(ctx, Z3_mk_and(ctx, 2, bar)); - } - if (num > 1){ - Z3_ast bar[2] = { res, cnsts[num - 1] }; - res = Z3_mk_and(ctx, 2, bar); - } - } - else { - std::vector > chs(num); - for (int i = 0; i < num - 1; i++){ - svector &c = chs[i]; - c.push_back(cnsts[i]); - Z3_ast foo = Z3_mk_interpolant(ctx, and_vec(ctx, c)); - chs[parents[i]].push_back(foo); - } - { - svector &c = chs[num - 1]; - c.push_back(cnsts[num - 1]); - res = and_vec(ctx, c); - } - } - Z3_inc_ref(ctx, res); - return res; - } - - void Z3_write_interpolation_problem(Z3_context ctx, unsigned num, Z3_ast *cnsts, unsigned *parents, const char *filename, unsigned num_theory, Z3_ast *theory){ - std::ofstream f(filename); - if (num > 0){ -#if 0 - // Suggested shorthand: - ptr_vector cnsts_vec; - cnsts_vec.append(num, to_exprs(cnsts)); - cnsts_vec.append(num_theory, to_exprs(theory)); -#endif - ptr_vector cnsts_vec(num); // get constraints in a vector - for (unsigned i = 0; i < num; i++){ - expr *a = to_expr(cnsts[i]); - cnsts_vec[i] = a; - } - for (unsigned i = 0; i < num_theory; i++){ - expr *a = to_expr(theory[i]); - cnsts_vec.push_back(a); - } - Z3_ast tree = parents_vector_to_tree(ctx, num, cnsts, parents); - iz3pp(mk_c(ctx)->m(), cnsts_vec, to_expr(tree), f); - Z3_dec_ref(ctx, tree); - } - f.close(); - -#if 0 - - - if(!parents){ - iZ3_write_seq(ctx,num,cnsts,filename,num_theory,theory); - return; - } - std::vector tcnsts(num); - hash_map syms; - for(int j = 0; j < num - 1; j++){ - std::ostringstream oss; - oss << "$P" << j; - std::string name = oss.str(); - Z3_symbol s = Z3_mk_string_symbol(ctx, name.c_str()); - Z3_ast symbol = Z3_mk_const(ctx, s, Z3_mk_bool_sort(ctx)); - syms[j] = symbol; - tcnsts[j] = Z3_mk_implies(ctx,cnsts[j],symbol); - } - tcnsts[num-1] = Z3_mk_implies(ctx,cnsts[num-1],Z3_mk_false(ctx)); - for(int j = num-2; j >= 0; j--){ - int parent = parents[j]; - // assert(parent >= 0 && parent < num); - tcnsts[parent] = Z3_mk_implies(ctx,syms[j],tcnsts[parent]); - } - iZ3_write_seq(ctx,num,&tcnsts[0],filename,num_theory,theory); -#endif - - } - - -#endif - - static std::vector read_cnsts; - static std::vector read_parents; - static std::ostringstream read_error; - static std::string read_msg; - static std::vector read_theory; - - static Z3_ast_vector iZ3_parse(Z3_context ctx, const char *filename, const char ** error){ - return nullptr; -#if 0 - read_error.clear(); - try { - Z3_ast assrts = Z3_parse_smtlib2_file(ctx, filename, 0, nullptr, nullptr, 0, nullptr, nullptr); - Z3_app app = Z3_to_app(ctx, assrts); - int nconjs = Z3_get_app_num_args(ctx, app); - assertions.resize(nconjs); - for (int k = 0; k < nconjs; k++) - assertions[k] = Z3_get_app_arg(ctx, app, k); - } - catch (...) { - read_error << "SMTLIB parse error: " << Z3_get_parser_error(ctx); - read_msg = read_error.str(); - *error = read_msg.c_str(); - return nullptr; - } - Z3_set_error_handler(ctx, nullptr); - return nullptr; -#endif - } - - - int Z3_read_interpolation_problem(Z3_context ctx, Z3_ast_vector cnsts, unsigned* _num, unsigned* parents[], const char *filename, Z3_string_ptr error, Z3_ast_vector theory){ - - hash_map file_params; - get_file_params(filename, file_params); - - unsigned num_theory = 0; - if (file_params.find("THEORY") != file_params.end()) { - num_theory = atoi(file_params["THEORY"].c_str()); - } - - Z3_ast_vector assertions = iZ3_parse(ctx, filename, error); - if (assertions == 0) - return false; - - if (num_theory > Z3_ast_vector_size(ctx, assertions)) - num_theory = Z3_ast_vector_size(ctx, assertions); - unsigned num = Z3_ast_vector_size(ctx, assertions) - num_theory; - - read_parents.resize(num); - - for (unsigned j = 0; theory && j < num_theory; j++) - Z3_ast_vector_push(ctx, theory, Z3_ast_vector_get(ctx, assertions, j)); - - for (unsigned j = 0; j < num; j++) - Z3_ast_vector_push(ctx, cnsts, Z3_ast_vector_get(ctx, assertions, j + num_theory)); - - if (!parents){ - Z3_ast_vector_dec_ref(ctx, assertions); - return true; - } - - for (unsigned j = 0; j < num; j++) - read_parents[j] = SHRT_MAX; - - hash_map pred_map; - - for (unsigned j = 0; j < num; j++){ - Z3_ast lhs = nullptr, rhs = Z3_ast_vector_get(ctx, cnsts, j); - - if (Z3_get_decl_kind(ctx, Z3_get_app_decl(ctx, Z3_to_app(ctx, rhs))) == Z3_OP_IMPLIES){ - Z3_app app1 = Z3_to_app(ctx, rhs); - Z3_ast lhs1 = Z3_get_app_arg(ctx, app1, 0); - Z3_ast rhs1 = Z3_get_app_arg(ctx, app1, 1); - if (Z3_get_decl_kind(ctx, Z3_get_app_decl(ctx, Z3_to_app(ctx, lhs1))) == Z3_OP_AND){ - Z3_app app2 = Z3_to_app(ctx, lhs1); - int nconjs = Z3_get_app_num_args(ctx, app2); - for (int k = nconjs - 1; k >= 0; --k) - rhs1 = Z3_mk_implies(ctx, Z3_get_app_arg(ctx, app2, k), rhs1); - rhs = rhs1; - } - } - - while (1){ - Z3_app app = Z3_to_app(ctx, rhs); - Z3_func_decl func = Z3_get_app_decl(ctx, app); - Z3_decl_kind dk = Z3_get_decl_kind(ctx, func); - if (dk == Z3_OP_IMPLIES){ - if (lhs){ - Z3_ast child = lhs; - if (pred_map.find(child) == pred_map.end()){ - read_error << "formula " << j + 1 << ": unknown: " << Z3_ast_to_string(ctx, child); - goto fail; - } - int child_num = pred_map[child]; - if (read_parents[child_num] != SHRT_MAX){ - read_error << "formula " << j + 1 << ": multiple reference: " << Z3_ast_to_string(ctx, child); - goto fail; - } - read_parents[child_num] = j; - } - lhs = Z3_get_app_arg(ctx, app, 0); - rhs = Z3_get_app_arg(ctx, app, 1); - } - else { - if (!lhs){ - read_error << "formula " << j + 1 << ": should be (implies {children} fmla parent)"; - goto fail; - } - Z3_ast_vector_set(ctx, cnsts, j, lhs); - Z3_ast name = rhs; - if (pred_map.find(name) != pred_map.end()){ - read_error << "formula " << j + 1 << ": duplicate symbol"; - goto fail; - } - pred_map[name] = j; - break; - } - } - } - - for (unsigned j = 0; j < num - 1; j++) - if (read_parents[j] == SHRT_MAX){ - read_error << "formula " << j + 1 << ": unreferenced"; - goto fail; - } - - *_num = num; - *parents = &read_parents[0]; - Z3_ast_vector_dec_ref(ctx, assertions); - return true; - - fail: - Z3_ast_vector_dec_ref(ctx, assertions); - read_msg = read_error.str(); - *error = read_msg.c_str(); - return false; - - } -} - - -#if 0 -/** Constant reprepresenting a root of a formula tree for tree interpolation */ -#define IZ3_ROOT SHRT_MAX - -/** This function uses Z3 to determine satisfiability of a set of - constraints. If UNSAT, an interpolant is returned, based on the - refutation generated by Z3. If SAT, a model is returned. - - If "parents" is non-null, computes a tree interpolant. The tree is - defined by the array "parents". This array maps each formula in - the tree to its parent, where formulas are indicated by their - integer index in "cnsts". The parent of formula n must have index - greater than n. The last formula is the root of the tree. Its - parent entry should be the constant IZ3_ROOT. - - If "parents" is null, computes a sequence interpolant. - - \param ctx The Z3 context. Must be generated by iz3_mk_context - \param num The number of constraints in the sequence - \param cnsts Array of constraints (AST's in context ctx) - \param parents The parents vector defining the tree structure - \param options Interpolation options (may be NULL) - \param interps Array to return interpolants (size at least num-1, may be NULL) - \param model Returns a Z3 model if constraints SAT (may be NULL) - \param labels Returns relevant labels if SAT (may be NULL) - \param incremental - - VERY IMPORTANT: All the Z3 formulas in cnsts must be in Z3 - context ctx. The model and interpolants returned are also - in this context. - - The return code is as in Z3_check_assumptions, that is, - - Z3_L_FALSE = constraints UNSAT (interpolants returned) - Z3_L_TRUE = constraints SAT (model returned) - Z3_L_UNDEF = Z3 produced no result, or interpolation not possible - - Currently, this function supports integer and boolean variables, - as well as arrays over these types, with linear arithmetic, - uninterpreted functions and quantifiers over integers (that is - AUFLIA). Interpolants are produced in AULIA. However, some - uses of array operations may cause quantifiers to appear in the - interpolants even when there are no quantifiers in the input formulas. - Although quantifiers may appear in the input formulas, Z3 may give up in - this case, returning Z3_L_UNDEF. - - If "incremental" is true, cnsts must contain exactly the set of - formulas that are currently asserted in the context. If false, - there must be no formulas currently asserted in the context. - Setting "incremental" to true makes it posisble to incrementally - add and remove constraints from the context until the context - becomes UNSAT, at which point an interpolant is computed. Caution - must be used, however. Before popping the context, if you wish to - keep the interolant formulas, you *must* preserve them by using - Z3_persist_ast. Also, if you want to simplify the interpolant - formulas using Z3_simplify, you must first pop all of the - assertions in the context (or use a different context). Otherwise, - the formulas will be simplified *relative* to these constraints, - which is almost certainly not what you want. - - - Current limitations on tree interpolants. In a tree interpolation - problem, each constant (0-ary function symbol) must occur only - along one path from root to leaf. Function symbols (of arity > 0) - are considered to have global scope (i.e., may appear in any - interpolant formula). - - def_API('Z3_interpolate', BOOL, (_in(CONTEXT), _in(UINT), _in_array(1, AST), _in_array(1, UINT), _in(PARAMS), _out_array(1, AST), _out(MODEL), _out(LITERALS), _in(UINT), _in(UINT), _in_array(9, AST))) -*/ - -Z3_lbool Z3_API Z3_interpolate(Z3_context ctx, - unsigned num, - Z3_ast *cnsts, - unsigned *parents, - Z3_params options, - Z3_ast *interps, - Z3_model *model, - Z3_literals *labels, - unsigned incremental, - unsigned num_theory, - Z3_ast *theory); -#endif From 727ba13566932a5f531241c4f33a4e1bade0080a Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 25 May 2018 12:55:04 -0700 Subject: [PATCH 631/637] fix #1653 Signed-off-by: Nikolaj Bjorner --- src/opt/opt_context.cpp | 21 +++++++++++++++------ src/opt/opt_context.h | 3 ++- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 52048386d..8fc74ec83 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -128,6 +128,7 @@ namespace opt { m_optsmt(m), m_scoped_state(m), m_fm(alloc(generic_model_converter, m, "opt")), + m_model_fixed(false), m_objective_refs(m), m_enable_sat(false), m_is_clausal(false), @@ -339,15 +340,17 @@ namespace opt { } void context::fix_model(model_ref& mdl) { - if (mdl) { + if (mdl && !m_model_fixed) { (*m_fm)(mdl); apply(m_model_converter, mdl); + m_model_fixed = true; } } void context::get_model_core(model_ref& mdl) { mdl = m_model; fix_model(mdl); + TRACE("opt", model_smt2_pp(tout, m, *mdl.get(), 0);); } void context::get_box_model(model_ref& mdl, unsigned index) { @@ -441,11 +444,13 @@ namespace opt { lbool context::execute_box() { if (m_box_index < m_box_models.size()) { m_model = m_box_models[m_box_index]; + m_model_fixed = false; ++m_box_index; return l_true; } if (m_box_index < m_objectives.size()) { m_model = nullptr; + m_model_fixed = false; ++m_box_index; return l_undef; } @@ -470,6 +475,7 @@ namespace opt { } if (r == l_true && m_box_models.size() > 0) { m_model = m_box_models[0]; + m_model_fixed = false; } return r; } @@ -557,8 +563,10 @@ namespace opt { void context::yield() { SASSERT (m_pareto); m_pareto->get_model(m_model, m_labels); + m_model_fixed = false; update_bound(true); update_bound(false); + TRACE("opt", model_smt2_pp(tout, m, *m_model.get(), 0);); } lbool context::execute_pareto() { @@ -1191,7 +1199,7 @@ namespace opt { rational r; switch(obj.m_type) { case O_MINIMIZE: { - bool evaluated = m_model->eval(obj.m_term, val); + bool evaluated = m_model->eval(obj.m_term, val, true); TRACE("opt", tout << obj.m_term << " " << val << " " << evaluated << " " << is_numeral(val, r) << "\n";); if (evaluated && is_numeral(val, r)) { inf_eps val = inf_eps(obj.m_adjust_value(r)); @@ -1206,7 +1214,7 @@ namespace opt { break; } case O_MAXIMIZE: { - bool evaluated = m_model->eval(obj.m_term, val); + bool evaluated = m_model->eval(obj.m_term, val, true); TRACE("opt", tout << obj.m_term << " " << val << "\n";); if (evaluated && is_numeral(val, r)) { inf_eps val = inf_eps(obj.m_adjust_value(r)); @@ -1223,7 +1231,7 @@ namespace opt { case O_MAXSMT: { bool ok = true; for (unsigned j = 0; ok && j < obj.m_terms.size(); ++j) { - bool evaluated = m_model->eval(obj.m_terms[j], val); + bool evaluated = m_model->eval(obj.m_terms[j], val, true); TRACE("opt", tout << mk_pp(obj.m_terms[j], m) << " " << val << "\n";); if (evaluated) { if (!m.is_true(val)) { @@ -1238,11 +1246,11 @@ namespace opt { maxsmt& ms = *m_maxsmts.find(obj.m_id); if (is_lower) { ms.update_upper(r); - TRACE("opt", tout << r << " " << ms.get_upper() << "\n";); + TRACE("opt", tout << "update upper from " << r << " to " << ms.get_upper() << "\n";); } else { ms.update_lower(r); - TRACE("opt", tout << r << " " << ms.get_lower() << "\n";); + TRACE("opt", tout << "update lower from " << r << " to " << ms.get_lower() << "\n";); } } break; @@ -1402,6 +1410,7 @@ namespace opt { m_pareto = nullptr; m_box_index = UINT_MAX; m_model.reset(); + m_model_fixed = false; } void context::set_pareto(pareto_base* p) { diff --git a/src/opt/opt_context.h b/src/opt/opt_context.h index b642f1d7a..51ea6cc71 100644 --- a/src/opt/opt_context.h +++ b/src/opt/opt_context.h @@ -156,9 +156,10 @@ namespace opt { map_t m_maxsmts; scoped_state m_scoped_state; vector m_objectives; - model_ref m_model; + model_ref m_model; model_converter_ref m_model_converter; generic_model_converter_ref m_fm; + bool m_model_fixed; unsigned m_model_counter; obj_map m_objective_fns; obj_map m_objective_orig; From da0239d20026051cdf952725101e9639e6152e35 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 25 May 2018 21:21:27 -0700 Subject: [PATCH 632/637] fix #1655 Signed-off-by: Nikolaj Bjorner --- src/opt/opt_context.cpp | 12 ++++-------- src/opt/opt_context.h | 2 +- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/src/opt/opt_context.cpp b/src/opt/opt_context.cpp index 8fc74ec83..2850dd59c 100644 --- a/src/opt/opt_context.cpp +++ b/src/opt/opt_context.cpp @@ -128,7 +128,7 @@ namespace opt { m_optsmt(m), m_scoped_state(m), m_fm(alloc(generic_model_converter, m, "opt")), - m_model_fixed(false), + m_model_fixed(), m_objective_refs(m), m_enable_sat(false), m_is_clausal(false), @@ -340,10 +340,10 @@ namespace opt { } void context::fix_model(model_ref& mdl) { - if (mdl && !m_model_fixed) { + if (mdl && !m_model_fixed.contains(mdl.get())) { (*m_fm)(mdl); apply(m_model_converter, mdl); - m_model_fixed = true; + m_model_fixed.push_back(mdl.get()); } } @@ -444,13 +444,11 @@ namespace opt { lbool context::execute_box() { if (m_box_index < m_box_models.size()) { m_model = m_box_models[m_box_index]; - m_model_fixed = false; ++m_box_index; return l_true; } if (m_box_index < m_objectives.size()) { m_model = nullptr; - m_model_fixed = false; ++m_box_index; return l_undef; } @@ -475,7 +473,6 @@ namespace opt { } if (r == l_true && m_box_models.size() > 0) { m_model = m_box_models[0]; - m_model_fixed = false; } return r; } @@ -563,7 +560,6 @@ namespace opt { void context::yield() { SASSERT (m_pareto); m_pareto->get_model(m_model, m_labels); - m_model_fixed = false; update_bound(true); update_bound(false); TRACE("opt", model_smt2_pp(tout, m, *m_model.get(), 0);); @@ -1410,7 +1406,7 @@ namespace opt { m_pareto = nullptr; m_box_index = UINT_MAX; m_model.reset(); - m_model_fixed = false; + m_model_fixed.reset(); } void context::set_pareto(pareto_base* p) { diff --git a/src/opt/opt_context.h b/src/opt/opt_context.h index 51ea6cc71..29b327855 100644 --- a/src/opt/opt_context.h +++ b/src/opt/opt_context.h @@ -159,7 +159,7 @@ namespace opt { model_ref m_model; model_converter_ref m_model_converter; generic_model_converter_ref m_fm; - bool m_model_fixed; + sref_vector m_model_fixed; unsigned m_model_counter; obj_map m_objective_fns; obj_map m_objective_orig; From 6dc9c3a5870e55a93ae2a923a8e514ac176e4435 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 29 May 2018 07:37:27 -0700 Subject: [PATCH 633/637] fix ml build breakd #1659, #1660 Signed-off-by: Nikolaj Bjorner --- src/api/ml/z3.ml | 47 ------------------------------------------ src/api/ml/z3.mli | 52 +---------------------------------------------- 2 files changed, 1 insertion(+), 98 deletions(-) diff --git a/src/api/ml/z3.ml b/src/api/ml/z3.ml index 5766c79f9..a676f8c43 100644 --- a/src/api/ml/z3.ml +++ b/src/api/ml/z3.ml @@ -1654,7 +1654,6 @@ struct mk_list f n let get_subgoal (x:apply_result) (i:int) = Z3native.apply_result_get_subgoal (gc x) x i - let convert_model (x:apply_result) (i:int) (m:Model.model) = Z3native.apply_result_convert_model (gc x) x i m let to_string (x:apply_result) = Z3native.apply_result_to_string (gc x) x end @@ -1995,52 +1994,6 @@ struct cs sort_names sorts cd decl_names decls end -module Interpolation = -struct - let mk_interpolant = Z3native.mk_interpolant - - let mk_interpolation_context (settings:(string * string) list) = - let cfg = Z3native.mk_config () in - let f e = Z3native.set_param_value cfg (fst e) (snd e) in - List.iter f settings; - let res = Z3native.mk_interpolation_context cfg in - Z3native.del_config cfg; - Z3native.set_ast_print_mode res (int_of_ast_print_mode PRINT_SMTLIB2_COMPLIANT); - Z3native.set_internal_error_handler res; - res - - let get_interpolant (ctx:context) (pf:expr) (pat:expr) (p:Params.params) = - let av = Z3native.get_interpolant ctx pf pat p in - AST.ASTVector.to_expr_list av - - let compute_interpolant (ctx:context) (pat:expr) (p:Params.params) = - let (r, interp, model) = Z3native.compute_interpolant ctx pat p in - let res = lbool_of_int r in - match res with - | L_TRUE -> (res, None, Some model) - | L_FALSE -> (res, Some (AST.ASTVector.to_expr_list interp), None) - | _ -> (res, None, None) - - let get_interpolation_profile = Z3native.interpolation_profile - - let read_interpolation_problem (ctx:context) (filename:string) = - let (r, num, cnsts, parents, error, num_theory, theory) = - Z3native.read_interpolation_problem ctx filename - in - match r with - | 0 -> raise (Error "Interpolation problem could not be read.") - | _ -> (cnsts, parents, theory) - - let check_interpolant (ctx:context) (num:int) (cnsts:Expr.expr list) (parents:int list) (interps:Expr.expr list) (num_theory:int) (theory:Expr.expr list) = - let (r, str) = Z3native.check_interpolant ctx num cnsts parents interps num_theory theory in - match (lbool_of_int r) with - | L_UNDEF -> raise (Error "Interpolant could not be verified.") - | L_FALSE -> raise (Error "Interpolant could not be verified.") - | _ -> () - - let write_interpolation_problem (ctx:context) (num:int) (cnsts:Expr.expr list) (parents:int list) (filename:string) (num_theory:int) (theory:Expr.expr list) = - Z3native.write_interpolation_problem ctx num cnsts parents filename num_theory theory -end let set_global_param = Z3native.global_param_set diff --git a/src/api/ml/z3.mli b/src/api/ml/z3.mli index 0fd1242ee..9b424b508 100644 --- a/src/api/ml/z3.mli +++ b/src/api/ml/z3.mli @@ -2447,7 +2447,7 @@ sig The antecedents are proofs for equalities used as substitution rules. The object is also used in a few cases. The cases are: - When applying contextual simplification (CONTEXT_SIMPLIFIER=true) - - When converting bit-vectors to Booleans (BIT2BOOL=true) + - When converting bit-vectors to Booleans (BIT2BOOL=true) *) val is_rewrite_star : Expr.expr -> bool (** Indicates whether the term is a proof for pulling quantifiers out. @@ -2964,11 +2964,6 @@ sig (** Retrieves a subgoal from the apply_result. *) val get_subgoal : apply_result -> int -> Goal.goal - (** Convert a model for a subgoal into a model for the original - goal [g], that the ApplyResult was obtained from. - #return A model for [g] *) - val convert_model : apply_result -> int -> Model.model -> Model.model - (** A string representation of the ApplyResult. *) val to_string : apply_result -> string end @@ -3424,51 +3419,6 @@ sig val parse_smtlib2_file : context -> string -> Symbol.symbol list -> Sort.sort list -> Symbol.symbol list -> FuncDecl.func_decl list -> Expr.expr end -(** Interpolation *) -module Interpolation : -sig - - (** Create an AST node marking a formula position for interpolation. - The expression must have Boolean sort. *) - val mk_interpolant : context -> Expr.expr -> Expr.expr - - (** The interpolation context is suitable for generation of interpolants. - For more information on interpolation please refer - too the C/C++ API, which is well documented. *) - val mk_interpolation_context : (string * string) list -> context - - (** Gets an interpolant. - For more information on interpolation please refer - too the C/C++ API, which is well documented. *) - val get_interpolant : context -> Expr.expr -> Expr.expr -> Params.params -> Expr.expr list - - (** Computes an interpolant. - For more information on interpolation please refer - too the C/C++ API, which is well documented. *) - val compute_interpolant : context -> Expr.expr -> Params.params -> (Z3enums.lbool * Expr.expr list option * Model.model option) - - (** Retrieves an interpolation profile. - For more information on interpolation please refer - too the C/C++ API, which is well documented. *) - val get_interpolation_profile : context -> string - - (** Read an interpolation problem from file. - For more information on interpolation please refer - too the C/C++ API, which is well documented. *) - val read_interpolation_problem : context -> string -> (Expr.expr list * int list * Expr.expr list) - - (** Check the correctness of an interpolant. - For more information on interpolation please refer - too the C/C++ API, which is well documented. *) - val check_interpolant : context -> int -> Expr.expr list -> int list -> Expr.expr list -> int -> Expr.expr list -> unit - - (** Write an interpolation problem to file suitable for reading with - Z3_read_interpolation_problem. - For more information on interpolation please refer - too the C/C++ API, which is well documented. *) - val write_interpolation_problem : context -> int -> Expr.expr list -> int list -> string -> int -> Expr.expr list -> unit - -end (** Set a global (or module) parameter, which is shared by all Z3 contexts. From db3f439e88c5696011da8beb3f7c363b686182aa Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Tue, 29 May 2018 20:55:30 -0700 Subject: [PATCH 634/637] fix memory leak from Arie Signed-off-by: Nikolaj Bjorner --- src/smt/asserted_formulas.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/smt/asserted_formulas.cpp b/src/smt/asserted_formulas.cpp index 605c447bd..c00fb93b1 100644 --- a/src/smt/asserted_formulas.cpp +++ b/src/smt/asserted_formulas.cpp @@ -500,6 +500,7 @@ unsigned asserted_formulas::propagate_values(unsigned i) { void asserted_formulas::update_substitution(expr* n, proof* pr) { expr* lhs, *rhs, *n1; + proof_ref pr1(m); if (is_ground(n) && (m.is_eq(n, lhs, rhs) || m.is_iff(n, lhs, rhs))) { compute_depth(lhs); compute_depth(rhs); @@ -510,12 +511,12 @@ void asserted_formulas::update_substitution(expr* n, proof* pr) { } if (is_gt(rhs, lhs)) { TRACE("propagate_values", tout << "insert " << mk_pp(rhs, m) << " -> " << mk_pp(lhs, m) << "\n";); - m_scoped_substitution.insert(rhs, lhs, m.proofs_enabled() ? m.mk_symmetry(pr) : nullptr); + pr1 = m.proofs_enabled() ? m.mk_symmetry(pr) : nullptr; + m_scoped_substitution.insert(rhs, lhs, pr1); return; } TRACE("propagate_values", tout << "incompatible " << mk_pp(n, m) << "\n";); } - proof_ref pr1(m); if (m.is_not(n, n1)) { pr1 = m.proofs_enabled() ? m.mk_iff_false(pr) : nullptr; m_scoped_substitution.insert(n1, m.mk_false(), pr1); From 0d668e14289c0728b65bbcc214749ac865297507 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 30 May 2018 03:18:22 -0700 Subject: [PATCH 635/637] fix #1661 Signed-off-by: Nikolaj Bjorner --- src/ast/rewriter/pb2bv_rewriter.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ast/rewriter/pb2bv_rewriter.cpp b/src/ast/rewriter/pb2bv_rewriter.cpp index e4a34fc93..3862aecae 100644 --- a/src/ast/rewriter/pb2bv_rewriter.cpp +++ b/src/ast/rewriter/pb2bv_rewriter.cpp @@ -357,8 +357,8 @@ struct pb2bv_rewriter::imp { /** \brief MiniSat+ based encoding of PB constraints. - The procedure is described in "Translating Pseudo-Boolean Constraints into SAT " -         Niklas Een, Niklas Sörensson, JSAT 2006. + Translating Pseudo-Boolean Constraints into SAT, + Niklas Een, Niklas Soerensson, JSAT 2006. */ From b9637924c44bf47b06643b728044bd48d2927e26 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Wed, 30 May 2018 16:47:17 -0700 Subject: [PATCH 636/637] fix #1662 Signed-off-by: Nikolaj Bjorner --- src/qe/qe_lite.cpp | 42 +++++++++++++++++++----------------------- src/qe/qe_lite.h | 1 - src/smt/theory_str.cpp | 6 ++++-- 3 files changed, 23 insertions(+), 26 deletions(-) diff --git a/src/qe/qe_lite.cpp b/src/qe/qe_lite.cpp index ae969a99e..6ecdfd835 100644 --- a/src/qe/qe_lite.cpp +++ b/src/qe/qe_lite.cpp @@ -89,7 +89,7 @@ namespace eq { var * v = vars[i]; expr * t = definitions[i]; if (t == nullptr || has_quantifiers(t) || occurs_var(v->get_idx(), t)) - definitions[i] = 0; + definitions[i] = nullptr; else found = true; // found at least one candidate } @@ -106,7 +106,7 @@ namespace eq { unsigned vidx, num; for (unsigned i = 0; i < definitions.size(); i++) { - if (definitions[i] == 0) + if (definitions[i] == nullptr) continue; var * v = vars[i]; SASSERT(v->get_idx() == i); @@ -116,7 +116,7 @@ namespace eq { start: frame & fr = todo.back(); expr * t = fr.first; - if (t->get_ref_count() > 1 && done.is_marked(t)) { + if (done.is_marked(t)) { todo.pop_back(); continue; } @@ -126,11 +126,11 @@ namespace eq { if (fr.second == 0) { CTRACE("der_bug", vidx >= definitions.size(), tout << "vidx: " << vidx << "\n";); // Remark: The size of definitions may be smaller than the number of variables occurring in the quantified formula. - if (definitions.get(vidx, 0) != 0) { + if (definitions.get(vidx, nullptr) != nullptr) { if (visiting.is_marked(t)) { // cycle detected: remove t visiting.reset_mark(t); - definitions[vidx] = 0; + definitions[vidx] = nullptr; } else { visiting.mark(t); @@ -142,17 +142,14 @@ namespace eq { } else { SASSERT(fr.second == 1); - if (definitions.get(vidx, 0) != 0) { - visiting.reset_mark(t); - order.push_back(vidx); - } - else { - // var was removed from the list of candidate vars to elim cycle - // do nothing + visiting.reset_mark(t); + if (!done.is_marked(t)) { + if (definitions.get(vidx, nullptr) != nullptr) + order.push_back(vidx); + done.mark(t); } } - if (t->get_ref_count() > 1) - done.mark(t); + done.mark(t); todo.pop_back(); break; case AST_QUANTIFIER: @@ -164,13 +161,11 @@ namespace eq { while (fr.second < num) { expr * arg = to_app(t)->get_arg(fr.second); fr.second++; - if (arg->get_ref_count() > 1 && done.is_marked(arg)) - continue; + if (done.is_marked(arg)) continue; todo.push_back(frame(arg, 0)); goto start; } - if (t->get_ref_count() > 1) - done.mark(t); + done.mark(t); todo.pop_back(); break; default: @@ -574,12 +569,15 @@ namespace eq { checkpoint(); ptr_vector vs; expr_ref_vector ts(m); + expr_ref t(m); if (is_var_def(is_exists, args[i], vs, ts)) { for (unsigned j = 0; j < vs.size(); ++j) { var* v = vs[j]; - expr* t = ts[j].get(); + t = ts.get(j); + m_rewriter(t); + if (t != ts.get(j)) m_new_exprs.push_back(t); unsigned idx = v->get_idx(); - if (m_map.get(idx, 0) == 0) { + if (m_map.get(idx, nullptr) == nullptr) { m_map.reserve(idx + 1, 0); m_inx2var.reserve(idx + 1, 0); m_map[idx] = t; @@ -2461,9 +2459,7 @@ public: fmls[index] = fml; return; } - TRACE("qe_lite", for (unsigned i = 0; i < fmls.size(); ++i) { - tout << mk_pp(fmls[i].get(), m) << "\n"; - }); + TRACE("qe_lite", tout << fmls << "\n";); is_variable_test is_var(index_set, index_of_bound); m_der.set_is_variable_proc(is_var); m_fm.set_is_variable_proc(is_var); diff --git a/src/qe/qe_lite.h b/src/qe/qe_lite.h index 4fc5572a2..63ad8bedd 100644 --- a/src/qe/qe_lite.h +++ b/src/qe/qe_lite.h @@ -57,7 +57,6 @@ public: void operator()(uint_set const& index_set, bool index_of_bound, expr_ref& fml); void operator()(uint_set const& index_set, bool index_of_bound, expr_ref_vector& conjs); - /** \brief full rewriting based light-weight quantifier elimination round. */ diff --git a/src/smt/theory_str.cpp b/src/smt/theory_str.cpp index dde75c4bc..0ef008927 100644 --- a/src/smt/theory_str.cpp +++ b/src/smt/theory_str.cpp @@ -6645,7 +6645,8 @@ namespace smt { expr * sub1; expr * sub2; if (u.re.is_to_re(re, sub1)) { - SASSERT(u.str.is_string(sub1)); + if (!u.str.is_string(sub1)) + throw default_exception("regular expressions must be built from string literals"); zstring str; u.str.is_string(sub1, str); return str.length(); @@ -6842,7 +6843,8 @@ namespace smt { expr * sub1; expr * sub2; if (u.re.is_to_re(re, sub1)) { - SASSERT(u.str.is_string(sub1)); + if (!u.str.is_string(sub1)) + throw default_exception("regular expressions must be built from string literals"); zstring str; u.str.is_string(sub1, str); rational strlen(str.length()); From fee4f91e2d598270f16cbfd68e9728dd8368d837 Mon Sep 17 00:00:00 2001 From: Nikolaj Bjorner Date: Fri, 1 Jun 2018 08:07:06 -0700 Subject: [PATCH 637/637] add set operations to python request by Francois Signed-off-by: Nikolaj Bjorner --- src/api/python/z3/z3.py | 113 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 113 insertions(+) diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index 784228120..7657fb347 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -2765,6 +2765,8 @@ def _py2expr(a, ctx=None): return IntVal(a, ctx) if isinstance(a, float): return RealVal(a, ctx) + if is_expr(a): + return a if __debug__: _z3_assert(False, "Python bool, int, long or float expected") @@ -4399,6 +4401,117 @@ def is_store(a): """ return is_app_of(a, Z3_OP_STORE) +######################################### +# +# Sets +# +######################################### + + +def SetSort(s): + """ Create a set sort over element sort s""" + return ArraySort(s, BoolSort()) + +def EmptySet(s): + """Create the empty set + >>> EmptySet(IntSort()) + K(Int, False) + """ + ctx = s.ctx + return ArrayRef(Z3_mk_empty_set(ctx.ref(), s.ast), ctx) + +def FullSet(s): + """Create the full set + >>> FullSet(IntSort()) + K(Int, True) + """ + ctx = s.ctx + return ArrayRef(Z3_mk_full_set(ctx.ref(), s.ast), ctx) + +def SetUnion(*args): + """ Take the union of sets + >>> a = Const('a', SetSort(IntSort())) + >>> b = Const('b', SetSort(IntSort())) + >>> SetUnion(a, b) + union(a, b) + """ + args = _get_args(args) + ctx = _ctx_from_ast_arg_list(args) + _args, sz = _to_ast_array(args) + return ArrayRef(Z3_mk_set_union(ctx.ref(), sz, _args), ctx) + +def SetIntersect(*args): + """ Take the union of sets + >>> a = Const('a', SetSort(IntSort())) + >>> b = Const('b', SetSort(IntSort())) + >>> SetIntersect(a, b) + intersect(a, b) + """ + args = _get_args(args) + ctx = _ctx_from_ast_arg_list(args) + _args, sz = _to_ast_array(args) + return ArrayRef(Z3_mk_set_intersect(ctx.ref(), sz, _args), ctx) + +def SetAdd(s, e): + """ Add element e to set s + >>> a = Const('a', SetSort(IntSort())) + >>> SetAdd(a, 1) + Store(a, 1, True) + """ + ctx = _ctx_from_ast_arg_list([s,e]) + e = _py2expr(e, ctx) + return ArrayRef(Z3_mk_set_add(ctx.ref(), s.as_ast(), e.as_ast()), ctx) + +def SetDel(s, e): + """ Remove element e to set s + >>> a = Const('a', SetSort(IntSort())) + >>> SetDel(a, 1) + Store(a, 1, False) + """ + ctx = _ctx_from_ast_arg_list([s,e]) + e = _py2expr(e, ctx) + return ArrayRef(Z3_mk_set_del(ctx.ref(), s.as_ast(), e.as_ast()), ctx) + +def SetComplement(s): + """ The complement of set s + >>> a = Const('a', SetSort(IntSort())) + >>> SetComplement(a) + complement(a) + """ + ctx = s.ctx + return ArrayRef(Z3_mk_set_complement(ctx.ref(), s.as_ast()), ctx) + +def SetDifference(a, b): + """ The set difference of a and b + >>> a = Const('a', SetSort(IntSort())) + >>> b = Const('b', SetSort(IntSort())) + >>> SetDifference(a, b) + difference(a, b) + """ + ctx = _ctx_from_ast_arg_list([a, b]) + return ArrayRef(Z3_mk_set_difference(ctx.ref(), a.as_ast(), b.as_ast()), ctx) + +def IsMember(e, s): + """ Check if e is a member of set s + >>> a = Const('a', SetSort(IntSort())) + >>> IsMember(1, a) + a[1] + """ + ctx = _ctx_from_ast_arg_list([s,e]) + e = _py2expr(e, ctx) + return BoolRef(Z3_mk_set_member(ctx.ref(), e.as_ast(), s.as_ast()), ctx) + +def IsSubset(a, b): + """ Check if a is a subset of b + >>> a = Const('a', SetSort(IntSort())) + >>> b = Const('b', SetSort(IntSort())) + >>> IsSubset(a, b) + subset(a, b) + """ + ctx = _ctx_from_ast_arg_list([a, b]) + return BoolRef(Z3_mk_set_subset(ctx.ref(), a.as_ast(), b.as_ast()), ctx) + + ######################################### # # Datatypes