mirror of
https://github.com/Z3Prover/z3
synced 2025-04-15 21:38:44 +00:00
working on hilbert basis
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
parent
0c0fe40446
commit
6e7d04f94e
|
@ -26,364 +26,219 @@ typedef u_map<unsigned> offset_refs_t;
|
|||
template<typename Value>
|
||||
class rational_map : public map<rational, Value, rational::hash_proc, rational::eq_proc> {};
|
||||
|
||||
class rational_abs_lt {
|
||||
vector<rational> & m_values;
|
||||
public:
|
||||
rational_abs_lt(vector<rational> & values):
|
||||
m_values(values) {
|
||||
}
|
||||
bool operator()(int v1, int v2) const {
|
||||
return m_values[v1] < m_values[v2];
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class hilbert_basis::rational_heap {
|
||||
vector<numeral> m_u2r; // [index |-> weight]
|
||||
rational_map<unsigned> m_r2u; // [weight |-> index]
|
||||
rational_abs_lt m_lt; // less_than on indices
|
||||
heap<rational_abs_lt> m_heap; // binary heap over weights
|
||||
public:
|
||||
|
||||
rational_heap(): m_lt(m_u2r), m_heap(10, m_lt) {}
|
||||
|
||||
vector<numeral>& u2r() { return m_u2r; }
|
||||
|
||||
void insert(unsigned v) {
|
||||
m_heap.insert(v);
|
||||
}
|
||||
|
||||
void reset() {
|
||||
m_u2r.reset();
|
||||
m_r2u.reset();
|
||||
m_heap.reset();
|
||||
}
|
||||
|
||||
bool is_declared(numeral const& r, unsigned& val) const {
|
||||
return m_r2u.find(r, val);
|
||||
}
|
||||
|
||||
unsigned declare(numeral const& r) {
|
||||
SASSERT(!m_r2u.contains(r));
|
||||
unsigned val = m_u2r.size();
|
||||
m_u2r.push_back(r);
|
||||
m_r2u.insert(r, val);
|
||||
m_heap.set_bounds(val+1);
|
||||
return val;
|
||||
}
|
||||
|
||||
void find_le(unsigned val, int_vector & result) {
|
||||
m_heap.find_le(val, result);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class hilbert_basis::weight_map {
|
||||
class hilbert_basis::value_index {
|
||||
struct stats {
|
||||
unsigned m_num_comparisons;
|
||||
unsigned m_num_hit;
|
||||
unsigned m_num_miss;
|
||||
|
||||
stats() { reset(); }
|
||||
void reset() { memset(this, 0, sizeof(*this)); }
|
||||
};
|
||||
|
||||
rational_heap m_heap;
|
||||
vector<unsigned_vector> m_offsets; // [index |-> offset-list]
|
||||
int_vector m_le; // recycled set of indices with lesser weights
|
||||
stats m_stats;
|
||||
svector<offset_t>& m_found;
|
||||
offset_refs_t& m_refs;
|
||||
unsigned m_cost;
|
||||
typedef int_hashtable<int_hash, default_eq<int> > int_table;
|
||||
hilbert_basis& hb;
|
||||
int_table m_table;
|
||||
stats m_stats;
|
||||
|
||||
unsigned get_value(numeral const& w) {
|
||||
numeral r = abs(w);
|
||||
unsigned val;
|
||||
if (!m_heap.is_declared(r, val)) {
|
||||
val = m_heap.declare(r);
|
||||
SASSERT(val == m_offsets.size());
|
||||
if (r.is_nonneg()) {
|
||||
m_heap.insert(val);
|
||||
}
|
||||
m_offsets.push_back(unsigned_vector());
|
||||
}
|
||||
return val;
|
||||
}
|
||||
public:
|
||||
weight_map(svector<offset_t>& found, offset_refs_t& refs): m_found(found), m_refs(refs) {}
|
||||
|
||||
void insert(offset_t idx, numeral const& w) {
|
||||
unsigned val = get_value(w);
|
||||
m_offsets[val].push_back(idx.m_offset);
|
||||
value_index(hilbert_basis& hb):
|
||||
hb(hb)
|
||||
{}
|
||||
|
||||
void insert(offset_t idx, values const& vs) {
|
||||
m_table.insert(idx.m_offset);
|
||||
}
|
||||
|
||||
void remove(offset_t idx, numeral const& w) {
|
||||
unsigned val = get_value(w);
|
||||
m_offsets[val].erase(idx.m_offset);
|
||||
}
|
||||
|
||||
unsigned get_size() const {
|
||||
unsigned sz = 0;
|
||||
for (unsigned i = 0; i < m_offsets.size(); ++i) {
|
||||
sz += m_offsets[i].size();
|
||||
}
|
||||
return sz;
|
||||
void remove(offset_t idx, values const& vs) {
|
||||
m_table.remove(idx.m_offset);
|
||||
}
|
||||
|
||||
void reset() {
|
||||
m_offsets.reset();
|
||||
m_heap.reset();
|
||||
m_le.reset();
|
||||
}
|
||||
|
||||
unsigned get_cost() const { return m_cost; }
|
||||
|
||||
/**
|
||||
retrieve
|
||||
*/
|
||||
bool init_find(numeral const& w, offset_t idx) {
|
||||
m_le.reset();
|
||||
m_found.reset();
|
||||
m_cost = 0;
|
||||
unsigned val = get_value(w);
|
||||
// for positive values, the weights should be less or equal.
|
||||
// for non-positive values, the weights have to be the same.
|
||||
if (w.is_pos()) {
|
||||
m_heap.find_le(val, m_le);
|
||||
}
|
||||
else {
|
||||
m_le.push_back(val);
|
||||
}
|
||||
for (unsigned i = 0; i < m_le.size(); ++i) {
|
||||
if (m_heap.u2r()[m_le[i]].is_zero() && !w.is_zero()) {
|
||||
continue;
|
||||
}
|
||||
unsigned_vector const& offsets = m_offsets[m_le[i]];
|
||||
for (unsigned j = 0; j < offsets.size(); ++j) {
|
||||
unsigned offs = offsets[j];
|
||||
++m_stats.m_num_comparisons;
|
||||
++m_cost;
|
||||
if (offs != idx.m_offset) {
|
||||
m_refs.insert(offs, 0);
|
||||
m_found.push_back(offset_t(offs));
|
||||
}
|
||||
}
|
||||
}
|
||||
return !m_found.empty();
|
||||
m_table.reset();
|
||||
}
|
||||
|
||||
unsigned get_find_cost(numeral const& w) {
|
||||
m_le.reset();
|
||||
unsigned cost = 0;
|
||||
unsigned val = get_value(w);
|
||||
m_heap.find_le(val, m_le);
|
||||
for (unsigned i = 0; i < m_le.size(); ++i) {
|
||||
cost += m_offsets[m_le[i]].size();
|
||||
}
|
||||
return cost;
|
||||
}
|
||||
|
||||
bool update_find(unsigned round, numeral const& w, offset_t idx) {
|
||||
m_found.reset();
|
||||
m_le.reset();
|
||||
m_cost = 0;
|
||||
unsigned vl = get_value(w);
|
||||
m_heap.find_le(vl, m_le);
|
||||
for (unsigned i = 0; i < m_le.size(); ++i) {
|
||||
unsigned_vector const& offsets = m_offsets[m_le[i]];
|
||||
for (unsigned j = 0; j < offsets.size(); ++j) {
|
||||
unsigned offs = offsets[j];
|
||||
++m_stats.m_num_comparisons;
|
||||
++m_cost;
|
||||
if (offs != idx.m_offset && m_refs.find(offs, vl) && vl == round) {
|
||||
m_refs.insert(offs, round + 1);
|
||||
m_found.push_back(offset_t(offs));
|
||||
}
|
||||
bool find(offset_t idx, values const& vs, offset_t& found_idx) {
|
||||
// display_profile(idx, std::cout);
|
||||
int_table::iterator it = m_table.begin(), end = m_table.end();
|
||||
for (; it != end; ++it) {
|
||||
offset_t offs(*it);
|
||||
++m_stats.m_num_comparisons;
|
||||
if (*it != idx.m_offset && hb.is_subsumed(idx, offs)) {
|
||||
found_idx = offs;
|
||||
++m_stats.m_num_hit;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return !m_found.empty();
|
||||
}
|
||||
++m_stats.m_num_miss;
|
||||
return false;
|
||||
}
|
||||
|
||||
void collect_statistics(statistics& st) const {
|
||||
st.update("hb.index.num_comparisons", m_stats.m_num_comparisons);
|
||||
st.update("hb.index.num_hit", m_stats.m_num_hit);
|
||||
st.update("hb.index.num_miss", m_stats.m_num_miss);
|
||||
}
|
||||
|
||||
void reset_statistics() {
|
||||
m_stats.reset();
|
||||
}
|
||||
|
||||
unsigned size() const {
|
||||
return m_table.size();
|
||||
}
|
||||
private:
|
||||
void display_profile(offset_t idx, std::ostream& out) {
|
||||
unsigned_vector leq;
|
||||
unsigned nv = hb.get_num_vars();
|
||||
values const& vs = hb.vec(idx);
|
||||
leq.resize(nv+1);
|
||||
numeral maxw(0);
|
||||
for (unsigned i = 0; i < nv; ++i) {
|
||||
if (!hb.is_abs_geq(maxw, vs[i])) {
|
||||
maxw = vs[i];
|
||||
}
|
||||
}
|
||||
unsigned num_below_max = 0;
|
||||
int_table::iterator it = m_table.begin(), end = m_table.end();
|
||||
for (; it != end; ++it) {
|
||||
offset_t offs(*it);
|
||||
values const& ws = hb.vec(offs);
|
||||
if (ws.weight() <= vs.weight()) {
|
||||
leq[0]++;
|
||||
}
|
||||
bool filtered = false;
|
||||
for (unsigned i = 0; i < nv; ++i) {
|
||||
if (hb.is_abs_geq(vs[i], ws[i])) {
|
||||
leq[i+1]++;
|
||||
}
|
||||
if (!hb.is_abs_geq(maxw, ws[i])) {
|
||||
filtered = true;
|
||||
}
|
||||
}
|
||||
if (!filtered) {
|
||||
++num_below_max;
|
||||
}
|
||||
}
|
||||
out << vs.weight() << ":" << leq[0] << " ";
|
||||
for (unsigned i = 0; i < nv; ++i) {
|
||||
out << vs[i] << ":" << leq[i+1] << " ";
|
||||
}
|
||||
out << " max<= " << num_below_max;
|
||||
out << "\n";
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
class hilbert_basis::index {
|
||||
// for each index, a heap of weights.
|
||||
// for each weight a list of offsets
|
||||
// for each non-positive weight a separate index.
|
||||
// for positive weights a shared value index.
|
||||
|
||||
struct stats {
|
||||
unsigned m_num_comparisons;
|
||||
unsigned m_num_find;
|
||||
unsigned m_num_insert;
|
||||
stats() { reset(); }
|
||||
void reset() { memset(this, 0, sizeof(*this)); }
|
||||
};
|
||||
|
||||
hilbert_basis& hb;
|
||||
offset_refs_t m_refs;
|
||||
svector<offset_t> m_found;
|
||||
ptr_vector<weight_map> m_values;
|
||||
weight_map m_weight;
|
||||
stats m_stats;
|
||||
typedef rational_map<value_index*> value_map;
|
||||
hilbert_basis& hb;
|
||||
value_map m_neg;
|
||||
value_index m_pos;
|
||||
value_index m_zero;
|
||||
stats m_stats;
|
||||
|
||||
public:
|
||||
|
||||
index(hilbert_basis& hb): hb(hb), m_weight(m_found, m_refs) {}
|
||||
|
||||
~index() {
|
||||
for (unsigned i = 0; i < m_values.size(); ++i) {
|
||||
dealloc(m_values[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void init(unsigned num_vars) {
|
||||
if (m_values.empty()) {
|
||||
for (unsigned i = 0; i < num_vars; ++i) {
|
||||
m_values.push_back(alloc(weight_map, m_found, m_refs));
|
||||
}
|
||||
}
|
||||
SASSERT(m_values.size() == num_vars);
|
||||
}
|
||||
index(hilbert_basis& hb): hb(hb), m_pos(hb), m_zero(hb) {}
|
||||
|
||||
void insert(offset_t idx, values const& vs) {
|
||||
++m_stats.m_num_insert;
|
||||
#if 0
|
||||
for (unsigned i = 0; i < m_values.size(); ++i) {
|
||||
m_values[i]->insert(idx, vs[i]);
|
||||
if (vs.weight().is_pos()) {
|
||||
m_pos.insert(idx, vs);
|
||||
}
|
||||
else if (vs.weight().is_zero()) {
|
||||
m_zero.insert(idx, vs);
|
||||
}
|
||||
else {
|
||||
value_index* map = 0;
|
||||
if (!m_neg.find(vs.weight(), map)) {
|
||||
map = alloc(value_index, hb);
|
||||
m_neg.insert(vs.weight(), map);
|
||||
}
|
||||
map->insert(idx, vs);
|
||||
}
|
||||
#endif
|
||||
m_weight.insert(idx, vs.value());
|
||||
}
|
||||
|
||||
void remove(offset_t idx, values const& vs) {
|
||||
#if 0
|
||||
for (unsigned i = 0; i < m_values.size(); ++i) {
|
||||
m_values[i]->remove(idx, vs[i]);
|
||||
if (vs.weight().is_pos()) {
|
||||
m_pos.remove(idx, vs);
|
||||
}
|
||||
#endif
|
||||
m_weight.remove(idx, vs.value());
|
||||
else if (vs.weight().is_zero()) {
|
||||
m_zero.remove(idx, vs);
|
||||
}
|
||||
else {
|
||||
m_neg.find(vs.weight())->remove(idx, vs);
|
||||
}
|
||||
}
|
||||
|
||||
bool find(values const& vs, offset_t idx, offset_t& found_idx) {
|
||||
bool find(offset_t idx, values const& vs, offset_t& found_idx) {
|
||||
++m_stats.m_num_find;
|
||||
m_refs.reset();
|
||||
bool found = m_weight.init_find(vs.value(), idx);
|
||||
TRACE("hilbert_basis", tout << "init: " << m_found.size() << " cost: " << m_weight.get_cost() << "\n";);
|
||||
#if 0
|
||||
std::cout << vs.value() << " " << m_found.size() << " ";
|
||||
for (unsigned i = 0; i < m_values.size(); ++i) {
|
||||
std::cout << vs[i] << ": " << m_values[i]->get_find_cost(vs[i]) << " ";
|
||||
if (vs.weight().is_pos()) {
|
||||
return m_pos.find(idx, vs, found_idx);
|
||||
}
|
||||
std::cout << "\n";
|
||||
#endif
|
||||
#if 0
|
||||
for (unsigned i = 0; found && i < m_values.size(); ++i) {
|
||||
found = m_values[i]->update_find(i, vs[i], idx);
|
||||
std::cout << vs[i] << ": " << m_found.size() << " ";
|
||||
TRACE("hilbert_basis", tout << "update " << i << ": " << m_found.size() << " cost: " << m_values[i]->get_cost() << "\n";);
|
||||
else if (vs.weight().is_zero()) {
|
||||
return m_zero.find(idx, vs, found_idx);
|
||||
}
|
||||
#else
|
||||
for (unsigned i = 0; i < m_found.size(); ++i) {
|
||||
if (is_subsumed(idx, m_found[i])) {
|
||||
found_idx = m_found[i];
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
#endif
|
||||
|
||||
if (found) {
|
||||
found_idx = m_found[0];
|
||||
}
|
||||
return found;
|
||||
}
|
||||
else {
|
||||
value_index* map;
|
||||
return
|
||||
m_neg.find(vs.weight(), map) &&
|
||||
map->find(idx, vs, found_idx);
|
||||
}
|
||||
}
|
||||
|
||||
void reset() {
|
||||
for (unsigned i = 0; i < m_values.size(); ++i) {
|
||||
m_values[i]->reset();
|
||||
m_pos.reset();
|
||||
m_neg.reset();
|
||||
value_map::iterator it = m_neg.begin(), end = m_neg.end();
|
||||
for (; it != end; ++it) {
|
||||
it->m_value->reset();
|
||||
}
|
||||
m_weight.reset();
|
||||
m_refs.reset();
|
||||
}
|
||||
|
||||
void collect_statistics(statistics& st) const {
|
||||
m_weight.collect_statistics(st);
|
||||
for (unsigned i = 0; i < m_values.size(); ++i) {
|
||||
m_values[i]->collect_statistics(st);
|
||||
}
|
||||
st.update("hb.index.num_find", m_stats.m_num_find);
|
||||
m_pos.collect_statistics(st);
|
||||
m_zero.collect_statistics(st);
|
||||
value_map::iterator it = m_neg.begin(), end = m_neg.end();
|
||||
for (; it != end; ++it) {
|
||||
it->m_value->collect_statistics(st);
|
||||
}
|
||||
st.update("hb.index.num_find", m_stats.m_num_find);
|
||||
st.update("hb.index.num_insert", m_stats.m_num_insert);
|
||||
st.update("hb.index.size", m_weight.get_size());
|
||||
st.update("hb.index.size", size());
|
||||
}
|
||||
|
||||
void reset_statistics() {
|
||||
m_stats.reset();
|
||||
m_weight.reset_statistics();
|
||||
for (unsigned i = 0; i < m_values.size(); ++i) {
|
||||
m_values[i]->reset_statistics();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Vector v is subsumed by vector w if
|
||||
|
||||
v[i] >= w[i] for each index i.
|
||||
|
||||
a*v >= a*w for the evaluation of vectors with respect to a.
|
||||
|
||||
a*v < 0 => a*v = a*w
|
||||
|
||||
|
||||
Justification:
|
||||
|
||||
let u := v - w, then
|
||||
|
||||
u[i] >= 0 for each index i
|
||||
|
||||
a*u = a*(v-w) >= 0
|
||||
|
||||
So v = u + w, where a*u >= 0, a*w >= 0.
|
||||
|
||||
If a*v >= a*w >= 0 then v and w are linear
|
||||
solutions of e_i, and also v-w is a solution.
|
||||
|
||||
If a*v = a*w < 0, then a*(v-w) = 0, so v can be obtained from w + (v - w).
|
||||
|
||||
*/
|
||||
|
||||
bool is_subsumed(offset_t i, offset_t j) const {
|
||||
values v = hb.vec(i);
|
||||
values w = hb.vec(j);
|
||||
numeral const& n = v.value();
|
||||
numeral const& m = w.value();
|
||||
bool r =
|
||||
i.m_offset != j.m_offset &&
|
||||
n >= m && (!m.is_neg() || n == m) &&
|
||||
is_geq(v, w);
|
||||
CTRACE("hilbert_basis", r,
|
||||
hb.display(tout, i);
|
||||
tout << " <= \n";
|
||||
hb.display(tout, j);
|
||||
tout << "\n";);
|
||||
return r;
|
||||
}
|
||||
|
||||
bool is_geq(values v, values w) const {
|
||||
unsigned nv = hb.get_num_vars();
|
||||
for (unsigned i = 0; i < nv; ++i) {
|
||||
if (v[i] < w[i]) {
|
||||
return false;
|
||||
}
|
||||
m_pos.reset_statistics();
|
||||
m_zero.reset_statistics();
|
||||
value_map::iterator it = m_neg.begin(), end = m_neg.end();
|
||||
for (; it != end; ++it) {
|
||||
it->m_value->reset_statistics();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
private:
|
||||
unsigned size() const {
|
||||
unsigned sz = m_pos.size();
|
||||
sz += m_zero.size();
|
||||
value_map::iterator it = m_neg.begin(), end = m_neg.end();
|
||||
for (; it != end; ++it) {
|
||||
sz += it->m_value->size();
|
||||
}
|
||||
return sz;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -391,18 +246,25 @@ public:
|
|||
*/
|
||||
|
||||
class hilbert_basis::passive {
|
||||
struct lt {
|
||||
passive& p;
|
||||
lt(passive& p): p(p) {}
|
||||
|
||||
bool operator()(int v1, int v2) const {
|
||||
return p(v1, v2);
|
||||
}
|
||||
};
|
||||
hilbert_basis& hb;
|
||||
svector<offset_t> m_passive;
|
||||
vector<numeral> m_weights;
|
||||
unsigned_vector m_free_list;
|
||||
rational_abs_lt m_lt; // less_than on indices
|
||||
heap<rational_abs_lt> m_heap; // binary heap over weights
|
||||
lt m_lt;
|
||||
heap<lt> m_heap; // binary heap over weights
|
||||
|
||||
numeral get_weight(offset_t idx) {
|
||||
numeral get_value(offset_t idx) const {
|
||||
numeral w(0);
|
||||
unsigned nv = hb.get_num_vars();
|
||||
for (unsigned i = 0; i < nv; ++i) {
|
||||
w += hb.vec(idx)[i];
|
||||
w += abs(hb.vec(idx)[i]);
|
||||
}
|
||||
return w;
|
||||
}
|
||||
|
@ -411,14 +273,13 @@ public:
|
|||
|
||||
passive(hilbert_basis& hb):
|
||||
hb(hb) ,
|
||||
m_lt(m_weights),
|
||||
m_lt(*this),
|
||||
m_heap(10, m_lt)
|
||||
{}
|
||||
|
||||
void reset() {
|
||||
m_heap.reset();
|
||||
m_free_list.reset();
|
||||
m_weights.reset();
|
||||
m_passive.reset();
|
||||
}
|
||||
|
||||
|
@ -440,14 +301,12 @@ public:
|
|||
if (m_free_list.empty()) {
|
||||
v = m_passive.size();
|
||||
m_passive.push_back(idx);
|
||||
m_weights.push_back(get_weight(idx));
|
||||
m_heap.set_bounds(v+1);
|
||||
}
|
||||
else {
|
||||
v = m_free_list.back();
|
||||
m_free_list.pop_back();
|
||||
m_passive[v] = idx;
|
||||
m_weights[v] = get_weight(idx);
|
||||
}
|
||||
m_heap.insert(v);
|
||||
}
|
||||
|
@ -478,6 +337,43 @@ public:
|
|||
iterator end() {
|
||||
return iterator(*this, m_passive.size());
|
||||
}
|
||||
|
||||
public:
|
||||
/**
|
||||
Prefer positive weights to negative.
|
||||
If both weights are positive, prefer the smallest weight.
|
||||
If weights are the same, prefer the one that has smallest sum of values.
|
||||
*/
|
||||
bool operator()(int v1, int v2) const {
|
||||
offset_t idx1 = m_passive[v1];
|
||||
offset_t idx2 = m_passive[v2];
|
||||
return get_value(idx1) < get_value(idx2);
|
||||
#if 0
|
||||
values const& vec1 = hb.vec(idx1);
|
||||
values const& vec2 = hb.vec(idx2);
|
||||
numeral const& w1 = vec1.weight();
|
||||
numeral const& w2 = vec2.weight();
|
||||
SASSERT(!w1.is_zero());
|
||||
SASSERT(!w2.is_zero());
|
||||
|
||||
if (w1.is_pos()) {
|
||||
if (w2.is_neg()) {
|
||||
return true;
|
||||
}
|
||||
if (w1 != w2) {
|
||||
return w1 < w2;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (w2.is_pos()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
SASSERT(w1 == w2);
|
||||
return get_value(idx1) < get_value(idx2);
|
||||
#endif
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
hilbert_basis::hilbert_basis():
|
||||
|
@ -529,9 +425,6 @@ void hilbert_basis::add_ge(num_vector const& v, numeral const& b) {
|
|||
num_vector w;
|
||||
w.push_back(-b);
|
||||
w.append(v);
|
||||
if (m_ineqs.empty()) {
|
||||
m_index->init(w.size());
|
||||
}
|
||||
m_ineqs.push_back(w);
|
||||
}
|
||||
|
||||
|
@ -561,6 +454,14 @@ void hilbert_basis::add_eq(num_vector const& v) {
|
|||
add_ge(v);
|
||||
}
|
||||
|
||||
void hilbert_basis::set_is_int(unsigned var_index) {
|
||||
//
|
||||
// The 0't index is reserved for the constant
|
||||
// coefficient. Shift indices by 1.
|
||||
//
|
||||
m_ints.push_back(var_index+1);
|
||||
}
|
||||
|
||||
unsigned hilbert_basis::get_num_vars() const {
|
||||
if (m_ineqs.empty()) {
|
||||
return 0;
|
||||
|
@ -580,26 +481,34 @@ void hilbert_basis::init_basis() {
|
|||
m_free_list.reset();
|
||||
unsigned num_vars = get_num_vars();
|
||||
for (unsigned i = 0; i < num_vars; ++i) {
|
||||
num_vector w(num_vars, numeral(0));
|
||||
w[i] = numeral(1);
|
||||
offset_t idx = alloc_vector();
|
||||
values v = vec(idx);
|
||||
for (unsigned i = 0; i < num_vars; ++i) {
|
||||
v[i] = w[i];
|
||||
}
|
||||
m_basis.push_back(idx);
|
||||
add_unit_vector(i, numeral(1));
|
||||
}
|
||||
for (unsigned i = 0; i < m_ints.size(); ++i) {
|
||||
add_unit_vector(m_ints[i], numeral(-1));
|
||||
}
|
||||
}
|
||||
|
||||
void hilbert_basis::add_unit_vector(unsigned i, numeral const& e) {
|
||||
unsigned num_vars = get_num_vars();
|
||||
num_vector w(num_vars, numeral(0));
|
||||
w[i] = e;
|
||||
offset_t idx = alloc_vector();
|
||||
values v = vec(idx);
|
||||
for (unsigned j = 0; j < num_vars; ++j) {
|
||||
v[j] = w[j];
|
||||
}
|
||||
m_basis.push_back(idx);
|
||||
}
|
||||
|
||||
lbool hilbert_basis::saturate() {
|
||||
init_basis();
|
||||
init_basis();
|
||||
for (unsigned i = 0; !m_cancel && i < m_ineqs.size(); ++i) {
|
||||
select_inequality(i);
|
||||
lbool r = saturate(m_ineqs[i]);
|
||||
++m_stats.m_num_saturations;
|
||||
if (r != l_true) {
|
||||
return r;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
if (m_cancel) {
|
||||
return l_undef;
|
||||
|
@ -619,7 +528,7 @@ lbool hilbert_basis::saturate(num_vector const& ineq) {
|
|||
values v = vec(*it);
|
||||
set_eval(v, ineq);
|
||||
add_goal(*it);
|
||||
if (v.value().is_nonneg()) {
|
||||
if (v.weight().is_nonneg()) {
|
||||
has_non_negative = true;
|
||||
}
|
||||
}
|
||||
|
@ -652,7 +561,7 @@ lbool hilbert_basis::saturate(num_vector const& ineq) {
|
|||
m_basis.append(m_zero);
|
||||
for (unsigned i = 0; i < m_active.size(); ++i) {
|
||||
offset_t idx = m_active[i];
|
||||
if (vec(idx).value().is_pos()) {
|
||||
if (vec(idx).weight().is_pos()) {
|
||||
m_basis.push_back(idx);
|
||||
}
|
||||
else {
|
||||
|
@ -666,6 +575,51 @@ lbool hilbert_basis::saturate(num_vector const& ineq) {
|
|||
return l_true;
|
||||
}
|
||||
|
||||
void hilbert_basis::select_inequality(unsigned i) {
|
||||
SASSERT(i < m_ineqs.size());
|
||||
unsigned best = i;
|
||||
unsigned non_zeros = get_num_nonzeros(m_ineqs[i]);
|
||||
unsigned prod = get_ineq_product(m_ineqs[i]);
|
||||
for (unsigned j = i+1; prod != 0 && j < m_ineqs.size(); ++j) {
|
||||
unsigned non_zeros2 = get_num_nonzeros(m_ineqs[j]);
|
||||
unsigned prod2 = get_ineq_product(m_ineqs[j]);
|
||||
if (prod2 < prod || (prod2 == prod && non_zeros2 < non_zeros)) {
|
||||
prod = prod2;
|
||||
non_zeros = non_zeros2;
|
||||
best = j;
|
||||
}
|
||||
}
|
||||
if (best != i) {
|
||||
std::swap(m_ineqs[i], m_ineqs[best]);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned hilbert_basis::get_num_nonzeros(num_vector const& ineq) {
|
||||
unsigned count = 0;
|
||||
for (unsigned i = 0; i < ineq.size(); ++i) {
|
||||
if (!ineq[i].is_zero()) {
|
||||
++count;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
unsigned hilbert_basis::get_ineq_product(num_vector const& ineq) {
|
||||
unsigned num_pos = 0, num_neg = 0;
|
||||
iterator it = begin();
|
||||
for (; it != end(); ++it) {
|
||||
values v = vec(*it);
|
||||
set_eval(v, ineq);
|
||||
if (v.weight().is_pos()) {
|
||||
++num_pos;
|
||||
}
|
||||
else if (v.weight().is_neg()) {
|
||||
++num_neg;
|
||||
}
|
||||
}
|
||||
return num_pos * num_neg;
|
||||
}
|
||||
|
||||
void hilbert_basis::recycle(offset_t idx) {
|
||||
m_index->remove(idx, vec(idx));
|
||||
m_free_list.push_back(idx);
|
||||
|
@ -680,8 +634,8 @@ void hilbert_basis::resolve(offset_t i, offset_t j, offset_t r) {
|
|||
for (unsigned k = 0; k < nv; ++k) {
|
||||
u[k] = v[k] + w[k];
|
||||
}
|
||||
u.value() = v.value() + w.value();
|
||||
// std::cout << "resolve: " << v.value() << " + " << w.value() << " = " << u.value() << "\n";
|
||||
u.weight() = v.weight() + w.weight();
|
||||
// std::cout << "resolve: " << v.weight() << " + " << w.weight() << " = " << u.weight() << "\n";
|
||||
TRACE("hilbert_basis_verbose",
|
||||
display(tout, i);
|
||||
display(tout, j);
|
||||
|
@ -694,7 +648,7 @@ hilbert_basis::offset_t hilbert_basis::alloc_vector() {
|
|||
if (m_free_list.empty()) {
|
||||
unsigned num_vars = get_num_vars();
|
||||
unsigned idx = m_store.size();
|
||||
m_store.resize(idx + 1 + get_num_vars());
|
||||
m_store.resize(idx + 1 + num_vars);
|
||||
return offset_t(idx);
|
||||
}
|
||||
else {
|
||||
|
@ -710,7 +664,7 @@ void hilbert_basis::add_goal(offset_t idx) {
|
|||
return;
|
||||
}
|
||||
m_index->insert(idx, v);
|
||||
if (v.value().is_zero()) {
|
||||
if (v.weight().is_zero()) {
|
||||
m_zero.push_back(idx);
|
||||
}
|
||||
else {
|
||||
|
@ -721,12 +675,7 @@ void hilbert_basis::add_goal(offset_t idx) {
|
|||
bool hilbert_basis::is_subsumed(offset_t idx) {
|
||||
|
||||
offset_t found_idx;
|
||||
if (m_index->find(vec(idx), idx, found_idx)) {
|
||||
TRACE("hilbert_basis",
|
||||
display(tout, idx);
|
||||
tout << " <= \n";
|
||||
display(tout, found_idx);
|
||||
tout << "\n";);
|
||||
if (m_index->find(idx, vec(idx), found_idx)) {
|
||||
++m_stats.m_num_subsumptions;
|
||||
return true;
|
||||
}
|
||||
|
@ -734,13 +683,30 @@ bool hilbert_basis::is_subsumed(offset_t idx) {
|
|||
}
|
||||
|
||||
bool hilbert_basis::can_resolve(offset_t i, offset_t j) const {
|
||||
sign_t s1 = get_sign(i);
|
||||
sign_t s2 = get_sign(j);
|
||||
return s1 != s2 && abs(vec(i)[0] + vec(j)[0]) <= numeral(1);
|
||||
if (get_sign(i) == get_sign(j)) {
|
||||
return false;
|
||||
}
|
||||
values const& v1 = vec(i);
|
||||
values const& v2 = vec(j);
|
||||
// index 0 is reserved for the constant coefficient.
|
||||
// The value of it should either be 0 or 1.
|
||||
if (abs(v1[0] + v2[0]) > numeral(1)) {
|
||||
return false;
|
||||
}
|
||||
for (unsigned i = 0; i < m_ints.size(); ++i) {
|
||||
unsigned j = m_ints[i];
|
||||
if (v1[j].is_pos() && v2[j].is_neg()) {
|
||||
return false;
|
||||
}
|
||||
if (v1[j].is_neg() && v2[j].is_pos()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
hilbert_basis::sign_t hilbert_basis::get_sign(offset_t idx) const {
|
||||
numeral val = vec(idx).value();
|
||||
numeral val = vec(idx).weight();
|
||||
if (val.is_pos()) {
|
||||
return pos;
|
||||
}
|
||||
|
@ -756,7 +722,7 @@ void hilbert_basis::set_eval(values& val, num_vector const& ineq) const {
|
|||
for (unsigned i = 0; i < num_vars; ++i) {
|
||||
result += val[i]*ineq[i];
|
||||
}
|
||||
val.value() = result;
|
||||
val.weight() = result;
|
||||
}
|
||||
|
||||
void hilbert_basis::display(std::ostream& out) const {
|
||||
|
@ -796,7 +762,7 @@ void hilbert_basis::display(std::ostream& out) const {
|
|||
|
||||
void hilbert_basis::display(std::ostream& out, offset_t o) const {
|
||||
display(out, vec(o));
|
||||
out << " -> " << vec(o).value() << "\n";
|
||||
out << " -> " << vec(o).weight() << "\n";
|
||||
}
|
||||
|
||||
void hilbert_basis::display(std::ostream& out, values const& v) const {
|
||||
|
@ -842,3 +808,68 @@ void hilbert_isl_basis::add_le(num_vector const& v, numeral bound) {
|
|||
}
|
||||
m_basis.add_le(w);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Vector v is subsumed by vector w if
|
||||
|
||||
v[i] >= w[i] for each index i.
|
||||
|
||||
a*v >= a*w for the evaluation of vectors with respect to a.
|
||||
|
||||
. a*v < 0 => a*v = a*w
|
||||
. a*v > 0 => a*w > 0
|
||||
. a*v = 0 => a*w = 0
|
||||
|
||||
Justification:
|
||||
|
||||
let u := v - w, then
|
||||
|
||||
u[i] >= 0 for each index i
|
||||
|
||||
a*u = a*(v-w) >= 0
|
||||
|
||||
So v = u + w, where a*u >= 0, a*w >= 0.
|
||||
|
||||
If a*v >= a*w >= 0 then v and w are linear
|
||||
solutions of e_i, and also v-w is a solution.
|
||||
|
||||
If a*v = a*w < 0, then a*(v-w) = 0, so v can be obtained from w + (v - w).
|
||||
|
||||
*/
|
||||
|
||||
bool hilbert_basis::is_subsumed(offset_t i, offset_t j) const {
|
||||
values v = vec(i);
|
||||
values w = vec(j);
|
||||
numeral const& n = v.weight();
|
||||
numeral const& m = w.weight();
|
||||
bool r =
|
||||
i.m_offset != j.m_offset &&
|
||||
n >= m && (!m.is_nonpos() || n == m) &&
|
||||
is_geq(v, w);
|
||||
CTRACE("hilbert_basis", r,
|
||||
display(tout, i);
|
||||
tout << " <= \n";
|
||||
display(tout, j);
|
||||
tout << "\n";);
|
||||
return r;
|
||||
}
|
||||
|
||||
bool hilbert_basis::is_geq(values const& v, values const& w) const {
|
||||
unsigned nv = get_num_vars();
|
||||
for (unsigned i = 0; i < nv; ++i) {
|
||||
if (!is_abs_geq(v[i], w[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool hilbert_basis::is_abs_geq(numeral const& v, numeral const& w) const {
|
||||
if (w.is_neg()) {
|
||||
return v <= w;
|
||||
}
|
||||
else {
|
||||
return v >= w;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,10 +34,9 @@ public:
|
|||
typedef rational numeral;
|
||||
typedef vector<numeral> num_vector;
|
||||
private:
|
||||
class rational_heap;
|
||||
class value_index;
|
||||
class index;
|
||||
class passive;
|
||||
class weight_map;
|
||||
struct offset_t {
|
||||
unsigned m_offset;
|
||||
offset_t(unsigned o) : m_offset(o) {}
|
||||
|
@ -58,25 +57,26 @@ private:
|
|||
numeral* m_values;
|
||||
public:
|
||||
values(numeral* v):m_values(v) {}
|
||||
numeral& value() { return m_values[0]; } // value of a*x
|
||||
numeral& weight() { return m_values[0]; } // value of a*x
|
||||
numeral& operator[](unsigned i) { return m_values[i+1]; } // value of x_i
|
||||
numeral const& value() const { return m_values[0]; } // value of a*x
|
||||
numeral const& weight() const { return m_values[0]; } // value of a*x
|
||||
numeral const& operator[](unsigned i) const { return m_values[i+1]; } // value of x_i
|
||||
};
|
||||
|
||||
vector<num_vector> m_ineqs;
|
||||
num_vector m_store;
|
||||
svector<offset_t> m_basis;
|
||||
svector<offset_t> m_free_list;
|
||||
svector<offset_t> m_active;
|
||||
svector<offset_t> m_zero;
|
||||
volatile bool m_cancel;
|
||||
vector<num_vector> m_ineqs; // set of asserted inequalities
|
||||
num_vector m_store; // store of vectors
|
||||
svector<offset_t> m_basis; // vector of current basis
|
||||
svector<offset_t> m_free_list; // free list of unused storage
|
||||
svector<offset_t> m_active; // active set
|
||||
svector<offset_t> m_zero; // zeros
|
||||
passive* m_passive; // passive set
|
||||
volatile bool m_cancel;
|
||||
stats m_stats;
|
||||
index* m_index;
|
||||
passive* m_passive;
|
||||
index* m_index; // index of generated vectors
|
||||
unsigned_vector m_ints; // indices that can be both positive and negative
|
||||
class iterator {
|
||||
hilbert_basis const& hb;
|
||||
unsigned m_idx;
|
||||
unsigned m_idx;
|
||||
public:
|
||||
iterator(hilbert_basis const& hb, unsigned idx): hb(hb), m_idx(idx) {}
|
||||
offset_t operator*() const { return hb.m_basis[m_idx]; }
|
||||
|
@ -90,8 +90,15 @@ private:
|
|||
static bool is_invalid_offset(offset_t offs);
|
||||
lbool saturate(num_vector const& ineq);
|
||||
void init_basis();
|
||||
void select_inequality(unsigned i);
|
||||
unsigned get_num_nonzeros(num_vector const& ineq);
|
||||
unsigned get_ineq_product(num_vector const& ineq);
|
||||
|
||||
void add_unit_vector(unsigned i, numeral const& e);
|
||||
unsigned get_num_vars() const;
|
||||
void set_eval(values& val, num_vector const& ineq) const;
|
||||
bool is_geq(values const& v, values const& w) const;
|
||||
bool is_abs_geq(numeral const& v, numeral const& w) const;
|
||||
bool is_subsumed(offset_t idx);
|
||||
bool is_subsumed(offset_t i, offset_t j) const;
|
||||
void recycle(offset_t idx);
|
||||
|
@ -130,6 +137,8 @@ public:
|
|||
void add_le(num_vector const& v, numeral const& b);
|
||||
void add_eq(num_vector const& v, numeral const& b);
|
||||
|
||||
void set_is_int(unsigned var_index);
|
||||
|
||||
lbool saturate();
|
||||
|
||||
void set_cancel(bool f) { m_cancel = f; }
|
||||
|
|
|
@ -245,23 +245,28 @@ static void tst11() {
|
|||
|
||||
void tst_hilbert_basis() {
|
||||
std::cout << "hilbert basis test\n";
|
||||
#if 0
|
||||
tst1();
|
||||
tst2();
|
||||
tst3();
|
||||
tst4();
|
||||
tst5();
|
||||
tst6();
|
||||
tst7();
|
||||
tst8();
|
||||
tst9();
|
||||
tst10();
|
||||
tst11();
|
||||
gorrila_test(0, 4, 3, 20, 5);
|
||||
gorrila_test(1, 4, 3, 20, 5);
|
||||
gorrila_test(2, 4, 3, 20, 5);
|
||||
gorrila_test(0, 4, 2, 20, 5);
|
||||
gorrila_test(0, 4, 2, 20, 5);
|
||||
#endif
|
||||
gorrila_test(0, 10, 7, 20, 11);
|
||||
return;
|
||||
|
||||
if (true) {
|
||||
tst1();
|
||||
tst2();
|
||||
tst3();
|
||||
tst4();
|
||||
tst5();
|
||||
tst6();
|
||||
tst7();
|
||||
tst8();
|
||||
tst9();
|
||||
tst10();
|
||||
tst11();
|
||||
gorrila_test(0, 4, 3, 20, 5);
|
||||
gorrila_test(1, 4, 3, 20, 5);
|
||||
gorrila_test(2, 4, 3, 20, 5);
|
||||
gorrila_test(0, 4, 2, 20, 5);
|
||||
gorrila_test(0, 4, 2, 20, 5);
|
||||
}
|
||||
else {
|
||||
gorrila_test(0, 10, 7, 20, 11);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue