3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-06-06 06:03:23 +00:00

adding deps

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
Nikolaj Bjorner 2021-08-04 14:02:32 -07:00
parent 91ac15d716
commit be9f172cc0
7 changed files with 268 additions and 194 deletions

View file

@ -70,12 +70,8 @@ inline std::ostream& operator<<(std::ostream& out, u256 const& u) {
inline bool operator<(uint64_t n, u256 const& y) { return y > n; }
inline bool operator<=(uint64_t n, u256 const& y) { return y >= n; }
inline bool operator>(uint64_t n, u256 const& y) { return y < n; }
inline unsigned trailing_zeros(u256 const& n) {
NOT_IMPLEMENTED_YET();
return 0;
}
inline u256 operator-(uint64_t n, u256 const& y) {
u256 x(n);
return x - y;
}
inline unsigned trailing_zeros(u256 const& n) { return n.trailing_zeros(); }
inline u256 operator-(uint64_t n, u256 const& y) { return u256(n) - y; }
inline bool operator>=(uint64_t n, u256 const& y) { return y <= n; }
inline rational to_rational(u256 const& x) { return x.to_rational(); }

View file

@ -27,6 +27,8 @@ Author:
#include "util/lbool.h"
#include "util/uint_set.h"
inline rational to_rational(uint64_t n) { return rational(n, rational::ui64()); }
namespace polysat {
typedef unsigned var_t;
@ -38,12 +40,14 @@ namespace polysat {
virtual void del_row(var_t base_var) = 0;
virtual std::ostream& display(std::ostream& out) const = 0;
virtual void collect_statistics(::statistics & st) const = 0;
virtual void set_bounds(var_t v, rational const& lo, rational const& hi) = 0;
virtual void set_value(var_t v, rational const& val) = 0;
virtual void set_bounds(var_t v, rational const& lo, rational const& hi, unsigned dep) = 0;
virtual void set_value(var_t v, rational const& val, unsigned dep) = 0;
virtual rational get_value(var_t v) = 0;
virtual void restore_bound() = 0;
virtual void add_le(var_t v, var_t w) = 0;
virtual void add_lt(var_t v, var_t w) = 0;
virtual void add_le(var_t v, var_t w, unsigned dep) = 0;
virtual void add_lt(var_t v, var_t w, unsigned dep) = 0;
virtual void restore_ineq() = 0;
virtual void get_infeasible_deps(unsigned_vector& deps) = 0;
};
@ -92,7 +96,9 @@ namespace polysat {
struct var_info : public mod_interval<numeral> {
unsigned m_base2row:29;
unsigned m_is_base:1;
numeral m_value { 0 };
numeral m_value = 0;
unsigned m_lo_dep = UINT_MAX;
unsigned m_hi_dep = UINT_MAX;
var_info():
m_base2row(0),
m_is_base(false)
@ -115,10 +121,10 @@ namespace polysat {
numeral m_base_coeff;
};
struct stashed_bound : mod_interval<numeral> {
struct stashed_bound : var_info {
var_t m_var;
stashed_bound(var_t v, mod_interval<numeral> const& i):
mod_interval<numeral>(i),
stashed_bound(var_t v, var_info const& i):
var_info(i),
m_var(v)
{}
};
@ -131,12 +137,13 @@ namespace polysat {
};
struct ineq {
var_t v { null_var };
var_t w { null_var };
bool strict { false };
bool is_active { true };
ineq(var_t v, var_t w, bool s):
v(v), w(w), strict(s) {}
var_t v = null_var;
var_t w = null_var;
bool strict = false;
bool is_active = true;
unsigned dep = UINT_MAX;
ineq(var_t v, var_t w, unsigned dep, bool s):
v(v), w(w), strict(s), dep(dep) {}
};
static const var_t null_var = UINT_MAX;
@ -179,14 +186,15 @@ namespace polysat {
std::ostream& display(std::ostream& out) const override;
void collect_statistics(::statistics & st) const override;
void del_row(var_t base_var) override;
void set_bounds(var_t v, rational const& lo, rational const& hi) override;
void set_value(var_t v, rational const& val) override;
void set_bounds(var_t v, rational const& lo, rational const& hi, unsigned dep) override;
void set_value(var_t v, rational const& val, unsigned dep) override;
rational get_value(var_t v) override;
void restore_bound() override;
void add_le(var_t v, var_t w) override { add_ineq(v, w, false); }
void add_lt(var_t v, var_t w) override { add_ineq(v, w, true); }
void add_le(var_t v, var_t w, unsigned dep) override { add_ineq(v, w, dep, false); }
void add_lt(var_t v, var_t w, unsigned dep) override { add_ineq(v, w, dep, true); }
virtual void restore_ineq() override;
void set_bounds(var_t v, numeral const& lo, numeral const& hi);
void set_bounds(var_t v, numeral const& lo, numeral const& hi, unsigned dep);
void unset_bounds(var_t v) { m_vars[v].set_free(); }
@ -202,10 +210,13 @@ namespace polysat {
void reset_eqs() { m_var_eqs.reset(); }
void add_row(var_t base, unsigned num_vars, var_t const* vars, numeral const* coeffs);
row get_infeasible_row();
void get_infeasible_deps(unsigned_vector& deps) override;
private:
row get_infeasible_row();
std::ostream& display_row(std::ostream& out, row const& r, bool values = true);
var_t get_base_var(row const& r) const { return m_rows[r.id()].m_base; }
@ -258,7 +269,7 @@ namespace polysat {
var_t select_error_var(bool least);
// facilities for handling inequalities
void add_ineq(var_t v, var_t w, bool strict);
void add_ineq(var_t v, var_t w, unsigned dep, bool strict);
void touch_var(var_t x);
lbool check_ineqs();
@ -284,7 +295,6 @@ namespace polysat {
numeral const& old_value_y);
};
template<typename uint_type>
struct generic_uint_ext {
typedef uint_type numeral;
@ -302,6 +312,7 @@ namespace polysat {
}
};
numeral from_rational(rational const& n) { return static_cast<uint_type>(n.get_uint64()); }
rational to_rational(numeral const& n) const { return ::to_rational(n); }
void reset() {}
void reset(numeral& n) { n = 0; }
void del(numeral const& n) {}

View file

@ -486,8 +486,14 @@ namespace polysat {
* - the variable v is queued to patch if v is basic.
*/
template<typename Ext>
void fixplex<Ext>::set_bounds(var_t v, numeral const& l, numeral const& h) {
m_vars[v] = mod_interval(l, h);
void fixplex<Ext>::set_bounds(var_t v, numeral const& l, numeral const& h, unsigned dep) {
auto lo0 = m_vars[v].lo;
auto hi0 = m_vars[v].hi;
m_vars[v] &= mod_interval(l, h);
if (lo0 != m_vars[v].lo)
m_vars[v].m_lo_dep = dep;
if (hi0 != m_vars[v].hi)
m_vars[v].m_hi_dep = dep;
if (in_bounds(v))
return;
if (is_base(v))
@ -497,35 +503,43 @@ namespace polysat {
}
template<typename Ext>
void fixplex<Ext>::set_bounds(var_t v, rational const& _lo, rational const& _hi) {
void fixplex<Ext>::set_bounds(var_t v, rational const& _lo, rational const& _hi, unsigned dep) {
numeral lo = m.from_rational(_lo);
numeral hi = m.from_rational(_hi);
m_stashed_bounds.push_back(stashed_bound(v, m_vars[v]));
set_bounds(v, lo, hi);
set_bounds(v, lo, hi, dep);
}
template<typename Ext>
void fixplex<Ext>::set_value(var_t v, rational const& _val) {
void fixplex<Ext>::set_value(var_t v, rational const& _val, unsigned dep) {
numeral val = m.from_rational(_val);
m_stashed_bounds.push_back(stashed_bound(v, m_vars[v]));
set_bounds(v, val, val + 1);
set_bounds(v, val, val + 1, dep);
}
template<typename Ext>
rational fixplex<Ext>::get_value(var_t v) {
return m.to_rational(m_vars[v].m_value);
}
template<typename Ext>
void fixplex<Ext>::restore_bound() {
auto const& b = m_stashed_bounds.back();
set_bounds(b.m_var, b.lo, b.hi);
m_vars[b.m_var].lo = b.lo;
m_vars[b.m_var].hi = b.hi;
m_vars[b.m_var].m_lo_dep = b.m_lo_dep;
m_vars[b.m_var].m_hi_dep = b.m_hi_dep;
m_stashed_bounds.pop_back();
}
template<typename Ext>
void fixplex<Ext>::add_ineq(var_t v, var_t w, bool strict) {
void fixplex<Ext>::add_ineq(var_t v, var_t w, unsigned dep, bool strict) {
unsigned idx = m_ineqs.size();
m_var2ineqs.reserve(std::max(v, w) + 1);
m_var2ineqs[v].push_back(idx);
m_var2ineqs[w].push_back(idx);
m_ineqs_to_check.push_back(idx);
m_ineqs.push_back(ineq(v, w, strict));
m_ineqs.push_back(ineq(v, w, dep, strict));
}
template<typename Ext>
@ -785,6 +799,28 @@ namespace polysat {
return base2row(m_infeasible_var);
}
/***
* Extract dependencies for infeasible row.
* A safe approximation is to extract dependencies for all bounds.
*
* Different modes of infeasibility may not be based on a row:
* - inequalities
* - parity constraints between two rows.
*/
template<typename Ext>
void fixplex<Ext>::get_infeasible_deps(unsigned_vector& deps) {
auto row = get_infeasible_row();
for (auto const& e : M.row_entries(row)) {
var_t v = e.var();
auto lo = m_vars[v].m_lo_dep;
auto hi = m_vars[v].m_hi_dep;
if (lo != UINT_MAX)
deps.push_back(lo);
if (hi != UINT_MAX)
deps.push_back(hi);
}
}
/**
\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.

View file

@ -60,11 +60,16 @@ namespace polysat {
m_rows.pop_back();
break;
}
case trail_i::set_active_i:
m_active.pop_back();
break;
default:
UNREACHABLE();
}
m_trail.pop_back();
}
m_unsat_f = nullptr;
}
fixplex_base& linear_solver::sz2fixplex(unsigned sz) {
@ -118,7 +123,15 @@ namespace polysat {
m_bool_var2row.setx(c.bvar(), pr, pr);
}
void linear_solver::assert_eq(eq_constraint& c) {
void linear_solver::new_le(ule_constraint& c) {
var_t v = internalize_pdd(c.lhs());
var_t w = internalize_pdd(c.rhs());
auto pr = std::make_pair(v, w);
m_bool_var2row.setx(c.bvar(), pr, pr);
}
void linear_solver::assert_eq(bool is_positive, eq_constraint& c) {
unsigned c_dep = constraint_idx2dep(m_active.size() - 1);
var_t v = m_bool_var2row[c.bvar()].first;
unsigned sz = c.p().power_of_2();
auto& fp = sz2fixplex(sz);
@ -126,17 +139,10 @@ namespace polysat {
m_rows.push_back(std::make_pair(v, sz));
rational z(0), o(1);
SASSERT(!c.is_undef());
if (c.is_positive())
fp.set_bounds(v, z, z);
if (is_positive)
fp.set_bounds(v, z, z, c_dep);
else
fp.set_bounds(v, o, z);
}
void linear_solver::new_le(ule_constraint& c) {
var_t v = internalize_pdd(c.lhs());
var_t w = internalize_pdd(c.rhs());
auto pr = std::make_pair(v, w);
m_bool_var2row.setx(c.bvar(), pr, pr);
fp.set_bounds(v, o, z, c_dep);
}
//
@ -152,44 +158,45 @@ namespace polysat {
// inequality graph (with offsets)
//
void linear_solver::assert_le(ule_constraint& c) {
void linear_solver::assert_le(bool is_positive, ule_constraint& c) {
auto [v, w] = m_bool_var2row[c.bvar()];
unsigned sz = c.lhs().power_of_2();
auto& fp = sz2fixplex(sz);
unsigned c_dep = constraint_idx2dep(m_active.size() - 1);
rational z(0);
if (c.rhs().is_val()) {
bool is_max_value = false;
if (c.is_positive())
if (is_positive)
// v <= rhs
fp.set_bounds(v, z, c.rhs().val());
fp.set_bounds(v, z, c.rhs().val(), c_dep);
else if (is_max_value)
throw default_exception("conflict not implemented");
else
// rhs < v
fp.set_bounds(v, c.rhs().val() + 1, z);
fp.set_bounds(v, c.rhs().val() + 1, z, c_dep);
m_trail.push_back(trail_i::set_bound_i);
m_rows.push_back(std::make_pair(v, sz));
return;
}
if (c.lhs().is_val()) {
if (c.is_positive())
if (is_positive)
// w >= lhs
fp.set_bounds(w, c.lhs().val(), z);
fp.set_bounds(w, c.lhs().val(), z, c_dep);
else if (c.lhs().val() == 0)
throw default_exception("conflict not implemented");
else
// w < lhs
fp.set_bounds(w, z, c.lhs().val() - 1);
fp.set_bounds(w, z, c.lhs().val() - 1, c_dep);
m_trail.push_back(trail_i::set_bound_i);
m_rows.push_back(std::make_pair(w, sz));
return;
}
if (c.is_positive())
fp.add_le(v, w);
if (is_positive)
fp.add_le(v, w, c_dep);
else
fp.add_lt(w, v);
fp.add_lt(w, v, c_dep);
m_trail.push_back(trail_i::add_ineq_i);
m_rows.push_back(std::make_pair(v, sz));
}
@ -209,14 +216,16 @@ namespace polysat {
}
}
void linear_solver::activate_constraint(constraint& c) {
void linear_solver::activate_constraint(bool is_positive, constraint& c) {
m_active.push_back(&c);
m_trail.push_back(trail_i::set_active_i);
SASSERT(!c.is_undef());
switch (c.kind()) {
case ckind_t::eq_t:
assert_eq(c.to_eq());
assert_eq(is_positive, c.to_eq());
break;
case ckind_t::ule_t:
assert_le(c.to_ule());
assert_le(is_positive, c.to_ule());
break;
default:
UNREACHABLE();
@ -261,34 +270,37 @@ namespace polysat {
return m_sz2num_vars[sz]++;
}
void linear_solver::set_value(pvar v, rational const& value) {
void linear_solver::set_value(pvar v, rational const& value, unsigned dep) {
unsigned sz = s.size(v);
auto& fp = sz2fixplex(sz);
var_t w = pvar2var(sz, v);
m_trail.push_back(trail_i::set_bound_i);
m_rows.push_back(std::make_pair(w, sz));
fp.set_value(w, value);
fp.set_value(w, value, external_dep2dep(dep));
}
void linear_solver::set_bound(pvar v, rational const& lo, rational const& hi) {
void linear_solver::set_bound(pvar v, rational const& lo, rational const& hi, unsigned dep) {
unsigned sz = s.size(v);
auto& fp = sz2fixplex(sz);
var_t w = pvar2var(sz, v);
m_trail.push_back(trail_i::set_bound_i);
m_rows.push_back(std::make_pair(w, sz));
fp.set_bounds(w, lo, hi);
fp.set_bounds(w, lo, hi, external_dep2dep(dep));
}
// check integer modular feasibility under current bounds.
// and inequalities
/**
* check integer modular feasibility under current bounds.
* and inequalities
*/
lbool linear_solver::check() {
lbool res = l_true;
m_unsat_f = nullptr;
for (auto* f : m_fix) {
if (!f)
continue;
lbool r = f->make_feasible();
if (r == l_false) {
// m_unsat_f = f;
m_unsat_f = f;
return r;
}
if (r == l_undef)
@ -297,13 +309,25 @@ namespace polysat {
return res;
}
void linear_solver::unsat_core(unsigned_vector& deps) {
NOT_IMPLEMENTED_YET();
void linear_solver::unsat_core(ptr_vector<constraint>& cs, unsigned_vector& deps) {
SASSERT(m_unsat_f);
deps.reset();
cs.reset();
m_unsat_f->get_infeasible_deps(deps);
unsigned j = 0;
for (unsigned dep : deps) {
if (is_constraint_dep(dep))
cs.push_back(m_active[dep2constraint_idx(dep)]);
else
deps[j++] = dep2external_dep(dep);
}
deps.shrink(j);
}
// current value assigned to (linear) variable according to tableau.
rational linear_solver::value(pvar v) {
return rational(0);
unsigned sz = s.size(v);
return sz2fixplex(sz).get_value(pvar2var(sz, v));
}
};

View file

@ -43,7 +43,8 @@ namespace polysat {
add_mono_i,
set_bound_i,
add_ineq_i,
add_row_i
add_row_i,
set_active_i
};
struct mono_info {
@ -81,6 +82,7 @@ namespace polysat {
svector<std::pair<var_t, unsigned>> m_rows;
unsigned_vector m_var2ext;
unsigned_vector m_ext2var;
ptr_vector<constraint> m_active;
svector<var_t> m_vars;
vector<rational> m_coeffs;
@ -90,29 +92,31 @@ namespace polysat {
unsigned_vector m_sz2num_vars;
small_object_allocator m_alloc;
svector<mono_info> m_monomials;
fixplex_base* m_unsat_f = nullptr;
fixplex_base& sz2fixplex(unsigned sz);
void linearize(pdd const& p);
var_t fresh_var(unsigned sz);
var_t internalize_pdd(pdd const& p);
void new_eq(eq_constraint& eq);
void new_le(ule_constraint& le);
void assert_eq(eq_constraint& eq);
void assert_le(ule_constraint& le);
void assert_eq(bool is_positive, eq_constraint& eq);
void assert_le(bool is_positive, ule_constraint& le);
// bind monomial to variable.
var_t mono2var(unsigned sz, unsigned_vector const& m);
var_t pvar2var(unsigned sz, pvar v);
unsigned_vector var2mono(unsigned sz, var_t v) { throw default_exception("nyi"); }
//
// TBD trail object for
// removing variables
// undoing variable bounds bounds
// removing rows from fixplex
//
// unsigned_vector var2mono(unsigned sz, var_t v) { throw default_exception("nyi"); }
// distinguish constraint and justification dependencies
unsigned external_dep2dep(unsigned dep) const { return UINT_MAX - dep; }
unsigned constraint_idx2dep(unsigned idx) const { return idx; }
bool is_constraint_dep(unsigned dep) const { return dep < UINT_MAX / 2; }
unsigned dep2constraint_idx(unsigned dep) const { return dep; }
unsigned dep2external_dep(unsigned dep) const { return UINT_MAX - dep; }
public:
linear_solver(solver& s):
s(s),
@ -122,13 +126,13 @@ namespace polysat {
void push();
void pop(unsigned n);
void new_constraint(constraint& c);
void set_value(pvar v, rational const& value);
void set_bound(pvar v, rational const& lo, rational const& hi);
void activate_constraint(constraint& c);
void set_value(pvar v, rational const& value, unsigned dep);
void set_bound(pvar v, rational const& lo, rational const& hi, unsigned dep);
void activate_constraint(bool is_positive, constraint& c);
// check integer modular feasibility under current bounds.
lbool check();
void unsat_core(unsigned_vector& deps);
void unsat_core(ptr_vector<constraint>& constraints, unsigned_vector& deps);
// current value assigned to (linear) variable according to tableau.
rational value(pvar v);

View file

@ -383,7 +383,8 @@ namespace polysat {
m_trail.push_back(trail_instr_t::assign_i);
m_justification[v] = j;
#if ENABLE_LINEAR_SOLVER
m_linear_solver.set_value(v, val);
// TODO: convert justification into a format that can be tracked in a depdendency core.
m_linear_solver.set_value(v, val, UINT_MAX);
#endif
}
@ -942,7 +943,12 @@ namespace polysat {
m_bvars.assign(lit, m_level, reason, lemma);
}
/// Activate constraint immediately
/**
* Activate constraint immediately
* Activation and de-activation of constraints follows the scope controlled by push/pop.
* constraints activated within the linear solver are de-activated when the linear
* solver is popped.
*/
void solver::activate_constraint(constraint& c, bool is_true) {
LOG("Activating constraint: " << c << " ; is_true = " << is_true);
SASSERT(m_bvars.value(c.bvar()) == to_lbool(is_true));
@ -950,18 +956,15 @@ namespace polysat {
add_watch(c);
c.narrow(*this);
#if ENABLE_LINEAR_SOLVER
m_linear_solver.activate_constraint(c);
m_linear_solver.activate_constraint(c.is_positive(), c);
#endif
}
/// Deactivate constraint immediately
/// Deactivate constraint
void solver::deactivate_constraint(constraint& c) {
LOG("Deactivating constraint: " << c);
erase_watch(c);
c.unassign();
#if ENABLE_LINEAR_SOLVER
m_linear_solver.deactivate_constraint(c); // TODO add this method to linear solver?
#endif
}
void solver::backjump(unsigned new_level) {

View file

@ -28,7 +28,7 @@ namespace polysat {
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);
fp.set_bounds(x, 1, 2, 0);
fp.run();
}
@ -38,7 +38,7 @@ namespace polysat {
var_t ys[3] = { x, y, z };
numeral coeffs[3] = { 1, 2, 4 };
fp.add_row(x, 3, ys, coeffs);
fp.set_bounds(x, 3, 4);
fp.set_bounds(x, 3, 4, 1);
fp.run();
}
@ -48,9 +48,9 @@ namespace polysat {
var_t ys[3] = { x, y, z };
numeral coeffs[3] = { 1, 1, 1 };
fp.add_row(x, 3, ys, coeffs);
fp.set_bounds(x, 3, 4);
fp.set_bounds(y, 3, 4);
fp.set_bounds(z, 3, 4);
fp.set_bounds(x, 3, 4, 1);
fp.set_bounds(y, 3, 4, 2);
fp.set_bounds(z, 3, 4, 3);
fp.run();
}
@ -60,22 +60,22 @@ namespace polysat {
var_t ys[3] = { x, y, z };
numeral coeffs[3] = { 1, 1, 1 };
fp.add_row(x, 3, ys, coeffs);
fp.set_bounds(x, 3, 4);
fp.set_bounds(y, 3, 6);
fp.set_bounds(x, 3, 4, 1);
fp.set_bounds(y, 3, 6, 2);
fp.run();
fp.propagate_bounds();
fp.reset();
coeffs[2] = 0ull - 1;
fp.add_row(x, 3, ys, coeffs);
fp.set_bounds(x, 3, 4);
fp.set_bounds(y, 3, 6);
fp.set_bounds(x, 3, 4, 1);
fp.set_bounds(y, 3, 6, 2);
fp.run();
fp.propagate_bounds();
fp.reset();
fp.add_row(x, 3, ys, coeffs);
fp.set_bounds(x, 3, 4);
fp.set_bounds(y, 3, 6);
fp.set_bounds(z, 1, 8);
fp.set_bounds(x, 3, 4, 1);
fp.set_bounds(y, 3, 6, 2);
fp.set_bounds(z, 1, 8, 3);
fp.run();
fp.propagate_bounds();
fp.reset();
@ -88,8 +88,8 @@ namespace polysat {
var_t ys[3] = { x, y, z };
numeral coeffs[3] = { 1, 1, 1 };
fp.add_row(x, 3, ys, coeffs);
fp.set_bounds(x, 3, 4);
fp.set_bounds(y, 3, 6);
fp.set_bounds(x, 3, 4, 1);
fp.set_bounds(y, 3, 6, 2);
var_t ys2[3] = { u, y, z };
fp.add_row(u, 3, ys2, coeffs);
fp.run();
@ -107,7 +107,7 @@ namespace polysat {
numeral coeffs2[3] = { 1, m1, 1 };
fp.add_row(x, 3, ys1, coeffs1);
fp.add_row(z, 3, ys2, coeffs2);
fp.set_bounds(u, 1, 2);
fp.set_bounds(u, 1, 2, 1);
fp.run();
fp.propagate_eqs();
for (auto e : fp.var_eqs())