3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-04-07 09:55:19 +00:00
z3/src/sat/smt/bv_ackerman.cpp
Nikolaj Bjorner 549753845e
bv and gc of literals (#4692)
* bv and gc of literals

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>

* overload

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>

* diseq

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>

* diseq

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
2020-09-17 14:24:07 -07:00

173 lines
4.8 KiB
C++

/*++
Copyright (c) 2020 Microsoft Corporation
Module Name:
bv_ackerman.cpp
Abstract:
Ackerman reduction plugin for bit-vectors
Author:
Nikolaj Bjorner (nbjorner) 2020-08-28
--*/
#include "sat/smt/bv_solver.h"
#include "sat/smt/bv_ackerman.h"
namespace bv {
ackerman::ackerman(solver& s): s(s) {
new_tmp();
m_propagate_low_watermark = s.get_config().m_dack_threshold;
}
ackerman::~ackerman() {
reset();
dealloc(m_tmp_vv);
}
void ackerman::reset() {
m_table.reset();
m_queue = nullptr;
}
void ackerman::used_eq_eh(euf::theory_var v1, euf::theory_var v2) {
if (v1 == v2)
return;
if (v1 > v2)
std::swap(v1, v2);
vv* n = m_tmp_vv;
n->v1 = v1;
n->v2 = v2;
vv* other = m_table.insert_if_not_there(n);
other->m_count++;
update_glue(*other);
if (other->m_count > m_propagate_high_watermark || other->m_glue == 0)
s.s().set_should_simplify();
vv::push_to_front(m_queue, other);
if (other == n) {
new_tmp();
gc();
}
}
void ackerman::used_diseq_eh(euf::theory_var v1, euf::theory_var v2) {
if (v1 == v2)
return;
if (v1 > v2)
std::swap(v1, v2);
vv* n = m_tmp_vv;
n->v1 = v1;
n->v2 = v2;
vv* other = m_table.insert_if_not_there(n);
other->m_count++;
if (other->m_count > m_propagate_high_watermark || other->m_glue == 0)
s.s().set_should_simplify();
vv::push_to_front(m_queue, other);
if (other == n) {
new_tmp();
gc();
}
}
void ackerman::update_glue(vv& v) {
unsigned sz = s.m_bits[v.v1].size();
m_diff_levels.reserve(s.s().scope_lvl() + 1, false);
unsigned glue = 0;
unsigned max_glue = v.m_glue;
auto const& bitsa = s.m_bits[v.v1];
auto const& bitsb = s.m_bits[v.v2];
unsigned i = 0;
for (; i < sz && i < max_glue; ++i) {
sat::literal a = bitsa[i];
sat::literal b = bitsb[i];
if (a == b)
continue;
SASSERT(s.s().value(a) != l_undef);
SASSERT(s.s().value(b) == s.s().value(a));
unsigned lvl_a = s.s().lvl(a);
unsigned lvl_b = s.s().lvl(b);
if (!m_diff_levels[lvl_a]) {
m_diff_levels[lvl_a] = true;
++glue;
}
if (!m_diff_levels[lvl_b]) {
m_diff_levels[lvl_b] = true;
++glue;
}
}
for (; i-- > 0; ) {
sat::literal a = bitsa[i];
sat::literal b = bitsb[i];
if (a != b) {
m_diff_levels[s.s().lvl(a)] = false;
m_diff_levels[s.s().lvl(b)] = false;
}
}
if (glue < max_glue)
v.m_glue = 2*glue <= sz ? 0 : glue;
}
void ackerman::remove(vv* p) {
vv::remove_from(m_queue, p);
m_table.erase(p);
dealloc(p);
}
void ackerman::new_tmp() {
m_tmp_vv = alloc(vv);
m_tmp_vv->init(m_tmp_vv);
m_tmp_vv->m_count = 0;
m_tmp_vv->m_glue = UINT_MAX;
}
void ackerman::gc() {
m_num_propagations_since_last_gc++;
if (m_num_propagations_since_last_gc <= s.get_config().m_dack_gc)
return;
m_num_propagations_since_last_gc = 0;
while (m_table.size() > m_gc_threshold)
remove(m_queue->prev());
m_gc_threshold *= 110;
m_gc_threshold /= 100;
m_gc_threshold++;
}
void ackerman::propagate() {
SASSERT(s.s().at_base_lvl());
auto* n = m_queue;
vv* k = nullptr;
unsigned num_prop = static_cast<unsigned>(s.s().get_stats().m_conflict * s.get_config().m_dack_factor);
num_prop = std::min(num_prop, m_table.size());
for (unsigned i = 0; i < num_prop; ++i, n = k) {
k = n->next();
if (n->m_count < m_propagate_low_watermark && n->m_glue != 0)
continue;
add_cc(n->v1, n->v2);
remove(n);
}
}
void ackerman::add_cc(euf::theory_var v1, euf::theory_var v2) {
SASSERT(v1 < v2);
if (static_cast<unsigned>(v2) >= s.get_num_vars())
return;
if (!s.var2enode(v1) || !s.var2enode(v2))
return;
sort* s1 = s.m.get_sort(s.var2expr(v1));
sort* s2 = s.m.get_sort(s.var2expr(v2));
if (s1 != s2 || !s.bv.is_bv_sort(s1))
return;
// IF_VERBOSE(0, verbose_stream() << "assert ackerman " << v1 << " " << v2 << "\n");
s.assert_ackerman(v1, v2);
}
}