mirror of
https://github.com/Z3Prover/z3
synced 2025-04-22 00:26:38 +00:00
remove references to unused linear solver
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
parent
02ff7efe25
commit
8b875f33db
8 changed files with 0 additions and 2899 deletions
|
@ -12,7 +12,6 @@ z3_add_component(polysat
|
|||
forbidden_intervals.cpp
|
||||
inference_logger.cpp
|
||||
justification.cpp
|
||||
linear_solver.cpp
|
||||
log.cpp
|
||||
naming.cpp
|
||||
op_constraint.cpp
|
||||
|
|
|
@ -1,483 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2014 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
fixplex.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Fixed-precision unsigned integer simplex tableau.
|
||||
|
||||
Author:
|
||||
|
||||
Nikolaj Bjorner (nbjorner) 2021-03-19
|
||||
Jakob Rath 2021-04-6
|
||||
|
||||
--*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <limits>
|
||||
#include "math/simplex/sparse_matrix.h"
|
||||
#include "fixplex_mod_interval.h"
|
||||
#include "util/heap.h"
|
||||
#include "util/map.h"
|
||||
#include "util/rational.h"
|
||||
#include "util/lbool.h"
|
||||
#include "util/uint_set.h"
|
||||
#include "util/dependency.h"
|
||||
#include "util/ref.h"
|
||||
#include "util/params.h"
|
||||
#include "util/union_find.h"
|
||||
|
||||
inline rational to_rational(uint64_t n) { return rational(n, rational::ui64()); }
|
||||
inline unsigned trailing_zeros(unsigned short n) { return trailing_zeros((uint32_t)n); }
|
||||
inline unsigned trailing_zeros(unsigned char n) { return trailing_zeros((uint32_t)n); }
|
||||
inline unsigned numeral2hash(unsigned char const& n) { return n; }
|
||||
inline unsigned numeral2hash(unsigned short const& n) { return n; }
|
||||
inline unsigned numeral2hash(uint32_t const& n) { return n; }
|
||||
inline unsigned numeral2hash(uint64_t const& n) { return static_cast<unsigned>(n ^ (n >> 32)); }
|
||||
|
||||
|
||||
namespace polysat {
|
||||
|
||||
typedef unsigned var_t;
|
||||
|
||||
struct fixplex_base {
|
||||
virtual ~fixplex_base() {}
|
||||
virtual lbool make_feasible() = 0;
|
||||
virtual void add_row(var_t base, unsigned num_vars, var_t const* vars, rational const* coeffs) = 0;
|
||||
virtual void del_row(var_t base_var) = 0;
|
||||
virtual void push() = 0;
|
||||
virtual void pop(unsigned n) = 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, 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, unsigned dep) = 0;
|
||||
virtual void add_lt(var_t v, var_t w, unsigned dep) = 0;
|
||||
virtual void restore_ineq() = 0;
|
||||
virtual bool inconsistent() const = 0;
|
||||
virtual unsigned_vector const& get_unsat_core() const = 0;
|
||||
virtual void updt_params(params_ref const& p) = 0;
|
||||
|
||||
};
|
||||
|
||||
struct ineq {
|
||||
var_t v = UINT_MAX;
|
||||
var_t w = UINT_MAX;
|
||||
bool strict = false;
|
||||
u_dependency* dep = nullptr;
|
||||
ineq(var_t v, var_t w, u_dependency* dep, bool s) :
|
||||
v(v), w(w), strict(s), dep(dep) {}
|
||||
|
||||
std::ostream& display(std::ostream& out) const {
|
||||
return out << "v" << v << (strict ? " < v" : " <= v") << w;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Ext>
|
||||
class fixplex : public fixplex_base {
|
||||
public:
|
||||
typedef typename Ext::numeral numeral;
|
||||
typedef typename Ext::scoped_numeral scoped_numeral;
|
||||
typedef typename Ext::manager manager;
|
||||
typedef simplex::sparse_matrix<Ext> matrix;
|
||||
typedef typename matrix::row row;
|
||||
typedef typename matrix::row_iterator row_iterator;
|
||||
typedef typename matrix::col_iterator col_iterator;
|
||||
|
||||
struct var_eq {
|
||||
var_t x, y;
|
||||
u_dependency* dep;
|
||||
var_eq(var_t x, var_t y, u_dependency* dep):
|
||||
x(x), y(y), dep(dep) {}
|
||||
};
|
||||
|
||||
protected:
|
||||
struct var_lt {
|
||||
bool operator()(var_t v1, var_t v2) const { return v1 < v2; }
|
||||
};
|
||||
typedef heap<var_lt> var_heap;
|
||||
|
||||
struct stats {
|
||||
unsigned m_num_pivots;
|
||||
unsigned m_num_infeasible;
|
||||
unsigned m_num_checks;
|
||||
unsigned m_num_approx;
|
||||
stats() { reset(); }
|
||||
void reset() {
|
||||
memset(this, 0, sizeof(*this));
|
||||
}
|
||||
};
|
||||
|
||||
enum pivot_strategy_t {
|
||||
S_BLAND,
|
||||
S_GREATEST_ERROR,
|
||||
S_LEAST_ERROR,
|
||||
S_DEFAULT
|
||||
};
|
||||
|
||||
struct var_info : public mod_interval<numeral> {
|
||||
unsigned m_base2row:29;
|
||||
unsigned m_is_base:1;
|
||||
numeral m_value = 0;
|
||||
u_dependency* m_lo_dep = nullptr;
|
||||
u_dependency* m_hi_dep = nullptr;
|
||||
var_info():
|
||||
m_base2row(0),
|
||||
m_is_base(false)
|
||||
{}
|
||||
~var_info() override {}
|
||||
var_info& operator&=(mod_interval<numeral> const& range) {
|
||||
mod_interval<numeral>::operator=(range & *this);
|
||||
return *this;
|
||||
}
|
||||
var_info& operator=(mod_interval<numeral> const& range) {
|
||||
mod_interval<numeral>::operator=(range);
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
struct row_info {
|
||||
bool m_integral { true };
|
||||
var_t m_base;
|
||||
numeral m_value;
|
||||
numeral m_base_coeff;
|
||||
};
|
||||
|
||||
struct stashed_bound : var_info {
|
||||
var_t m_var;
|
||||
stashed_bound(var_t v, var_info const& i):
|
||||
var_info(i),
|
||||
m_var(v)
|
||||
{}
|
||||
};
|
||||
|
||||
struct fix_entry {
|
||||
var_t x = null_var;
|
||||
u_dependency* dep = nullptr;
|
||||
fix_entry(var_t x, u_dependency* dep): x(x), dep(dep) {}
|
||||
fix_entry() {}
|
||||
};
|
||||
|
||||
enum trail_i {
|
||||
inc_level_i,
|
||||
set_bound_i,
|
||||
set_inconsistent_i,
|
||||
add_ineq_i,
|
||||
add_row_i,
|
||||
add_eq_i,
|
||||
fixed_val_i
|
||||
};
|
||||
|
||||
static const var_t null_var = UINT_MAX;
|
||||
reslimit& m_limit;
|
||||
mutable manager m;
|
||||
mutable matrix M;
|
||||
unsigned m_max_iterations = UINT_MAX;
|
||||
unsigned m_num_non_integral = 0;
|
||||
uint_set m_non_integral;
|
||||
var_heap m_to_patch;
|
||||
vector<var_info> m_vars;
|
||||
vector<row_info> m_rows;
|
||||
|
||||
bool m_bland = false ;
|
||||
unsigned m_blands_rule_threshold = 1000;
|
||||
unsigned m_num_repeated = 0;
|
||||
random_gen m_random;
|
||||
uint_set m_left_basis;
|
||||
unsigned_vector m_unsat_core;
|
||||
bool m_inconsistent = false;
|
||||
unsigned_vector m_base_vars;
|
||||
stats m_stats;
|
||||
vector<stashed_bound> m_stashed_bounds;
|
||||
u_dependency_manager m_deps;
|
||||
svector<trail_i> m_trail;
|
||||
svector<var_t> m_row_trail;
|
||||
|
||||
// euqality propagation
|
||||
union_find_default_ctx m_union_find_ctx;
|
||||
union_find<> m_union_find;
|
||||
vector<var_eq> m_var_eqs;
|
||||
vector<numeral> m_fixed_vals;
|
||||
map<numeral, fix_entry, typename manager::hash, typename manager::eq> m_value2fixed_var;
|
||||
uint_set m_eq_rows;
|
||||
|
||||
// inequalities
|
||||
svector<ineq> m_ineqs;
|
||||
uint_set m_ineqs_to_propagate;
|
||||
uint_set m_touched_vars;
|
||||
vector<unsigned_vector> m_var2ineqs;
|
||||
|
||||
// bound propagation
|
||||
uint_set m_bound_rows;
|
||||
|
||||
public:
|
||||
fixplex(params_ref const& p, reslimit& lim):
|
||||
m_limit(lim),
|
||||
M(m),
|
||||
m_to_patch(1024),
|
||||
m_union_find(m_union_find_ctx) {
|
||||
updt_params(p);
|
||||
}
|
||||
|
||||
~fixplex() override;
|
||||
|
||||
void push() override;
|
||||
void pop(unsigned n) override;
|
||||
bool inconsistent() const override { return m_inconsistent; }
|
||||
void updt_params(params_ref const& p) override;
|
||||
|
||||
lbool make_feasible() override;
|
||||
void add_row(var_t base, unsigned num_vars, var_t const* vars, rational const* coeffs) override;
|
||||
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, 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, 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, unsigned dep);
|
||||
void update_bounds(var_t v, numeral const& l, numeral const& h, u_dependency* dep);
|
||||
void unset_bounds(var_t v) { m_vars[v].set_free(); }
|
||||
|
||||
|
||||
numeral const& lo(var_t var) const { return m_vars[var].lo; }
|
||||
numeral const& hi(var_t var) const { return m_vars[var].hi; }
|
||||
numeral const& value(var_t var) const { return m_vars[var].m_value; }
|
||||
void set_max_iterations(unsigned n) { m_max_iterations = n; }
|
||||
unsigned get_num_vars() const { return m_vars.size(); }
|
||||
void reset();
|
||||
|
||||
vector<var_eq> const& var_eqs() const { return m_var_eqs; }
|
||||
|
||||
void add_row(var_t base, unsigned num_vars, var_t const* vars, numeral const* coeffs);
|
||||
|
||||
unsigned_vector const& get_unsat_core() const override { return m_unsat_core; }
|
||||
|
||||
private:
|
||||
|
||||
svector<std::pair<unsigned, unsigned>> stack;
|
||||
uint_set on_stack;
|
||||
lbool propagate_ineqs(unsigned idx);
|
||||
|
||||
std::ostream& display_row(std::ostream& out, row const& r, bool values = true) const;
|
||||
var_t get_base_var(row const& r) const { return m_rows[r.id()].m_base; }
|
||||
|
||||
void update_value_core(var_t v, numeral const& delta);
|
||||
void ensure_var(var_t v);
|
||||
|
||||
bool patch();
|
||||
bool propagate_ineqs();
|
||||
bool propagate_row_eqs();
|
||||
bool propagate_row_bounds();
|
||||
bool is_satisfied();
|
||||
|
||||
struct backoff {
|
||||
unsigned m_tries = 0;
|
||||
unsigned m_delay = 1;
|
||||
bool should_propagate() {
|
||||
return ++m_tries >= m_delay;
|
||||
}
|
||||
void update(bool progress) {
|
||||
m_tries = 0;
|
||||
if (progress)
|
||||
m_delay = 1;
|
||||
else
|
||||
++m_delay;
|
||||
}
|
||||
};
|
||||
|
||||
backoff m_propagate_eqs_backoff;
|
||||
backoff m_propagate_bounds_backoff;
|
||||
|
||||
|
||||
|
||||
var_t select_smallest_var() { return m_to_patch.empty()?null_var:m_to_patch.erase_min(); }
|
||||
lbool make_var_feasible(var_t x_i);
|
||||
bool is_infeasible_row(var_t x);
|
||||
bool is_parity_infeasible_row(var_t x);
|
||||
bool is_offset_row(row const& r, numeral& cx, var_t& x, numeral& cy, var_t & y) const;
|
||||
void lookahead_eq(row const& r1, numeral const& cx, var_t x, numeral const& cy, var_t y);
|
||||
void get_offset_eqs(row const& r);
|
||||
void fixed_var_eh(u_dependency* dep, var_t x);
|
||||
var_t find(var_t x) { return m_union_find.find(x); }
|
||||
void merge(var_t x, var_t y) { m_union_find.merge(x, y); }
|
||||
void eq_eh(var_t x, var_t y, u_dependency* dep);
|
||||
bool propagate_row(row const& r);
|
||||
bool propagate_ineq(ineq const& i);
|
||||
bool propagate_strict_bounds(ineq const& i);
|
||||
bool propagate_non_strict_bounds(ineq const& i);
|
||||
bool new_bound(row const& r, var_t x, mod_interval<numeral> const& range);
|
||||
bool new_bound(ineq const& i, var_t x, numeral const& lo, numeral const& hi, u_dependency* a = nullptr, u_dependency* b = nullptr, u_dependency* c = nullptr, u_dependency* d = nullptr);
|
||||
void conflict(ineq const& i, u_dependency* a = nullptr, u_dependency* b = nullptr, u_dependency* c = nullptr, u_dependency* d = nullptr);
|
||||
void conflict(u_dependency* a);
|
||||
void conflict(u_dependency* a, u_dependency* b, u_dependency* c = nullptr, u_dependency* d = nullptr) { conflict(m_deps.mk_join(m_deps.mk_join(a, b), m_deps.mk_join(c, d))); }
|
||||
u_dependency* row2dep(row const& r);
|
||||
void pivot(var_t x_i, var_t x_j, numeral const& b, numeral const& value);
|
||||
numeral value2delta(var_t v, numeral const& new_value) const;
|
||||
numeral value2error(var_t v, numeral const& new_value) const;
|
||||
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(var_t x_i, numeral const& new_value, numeral& out_b);
|
||||
var_t select_pivot_core(var_t x, numeral const& new_value, numeral& out_b);
|
||||
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, m_vars[v]); }
|
||||
bool in_bounds(numeral const& val, mod_interval<numeral> const& range) const { return range.contains(val); }
|
||||
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_fixed(var_t v) const { return lo(v) + 1 == hi(v); }
|
||||
bool is_valid_variable(var_t v) const { return v < m_vars.size(); }
|
||||
bool is_base(var_t x) const { return m_vars[x].m_is_base; }
|
||||
row base2row(var_t x) const { return row(m_vars[x].m_base2row); }
|
||||
numeral const& row2value(row const& r) const { return m_rows[r.id()].m_value; }
|
||||
numeral const& row2base_coeff(row const& r) const { return m_rows[r.id()].m_base_coeff; }
|
||||
var_t row2base(row const& r) const { return m_rows[r.id()].m_base; }
|
||||
bool row_is_integral(row const& r) const { return m_rows[r.id()].m_integral; }
|
||||
void set_base_value(var_t x);
|
||||
numeral solve_for(numeral const& row_value, numeral const& coeff);
|
||||
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);
|
||||
pivot_strategy_t pivot_strategy() { return m_bland ? S_BLAND : S_DEFAULT; }
|
||||
var_t select_error_var(bool least);
|
||||
void set_infeasible_base(var_t v);
|
||||
void set_infeasible_bounds(var_t v);
|
||||
|
||||
u_dependency* mk_leaf(unsigned dep) { return UINT_MAX == dep ? nullptr : m_deps.mk_leaf(dep); }
|
||||
|
||||
// facilities for handling inequalities
|
||||
void add_ineq(var_t v, var_t w, unsigned dep, bool strict);
|
||||
void touch_var(var_t x);
|
||||
|
||||
|
||||
bool is_solved(row const& r) const;
|
||||
bool is_solved(var_t v) const { SASSERT(is_base(v)); return is_solved(base2row(v)); }
|
||||
|
||||
bool well_formed() const;
|
||||
bool well_formed_row(row const& r) const;
|
||||
|
||||
void del_row(row const& r);
|
||||
|
||||
var_t select_pivot_blands(var_t x, numeral const& new_value, numeral& out_b);
|
||||
bool can_improve(var_t x, numeral const& new_value, var_t y, numeral const& b);
|
||||
|
||||
bool pivot_base_vars();
|
||||
bool elim_base(var_t v);
|
||||
|
||||
bool eliminate_var(
|
||||
row const& r_y,
|
||||
col_iterator const& z_col,
|
||||
unsigned tz_b,
|
||||
numeral const& old_value_y);
|
||||
};
|
||||
|
||||
template<typename uint_type>
|
||||
struct generic_uint_ext {
|
||||
typedef uint_type numeral;
|
||||
|
||||
struct manager {
|
||||
typedef uint_type numeral;
|
||||
struct hash {
|
||||
unsigned operator()(numeral const& n) const {
|
||||
return numeral2hash(n);
|
||||
}
|
||||
};
|
||||
struct eq {
|
||||
bool operator()(numeral const& a, numeral const& b) const {
|
||||
return a == b;
|
||||
}
|
||||
};
|
||||
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) {}
|
||||
bool is_zero(numeral const& n) const { return n == 0; }
|
||||
bool is_one(numeral const& n) const { return n == 1; }
|
||||
bool is_even(numeral const& n) const { return (n & 1) == 0; }
|
||||
bool is_minus_one(numeral const& n) const { return n + 1 == 0; }
|
||||
void add(numeral const& a, numeral const& b, numeral& r) { r = a + b; }
|
||||
void sub(numeral const& a, numeral const& b, numeral& r) { r = a - b; }
|
||||
void mul(numeral const& a, numeral const& b, numeral& r) { r = a * b; }
|
||||
void set(numeral& r, numeral const& a) { r = a; }
|
||||
void neg(numeral& a) { a = 0 - a; }
|
||||
numeral inv(numeral const& a) { return 0 - a; }
|
||||
void swap(numeral& a, numeral& b) { std::swap(a, b); }
|
||||
unsigned trailing_zeros(numeral const& a) const { return ::trailing_zeros(a); }
|
||||
numeral mul_inverse(numeral const& x) {
|
||||
if (x == 0)
|
||||
return 0;
|
||||
numeral t0 = 1, t1 = 0 - 1;
|
||||
numeral r0 = x, r1 = 0 - x;
|
||||
while (r1 != 0) {
|
||||
numeral q = r0 / r1;
|
||||
numeral tmp = t1;
|
||||
t1 = t0 - q * t1;
|
||||
t0 = tmp;
|
||||
tmp = r1;
|
||||
r1 = r0 - q * r1;
|
||||
r0 = tmp;
|
||||
}
|
||||
return t0;
|
||||
}
|
||||
numeral gcd(numeral x, numeral y) {
|
||||
if (x == 0)
|
||||
return y;
|
||||
if (y == 0)
|
||||
return x;
|
||||
unsigned tz = trailing_zeros(x);
|
||||
numeral shift = std::min(trailing_zeros(y), tz);
|
||||
x >>= tz;
|
||||
if (x == 1)
|
||||
return x << shift;
|
||||
if (y == 1)
|
||||
return y << shift;
|
||||
if (x == y)
|
||||
return x << shift;
|
||||
do {
|
||||
tz = trailing_zeros(y);
|
||||
y >>= tz;
|
||||
if (x > y)
|
||||
swap(x, y);
|
||||
y -= x;
|
||||
}
|
||||
while (y != 0);
|
||||
return x << shift;
|
||||
}
|
||||
|
||||
std::ostream& display(std::ostream& out, numeral const& x) const {
|
||||
return out << pp(x);
|
||||
}
|
||||
};
|
||||
typedef _scoped_numeral<manager> scoped_numeral;
|
||||
|
||||
};
|
||||
|
||||
typedef generic_uint_ext<uint64_t> uint64_ext;
|
||||
|
||||
|
||||
template<typename Ext>
|
||||
inline std::ostream& operator<<(std::ostream& out, fixplex<Ext> const& fp) {
|
||||
return fp.display(out);
|
||||
}
|
||||
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& out, ineq const& i) {
|
||||
return i.display(out);
|
||||
}
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
File diff suppressed because it is too large
Load diff
|
@ -1,111 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2014 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
mod_interval.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Intervals over fixed precision modular arithmetic
|
||||
|
||||
Author:
|
||||
|
||||
Nikolaj Bjorner (nbjorner) 2021-03-19
|
||||
Jakob Rath 2021-04-6
|
||||
|
||||
--*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "util/rational.h"
|
||||
|
||||
|
||||
template<typename Numeral>
|
||||
struct pp {
|
||||
Numeral n;
|
||||
pp(Numeral const& n):n(n) {}
|
||||
};
|
||||
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& out, pp<uint8_t> const& p) {
|
||||
return out << (unsigned)p.n;
|
||||
}
|
||||
|
||||
template<typename Numeral>
|
||||
inline std::ostream& operator<<(std::ostream& out, pp<Numeral> const& p) {
|
||||
if ((Numeral)(0 - p.n) < p.n)
|
||||
return out << "-" << (Numeral)(0 - p.n);
|
||||
return out << p.n;
|
||||
}
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& out, pp<rational> const& p) {
|
||||
return out << p.n;
|
||||
}
|
||||
|
||||
template<typename Numeral>
|
||||
class mod_interval {
|
||||
bool emp = false;
|
||||
public:
|
||||
Numeral lo { 0 };
|
||||
Numeral hi { 0 };
|
||||
mod_interval() {}
|
||||
mod_interval(Numeral const& l, Numeral const& h): lo(l), hi(h) {}
|
||||
virtual ~mod_interval() {}
|
||||
static mod_interval free() { return mod_interval(0, 0); }
|
||||
static mod_interval empty() { mod_interval i(0, 0); i.emp = true; return i; }
|
||||
|
||||
bool is_free() const { return !emp && lo == hi; }
|
||||
bool is_empty() const { return emp; }
|
||||
bool is_singleton() const { return !is_empty() && (lo + 1 == hi || (hi == 0 && is_max(lo))); }
|
||||
bool contains(Numeral const& n) const;
|
||||
bool contains(mod_interval const& other) const;
|
||||
virtual bool is_max(Numeral const& n) const { return (Numeral)(n + 1) == 0; }
|
||||
Numeral max() const;
|
||||
Numeral min() const;
|
||||
|
||||
void set_free() { lo = hi = 0; emp = false; }
|
||||
void set_bounds(Numeral const& l, Numeral const& h) { lo = l; hi = h; }
|
||||
void set_empty() { emp = true; }
|
||||
|
||||
mod_interval& intersect_ule(Numeral const& h);
|
||||
mod_interval& intersect_uge(Numeral const& l);
|
||||
mod_interval& intersect_ult(Numeral const& h);
|
||||
mod_interval& intersect_ugt(Numeral const& l);
|
||||
mod_interval& intersect_fixed(Numeral const& n);
|
||||
mod_interval& intersect_diff(Numeral const& n);
|
||||
mod_interval& update_lo(Numeral const& new_lo);
|
||||
mod_interval& update_hi(Numeral const& new_hi);
|
||||
|
||||
mod_interval operator&(mod_interval const& other) const;
|
||||
mod_interval operator+(mod_interval const& other) const;
|
||||
mod_interval operator-(mod_interval const& other) const;
|
||||
mod_interval operator*(mod_interval const& other) const;
|
||||
mod_interval operator-() const;
|
||||
mod_interval operator*(Numeral const& n) const;
|
||||
mod_interval operator+(Numeral const& n) const { return mod_interval(lo + n, hi + n); }
|
||||
mod_interval operator-(Numeral const& n) const { return mod_interval(lo - n, hi - n); }
|
||||
mod_interval& operator+=(mod_interval const& other) { *this = *this + other; return *this; }
|
||||
std::ostream& display(std::ostream& out) const {
|
||||
if (is_empty()) return out << "empty";
|
||||
if (is_free()) return out << "free";
|
||||
return out << "[" << pp(lo) << ", " << pp(hi) << "[";
|
||||
}
|
||||
Numeral closest_value(Numeral const& n) const;
|
||||
bool operator==(mod_interval const& other) const {
|
||||
if (is_empty())
|
||||
return other.is_empty();
|
||||
if (is_free())
|
||||
return other.is_free();
|
||||
return lo == other.lo && hi == other.hi;
|
||||
}
|
||||
bool operator!=(mod_interval const& other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Numeral>
|
||||
inline std::ostream& operator<<(std::ostream& out, mod_interval<Numeral> const& i) {
|
||||
return i.display(out);
|
||||
}
|
||||
|
|
@ -1,333 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2014 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
mod_interval_def.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Intervals over fixed precision modular arithmetic
|
||||
|
||||
Author:
|
||||
|
||||
Nikolaj Bjorner (nbjorner) 2021-03-19
|
||||
Jakob Rath 2021-04-6
|
||||
|
||||
--*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "fixplex_mod_interval.h"
|
||||
|
||||
template<typename Numeral>
|
||||
bool mod_interval<Numeral>::contains(Numeral const& n) const {
|
||||
if (is_empty())
|
||||
return false;
|
||||
if (is_free())
|
||||
return true;
|
||||
if (lo < hi)
|
||||
return lo <= n && n < hi;
|
||||
else
|
||||
return lo <= n || n < hi;
|
||||
}
|
||||
|
||||
template<typename Numeral>
|
||||
bool mod_interval<Numeral>::contains(mod_interval const& other) const {
|
||||
if (is_empty())
|
||||
return other.is_empty();
|
||||
if (is_free())
|
||||
return true;
|
||||
if (hi == 0)
|
||||
return lo <= other.lo && (other.lo < other.hi || other.hi == 0);
|
||||
if (lo < hi)
|
||||
return lo <= other.lo && other.hi <= hi;
|
||||
if (other.lo < other.hi && other.hi <= hi)
|
||||
return true;
|
||||
if (other.lo < other.hi && lo <= other.lo)
|
||||
return true;
|
||||
if (other.hi == 0)
|
||||
return lo <= other.lo;
|
||||
SASSERT(other.hi < other.lo && other.hi != 0);
|
||||
SASSERT(hi < lo && hi != 0);
|
||||
return lo <= other.lo && other.hi <= hi;
|
||||
}
|
||||
|
||||
template<typename Numeral>
|
||||
mod_interval<Numeral> mod_interval<Numeral>::operator+(mod_interval<Numeral> const& other) const {
|
||||
if (is_empty())
|
||||
return *this;
|
||||
if (other.is_empty())
|
||||
return other;
|
||||
if (is_free())
|
||||
return *this;
|
||||
if (other.is_free())
|
||||
return other;
|
||||
Numeral sz = (hi - lo) + (other.hi - other.lo);
|
||||
if (sz < (hi - lo))
|
||||
return mod_interval::free();
|
||||
return mod_interval(lo + other.lo, hi + other.hi);
|
||||
}
|
||||
|
||||
template<typename Numeral>
|
||||
mod_interval<Numeral> mod_interval<Numeral>::operator-(mod_interval<Numeral> const& other) const {
|
||||
return *this + (-other);
|
||||
}
|
||||
|
||||
template<typename Numeral>
|
||||
mod_interval<Numeral> mod_interval<Numeral>::operator-() const {
|
||||
if (is_empty())
|
||||
return *this;
|
||||
if (is_free())
|
||||
return *this;
|
||||
return mod_interval(1 - hi, 1 - lo);
|
||||
}
|
||||
|
||||
template<typename Numeral>
|
||||
mod_interval<Numeral> mod_interval<Numeral>::operator*(Numeral const& n) const {
|
||||
if (is_empty())
|
||||
return *this;
|
||||
if (n == 0)
|
||||
return mod_interval(0, 1);
|
||||
if (n == 1)
|
||||
return *this;
|
||||
if (is_free())
|
||||
return *this;
|
||||
Numeral sz = hi - lo;
|
||||
if (0 - n < n) {
|
||||
Numeral mn = 0 - n;
|
||||
Numeral mz = mn * sz;
|
||||
if (mz / mn != sz)
|
||||
return mod_interval::free();
|
||||
return mod_interval((hi - 1) * n, n * lo + 1);
|
||||
}
|
||||
else {
|
||||
Numeral mz = n * sz;
|
||||
if (mz / n != sz)
|
||||
return mod_interval::free();
|
||||
return mod_interval(n * lo, n * (hi - 1) + 1);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Numeral>
|
||||
mod_interval<Numeral> mod_interval<Numeral>::operator&(mod_interval const& other) const {
|
||||
Numeral l, h;
|
||||
if (is_free() || other.is_empty())
|
||||
return other;
|
||||
if (other.is_free() || is_empty())
|
||||
return *this;
|
||||
|
||||
if (lo < hi || hi == 0) {
|
||||
if (other.lo < other.hi || other.hi == 0) {
|
||||
if (hi != 0 && hi <= other.lo)
|
||||
return mod_interval::empty();
|
||||
if (other.hi != 0 && other.hi <= lo)
|
||||
return mod_interval::empty();
|
||||
l = lo >= other.lo ? lo : other.lo;
|
||||
h = hi == 0 ? other.hi : (other.hi == 0 ? hi : (hi <= other.hi ? hi : other.hi));
|
||||
return mod_interval(l, h);
|
||||
}
|
||||
SASSERT(0 < other.hi && other.hi < other.lo);
|
||||
if (other.lo <= lo)
|
||||
return *this;
|
||||
if (other.hi <= lo && lo < hi && hi <= other.lo)
|
||||
return mod_interval::empty();
|
||||
if (lo <= other.hi && other.hi <= hi && hi <= other.lo)
|
||||
return mod_interval(lo, other.hi);
|
||||
if (hi == 0 && lo < other.hi)
|
||||
return *this;
|
||||
if (hi == 0 && other.hi <= lo)
|
||||
return mod_interval(other.lo, hi);
|
||||
if (other.hi <= lo && other.hi <= hi)
|
||||
return mod_interval(other.lo, hi);
|
||||
return *this;
|
||||
}
|
||||
SASSERT(hi < lo);
|
||||
if (other.lo < other.hi || other.hi == 0)
|
||||
return other & *this;
|
||||
SASSERT(other.hi < other.lo);
|
||||
SASSERT(hi != 0);
|
||||
SASSERT(other.hi != 0);
|
||||
if (lo <= other.hi)
|
||||
return *this;
|
||||
if (other.lo <= hi)
|
||||
return other;
|
||||
l = lo <= other.lo ? other.lo : lo;
|
||||
h = hi >= other.hi ? other.hi : hi;
|
||||
return mod_interval(l, h);
|
||||
|
||||
}
|
||||
|
||||
template<typename Numeral>
|
||||
Numeral mod_interval<Numeral>::max() const {
|
||||
if (lo < hi)
|
||||
return hi - 1;
|
||||
else
|
||||
return Numeral(0) - 1;
|
||||
}
|
||||
|
||||
template<typename Numeral>
|
||||
Numeral mod_interval<Numeral>::min() const {
|
||||
if (lo < hi || hi == 0)
|
||||
return lo;
|
||||
else
|
||||
return Numeral(0);
|
||||
}
|
||||
|
||||
|
||||
template<typename Numeral>
|
||||
Numeral mod_interval<Numeral>::closest_value(Numeral const& n) const {
|
||||
if (contains(n))
|
||||
return n;
|
||||
if (is_empty())
|
||||
return n;
|
||||
if ((Numeral)(lo - n) < (Numeral)(n - hi))
|
||||
return lo;
|
||||
return hi - 1;
|
||||
}
|
||||
|
||||
template<typename Numeral>
|
||||
mod_interval<Numeral>& mod_interval<Numeral>::intersect_uge(Numeral const& l) {
|
||||
if (is_empty())
|
||||
return *this;
|
||||
if (lo < hi && hi <= l)
|
||||
set_empty();
|
||||
else if (is_free())
|
||||
lo = l, hi = 0;
|
||||
else if ((lo < hi || hi == 0) && lo < l)
|
||||
lo = l;
|
||||
else if (hi < lo && hi <= l && l <= lo)
|
||||
hi = 0;
|
||||
else if (hi < lo && lo < l)
|
||||
hi = 0, lo = l;
|
||||
else if (0 < l && l < hi && hi < lo)
|
||||
lo = l, hi = 0;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename Numeral>
|
||||
mod_interval<Numeral>& mod_interval<Numeral>::intersect_ugt(Numeral const& l) {
|
||||
if (is_empty())
|
||||
return *this;
|
||||
if (is_max(l))
|
||||
set_empty();
|
||||
else if (is_free())
|
||||
lo = l + 1, hi = 0;
|
||||
else if (lo < hi && hi - 1 <= l)
|
||||
set_empty();
|
||||
else if (lo < hi && l < lo)
|
||||
return *this;
|
||||
else if (lo < hi)
|
||||
lo = l + 1;
|
||||
else if (hi < lo && hi <= l + 1 && l < lo)
|
||||
hi = 0;
|
||||
else if (hi < lo && lo <= l)
|
||||
hi = 0, lo = l + 1;
|
||||
else if (l <= hi && hi < lo)
|
||||
lo = l + 1, hi = 0;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename Numeral>
|
||||
mod_interval<Numeral>& mod_interval<Numeral>::intersect_ule(Numeral const& h) {
|
||||
if (is_empty())
|
||||
return *this;
|
||||
if (is_max(h))
|
||||
return *this;
|
||||
else if (is_free())
|
||||
lo = 0, hi = h + 1;
|
||||
else if (h < lo && (lo < hi || hi == 0))
|
||||
set_empty();
|
||||
else if (hi == 0 && h >= lo)
|
||||
hi = h + 1;
|
||||
else if (lo <= h && h + 1 < hi)
|
||||
hi = h + 1;
|
||||
else if (h < hi && hi < lo)
|
||||
hi = h + 1, lo = 0;
|
||||
else if (hi <= h && h < lo)
|
||||
lo = 0;
|
||||
else if (hi == 0 && hi == h && hi < lo)
|
||||
set_empty();
|
||||
else if (0 < hi && hi == h && hi < lo)
|
||||
lo = 0;
|
||||
else if (0 < hi && hi < h && hi < lo)
|
||||
lo = 0, hi = h + 1;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename Numeral>
|
||||
mod_interval<Numeral>& mod_interval<Numeral>::intersect_ult(Numeral const& h) {
|
||||
if (is_empty())
|
||||
return *this;
|
||||
if (h == 0)
|
||||
set_empty();
|
||||
else if (is_free())
|
||||
lo = 0, hi = h;
|
||||
else if (h <= lo && (lo < hi || hi == 0))
|
||||
set_empty();
|
||||
else if (h > lo && (h < hi || hi == 0))
|
||||
hi = h;
|
||||
else if (hi < lo && h <= hi)
|
||||
hi = h, lo = 0;
|
||||
else if (hi < h && h <= lo)
|
||||
lo = 0;
|
||||
else if (0 < hi && hi < lo && hi + 1 <= h)
|
||||
lo = 0, hi = h;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
template<typename Numeral>
|
||||
mod_interval<Numeral>& mod_interval<Numeral>::intersect_fixed(Numeral const& a) {
|
||||
if (is_empty())
|
||||
return *this;
|
||||
if (!contains(a))
|
||||
set_empty();
|
||||
else if (is_max(a))
|
||||
lo = a, hi = 0;
|
||||
else
|
||||
lo = a, hi = a + 1;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename Numeral>
|
||||
mod_interval<Numeral>& mod_interval<Numeral>::intersect_diff(Numeral const& a) {
|
||||
if (!contains(a) || is_empty())
|
||||
return *this;
|
||||
if (a == lo && a + 1 == hi)
|
||||
set_empty();
|
||||
else if (a == lo && hi == 0 && is_max(a))
|
||||
set_empty();
|
||||
else if (is_free())
|
||||
lo = a + 1, hi = a;
|
||||
else if (0 < hi && hi < lo && a == lo)
|
||||
return *this;
|
||||
else if (a == lo && !is_max(a))
|
||||
lo = a + 1;
|
||||
else if (a + 1 == hi)
|
||||
hi = a;
|
||||
else if (hi == 0 && is_max(a))
|
||||
hi = a;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename Numeral>
|
||||
mod_interval<Numeral>& mod_interval<Numeral>::update_lo(Numeral const& new_lo) {
|
||||
SASSERT(lo <= new_lo);
|
||||
if (lo < hi && hi <= new_lo)
|
||||
set_empty();
|
||||
else
|
||||
lo = new_lo;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename Numeral>
|
||||
mod_interval<Numeral>& mod_interval<Numeral>::update_hi(Numeral const& new_hi) {
|
||||
SASSERT(new_hi <= hi);
|
||||
if (new_hi <= lo && lo < hi)
|
||||
set_empty();
|
||||
else
|
||||
hi = new_hi;
|
||||
return *this;
|
||||
}
|
|
@ -1,288 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2014 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
linear_solver.cpp
|
||||
|
||||
Author:
|
||||
|
||||
Nikolaj Bjorner (nbjorner) 2021-05-14
|
||||
Jakob Rath 2021-05-14
|
||||
|
||||
--*/
|
||||
|
||||
#include "math/bigfix/u256.h"
|
||||
#include "math/polysat/linear_solver.h"
|
||||
#include "math/polysat/fixplex_def.h"
|
||||
#include "math/polysat/solver.h"
|
||||
|
||||
inline unsigned numeral2hash(u256 const& n) { return n.hash(); }
|
||||
|
||||
namespace polysat {
|
||||
|
||||
void linear_solver::push() {
|
||||
m_trail.push_back(trail_i::inc_level_i);
|
||||
for (auto* f : m_fix_ptr)
|
||||
f->push();
|
||||
}
|
||||
|
||||
void linear_solver::pop(unsigned n) {
|
||||
for (auto* f : m_fix_ptr)
|
||||
f->pop(n);
|
||||
while (n > 0) {
|
||||
switch (m_trail.back()) {
|
||||
case trail_i::inc_level_i:
|
||||
--n;
|
||||
break;
|
||||
case trail_i::add_var_i: {
|
||||
auto [v, sz] = m_rows.back();
|
||||
--m_sz2num_vars[sz];
|
||||
m_rows.pop_back();
|
||||
break;
|
||||
}
|
||||
case trail_i::add_mono_i: {
|
||||
auto m = m_monomials.back();
|
||||
m_mono2var.erase(m);
|
||||
m_alloc.deallocate(m.num_vars*sizeof(unsigned), m.vars);
|
||||
m_monomials.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) {
|
||||
fixplex_base* b = m_fix.get(sz, nullptr);
|
||||
if (!b) {
|
||||
switch (sz) {
|
||||
case 8:
|
||||
b = alloc(fixplex<generic_uint_ext<unsigned char>>, s.params(), s.m_lim);
|
||||
break;
|
||||
case 16:
|
||||
b = alloc(fixplex<generic_uint_ext<unsigned short>>, s.params(), s.m_lim);
|
||||
break;
|
||||
case 32:
|
||||
b = alloc(fixplex<generic_uint_ext<unsigned>>, s.params(), s.m_lim);
|
||||
break;
|
||||
case 64:
|
||||
b = alloc(fixplex<uint64_ext>, s.params(), s.m_lim);
|
||||
break;
|
||||
case 128:
|
||||
NOT_IMPLEMENTED_YET();
|
||||
break;
|
||||
case 256:
|
||||
b = alloc(fixplex<generic_uint_ext<u256>>, s.params(), s.m_lim);
|
||||
break;
|
||||
default:
|
||||
NOT_IMPLEMENTED_YET();
|
||||
break;
|
||||
}
|
||||
if (b)
|
||||
m_fix_ptr.push_back(b);
|
||||
m_fix.set(sz, b);
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
|
||||
var_t linear_solver::internalize_pdd(pdd const& p) {
|
||||
unsigned sz = p.power_of_2();
|
||||
linearize(p);
|
||||
if (m_vars.size() == 1 && m_coeffs.back() == 1)
|
||||
return m_vars.back();
|
||||
var_t v = fresh_var(sz);
|
||||
m_vars.push_back(v);
|
||||
m_coeffs.push_back(rational::power_of_two(sz) - 1);
|
||||
auto* f = sz2fixplex(sz);
|
||||
if (f)
|
||||
f->add_row(v, m_vars.size(), m_vars.data(), m_coeffs.data());
|
||||
return v;
|
||||
}
|
||||
|
||||
/**
|
||||
* create the row c.p() - v == 0
|
||||
* when equality is asserted, set range on v as v == 0 or v > 0.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
//
|
||||
// v <= w:
|
||||
// static constraints:
|
||||
// - lo(v) <= lo(w)
|
||||
// - hi(v) <= hi(w)
|
||||
//
|
||||
// special case for inequalities with constant bounds
|
||||
// bounds propagation on fp, then bounds strengthening
|
||||
// based on static constraints
|
||||
// internal backtrack search over bounds
|
||||
// inequality graph (with offsets)
|
||||
//
|
||||
|
||||
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);
|
||||
if (!fp)
|
||||
return;
|
||||
unsigned c_dep = constraint_idx2dep(m_active.size() - 1);
|
||||
rational z(0);
|
||||
if (c.rhs().is_val()) {
|
||||
bool is_max_value = false;
|
||||
if (is_positive)
|
||||
// v <= rhs
|
||||
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, c_dep);
|
||||
return;
|
||||
}
|
||||
|
||||
if (c.lhs().is_val()) {
|
||||
if (is_positive)
|
||||
// w >= lhs
|
||||
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, c_dep);
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_positive)
|
||||
fp->add_le(v, w, c_dep);
|
||||
else
|
||||
fp->add_lt(w, v, c_dep);
|
||||
}
|
||||
|
||||
|
||||
void linear_solver::new_constraint(constraint& c) {
|
||||
if (c.is_ule())
|
||||
new_le(c.to_ule());
|
||||
}
|
||||
|
||||
void linear_solver::activate_constraint(bool is_positive, constraint& c) {
|
||||
if (!c.is_ule())
|
||||
return;
|
||||
m_active.push_back(&c);
|
||||
m_trail.push_back(trail_i::set_active_i);
|
||||
assert_le(is_positive, c.to_ule());
|
||||
}
|
||||
|
||||
void linear_solver::linearize(pdd const& p) {
|
||||
unsigned sz = p.power_of_2();
|
||||
m_vars.reset();
|
||||
m_coeffs.reset();
|
||||
for (auto const& m : p) {
|
||||
m_vars.push_back(mono2var(sz, m.vars));
|
||||
m_coeffs.push_back(m.coeff);
|
||||
}
|
||||
}
|
||||
|
||||
var_t linear_solver::mono2var(unsigned sz, unsigned_vector const& var) {
|
||||
mono_info m(sz, var.size(), var.data()), m1;
|
||||
if (m_mono2var.find(m, m1))
|
||||
return m1.var;
|
||||
m.vars = static_cast<unsigned*>(m_alloc.allocate(var.size()*sizeof(unsigned)));
|
||||
for (unsigned i = 0; i < var.size(); ++i)
|
||||
m.vars[i] = var[i];
|
||||
m.var = fresh_var(sz);
|
||||
m_mono2var.insert(m);
|
||||
m_monomials.push_back(m);
|
||||
m_trail.push_back(trail_i::add_mono_i);
|
||||
return m.var;
|
||||
}
|
||||
|
||||
var_t linear_solver::pvar2var(unsigned sz, pvar v) {
|
||||
unsigned_vector vars;
|
||||
vars.push_back(v);
|
||||
return mono2var(sz, vars);
|
||||
}
|
||||
|
||||
var_t linear_solver::fresh_var(unsigned sz) {
|
||||
m_sz2num_vars.reserve(sz + 1);
|
||||
m_trail.push_back(trail_i::add_var_i);
|
||||
m_rows.push_back(std::make_pair(0, sz));
|
||||
return m_sz2num_vars[sz]++;
|
||||
}
|
||||
|
||||
void linear_solver::set_value(pvar v, rational const& value, unsigned dep) {
|
||||
unsigned sz = s.size(v);
|
||||
auto* fp = sz2fixplex(sz);
|
||||
if (!fp)
|
||||
return;
|
||||
var_t w = pvar2var(sz, v);
|
||||
fp->set_value(w, value, external_dep2dep(dep));
|
||||
}
|
||||
|
||||
void linear_solver::set_bound(pvar v, rational const& lo, rational const& hi, unsigned dep) {
|
||||
unsigned sz = s.size(v);
|
||||
auto* fp = sz2fixplex(sz);
|
||||
if (!fp)
|
||||
return;
|
||||
var_t w = pvar2var(sz, v);
|
||||
fp->set_bounds(w, lo, hi, external_dep2dep(dep));
|
||||
}
|
||||
|
||||
/**
|
||||
* check integer modular feasibility under current bounds.
|
||||
* and inequalities
|
||||
*/
|
||||
lbool linear_solver::check() {
|
||||
lbool res = l_true;
|
||||
m_unsat_f = nullptr;
|
||||
for (auto* fp : m_fix_ptr) {
|
||||
lbool r = fp->make_feasible();
|
||||
if (r == l_false) {
|
||||
m_unsat_f = fp;
|
||||
return r;
|
||||
}
|
||||
if (r == l_undef)
|
||||
res = l_undef;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
void linear_solver::unsat_core(ptr_vector<constraint>& cs, unsigned_vector& deps) {
|
||||
SASSERT(m_unsat_f);
|
||||
deps.reset();
|
||||
cs.reset();
|
||||
for (unsigned dep : m_unsat_f->get_unsat_core()) {
|
||||
if (is_constraint_dep(dep))
|
||||
cs.push_back(m_active[dep2constraint_idx(dep)]);
|
||||
else
|
||||
deps.push_back(dep2external_dep(dep));
|
||||
}
|
||||
}
|
||||
|
||||
// current value assigned to (linear) variable according to tableau.
|
||||
bool linear_solver::value(pvar v, rational& val) {
|
||||
unsigned sz = s.size(v);
|
||||
auto* fp = sz2fixplex(sz);
|
||||
if (!fp)
|
||||
return false;
|
||||
val = fp->get_value(pvar2var(sz, v));
|
||||
return true;
|
||||
}
|
||||
|
||||
};
|
||||
|
|
@ -1,144 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2014 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
linear_solver.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Fixed-precision unsigned integer linear solver
|
||||
|
||||
This wraps around fixplex and translates polynomials
|
||||
into linear form.
|
||||
Equalities, Inequalities are converted into rows and slack variables.
|
||||
Slack variables are bounded when constraints are activated.
|
||||
It also handles backtracking state: bounds that are activated inside one
|
||||
scope are de-activated when exiting the scope.
|
||||
|
||||
Author:
|
||||
|
||||
Nikolaj Bjorner (nbjorner) 2021-05-14
|
||||
Jakob Rath 2021-05-14
|
||||
|
||||
--*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "util/hashtable.h"
|
||||
#include "util/small_object_allocator.h"
|
||||
#include "math/polysat/fixplex.h"
|
||||
#include "math/polysat/constraint.h"
|
||||
#include "math/polysat/ule_constraint.h"
|
||||
|
||||
namespace polysat {
|
||||
|
||||
class solver;
|
||||
|
||||
class linear_solver {
|
||||
enum trail_i {
|
||||
inc_level_i,
|
||||
add_var_i,
|
||||
add_mono_i,
|
||||
set_active_i
|
||||
};
|
||||
|
||||
struct mono_info {
|
||||
unsigned sz { 0 };
|
||||
unsigned num_vars { 0 };
|
||||
unsigned* vars { nullptr };
|
||||
unsigned var { 0 };
|
||||
mono_info(unsigned sz, unsigned num_vars, unsigned* vars):
|
||||
sz(sz),
|
||||
num_vars(num_vars),
|
||||
vars(vars)
|
||||
{}
|
||||
mono_info() {}
|
||||
struct hash {
|
||||
unsigned operator()(mono_info const& i) const {
|
||||
// TODO
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
struct eq {
|
||||
bool operator()(mono_info const& a, mono_info const& b) const {
|
||||
if (a.num_vars != b.num_vars)
|
||||
return false;
|
||||
for (unsigned i = 0; i < a.num_vars; ++i)
|
||||
if (a.vars[i] != b.vars[i])
|
||||
return false;
|
||||
return a.sz == b.sz;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
solver& s;
|
||||
scoped_ptr_vector<fixplex_base> m_fix;
|
||||
ptr_vector<fixplex_base> m_fix_ptr;
|
||||
svector<trail_i> m_trail;
|
||||
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;
|
||||
svector<std::pair<var_t, var_t>> m_bool_var2row;
|
||||
|
||||
hashtable<mono_info, mono_info::hash, mono_info::eq> m_mono2var;
|
||||
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_le(ule_constraint& le);
|
||||
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"); }
|
||||
|
||||
// distinguish constraint and justification dependencies
|
||||
unsigned external_dep2dep(unsigned dep) const { return dep * 2; }
|
||||
unsigned constraint_idx2dep(unsigned idx) const { return 1 + (idx * 2); }
|
||||
bool is_constraint_dep(unsigned dep) const { return 0 != (dep & 0x1); }
|
||||
unsigned dep2constraint_idx(unsigned dep) const { return dep >> 2; }
|
||||
unsigned dep2external_dep(unsigned dep) const { return dep >> 2; }
|
||||
|
||||
public:
|
||||
linear_solver(solver& s):
|
||||
s(s),
|
||||
m_alloc("mononials")
|
||||
{}
|
||||
|
||||
void push();
|
||||
void pop(unsigned n);
|
||||
void new_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);
|
||||
void activate_constraint(signed_constraint c) { activate_constraint(c.is_positive(), *c.get()); }
|
||||
|
||||
// check integer modular feasibility under current bounds.
|
||||
lbool check();
|
||||
void unsat_core(ptr_vector<constraint>& constraints, unsigned_vector& deps);
|
||||
|
||||
// current value assigned to (linear) variable according to tableau.
|
||||
bool value(pvar v, rational& val);
|
||||
|
||||
std::ostream& display(std::ostream& out) const { return out; }
|
||||
void collect_statistics(::statistics & st) const {}
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
|
@ -139,7 +139,6 @@ namespace polysat {
|
|||
friend class inference_engine;
|
||||
friend class file_inference_logger;
|
||||
friend class forbidden_intervals;
|
||||
friend class linear_solver;
|
||||
friend class viable;
|
||||
friend class viable_fallback;
|
||||
friend class search_state;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue