mirror of
https://github.com/Z3Prover/z3
synced 2025-04-24 17:45:32 +00:00
test 1
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
parent
82a364ed7b
commit
20277f4a3f
5 changed files with 250 additions and 72 deletions
|
@ -60,9 +60,9 @@ namespace polysat {
|
|||
struct var_info {
|
||||
unsigned m_base2row:29;
|
||||
unsigned m_is_base:1;
|
||||
numeral m_lo;
|
||||
numeral m_hi;
|
||||
numeral m_value;
|
||||
numeral m_lo { 0 };
|
||||
numeral m_hi { 0 };
|
||||
numeral m_value { 0 };
|
||||
var_info():
|
||||
m_base2row(0),
|
||||
m_is_base(false)
|
||||
|
@ -75,19 +75,19 @@ namespace polysat {
|
|||
numeral m_base_coeff;
|
||||
};
|
||||
|
||||
static const var_t null_var = 0;
|
||||
static const var_t null_var = UINT_MAX;
|
||||
reslimit& m_limit;
|
||||
mutable manager m;
|
||||
mutable matrix M;
|
||||
unsigned m_max_iterations;
|
||||
unsigned m_max_iterations { UINT_MAX };
|
||||
var_heap m_to_patch;
|
||||
vector<var_info> m_vars;
|
||||
vector<row_info> m_rows;
|
||||
bool m_bland;
|
||||
unsigned m_blands_rule_threshold;
|
||||
bool m_bland { false };
|
||||
unsigned m_blands_rule_threshold { 1000 };
|
||||
random_gen m_random;
|
||||
uint_set m_left_basis;
|
||||
unsigned m_infeasible_var;
|
||||
unsigned m_infeasible_var { null_var };
|
||||
unsigned_vector m_base_vars;
|
||||
stats m_stats;
|
||||
|
||||
|
@ -95,10 +95,7 @@ namespace polysat {
|
|||
fixplex(reslimit& lim):
|
||||
m_limit(lim),
|
||||
M(m),
|
||||
m_max_iterations(UINT_MAX),
|
||||
m_to_patch(1024),
|
||||
m_bland(false),
|
||||
m_blands_rule_threshold(1000) {}
|
||||
m_to_patch(1024) {}
|
||||
|
||||
~fixplex();
|
||||
|
||||
|
@ -106,33 +103,29 @@ namespace polysat {
|
|||
typedef typename matrix::row_iterator row_iterator;
|
||||
typedef typename matrix::col_iterator col_iterator;
|
||||
|
||||
void set_lo(var_t var, numeral const& b) { m_vars[var].m_lo = b; }
|
||||
void set_hi(var_t var, numeral const& b) { m_vars[var].m_hi = b; }
|
||||
void set_bounds(var_t v, numeral const& lo, numeral const& hi);
|
||||
void unset_bounds(var_t v) { m_vars[v].m_lo = m_vars[v].m_hi; }
|
||||
|
||||
var_t get_base_var(row const& r) const { return m_rows[r.id()].m_base; }
|
||||
numeral const& lo(var_t var) const { return m_vars[var].m_lo; }
|
||||
numeral const& hi(var_t var) const { return m_vars[var].m_hi; }
|
||||
numeral const& value(var_t var) const { return m_vars[var].m_value; }
|
||||
void set_max_iterations(unsigned n) { m_max_iterations = n; }
|
||||
row_iterator row_begin(row const& r) { return M.row_begin(r); }
|
||||
row_iterator row_end(row const& r) { return M.row_end(r); }
|
||||
unsigned get_num_vars() const { return m_vars.size(); }
|
||||
void ensure_var(var_t v);
|
||||
void reset();
|
||||
lbool make_feasible();
|
||||
row add_row(var_t base, unsigned num_vars, var_t const* vars, numeral const* coeffs);
|
||||
row add_row(var_t base, unsigned num_vars, var_t const* vars, numeral const* coeffs);
|
||||
std::ostream& display(std::ostream& out) const;
|
||||
void display_row(std::ostream& out, row const& r, bool values = true);
|
||||
void collect_statistics(::statistics & st) const;
|
||||
|
||||
row get_infeasible_row();
|
||||
|
||||
#if 0
|
||||
// TBD
|
||||
row get_infeasible_row() { throw nullptr; }
|
||||
void del_row(var_t base_var) {}
|
||||
bool in_range(var_t var, numeral const& b) const {}
|
||||
void unset_lo(var_t var) {}
|
||||
void unset_hi(var_t var) {}
|
||||
void set_value(var_t var, numeral const& b) {}
|
||||
numeral const& get_value(var_t v) { throw nullptr; }
|
||||
void display(std::ostream& out) const {}
|
||||
void display_row(std::ostream& out, row const& r, bool values = true) {}
|
||||
void collect_statistics(::statistics & st) const {}
|
||||
void del_row(var_t base_var) {}
|
||||
#endif
|
||||
|
||||
|
||||
private:
|
||||
|
||||
|
@ -140,41 +133,45 @@ namespace polysat {
|
|||
void make_basic(var_t v, row const& r);
|
||||
|
||||
void update_value_core(var_t v, numeral const& delta);
|
||||
void ensure_var(var_t v);
|
||||
|
||||
|
||||
// TBD:
|
||||
void del_row(row const& r) {}
|
||||
var_t select_var_to_fix() { throw nullptr; }
|
||||
pivot_strategy_t pivot_strategy() { throw nullptr; }
|
||||
var_t select_smallest_var() { return m_to_patch.empty()?null_var:m_to_patch.erase_min(); }
|
||||
var_t select_error_var(bool least) { throw nullptr; }
|
||||
void check_blands_rule(var_t v, unsigned& num_repeated) {}
|
||||
lbool make_var_feasible(var_t x_i);
|
||||
bool is_infeasible_row(var_t x);
|
||||
void pivot(var_t x_i, var_t x_j, numeral const& b, numeral const& new_value);
|
||||
void update_value(var_t v, numeral const& delta);
|
||||
bool can_pivot(var_t x_i, numeral const& new_value, numeral const& a_ij, var_t x_j);
|
||||
bool has_minimal_trailing_zeros(var_t y, numeral const& b);
|
||||
var_t select_pivot_core(var_t x, numeral const& delta, numeral const& new_value, numeral& out_b);
|
||||
numeral new_value(var_t v) const;
|
||||
bool in_bounds(var_t v) const { return in_bounds(v, value(v)); }
|
||||
bool in_bounds(var_t v, numeral const& b) const { return in_bounds(b, lo(v), hi(v)); }
|
||||
bool in_bounds(numeral const& val, numeral const& lo, numeral const& hi) const;
|
||||
bool is_free(var_t v) const { return lo(v) == hi(v); }
|
||||
bool is_non_free(var_t v) const { return !is_free(v); }
|
||||
bool is_base(var_t x) const { return m_vars[x].m_is_base; }
|
||||
bool is_feasible() const;
|
||||
int get_num_non_free_dep_vars(var_t x_j, int best_so_far);
|
||||
void add_patch(var_t v);
|
||||
var_t select_var_to_fix();
|
||||
void check_blands_rule(var_t v, unsigned& num_repeated);
|
||||
pivot_strategy_t pivot_strategy() { return m_bland ? S_BLAND : S_DEFAULT; }
|
||||
var_t select_error_var(bool least);
|
||||
|
||||
bool well_formed() const;
|
||||
bool well_formed_row(row const& r) const;
|
||||
|
||||
|
||||
#if 0
|
||||
// TBD:
|
||||
void del_row(row const& r) {}
|
||||
void move_to_bound(var_t x, bool to_lower) {}
|
||||
bool can_pivot(var_t x_i, numeral const& new_value, numeral const& a_ij, var_t x_j);
|
||||
bool has_minimal_trailing_zeros(var_t y, numeral const& b);
|
||||
var_t select_pivot(var_t x_i, bool is_below, numeral& out_a_ij) { throw nullptr; }
|
||||
var_t select_pivot_blands(var_t x_i, bool is_below, numeral& out_a_ij) { throw nullptr; }
|
||||
var_t select_pivot_core(var_t x, numeral const& delta, numeral const& new_value, numeral& out_b);
|
||||
int get_num_non_free_dep_vars(var_t x_j, int best_so_far) { throw nullptr; }
|
||||
var_t pick_var_to_leave(var_t x_j, bool is_pos,
|
||||
numeral& gain, numeral& new_a_ij, bool& inc) { throw nullptr; }
|
||||
|
||||
void select_pivot_primal(var_t v, var_t& x_i, var_t& x_j, numeral& a_ij, bool& inc_x_i, bool& inc_x_j) {}
|
||||
numeral new_value(var_t v) const;
|
||||
bool in_bounds(var_t v) const;
|
||||
bool in_bounds(numeral const& val, numeral const& lo, numeral const& hi) const;
|
||||
bool is_free(var_t v) const { return m_vars[v].m_lo == m_vars[v].m_hi; }
|
||||
bool is_non_free(var_t v) const { return !is_free(v); }
|
||||
bool is_base(var_t x) const { return m_vars[x].m_is_base; }
|
||||
void add_patch(var_t v) {}
|
||||
|
||||
bool well_formed() const { return false; }
|
||||
bool well_formed_row(row const& r) const { return false; }
|
||||
bool is_feasible() const { return false; }
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
|
@ -200,9 +197,15 @@ namespace polysat {
|
|||
// treat numerals as signed and check for overflow/underflow
|
||||
bool signed_mul(numeral& r, numeral const& x, numeral const& y) { r = x * y; return true; }
|
||||
bool signed_add(numeral& r, numeral const& x, numeral const& y) { r = x + y; return true; }
|
||||
std::ostream& display(std::ostream& out, numeral const& x) const { return out << x; }
|
||||
};
|
||||
typedef _scoped_numeral<manager> scoped_numeral;
|
||||
};
|
||||
|
||||
template<typename Ext>
|
||||
inline std::ostream& operator<<(std::ostream& out, fixplex<Ext> const& fp) {
|
||||
return fp.display(out);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -46,8 +46,6 @@ namespace polysat {
|
|||
m_rows.reset();
|
||||
m_left_basis.reset();
|
||||
m_base_vars.reset();
|
||||
|
||||
// pivot(0,1, 2);
|
||||
}
|
||||
|
||||
template<typename Ext>
|
||||
|
@ -61,10 +59,9 @@ namespace polysat {
|
|||
m_bland = false;
|
||||
SASSERT(well_formed());
|
||||
while ((v = select_var_to_fix()) != null_var) {
|
||||
TRACE("simplex", display(tout << "v" << v << "\n"););
|
||||
if (!m_limit.inc() || num_iterations > m_max_iterations) {
|
||||
TRACE("polysat", display(tout << "v" << v << "\n"););
|
||||
if (!m_limit.inc() || num_iterations > m_max_iterations)
|
||||
return l_undef;
|
||||
}
|
||||
check_blands_rule(v, num_repeated);
|
||||
switch (make_var_feasible(v)) {
|
||||
case l_true:
|
||||
|
@ -87,6 +84,9 @@ namespace polysat {
|
|||
template<typename Ext>
|
||||
typename fixplex<Ext>::row
|
||||
fixplex<Ext>::add_row(var_t base_var, unsigned num_vars, var_t const* vars, numeral const* coeffs) {
|
||||
for (unsigned i = 0; i < num_vars; ++i)
|
||||
ensure_var(vars[i]);
|
||||
|
||||
m_base_vars.reset();
|
||||
row r = M.mk_row();
|
||||
for (unsigned i = 0; i < num_vars; ++i)
|
||||
|
@ -179,11 +179,6 @@ namespace polysat {
|
|||
|
||||
}
|
||||
|
||||
template<typename Ext>
|
||||
bool fixplex<Ext>::in_bounds(var_t v) const {
|
||||
return in_bounds(value(v), lo(v), hi(v));
|
||||
}
|
||||
|
||||
template<typename Ext>
|
||||
bool fixplex<Ext>::in_bounds(numeral const& val, numeral const& lo, numeral const& hi) const {
|
||||
if (lo == hi)
|
||||
|
@ -193,7 +188,6 @@ namespace polysat {
|
|||
return val < hi || lo <= val;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Attempt to improve assigment to make x feasible.
|
||||
*
|
||||
|
@ -254,7 +248,7 @@ namespace polysat {
|
|||
int best_so_far = INT_MAX;
|
||||
numeral row_value = m_rows[r.id()].m_value;
|
||||
numeral a = m_rows[r.id()].m_base_coeff;
|
||||
numeral delta_y;
|
||||
numeral delta_y = 0;
|
||||
numeral delta_best = 0;
|
||||
bool best_in_bounds = false;
|
||||
|
||||
|
@ -288,7 +282,7 @@ namespace polysat {
|
|||
is_improvement = true;
|
||||
else if (best_in_bounds && _in_bounds && num == best_so_far && col_sz < best_col_sz)
|
||||
is_improvement = true;
|
||||
else if (best_in_bounds && delta_y == delta_best && best_so_far == num && col_sz == best_col_sz)
|
||||
else if (best_in_bounds && !_in_bounds && delta_y == delta_best && best_so_far == num && col_sz == best_col_sz)
|
||||
is_plateau = true;
|
||||
|
||||
if (is_improvement) {
|
||||
|
@ -310,6 +304,20 @@ namespace polysat {
|
|||
return result < max ? result : null_var;
|
||||
}
|
||||
|
||||
template<typename Ext>
|
||||
void fixplex<Ext>::set_bounds(var_t v, numeral const& lo, numeral const& hi) {
|
||||
m_vars[v].m_lo = lo;
|
||||
m_vars[v].m_hi = hi;
|
||||
if (in_bounds(v))
|
||||
return;
|
||||
if (is_base(v))
|
||||
add_patch(v);
|
||||
else {
|
||||
NOT_IMPLEMENTED_YET();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<typename Ext>
|
||||
bool fixplex<Ext>::has_minimal_trailing_zeros(var_t y, numeral const& b) {
|
||||
unsigned tz1 = trailing_zeros(b);
|
||||
|
@ -426,6 +434,169 @@ namespace polysat {
|
|||
SASSERT(well_formed());
|
||||
}
|
||||
|
||||
template<typename Ext>
|
||||
bool fixplex<Ext>::is_feasible() const {
|
||||
for (unsigned i = m_vars.size(); i-- > 0; )
|
||||
if (!in_bounds(i))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename Ext>
|
||||
typename fixplex<Ext>::row
|
||||
fixplex<Ext>::get_infeasible_row() {
|
||||
SASSERT(is_base(m_infeasible_var));
|
||||
unsigned row_id = m_vars[m_infeasible_var].m_base2row;
|
||||
return row(row_id);
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Return the number of base variables that are non free and are v dependent.
|
||||
The function adds 1 to the result if v is non free.
|
||||
The function returns with a partial result r if r > best_so_far.
|
||||
This function is used to select the pivot variable.
|
||||
*/
|
||||
template<typename Ext>
|
||||
int fixplex<Ext>::get_num_non_free_dep_vars(var_t x_j, int best_so_far) {
|
||||
int result = is_non_free(x_j);
|
||||
for (auto const& col : M.col_entries(x_j)) {
|
||||
var_t s = m_rows[col.get_row().id()].m_base;
|
||||
result += is_non_free(s);
|
||||
if (result > best_so_far)
|
||||
return result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template<typename Ext>
|
||||
void fixplex<Ext>::add_patch(var_t v) {
|
||||
SASSERT(is_base(v));
|
||||
CTRACE("polysat", !in_bounds(v), tout << "Add patch: v" << v << "\n";);
|
||||
if (!in_bounds(v))
|
||||
m_to_patch.insert(v);
|
||||
}
|
||||
|
||||
template<typename Ext>
|
||||
var_t fixplex<Ext>::select_var_to_fix() {
|
||||
switch (pivot_strategy()) {
|
||||
case S_BLAND:
|
||||
return select_smallest_var();
|
||||
case S_GREATEST_ERROR:
|
||||
return select_error_var(false);
|
||||
case S_LEAST_ERROR:
|
||||
return select_error_var(true);
|
||||
default:
|
||||
return select_smallest_var();
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Ext>
|
||||
var_t fixplex<Ext>::select_error_var(bool least) {
|
||||
var_t best = null_var;
|
||||
numeral best_error = 0, curr_error = 0;
|
||||
for (var_t v : m_to_patch) {
|
||||
if (in_bounds(v))
|
||||
continue;
|
||||
if (lo(v) - value(v) < value(v) - hi(v))
|
||||
curr_error = lo(v) - value(v);
|
||||
else
|
||||
curr_error = value(v) - hi(v) - 1;
|
||||
if ((best == null_var) ||
|
||||
(least && curr_error < best_error) ||
|
||||
(!least && curr_error > best_error)) {
|
||||
best = v;
|
||||
best_error = curr_error;
|
||||
}
|
||||
}
|
||||
if (best == null_var)
|
||||
m_to_patch.clear(); // all variables are satisfied
|
||||
else
|
||||
m_to_patch.erase(best);
|
||||
return best;
|
||||
}
|
||||
|
||||
template<typename Ext>
|
||||
void fixplex<Ext>::check_blands_rule(var_t v, unsigned& num_repeated) {
|
||||
if (m_bland)
|
||||
return;
|
||||
if (!m_left_basis.contains(v))
|
||||
m_left_basis.insert(v);
|
||||
else {
|
||||
++num_repeated;
|
||||
m_bland = num_repeated > m_blands_rule_threshold;
|
||||
CTRACE("polysat", m_bland, tout << "using blands rule, " << num_repeated << "\n";);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Ext>
|
||||
std::ostream& fixplex<Ext>::display(std::ostream& out) const {
|
||||
M.display(out);
|
||||
for (unsigned i = 0; i < m_vars.size(); ++i) {
|
||||
var_info const& vi = m_vars[i];
|
||||
out << "v" << i << " " << value(i) << " [" << lo(i) << ", " << hi(i) << "[ ";
|
||||
if (vi.m_is_base) out << "b:" << vi.m_base2row << " ";
|
||||
out << "\n";
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
template<typename Ext>
|
||||
void fixplex<Ext>::display_row(std::ostream& out, row const& r, bool values) {
|
||||
for (auto const& e : M.row_entries(r)) {
|
||||
var_t v = e.m_var;
|
||||
if (e.m_coeff != 1)
|
||||
out << e.m_coeff << " * ";
|
||||
out << "v" << v << " ";
|
||||
if (values)
|
||||
out << value(v) << " [" << lo(v) << ", " << hi(v) << "[ ";
|
||||
}
|
||||
return out << "\n";
|
||||
}
|
||||
|
||||
template<typename Ext>
|
||||
bool fixplex<Ext>::well_formed() const {
|
||||
SASSERT(M.well_formed());
|
||||
for (unsigned i = 0; i < m_rows.size(); ++i) {
|
||||
var_t s = m_rows[i].m_base;
|
||||
if (s == null_var)
|
||||
continue;
|
||||
SASSERT(i == m_vars[s].m_base2row);
|
||||
VERIFY(well_formed_row(row(i)));
|
||||
}
|
||||
for (unsigned i = 0; i < m_vars.size(); ++i) {
|
||||
SASSERT(is_base(i) || in_bounds(i));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename Ext>
|
||||
bool fixplex<Ext>::well_formed_row(row const& r) const {
|
||||
var_t s = m_rows[r.id()].m_base;
|
||||
(void)s;
|
||||
SASSERT(m_vars[s].m_base2row == r.id());
|
||||
SASSERT(m_vars[s].m_is_base);
|
||||
numeral sum = 0;
|
||||
for (auto const& e : M.row_entries(r)) {
|
||||
sum += value(e.m_var) * e.m_coeff;
|
||||
SASSERT(s != e.m_var || m_rows[r.id()].m_base_coeff == e.m_coeff);
|
||||
}
|
||||
if (sum != 0) {
|
||||
IF_VERBOSE(0, M.display_row(verbose_stream(), r););
|
||||
TRACE("polysat", display(tout << "non-well formed row\n"); M.display_row(tout << "row: ", r););
|
||||
throw default_exception("non-well formed row");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename Ext>
|
||||
void fixplex<Ext>::collect_statistics(::statistics & st) const {
|
||||
M.collect_statistics(st);
|
||||
st.update("fixplex num pivots", m_stats.m_num_pivots);
|
||||
st.update("fixplex num infeasible", m_stats.m_num_infeasible);
|
||||
st.update("fixplex num checks", m_stats.m_num_checks);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -238,7 +238,7 @@ namespace simplex {
|
|||
--m_col.m_refs;
|
||||
}
|
||||
|
||||
row get_row() {
|
||||
row get_row() const {
|
||||
return row(m_col.m_entries[m_curr].m_row_id);
|
||||
}
|
||||
row_entry const& get_row_entry() {
|
||||
|
|
|
@ -9,17 +9,20 @@ namespace polysat {
|
|||
reslimit lim;
|
||||
fixplex<uint64_ext> fp(lim);
|
||||
var_t x = 0, y = 1, z = 2, u = 3;
|
||||
fp.ensure_var(3);
|
||||
|
||||
var_t ys[2] = { y, z };
|
||||
numeral coeffs[2] = { 1, 4 };
|
||||
fp.add_row(x, 2, ys, coeffs);
|
||||
fp.set_lo(x, 1);
|
||||
fp.set_hi(x, 2);
|
||||
var_t ys[3] = { x, y, z };
|
||||
numeral coeffs[3] = { 2, 1, 4 };
|
||||
fp.add_row(x, 3, ys, coeffs);
|
||||
fp.set_bounds(x, 1, 2);
|
||||
std::cout << fp << "\n";
|
||||
fp.make_feasible();
|
||||
std::cout << fp << "\n";
|
||||
statistics st;
|
||||
fp.collect_statistics(st);
|
||||
std::cout << st << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
void tst_fixplex() {
|
||||
|
||||
polysat::test1();
|
||||
}
|
||||
|
|
|
@ -264,4 +264,5 @@ int main(int argc, char ** argv) {
|
|||
TST(finder);
|
||||
TST(polysat);
|
||||
TST_ARGV(polysat_argv);
|
||||
TST(fixplex);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue