mirror of
https://github.com/Z3Prover/z3
synced 2025-04-12 12:08:18 +00:00
runs a simple test
This commit is contained in:
parent
c050af922f
commit
c309d52283
|
@ -26,6 +26,8 @@ Revision History:
|
||||||
#include "math/lp/test_bound_analyzer.h"
|
#include "math/lp/test_bound_analyzer.h"
|
||||||
|
|
||||||
namespace lp {
|
namespace lp {
|
||||||
|
|
||||||
|
|
||||||
template <typename C, typename B> // C plays a role of a container, B - lp_bound_propagator
|
template <typename C, typename B> // C plays a role of a container, B - lp_bound_propagator
|
||||||
class bound_analyzer_on_row {
|
class bound_analyzer_on_row {
|
||||||
const C& m_row;
|
const C& m_row;
|
||||||
|
@ -301,8 +303,12 @@ private:
|
||||||
// */
|
// */
|
||||||
// }
|
// }
|
||||||
|
|
||||||
void limit_j(unsigned j, const mpq& u, bool coeff_before_j_is_pos, bool is_lower_bound, bool strict){
|
|
||||||
m_bp.try_add_bound(u, j, is_lower_bound, coeff_before_j_is_pos, m_row_index, strict);
|
void limit_j(unsigned bound_j, const mpq& u, bool coeff_before_j_is_pos, bool is_lower_bound, bool strict){
|
||||||
|
lar_solver* lar = & this->m_bp.lp();
|
||||||
|
unsigned row_index = this->m_row_index;
|
||||||
|
auto explain = [lar, bound_j, coeff_before_j_is_pos, is_lower_bound, strict, row_index]() { return explain_bound_on_var_on_coeff(lar, bound_j, coeff_before_j_is_pos, is_lower_bound, strict, row_index); };
|
||||||
|
m_bp.add_bound(u, bound_j, is_lower_bound, strict, explain );
|
||||||
}
|
}
|
||||||
|
|
||||||
void advance_u(unsigned j) {
|
void advance_u(unsigned j) {
|
||||||
|
@ -335,6 +341,27 @@ private:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
static u_dependency* explain_bound_on_var_on_coeff(lar_solver* lar, unsigned bound_j, bool coeff_before_j_is_pos, bool is_lower_bound, bool strict, unsigned row_index) {
|
||||||
|
int bound_sign = (is_lower_bound ? 1 : -1);
|
||||||
|
int j_sign = (coeff_before_j_is_pos ? 1 : -1) * bound_sign;
|
||||||
|
|
||||||
|
if (tv::is_term(bound_j))
|
||||||
|
bound_j = lar->map_term_index_to_column_index(bound_j);
|
||||||
|
u_dependency* ret = nullptr;
|
||||||
|
for (auto const& r : lar->get_row(row_index)) {
|
||||||
|
unsigned j = r.var();
|
||||||
|
if (j == bound_j)
|
||||||
|
continue;
|
||||||
|
mpq const& a = r.coeff();
|
||||||
|
int a_sign = is_pos(a) ? 1 : -1;
|
||||||
|
int sign = j_sign * a_sign;
|
||||||
|
u_dependency* witness = sign > 0 ? lar->get_column_upper_bound_witness(j) : lar->get_column_lower_bound_witness(j);
|
||||||
|
ret = lar->join_deps(ret, witness);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,37 +21,34 @@ Revision History:
|
||||||
#include "math/lp/lp_settings.h"
|
#include "math/lp/lp_settings.h"
|
||||||
#include "math/lp/lar_constraints.h"
|
#include "math/lp/lar_constraints.h"
|
||||||
namespace lp {
|
namespace lp {
|
||||||
struct implied_bound {
|
class implied_bound {
|
||||||
|
public:
|
||||||
mpq m_bound;
|
mpq m_bound;
|
||||||
unsigned m_j; // the column for which the bound has been found
|
unsigned m_j; // the column for which the bound has been found
|
||||||
bool m_is_lower_bound;
|
bool m_is_lower_bound;
|
||||||
bool m_coeff_before_j_is_pos;
|
bool m_strict;
|
||||||
unsigned m_row_or_term_index;
|
private:
|
||||||
bool m_strict;
|
std::function<u_dependency*(void)> m_explain_bound = nullptr;
|
||||||
|
public:
|
||||||
|
u_dependency* explain() const { return m_explain_bound(); }
|
||||||
|
void set_explain(std::function<u_dependency*(void)> f) { m_explain_bound = f; }
|
||||||
lconstraint_kind kind() const {
|
lconstraint_kind kind() const {
|
||||||
lconstraint_kind k = m_is_lower_bound? GE : LE;
|
lconstraint_kind k = m_is_lower_bound? GE : LE;
|
||||||
if (m_strict)
|
if (m_strict)
|
||||||
k = static_cast<lconstraint_kind>(k / 2);
|
k = static_cast<lconstraint_kind>(k / 2);
|
||||||
return k;
|
return k;
|
||||||
}
|
}
|
||||||
bool operator==(const implied_bound & o) const {
|
|
||||||
return m_j == o.m_j && m_is_lower_bound == o.m_is_lower_bound && m_bound == o.m_bound &&
|
|
||||||
m_coeff_before_j_is_pos == o.m_coeff_before_j_is_pos &&
|
|
||||||
m_row_or_term_index == o.m_row_or_term_index && m_strict == o.m_strict;
|
|
||||||
}
|
|
||||||
implied_bound(){}
|
implied_bound(){}
|
||||||
implied_bound(const mpq & a,
|
implied_bound(const mpq & a,
|
||||||
unsigned j,
|
unsigned j,
|
||||||
bool lower_bound,
|
bool is_lower_bound,
|
||||||
bool coeff_before_j_is_pos,
|
bool is_strict,
|
||||||
unsigned row_or_term_index,
|
std::function<u_dependency*(void)> get_dep):
|
||||||
bool strict):
|
|
||||||
m_bound(a),
|
m_bound(a),
|
||||||
m_j(j),
|
m_j(j),
|
||||||
m_is_lower_bound(lower_bound),
|
m_is_lower_bound(is_lower_bound),
|
||||||
m_coeff_before_j_is_pos(coeff_before_j_is_pos),
|
m_strict(is_strict),
|
||||||
m_row_or_term_index(row_or_term_index),
|
m_explain_bound(get_dep) {
|
||||||
m_strict(strict) {
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -311,26 +311,34 @@ class lar_solver : public column_namer {
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void explain_implied_bound(const implied_bound& ib, lp_bound_propagator<T>& bp) {
|
void explain_implied_bound(const implied_bound& ib, lp_bound_propagator<T>& bp) {
|
||||||
unsigned i = ib.m_row_or_term_index;
|
u_dependency* dep = ib.explain();
|
||||||
int bound_sign = (ib.m_is_lower_bound ? 1 : -1);
|
for (auto ci : flatten(dep))
|
||||||
int j_sign = (ib.m_coeff_before_j_is_pos ? 1 : -1) * bound_sign;
|
bp.consume(mpq(1), ci); // TODO: flatten should provid the coefficients
|
||||||
unsigned bound_j = ib.m_j;
|
/*
|
||||||
if (tv::is_term(bound_j))
|
if (ib.m_is_monic) {
|
||||||
bound_j = m_var_register.external_to_local(bound_j);
|
NOT_IMPLEMENTED_YET();
|
||||||
|
} else {
|
||||||
|
unsigned i = ib.m_row_or_term_index;
|
||||||
|
int bound_sign = (ib.m_is_lower_bound ? 1 : -1);
|
||||||
|
int j_sign = (ib.m_coeff_before_j_is_pos ? 1 : -1) * bound_sign;
|
||||||
|
unsigned bound_j = ib.m_j;
|
||||||
|
if (tv::is_term(bound_j))
|
||||||
|
bound_j = m_var_register.external_to_local(bound_j);
|
||||||
|
|
||||||
for (auto const& r : get_row(i)) {
|
for (auto const& r : get_row(i)) {
|
||||||
unsigned j = r.var();
|
unsigned j = r.var();
|
||||||
if (j == bound_j)
|
if (j == bound_j)
|
||||||
continue;
|
continue;
|
||||||
mpq const& a = r.coeff();
|
mpq const& a = r.coeff();
|
||||||
int a_sign = is_pos(a) ? 1 : -1;
|
int a_sign = is_pos(a) ? 1 : -1;
|
||||||
int sign = j_sign * a_sign;
|
int sign = j_sign * a_sign;
|
||||||
const ul_pair& ul = m_columns_to_ul_pairs[j];
|
const ul_pair& ul = m_columns_to_ul_pairs[j];
|
||||||
auto* witness = sign > 0 ? ul.upper_bound_witness() : ul.lower_bound_witness();
|
auto* witness = sign > 0 ? ul.upper_bound_witness() : ul.lower_bound_witness();
|
||||||
lp_assert(witness);
|
lp_assert(witness);
|
||||||
for (auto ci : flatten(witness))
|
for (auto ci : flatten(witness))
|
||||||
bp.consume(a, ci);
|
bp.consume(a, ci);
|
||||||
}
|
}
|
||||||
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_value_for_nbasic_column(unsigned j, const impq& new_val);
|
void set_value_for_nbasic_column(unsigned j, const impq& new_val);
|
||||||
|
@ -564,6 +572,16 @@ class lar_solver : public column_namer {
|
||||||
const ul_pair& ul = m_columns_to_ul_pairs[j];
|
const ul_pair& ul = m_columns_to_ul_pairs[j];
|
||||||
return m_dependencies.mk_join(ul.lower_bound_witness(), ul.upper_bound_witness());
|
return m_dependencies.mk_join(ul.lower_bound_witness(), ul.upper_bound_witness());
|
||||||
}
|
}
|
||||||
|
template <typename T>
|
||||||
|
u_dependency* get_bound_constraint_witnesses_for_columns(const T& collection) {
|
||||||
|
u_dependency* dep = nullptr;
|
||||||
|
for (auto j : collection) {
|
||||||
|
u_dependency* d = get_bound_constraint_witnesses_for_column(j);
|
||||||
|
dep = m_dependencies.mk_join(dep, d);
|
||||||
|
}
|
||||||
|
return dep;
|
||||||
|
}
|
||||||
|
u_dependency* join_deps(u_dependency* a, u_dependency *b) { return m_dependencies.mk_join(a, b); }
|
||||||
inline constraint_set const& constraints() const { return m_constraints; }
|
inline constraint_set const& constraints() const { return m_constraints; }
|
||||||
void push();
|
void push();
|
||||||
void pop();
|
void pop();
|
||||||
|
|
|
@ -40,6 +40,7 @@ class lp_bound_propagator {
|
||||||
return x != UINT_MAX;
|
return x != UINT_MAX;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void try_add_equation_with_internal_fixed_tables(unsigned r1) {
|
void try_add_equation_with_internal_fixed_tables(unsigned r1) {
|
||||||
unsigned v1, v2;
|
unsigned v1, v2;
|
||||||
if (!only_one_nfixed(r1, v1))
|
if (!only_one_nfixed(r1, v1))
|
||||||
|
@ -94,6 +95,115 @@ class lp_bound_propagator {
|
||||||
m_ibounds.reset();
|
m_ibounds.reset();
|
||||||
m_column_types = &lp().get_column_types();
|
m_column_types = &lp().get_column_types();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool is_linear(const svector<lpvar>& m, lpvar& zero_var, lpvar& non_fixed) {
|
||||||
|
zero_var = non_fixed = null_lpvar;
|
||||||
|
unsigned n_of_non_fixed = 0;
|
||||||
|
bool big_bound = false;
|
||||||
|
for (lpvar v : m) {
|
||||||
|
if (!this->column_is_fixed(v)) {
|
||||||
|
n_of_non_fixed++;
|
||||||
|
non_fixed = v;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const auto & b = get_lower_bound(v).x;
|
||||||
|
if (b.is_zero()) {
|
||||||
|
zero_var = v;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (b.is_big()) {
|
||||||
|
big_bound |= true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return n_of_non_fixed <= 1 && !big_bound;
|
||||||
|
}
|
||||||
|
|
||||||
|
void add_bounds_for_zero_var(lpvar monic_var, lpvar zero_var) {
|
||||||
|
add_lower_bound_monic(monic_var, mpq(0), false, [&](){return lp().get_bound_constraint_witnesses_for_column(zero_var);});
|
||||||
|
add_upper_bound_monic(monic_var, mpq(0), false, [&](){return lp().get_bound_constraint_witnesses_for_column(zero_var);});
|
||||||
|
}
|
||||||
|
|
||||||
|
void add_lower_bound_monic(lpvar monic_var, const mpq& v, bool is_strict, std::function<u_dependency* ()> explain_dep) {
|
||||||
|
unsigned k;
|
||||||
|
if (!try_get_value(m_improved_lower_bounds, monic_var, k)) {
|
||||||
|
m_improved_lower_bounds[monic_var] = m_ibounds.size();
|
||||||
|
m_ibounds.push_back(implied_bound(v, monic_var, true, is_strict, explain_dep));
|
||||||
|
} else {
|
||||||
|
auto& found_bound = m_ibounds[k];
|
||||||
|
if (v > found_bound.m_bound || (v == found_bound.m_bound && !found_bound.m_strict && is_strict)) {
|
||||||
|
found_bound = implied_bound(v, monic_var, true, is_strict, explain_dep);
|
||||||
|
TRACE("add_bound", m_imp.lp().print_implied_bound(found_bound, tout););
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void add_upper_bound_monic(lpvar monic_var, const mpq& bound_val, bool is_strict, std::function <u_dependency* ()> explain_bound) {
|
||||||
|
unsigned k;
|
||||||
|
if (!try_get_value(m_improved_upper_bounds, monic_var, k)) {
|
||||||
|
m_improved_upper_bounds[monic_var] = m_ibounds.size();
|
||||||
|
m_ibounds.push_back(implied_bound(bound_val, monic_var, false, is_strict, explain_bound));
|
||||||
|
} else {
|
||||||
|
auto& found_bound = m_ibounds[k];
|
||||||
|
if (bound_val > found_bound.m_bound || (bound_val == found_bound.m_bound && !found_bound.m_strict && is_strict)) {
|
||||||
|
found_bound = implied_bound(bound_val, monic_var, false, is_strict, explain_bound);
|
||||||
|
TRACE("add_bound", m_imp.lp().print_implied_bound(found_bound, tout););
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void propagate_monic(lpvar monic_var, const svector<lpvar>& vars) {
|
||||||
|
lpvar non_fixed, zero_var;
|
||||||
|
if (!is_linear(vars, zero_var, non_fixed)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (zero_var != null_lpvar) {
|
||||||
|
add_bounds_for_zero_var(monic_var, zero_var);
|
||||||
|
} else {
|
||||||
|
if (non_fixed != null_lpvar && get_column_type(non_fixed) == column_type::free_column) return;
|
||||||
|
rational k = rational(1);
|
||||||
|
for (auto v : vars)
|
||||||
|
if (v != non_fixed) {
|
||||||
|
k *= lp().get_column_value(v).x;
|
||||||
|
if (k.is_big()) return;
|
||||||
|
}
|
||||||
|
u_dependency* dep;
|
||||||
|
lp::mpq bound_value;
|
||||||
|
bool is_strict;
|
||||||
|
if (non_fixed != null_lpvar) {
|
||||||
|
if (this->lp().has_lower_bound(non_fixed, dep, bound_value, is_strict)) {
|
||||||
|
if (k.is_pos())
|
||||||
|
add_lower_bound_monic(monic_var, k * bound_value, is_strict, [&]() { return dep; });
|
||||||
|
else
|
||||||
|
add_upper_bound_monic(monic_var, k * bound_value, is_strict, [&]() {return dep;});
|
||||||
|
}
|
||||||
|
if (this->lp().has_upper_bound(non_fixed, dep, bound_value, is_strict)) {
|
||||||
|
if (k.is_neg())
|
||||||
|
add_lower_bound_monic(monic_var, k * bound_value, is_strict, [&]() {return dep;});
|
||||||
|
else
|
||||||
|
add_upper_bound_monic(monic_var, k * bound_value, is_strict, [&]() {return dep;});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this->lp().has_lower_bound(monic_var, dep, bound_value, is_strict)) {
|
||||||
|
if (k.is_pos())
|
||||||
|
add_lower_bound_monic(non_fixed, bound_value / k, is_strict, [&]() {return dep;});
|
||||||
|
else
|
||||||
|
add_upper_bound_monic(non_fixed, bound_value / k, is_strict, [&]() {return dep;});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this->lp().has_upper_bound(monic_var, dep, bound_value, is_strict)) {
|
||||||
|
if (k.is_neg())
|
||||||
|
add_lower_bound_monic(non_fixed, bound_value / k, is_strict, [&]() {return dep;});
|
||||||
|
else
|
||||||
|
add_upper_bound_monic(non_fixed, bound_value / k, is_strict, [&]() {return dep;});
|
||||||
|
}
|
||||||
|
|
||||||
|
} else { // all variables are fixed
|
||||||
|
add_lower_bound_monic(monic_var, k, false, [&](){return lp().get_bound_constraint_witnesses_for_columns(vars);});
|
||||||
|
add_upper_bound_monic(monic_var, k, false, [&](){return lp().get_bound_constraint_witnesses_for_columns(vars);});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const lar_solver& lp() const { return m_imp.lp(); }
|
const lar_solver& lp() const { return m_imp.lp(); }
|
||||||
lar_solver& lp() { return m_imp.lp(); }
|
lar_solver& lp() { return m_imp.lp(); }
|
||||||
|
@ -123,7 +233,7 @@ class lp_bound_propagator {
|
||||||
return (*m_column_types)[j] == column_type::fixed && get_lower_bound(j).y.is_zero();
|
return (*m_column_types)[j] == column_type::fixed && get_lower_bound(j).y.is_zero();
|
||||||
}
|
}
|
||||||
|
|
||||||
void try_add_bound(mpq const& v, unsigned j, bool is_low, bool coeff_before_j_is_pos, unsigned row_or_term_index, bool strict) {
|
void add_bound(mpq const& v, unsigned j, bool is_low, bool strict, std::function<u_dependency* ()> explain_bound) {
|
||||||
j = m_imp.lp().column_to_reported_index(j);
|
j = m_imp.lp().column_to_reported_index(j);
|
||||||
|
|
||||||
lconstraint_kind kind = is_low ? GE : LE;
|
lconstraint_kind kind = is_low ? GE : LE;
|
||||||
|
@ -137,25 +247,29 @@ class lp_bound_propagator {
|
||||||
if (try_get_value(m_improved_lower_bounds, j, k)) {
|
if (try_get_value(m_improved_lower_bounds, j, k)) {
|
||||||
auto& found_bound = m_ibounds[k];
|
auto& found_bound = m_ibounds[k];
|
||||||
if (v > found_bound.m_bound || (v == found_bound.m_bound && !found_bound.m_strict && strict)) {
|
if (v > found_bound.m_bound || (v == found_bound.m_bound && !found_bound.m_strict && strict)) {
|
||||||
found_bound = implied_bound(v, j, is_low, coeff_before_j_is_pos, row_or_term_index, strict);
|
found_bound.m_bound = v;
|
||||||
TRACE("try_add_bound", m_imp.lp().print_implied_bound(found_bound, tout););
|
found_bound.m_strict = strict;
|
||||||
|
found_bound.set_explain(explain_bound);
|
||||||
|
TRACE("add_bound", m_imp.lp().print_implied_bound(found_bound, tout););
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
m_improved_lower_bounds[j] = m_ibounds.size();
|
m_improved_lower_bounds[j] = m_ibounds.size();
|
||||||
m_ibounds.push_back(implied_bound(v, j, is_low, coeff_before_j_is_pos, row_or_term_index, strict));
|
m_ibounds.push_back(implied_bound(v, j, is_low, strict, explain_bound));
|
||||||
TRACE("try_add_bound", m_imp.lp().print_implied_bound(m_ibounds.back(), tout););
|
TRACE("add_bound", m_imp.lp().print_implied_bound(m_ibounds.back(), tout););
|
||||||
}
|
}
|
||||||
} else { // the upper bound case
|
} else { // the upper bound case
|
||||||
if (try_get_value(m_improved_upper_bounds, j, k)) {
|
if (try_get_value(m_improved_upper_bounds, j, k)) {
|
||||||
auto& found_bound = m_ibounds[k];
|
auto& found_bound = m_ibounds[k];
|
||||||
if (v < found_bound.m_bound || (v == found_bound.m_bound && !found_bound.m_strict && strict)) {
|
if (v < found_bound.m_bound || (v == found_bound.m_bound && !found_bound.m_strict && strict)) {
|
||||||
found_bound = implied_bound(v, j, is_low, coeff_before_j_is_pos, row_or_term_index, strict);
|
found_bound.m_bound = v;
|
||||||
TRACE("try_add_bound", m_imp.lp().print_implied_bound(found_bound, tout););
|
found_bound.m_strict = strict;
|
||||||
|
found_bound.set_explain(explain_bound);
|
||||||
|
TRACE("add_bound", m_imp.lp().print_implied_bound(found_bound, tout););
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
m_improved_upper_bounds[j] = m_ibounds.size();
|
m_improved_upper_bounds[j] = m_ibounds.size();
|
||||||
m_ibounds.push_back(implied_bound(v, j, is_low, coeff_before_j_is_pos, row_or_term_index, strict));
|
m_ibounds.push_back(implied_bound(v, j, is_low, strict, explain_bound));
|
||||||
TRACE("try_add_bound", m_imp.lp().print_implied_bound(m_ibounds.back(), tout););
|
TRACE("add_bound", m_imp.lp().print_implied_bound(m_ibounds.back(), tout););
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -261,6 +261,7 @@ namespace nla {
|
||||||
void monomial_bounds::unit_propagate() {
|
void monomial_bounds::unit_propagate() {
|
||||||
for (lpvar v : c().m_monics_with_changed_bounds)
|
for (lpvar v : c().m_monics_with_changed_bounds)
|
||||||
unit_propagate(c().emons()[v]);
|
unit_propagate(c().emons()[v]);
|
||||||
|
c().m_monics_with_changed_bounds.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void monomial_bounds::unit_propagate(monic const& m) {
|
void monomial_bounds::unit_propagate(monic const& m) {
|
||||||
|
@ -268,68 +269,61 @@ namespace nla {
|
||||||
if (m_propagated[m.var()])
|
if (m_propagated[m.var()])
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!is_linear(m))
|
lpvar non_fixed = null_lpvar, zero_var = null_lpvar;
|
||||||
|
if (!is_linear(m, zero_var, non_fixed))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
c().trail().push(set_bitvector_trail(m_propagated, m.var()));
|
c().trail().push(set_bitvector_trail(m_propagated, m.var()));
|
||||||
|
|
||||||
rational k = fixed_var_product(m);
|
|
||||||
|
|
||||||
new_lemma lemma(c(), "fixed-values");
|
if (zero_var != null_lpvar) {
|
||||||
if (k == 0) {
|
new_lemma lemma(c(), "fixed-values");
|
||||||
for (auto v : m) {
|
lemma.explain_fixed(zero_var);
|
||||||
if (c().var_is_fixed(v) && c().val(v).is_zero()) {
|
|
||||||
lemma.explain_fixed(v);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
lemma += ineq(m.var(), lp::lconstraint_kind::EQ, 0);
|
lemma += ineq(m.var(), lp::lconstraint_kind::EQ, 0);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
rational k = rational(1);
|
||||||
for (auto v : m)
|
for (auto v : m)
|
||||||
if (c().var_is_fixed(v))
|
if (v != non_fixed) {
|
||||||
|
k *= c().lra.get_column_value(v).x;
|
||||||
|
if (k.is_big()) return;
|
||||||
|
}
|
||||||
|
|
||||||
|
new_lemma lemma(c(), "fixed-values");
|
||||||
|
|
||||||
|
for (auto v : m)
|
||||||
|
if (v != non_fixed)
|
||||||
lemma.explain_fixed(v);
|
lemma.explain_fixed(v);
|
||||||
|
|
||||||
lpvar w = non_fixed_var(m);
|
if (non_fixed != null_lpvar) {
|
||||||
if (w != null_lpvar) {
|
|
||||||
lp::lar_term term;
|
lp::lar_term term;
|
||||||
term.add_var(m.var());
|
term.add_var(m.var());
|
||||||
term.add_monomial(-k, w);
|
term.add_monomial(-k, non_fixed);
|
||||||
lemma += ineq(term, lp::lconstraint_kind::EQ, 0);
|
lemma += ineq(term, lp::lconstraint_kind::EQ, 0);
|
||||||
} else {
|
} else {
|
||||||
lemma += ineq(m.var(), lp::lconstraint_kind::EQ, k);
|
lemma += ineq(m.var(), lp::lconstraint_kind::EQ, k);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
// returns true iff (all variables are fixed,
|
||||||
bool monomial_bounds::is_linear(monic const& m) {
|
// or all but one variable are fixed) and the bounds are not big,
|
||||||
unsigned non_fixed = 0;
|
// or at least one variable is fixed to zero.
|
||||||
|
bool monomial_bounds::is_linear(monic const& m, lpvar& zero_var, lpvar& non_fixed) {
|
||||||
|
zero_var = non_fixed = null_lpvar;
|
||||||
|
unsigned n_of_non_fixed = 0;
|
||||||
|
bool big_bound = false;
|
||||||
for (lpvar v : m) {
|
for (lpvar v : m) {
|
||||||
if (!c().var_is_fixed(v))
|
if (!c().var_is_fixed(v)) {
|
||||||
++non_fixed;
|
n_of_non_fixed++;
|
||||||
else if (c().val(v).is_zero())
|
non_fixed = v;
|
||||||
|
} else if (c().var_is_fixed_to_zero(v)) {
|
||||||
|
zero_var = v;
|
||||||
return true;
|
return true;
|
||||||
|
} else if (c().fixed_var_has_big_bound(v)) {
|
||||||
|
big_bound |= true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return non_fixed <= 1;
|
return n_of_non_fixed <= 1 && !big_bound;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
rational monomial_bounds::fixed_var_product(monic const& m) {
|
|
||||||
rational r(1);
|
|
||||||
for (lpvar v : m) {
|
|
||||||
if (c().var_is_fixed(v))
|
|
||||||
r *= c().lra.get_column_value(v).x;
|
|
||||||
}
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
lpvar monomial_bounds::non_fixed_var(monic const& m) {
|
|
||||||
for (lpvar v : m)
|
|
||||||
if (!c().var_is_fixed(v))
|
|
||||||
return v;
|
|
||||||
return null_lpvar;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -33,10 +33,8 @@ namespace nla {
|
||||||
// monomial propagation
|
// monomial propagation
|
||||||
bool_vector m_propagated;
|
bool_vector m_propagated;
|
||||||
void unit_propagate(monic const& m);
|
void unit_propagate(monic const& m);
|
||||||
bool is_linear(monic const& m);
|
bool is_linear(monic const& m, lpvar& zero_var, lpvar& non_fixed);
|
||||||
rational fixed_var_product(monic const& m);
|
|
||||||
lpvar non_fixed_var(monic const& m);
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
monomial_bounds(core* core);
|
monomial_bounds(core* core);
|
||||||
void propagate();
|
void propagate();
|
||||||
|
|
|
@ -40,7 +40,6 @@ core::core(lp::lar_solver& s, params_ref const& p, reslimit& lim) : m_evars(),
|
||||||
m_nra(s, m_nra_lim, *this) {
|
m_nra(s, m_nra_lim, *this) {
|
||||||
m_nlsat_delay = lp_settings().nlsat_delay();
|
m_nlsat_delay = lp_settings().nlsat_delay();
|
||||||
lra.m_find_monics_with_changed_bounds_func = [&](const indexed_uint_set& columns_with_changed_bounds) {
|
lra.m_find_monics_with_changed_bounds_func = [&](const indexed_uint_set& columns_with_changed_bounds) {
|
||||||
m_monics_with_changed_bounds.clear();
|
|
||||||
for (const auto& m : m_emons) {
|
for (const auto& m : m_emons) {
|
||||||
if (columns_with_changed_bounds.contains(m.var())) {
|
if (columns_with_changed_bounds.contains(m.var())) {
|
||||||
m_monics_with_changed_bounds.push_back(m.var());
|
m_monics_with_changed_bounds.push_back(m.var());
|
||||||
|
@ -553,6 +552,13 @@ bool core::var_is_fixed_to_zero(lpvar j) const {
|
||||||
lra.column_is_fixed(j) &&
|
lra.column_is_fixed(j) &&
|
||||||
lra.get_lower_bound(j) == lp::zero_of_type<lp::impq>();
|
lra.get_lower_bound(j) == lp::zero_of_type<lp::impq>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool core::fixed_var_has_big_bound(lpvar j) const {
|
||||||
|
SASSERT(lra.column_is_fixed(j));
|
||||||
|
const auto& b = lra.get_lower_bound(j);
|
||||||
|
return b.x.is_big() || b.y.is_big();
|
||||||
|
}
|
||||||
|
|
||||||
bool core::var_is_fixed_to_val(lpvar j, const rational& v) const {
|
bool core::var_is_fixed_to_val(lpvar j, const rational& v) const {
|
||||||
return
|
return
|
||||||
lra.column_is_fixed(j) &&
|
lra.column_is_fixed(j) &&
|
||||||
|
|
|
@ -120,7 +120,8 @@ class core {
|
||||||
public:
|
public:
|
||||||
// constructor
|
// constructor
|
||||||
core(lp::lar_solver& s, params_ref const& p, reslimit&);
|
core(lp::lar_solver& s, params_ref const& p, reslimit&);
|
||||||
|
const auto& monics_with_changed_bounds() const { return m_monics_with_changed_bounds; }
|
||||||
|
void reset_monics_with_changed_bounds() { m_monics_with_changed_bounds.reset(); }
|
||||||
void insert_to_refine(lpvar j);
|
void insert_to_refine(lpvar j);
|
||||||
void erase_from_to_refine(lpvar j);
|
void erase_from_to_refine(lpvar j);
|
||||||
|
|
||||||
|
@ -310,6 +311,7 @@ public:
|
||||||
bool sign_contradiction(const monic& m) const;
|
bool sign_contradiction(const monic& m) const;
|
||||||
|
|
||||||
bool var_is_fixed_to_zero(lpvar j) const;
|
bool var_is_fixed_to_zero(lpvar j) const;
|
||||||
|
bool fixed_var_has_big_bound(lpvar j) const;
|
||||||
bool var_is_fixed_to_val(lpvar j, const rational& v) const;
|
bool var_is_fixed_to_val(lpvar j, const rational& v) const;
|
||||||
|
|
||||||
bool var_is_fixed(lpvar j) const;
|
bool var_is_fixed(lpvar j) const;
|
||||||
|
|
|
@ -26,7 +26,8 @@ namespace nla {
|
||||||
|
|
||||||
solver(lp::lar_solver& s, params_ref const& p, reslimit& limit);
|
solver(lp::lar_solver& s, params_ref const& p, reslimit& limit);
|
||||||
~solver();
|
~solver();
|
||||||
|
const auto& monics_with_changed_bounds() const { return m_core->monics_with_changed_bounds(); }
|
||||||
|
void reset_monics_with_changed_bounds() { m_core->reset_monics_with_changed_bounds(); }
|
||||||
void add_monic(lpvar v, unsigned sz, lpvar const* vs);
|
void add_monic(lpvar v, unsigned sz, lpvar const* vs);
|
||||||
void add_idivision(lpvar q, lpvar x, lpvar y);
|
void add_idivision(lpvar q, lpvar x, lpvar y);
|
||||||
void add_rdivision(lpvar q, lpvar x, lpvar y);
|
void add_rdivision(lpvar q, lpvar x, lpvar y);
|
||||||
|
|
|
@ -253,7 +253,7 @@ namespace arith {
|
||||||
first = false;
|
first = false;
|
||||||
reset_evidence();
|
reset_evidence();
|
||||||
m_explanation.clear();
|
m_explanation.clear();
|
||||||
lp().explain_implied_bound(be, m_bp);
|
be.explain();
|
||||||
}
|
}
|
||||||
CTRACE("arith", m_unassigned_bounds[v] == 0, tout << "missed bound\n";);
|
CTRACE("arith", m_unassigned_bounds[v] == 0, tout << "missed bound\n";);
|
||||||
updt_unassigned_bounds(v, -1);
|
updt_unassigned_bounds(v, -1);
|
||||||
|
|
|
@ -2150,7 +2150,7 @@ public:
|
||||||
case l_true:
|
case l_true:
|
||||||
propagate_basic_bounds();
|
propagate_basic_bounds();
|
||||||
propagate_bounds_with_lp_solver();
|
propagate_bounds_with_lp_solver();
|
||||||
propagate_nla();
|
propagate_bounds_with_nlp();
|
||||||
break;
|
break;
|
||||||
case l_undef:
|
case l_undef:
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
|
@ -2185,33 +2185,55 @@ public:
|
||||||
set_evidence(j, m_core, m_eqs);
|
set_evidence(j, m_core, m_eqs);
|
||||||
m_explanation.add_pair(j, v);
|
m_explanation.add_pair(j, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
void propagate_bounds_with_lp_solver() {
|
|
||||||
if (!should_propagate())
|
|
||||||
return;
|
|
||||||
|
|
||||||
m_bp.init();
|
|
||||||
lp().propagate_bounds_for_touched_rows(m_bp);
|
|
||||||
|
|
||||||
if (!m.inc())
|
|
||||||
return;
|
|
||||||
|
|
||||||
|
void finish_bound_propagation() {
|
||||||
if (is_infeasible()) {
|
if (is_infeasible()) {
|
||||||
get_infeasibility_explanation_and_set_conflict();
|
get_infeasibility_explanation_and_set_conflict();
|
||||||
// verbose_stream() << "unsat\n";
|
// verbose_stream() << "unsat\n";
|
||||||
}
|
} else {
|
||||||
else {
|
for (auto &ib : m_bp.ibounds()) {
|
||||||
unsigned count = 0, prop = 0;
|
|
||||||
for (auto& ib : m_bp.ibounds()) {
|
|
||||||
m.inc();
|
m.inc();
|
||||||
if (ctx().inconsistent())
|
if (ctx().inconsistent())
|
||||||
break;
|
break;
|
||||||
++prop;
|
propagate_lp_solver_bound(ib);
|
||||||
count += propagate_lp_solver_bound(ib);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void propagate_bounds_with_lp_solver() {
|
||||||
|
if (!should_propagate())
|
||||||
|
return;
|
||||||
|
m_bp.init();
|
||||||
|
lp().propagate_bounds_for_touched_rows(m_bp);
|
||||||
|
|
||||||
|
if (m.inc())
|
||||||
|
finish_bound_propagation();
|
||||||
|
}
|
||||||
|
|
||||||
|
void calculate_implied_bounds_for_monic(lpvar monic_var, const svector<lpvar>& vars) {
|
||||||
|
m_bp.propagate_monic(monic_var, vars);
|
||||||
|
}
|
||||||
|
|
||||||
|
void propagate_bounds_for_touched_monomials() {
|
||||||
|
for (unsigned v : m_nla->monics_with_changed_bounds()) {
|
||||||
|
calculate_implied_bounds_for_monic(v, m_nla->get_core().emons()[v].vars());
|
||||||
|
}
|
||||||
|
m_nla->reset_monics_with_changed_bounds();
|
||||||
|
}
|
||||||
|
|
||||||
|
void propagate_bounds_with_nlp() {
|
||||||
|
if (!m_nla)
|
||||||
|
return;
|
||||||
|
if (is_infeasible() || !should_propagate())
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_bp.init();
|
||||||
|
propagate_bounds_for_touched_monomials();
|
||||||
|
|
||||||
|
if (m.inc())
|
||||||
|
finish_bound_propagation();
|
||||||
|
}
|
||||||
|
|
||||||
bool bound_is_interesting(unsigned vi, lp::lconstraint_kind kind, const rational & bval) const {
|
bool bound_is_interesting(unsigned vi, lp::lconstraint_kind kind, const rational & bval) const {
|
||||||
theory_var v = lp().local_to_external(vi);
|
theory_var v = lp().local_to_external(vi);
|
||||||
if (v == null_theory_var)
|
if (v == null_theory_var)
|
||||||
|
|
Loading…
Reference in a new issue