mirror of
https://github.com/Z3Prover/z3
synced 2025-04-23 17:15:31 +00:00
smarter explanation.h (#4385)
* smarter explanation.h Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * clean explanation API Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * suppress warnings Signed-off-by: Lev Nachmanson <levnach@hotmail.com> * disable the warnings Signed-off-by: Lev Nachmanson <levnach@hotmail.com>
This commit is contained in:
parent
3b0c40044f
commit
af2f74c05f
16 changed files with 109 additions and 89 deletions
|
@ -18,47 +18,70 @@ Revision History:
|
|||
|
||||
--*/
|
||||
#pragma once
|
||||
#include <unordered_set>
|
||||
#include "math/lp/lp_utils.h"
|
||||
#include "util/map.h"
|
||||
#include "util/optional.h"
|
||||
namespace lp {
|
||||
class explanation {
|
||||
vector<std::pair<mpq, constraint_index>> m_explanation;
|
||||
std::unordered_set<unsigned> m_set_of_ci;
|
||||
u_map<optional<mpq>> m_j_to_mpq;
|
||||
public:
|
||||
explanation() {}
|
||||
template <typename T>
|
||||
explanation(const T& t) { for ( unsigned c : t) add(c); }
|
||||
|
||||
void clear() { m_explanation.clear(); m_set_of_ci.clear(); }
|
||||
vector<std::pair<mpq, constraint_index>>::const_iterator begin() const { return m_explanation.begin(); }
|
||||
vector<std::pair<mpq, constraint_index>>::const_iterator end() const { return m_explanation.end(); }
|
||||
void push_justification(constraint_index j, const mpq& v) {
|
||||
if (m_set_of_ci.find(j) != m_set_of_ci.end()) return;
|
||||
m_set_of_ci.insert(j);
|
||||
m_explanation.push_back(std::make_pair(v, j));
|
||||
explanation(const T& t) {
|
||||
for ( unsigned c : t)
|
||||
push_back(c);
|
||||
}
|
||||
void push_justification(constraint_index j) {
|
||||
if (m_set_of_ci.find(j) != m_set_of_ci.end()) return;
|
||||
m_set_of_ci.insert(j);
|
||||
m_explanation.push_back(std::make_pair(one_of_type<mpq>(), j));
|
||||
|
||||
void clear() { m_j_to_mpq.reset(); }
|
||||
void add_with_coeff(constraint_index j, const mpq& v) {
|
||||
SASSERT(m_j_to_mpq.contains(j) == false); // if we hit the assert then we
|
||||
// might start using summation
|
||||
m_j_to_mpq.insert(j, optional<mpq>(v));
|
||||
}
|
||||
|
||||
// this signature is needed to use it in a template that also works for the vector type
|
||||
void push_back(constraint_index j) {
|
||||
push_justification(j);
|
||||
if (m_j_to_mpq.contains(j))
|
||||
return;
|
||||
m_j_to_mpq.insert(j, optional<mpq>());
|
||||
}
|
||||
|
||||
void add(const explanation& e) {
|
||||
for (const auto& p: e.m_explanation) {
|
||||
add(p.second);
|
||||
void add_expl(const explanation& e) {
|
||||
for (const auto& p: e.m_j_to_mpq) {
|
||||
m_j_to_mpq.insert(p.m_key, p.m_value);
|
||||
}
|
||||
}
|
||||
template <typename T>
|
||||
void add_expl(const T& e) { for (auto j: e) add(j); }
|
||||
void add(unsigned ci) { push_justification(ci); }
|
||||
|
||||
void add(const std::pair<mpq, constraint_index>& j) { push_justification(j.second, j.first); }
|
||||
|
||||
bool empty() const { return m_explanation.empty(); }
|
||||
size_t size() const { return m_explanation.size(); }
|
||||
void add_pair(const std::pair<mpq, constraint_index>& j) {
|
||||
add_with_coeff(j.second, j.first);
|
||||
}
|
||||
|
||||
bool empty() const { return m_j_to_mpq.empty(); }
|
||||
size_t size() const { return m_j_to_mpq.size(); }
|
||||
|
||||
class cimpq {
|
||||
constraint_index m_var;
|
||||
const optional<mpq> & m_coeff;
|
||||
public:
|
||||
cimpq(constraint_index var, const optional<mpq> & val) : m_var(var), m_coeff(val) { }
|
||||
constraint_index ci() const { return m_var; }
|
||||
mpq coeff() const { return m_coeff.undef()? one_of_type<mpq>(): *m_coeff; }
|
||||
};
|
||||
class iterator {
|
||||
u_map<optional<mpq>>::iterator m_it;
|
||||
public:
|
||||
cimpq operator*() const {
|
||||
return cimpq(m_it->m_key, m_it->m_value);
|
||||
}
|
||||
iterator operator++() { iterator i = *this; m_it++; return i; }
|
||||
iterator operator++(int) { m_it++; return *this; }
|
||||
iterator(u_map<optional<mpq>>::iterator it) : m_it(it) {}
|
||||
bool operator==(const iterator &other) const { return m_it == other.m_it; }
|
||||
bool operator!=(const iterator &other) const { return !(*this == other); }
|
||||
};
|
||||
|
||||
iterator begin() const { return iterator(m_j_to_mpq.begin()); }
|
||||
iterator end() const { return iterator(m_j_to_mpq.end()); }
|
||||
|
||||
};
|
||||
}
|
||||
|
|
|
@ -67,7 +67,7 @@ class create_cut {
|
|||
new_a = m_fj <= m_one_minus_f ? m_fj / m_one_minus_f : ((1 - m_fj) / m_f);
|
||||
lp_assert(new_a.is_pos());
|
||||
m_k.addmul(new_a, lower_bound(j).x);
|
||||
m_ex->push_justification(column_lower_bound_constraint(j));
|
||||
m_ex->push_back(column_lower_bound_constraint(j));
|
||||
}
|
||||
else {
|
||||
lp_assert(at_upper(j));
|
||||
|
@ -75,7 +75,7 @@ class create_cut {
|
|||
new_a = - (m_fj <= m_f ? m_fj / m_f : ((1 - m_fj) / m_one_minus_f));
|
||||
lp_assert(new_a.is_neg());
|
||||
m_k.addmul(new_a, upper_bound(j).x);
|
||||
m_ex->push_justification(column_upper_bound_constraint(j));
|
||||
m_ex->push_back(column_upper_bound_constraint(j));
|
||||
}
|
||||
m_t.add_monomial(new_a, j);
|
||||
m_lcm_den = lcm(m_lcm_den, denominator(new_a));
|
||||
|
@ -100,7 +100,7 @@ class create_cut {
|
|||
}
|
||||
m_k.addmul(new_a, lower_bound(j).x); // is it a faster operation than
|
||||
// k += lower_bound(j).x * new_a;
|
||||
m_ex->push_justification(column_lower_bound_constraint(j));
|
||||
m_ex->push_back(column_lower_bound_constraint(j));
|
||||
}
|
||||
else {
|
||||
lp_assert(at_upper(j));
|
||||
|
@ -113,7 +113,7 @@ class create_cut {
|
|||
new_a = a / m_one_minus_f;
|
||||
}
|
||||
m_k.addmul(new_a, upper_bound(j).x); // k += upper_bound(j).x * new_a;
|
||||
m_ex->push_justification(column_upper_bound_constraint(j));
|
||||
m_ex->push_back(column_upper_bound_constraint(j));
|
||||
}
|
||||
m_t.add_monomial(new_a, j);
|
||||
TRACE("gomory_cut_detail_real", tout << "add " << new_a << "*v" << j << ", k: " << m_k << "\n";
|
||||
|
@ -320,8 +320,8 @@ public:
|
|||
// use -p.coeff() to make the format compatible with the format used in: Integrating Simplex with DPLL(T)
|
||||
try {
|
||||
if (lia.is_fixed(j)) {
|
||||
m_ex->push_justification(column_lower_bound_constraint(j));
|
||||
m_ex->push_justification(column_upper_bound_constraint(j));
|
||||
m_ex->push_back(column_lower_bound_constraint(j));
|
||||
m_ex->push_back(column_upper_bound_constraint(j));
|
||||
continue;
|
||||
}
|
||||
if (is_real(j)) {
|
||||
|
|
|
@ -263,7 +263,7 @@ namespace lp {
|
|||
lia.settings().stats().m_hnf_cuts++;
|
||||
lia.m_ex->clear();
|
||||
for (unsigned i : constraints_for_explanation()) {
|
||||
lia.m_ex->push_justification(i);
|
||||
lia.m_ex->push_back(i);
|
||||
}
|
||||
}
|
||||
return r;
|
||||
|
|
|
@ -30,7 +30,7 @@ public:
|
|||
// for a column element it points to the row element offset
|
||||
unsigned m_other;
|
||||
indexed_value() {}
|
||||
indexed_value(T v, unsigned i) : m_value(v), m_index(i) {}
|
||||
|
||||
indexed_value(T v, unsigned i, unsigned other) :
|
||||
m_value(v), m_index(i), m_other(other) {
|
||||
}
|
||||
|
|
|
@ -51,7 +51,6 @@ lia_move int_branch::create_branch_on_column(int j) {
|
|||
}
|
||||
|
||||
|
||||
|
||||
int int_branch::find_inf_int_base_column() {
|
||||
int result = -1;
|
||||
mpq range;
|
||||
|
@ -59,7 +58,7 @@ int int_branch::find_inf_int_base_column() {
|
|||
mpq small_range_thresold(1024);
|
||||
unsigned n = 0;
|
||||
lar_core_solver & lcs = lra.m_mpq_lar_core_solver;
|
||||
unsigned prev_usage;
|
||||
unsigned prev_usage = 0; // to quiet down the compile
|
||||
unsigned k = 0;
|
||||
unsigned usage;
|
||||
unsigned j;
|
||||
|
@ -103,5 +102,5 @@ int int_branch::find_inf_int_base_column() {
|
|||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -210,8 +210,8 @@ namespace lp {
|
|||
void int_gcd_test::add_to_explanation_from_fixed_or_boxed_column(unsigned j) {
|
||||
constraint_index lc, uc;
|
||||
lra.get_bound_constraint_witnesses_for_column(j, lc, uc);
|
||||
lia.m_ex->push_justification(lc);
|
||||
lia.m_ex->push_justification(uc);
|
||||
lia.m_ex->push_back(lc);
|
||||
lia.m_ex->push_back(uc);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -307,8 +307,8 @@ void lar_solver::fill_explanation_from_crossed_bounds_column(explanation & evide
|
|||
|
||||
// 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_crossed_bounds_column];
|
||||
evidence.push_justification(ul.upper_bound_witness(), numeric_traits<mpq>::one());
|
||||
evidence.push_justification(ul.lower_bound_witness(), -numeric_traits<mpq>::one());
|
||||
evidence.add_with_coeff(ul.upper_bound_witness(), numeric_traits<mpq>::one());
|
||||
evidence.add_with_coeff(ul.lower_bound_witness(), -numeric_traits<mpq>::one());
|
||||
}
|
||||
|
||||
|
||||
|
@ -1097,9 +1097,9 @@ bool lar_solver::inf_explanation_is_correct() const {
|
|||
|
||||
mpq lar_solver::sum_of_right_sides_of_explanation(explanation& exp) const {
|
||||
mpq ret = numeric_traits<mpq>::zero();
|
||||
for (auto & it : exp) {
|
||||
mpq coeff = it.first;
|
||||
constraint_index con_ind = it.second;
|
||||
for (auto it : exp) {
|
||||
mpq coeff = it.coeff();
|
||||
constraint_index con_ind = it.ci();
|
||||
lp_assert(m_constraints.valid_index(con_ind));
|
||||
ret += (m_constraints[con_ind].rhs() - m_constraints[con_ind].get_free_coeff_of_left_side()) * coeff;
|
||||
}
|
||||
|
@ -1195,7 +1195,7 @@ void lar_solver::get_infeasibility_explanation_for_inf_sign(
|
|||
|
||||
constraint_index bound_constr_i = adj_sign < 0 ? ul.upper_bound_witness() : ul.lower_bound_witness();
|
||||
lp_assert(m_constraints.valid_index(bound_constr_i));
|
||||
exp.push_justification(bound_constr_i, coeff);
|
||||
exp.add_with_coeff(bound_constr_i, coeff);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -259,9 +259,9 @@ std::ostream& core::print_monic_with_vars(const monic& m, std::ostream& out) con
|
|||
std::ostream& core::print_explanation(const lp::explanation& exp, std::ostream& out) const {
|
||||
out << "expl: ";
|
||||
unsigned i = 0;
|
||||
for (auto &p : exp) {
|
||||
out << "(" << p.second << ")";
|
||||
m_lar_solver.constraints().display(out, [this](lpvar j) { return var_str(j);}, p.second);
|
||||
for (auto p : exp) {
|
||||
out << "(" << p.ci() << ")";
|
||||
m_lar_solver.constraints().display(out, [this](lpvar j) { return var_str(j);}, p.ci());
|
||||
if (++i < exp.size())
|
||||
out << " ";
|
||||
}
|
||||
|
@ -312,7 +312,7 @@ bool core::explain_coeff_lower_bound(const lp::lar_term::ival& p, rational& boun
|
|||
if (c + 1 == 0)
|
||||
return false;
|
||||
bound = a * m_lar_solver.get_lower_bound(p.column()).x;
|
||||
e.add(c);
|
||||
e.push_back(c);
|
||||
return true;
|
||||
}
|
||||
// a.is_neg()
|
||||
|
@ -320,7 +320,7 @@ bool core::explain_coeff_lower_bound(const lp::lar_term::ival& p, rational& boun
|
|||
if (c + 1 == 0)
|
||||
return false;
|
||||
bound = a * m_lar_solver.get_upper_bound(p.column()).x;
|
||||
e.add(c);
|
||||
e.push_back(c);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -334,7 +334,7 @@ bool core::explain_coeff_upper_bound(const lp::lar_term::ival& p, rational& boun
|
|||
if (c + 1 == 0)
|
||||
return false;
|
||||
bound = a * m_lar_solver.get_lower_bound(j).x;
|
||||
e.add(c);
|
||||
e.push_back(c);
|
||||
return true;
|
||||
}
|
||||
// a.is_pos()
|
||||
|
@ -342,7 +342,7 @@ bool core::explain_coeff_upper_bound(const lp::lar_term::ival& p, rational& boun
|
|||
if (c + 1 == 0)
|
||||
return false;
|
||||
bound = a * m_lar_solver.get_upper_bound(j).x;
|
||||
e.add(c);
|
||||
e.push_back(c);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -855,7 +855,7 @@ std::unordered_set<lpvar> core::collect_vars(const lemma& l) const {
|
|||
}
|
||||
}
|
||||
for (const auto& p : l.expl()) {
|
||||
const auto& c = m_lar_solver.constraints()[p.second];
|
||||
const auto& c = m_lar_solver.constraints()[p.ci()];
|
||||
for (const auto& r : c.coeffs()) {
|
||||
insert_j(r.second);
|
||||
}
|
||||
|
@ -1060,7 +1060,7 @@ lemma& new_lemma::current() const {
|
|||
}
|
||||
|
||||
new_lemma& new_lemma::operator&=(lp::explanation const& e) {
|
||||
expl().add(e);
|
||||
expl().add_expl(e);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -1124,7 +1124,7 @@ new_lemma& new_lemma::explain_var_separated_from_zero(lpvar j) {
|
|||
new_lemma& new_lemma::explain_existing_lower_bound(lpvar j) {
|
||||
SASSERT(c.has_lower_bound(j));
|
||||
lp::explanation ex;
|
||||
ex.add(c.m_lar_solver.get_column_lower_bound_witness(j));
|
||||
ex.push_back(c.m_lar_solver.get_column_lower_bound_witness(j));
|
||||
*this &= ex;
|
||||
TRACE("nla_solver", tout << j << ": " << *this << "\n";);
|
||||
return *this;
|
||||
|
@ -1133,7 +1133,7 @@ new_lemma& new_lemma::explain_existing_lower_bound(lpvar j) {
|
|||
new_lemma& new_lemma::explain_existing_upper_bound(lpvar j) {
|
||||
SASSERT(c.has_upper_bound(j));
|
||||
lp::explanation ex;
|
||||
ex.add(c.m_lar_solver.get_column_upper_bound_witness(j));
|
||||
ex.push_back(c.m_lar_solver.get_column_upper_bound_witness(j));
|
||||
*this &= ex;
|
||||
return *this;
|
||||
}
|
||||
|
@ -1141,9 +1141,9 @@ new_lemma& new_lemma::explain_existing_upper_bound(lpvar j) {
|
|||
std::ostream& new_lemma::display(std::ostream & out) const {
|
||||
auto const& lemma = current();
|
||||
|
||||
for (auto &p : lemma.expl()) {
|
||||
out << "(" << p.second << ") ";
|
||||
c.m_lar_solver.constraints().display(out, [this](lpvar j) { return c.var_str(j);}, p.second);
|
||||
for (auto p : lemma.expl()) {
|
||||
out << "(" << p.ci() << ") ";
|
||||
c.m_lar_solver.constraints().display(out, [this](lpvar j) { return c.var_str(j);}, p.ci());
|
||||
}
|
||||
out << " ==> ";
|
||||
if (lemma.ineqs().empty()) {
|
||||
|
|
|
@ -214,9 +214,9 @@ u_dependency *intervals::mk_dep(const lp::explanation& expl) {
|
|||
u_dependency * r = nullptr;
|
||||
for (auto p : expl) {
|
||||
if (r == nullptr) {
|
||||
r = m_dep_intervals.mk_leaf(p.second);
|
||||
r = m_dep_intervals.mk_leaf(p.ci());
|
||||
} else {
|
||||
r = m_dep_intervals.mk_join(r, m_dep_intervals.mk_leaf(p.second));
|
||||
r = m_dep_intervals.mk_join(r, m_dep_intervals.mk_leaf(p.ci()));
|
||||
}
|
||||
}
|
||||
return r;
|
||||
|
@ -285,7 +285,7 @@ bool intervals::interval_from_term(const nex& e, scoped_dep_interval& i) {
|
|||
m_dep_intervals.set_interval_for_scalar(i, b);
|
||||
if (wd == e_with_deps::with_deps) {
|
||||
for (auto p : exp) {
|
||||
i.get().m_lower_dep = mk_join(i.get().m_lower_dep, mk_leaf(p.second));
|
||||
i.get().m_lower_dep = mk_join(i.get().m_lower_dep, mk_leaf(p.ci()));
|
||||
}
|
||||
i.get().m_upper_dep = i.get().m_lower_dep;
|
||||
}
|
||||
|
|
|
@ -94,7 +94,7 @@ struct solver::imp {
|
|||
m_nlsat->get_core(core);
|
||||
for (auto c : core) {
|
||||
unsigned idx = static_cast<unsigned>(static_cast<imp*>(c) - this);
|
||||
ex.push_justification(idx, rational(1));
|
||||
ex.push_back(idx);
|
||||
TRACE("arith", tout << "ex: " << idx << "\n";);
|
||||
}
|
||||
nla::new_lemma lemma(m_nla_core, __FUNCTION__);
|
||||
|
|
|
@ -110,7 +110,7 @@ void square_sparse_matrix<T, X>::set_with_no_adjusting_for_row(unsigned row, uns
|
|||
}
|
||||
}
|
||||
// have not found the column between the indices
|
||||
row_vec.push_back(indexed_value<T>(val, col)); // what about m_other ???
|
||||
row_vec.push_back(indexed_value<T>(val, col, -1));
|
||||
}
|
||||
|
||||
template <typename T, typename X>
|
||||
|
@ -123,7 +123,7 @@ void square_sparse_matrix<T, X>::set_with_no_adjusting_for_col(unsigned row, uns
|
|||
}
|
||||
}
|
||||
// have not found the column between the indices
|
||||
col_vec.push_back(indexed_value<T>(val, row)); // what about m_other ???
|
||||
col_vec.push_back(indexed_value<T>(val, row, -1));
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -43,7 +43,7 @@ public:
|
|||
void explain(lp::explanation& e) const {
|
||||
for (lpci c : m_cs)
|
||||
if (c + 1 != 0) // c != -1
|
||||
e.add(c);
|
||||
e.push_back(c);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue