diff --git a/src/smt/smt_conflict_resolution.cpp b/src/smt/smt_conflict_resolution.cpp index 818e12fd1..3aa02c0b6 100644 --- a/src/smt/smt_conflict_resolution.cpp +++ b/src/smt/smt_conflict_resolution.cpp @@ -288,11 +288,13 @@ namespace smt { } void conflict_resolution::process_antecedent(literal antecedent, unsigned & num_marks) { - TRACE("conflict", tout << "processing antecedent: "; m_ctx.display_literal(tout, antecedent); tout << "\n";); bool_var var = antecedent.var(); unsigned lvl = m_ctx.get_assign_level(var); SASSERT(var < static_cast(m_ctx.get_num_bool_vars())); - + TRACE("conflict", tout << "processing antecedent (level " << lvl << "):"; + m_ctx.display_literal(tout, antecedent); + m_ctx.display_detailed_literal(tout << " ", antecedent); tout << "\n";); + if (!m_ctx.is_marked(var) && lvl > m_ctx.get_base_level()) { m_ctx.set_mark(var); m_ctx.inc_bvar_activity(var); diff --git a/src/smt/smt_context.cpp b/src/smt/smt_context.cpp index 43757b432..6b3316809 100644 --- a/src/smt/smt_context.cpp +++ b/src/smt/smt_context.cpp @@ -172,7 +172,9 @@ namespace smt { } void context::assign_core(literal l, b_justification j, bool decision) { - TRACE("assign_core", tout << "assigning: " << l << " "; display_literal(tout, l); tout << "\n";); + TRACE("assign_core", tout << (decision?"decision: ":"propagating: ") << l << " "; + display_literal(tout, l); tout << " level: " << m_scope_lvl << "\n"; + display(tout, j);); SASSERT(l.var() < static_cast(m_b_internalized_stack.size())); m_assigned_literals.push_back(l); m_assignment[l.index()] = l_true; @@ -1609,7 +1611,7 @@ namespace smt { } bool context::propagate() { - TRACE("propagate", tout << "propagating...\n";); + TRACE("propagate", tout << "propagating... " << m_qhead << ":" << m_assigned_literals.size() << "\n";); while (true) { if (inconsistent()) return false; diff --git a/src/smt/smt_context.h b/src/smt/smt_context.h index 605d23876..040054d39 100644 --- a/src/smt/smt_context.h +++ b/src/smt/smt_context.h @@ -1237,6 +1237,8 @@ namespace smt { void display_profile(std::ostream & out) const; + void display(std::ostream& out, b_justification j) const; + // ----------------------------------- // // Debugging support diff --git a/src/smt/smt_context_pp.cpp b/src/smt/smt_context_pp.cpp index 3dca6a70b..8eebe0531 100644 --- a/src/smt/smt_context_pp.cpp +++ b/src/smt/smt_context_pp.cpp @@ -97,7 +97,7 @@ namespace smt { } void context::display_literals_verbose(std::ostream & out, unsigned num_lits, literal const * lits) const { - display_verbose(out, m_manager, num_lits, lits, m_bool_var2expr.c_ptr()); + display_verbose(out, m_manager, num_lits, lits, m_bool_var2expr.c_ptr(), "\n"); } void context::display_literal_info(std::ostream & out, literal l) const { @@ -204,9 +204,10 @@ namespace smt { literal_vector::const_iterator end = m_assigned_literals.end(); for (; it != end; ++it) { display_literal(out, *it); - out << " "; + out << ": "; + display_verbose(tout, m_manager, 1, &*it, m_bool_var2expr.c_ptr()); + out << "\n"; } - out << "\n"; } } @@ -581,15 +582,8 @@ namespace smt { } } } - - void context::trace_assign(literal l, b_justification j, bool decision) const { - SASSERT(m_manager.has_trace_stream()); - std::ostream & out = m_manager.trace_stream(); - out << "[assign] "; - display_literal(out, l); - if (decision) - out << " decision"; - out << " "; + + void context::display(std::ostream& out, b_justification j) const { switch (j.get_kind()) { case b_justification::AXIOM: out << "axiom"; @@ -597,8 +591,6 @@ namespace smt { case b_justification::BIN_CLAUSE: { literal l2 = j.get_literal(); out << "bin-clause "; - display_literal(out, l); - out << " "; display_literal(out, l2); break; } @@ -618,5 +610,16 @@ namespace smt { out << "\n"; } + void context::trace_assign(literal l, b_justification j, bool decision) const { + SASSERT(m_manager.has_trace_stream()); + std::ostream & out = m_manager.trace_stream(); + out << "[assign] "; + display_literal(out, l); + if (decision) + out << " decision"; + out << " "; + display(out, j); + } + }; diff --git a/src/smt/smt_literal.cpp b/src/smt/smt_literal.cpp index 05bf4d04b..d510027f0 100644 --- a/src/smt/smt_literal.cpp +++ b/src/smt/smt_literal.cpp @@ -69,10 +69,10 @@ namespace smt { } } - void display_verbose(std::ostream & out, ast_manager& m, unsigned num_lits, literal const * lits, expr * const * bool_var2expr_map) { + void display_verbose(std::ostream & out, ast_manager& m, unsigned num_lits, literal const * lits, expr * const * bool_var2expr_map, char const* sep) { for (unsigned i = 0; i < num_lits; i++) { if (i > 0) - out << " "; + out << sep; lits[i].display(out, m, bool_var2expr_map); } } diff --git a/src/smt/smt_literal.h b/src/smt/smt_literal.h index 0d8a62f20..3dbd6911e 100644 --- a/src/smt/smt_literal.h +++ b/src/smt/smt_literal.h @@ -103,7 +103,7 @@ namespace smt { void display_compact(std::ostream & out, unsigned num_lits, literal const * lits, expr * const * bool_var2expr_map); - void display_verbose(std::ostream & out, ast_manager& m, unsigned num_lits, literal const * lits, expr * const * bool_var2expr_map); + void display_verbose(std::ostream & out, ast_manager& m, unsigned num_lits, literal const * lits, expr * const * bool_var2expr_map, char const* sep = " "); template void neg_literals(unsigned num_lits, literal const * lits, T & result) { diff --git a/src/smt/theory_arith.h b/src/smt/theory_arith.h index 9c391ca1a..5af436919 100644 --- a/src/smt/theory_arith.h +++ b/src/smt/theory_arith.h @@ -218,7 +218,7 @@ namespace smt { typedef svector eq_vector; // keep track of coefficients used for bounds for proof generation. - class antecedents { + class antecedents_t { literal_vector m_lits; eq_vector m_eqs; vector m_lit_coeffs; @@ -233,16 +233,38 @@ namespace smt { void init(); public: - antecedents(): m_init(false) {} + antecedents_t(): m_init(false) {} void reset(); - literal_vector& lits() { return m_lits; } - eq_vector& eqs() { return m_eqs; } + literal_vector const& lits() const { return m_lits; } + eq_vector const& eqs() const { return m_eqs; } void push_lit(literal l, numeral const& r, bool proofs_enabled); void push_eq(enode_pair const& p, numeral const& r, bool proofs_enabled); + void append(unsigned sz, literal const* ls) { m_lits.append(sz, ls); } + void append(unsigned sz, enode_pair const* ps) { m_eqs.append(sz, ps); } unsigned num_params() const { return empty()?0:m_eq_coeffs.size() + m_lit_coeffs.size() + 1; } numeral const* lit_coeffs() const { return m_lit_coeffs.c_ptr(); } numeral const* eq_coeffs() const { return m_eq_coeffs.c_ptr(); } parameter* params(char const* name); + std::ostream& display(theory_arith& th, std::ostream& out) const; + }; + + class antecedents { + theory_arith& th; + antecedents_t& a; + public: + antecedents(theory_arith& th); + ~antecedents(); + literal_vector const& lits() const { return a.lits(); } + eq_vector const& eqs() const { return a.eqs(); } + void push_lit(literal l, numeral const& r, bool e) { a.push_lit(l, r, e); } + void push_eq(enode_pair const& p, numeral const& r, bool e) { a.push_eq(p, r, e); } + void append(unsigned sz, literal const* ls) { a.append(sz, ls); } + void append(unsigned sz, enode_pair const* ps) { a.append(sz, ps); } + unsigned num_params() const { return a.num_params(); } + numeral const* lit_coeffs() const { return a.lit_coeffs(); } + numeral const* eq_coeffs() const { return a.eq_coeffs(); } + parameter* params(char const* name) { return a.params(name); } + std::ostream& display(std::ostream& out) const { return a.display(th, out); } }; class gomory_cut_justification; @@ -324,11 +346,14 @@ namespace smt { public: derived_bound(theory_var v, inf_numeral const & val, bound_kind k):bound(v, val, k, false) {} virtual ~derived_bound() {} + literal_vector const& lits() const { return m_lits; } + eq_vector const& eqs() const { return m_eqs; } virtual bool has_justification() const { return true; } virtual void push_justification(antecedents& a, numeral const& coeff, bool proofs_enabled); virtual void push_lit(literal l, numeral const&) { m_lits.push_back(l); } virtual void push_eq(enode_pair const& p, numeral const&) { m_eqs.push_back(p); } virtual void display(theory_arith const& th, std::ostream& out) const; + }; class justified_derived_bound : public derived_bound { @@ -460,8 +485,8 @@ namespace smt { svector m_scopes; literal_vector m_tmp_literal_vector2; - antecedents m_tmp_antecedents; - antecedents m_tmp_antecedents2; + antecedents_t m_antecedents[3]; + unsigned m_antecedents_index; struct var_value_hash; friend struct var_value_hash; @@ -506,6 +531,8 @@ namespace smt { bool relax_bounds() const { return m_params.m_arith_stronger_lemmas; } bool skip_big_coeffs() const { return m_params.m_arith_skip_rows_with_big_coeffs; } bool dump_lemmas() const { return m_params.m_arith_dump_lemmas; } + void dump_lemmas(literal l, antecedents const& ante); + void dump_lemmas(literal l, derived_bound const& ante); bool process_atoms() const; unsigned get_num_conflicts() const { return m_num_conflicts; } var_kind get_var_kind(theory_var v) const { return m_data[v].kind(); } @@ -750,7 +777,7 @@ namespace smt { void explain_bound(row const & r, int idx, bool lower, inf_numeral & delta, antecedents & antecedents); void mk_implied_bound(row const & r, unsigned idx, bool lower, theory_var v, bound_kind kind, inf_numeral const & k); - void assign_bound_literal(literal l, row const & r, unsigned idx, bool lower, inf_numeral & delta, antecedents& antecedents); + void assign_bound_literal(literal l, row const & r, unsigned idx, bool lower, inf_numeral & delta); void propagate_bounds(); // ----------------------------------- @@ -836,7 +863,9 @@ namespace smt { // Justification // // ----------------------------------- - void set_conflict(unsigned num_literals, literal const * lits, unsigned num_eqs, enode_pair const * eqs, antecedents& antecedents, bool is_lia, char const* proof_rule); + void set_conflict(unsigned num_literals, literal const * lits, unsigned num_eqs, enode_pair const * eqs, antecedents& antecedents, char const* proof_rule); + void set_conflict(antecedents const& ante, antecedents& bounds, char const* proof_rule); + void set_conflict(derived_bound const& ante, antecedents& bounds, char const* proof_rule); void collect_fixed_var_justifications(row const & r, antecedents& antecedents) const; // ----------------------------------- @@ -989,7 +1018,7 @@ namespace smt { gb_result compute_grobner(svector const & nl_cluster); bool max_min_nl_vars(); final_check_status process_non_linear(); - antecedents& get_antecedents(); + // ----------------------------------- // diff --git a/src/smt/theory_arith_aux.h b/src/smt/theory_arith_aux.h index 581fbb4df..e2a2d48a6 100644 --- a/src/smt/theory_arith_aux.h +++ b/src/smt/theory_arith_aux.h @@ -316,7 +316,7 @@ namespace smt { // ----------------------------------- template - void theory_arith::antecedents::init() { + void theory_arith::antecedents_t::init() { if (!m_init && !empty()) { m_params.push_back(parameter(symbol("unknown-arith"))); for (unsigned i = 0; i < m_lits.size(); i++) { @@ -330,7 +330,7 @@ namespace smt { } template - void theory_arith::antecedents::reset() { + void theory_arith::antecedents_t::reset() { m_init = false; m_eq_coeffs.reset(); m_lit_coeffs.reset(); @@ -340,7 +340,7 @@ namespace smt { } template - void theory_arith::antecedents::push_lit(literal l, numeral const& r, bool proofs_enabled) { + void theory_arith::antecedents_t::push_lit(literal l, numeral const& r, bool proofs_enabled) { m_lits.push_back(l); if (proofs_enabled) { m_lit_coeffs.push_back(r); @@ -348,7 +348,7 @@ namespace smt { } template - void theory_arith::antecedents::push_eq(enode_pair const& p, numeral const& r, bool proofs_enabled) { + void theory_arith::antecedents_t::push_eq(enode_pair const& p, numeral const& r, bool proofs_enabled) { m_eqs.push_back(p); if (proofs_enabled) { m_eq_coeffs.push_back(r); @@ -356,7 +356,7 @@ namespace smt { } template - parameter * theory_arith::antecedents::params(char const* name) { + parameter * theory_arith::antecedents_t::params(char const* name) { if (empty()) return 0; init(); m_params[0] = parameter(symbol(name)); @@ -740,8 +740,8 @@ namespace smt { } } else { - a.lits().append(m_lits.size(), m_lits.c_ptr()); - a.eqs().append(m_eqs.size(), m_eqs.c_ptr()); + a.append(m_lits.size(), m_lits.c_ptr()); + a.append(m_eqs.size(), m_eqs.c_ptr()); } } @@ -804,8 +804,7 @@ namespace smt { */ template void theory_arith::accumulate_justification(bound & b, derived_bound& new_bound, numeral const& coeff, literal_idx_set & lits, eq_set & eqs) { - antecedents& ante = m_tmp_antecedents; - ante.reset(); + antecedents ante(*this); b.push_justification(ante, coeff, proofs_enabled()); unsigned num_lits = ante.lits().size(); for (unsigned i = 0; i < num_lits; ++i) { diff --git a/src/smt/theory_arith_core.h b/src/smt/theory_arith_core.h index c47585606..6ae146b1b 100644 --- a/src/smt/theory_arith_core.h +++ b/src/smt/theory_arith_core.h @@ -349,7 +349,6 @@ namespace smt { template void theory_arith::mk_axiom(expr * ante, expr * conseq) { ast_manager & m = get_manager(); - TRACE("arith_axiom", tout << mk_pp(ante, m) << "\n" << mk_pp(conseq, m) << "\n";); context & ctx = get_context(); simplifier & s = ctx.get_simplifier(); expr_ref s_ante(m), s_conseq(m); @@ -371,6 +370,9 @@ namespace smt { literal l_conseq = ctx.get_literal(s_conseq); if (negated) l_conseq.neg(); + TRACE("arith_axiom", tout << mk_pp(ante, m) << "\n" << mk_pp(conseq, m) << "\n"; + tout << s_ante << "\n" << s_conseq << "\n";); + literal lits[2] = {l_ante, l_conseq}; ctx.mk_th_axiom(get_id(), 2, lits); if (ctx.relevancy()) { @@ -394,12 +396,12 @@ namespace smt { void theory_arith::mk_div_axiom(expr * p, expr * q) { if (!m_util.is_zero(q)) { ast_manager & m = get_manager(); + expr_ref div(m), zero(m), eqz(m), eq(m); TRACE("div_axiom_bug", tout << "expanding div_axiom for: " << mk_pp(p, m) << " / " << mk_pp(q, m) << "\n";); - expr * div = m_util.mk_div(p, q); - expr * zero = m_util.mk_numeral(rational(0), false); - expr_ref eqz(m), eq(m); - eqz = m.mk_eq(q, zero); - eq = m.mk_eq(m_util.mk_mul(q, div), p); + div = m_util.mk_div(p, q); + zero = m_util.mk_numeral(rational(0), false); + eqz = m.mk_eq(q, zero); + eq = m.mk_eq(m_util.mk_mul(q, div), p); TRACE("div_axiom_bug", tout << "eqz: " << mk_pp(eqz, m) << "\neq: " << mk_pp(eq, m) << "\n";); mk_axiom(eqz, eq); } @@ -410,15 +412,21 @@ namespace smt { if (!m_util.is_zero(divisor)) { // if divisor is zero, then idiv and mod are uninterpreted functions. ast_manager & m = get_manager(); - expr * div = m_util.mk_idiv(dividend, divisor); - expr * mod = m_util.mk_mod(dividend, divisor); - expr * zero = m_util.mk_numeral(rational(0), true); - expr * abs_divisor = m.mk_ite(m_util.mk_lt(divisor, zero), m_util.mk_sub(zero, divisor), divisor); + expr_ref div(m), mod(m), zero(m), abs_divisor(m); expr_ref eqz(m), eq(m), lower(m), upper(m); - eqz = m.mk_eq(divisor, zero); - eq = m.mk_eq(m_util.mk_add(m_util.mk_mul(divisor, div), mod), dividend); - lower = m_util.mk_le(zero, mod); - upper = m_util.mk_lt(mod, abs_divisor); + div = m_util.mk_idiv(dividend, divisor); + mod = m_util.mk_mod(dividend, divisor); + zero = m_util.mk_numeral(rational(0), true); + abs_divisor = m.mk_ite(m_util.mk_lt(divisor, zero), m_util.mk_sub(zero, divisor), divisor); + eqz = m.mk_eq(divisor, zero); + eq = m.mk_eq(m_util.mk_add(m_util.mk_mul(divisor, div), mod), dividend); + lower = m_util.mk_le(zero, mod); + upper = m_util.mk_lt(mod, abs_divisor); + TRACE("div_axiom_bug", + tout << "eqz: " << mk_pp(eqz, m) << "\neq: " << mk_pp(eq, m) << "\n"; + tout << "lower: " << mk_pp(lower, m) << "\n"; + tout << "upper: " << mk_pp(upper, m) << "\n";); + mk_axiom(eqz, eq); mk_axiom(eqz, lower); mk_axiom(eqz, upper); @@ -814,6 +822,7 @@ namespace smt { void theory_arith::mk_bound_axioms(atom * a1) { theory_var v = a1->get_var(); atoms & occs = m_var_occs[v]; + //SASSERT(v != 15); TRACE("mk_bound_axioms", tout << "add bound axioms for v" << v << " " << a1 << "\n";); if (!get_context().is_searching()) { // @@ -937,6 +946,8 @@ namespace smt { template void theory_arith::flush_bound_axioms() { + CTRACE("arith", !m_new_atoms.empty(), tout << "flush bound axioms\n";); + while (!m_new_atoms.empty()) { ptr_vector atoms; atoms.push_back(m_new_atoms.back()); @@ -950,6 +961,10 @@ namespace smt { --i; } } + TRACE("arith", + for (unsigned i = 0; i < atoms.size(); ++i) { + atoms[i]->display(*this, tout); + }); ptr_vector occs(m_var_occs[v]); std::sort(atoms.begin(), atoms.end(), compare_atoms()); @@ -1140,7 +1155,7 @@ namespace smt { template void theory_arith::assign_eh(bool_var v, bool is_true) { - TRACE("arith", tout << "v" << v << " " << is_true << "\n";); + TRACE("arith", tout << "p" << v << " := " << (is_true?"true":"false") << "\n";); atom * a = get_bv2a(v); if (!a) return; SASSERT(get_context().get_assignment(a->get_bool_var()) != l_undef); @@ -1299,28 +1314,6 @@ namespace smt { final_check_status theory_arith::final_check_eh() { TRACE("arith_eq_adapter_info", m_arith_eq_adapter.display_already_processed(tout);); TRACE("arith_final_check", display(tout);); -#if 0 - if (true /*m_params.m_smtlib_dump_lemmas*/) { - literal_buffer tmp; - - for (unsigned i = 0; i < m_asserted_qhead; i++) { - bound * b = m_asserted_bounds[i]; - if (b->is_atom()) { - atom* a = static_cast(b); - bool_var bv = a->get_bool_var(); - lbool is_true = get_context().get_assignment(bv); - if (is_true == l_true) { - tmp.push_back(literal(bv)); - } - else if (is_true == l_false) { - tmp.push_back(~literal(bv)); - } - } - } - - get_context().display_lemma_as_smt_problem(tmp.size(), tmp.c_ptr(), false_literal, "QF_LIA"); - } -#endif if (!propagate_core()) return FC_CONTINUE; @@ -1530,6 +1523,7 @@ namespace smt { m_branch_cut_counter(0), m_eager_gcd(m_params.m_arith_eager_gcd), m_final_check_idx(0), + m_antecedents_index(0), m_var_value_table(DEFAULT_HASHTABLE_INITIAL_CAPACITY, var_value_hash(*this), var_value_eq(*this)), m_liberal_final_check(true), m_changed_assignment(false), @@ -2202,15 +2196,15 @@ namespace smt { } } - TRACE("sign_row_conflict", tout << "v" << x_i << " is_below: " << is_below << " delta: " << delta << "\n"; display_var(tout, x_i); - tout << "is_below_lower: " << below_lower(x_i) << ", is_above_upper: " << above_upper(x_i) << "\n";); - antecedents& ante = get_antecedents(); + antecedents ante(*this); explain_bound(r, idx, !is_below, delta, ante); b->push_justification(ante, numeral(1), coeffs_enabled()); + TRACE("sign_row_conflict", tout << "v" << x_i << " is_below: " << is_below << " delta: " << delta << "\n"; display_var(tout, x_i); + tout << "is_below_lower: " << below_lower(x_i) << ", is_above_upper: " << above_upper(x_i) << "\n"; + ante.display(tout);); - set_conflict(ante.lits().size(), ante.lits().c_ptr(), - ante.eqs().size(), ante.eqs().c_ptr(), ante, is_int(x_i), "farkas"); + set_conflict(ante, ante, "farkas"); // display_bounds_in_smtlib(); } @@ -2348,11 +2342,11 @@ namespace smt { template void theory_arith::sign_bound_conflict(bound * b1, bound * b2) { SASSERT(b1->get_var() == b2->get_var()); - antecedents& ante = get_antecedents(); + antecedents ante(*this); b1->push_justification(ante, numeral(1), coeffs_enabled()); b2->push_justification(ante, numeral(1), coeffs_enabled()); - set_conflict(ante.lits().size(), ante.lits().c_ptr(), ante.eqs().size(), ante.eqs().c_ptr(), ante, is_int(b1->get_var()), "farkas"); + set_conflict(ante, ante, "farkas"); TRACE("arith_conflict", tout << "bound conflict v" << b1->get_var() << "\n"; tout << "bounds: " << b1 << " " << b2 << "\n";); } @@ -2590,7 +2584,6 @@ namespace smt { if (!relax_bounds() && (!ante.lits().empty() || !ante.eqs().empty())) return; context & ctx = get_context(); - ante.reset(); // !!!!TBD: should equality ante also be reset here!!!! row_entry const & entry = r[idx]; numeral coeff = entry.m_coeff; if (relax_bounds()) { @@ -2695,7 +2688,6 @@ namespace smt { template void theory_arith::mk_implied_bound(row const & r, unsigned idx, bool is_lower, theory_var v, bound_kind kind, inf_numeral const & k) { atoms const & as = m_var_occs[v]; - antecedents& ante = get_antecedents(); inf_numeral const & epsilon = get_epsilon(v); inf_numeral delta; typename atoms::const_iterator it = as.begin(); @@ -2716,7 +2708,7 @@ namespace smt { } TRACE("propagate_bounds", tout << "v" << v << " >= " << k << ", v" << v << " >= " << k2 << ", delta: " << delta << "\n"; display_row(tout, r);); - assign_bound_literal(l, r, idx, is_lower, delta, ante); + assign_bound_literal(l, r, idx, is_lower, delta); } // v <= k k < k2 |- v < k2 |- not v >= k2 if (kind == B_UPPER && k < k2) { @@ -2732,7 +2724,7 @@ namespace smt { if (delta.is_nonneg()) { TRACE("propagate_bounds", tout << "v" << v << " <= " << k << ", not v" << v << " >= " << k2 << ", delta: " << delta << "\n"; display_row(tout, r);); - assign_bound_literal(~l, r, idx, is_lower, delta, ante); + assign_bound_literal(~l, r, idx, is_lower, delta); } } } @@ -2747,7 +2739,7 @@ namespace smt { if (delta.is_nonneg()) { TRACE("propagate_bounds", tout << "v" << v << " >= " << k << ", not v" << v << " <= " << k2 << ", delta: " << delta << "\n"; display_row(tout, r);); - assign_bound_literal(~l, r, idx, is_lower, delta, ante); + assign_bound_literal(~l, r, idx, is_lower, delta); } } // v <= k k <= k2 |- v <= k2 @@ -2758,7 +2750,7 @@ namespace smt { } TRACE("propagate_bounds", tout << "v" << v << " <= " << k << ", v" << v << " <= " << k2 << ", delta: " << delta << "\n"; display_row(tout, r);); - assign_bound_literal(l, r, idx, is_lower, delta, ante); + assign_bound_literal(l, r, idx, is_lower, delta); } } } @@ -2766,28 +2758,34 @@ namespace smt { } template - void theory_arith::assign_bound_literal(literal l, row const & r, unsigned idx, bool is_lower, inf_numeral & delta, antecedents& ante) { + void theory_arith::dump_lemmas(literal l, antecedents const& ante) { + context & ctx = get_context(); + if (dump_lemmas()) { + TRACE("arith", ante.display(tout) << " --> "; ctx.display_detailed_literal(tout, l); tout << "\n";); + ctx.display_lemma_as_smt_problem(ante.lits().size(), ante.lits().c_ptr(), + ante.eqs().size(), ante.eqs().c_ptr(), l, 0); + } + } + + template + void theory_arith::dump_lemmas(literal l, derived_bound const& ante) { + context & ctx = get_context(); + if (dump_lemmas()) { + ctx.display_lemma_as_smt_problem(ante.lits().size(), ante.lits().c_ptr(), + ante.eqs().size(), ante.eqs().c_ptr(), l, 0); + } + } + + template + void theory_arith::assign_bound_literal(literal l, row const & r, unsigned idx, bool is_lower, inf_numeral & delta) { m_stats.m_bound_props++; context & ctx = get_context(); + antecedents ante(*this); explain_bound(r, idx, is_lower, delta, ante); - if (dump_lemmas()) { - char const * logic = is_int(r.get_base_var()) ? "QF_LIA" : "QF_LRA"; - ctx.display_lemma_as_smt_problem(ante.lits().size(), ante.lits().c_ptr(), - ante.eqs().size(), ante.eqs().c_ptr(), l, logic); - } + dump_lemmas(l, ante); + TRACE("propagate_bounds", - literal_vector::const_iterator it = ante.lits().begin(); - literal_vector::const_iterator end = ante.lits().end(); - for (; it != end; ++it) { - ctx.display_detailed_literal(tout, *it); - tout << " "; - } - eq_vector::const_iterator it2 = ante.eqs().begin(); - eq_vector::const_iterator end2 = ante.eqs().end(); - for (; it2 != end2; ++it2) { - tout << "#" << it2->first->get_owner_id() << "=#" << it2->second->get_owner_id() << " "; - } - tout << " --> "; + ante.display(tout) << " --> "; ctx.display_detailed_literal(tout, l); tout << "\n";); if (ante.lits().size() < small_lemma_size() && ante.eqs().empty()) { @@ -2869,19 +2867,26 @@ namespace smt { // Justification // // ----------------------------------- + + template + void theory_arith::set_conflict(antecedents const& ante, antecedents& bounds, char const* proof_rule) { + dump_lemmas(false_literal, ante); + set_conflict(ante.lits().size(), ante.lits().c_ptr(), ante.eqs().size(), ante.eqs().c_ptr(), bounds, proof_rule); + } + + template + void theory_arith::set_conflict(derived_bound const& ante, antecedents& bounds, char const* proof_rule) { + dump_lemmas(false_literal, ante); + set_conflict(ante.lits().size(), ante.lits().c_ptr(), ante.eqs().size(), ante.eqs().c_ptr(), bounds, proof_rule); + } template - void theory_arith::set_conflict(unsigned num_literals, literal const * lits, unsigned num_eqs, enode_pair const * eqs, - antecedents& bounds, bool is_lia, char const* proof_rule) { + void theory_arith::set_conflict(unsigned num_literals, literal const * lits, unsigned num_eqs, enode_pair const * eqs, + antecedents& bounds, char const* proof_rule) { SASSERT(num_literals != 0 || num_eqs != 0); context & ctx = get_context(); m_stats.m_conflicts++; m_num_conflicts++; - if (dump_lemmas()) { - char const * logic = is_lia ? "QF_LIA" : "QF_LRA"; - ctx.display_lemma_as_smt_problem(num_literals, lits, num_eqs, eqs, false_literal, logic); - } - region & r = ctx.get_region(); TRACE("arith_conflict", for (unsigned i = 0; i < num_literals; i++) { ctx.display_detailed_literal(tout, lits[i]); @@ -2903,7 +2908,7 @@ namespace smt { record_conflict(num_literals, lits, num_eqs, eqs, bounds.num_params(), bounds.params(proof_rule)); ctx.set_conflict( ctx.mk_justification( - ext_theory_conflict_justification(get_id(), r, num_literals, lits, num_eqs, eqs, + ext_theory_conflict_justification(get_id(), ctx.get_region(), num_literals, lits, num_eqs, eqs, bounds.num_params(), bounds.params(proof_rule)))); } @@ -3315,11 +3320,20 @@ namespace smt { */ template - typename theory_arith::antecedents& theory_arith::get_antecedents() { - m_tmp_antecedents.reset(); - return m_tmp_antecedents; + theory_arith::antecedents::antecedents(theory_arith& th): + th(th), + a(th.m_antecedents[th.m_antecedents_index]) { + SASSERT(th.m_antecedents_index < 3); + a.reset(); + ++th.m_antecedents_index; } + template + theory_arith::antecedents::~antecedents() { + --th.m_antecedents_index; + } + + }; #endif /* THEORY_ARITH_CORE_H_ */ diff --git a/src/smt/theory_arith_eq.h b/src/smt/theory_arith_eq.h index 80b13050d..7e61b968e 100644 --- a/src/smt/theory_arith_eq.h +++ b/src/smt/theory_arith_eq.h @@ -52,7 +52,7 @@ namespace smt { // contain invalid (key -> value) pairs. So, we must check whether v2 is really equal to val (previous test) AND it has // the same sort of v. The following test was missing in a previous version of Z3. if (!is_equal(v, v2) && is_int(v) == is_int(v2)) { - antecedents& ante = get_antecedents(); + antecedents ante(*this); // // v <= k <= v2 => v <= v2 @@ -241,7 +241,7 @@ namespace smt { is_int(x) == is_int(x2) && !is_equal(x, x2)) { - antecedents& ante = get_antecedents(); + antecedents ante(*this); collect_fixed_var_justifications(r, ante); // @@ -256,7 +256,7 @@ namespace smt { if (k.is_zero() && y != null_theory_var && !is_equal(x, y) && is_int(x) == is_int(y)) { // found equality x = y - antecedents& ante = get_antecedents(); + antecedents ante(*this); collect_fixed_var_justifications(r, ante); TRACE("propagate_cheap_eq", tout << "propagate eq using x-y=0 row:\n"; display_row_info(tout, r);); m_stats.m_offset_eqs++; @@ -296,7 +296,7 @@ namespace smt { if (new_eq) { if (!is_equal(x, x2) && is_int(x) == is_int(x2)) { SASSERT(y == y2 && k == k2); - antecedents& ante = get_antecedents(); + antecedents ante(*this); collect_fixed_var_justifications(r, ante); collect_fixed_var_justifications(r2, ante); TRACE("propagate_cheap_eq", tout << "propagate eq two rows:\n"; diff --git a/src/smt/theory_arith_int.h b/src/smt/theory_arith_int.h index d0493b274..30ae6feac 100644 --- a/src/smt/theory_arith_int.h +++ b/src/smt/theory_arith_int.h @@ -201,12 +201,13 @@ namespace smt { SASSERT(is_int(v)); SASSERT(!get_value(v).is_int()); m_stats.m_branches++; - TRACE("arith_branching", tout << "branching v" << v << " = " << get_value(v) << "\n"; + 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(); - expr * bound = m_util.mk_ge(get_enode(v)->get_owner(), m_util.mk_numeral(_k, true)); - TRACE("arith_branching", tout << mk_bounded_pp(bound, get_manager()) << "\n";); + expr_ref bound(get_manager()); + bound = m_util.mk_ge(get_enode(v)->get_owner(), m_util.mk_numeral(_k, true)); + TRACE("arith_int", tout << mk_bounded_pp(bound, get_manager()) << "\n";); context & ctx = get_context(); ctx.internalize(bound, true); ctx.mark_as_relevant(bound); @@ -452,11 +453,11 @@ namespace smt { expr_ref pol(m); pol = m_util.mk_add(_args.size(), _args.c_ptr()); result = m_util.mk_ge(pol, m_util.mk_numeral(k, all_int)); - TRACE("arith_mk_polynomial", tout << "before simplification:\n" << mk_pp(pol, m) << "\n";); + TRACE("arith_mk_polynomial", tout << "before simplification:\n" << result << "\n";); simplifier & s = get_context().get_simplifier(); proof_ref pr(m); s(result, result, pr); - TRACE("arith_mk_polynomial", tout << "after simplification:\n" << mk_pp(pol, m) << "\n";); + TRACE("arith_mk_polynomial", tout << "after simplification:\n" << result << "\n";); SASSERT(is_well_sorted(get_manager(), result)); } @@ -498,7 +499,7 @@ namespace smt { TRACE("gomory_cut", tout << "applying cut at:\n"; display_row_info(tout, r);); - antecedents& ante = get_antecedents(); + antecedents ante(*this); m_stats.m_gomory_cuts++; @@ -508,6 +509,8 @@ namespace smt { 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; @@ -521,36 +524,30 @@ namespace smt { 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; - TRACE("gomory_cut_detail", tout << a_ij << "*v" << x_j << "\n";); if (at_lower(x_j)) { if (a_ij.is_pos()) { new_a_ij = a_ij / one_minus_f_0; } else { - TRUSTME(!f_0.is_zero()); new_a_ij = a_ij / f_0; new_a_ij.neg(); } - // k += new_a_ij * lower_bound(x_j).get_rational(); 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()) { - TRUSTME(!f_0.is_zero()); 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 - // new_a_ij.neg() // the upper terms are inverted - new_a_ij = a_ij / one_minus_f_0; + new_a_ij = a_ij / one_minus_f_0; } - // k += new_a_ij * upper_bound(x_j).get_rational(); 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 { @@ -572,7 +569,6 @@ namespace smt { else { new_a_ij = (numeral(1) - f_j) / f_0; } - // k += new_a_ij * lower_bound(x_j).get_rational(); k.addmul(new_a_ij, lower_bound(x_j).get_rational()); lower(x_j)->push_justification(ante, new_a_ij, coeffs_enabled()); } @@ -585,11 +581,10 @@ namespace smt { new_a_ij = (numeral(1) - f_j) / one_minus_f_0; } new_a_ij.neg(); // the upper terms are inverted - // k += new_a_ij * upper_bound(x_j).get_rational(); 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 << "\n";); + 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)); } @@ -603,7 +598,7 @@ namespace smt { if (pol.empty()) { SASSERT(k.is_pos()); // conflict 0 >= k where k is positive - set_conflict(ante.lits().size(), ante.lits().c_ptr(), ante.eqs().size(), ante.eqs().c_ptr(), ante, true, "gomory-cut"); + set_conflict(ante, ante, "gomory-cut"); return true; } else if (pol.size() == 1) { @@ -639,18 +634,19 @@ namespace smt { } TRACE("gomory_cut_detail", tout << "after *lcm\n"; for (unsigned i = 0; i < pol.size(); i++) { - tout << pol[i].m_coeff << " " << pol[i].m_var << "\n"; + 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" << mk_pp(bound, get_manager()) << "\n";); + 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(), @@ -721,7 +717,7 @@ namespace smt { if (!(consts / gcds).is_int()) { TRACE("gcd_test", tout << "row failed the GCD test:\n"; display_row_info(tout, r);); - antecedents& ante = get_antecedents(); + antecedents ante(*this); collect_fixed_var_justifications(r, ante); context & ctx = get_context(); ctx.set_conflict( @@ -754,7 +750,7 @@ namespace smt { numeral l(consts); numeral u(consts); - antecedents& ante = get_antecedents(); + antecedents ante(*this); typename vector::const_iterator it = r.begin_entries(); diff --git a/src/smt/theory_arith_nl.h b/src/smt/theory_arith_nl.h index 33efb4fcc..982aa963f 100644 --- a/src/smt/theory_arith_nl.h +++ b/src/smt/theory_arith_nl.h @@ -1910,11 +1910,10 @@ namespace smt { */ template void theory_arith::set_conflict(v_dependency * d) { - bool is_lia = false; // TODO: fix it, but this is only used for debugging. - antecedents& ante = get_antecedents(); + antecedents ante(*this); derived_bound b(null_theory_var, inf_numeral(0), B_LOWER); dependency2new_bound(d, b); - set_conflict(b.m_lits.size(), b.m_lits.c_ptr(), b.m_eqs.size(), b.m_eqs.c_ptr(), ante, is_lia, "arith_nl"); + set_conflict(b, ante, "arith_nl"); TRACE("non_linear", for (unsigned i = 0; i < b.m_lits.size(); ++i) { tout << b.m_lits[i] << " "; diff --git a/src/smt/theory_arith_pp.h b/src/smt/theory_arith_pp.h index db0a9dd39..ea4581925 100644 --- a/src/smt/theory_arith_pp.h +++ b/src/smt/theory_arith_pp.h @@ -399,6 +399,18 @@ namespace smt { out << "\n"; } + template + std::ostream& theory_arith::antecedents_t::display(theory_arith& th, std::ostream & out) const { + th.get_context().display_literals_verbose(out, lits().size(), lits().c_ptr()); + if (!lits().empty()) out << "\n"; + ast_manager& m = th.get_manager(); + for (unsigned i = 0; i < m_eqs.size(); ++i) { + out << mk_pp(m_eqs[i].first->get_owner(), m) << " "; + out << mk_pp(m_eqs[i].second->get_owner(), m) << "\n"; + } + return out; + } + template void theory_arith::display_deps(std::ostream & out, v_dependency* dep) { ptr_vector bounds; diff --git a/src/util/scoped_timer.cpp b/src/util/scoped_timer.cpp index 5c36a2d82..cf06b27be 100644 --- a/src/util/scoped_timer.cpp +++ b/src/util/scoped_timer.cpp @@ -204,7 +204,7 @@ struct scoped_timer::imp { throw default_exception("failed to destroy pthread attributes object"); #elif defined(_LINUX_) || defined(_FREEBSD_) // Linux & FreeBSD - timer_delete(m_timerid); + timer_delete(m_timerid); #else // Other Platforms #endif