mirror of
https://github.com/Z3Prover/z3
synced 2025-08-18 01:02:15 +00:00
propagate cheap eqs
Signed-off-by: Lev Nachmanson <levnach@hotmail.com>
This commit is contained in:
parent
865dfe0590
commit
1e4e887221
5 changed files with 78 additions and 82 deletions
|
@ -13,9 +13,8 @@ Abstract:
|
||||||
In the same loop trying to pin variables by pushing the partial sum up, denoting the variable related to it by _l
|
In the same loop trying to pin variables by pushing the partial sum up, denoting the variable related to it by _l
|
||||||
|
|
||||||
Author:
|
Author:
|
||||||
|
Lev Nachmanson (levnach)
|
||||||
Lev Nachmanson (levnach)
|
Nikolaj Bjorner (nbjorner)
|
||||||
|
|
||||||
Revision History:
|
Revision History:
|
||||||
|
|
||||||
|
|
||||||
|
@ -31,7 +30,7 @@ template <typename C, typename B> // C plays a role of a container, B - lp_bound
|
||||||
class bound_analyzer_on_row {
|
class bound_analyzer_on_row {
|
||||||
const C& m_row;
|
const C& m_row;
|
||||||
B & m_bp;
|
B & m_bp;
|
||||||
unsigned m_row_or_term_index;
|
unsigned m_row_index;
|
||||||
int m_column_of_u; // index of an unlimited from above monoid
|
int m_column_of_u; // index of an unlimited from above monoid
|
||||||
// -1 means that such a value is not found, -2 means that at least two of such monoids were found
|
// -1 means that such a value is not found, -2 means that at least two of such monoids were found
|
||||||
int m_column_of_l; // index of an unlimited from below monoid
|
int m_column_of_l; // index of an unlimited from below monoid
|
||||||
|
@ -48,7 +47,7 @@ public :
|
||||||
:
|
:
|
||||||
m_row(it),
|
m_row(it),
|
||||||
m_bp(bp),
|
m_bp(bp),
|
||||||
m_row_or_term_index(row_or_term_index),
|
m_row_index(row_or_term_index),
|
||||||
m_column_of_u(-1),
|
m_column_of_u(-1),
|
||||||
m_column_of_l(-1),
|
m_column_of_l(-1),
|
||||||
m_rs(rs)
|
m_rs(rs)
|
||||||
|
@ -62,7 +61,7 @@ public :
|
||||||
B & bp) {
|
B & bp) {
|
||||||
bound_analyzer_on_row a(row, bj, rs, row_or_term_index, bp);
|
bound_analyzer_on_row a(row, bj, rs, row_or_term_index, bp);
|
||||||
a.analyze();
|
a.analyze();
|
||||||
// TBD: a.analyze_eq();
|
a.analyze_eq();
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -84,37 +83,6 @@ private:
|
||||||
limit_all_monoids_from_above();
|
limit_all_monoids_from_above();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void analyze_eq() {
|
|
||||||
lpvar x = null_lpvar, y = null_lpvar;
|
|
||||||
for (const auto & c : m_row) {
|
|
||||||
if (m_bp.get_column_type(c.var()) == column_type::fixed)
|
|
||||||
continue;
|
|
||||||
if (x == null_lpvar && c.coeff().is_one())
|
|
||||||
x = c.var();
|
|
||||||
else if (y == null_lpvar && c.coeff().is_minus_one())
|
|
||||||
y = c.var();
|
|
||||||
else
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (x == null_lpvar || y == null_lpvar)
|
|
||||||
return;
|
|
||||||
impq value;
|
|
||||||
for (const auto & c : m_row) {
|
|
||||||
if (m_bp.get_column_type(c.var()) == column_type::fixed)
|
|
||||||
value += c.coeff() * lb(c.var());
|
|
||||||
}
|
|
||||||
if (!value.is_zero()) {
|
|
||||||
// insert / check offset table to infer equalities
|
|
||||||
// of the form y = z from offset table collision:
|
|
||||||
// value = (x - y)
|
|
||||||
// value = (x - z)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// m_bp.try_add_fixed(x, y, m_row_or_term_index);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool bound_is_available(unsigned j, bool lower_bound) {
|
bool bound_is_available(unsigned j, bool lower_bound) {
|
||||||
return (lower_bound && lower_bound_is_available(j)) ||
|
return (lower_bound && lower_bound_is_available(j)) ||
|
||||||
(!lower_bound && upper_bound_is_available(j));
|
(!lower_bound && upper_bound_is_available(j));
|
||||||
|
@ -327,7 +295,7 @@ private:
|
||||||
// }
|
// }
|
||||||
|
|
||||||
void limit_j(unsigned j, const mpq& u, bool coeff_before_j_is_pos, bool is_lower_bound, bool strict){
|
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_or_term_index, strict);
|
m_bp.try_add_bound(u, j, is_lower_bound, coeff_before_j_is_pos, m_row_index, strict);
|
||||||
}
|
}
|
||||||
|
|
||||||
void advance_u(unsigned j) {
|
void advance_u(unsigned j) {
|
||||||
|
@ -361,6 +329,24 @@ private:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void analyze_eq() {
|
||||||
|
unsigned x = UINT_MAX, y = UINT_MAX;
|
||||||
|
unsigned k = 0;
|
||||||
|
for (const auto& c : m_row) {
|
||||||
|
if (!m_bp.lp().column_is_fixed(c.var())) {
|
||||||
|
if (x == UINT_MAX && c.coeff().is_one())
|
||||||
|
x = k;
|
||||||
|
else if (y == UINT_MAX && c.coeff().is_minus_one())
|
||||||
|
y = k;
|
||||||
|
else
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
k++;
|
||||||
|
}
|
||||||
|
if (x == UINT_MAX || y == UINT_MAX)
|
||||||
|
return;
|
||||||
|
m_bp.try_create_eq(x, y, m_row_index);
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -83,7 +83,7 @@ public:
|
||||||
return m_data.size();
|
return m_data.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned size() {
|
unsigned size() const {
|
||||||
return m_index.size();
|
return m_index.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -161,20 +161,7 @@ class lar_solver : public column_namer {
|
||||||
bool use_lu() const;
|
bool use_lu() const;
|
||||||
bool sizes_are_correct() const;
|
bool sizes_are_correct() const;
|
||||||
bool implied_bound_is_correctly_explained(implied_bound const & be, const vector<std::pair<mpq, unsigned>> & explanation) const;
|
bool implied_bound_is_correctly_explained(implied_bound const & be, const vector<std::pair<mpq, unsigned>> & explanation) const;
|
||||||
template <typename T>
|
|
||||||
void analyze_new_bounds_on_row(
|
|
||||||
unsigned row_index,
|
|
||||||
lp_bound_propagator<T>& bp) {
|
|
||||||
lp_assert(!use_tableau());
|
|
||||||
unsigned j = m_mpq_lar_core_solver.m_r_basis[row_index]; // basis column for the row
|
|
||||||
bound_analyzer_on_row<indexed_vector<mpq>, lp_bound_propagator<T>>::analyze_row(
|
|
||||||
m_mpq_lar_core_solver.get_pivot_row(),
|
|
||||||
j,
|
|
||||||
zero_of_type<numeric_pair<mpq>>(),
|
|
||||||
row_index,
|
|
||||||
bp);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void analyze_new_bounds_on_row_tableau(
|
void analyze_new_bounds_on_row_tableau(
|
||||||
unsigned row_index,
|
unsigned row_index,
|
||||||
|
@ -196,17 +183,8 @@ class lar_solver : public column_namer {
|
||||||
void substitute_basis_var_in_terms_for_row(unsigned i);
|
void substitute_basis_var_in_terms_for_row(unsigned i);
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void calculate_implied_bounds_for_row(unsigned i, lp_bound_propagator<T> & bp) {
|
void calculate_implied_bounds_for_row(unsigned i, lp_bound_propagator<T> & bp) {
|
||||||
if (use_tableau()) {
|
SASSERT(use_tableau());
|
||||||
analyze_new_bounds_on_row_tableau(i, bp);
|
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
template <typename T>
|
|
||||||
void propagate_bounds_on_a_term(const lar_term& t, lp_bound_propagator<T> & bp, unsigned term_offset) {
|
|
||||||
NOT_IMPLEMENTED_YET();
|
|
||||||
}
|
}
|
||||||
static void clean_popped_elements(unsigned n, u_set& set);
|
static void clean_popped_elements(unsigned n, u_set& set);
|
||||||
static void shrink_inf_set_after_pop(unsigned n, u_set & set);
|
static void shrink_inf_set_after_pop(unsigned n, u_set & set);
|
||||||
|
@ -346,28 +324,14 @@ public:
|
||||||
void activate(constraint_index ci);
|
void activate(constraint_index ci);
|
||||||
void random_update(unsigned sz, var_index const * vars);
|
void random_update(unsigned sz, var_index const * vars);
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void propagate_bounds_on_terms(lp_bound_propagator<T> & bp) {
|
|
||||||
for (unsigned i = 0; i < m_terms.size(); i++) {
|
|
||||||
if (term_is_used_as_row(i))
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
template <typename T>
|
|
||||||
void propagate_bounds_for_touched_rows(lp_bound_propagator<T> & bp) {
|
void propagate_bounds_for_touched_rows(lp_bound_propagator<T> & bp) {
|
||||||
if (!use_tableau())
|
SASSERT(use_tableau());
|
||||||
return; // todo: consider to remove the restriction
|
|
||||||
|
|
||||||
for (unsigned i : m_rows_with_changed_bounds) {
|
for (unsigned i : m_rows_with_changed_bounds) {
|
||||||
calculate_implied_bounds_for_row(i, bp);
|
calculate_implied_bounds_for_row(i, bp);
|
||||||
if (settings().get_cancel_flag())
|
if (settings().get_cancel_flag())
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
m_rows_with_changed_bounds.clear();
|
m_rows_with_changed_bounds.clear();
|
||||||
if (!use_tableau()) {
|
|
||||||
propagate_bounds_on_terms(bp);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
bool is_fixed(column_index const& j) const { return column_is_fixed(j); }
|
bool is_fixed(column_index const& j) const { return column_is_fixed(j); }
|
||||||
inline column_index to_column_index(unsigned v) const { return column_index(external_to_column_index(v)); }
|
inline column_index to_column_index(unsigned v) const { return column_index(external_to_column_index(v)); }
|
||||||
|
@ -591,7 +555,7 @@ public:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
void round_to_integer_solution();
|
void round_to_integer_solution();
|
||||||
inline const row_strip<mpq> & get_row(unsigned i) { return A_r().m_rows[i]; }
|
inline const row_strip<mpq> & get_row(unsigned i) const { return A_r().m_rows[i]; }
|
||||||
bool row_is_correct(unsigned i) const;
|
bool row_is_correct(unsigned i) const;
|
||||||
bool ax_is_correct() const;
|
bool ax_is_correct() const;
|
||||||
bool get_equality_and_right_side_for_term_on_current_x(tv const& t, mpq &rs, constraint_index& ci, bool &upper_bound) const;
|
bool get_equality_and_right_side_for_term_on_current_x(tv const& t, mpq &rs, constraint_index& ci, bool &upper_bound) const;
|
||||||
|
|
|
@ -1,18 +1,40 @@
|
||||||
/*
|
/*
|
||||||
Copyright (c) 2017 Microsoft Corporation
|
Copyright (c) 2017 Microsoft Corporation
|
||||||
Author: Lev Nachmanson
|
Author:
|
||||||
|
Nickolaj Bjorner (nbjorner)
|
||||||
|
Lev Nachmanson (levnach)
|
||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "math/lp/lp_settings.h"
|
#include "math/lp/lp_settings.h"
|
||||||
namespace lp {
|
namespace lp {
|
||||||
template <typename T>
|
template <typename T>
|
||||||
class lp_bound_propagator {
|
class lp_bound_propagator {
|
||||||
|
|
||||||
|
// defining a graph on columns x, y such that there is a row x - y = c, where c is a constant
|
||||||
|
struct vertex {
|
||||||
|
unsigned m_row;
|
||||||
|
unsigned m_index; // in the row
|
||||||
|
bool m_sign; // true if the vertex plays the role of y
|
||||||
|
vector<unsigned> m_adjacent_edges; // points to the
|
||||||
|
vertex(unsigned row, unsigned index) : m_row(row), m_index(index) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
// an edge can be between columns in the same row or between two different rows in the same column
|
||||||
|
struct edge {
|
||||||
|
unsigned m_a;
|
||||||
|
unsigned m_b;
|
||||||
|
impq m_offset;
|
||||||
|
};
|
||||||
|
vector<vertex> m_vertices;
|
||||||
|
vector<edge> m_edges;
|
||||||
|
|
||||||
std::unordered_map<unsigned, unsigned> m_improved_lower_bounds; // these maps map a column index to the corresponding index in ibounds
|
std::unordered_map<unsigned, unsigned> m_improved_lower_bounds; // these maps map a column index to the corresponding index in ibounds
|
||||||
std::unordered_map<unsigned, unsigned> m_improved_upper_bounds;
|
std::unordered_map<unsigned, unsigned> m_improved_upper_bounds;
|
||||||
T& m_imp;
|
T& m_imp;
|
||||||
public:
|
public:
|
||||||
vector<implied_bound> m_ibounds;
|
vector<implied_bound> m_ibounds;
|
||||||
lp_bound_propagator(T& imp): m_imp(imp) {}
|
lp_bound_propagator(T& imp): m_imp(imp) {}
|
||||||
|
const lar_solver& lp() const { return m_imp.lp(); }
|
||||||
column_type get_column_type(unsigned j) const {
|
column_type get_column_type(unsigned j) const {
|
||||||
return m_imp.lp().get_column_type(j);
|
return m_imp.lp().get_column_type(j);
|
||||||
}
|
}
|
||||||
|
@ -65,5 +87,30 @@ public:
|
||||||
void consume(const mpq& a, constraint_index ci) {
|
void consume(const mpq& a, constraint_index ci) {
|
||||||
m_imp.consume(a, ci);
|
m_imp.consume(a, ci);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void create_initial_xy(unsigned x, unsigned y, unsigned row_index) {
|
||||||
|
impq value;
|
||||||
|
const auto& row = lp().get_row(row_index);
|
||||||
|
for (unsigned k = 0; k < row.size(); k++) {
|
||||||
|
if (k == x || k == y)
|
||||||
|
continue;
|
||||||
|
const auto& c = row[k];
|
||||||
|
value += c.coeff() * lp().get_lower_bound(c.var());
|
||||||
|
}
|
||||||
|
vertex xv(row_index, x);
|
||||||
|
m_vertices.push_back(xv);
|
||||||
|
vertex yv(row_index, y);
|
||||||
|
m_vertices.push_back(yv);
|
||||||
|
|
||||||
|
NOT_IMPLEMENTED_YET();
|
||||||
|
}
|
||||||
|
|
||||||
|
void try_create_eq(unsigned x, unsigned y, unsigned row_index) {
|
||||||
|
m_vertices.clear();
|
||||||
|
m_edges.clear();
|
||||||
|
create_initial_xy(x, y, row_index);
|
||||||
|
NOT_IMPLEMENTED_YET();
|
||||||
|
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -4033,4 +4033,3 @@ template class lp::lp_bound_propagator<smt::theory_lra::imp>;
|
||||||
template void lp::lar_solver::propagate_bounds_for_touched_rows<smt::theory_lra::imp>(lp::lp_bound_propagator<smt::theory_lra::imp>&);
|
template void lp::lar_solver::propagate_bounds_for_touched_rows<smt::theory_lra::imp>(lp::lp_bound_propagator<smt::theory_lra::imp>&);
|
||||||
template void lp::lar_solver::explain_implied_bound<smt::theory_lra::imp>(lp::implied_bound&, lp::lp_bound_propagator<smt::theory_lra::imp>&);
|
template void lp::lar_solver::explain_implied_bound<smt::theory_lra::imp>(lp::implied_bound&, lp::lp_bound_propagator<smt::theory_lra::imp>&);
|
||||||
template void lp::lar_solver::calculate_implied_bounds_for_row<smt::theory_lra::imp>(unsigned int, lp::lp_bound_propagator<smt::theory_lra::imp>&);
|
template void lp::lar_solver::calculate_implied_bounds_for_row<smt::theory_lra::imp>(unsigned int, lp::lp_bound_propagator<smt::theory_lra::imp>&);
|
||||||
template void lp::lar_solver::propagate_bounds_on_terms<smt::theory_lra::imp>(lp::lp_bound_propagator<smt::theory_lra::imp>&);
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue