mirror of
https://github.com/Z3Prover/z3
synced 2025-12-24 13:06:50 +00:00
remove stale experimental code #8063
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
parent
175625f43c
commit
f917005ee1
23 changed files with 9 additions and 3918 deletions
|
|
@ -75,15 +75,6 @@ def_module_params('sat',
|
|||
('anf', BOOL, False, 'enable ANF based simplification in-processing'),
|
||||
('anf.delay', UINT, 2, 'delay ANF simplification by in-processing round'),
|
||||
('anf.exlin', BOOL, False, 'enable extended linear simplification'),
|
||||
('cut', BOOL, False, 'enable AIG based simplification in-processing'),
|
||||
('cut.delay', UINT, 2, 'delay cut simplification by in-processing round'),
|
||||
('cut.aig', BOOL, False, 'extract aigs (and ites) from cluases for cut simplification'),
|
||||
('cut.lut', BOOL, False, 'extract luts from clauses for cut simplification'),
|
||||
('cut.xor', BOOL, False, 'extract xors from clauses for cut simplification'),
|
||||
('cut.npn3', BOOL, False, 'extract 3 input functions from clauses for cut simplification'),
|
||||
('cut.dont_cares', BOOL, True, 'integrate dont cares with cuts'),
|
||||
('cut.redundancies', BOOL, True, 'integrate redundancy checking of cuts'),
|
||||
('cut.force', BOOL, False, 'force redoing cut-enumeration until a fixed-point'),
|
||||
('lookahead.cube.cutoff', SYMBOL, 'depth', 'cutoff type used to create lookahead cubes: depth, freevars, psat, adaptive_freevars, adaptive_psat'),
|
||||
# - depth: the maximal cutoff is fixed to the value of lookahead.cube.depth.
|
||||
# So if the value is 10, at most 1024 cubes will be generated of length 10.
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
z3_add_component(sat
|
||||
SOURCES
|
||||
dimacs.cpp
|
||||
sat_aig_cuts.cpp
|
||||
sat_aig_finder.cpp
|
||||
sat_anf_simplifier.cpp
|
||||
sat_asymm_branch.cpp
|
||||
|
|
@ -12,8 +11,6 @@ z3_add_component(sat
|
|||
sat_clause_use_list.cpp
|
||||
sat_cleaner.cpp
|
||||
sat_config.cpp
|
||||
sat_cut_simplifier.cpp
|
||||
sat_cutset.cpp
|
||||
sat_ddfw_wrapper.cpp
|
||||
sat_drat.cpp
|
||||
sat_elim_eqs.cpp
|
||||
|
|
@ -21,7 +18,6 @@ z3_add_component(sat
|
|||
sat_integrity_checker.cpp
|
||||
sat_local_search.cpp
|
||||
sat_lookahead.cpp
|
||||
sat_lut_finder.cpp
|
||||
sat_model_converter.cpp
|
||||
sat_mus.cpp
|
||||
sat_npn3_finder.cpp
|
||||
|
|
|
|||
|
|
@ -1,886 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2020 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
sat_aig_cuts.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Perform cut-set enumeration to identify equivalences.
|
||||
|
||||
Author:
|
||||
|
||||
Nikolaj Bjorner 2020-01-02
|
||||
|
||||
--*/
|
||||
|
||||
#include "util/trace.h"
|
||||
#include "sat/sat_aig_cuts.h"
|
||||
#include "sat/sat_solver.h"
|
||||
#include "sat/sat_lut_finder.h"
|
||||
|
||||
namespace sat {
|
||||
|
||||
aig_cuts::aig_cuts() {
|
||||
m_cut_set1.init(m_region, m_config.m_max_cutset_size + 1, UINT_MAX);
|
||||
m_cut_set2.init(m_region, m_config.m_max_cutset_size + 1, UINT_MAX);
|
||||
m_empty_cuts.init(m_region, m_config.m_max_cutset_size + 1, UINT_MAX);
|
||||
m_num_cut_calls = 0;
|
||||
m_num_cuts = 0;
|
||||
}
|
||||
|
||||
vector<cut_set> const& aig_cuts::operator()() {
|
||||
if (m_config.m_full) flush_roots();
|
||||
unsigned_vector node_ids = filter_valid_nodes();
|
||||
TRACE(cut_simplifier, display(tout););
|
||||
augment(node_ids);
|
||||
TRACE(cut_simplifier, display(tout););
|
||||
++m_num_cut_calls;
|
||||
return m_cuts;
|
||||
}
|
||||
|
||||
void aig_cuts::augment(unsigned_vector const& ids) {
|
||||
for (unsigned id : ids) {
|
||||
if (m_aig[id].empty()) {
|
||||
continue;
|
||||
}
|
||||
IF_VERBOSE(20, m_cuts[id].display(verbose_stream() << "augment " << id << "\nbefore\n"));
|
||||
for (node const& n : m_aig[id]) {
|
||||
augment(id, n);
|
||||
}
|
||||
|
||||
#if 0
|
||||
// augment cuts directly
|
||||
m_cut_save.reset();
|
||||
cut_set& cs = m_cuts[id];
|
||||
for (cut const& c : cs) {
|
||||
if (c.size() > 1) m_cut_save.push_back(c);
|
||||
}
|
||||
for (cut const& c : m_cut_save) {
|
||||
lut lut(*this, c);
|
||||
augment_lut(id, lut, cs);
|
||||
}
|
||||
#endif
|
||||
IF_VERBOSE(20, m_cuts[id].display(verbose_stream() << "after\n"));
|
||||
}
|
||||
}
|
||||
|
||||
void aig_cuts::augment(unsigned id, node const& n) {
|
||||
unsigned nc = n.size();
|
||||
m_insertions = 0;
|
||||
cut_set& cs = m_cuts[id];
|
||||
if (!is_touched(id, n)) {
|
||||
// no-op
|
||||
}
|
||||
else if (n.is_var()) {
|
||||
SASSERT(!n.sign());
|
||||
}
|
||||
else if (n.is_lut()) {
|
||||
lut lut(*this, n);
|
||||
augment_lut(id, lut, cs);
|
||||
}
|
||||
else if (n.is_ite()) {
|
||||
augment_ite(id, n, cs);
|
||||
}
|
||||
else if (nc == 0) {
|
||||
augment_aig0(id, n, cs);
|
||||
}
|
||||
else if (nc == 1) {
|
||||
augment_aig1(id, n, cs);
|
||||
}
|
||||
else if (nc == 2) {
|
||||
augment_aig2(id, n, cs);
|
||||
}
|
||||
else if (nc <= cut::max_cut_size()) {
|
||||
augment_aigN(id, n, cs);
|
||||
}
|
||||
if (m_insertions > 0) {
|
||||
touch(id);
|
||||
}
|
||||
}
|
||||
|
||||
bool aig_cuts::insert_cut(unsigned v, cut const& c, cut_set& cs) {
|
||||
if (!cs.insert(m_on_cut_add, m_on_cut_del, c)) {
|
||||
return true;
|
||||
}
|
||||
m_num_cuts++;
|
||||
if (++m_insertions > max_cutset_size(v)) {
|
||||
return false;
|
||||
}
|
||||
while (cs.size() >= max_cutset_size(v)) {
|
||||
// never evict the first entry, it is used for the starting point
|
||||
unsigned idx = 1 + (m_rand() % (cs.size() - 1));
|
||||
evict(cs, idx);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void aig_cuts::augment_lut(unsigned v, lut const& n, cut_set& cs) {
|
||||
IF_VERBOSE(4, n.display(verbose_stream() << "augment_lut " << v << " ") << "\n");
|
||||
literal l1 = n.child(0);
|
||||
VERIFY(&cs != &lit2cuts(l1));
|
||||
for (auto const& a : lit2cuts(l1)) {
|
||||
m_tables[0] = &a;
|
||||
m_lits[0] = l1;
|
||||
cut b(a);
|
||||
augment_lut_rec(v, n, b, 1, cs);
|
||||
}
|
||||
}
|
||||
|
||||
void aig_cuts::augment_lut_rec(unsigned v, lut const& n, cut& a, unsigned idx, cut_set& cs) {
|
||||
if (idx < n.size()) {
|
||||
literal lit = n.child(idx);
|
||||
VERIFY(&cs != &lit2cuts(lit));
|
||||
for (auto const& b : lit2cuts(lit)) {
|
||||
cut ab;
|
||||
if (!ab.merge(a, b)) continue;
|
||||
m_tables[idx] = &b;
|
||||
m_lits[idx] = lit;
|
||||
augment_lut_rec(v, n, ab, idx + 1, cs);
|
||||
}
|
||||
return;
|
||||
}
|
||||
for (unsigned i = n.size(); i-- > 0; ) {
|
||||
m_luts[i] = m_tables[i]->shift_table(a);
|
||||
}
|
||||
uint64_t r = 0;
|
||||
SASSERT(a.size() <= 6);
|
||||
SASSERT(n.size() <= 6);
|
||||
for (unsigned j = (1u << a.size()); j-- > 0; ) {
|
||||
unsigned w = 0;
|
||||
// when computing the output at position j,
|
||||
// the i'th bit to index into n.lut() is
|
||||
// based on the j'th output bit in lut[i]
|
||||
// m_lits[i].sign() tracks if output bit is negated
|
||||
for (unsigned i = n.size(); i-- > 0; ) {
|
||||
w |= (((m_luts[i] >> j) ^ (uint64_t)m_lits[i].sign()) & 1u) << i;
|
||||
}
|
||||
r |= ((n.table() >> w) & 1u) << j;
|
||||
}
|
||||
a.set_table(r);
|
||||
IF_VERBOSE(8,
|
||||
verbose_stream() << "lut: " << v << " - " << a << "\n";
|
||||
for (unsigned i = 0; i < n.size(); ++i) {
|
||||
verbose_stream() << m_lits[i] << ": " << *m_tables[i] << "\n";
|
||||
});
|
||||
insert_cut(v, a, cs);
|
||||
}
|
||||
|
||||
void aig_cuts::augment_ite(unsigned v, node const& n, cut_set& cs) {
|
||||
IF_VERBOSE(4, display(verbose_stream() << "augment_ite " << v << " ", n) << "\n");
|
||||
literal l1 = child(n, 0);
|
||||
literal l2 = child(n, 1);
|
||||
literal l3 = child(n, 2);
|
||||
VERIFY(&cs != &lit2cuts(l1));
|
||||
VERIFY(&cs != &lit2cuts(l2));
|
||||
VERIFY(&cs != &lit2cuts(l3));
|
||||
for (auto const& a : lit2cuts(l1)) {
|
||||
for (auto const& b : lit2cuts(l2)) {
|
||||
cut ab;
|
||||
if (!ab.merge(a, b)) continue;
|
||||
for (auto const& c : lit2cuts(l3)) {
|
||||
cut abc;
|
||||
if (!abc.merge(ab, c)) continue;
|
||||
uint64_t t1 = a.shift_table(abc);
|
||||
uint64_t t2 = b.shift_table(abc);
|
||||
uint64_t t3 = c.shift_table(abc);
|
||||
if (l1.sign()) t1 = ~t1;
|
||||
if (l2.sign()) t2 = ~t2;
|
||||
if (l3.sign()) t3 = ~t3;
|
||||
abc.set_table((t1 & t2) | ((~t1) & t3));
|
||||
if (n.sign()) abc.negate();
|
||||
if (!insert_cut(v, abc, cs)) return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void aig_cuts::augment_aig0(unsigned v, node const& n, cut_set& cs) {
|
||||
IF_VERBOSE(4, display(verbose_stream() << "augment_unit " << v << " ", n) << "\n");
|
||||
SASSERT(n.is_and() && n.size() == 0);
|
||||
reset(cs);
|
||||
cut c;
|
||||
c.set_table(n.sign() ? 0x0 : 0x1);
|
||||
push_back(cs, c);
|
||||
}
|
||||
|
||||
void aig_cuts::augment_aig1(unsigned v, node const& n, cut_set& cs) {
|
||||
IF_VERBOSE(4, display(verbose_stream() << "augment_aig1 " << v << " ", n) << "\n");
|
||||
SASSERT(n.is_and());
|
||||
literal lit = child(n, 0);
|
||||
VERIFY(&cs != &lit2cuts(lit));
|
||||
for (auto const& a : lit2cuts(lit)) {
|
||||
cut c(a);
|
||||
if (n.sign()) c.negate();
|
||||
if (!insert_cut(v, c, cs)) return;
|
||||
}
|
||||
}
|
||||
|
||||
void aig_cuts::augment_aig2(unsigned v, node const& n, cut_set& cs) {
|
||||
IF_VERBOSE(4, display(verbose_stream() << "augment_aig2 " << v << " ", n) << "\n");
|
||||
SASSERT(n.is_and() || n.is_xor());
|
||||
literal l1 = child(n, 0);
|
||||
literal l2 = child(n, 1);
|
||||
VERIFY(&cs != &lit2cuts(l1));
|
||||
VERIFY(&cs != &lit2cuts(l2));
|
||||
for (auto const& a : lit2cuts(l1)) {
|
||||
for (auto const& b : lit2cuts(l2)) {
|
||||
cut c;
|
||||
if (!c.merge(a, b)) continue;
|
||||
uint64_t t1 = a.shift_table(c);
|
||||
uint64_t t2 = b.shift_table(c);
|
||||
if (l1.sign()) t1 = ~t1;
|
||||
if (l2.sign()) t2 = ~t2;
|
||||
uint64_t t3 = n.is_and() ? (t1 & t2) : (t1 ^ t2);
|
||||
c.set_table(t3);
|
||||
if (n.sign()) c.negate();
|
||||
// validate_aig2(a, b, v, n, c);
|
||||
if (!insert_cut(v, c, cs)) return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void aig_cuts::augment_aigN(unsigned v, node const& n, cut_set& cs) {
|
||||
IF_VERBOSE(4, display(verbose_stream() << "augment_aigN " << v << " ", n) << "\n");
|
||||
m_cut_set1.reset(m_on_cut_del);
|
||||
SASSERT(n.is_and() || n.is_xor());
|
||||
literal lit = child(n, 0);
|
||||
for (auto const& a : lit2cuts(lit)) {
|
||||
cut b(a);
|
||||
if (lit.sign()) {
|
||||
b.negate();
|
||||
}
|
||||
m_cut_set1.push_back(m_on_cut_add, b);
|
||||
}
|
||||
for (unsigned i = 1; i < n.size(); ++i) {
|
||||
m_cut_set2.reset(m_on_cut_del);
|
||||
lit = child(n, i);
|
||||
m_insertions = 0;
|
||||
for (auto const& a : m_cut_set1) {
|
||||
for (auto const& b : lit2cuts(lit)) {
|
||||
cut c;
|
||||
if (!c.merge(a, b)) continue;
|
||||
uint64_t t1 = a.shift_table(c);
|
||||
uint64_t t2 = b.shift_table(c);
|
||||
if (lit.sign()) t2 = ~t2;
|
||||
uint64_t t3 = n.is_and() ? (t1 & t2) : (t1 ^ t2);
|
||||
c.set_table(t3);
|
||||
if (i + 1 == n.size() && n.sign()) c.negate();
|
||||
if (!insert_cut(UINT_MAX, c, m_cut_set2)) goto next_child;
|
||||
}
|
||||
}
|
||||
next_child:
|
||||
m_cut_set1.swap(m_cut_set2);
|
||||
}
|
||||
m_insertions = 0;
|
||||
for (auto & cut : m_cut_set1) {
|
||||
// validate_aigN(v, n, cut);
|
||||
if (!insert_cut(v, cut, cs)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool aig_cuts::is_touched(bool_var v, node const& n) {
|
||||
for (unsigned i = 0; i < n.size(); ++i) {
|
||||
literal lit = m_literals[n.offset() + i];
|
||||
if (is_touched(lit)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return is_touched(v);
|
||||
}
|
||||
|
||||
void aig_cuts::reserve(unsigned v) {
|
||||
m_aig.reserve(v + 1);
|
||||
m_cuts.reserve(v + 1);
|
||||
m_max_cutset_size.reserve(v + 1, m_config.m_max_cutset_size);
|
||||
m_last_touched.reserve(v + 1, 0);
|
||||
}
|
||||
|
||||
void aig_cuts::add_var(unsigned v) {
|
||||
reserve(v);
|
||||
if (m_aig[v].empty()) {
|
||||
m_aig[v].push_back(node(v));
|
||||
init_cut_set(v);
|
||||
touch(v);
|
||||
}
|
||||
}
|
||||
|
||||
void aig_cuts::add_node(bool_var v, node const& n) {
|
||||
for (unsigned i = 0; i < n.size(); ++i) {
|
||||
reserve(m_literals[i].var());
|
||||
if (m_aig[m_literals[i].var()].empty()) {
|
||||
add_var(m_literals[i].var());
|
||||
}
|
||||
}
|
||||
if (m_aig[v].empty() || n.is_const()) {
|
||||
m_aig[v].reset();
|
||||
m_aig[v].push_back(n);
|
||||
on_node_add(v, n);
|
||||
init_cut_set(v);
|
||||
if (n.is_const()) {
|
||||
augment_aig0(v, n, m_cuts[v]);
|
||||
}
|
||||
touch(v);
|
||||
IF_VERBOSE(12, display(verbose_stream() << "add " << v << " == ", n) << "\n");
|
||||
}
|
||||
else if (m_aig[v][0].is_const() || !insert_aux(v, n)) {
|
||||
m_literals.shrink(m_literals.size() - n.size());
|
||||
TRACE(cut_simplifier, tout << "duplicate\n";);
|
||||
}
|
||||
SASSERT(!m_aig[v].empty());
|
||||
}
|
||||
|
||||
void aig_cuts::add_node(bool_var v, uint64_t lut, unsigned sz, bool_var const* args) {
|
||||
TRACE(cut_simplifier, tout << v << " == " << cut::table2string(sz, lut) << " " << bool_var_vector(sz, args) << "\n";);
|
||||
reserve(v);
|
||||
unsigned offset = m_literals.size();
|
||||
node n(lut, sz, offset);
|
||||
for (unsigned i = 0; i < sz; ++i) {
|
||||
reserve(args[i]);
|
||||
m_literals.push_back(literal(args[i], false));
|
||||
}
|
||||
add_node(v, n);
|
||||
}
|
||||
|
||||
void aig_cuts::add_node(literal head, bool_op op, unsigned sz, literal const* args) {
|
||||
TRACE(cut_simplifier, tout << head << " == " << op << " " << literal_vector(sz, args) << "\n";);
|
||||
unsigned v = head.var();
|
||||
reserve(v);
|
||||
unsigned offset = m_literals.size();
|
||||
node n(head.sign(), op, sz, offset);
|
||||
m_literals.append(sz, args);
|
||||
for (unsigned i = 0; i < sz; ++i) reserve(args[i].var());
|
||||
if (op == and_op || op == xor_op) {
|
||||
std::sort(m_literals.data() + offset, m_literals.data() + offset + sz);
|
||||
}
|
||||
add_node(v, n);
|
||||
}
|
||||
|
||||
void aig_cuts::add_cut(bool_var v, uint64_t lut, bool_var_vector const& args) {
|
||||
// args can be assumed to be sorted
|
||||
DEBUG_CODE(for (unsigned i = 0; i + 1 < args.size(); ++i) VERIFY(args[i] < args[i+1]););
|
||||
add_var(v);
|
||||
for (bool_var w : args) add_var(w);
|
||||
cut c;
|
||||
for (bool_var w : args) VERIFY(c.add(w));
|
||||
c.set_table(lut);
|
||||
insert_cut(v, c, m_cuts[v]);
|
||||
}
|
||||
|
||||
|
||||
void aig_cuts::set_root(bool_var v, literal r) {
|
||||
IF_VERBOSE(10, verbose_stream() << "set-root " << v << " -> " << r << "\n");
|
||||
m_roots.push_back(std::make_pair(v, r));
|
||||
}
|
||||
|
||||
void aig_cuts::flush_roots() {
|
||||
if (m_roots.empty()) return;
|
||||
to_root to_root;
|
||||
for (unsigned i = m_roots.size(); i-- > 0; ) {
|
||||
bool_var v = m_roots[i].first;
|
||||
literal r = m_roots[i].second;
|
||||
reserve(v);
|
||||
reserve(r.var());
|
||||
literal rr = to_root[r.var()];
|
||||
to_root[v] = r.sign() ? ~rr : rr;
|
||||
}
|
||||
for (unsigned i = 0; i < m_aig.size(); ++i) {
|
||||
// invalidate nodes that have been rooted
|
||||
if (to_root[i] != literal(i, false)) {
|
||||
m_aig[i].reset();
|
||||
reset(m_cuts[i]);
|
||||
}
|
||||
else {
|
||||
unsigned j = 0;
|
||||
for (node & n : m_aig[i]) {
|
||||
if (flush_roots(i, to_root, n)) {
|
||||
m_aig[i][j++] = n;
|
||||
}
|
||||
}
|
||||
m_aig[i].shrink(j);
|
||||
}
|
||||
}
|
||||
for (cut_set& cs : m_cuts) {
|
||||
flush_roots(to_root, cs);
|
||||
}
|
||||
m_roots.reset();
|
||||
TRACE(cut_simplifier, display(tout););
|
||||
}
|
||||
|
||||
bool aig_cuts::flush_roots(bool_var var, to_root const& to_root, node& n) {
|
||||
bool changed = false;
|
||||
for (unsigned i = 0; i < n.size(); ++i) {
|
||||
literal& lit = m_literals[n.offset() + i];
|
||||
literal r = to_root[lit.var()];
|
||||
if (r != lit) {
|
||||
changed = true;
|
||||
lit = lit.sign() ? ~r : r;
|
||||
}
|
||||
if (lit.var() == var) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (changed && (n.is_and() || n.is_xor())) {
|
||||
std::sort(m_literals.data() + n.offset(), m_literals.data() + n.offset() + n.size());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void aig_cuts::flush_roots(to_root const& to_root, cut_set& cs) {
|
||||
for (unsigned j = 0; j < cs.size(); ++j) {
|
||||
for (unsigned v : cs[j]) {
|
||||
if (to_root[v] != literal(v, false)) {
|
||||
evict(cs, j--);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lbool aig_cuts::get_value(bool_var v) const {
|
||||
return (m_aig[v].size() == 1 && m_aig[v][0].is_const()) ?
|
||||
(m_aig[v][0].sign() ? l_false : l_true) :
|
||||
l_undef;
|
||||
}
|
||||
|
||||
void aig_cuts::init_cut_set(unsigned id) {
|
||||
SASSERT(m_aig[id].size() == 1);
|
||||
SASSERT(m_aig[id][0].is_valid());
|
||||
auto& cut_set = m_cuts[id];
|
||||
reset(cut_set);
|
||||
cut_set.init(m_region, m_config.m_max_cutset_size + 1, id);
|
||||
push_back(cut_set, cut(id));
|
||||
}
|
||||
|
||||
bool aig_cuts::eq(node const& a, node const& b) {
|
||||
if (a.is_valid() != b.is_valid()) return false;
|
||||
if (!a.is_valid()) return true;
|
||||
if (a.op() != b.op() || a.sign() != b.sign() || a.size() != b.size())
|
||||
return false;
|
||||
for (unsigned i = a.size(); i-- > 0; ) {
|
||||
if (m_literals[a.offset() + i] != m_literals[b.offset() + i])
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool aig_cuts::similar(node const& a, node const& b) {
|
||||
bool sim = true;
|
||||
sim = a.is_lut() && !b.is_lut() && a.size() == b.size();
|
||||
for (unsigned i = a.size(); sim && i-- > 0; ) {
|
||||
sim = m_literals[a.offset() + i].var() == m_literals[b.offset() + i].var();
|
||||
}
|
||||
return sim;
|
||||
}
|
||||
|
||||
bool aig_cuts::insert_aux(unsigned v, node const& n) {
|
||||
if (!m_config.m_full) return false;
|
||||
unsigned num_gt = 0, num_eq = 0;
|
||||
for (node const& n2 : m_aig[v]) {
|
||||
if (eq(n, n2) || similar(n, n2)) return false;
|
||||
else if (n.size() < n2.size()) num_gt++;
|
||||
else if (n.size() == n2.size()) num_eq++;
|
||||
}
|
||||
if (m_aig[v].size() < m_config.m_max_aux) {
|
||||
on_node_add(v, n);
|
||||
m_aig[v].push_back(n);
|
||||
touch(v);
|
||||
return true;
|
||||
}
|
||||
if (num_gt > 0) {
|
||||
unsigned idx = rand() % num_gt;
|
||||
for (node const& n2 : m_aig[v]) {
|
||||
if (n.size() < n2.size()) {
|
||||
if (idx == 0) {
|
||||
on_node_del(v, m_aig[v][idx]);
|
||||
on_node_add(v, n);
|
||||
m_aig[v][idx] = n;
|
||||
touch(v);
|
||||
return true;
|
||||
}
|
||||
--idx;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (num_eq > 0) {
|
||||
unsigned idx = rand() % num_eq;
|
||||
for (node const& n2 : m_aig[v]) {
|
||||
if (n.size() == n2.size()) {
|
||||
if (idx == 0) {
|
||||
on_node_del(v, m_aig[v][idx]);
|
||||
on_node_add(v, n);
|
||||
m_aig[v][idx] = n;
|
||||
touch(v);
|
||||
return true;
|
||||
}
|
||||
--idx;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned_vector aig_cuts::filter_valid_nodes() const {
|
||||
unsigned id = 0;
|
||||
unsigned_vector result;
|
||||
for (auto& v : m_aig) {
|
||||
if (!v.empty()) result.push_back(id);
|
||||
++id;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
cut_val aig_cuts::eval(node const& n, cut_eval const& env) const {
|
||||
uint64_t result = 0;
|
||||
switch (n.op()) {
|
||||
case var_op:
|
||||
UNREACHABLE();
|
||||
break;
|
||||
case and_op:
|
||||
result = ~0ull;
|
||||
for (unsigned i = 0; i < n.size(); ++i) {
|
||||
literal u = m_literals[n.offset() + i];
|
||||
uint64_t uv = u.sign() ? env[u.var()].m_f : env[u.var()].m_t;
|
||||
result &= uv;
|
||||
}
|
||||
break;
|
||||
case xor_op:
|
||||
result = 0ull;
|
||||
for (unsigned i = 0; i < n.size(); ++i) {
|
||||
literal u = m_literals[n.offset() + i];
|
||||
uint64_t uv = u.sign() ? env[u.var()].m_f : env[u.var()].m_t;
|
||||
result ^= uv;
|
||||
}
|
||||
break;
|
||||
case ite_op: {
|
||||
literal u = m_literals[n.offset() + 0];
|
||||
literal v = m_literals[n.offset() + 1];
|
||||
literal w = m_literals[n.offset() + 2];
|
||||
uint64_t uv = u.sign() ? env[u.var()].m_f : env[u.var()].m_t;
|
||||
uint64_t vv = v.sign() ? env[v.var()].m_f : env[v.var()].m_t;
|
||||
uint64_t wv = w.sign() ? env[w.var()].m_f : env[w.var()].m_t;
|
||||
result = (uv & vv) | ((~uv) & wv);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
if (n.sign()) result = ~result;
|
||||
return cut_val(result, ~result);
|
||||
}
|
||||
|
||||
cut_eval aig_cuts::simulate(unsigned num_rounds) {
|
||||
cut_eval result;
|
||||
for (unsigned i = 0; i < m_cuts.size(); ++i) {
|
||||
uint64_t r =
|
||||
(uint64_t)m_rand() + ((uint64_t)m_rand() << 16ull) +
|
||||
((uint64_t)m_rand() << 32ull) + ((uint64_t)m_rand() << 48ull);
|
||||
result.push_back(cut_val(r, ~r));
|
||||
}
|
||||
for (unsigned i = 0; i < num_rounds; ++i) {
|
||||
for (unsigned j = 0; j < m_cuts.size(); ++j) {
|
||||
cut_set const& cs = m_cuts[j];
|
||||
if (cs.size() <= 1) {
|
||||
if (!m_aig[j].empty() && !m_aig[j][0].is_var()) {
|
||||
result[j] = eval(m_aig[j][0], result);
|
||||
}
|
||||
}
|
||||
else if (cs.size() > 1) {
|
||||
cut const& c = cs[1 + (m_rand() % (cs.size() - 1))];
|
||||
result[j] = c.eval(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
void aig_cuts::on_node_add(unsigned v, node const& n) {
|
||||
if (m_on_clause_add) {
|
||||
node2def(m_on_clause_add, n, literal(v, false));
|
||||
}
|
||||
}
|
||||
|
||||
void aig_cuts::on_node_del(unsigned v, node const& n) {
|
||||
if (m_on_clause_del) {
|
||||
node2def(m_on_clause_del, n, literal(v, false));
|
||||
}
|
||||
}
|
||||
|
||||
void aig_cuts::set_on_clause_add(on_clause_t& on_clause_add) {
|
||||
m_on_clause_add = on_clause_add;
|
||||
std::function<void(unsigned v, cut const& c)> _on_cut_add =
|
||||
[this](unsigned v, cut const& c) { cut2def(m_on_clause_add, c, literal(v, false)); };
|
||||
m_on_cut_add = _on_cut_add;
|
||||
}
|
||||
|
||||
void aig_cuts::set_on_clause_del(on_clause_t& on_clause_del) {
|
||||
m_on_clause_del = on_clause_del;
|
||||
std::function<void(unsigned v, cut const& c)> _on_cut_del =
|
||||
[this](unsigned v, cut const& c) { cut2def(m_on_clause_del, c, literal(v, false)); };
|
||||
m_on_cut_del = _on_cut_del;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode the cut (variables and truth-table) in a set of clauses.
|
||||
* r is the result.
|
||||
*/
|
||||
|
||||
void aig_cuts::cut2def(on_clause_t& on_clause, cut const& c, literal r) {
|
||||
IF_VERBOSE(10, verbose_stream() << "cut2def: " << r << " == " << c << "\n");
|
||||
VERIFY(r != null_literal);
|
||||
unsigned sz = c.size();
|
||||
unsigned num_assigns = 1 << sz;
|
||||
for (unsigned i = 0; i < num_assigns; ++i) {
|
||||
m_clause.reset();
|
||||
for (unsigned j = 0; j < sz; ++j) {
|
||||
literal lit(c[j], 0 != (i & (1ull << j)));
|
||||
m_clause.push_back(lit);
|
||||
}
|
||||
literal rr = r;
|
||||
if (0 == (c.table() & (1ull << i))) rr.neg();
|
||||
m_clause.push_back(rr);
|
||||
on_clause(m_clause);
|
||||
}
|
||||
}
|
||||
|
||||
void aig_cuts::node2def(on_clause_t& on_clause, node const& n, literal r) {
|
||||
IF_VERBOSE(10, display(verbose_stream() << "node2def " << r << " == ", n) << "\n");
|
||||
SASSERT(on_clause);
|
||||
literal c, t, e;
|
||||
if (n.sign()) r.neg();
|
||||
m_clause.reset();
|
||||
unsigned num_comb = 0;
|
||||
switch (n.op()) {
|
||||
case var_op:
|
||||
return;
|
||||
case and_op:
|
||||
for (unsigned i = 0; i < n.size(); ++i) {
|
||||
m_clause.push_back(~r);
|
||||
m_clause.push_back(m_literals[n.offset() + i]);
|
||||
on_clause(m_clause);
|
||||
m_clause.reset();
|
||||
}
|
||||
for (unsigned i = 0; i < n.size(); ++i) {
|
||||
m_clause.push_back(~m_literals[n.offset()+i]);
|
||||
}
|
||||
m_clause.push_back(r);
|
||||
on_clause(m_clause);
|
||||
return;
|
||||
case ite_op:
|
||||
// r & c => t, r & ~c => e
|
||||
// ~r & c => ~t, ~r & ~c => ~e
|
||||
SASSERT(n.size() == 3);
|
||||
c = m_literals[n.offset()+0];
|
||||
t = m_literals[n.offset()+1];
|
||||
e = m_literals[n.offset()+2];
|
||||
m_clause.push_back(~r, ~c, t);
|
||||
on_clause(m_clause);
|
||||
m_clause.reset();
|
||||
m_clause.push_back(~r, c, e);
|
||||
on_clause(m_clause);
|
||||
m_clause.reset();
|
||||
m_clause.push_back(r, ~c, ~t);
|
||||
on_clause(m_clause);
|
||||
m_clause.reset();
|
||||
m_clause.push_back(r, c, ~e);
|
||||
on_clause(m_clause);
|
||||
return;
|
||||
case xor_op:
|
||||
// r = a ^ b ^ c
|
||||
// <=>
|
||||
// ~r ^ a ^ b ^ c = 1
|
||||
if (n.size() > 10) {
|
||||
throw default_exception("cannot handle large xors");
|
||||
}
|
||||
num_comb = (1 << n.size());
|
||||
for (unsigned i = 0; i < num_comb; ++i) {
|
||||
bool parity = n.size() % 2 == 1;
|
||||
m_clause.reset();
|
||||
for (unsigned j = 0; j < n.size(); ++j) {
|
||||
literal lit = m_literals[n.offset() + j];
|
||||
if (0 == (i & (1 << j))) {
|
||||
lit.neg();
|
||||
}
|
||||
else {
|
||||
parity ^= true;
|
||||
}
|
||||
m_clause.push_back(lit);
|
||||
}
|
||||
m_clause.push_back(parity ? r : ~r);
|
||||
TRACE(cut_simplifier, tout << "validate: " << m_clause << "\n";);
|
||||
on_clause(m_clause);
|
||||
}
|
||||
return;
|
||||
case lut_op:
|
||||
// r = LUT(v0, v1, v2)
|
||||
num_comb = (1 << n.size());
|
||||
for (unsigned i = 0; i < num_comb; ++i) {
|
||||
m_clause.reset();
|
||||
for (unsigned j = 0; j < n.size(); ++j) {
|
||||
literal lit = m_literals[n.offset() + j];
|
||||
if (0 != (i & (1 << j))) lit.neg();
|
||||
m_clause.push_back(lit);
|
||||
}
|
||||
m_clause.push_back(0 == (n.lut() & (1ull << i)) ? ~r : r);
|
||||
TRACE(cut_simplifier, tout << n.lut() << " " << m_clause << "\n";);
|
||||
on_clause(m_clause);
|
||||
}
|
||||
return;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* compile the truth table from c into clauses that define ~v.
|
||||
* compile definitions for nodes until all inputs have been covered.
|
||||
* Assume only the first definition for a node is used for all cuts.
|
||||
*/
|
||||
void aig_cuts::cut2clauses(on_clause_t& on_clause, unsigned v, cut const& c) {
|
||||
bool_vector visited(m_aig.size(), false);
|
||||
for (unsigned u : c) visited[u] = true;
|
||||
unsigned_vector todo;
|
||||
todo.push_back(v);
|
||||
|
||||
while (!todo.empty()) {
|
||||
unsigned u = todo.back();
|
||||
todo.pop_back();
|
||||
if (visited[u]) {
|
||||
continue;
|
||||
}
|
||||
visited[u] = true;
|
||||
node const& n = m_aig[u][0];
|
||||
node2def(on_clause, n, literal(u, false));
|
||||
for (unsigned i = 0; i < n.size(); ++i) {
|
||||
todo.push_back(m_literals[n.offset()+i].var());
|
||||
}
|
||||
}
|
||||
cut2def(on_clause, c, literal(v, true));
|
||||
}
|
||||
|
||||
/**
|
||||
* simplify a set of cuts by removing don't cares.
|
||||
*/
|
||||
void aig_cuts::simplify() {
|
||||
uint64_t masks[7];
|
||||
for (unsigned i = 0; i <= 6; ++i) {
|
||||
masks[i] = cut::effect_mask(i);
|
||||
}
|
||||
unsigned dont_cares = 0;
|
||||
for (cut_set & cs : m_cuts) {
|
||||
for (cut const& c : cs) {
|
||||
uint64_t t = c.table();
|
||||
for (unsigned i = 0; i < std::min(6u, c.size()); ++i) {
|
||||
uint64_t diff = masks[i] & (t ^ (t >> (1ull << i)));
|
||||
if (diff == 0ull) {
|
||||
cut d(c);
|
||||
d.remove_elem(i);
|
||||
cs.insert(m_on_cut_add, m_on_cut_del, d);
|
||||
cs.evict(m_on_cut_del, c);
|
||||
++dont_cares;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
IF_VERBOSE(2, verbose_stream() << "#don't cares " << dont_cares << "\n");
|
||||
}
|
||||
|
||||
struct aig_cuts::validator {
|
||||
aig_cuts& t;
|
||||
params_ref p;
|
||||
reslimit lim;
|
||||
solver s;
|
||||
unsigned_vector vars;
|
||||
bool_vector is_var;
|
||||
|
||||
validator(aig_cuts& t):t(t),s(p, lim) {
|
||||
p.set_bool("cut_simplifier", false);
|
||||
s.updt_params(p);
|
||||
}
|
||||
|
||||
void on_clause(literal_vector const& clause) {
|
||||
IF_VERBOSE(20, verbose_stream() << clause << "\n");
|
||||
for (literal lit : clause) {
|
||||
while (lit.var() >= s.num_vars()) s.mk_var();
|
||||
is_var.reserve(lit.var() + 1, false);
|
||||
if (!is_var[lit.var()]) { vars.push_back(lit.var()); is_var[lit.var()] = true; }
|
||||
}
|
||||
s.mk_clause(clause);
|
||||
}
|
||||
|
||||
void check() {
|
||||
lbool r = s.check();
|
||||
IF_VERBOSE(10, verbose_stream() << "check: " << r << "\n");
|
||||
if (r == l_true) {
|
||||
IF_VERBOSE(0,
|
||||
std::sort(vars.begin(), vars.end());
|
||||
s.display(verbose_stream());
|
||||
for (auto v : vars) verbose_stream() << v << " := " << s.get_model()[v] << "\n";
|
||||
);
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void aig_cuts::validate_aig2(cut const& a, cut const& b, unsigned v, node const& n, cut const& c) {
|
||||
validator val(*this);
|
||||
on_clause_t on_clause = [&](literal_vector const& clause) { val.on_clause(clause); };
|
||||
cut2def(on_clause, a, literal(child(n, 0).var(), false));
|
||||
cut2def(on_clause, b, literal(child(n, 1).var(), false));
|
||||
cut2def(on_clause, c, literal(v, false));
|
||||
node2def(on_clause, n, literal(v, true));
|
||||
val.check();
|
||||
}
|
||||
|
||||
void aig_cuts::validate_aigN(unsigned v, node const& n, cut const& c) {
|
||||
IF_VERBOSE(10, verbose_stream() << "validate_aigN " << v << " == " << c << "\n");
|
||||
validator val(*this);
|
||||
on_clause_t on_clause = [&](literal_vector const& clause) { val.on_clause(clause); };
|
||||
for (unsigned i = 0; i < n.size(); ++i) {
|
||||
unsigned w = m_literals[n.offset() + i].var();
|
||||
for (cut const& d : m_cuts[w]) {
|
||||
cut2def(on_clause, d, literal(w, false));
|
||||
}
|
||||
}
|
||||
cut2def(on_clause, c, literal(v, false));
|
||||
node2def(on_clause, n, literal(v, true));
|
||||
val.check();
|
||||
}
|
||||
|
||||
std::ostream& aig_cuts::display(std::ostream& out) const {
|
||||
auto ids = filter_valid_nodes();
|
||||
for (auto id : ids) {
|
||||
out << id << " == ";
|
||||
bool first = true;
|
||||
for (auto const& n : m_aig[id]) {
|
||||
if (first) first = false; else out << " ";
|
||||
display(out, n) << "\n";
|
||||
}
|
||||
m_cuts[id].display(out);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
std::ostream& aig_cuts::display(std::ostream& out, node const& n) const {
|
||||
out << (n.sign() ? "! " : " ");
|
||||
switch (n.op()) {
|
||||
case var_op: out << "var "; break;
|
||||
case and_op: out << "& "; break;
|
||||
case xor_op: out << "^ "; break;
|
||||
case ite_op: out << "? "; break;
|
||||
default: break;
|
||||
}
|
||||
for (unsigned i = 0; i < n.size(); ++i) {
|
||||
out << m_literals[n.offset() + i] << " ";
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -1,238 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2020 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
sat_aig_cuts.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Extract AIG definitions from clauses.
|
||||
Perform cut-set enumeration to identify equivalences.
|
||||
|
||||
AIG extraction is incremental.
|
||||
It can be called repeatedly.
|
||||
Initially, a main aig node is inserted
|
||||
(from initial clauses or the input
|
||||
clausification in goal2sat).
|
||||
Then, auxiliary AIG nodes can be inserted
|
||||
by walking the current set of main and learned
|
||||
clauses. AIG nodes with fewer arguments are preferred.
|
||||
|
||||
|
||||
|
||||
Author:
|
||||
|
||||
Nikolaj Bjorner 2020-01-02
|
||||
|
||||
--*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "sat/sat_cutset.h"
|
||||
#include "sat/sat_types.h"
|
||||
|
||||
namespace sat {
|
||||
|
||||
enum bool_op {
|
||||
var_op,
|
||||
and_op,
|
||||
ite_op,
|
||||
xor_op,
|
||||
lut_op,
|
||||
no_op
|
||||
};
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& out, bool_op op) {
|
||||
switch (op) {
|
||||
case var_op: return out << "v";
|
||||
case and_op: return out << "&";
|
||||
case ite_op: return out << "?";
|
||||
case xor_op: return out << "^";
|
||||
case lut_op: return out << "#";
|
||||
default: return out << "";
|
||||
}
|
||||
}
|
||||
|
||||
class aig_cuts {
|
||||
public:
|
||||
typedef std::function<void(literal_vector const&)> on_clause_t;
|
||||
|
||||
struct config {
|
||||
unsigned m_max_cutset_size;
|
||||
unsigned m_max_aux;
|
||||
unsigned m_max_insertions;
|
||||
bool m_full;
|
||||
config(): m_max_cutset_size(20), m_max_aux(5), m_max_insertions(20), m_full(true) {}
|
||||
};
|
||||
private:
|
||||
|
||||
// encodes one of var, and, !and, xor, !xor, ite, !ite.
|
||||
class node {
|
||||
bool m_sign{ false };
|
||||
bool_op m_op{ no_op };
|
||||
uint64_t m_lut{ 0 };
|
||||
unsigned m_size{ 0 };
|
||||
unsigned m_offset{ 0 };
|
||||
public:
|
||||
node():
|
||||
m_sign(false), m_op(no_op), m_size(UINT_MAX), m_offset(UINT_MAX) {}
|
||||
explicit node(unsigned v) :
|
||||
m_sign(false), m_op(var_op), m_size(0), m_offset(v) {}
|
||||
explicit node(bool sign, bool_op op, unsigned nc, unsigned o) :
|
||||
m_sign(sign), m_op(op), m_size(nc), m_offset(o) {}
|
||||
explicit node(uint64_t lut, unsigned nc, unsigned o):
|
||||
m_sign(false), m_op(lut_op), m_lut(lut), m_size(nc), m_offset(o) {}
|
||||
bool is_valid() const { return m_offset != UINT_MAX; }
|
||||
bool_op op() const { return m_op; }
|
||||
bool is_var() const { return m_op == var_op; }
|
||||
bool is_and() const { return m_op == and_op; }
|
||||
bool is_xor() const { return m_op == xor_op; }
|
||||
bool is_ite() const { return m_op == ite_op; }
|
||||
bool is_lut() const { return m_op == lut_op; }
|
||||
bool is_const() const { return is_and() && size() == 0; }
|
||||
unsigned var() const { SASSERT(is_var()); return m_offset; }
|
||||
bool sign() const { return m_sign; }
|
||||
unsigned size() const { return m_size; }
|
||||
unsigned offset() const { return m_offset; }
|
||||
uint64_t lut() const { return m_lut; }
|
||||
};
|
||||
random_gen m_rand;
|
||||
config m_config;
|
||||
vector<svector<node>> m_aig;
|
||||
literal_vector m_literals;
|
||||
region m_region;
|
||||
cut_set m_cut_set1, m_cut_set2, m_empty_cuts;
|
||||
vector<cut_set> m_cuts;
|
||||
unsigned_vector m_max_cutset_size;
|
||||
unsigned_vector m_last_touched;
|
||||
unsigned m_num_cut_calls;
|
||||
unsigned m_num_cuts;
|
||||
svector<std::pair<bool_var, literal>> m_roots;
|
||||
unsigned m_insertions;
|
||||
on_clause_t m_on_clause_add, m_on_clause_del;
|
||||
cut_set::on_update_t m_on_cut_add, m_on_cut_del;
|
||||
literal_vector m_clause;
|
||||
cut const* m_tables[6];
|
||||
uint64_t m_luts[6];
|
||||
literal m_lits[6];
|
||||
|
||||
class to_root {
|
||||
literal_vector m_to_root;
|
||||
void reserve(bool_var v) {
|
||||
while (v >= m_to_root.size()) {
|
||||
m_to_root.push_back(literal(m_to_root.size(), false));
|
||||
}
|
||||
}
|
||||
public:
|
||||
literal operator[](bool_var v) const {
|
||||
return (v < m_to_root.size()) ? m_to_root[v] : literal(v, false);
|
||||
}
|
||||
literal& operator[](bool_var v) {
|
||||
reserve(v);
|
||||
return m_to_root[v];
|
||||
}
|
||||
};
|
||||
|
||||
class lut {
|
||||
aig_cuts& a;
|
||||
node const* n;
|
||||
cut const* c;
|
||||
public:
|
||||
lut(aig_cuts& a, node const& n) : a(a), n(&n), c(nullptr) {}
|
||||
lut(aig_cuts& a, cut const& c) : a(a), n(nullptr), c(&c) {}
|
||||
unsigned size() const { return n ? n->size() : c->size(); }
|
||||
literal child(unsigned idx) const { return n ? a.child(*n, idx) : a.child(*c, idx); }
|
||||
uint64_t table() const { return n ? n->lut() : c->table(); }
|
||||
std::ostream& display(std::ostream& out) const { return n ? a.display(out, *n) : out << *c; }
|
||||
};
|
||||
|
||||
bool is_touched(bool_var v, node const& n);
|
||||
bool is_touched(literal lit) const { return is_touched(lit.var()); }
|
||||
bool is_touched(bool_var v) const { return v < m_last_touched.size() && m_last_touched[v] + m_aig.size() >= m_num_cut_calls * m_aig.size(); }
|
||||
void reserve(unsigned v);
|
||||
bool insert_aux(unsigned v, node const& n);
|
||||
void init_cut_set(unsigned id);
|
||||
|
||||
bool eq(node const& a, node const& b);
|
||||
bool similar(node const& a, node const& b);
|
||||
|
||||
unsigned_vector filter_valid_nodes() const;
|
||||
void augment(unsigned_vector const& ids);
|
||||
void augment(unsigned id, node const& n);
|
||||
void augment_ite(unsigned v, node const& n, cut_set& cs);
|
||||
void augment_aig0(unsigned v, node const& n, cut_set& cs);
|
||||
void augment_aig1(unsigned v, node const& n, cut_set& cs);
|
||||
void augment_aig2(unsigned v, node const& n, cut_set& cs);
|
||||
void augment_aigN(unsigned v, node const& n, cut_set& cs);
|
||||
|
||||
|
||||
void augment_lut(unsigned v, lut const& n, cut_set& cs);
|
||||
void augment_lut_rec(unsigned v, lut const& n, cut& a, unsigned idx, cut_set& cs);
|
||||
|
||||
cut_set const& lit2cuts(literal lit) const { return lit.var() < m_cuts.size() ? m_cuts[lit.var()] : m_empty_cuts; }
|
||||
|
||||
bool insert_cut(unsigned v, cut const& c, cut_set& cs);
|
||||
|
||||
void flush_roots();
|
||||
bool flush_roots(bool_var var, to_root const& to_root, node& n);
|
||||
void flush_roots(to_root const& to_root, cut_set& cs);
|
||||
|
||||
cut_val eval(node const& n, cut_eval const& env) const;
|
||||
lbool get_value(bool_var v) const;
|
||||
|
||||
std::ostream& display(std::ostream& out, node const& n) const;
|
||||
|
||||
literal child(node const& n, unsigned idx) const { SASSERT(!n.is_var()); SASSERT(idx < n.size()); return m_literals[n.offset() + idx]; }
|
||||
literal child(cut const& n, unsigned idx) const { SASSERT(idx < n.size()); return literal(n[idx], false); }
|
||||
|
||||
void on_node_add(unsigned v, node const& n);
|
||||
void on_node_del(unsigned v, node const& n);
|
||||
|
||||
void evict(cut_set& cs, unsigned idx) { cs.evict(m_on_cut_del, idx); }
|
||||
void reset(cut_set& cs) { cs.reset(m_on_cut_del); }
|
||||
void push_back(cut_set& cs, cut const& c) { cs.push_back(m_on_cut_add, c); }
|
||||
void shrink(cut_set& cs, unsigned j) { cs.shrink(m_on_cut_del, j); }
|
||||
|
||||
void cut2clauses(on_clause_t& on_clause, unsigned v, cut const& c);
|
||||
void node2def(on_clause_t& on_clause, node const& n, literal r);
|
||||
|
||||
struct validator;
|
||||
void validate_cut(unsigned v, cut const& c);
|
||||
void validate_aig2(cut const& a, cut const& b, unsigned v, node const& n, cut const& c);
|
||||
void validate_aigN(unsigned v, node const& n, cut const& c);
|
||||
|
||||
void add_node(bool_var v, node const& n);
|
||||
public:
|
||||
|
||||
aig_cuts();
|
||||
void add_var(unsigned v);
|
||||
void add_node(literal head, bool_op op, unsigned sz, literal const* args);
|
||||
void add_node(bool_var head, uint64_t lut, unsigned sz, bool_var const* args);
|
||||
void add_cut(bool_var v, uint64_t lut, bool_var_vector const& args);
|
||||
void set_root(bool_var v, literal r);
|
||||
|
||||
void set_on_clause_add(on_clause_t& on_clause_add);
|
||||
void set_on_clause_del(on_clause_t& on_clause_del);
|
||||
|
||||
void inc_max_cutset_size(unsigned v) { m_max_cutset_size.reserve(v + 1, 0); m_max_cutset_size[v] += 10; touch(v); }
|
||||
unsigned max_cutset_size(unsigned v) const { return v == UINT_MAX ? m_config.m_max_cutset_size : m_max_cutset_size[v]; }
|
||||
|
||||
vector<cut_set> const & operator()();
|
||||
unsigned num_cuts() const { return m_num_cuts; }
|
||||
|
||||
void cut2def(on_clause_t& on_clause, cut const& c, literal r);
|
||||
|
||||
void touch(bool_var v) { m_last_touched.reserve(v + 1, false); m_last_touched[v] = v + m_num_cut_calls * m_aig.size(); }
|
||||
|
||||
cut_eval simulate(unsigned num_rounds);
|
||||
|
||||
void simplify();
|
||||
|
||||
std::ostream& display(std::ostream& out) const;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -109,15 +109,6 @@ namespace sat {
|
|||
m_anf_simplify = p.anf();
|
||||
m_anf_delay = p.anf_delay();
|
||||
m_anf_exlin = p.anf_exlin();
|
||||
m_cut_simplify = p.cut();
|
||||
m_cut_delay = p.cut_delay();
|
||||
m_cut_aig = p.cut_aig();
|
||||
m_cut_lut = p.cut_lut();
|
||||
m_cut_xor = p.cut_xor();
|
||||
m_cut_npn3 = p.cut_npn3();
|
||||
m_cut_dont_cares = p.cut_dont_cares();
|
||||
m_cut_redundancies = p.cut_redundancies();
|
||||
m_cut_force = p.cut_force();
|
||||
m_lookahead_simplify = p.lookahead_simplify();
|
||||
m_lookahead_double = p.lookahead_double();
|
||||
m_lookahead_simplify_bca = p.lookahead_simplify_bca();
|
||||
|
|
|
|||
|
|
@ -119,15 +119,6 @@ namespace sat {
|
|||
bool m_local_search;
|
||||
local_search_mode m_local_search_mode;
|
||||
bool m_local_search_dbg_flips;
|
||||
bool m_cut_simplify;
|
||||
unsigned m_cut_delay;
|
||||
bool m_cut_aig;
|
||||
bool m_cut_lut;
|
||||
bool m_cut_xor;
|
||||
bool m_cut_npn3;
|
||||
bool m_cut_dont_cares;
|
||||
bool m_cut_redundancies;
|
||||
bool m_cut_force;
|
||||
bool m_anf_simplify;
|
||||
unsigned m_anf_delay;
|
||||
bool m_anf_exlin;
|
||||
|
|
|
|||
|
|
@ -1,755 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2020 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
sat_cut_simplifier.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
extract AIG definitions from clauses
|
||||
Perform cut-set enumeration to identify equivalences.
|
||||
|
||||
Author:
|
||||
|
||||
Nikolaj Bjorner 2020-01-02
|
||||
|
||||
--*/
|
||||
|
||||
#include "sat/sat_cut_simplifier.h"
|
||||
#include "sat/sat_xor_finder.h"
|
||||
#include "sat/sat_lut_finder.h"
|
||||
#include "sat/sat_npn3_finder.h"
|
||||
#include "sat/sat_elim_eqs.h"
|
||||
|
||||
namespace sat {
|
||||
|
||||
struct cut_simplifier::report {
|
||||
cut_simplifier& s;
|
||||
stopwatch m_watch;
|
||||
unsigned m_num_eqs, m_num_units, m_num_cuts, m_num_learned_implies;
|
||||
|
||||
report(cut_simplifier& s): s(s) {
|
||||
m_watch.start();
|
||||
m_num_eqs = s.m_stats.m_num_eqs;
|
||||
m_num_units = s.m_stats.m_num_units;
|
||||
m_num_cuts = s.m_stats.m_num_cuts;
|
||||
m_num_learned_implies = s.m_stats.m_num_learned_implies;
|
||||
}
|
||||
~report() {
|
||||
unsigned ne = s.m_stats.m_num_eqs - m_num_eqs;
|
||||
unsigned nu = s.m_stats.m_num_units - m_num_units;
|
||||
unsigned nc = s.m_stats.m_num_cuts - m_num_cuts;
|
||||
unsigned ni = s.m_stats.m_num_learned_implies - m_num_learned_implies;
|
||||
IF_VERBOSE(2,
|
||||
verbose_stream() << "(sat.cut-simplifier";
|
||||
if (nu > 0) verbose_stream() << " :num-units " << nu;
|
||||
if (ne > 0) verbose_stream() << " :num-eqs " << ne;
|
||||
if (ni > 0) verbose_stream() << " :num-bin " << ni;
|
||||
if (nc > 0) verbose_stream() << " :num-cuts " << nc;
|
||||
verbose_stream() << " :mb " << mem_stat() << m_watch << ")\n");
|
||||
}
|
||||
};
|
||||
|
||||
struct cut_simplifier::validator {
|
||||
solver& _s;
|
||||
params_ref p;
|
||||
literal_vector m_assumptions;
|
||||
|
||||
validator(solver& _s, params_ref const& p): _s(_s), p(p) {
|
||||
}
|
||||
|
||||
void validate(unsigned n, literal const* clause) {
|
||||
validate(literal_vector(n, clause));
|
||||
}
|
||||
|
||||
void validate(literal_vector const& clause) {
|
||||
if (clause.size() == 2 && clause[0] == ~clause[1]) return;
|
||||
solver s(p, _s.rlimit());
|
||||
s.copy(_s, false);
|
||||
IF_VERBOSE(10, verbose_stream() << "validate: " << clause << "\n");
|
||||
m_assumptions.reset();
|
||||
for (literal lit : clause) m_assumptions.push_back(~lit);
|
||||
lbool r = s.check(clause.size(), m_assumptions.data());
|
||||
if (r != l_false) {
|
||||
IF_VERBOSE(0,
|
||||
verbose_stream() << "not validated: " << clause << "\n";
|
||||
s.display(verbose_stream()););
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void cut_simplifier::ensure_validator() {
|
||||
if (!m_validator) {
|
||||
params_ref p;
|
||||
p.set_bool("aig", false);
|
||||
p.set_bool("drat.check_unsat", false);
|
||||
p.set_sym("drat.file", symbol());
|
||||
p.set_uint("max_conflicts", 10000);
|
||||
m_validator = alloc(validator, s, p);
|
||||
}
|
||||
}
|
||||
|
||||
cut_simplifier::cut_simplifier(solver& _s):
|
||||
s(_s),
|
||||
m_trail_size(0),
|
||||
m_validator(nullptr) {
|
||||
if (s.get_config().m_drat) {
|
||||
std::function<void(literal_vector const& clause)> _on_add =
|
||||
[this](literal_vector const& clause) { s.m_drat.add(clause); };
|
||||
std::function<void(literal_vector const& clause)> _on_del =
|
||||
[this](literal_vector const& clause) { s.m_drat.del(clause); };
|
||||
m_aig_cuts.set_on_clause_add(_on_add);
|
||||
m_aig_cuts.set_on_clause_del(_on_del);
|
||||
}
|
||||
else if (m_config.m_validate_cuts) {
|
||||
ensure_validator();
|
||||
std::function<void(literal_vector const& clause)> _on_add =
|
||||
[this](literal_vector const& clause) {
|
||||
m_validator->validate(clause);
|
||||
};
|
||||
m_aig_cuts.set_on_clause_add(_on_add);
|
||||
}
|
||||
}
|
||||
|
||||
cut_simplifier::~cut_simplifier() {
|
||||
dealloc(m_validator);
|
||||
}
|
||||
|
||||
void cut_simplifier::add_and(literal head, unsigned sz, literal const* lits) {
|
||||
m_aig_cuts.add_node(head, and_op, sz, lits);
|
||||
for (unsigned i = 0; i < sz; ++i) VERIFY(head.var() != lits[i].var());
|
||||
m_stats.m_num_ands++;
|
||||
}
|
||||
|
||||
// head == l1 or l2 or l3
|
||||
// <=>
|
||||
// ~head == ~l1 and ~l2 and ~l3
|
||||
void cut_simplifier::add_or(literal head, unsigned sz, literal const* lits) {
|
||||
m_lits.reset();
|
||||
m_lits.append(sz, lits);
|
||||
for (unsigned i = 0; i < sz; ++i) m_lits[i].neg();
|
||||
m_aig_cuts.add_node(~head, and_op, sz, m_lits.data());
|
||||
m_stats.m_num_ands++;
|
||||
}
|
||||
|
||||
void cut_simplifier::add_xor(literal head, unsigned sz, literal const* lits) {
|
||||
m_aig_cuts.add_node(head, xor_op, sz, lits);
|
||||
m_stats.m_num_xors++;
|
||||
}
|
||||
|
||||
void cut_simplifier::add_ite(literal head, literal c, literal t, literal e) {
|
||||
literal lits[3] = { c, t, e };
|
||||
m_aig_cuts.add_node(head, ite_op, 3, lits);
|
||||
m_stats.m_num_ites++;
|
||||
}
|
||||
|
||||
void cut_simplifier::add_iff(literal head, literal l1, literal l2) {
|
||||
literal lits[2] = { l1, ~l2 };
|
||||
m_aig_cuts.add_node(head, xor_op, 2, lits);
|
||||
m_stats.m_num_xors++;
|
||||
}
|
||||
|
||||
void cut_simplifier::set_root(bool_var v, literal r) {
|
||||
m_aig_cuts.set_root(v, r);
|
||||
}
|
||||
|
||||
void cut_simplifier::operator()() {
|
||||
|
||||
bool force = s.m_config.m_cut_force;
|
||||
report _report(*this);
|
||||
TRACE(cut_simplifier, s.display(tout););
|
||||
unsigned n = 0, i = 0;
|
||||
++m_stats.m_num_calls;
|
||||
do {
|
||||
n = m_stats.m_num_eqs + m_stats.m_num_units;
|
||||
clauses2aig();
|
||||
aig2clauses();
|
||||
++i;
|
||||
}
|
||||
while (((force && i < 5) || i*i < m_stats.m_num_calls) && n < m_stats.m_num_eqs + m_stats.m_num_units);
|
||||
}
|
||||
|
||||
/**
|
||||
\brief extract AIG definitions from clauses
|
||||
Ensure that they are sorted and variables have unique definitions.
|
||||
*/
|
||||
void cut_simplifier::clauses2aig() {
|
||||
|
||||
for (; m_config.m_enable_units && m_trail_size < s.init_trail_size(); ++m_trail_size) {
|
||||
literal lit = s.trail_literal(m_trail_size);
|
||||
m_aig_cuts.add_node(lit, and_op, 0, nullptr);
|
||||
}
|
||||
|
||||
clause_vector clauses(s.clauses());
|
||||
if (m_config.m_learned2aig) clauses.append(s.learned());
|
||||
|
||||
std::function<void (literal head, literal_vector const& ands)> on_and =
|
||||
[&,this](literal head, literal_vector const& ands) {
|
||||
m_aig_cuts.add_node(head, and_op, ands.size(), ands.data());
|
||||
m_stats.m_xands++;
|
||||
};
|
||||
std::function<void (literal head, literal c, literal t, literal e)> on_ite =
|
||||
[&,this](literal head, literal c, literal t, literal e) {
|
||||
literal args[3] = { c, t, e };
|
||||
m_aig_cuts.add_node(head, ite_op, 3, args);
|
||||
m_stats.m_xites++;
|
||||
};
|
||||
if (s.m_config.m_cut_aig) {
|
||||
aig_finder af(s);
|
||||
af.set(on_and);
|
||||
af.set(on_ite);
|
||||
af(clauses);
|
||||
}
|
||||
|
||||
|
||||
std::function<void (literal_vector const&)> on_xor =
|
||||
[&,this](literal_vector const& xors) {
|
||||
SASSERT(xors.size() > 1);
|
||||
unsigned max_level = xors.back().var();
|
||||
unsigned index = xors.size() - 1;
|
||||
for (unsigned i = index; i-- > 0; ) {
|
||||
literal l = xors[i];
|
||||
if (l.var() > max_level) {
|
||||
max_level = l.var();
|
||||
index = i;
|
||||
}
|
||||
}
|
||||
// head + t1 + t2 + .. = 1
|
||||
// <=>
|
||||
// ~head = t1 + t2 + ..
|
||||
literal head = ~xors[index];
|
||||
TRACE(cut_simplifier, tout << xors << "\n";);
|
||||
unsigned sz = xors.size() - 1;
|
||||
m_lits.reset();
|
||||
for (unsigned i = xors.size(); i-- > 0; ) {
|
||||
if (i != index)
|
||||
m_lits.push_back(xors[i]);
|
||||
}
|
||||
m_aig_cuts.add_node(head, xor_op, sz, m_lits.data());
|
||||
m_lits.reset();
|
||||
m_stats.m_xxors++;
|
||||
};
|
||||
if (s.m_config.m_cut_xor) {
|
||||
xor_finder xf(s);
|
||||
xf.set(on_xor);
|
||||
xf(clauses);
|
||||
}
|
||||
|
||||
std::function<void(uint64_t, bool_var_vector const&, bool_var)> on_lut =
|
||||
[&,this](uint64_t lut, bool_var_vector const& vars, bool_var v) {
|
||||
m_stats.m_xluts++;
|
||||
// m_aig_cuts.add_cut(v, lut, vars);
|
||||
m_aig_cuts.add_node(v, lut, vars.size(), vars.data());
|
||||
};
|
||||
|
||||
if (s.m_config.m_cut_npn3) {
|
||||
npn3_finder nf(s);
|
||||
// TBD: stubs for npn3
|
||||
// question: perhaps just use a LUT interface?
|
||||
// nf.set_on_mux
|
||||
// nf.set_on_maj
|
||||
// nf.set_on_orand
|
||||
// nf.set_on_and
|
||||
// nf.set_on_xor
|
||||
// nf.set_on_andxor
|
||||
// nf.set_on_xorand
|
||||
// nf.set_on_gamble
|
||||
// nf.set_on_onehot
|
||||
// nf.set_on_dot
|
||||
// nf(clauses);
|
||||
}
|
||||
|
||||
if (s.m_config.m_cut_lut) {
|
||||
lut_finder lf(s);
|
||||
lf.set(on_lut);
|
||||
lf(clauses);
|
||||
}
|
||||
|
||||
#if 0
|
||||
statistics st;
|
||||
collect_statistics(st);
|
||||
st.display(std::cout);
|
||||
exit(0);
|
||||
#endif
|
||||
}
|
||||
|
||||
void cut_simplifier::aig2clauses() {
|
||||
vector<cut_set> const& cuts = m_aig_cuts();
|
||||
m_stats.m_num_cuts = m_aig_cuts.num_cuts();
|
||||
add_dont_cares(cuts);
|
||||
cuts2equiv(cuts);
|
||||
cuts2implies(cuts);
|
||||
simulate_eqs();
|
||||
}
|
||||
|
||||
void cut_simplifier::cuts2equiv(vector<cut_set> const& cuts) {
|
||||
map<cut const*, unsigned, cut::hash_proc, cut::eq_proc> cut2id;
|
||||
bool new_eq = false;
|
||||
union_find_default_ctx ctx;
|
||||
union_find<> uf(ctx);
|
||||
|
||||
for (unsigned i = 2*s.num_vars(); i--> 0; ) uf.mk_var();
|
||||
auto add_eq = [&](literal l1, literal l2) {
|
||||
uf.merge(l1.index(), l2.index());
|
||||
uf.merge((~l1).index(), (~l2).index());
|
||||
new_eq = true;
|
||||
};
|
||||
|
||||
for (unsigned i = cuts.size(); i-- > 0; ) {
|
||||
literal u(i, false);
|
||||
for (auto& c : cuts[i]) {
|
||||
unsigned j = 0;
|
||||
cut nc(c);
|
||||
nc.negate();
|
||||
if (m_config.m_enable_units && c.is_true()) {
|
||||
assign_unit(c, u);
|
||||
}
|
||||
else if (m_config.m_enable_units && c.is_false()) {
|
||||
assign_unit(nc, ~u);
|
||||
}
|
||||
else if (cut2id.find(&c, j)) {
|
||||
literal v(j, false);
|
||||
assign_equiv(c, u, v);
|
||||
add_eq(u, v);
|
||||
}
|
||||
else if (cut2id.find(&nc, j)) {
|
||||
literal v(j, true);
|
||||
assign_equiv(c, u, v);
|
||||
add_eq(u, v);
|
||||
}
|
||||
else {
|
||||
cut2id.insert(&c, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (new_eq) {
|
||||
uf2equiv(uf);
|
||||
}
|
||||
}
|
||||
|
||||
void cut_simplifier::assign_unit(cut const& c, literal lit) {
|
||||
if (s.value(lit) != l_undef)
|
||||
return;
|
||||
IF_VERBOSE(10, verbose_stream() << "new unit " << lit << "\n");
|
||||
validate_unit(lit);
|
||||
certify_unit(lit, c);
|
||||
s.assign_unit(lit);
|
||||
++m_stats.m_num_units;
|
||||
}
|
||||
|
||||
void cut_simplifier::assign_equiv(cut const& c, literal u, literal v) {
|
||||
if (u.var() == v.var()) return;
|
||||
IF_VERBOSE(10, verbose_stream() << u << " " << v << " " << c << "\n";);
|
||||
TRACE(cut_simplifier, tout << u << " == " << v << "\n";);
|
||||
certify_equivalence(u, v, c);
|
||||
validate_eq(u, v);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a union-find over literals into input for eim_eqs.
|
||||
*/
|
||||
void cut_simplifier::uf2equiv(union_find<> const& uf) {
|
||||
union_find_default_ctx ctx;
|
||||
union_find<> uf2(ctx);
|
||||
bool new_eq = false;
|
||||
for (unsigned i = 2*s.num_vars(); i--> 0; ) uf2.mk_var();
|
||||
// extract equivalences over non-eliminated literals.
|
||||
for (unsigned idx = 0; idx < uf.get_num_vars(); ++idx) {
|
||||
if (!uf.is_root(idx) || 1 == uf.size(idx)) continue;
|
||||
literal root = null_literal;
|
||||
unsigned first = idx;
|
||||
do {
|
||||
literal lit = to_literal(idx);
|
||||
if (!s.was_eliminated(lit)) {
|
||||
if (root == null_literal) {
|
||||
root = lit;
|
||||
}
|
||||
else {
|
||||
uf2.merge(lit.index(), root.index());
|
||||
new_eq = true;
|
||||
++m_stats.m_num_eqs;
|
||||
}
|
||||
}
|
||||
idx = uf.next(idx);
|
||||
}
|
||||
while (first != idx);
|
||||
}
|
||||
for (unsigned i = s.num_vars(); i-- > 0; ) {
|
||||
literal lit(i, false);
|
||||
if (uf2.find(lit.index()) == uf2.find((~lit).index())) {
|
||||
s.set_conflict();
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (new_eq) {
|
||||
elim_eqs elim(s);
|
||||
elim(uf2);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract binary clauses from cuts.
|
||||
* A bit encoding of a LUT of u
|
||||
* that sets a subset of bits for LUT' of v establishes
|
||||
* that u implies v.
|
||||
*/
|
||||
void cut_simplifier::cuts2implies(vector<cut_set> const& cuts) {
|
||||
if (!m_config.m_learn_implies) return;
|
||||
vector<vector<std::pair<unsigned, cut const*>>> var_tables;
|
||||
map<cut const*, unsigned, cut::dom_hash_proc, cut::dom_eq_proc> cut2tables;
|
||||
unsigned j = 0;
|
||||
big big(s.rand());
|
||||
big.init(s, true);
|
||||
for (auto const& cs : cuts) {
|
||||
if (s.was_eliminated(cs.var()))
|
||||
continue;
|
||||
for (auto const& c : cs) {
|
||||
if (c.is_false() || c.is_true())
|
||||
continue;
|
||||
if (!cut2tables.find(&c, j)) {
|
||||
j = var_tables.size();
|
||||
var_tables.push_back(vector<std::pair<unsigned, cut const*>>());
|
||||
cut2tables.insert(&c, j);
|
||||
}
|
||||
var_tables[j].push_back(std::make_pair(cs.var(), &c));
|
||||
}
|
||||
}
|
||||
for (unsigned i = 0; i < var_tables.size(); ++i) {
|
||||
auto const& vt = var_tables[i];
|
||||
for (unsigned j = 0; j < vt.size(); ++j) {
|
||||
literal u(vt[j].first, false);
|
||||
cut const& c1 = *vt[j].second;
|
||||
cut nc1(c1);
|
||||
nc1.negate();
|
||||
uint64_t t1 = c1.table();
|
||||
uint64_t n1 = nc1.table();
|
||||
for (unsigned k = j + 1; k < vt.size(); ++k) {
|
||||
literal v(vt[k].first, false);
|
||||
cut const& c2 = *vt[k].second;
|
||||
uint64_t t2 = c2.table();
|
||||
uint64_t n2 = c2.ntable();
|
||||
if (t1 == t2 || t1 == n2) {
|
||||
// already handled
|
||||
}
|
||||
else if ((t1 | t2) == t2) {
|
||||
learn_implies(big, c1, u, v);
|
||||
}
|
||||
else if ((t1 | n2) == n2) {
|
||||
learn_implies(big, c1, u, ~v);
|
||||
}
|
||||
else if ((n1 | t2) == t2) {
|
||||
learn_implies(big, nc1, ~u, v);
|
||||
}
|
||||
else if ((n1 | n2) == n2) {
|
||||
learn_implies(big, nc1, ~u, ~v);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void cut_simplifier::learn_implies(big& big, cut const& c, literal u, literal v) {
|
||||
if (u == ~v) {
|
||||
assign_unit(c, v);
|
||||
return;
|
||||
}
|
||||
if (u == v) {
|
||||
return;
|
||||
}
|
||||
bin_rel q, p(~u, v);
|
||||
if (m_bins.find(p, q) && q.op != op_code::none)
|
||||
return;
|
||||
if (big.connected(u, v))
|
||||
return;
|
||||
for (auto const& w : s.get_wlist(u))
|
||||
if (w.is_binary_clause() && v == w.get_literal())
|
||||
return;
|
||||
certify_implies(u, v, c);
|
||||
s.mk_clause(~u, v, sat::status::redundant());
|
||||
// m_bins owns reference to ~u or v created by certify_implies
|
||||
m_bins.insert(p);
|
||||
++m_stats.m_num_learned_implies;
|
||||
}
|
||||
|
||||
void cut_simplifier::simulate_eqs() {
|
||||
if (!m_config.m_simulate_eqs) return;
|
||||
auto var2val = m_aig_cuts.simulate(4);
|
||||
|
||||
// Assign higher cutset budgets to equality candidates that come from simulation
|
||||
// touch them to trigger recomputation of cutsets.
|
||||
u64_map<literal> val2lit;
|
||||
unsigned i = 0, num_eqs = 0;
|
||||
for (cut_val val : var2val) {
|
||||
if (!s.was_eliminated(i) && s.value(i) == l_undef) {
|
||||
literal u(i, false), v;
|
||||
if (val2lit.find(val.m_t, v)) {
|
||||
|
||||
m_aig_cuts.inc_max_cutset_size(i);
|
||||
m_aig_cuts.inc_max_cutset_size(v.var());
|
||||
num_eqs++;
|
||||
}
|
||||
else if (val2lit.find(val.m_f, v)) {
|
||||
m_aig_cuts.inc_max_cutset_size(i);
|
||||
m_aig_cuts.inc_max_cutset_size(v.var());
|
||||
num_eqs++;
|
||||
}
|
||||
else {
|
||||
val2lit.insert(val.m_t, u);
|
||||
val2lit.insert(val.m_f, ~u);
|
||||
}
|
||||
}
|
||||
++i;
|
||||
}
|
||||
IF_VERBOSE(2, verbose_stream() << "(sat.cut-simplifier num simulated eqs " << num_eqs << ")\n");
|
||||
}
|
||||
|
||||
void cut_simplifier::track_binary(bin_rel const& p) {
|
||||
if (!s.m_config.m_drat)
|
||||
return;
|
||||
literal u, v;
|
||||
p.to_binary(u, v);
|
||||
track_binary(u, v);
|
||||
}
|
||||
|
||||
void cut_simplifier::untrack_binary(bin_rel const& p) {
|
||||
if (!s.m_config.m_drat)
|
||||
return;
|
||||
literal u, v;
|
||||
p.to_binary(u, v);
|
||||
untrack_binary(u, v);
|
||||
}
|
||||
|
||||
void cut_simplifier::track_binary(literal u, literal v) {
|
||||
if (s.m_config.m_drat) {
|
||||
s.m_drat.add(u, v, sat::status::redundant());
|
||||
}
|
||||
}
|
||||
|
||||
void cut_simplifier::untrack_binary(literal u, literal v) {
|
||||
if (s.m_config.m_drat) {
|
||||
s.m_drat.del(u, v);
|
||||
}
|
||||
}
|
||||
|
||||
void cut_simplifier::certify_unit(literal u, cut const& c) {
|
||||
certify_implies(~u, u, c);
|
||||
}
|
||||
|
||||
/**
|
||||
* Equivalences modulo cuts are not necessarily DRAT derivable.
|
||||
* To ensure that there is a DRAT derivation we create all resolvents
|
||||
* of the LUT clauses until deriving binary u or ~v and ~u or v.
|
||||
* each resolvent is DRAT derivable because there are two previous lemmas that
|
||||
* contain complementary literals.
|
||||
*/
|
||||
void cut_simplifier::certify_equivalence(literal u, literal v, cut const& c) {
|
||||
certify_implies(u, v, c);
|
||||
certify_implies(v, u, c);
|
||||
}
|
||||
|
||||
/**
|
||||
* certify that u implies v, where c is the cut for u.
|
||||
* Then every position in c where u is true, it has to be
|
||||
* the case that v is too.
|
||||
* Where u is false, v can have any value.
|
||||
* Thus, for every clause C or u', where u' is u or ~u,
|
||||
* it follows that C or ~u or v
|
||||
*/
|
||||
void cut_simplifier::certify_implies(literal u, literal v, cut const& c) {
|
||||
if (!s.m_config.m_drat) return;
|
||||
|
||||
vector<literal_vector> clauses;
|
||||
std::function<void(literal_vector const& clause)> on_clause =
|
||||
[&,this](literal_vector const& clause) {
|
||||
SASSERT(clause.back().var() == u.var());
|
||||
clauses.push_back(clause);
|
||||
clauses.back().back() = ~u;
|
||||
if (~u != v) clauses.back().push_back(v);
|
||||
s.m_drat.add(clauses.back());
|
||||
};
|
||||
m_aig_cuts.cut2def(on_clause, c, u);
|
||||
|
||||
// create all resolvents over C. C is assumed to
|
||||
// contain all combinations of some set of literals.
|
||||
unsigned i = 0, sz = clauses.size();
|
||||
while (sz - i > 1) {
|
||||
SASSERT((sz & (sz - 1)) == 0 && "sz is a power of 2");
|
||||
for (; i < sz; ++i) {
|
||||
auto const& clause = clauses[i];
|
||||
if (clause[0].sign()) {
|
||||
literal_vector cl(clause.size() - 1, clause.data() + 1);
|
||||
clauses.push_back(cl);
|
||||
s.m_drat.add(cl);
|
||||
}
|
||||
}
|
||||
i = sz;
|
||||
sz = clauses.size();
|
||||
}
|
||||
|
||||
IF_VERBOSE(10, for (auto const& clause : clauses) verbose_stream() << clause << "\n";);
|
||||
|
||||
// once we established equivalence, don't need auxiliary clauses for DRAT.
|
||||
clauses.pop_back();
|
||||
for (auto const& clause : clauses) {
|
||||
s.m_drat.del(clause);
|
||||
}
|
||||
}
|
||||
|
||||
void cut_simplifier::add_dont_cares(vector<cut_set> const& cuts) {
|
||||
if (s.m_config.m_cut_dont_cares) {
|
||||
cuts2bins(cuts);
|
||||
bins2dont_cares();
|
||||
dont_cares2cuts(cuts);
|
||||
}
|
||||
if (s.m_config.m_cut_redundancies) {
|
||||
m_aig_cuts.simplify();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Collect binary relations between variables that occur in cut sets.
|
||||
*/
|
||||
void cut_simplifier::cuts2bins(vector<cut_set> const& cuts) {
|
||||
svector<bin_rel> dcs;
|
||||
for (auto const& p : m_bins)
|
||||
if (p.op != op_code::none)
|
||||
dcs.push_back(p);
|
||||
m_bins.reset();
|
||||
for (auto const& cs : cuts)
|
||||
for (auto const& c : cs)
|
||||
for (unsigned i = c.size(); i-- > 0; )
|
||||
for (unsigned j = i; j-- > 0; )
|
||||
m_bins.insert(bin_rel(c[j],c[i]));
|
||||
|
||||
// don't lose previous don't cares
|
||||
for (auto const& p : dcs) {
|
||||
if (m_bins.contains(p)) {
|
||||
m_bins.insert(p);
|
||||
}
|
||||
else {
|
||||
untrack_binary(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute masks for binary relations.
|
||||
*/
|
||||
void cut_simplifier::bins2dont_cares() {
|
||||
big b(s.rand());
|
||||
b.init(s, true);
|
||||
for (auto& p : m_bins) {
|
||||
if (p.op != op_code::none) continue;
|
||||
literal u(p.u, false), v(p.v, false);
|
||||
// u -> v, then u & ~v is impossible
|
||||
if (b.connected(u, v)) {
|
||||
p.op = op_code::pn;
|
||||
}
|
||||
else if (b.connected(u, ~v)) {
|
||||
p.op = op_code::pp;
|
||||
}
|
||||
else if (b.connected(~u, v)) {
|
||||
p.op = op_code::nn;
|
||||
}
|
||||
else if (b.connected(~u, ~v)) {
|
||||
p.op = op_code::np;
|
||||
}
|
||||
if (p.op != op_code::none) {
|
||||
track_binary(p);
|
||||
}
|
||||
}
|
||||
IF_VERBOSE(2, {
|
||||
unsigned n = 0; for (auto const& p : m_bins) if (p.op != op_code::none) ++n;
|
||||
verbose_stream() << n << " / " << m_bins.size() << " don't cares\n";
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Loop over cuts, if it is possible to add a new don't care combination
|
||||
* to a cut, then ensure that the variable is "touched" so that it participates
|
||||
* in the next propagation.
|
||||
*/
|
||||
void cut_simplifier::dont_cares2cuts(vector<cut_set> const& cuts) {
|
||||
for (auto& cs : cuts) {
|
||||
for (auto const& c : cs) {
|
||||
if (add_dont_care(c)) {
|
||||
m_aig_cuts.touch(cs.var());
|
||||
m_stats.m_num_dont_care_reductions++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* compute masks for position i, j and op-code p.op
|
||||
* For the don't care combination false, false, the first don't care
|
||||
* position is 0. If it is true, false, the first don't care position
|
||||
* is the position that encodes the first occurrence where i is true.
|
||||
* It is 2^i. Cases for false, true and true, true are similar.
|
||||
* Don't care positions are spaced apart by 2^{j+1},
|
||||
* where j is the second variable position.
|
||||
*/
|
||||
uint64_t cut_simplifier::op2dont_care(unsigned i, unsigned j, bin_rel const& p) {
|
||||
SASSERT(i < j && j < 6);
|
||||
if (p.op == op_code::none) return 0ull;
|
||||
// first position of mask is offset into output bits contributed by i and j
|
||||
bool i_is_0 = (p.op == op_code::np || p.op == op_code::nn);
|
||||
bool j_is_0 = (p.op == op_code::pn || p.op == op_code::nn);
|
||||
uint64_t first = (i_is_0 ? 0 : (1 << i)) + (j_is_0 ? 0 : (1 << j));
|
||||
uint64_t inc = 1ull << (j + 1);
|
||||
uint64_t r = 1ull << first;
|
||||
while (inc < 64ull) { r |= (r << inc); inc *= 2; }
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply obtained dont_cares to cut sets.
|
||||
* The don't care bits are added to the LUT, so that the
|
||||
* output is always 1 on don't care combinations.
|
||||
*/
|
||||
bool cut_simplifier::add_dont_care(cut const & c) {
|
||||
uint64_t dc = 0;
|
||||
for (unsigned i = 0; i < c.size(); ++i) {
|
||||
for (unsigned j = i + 1; j < c.size(); ++j) {
|
||||
bin_rel p(c[i], c[j]);
|
||||
if (m_bins.find(p, p) && p.op != op_code::none) {
|
||||
dc |= op2dont_care(i, j, p);
|
||||
}
|
||||
}
|
||||
}
|
||||
return (dc != c.dont_care()) && (c.add_dont_care(dc), true);
|
||||
}
|
||||
|
||||
void cut_simplifier::collect_statistics(statistics& st) const {
|
||||
st.update("sat-cut.eqs", m_stats.m_num_eqs);
|
||||
st.update("sat-cut.cuts", m_stats.m_num_cuts);
|
||||
st.update("sat-cut.ands", m_stats.m_num_ands);
|
||||
st.update("sat-cut.ites", m_stats.m_num_ites);
|
||||
st.update("sat-cut.xors", m_stats.m_num_xors);
|
||||
st.update("sat-cut.xands", m_stats.m_xands);
|
||||
st.update("sat-cut.xites", m_stats.m_xites);
|
||||
st.update("sat-cut.xxors", m_stats.m_xxors);
|
||||
st.update("sat-cut.xluts", m_stats.m_xluts);
|
||||
st.update("sat-cut.dc-reduce", m_stats.m_num_dont_care_reductions);
|
||||
}
|
||||
|
||||
void cut_simplifier::validate_unit(literal lit) {
|
||||
if (!m_config.m_validate_lemmas) return;
|
||||
ensure_validator();
|
||||
m_validator->validate(1, &lit);
|
||||
}
|
||||
|
||||
void cut_simplifier::validate_eq(literal a, literal b) {
|
||||
if (!m_config.m_validate_lemmas) return;
|
||||
ensure_validator();
|
||||
literal lits1[2] = { a, ~b };
|
||||
literal lits2[2] = { ~a, b };
|
||||
m_validator->validate(2, lits1);
|
||||
m_validator->validate(2, lits2);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -1,174 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2020 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
sat_cut_simplifier.h
|
||||
|
||||
Abstract:
|
||||
|
||||
extract AIG definitions from clauses
|
||||
Perform cut-set enumeration to identify equivalences.
|
||||
|
||||
Author:
|
||||
|
||||
Nikolaj Bjorner 2020-01-02
|
||||
|
||||
--*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "util/union_find.h"
|
||||
#include "sat/sat_aig_finder.h"
|
||||
#include "sat/sat_aig_cuts.h"
|
||||
|
||||
namespace sat {
|
||||
|
||||
class cut_simplifier {
|
||||
public:
|
||||
struct stats {
|
||||
unsigned m_num_eqs, m_num_units, m_num_cuts, m_num_xors, m_num_ands, m_num_ites;
|
||||
unsigned m_xxors, m_xands, m_xites, m_xluts; // extrated gates
|
||||
unsigned m_num_calls, m_num_dont_care_reductions, m_num_learned_implies;
|
||||
stats() { reset(); }
|
||||
void reset() { memset(this, 0, sizeof(*this)); }
|
||||
};
|
||||
struct config {
|
||||
bool m_enable_units; // enable learning units
|
||||
bool m_enable_dont_cares; // enable applying don't cares to LUTs
|
||||
bool m_learn_implies; // learn binary clauses
|
||||
bool m_learned2aig; // add learned clauses to AIGs used by cut-set enumeration
|
||||
bool m_validate_cuts; // enable direct validation of generated cuts
|
||||
bool m_validate_lemmas; // enable direct validation of learned lemmas
|
||||
bool m_simulate_eqs; // use symbolic simulation to control size of cutsets.
|
||||
config():
|
||||
m_enable_units(true),
|
||||
m_enable_dont_cares(true),
|
||||
m_learn_implies(false),
|
||||
m_learned2aig(true),
|
||||
m_validate_cuts(false),
|
||||
m_validate_lemmas(false),
|
||||
m_simulate_eqs(false) {}
|
||||
};
|
||||
private:
|
||||
struct report;
|
||||
struct validator;
|
||||
|
||||
/**
|
||||
* collect pairs of literal combinations that are impossible
|
||||
* base on binary implication graph queries. Apply the masks
|
||||
* on cut sets so to allow detecting equivalences modulo
|
||||
* implications.
|
||||
*
|
||||
* The encoding is as follows:
|
||||
* a or b -> op = nn because (~a & ~b) is a don't care
|
||||
* ~a or b -> op = pn because (a & ~b) is a don't care
|
||||
* a or ~b -> op = np because (~a & b) is a don't care
|
||||
* ~a or ~b -> op = pp because (a & b) is a don't care
|
||||
*
|
||||
*/
|
||||
|
||||
enum class op_code { pp, pn, np, nn, none };
|
||||
|
||||
struct bin_rel {
|
||||
unsigned u, v;
|
||||
op_code op;
|
||||
bin_rel(unsigned _u, unsigned _v): u(_u), v(_v), op(op_code::none) {
|
||||
if (u > v) std::swap(u, v);
|
||||
}
|
||||
// convert binary clause into a bin-rel
|
||||
bin_rel(literal _u, literal _v): u(_u.var()), v(_v.var()), op(op_code::none) {
|
||||
if (_u.sign() && _v.sign()) op = op_code::pp;
|
||||
else if (_u.sign()) op = op_code::pn;
|
||||
else if (_v.sign()) op = op_code::np;
|
||||
else op = op_code::nn;
|
||||
if (u > v) {
|
||||
std::swap(u, v);
|
||||
if (op == op_code::np) op = op_code::pn;
|
||||
else if (op == op_code::pn) op = op_code::np;
|
||||
}
|
||||
}
|
||||
bin_rel(): u(UINT_MAX), v(UINT_MAX), op(op_code::none) {}
|
||||
|
||||
struct hash {
|
||||
unsigned operator()(bin_rel const& p) const {
|
||||
return p.u + 65599*p.v; // Weinberger's should be a bit cheaper mk_mix(p.u, p.v, 1);
|
||||
}
|
||||
};
|
||||
struct eq {
|
||||
bool operator()(bin_rel const& a, bin_rel const& b) const {
|
||||
return a.u == b.u && a.v == b.v;
|
||||
}
|
||||
};
|
||||
void to_binary(literal& lu, literal& lv) const {
|
||||
switch (op) {
|
||||
case op_code::pp: lu = literal(u, true); lv = literal(v, true); break;
|
||||
case op_code::pn: lu = literal(u, true); lv = literal(v, false); break;
|
||||
case op_code::np: lu = literal(u, false); lv = literal(v, true); break;
|
||||
case op_code::nn: lu = literal(u, false); lv = literal(v, false); break;
|
||||
default: UNREACHABLE(); break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
solver& s;
|
||||
stats m_stats;
|
||||
config m_config;
|
||||
aig_cuts m_aig_cuts;
|
||||
unsigned m_trail_size;
|
||||
literal_vector m_lits;
|
||||
validator* m_validator;
|
||||
hashtable<bin_rel, bin_rel::hash, bin_rel::eq> m_bins;
|
||||
|
||||
void clauses2aig();
|
||||
void aig2clauses();
|
||||
void simulate_eqs();
|
||||
void cuts2equiv(vector<cut_set> const& cuts);
|
||||
void cuts2implies(vector<cut_set> const& cuts);
|
||||
void uf2equiv(union_find<> const& uf);
|
||||
void assign_unit(cut const& c, literal lit);
|
||||
void assign_equiv(cut const& c, literal u, literal v);
|
||||
void learn_implies(big& big, cut const& c, literal u, literal v);
|
||||
void ensure_validator();
|
||||
void validate_unit(literal lit);
|
||||
void validate_eq(literal a, literal b);
|
||||
void certify_unit(literal u, cut const& c);
|
||||
void certify_implies(literal u, literal v, cut const& c);
|
||||
void certify_equivalence(literal u, literal v, cut const& c);
|
||||
void track_binary(literal u, literal v);
|
||||
void untrack_binary(literal u, literal v);
|
||||
void track_binary(bin_rel const& p);
|
||||
void untrack_binary(bin_rel const& p);
|
||||
|
||||
|
||||
void add_dont_cares(vector<cut_set> const& cuts);
|
||||
void cuts2bins(vector<cut_set> const& cuts);
|
||||
void bins2dont_cares();
|
||||
void dont_cares2cuts(vector<cut_set> const& cuts);
|
||||
bool add_dont_care(cut const & c);
|
||||
uint64_t op2dont_care(unsigned i, unsigned j, bin_rel const& p);
|
||||
|
||||
public:
|
||||
cut_simplifier(solver& s);
|
||||
~cut_simplifier();
|
||||
void operator()();
|
||||
void collect_statistics(statistics& st) const;
|
||||
|
||||
/**
|
||||
* The clausifier may know that some literal is defined as a
|
||||
* function of other literals. This API is exposed so that
|
||||
* the clausifier can instrument the simplifier with an initial
|
||||
* AIG.
|
||||
* set_root is issued from the equivalence finder.
|
||||
*/
|
||||
void add_and(literal head, unsigned sz, literal const* args);
|
||||
void add_or(literal head, unsigned sz, literal const* args);
|
||||
void add_xor(literal head, unsigned sz, literal const* args);
|
||||
void add_ite(literal head, literal c, literal t, literal e);
|
||||
void add_iff(literal head, literal l1, literal l2);
|
||||
void set_root(bool_var v, literal r);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1,280 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2020 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
sat_cutset.cpp
|
||||
|
||||
Author:
|
||||
|
||||
Nikolaj Bjorner 2020-01-02
|
||||
|
||||
--*/
|
||||
|
||||
|
||||
#include "util/hashtable.h"
|
||||
#include "sat/sat_cutset.h"
|
||||
#include "sat/sat_cutset_compute_shift.h"
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
|
||||
|
||||
namespace sat {
|
||||
|
||||
/**
|
||||
\brief
|
||||
if c is subsumed by a member in cut_set, then c is not inserted.
|
||||
otherwise, remove members that c subsumes.
|
||||
Note that the cut_set maintains invariant that elements don't subsume each-other.
|
||||
|
||||
TBD: this is a bottleneck.
|
||||
Ideas:
|
||||
- add Bloom filter to is_subset_of operation.
|
||||
- pre-allocate fixed array instead of vector for cut_set to avoid overhead for memory allocation.
|
||||
*/
|
||||
|
||||
bool cut_set::insert(on_update_t& on_add, on_update_t& on_del, cut const& c) {
|
||||
unsigned i = 0, k = m_size;
|
||||
for (; i < k; ++i) {
|
||||
cut const& a = (*this)[i];
|
||||
if (a.subset_of(c)) {
|
||||
return false;
|
||||
}
|
||||
if (c.subset_of(a)) {
|
||||
std::swap(m_cuts[i--], m_cuts[--k]);
|
||||
}
|
||||
}
|
||||
// for DRAT make sure to add new element before removing old cuts
|
||||
// the new cut may need to be justified relative to the old cut
|
||||
push_back(on_add, c);
|
||||
std::swap(m_cuts[i++], m_cuts[m_size-1]);
|
||||
shrink(on_del, i);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cut_set::no_duplicates() const {
|
||||
hashtable<cut const*, cut::hash_proc, cut::eq_proc> table;
|
||||
for (auto const& cut : *this) {
|
||||
VERIFY(!table.contains(&cut));
|
||||
table.insert(&cut);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
std::ostream& cut_set::display(std::ostream& out) const {
|
||||
for (auto const& cut : *this) {
|
||||
cut.display(out) << "\n";
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
void cut_set::shrink(on_update_t& on_del, unsigned j) {
|
||||
if (m_var != UINT_MAX && on_del) {
|
||||
for (unsigned i = j; i < m_size; ++i) {
|
||||
on_del(m_var, m_cuts[i]);
|
||||
}
|
||||
}
|
||||
m_size = j;
|
||||
}
|
||||
|
||||
void cut_set::push_back(on_update_t& on_add, cut const& c) {
|
||||
SASSERT(m_max_size > 0);
|
||||
if (!m_cuts) {
|
||||
m_cuts = new (*m_region) cut[m_max_size];
|
||||
}
|
||||
if (m_size == m_max_size) {
|
||||
m_max_size *= 2;
|
||||
cut* new_cuts = new (*m_region) cut[m_max_size];
|
||||
std::uninitialized_copy(m_cuts, m_cuts + m_size, new_cuts);
|
||||
m_cuts = new_cuts;
|
||||
}
|
||||
if (m_var != UINT_MAX && on_add) on_add(m_var, c);
|
||||
m_cuts[m_size++] = c;
|
||||
}
|
||||
|
||||
void cut_set::evict(on_update_t& on_del, cut const& c) {
|
||||
for (unsigned i = 0; i < m_size; ++i) {
|
||||
if (m_cuts[i] == c) {
|
||||
evict(on_del, i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void cut_set::evict(on_update_t& on_del, unsigned idx) {
|
||||
if (m_var != UINT_MAX && on_del) on_del(m_var, m_cuts[idx]);
|
||||
m_cuts[idx] = m_cuts[--m_size];
|
||||
}
|
||||
|
||||
void cut_set::init(region& r, unsigned max_sz, unsigned v) {
|
||||
m_var = v;
|
||||
m_size = 0;
|
||||
SASSERT(!m_region || m_cuts);
|
||||
VERIFY(!m_region || m_max_size > 0);
|
||||
if (!m_region) {
|
||||
m_max_size = 2; // max_sz;
|
||||
m_region = &r;
|
||||
m_cuts = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
\brief shift table 'a' by adding elements from 'c'.
|
||||
a.shift_table(c)
|
||||
|
||||
\pre 'a' is a subset of 'c'.
|
||||
|
||||
Let 't' be the table for 'a'.
|
||||
|
||||
i'th bit in t is function of indices x0*2^0 + x2*2^1 = i
|
||||
i'th bit in t' is function of indices x0*2^0 + x1*2^1 + x2*2^2 = i
|
||||
|
||||
i -> assignment to coefficients in c,
|
||||
-> assignment to coefficients in a
|
||||
-> compute j,
|
||||
-> t'[i] <- t[j]
|
||||
|
||||
This is still time consuming:
|
||||
Ideas:
|
||||
- pre-compute some shift operations.
|
||||
- use strides on some common cases.
|
||||
- what ABC does?
|
||||
*/
|
||||
uint64_t cut::shift_table(cut const& c) const {
|
||||
SASSERT(subset_of(c));
|
||||
unsigned index = 0;
|
||||
for (unsigned i = 0, j = 0, x = (*this)[i], y = c[j]; x != UINT_MAX; ) {
|
||||
if (x == y) {
|
||||
index |= (1 << j);
|
||||
x = (*this)[++i];
|
||||
}
|
||||
y = c[++j];
|
||||
}
|
||||
index |= (1 << c.m_size);
|
||||
return compute_shift(table(), index);
|
||||
}
|
||||
|
||||
bool cut::operator==(cut const& other) const {
|
||||
return table() == other.table() && dom_eq(other);
|
||||
}
|
||||
|
||||
unsigned cut::hash() const {
|
||||
return get_composite_hash(*this, m_size,
|
||||
[](cut const& c) { return (unsigned)c.table(); },
|
||||
[](cut const& c, unsigned i) { return c[i]; });
|
||||
}
|
||||
|
||||
unsigned cut::dom_hash() const {
|
||||
return get_composite_hash(*this, m_size,
|
||||
[](cut const& c) { return 3; },
|
||||
[](cut const& c, unsigned i) { return c[i]; });
|
||||
}
|
||||
|
||||
bool cut::dom_eq(cut const& other) const {
|
||||
if (m_size != other.m_size) return false;
|
||||
for (unsigned i = 0; i < m_size; ++i) {
|
||||
if ((*this)[i] != other[i]) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief create the masks
|
||||
* i = 0: 101010101010101
|
||||
* i = 1: 1100110011001100
|
||||
* i = 2: 1111000011110000
|
||||
* i = 3: 111111110000000011111111
|
||||
*/
|
||||
|
||||
uint64_t cut::effect_mask(unsigned i) {
|
||||
SASSERT(i <= 6);
|
||||
uint64_t m = 0;
|
||||
if (i == 6) {
|
||||
m = ~((uint64_t)0);
|
||||
}
|
||||
else {
|
||||
m = (1ull << (1u << i)) - 1; // i = 0: m = 1
|
||||
unsigned w = 1u << (i + 1); // i = 0: w = 2
|
||||
while (w < 64) {
|
||||
m |= (m << w); // i = 0: m = 1 + 4
|
||||
w *= 2;
|
||||
}
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
/**
|
||||
remove element from cut as it is deemed a don't care
|
||||
*/
|
||||
void cut::remove_elem(unsigned i) {
|
||||
for (unsigned j = i + 1; j < m_size; ++j) {
|
||||
m_elems[j-1] = m_elems[j];
|
||||
}
|
||||
--m_size;
|
||||
uint64_t m = effect_mask(i);
|
||||
uint64_t t = 0;
|
||||
for (unsigned j = 0, offset = 0; j < 64; ++j) {
|
||||
if (0 != (m & (1ull << j))) {
|
||||
t |= ((m_table >> j) & 1u) << offset;
|
||||
++offset;
|
||||
}
|
||||
}
|
||||
m_table = t;
|
||||
m_dont_care = 0;
|
||||
unsigned f = 0;
|
||||
for (unsigned e : *this) {
|
||||
f |= (1u << (e & 0x1F));
|
||||
}
|
||||
m_filter = f;
|
||||
}
|
||||
|
||||
/**
|
||||
sat-sweep evaluation. Given 64 bits worth of possible values per variable,
|
||||
find possible values for function table encoded by cut.
|
||||
*/
|
||||
cut_val cut::eval(cut_eval const& env) const {
|
||||
cut_val v;
|
||||
uint64_t t = table();
|
||||
uint64_t n = table();
|
||||
unsigned sz = size();
|
||||
if (sz == 1 && t == 2) {
|
||||
return env[m_elems[0]];
|
||||
}
|
||||
for (unsigned i = 0; i < 64; ++i) {
|
||||
unsigned offset = 0;
|
||||
for (unsigned j = 0; j < sz; ++j) {
|
||||
offset |= (((env[m_elems[j]].m_t >> i) & 0x1) << j);
|
||||
}
|
||||
v.m_t |= ((t >> offset) & 0x1) << i;
|
||||
v.m_f |= ((n >> offset) & 0x1) << i;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
std::ostream& cut::display(std::ostream& out) const {
|
||||
out << "{";
|
||||
for (unsigned i = 0; i < m_size; ++i) {
|
||||
out << (*this)[i];
|
||||
if (i + 1 < m_size) out << " ";
|
||||
}
|
||||
out << "} ";
|
||||
display_table(out, m_size, table());
|
||||
return out;
|
||||
}
|
||||
|
||||
std::ostream& cut::display_table(std::ostream& out, unsigned num_input, uint64_t table) {
|
||||
for (unsigned i = 0; i < (1u << num_input); ++i) {
|
||||
if (0 != (table & (1ull << i))) out << "1"; else out << "0";
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
std::string cut::table2string(unsigned num_input, uint64_t table) {
|
||||
std::ostringstream strm;
|
||||
display_table(strm, num_input, table);
|
||||
return std::move(strm).str();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -1,201 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2020 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
sat_cutset.cpp
|
||||
|
||||
Author:
|
||||
|
||||
Nikolaj Bjorner 2020-01-02
|
||||
|
||||
--*/
|
||||
|
||||
#pragma once
|
||||
#include "util/region.h"
|
||||
#include "util/debug.h"
|
||||
#include "util/util.h"
|
||||
#include "util/lbool.h"
|
||||
#include "util/vector.h"
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include <functional>
|
||||
|
||||
namespace sat {
|
||||
|
||||
struct cut_val {
|
||||
cut_val():m_t(0ull), m_f(0ull) {}
|
||||
cut_val(uint64_t t, uint64_t f): m_t(t), m_f(f) {}
|
||||
uint64_t m_t, m_f;
|
||||
};
|
||||
|
||||
typedef svector<cut_val> cut_eval;
|
||||
|
||||
class cut {
|
||||
unsigned m_filter;
|
||||
unsigned m_size;
|
||||
unsigned m_elems[5];
|
||||
uint64_t m_table;
|
||||
mutable uint64_t m_dont_care;
|
||||
|
||||
uint64_t table_mask() const { return (1ull << (1ull << m_size)) - 1ull; }
|
||||
|
||||
public:
|
||||
cut(): m_filter(0), m_size(0), m_table(0), m_dont_care(0) {
|
||||
m_elems[0] = m_elems[1] = m_elems[2] = m_elems[3] = m_elems[4] = 0;
|
||||
}
|
||||
|
||||
cut(unsigned id): m_filter(1u << (id & 0x1F)), m_size(1), m_table(2), m_dont_care(0) {
|
||||
m_elems[0] = id;
|
||||
m_elems[1] = m_elems[2] = m_elems[3] = m_elems[4] = 0;
|
||||
}
|
||||
|
||||
cut_val eval(cut_eval const& env) const;
|
||||
|
||||
unsigned size() const { return m_size; }
|
||||
|
||||
unsigned filter() const { return m_filter; }
|
||||
|
||||
static unsigned max_cut_size() { return 5; }
|
||||
|
||||
unsigned const* begin() const { return m_elems; }
|
||||
unsigned const* end() const { return m_elems + m_size; }
|
||||
|
||||
bool add(unsigned i) {
|
||||
if (m_size >= max_cut_size()) {
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
m_elems[m_size++] = i;
|
||||
m_filter |= (1u << (i & 0x1F));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
void negate() { set_table(~m_table); }
|
||||
void set_table(uint64_t t) { m_table = t & table_mask(); }
|
||||
uint64_t table() const { return (m_table | m_dont_care) & table_mask(); }
|
||||
uint64_t ntable() const { return (~m_table | m_dont_care) & table_mask(); }
|
||||
|
||||
uint64_t dont_care() const { return m_dont_care; }
|
||||
void add_dont_care(uint64_t t) const { m_dont_care |= t; }
|
||||
|
||||
bool is_true() const { return 0 == (table_mask() & ~table()); }
|
||||
bool is_false() const { return 0 == (table_mask() & ~m_dont_care & m_table); }
|
||||
|
||||
bool operator==(cut const& other) const;
|
||||
bool operator!=(cut const& other) const { return !(*this == other); }
|
||||
unsigned hash() const;
|
||||
unsigned dom_hash() const;
|
||||
bool dom_eq(cut const& other) const;
|
||||
struct eq_proc {
|
||||
bool operator()(cut const& a, cut const& b) const { return a == b; }
|
||||
bool operator()(cut const* a, cut const* b) const { return *a == *b; }
|
||||
};
|
||||
struct hash_proc {
|
||||
unsigned operator()(cut const& a) const { return a.hash(); }
|
||||
unsigned operator()(cut const* a) const { return a->hash(); }
|
||||
};
|
||||
|
||||
struct dom_eq_proc {
|
||||
bool operator()(cut const& a, cut const& b) const { return a.dom_eq(b); }
|
||||
bool operator()(cut const* a, cut const* b) const { return a->dom_eq(*b); }
|
||||
};
|
||||
|
||||
struct dom_hash_proc {
|
||||
unsigned operator()(cut const& a) const { return a.dom_hash(); }
|
||||
unsigned operator()(cut const* a) const { return a->dom_hash(); }
|
||||
};
|
||||
|
||||
unsigned operator[](unsigned idx) const {
|
||||
return (idx >= m_size) ? UINT_MAX : m_elems[idx];
|
||||
}
|
||||
|
||||
uint64_t shift_table(cut const& other) const;
|
||||
|
||||
bool merge(cut const& a, cut const& b) {
|
||||
unsigned i = 0, j = 0;
|
||||
unsigned x = a[i];
|
||||
unsigned y = b[j];
|
||||
while (x != UINT_MAX || y != UINT_MAX) {
|
||||
if (!add(std::min(x, y))) {
|
||||
return false;
|
||||
}
|
||||
if (x < y) {
|
||||
x = a[++i];
|
||||
}
|
||||
else if (y < x) {
|
||||
y = b[++j];
|
||||
}
|
||||
else {
|
||||
x = a[++i];
|
||||
y = b[++j];
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool subset_of(cut const& other) const {
|
||||
if (other.m_filter != (m_filter | other.m_filter)) {
|
||||
return false;
|
||||
}
|
||||
unsigned i = 0;
|
||||
unsigned other_id = other[i];
|
||||
for (unsigned id : *this) {
|
||||
while (id > other_id) {
|
||||
other_id = other[++i];
|
||||
}
|
||||
if (id != other_id) return false;
|
||||
other_id = other[++i];
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void remove_elem(unsigned i);
|
||||
|
||||
static uint64_t effect_mask(unsigned i);
|
||||
|
||||
std::ostream& display(std::ostream& out) const;
|
||||
|
||||
static std::ostream& display_table(std::ostream& out, unsigned num_input, uint64_t table);
|
||||
|
||||
static std::string table2string(unsigned num_input, uint64_t table);
|
||||
};
|
||||
|
||||
class cut_set {
|
||||
unsigned m_var;
|
||||
region* m_region;
|
||||
unsigned m_size;
|
||||
unsigned m_max_size;
|
||||
cut * m_cuts;
|
||||
public:
|
||||
typedef std::function<void(unsigned v, cut const& c)> on_update_t;
|
||||
|
||||
cut_set(): m_var(UINT_MAX), m_region(nullptr), m_size(0), m_max_size(0), m_cuts(nullptr) {}
|
||||
void init(region& r, unsigned max_sz, unsigned v);
|
||||
bool insert(on_update_t& on_add, on_update_t& on_del, cut const& c);
|
||||
bool no_duplicates() const;
|
||||
unsigned var() const { return m_var; }
|
||||
unsigned size() const { return m_size; }
|
||||
cut const * begin() const { return m_cuts; }
|
||||
cut const * end() const { return m_cuts + m_size; }
|
||||
cut const & back() { return m_cuts[m_size-1]; }
|
||||
void push_back(on_update_t& on_add, cut const& c);
|
||||
void reset(on_update_t& on_del) { shrink(on_del, 0); }
|
||||
cut const & operator[](unsigned idx) const { return m_cuts[idx]; }
|
||||
void shrink(on_update_t& on_del, unsigned j);
|
||||
void swap(cut_set& other) noexcept {
|
||||
std::swap(m_var, other.m_var);
|
||||
std::swap(m_size, other.m_size);
|
||||
std::swap(m_max_size, other.m_max_size);
|
||||
std::swap(m_cuts, other.m_cuts);
|
||||
}
|
||||
void evict(on_update_t& on_del, unsigned idx);
|
||||
void evict(on_update_t& on_del, cut const& c);
|
||||
|
||||
std::ostream& display(std::ostream& out) const;
|
||||
};
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& out, cut const& c) { return c.display(out); }
|
||||
inline std::ostream& operator<<(std::ostream& out, cut_set const& cs) { return cs.display(out); }
|
||||
|
||||
}
|
||||
|
|
@ -1,939 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2020 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
sat_cutset_compute_shift.h
|
||||
|
||||
Author:
|
||||
|
||||
Nikolaj Bjorner 2020-01-02
|
||||
|
||||
Notes:
|
||||
|
||||
shifts truth table x using 'code'.
|
||||
code encodes a mapping from bit-positions of the
|
||||
input truth table encoded with x into bit-positions
|
||||
in the output truth table.
|
||||
The truth table covers up to 6 inputs, which fits in 64 bits.
|
||||
|
||||
--*/
|
||||
#pragma once
|
||||
|
||||
static uint64_t compute_shift(uint64_t x, unsigned code) {
|
||||
switch (code) {
|
||||
#define _x0 (x & 1ull)
|
||||
#define _x1 _x0
|
||||
case 1: return _x1;
|
||||
#define _x2 (_x1 | (_x1 << 1ull))
|
||||
case 2: return _x2;
|
||||
#define _x3 (x & 3ull)
|
||||
#define _x4 _x3
|
||||
case 3: return _x4;
|
||||
#define _x5 (_x2 | (_x2 << 2ull))
|
||||
case 4: return _x5;
|
||||
#define _x6 (_x4 | (_x4 << 2ull))
|
||||
case 5: return _x6;
|
||||
#define _x7 (x & 2ull)
|
||||
#define _x8 (_x7 << 1ull)
|
||||
#define _x9 (_x8 | (_x8 << 1ull))
|
||||
#define _x10 (_x2 | _x9)
|
||||
case 6: return _x10;
|
||||
#define _x11 (x & 15ull)
|
||||
#define _x12 _x11
|
||||
case 7: return _x12;
|
||||
#define _x13 (_x5 | (_x5 << 4ull))
|
||||
case 8: return _x13;
|
||||
#define _x14 (_x6 | (_x6 << 4ull))
|
||||
case 9: return _x14;
|
||||
#define _x15 (_x10 | (_x10 << 4ull))
|
||||
case 10: return _x15;
|
||||
#define _x16 (_x12 | (_x12 << 4ull))
|
||||
case 11: return _x16;
|
||||
#define _x17 (_x7 << 3ull)
|
||||
#define _x18 (_x17 | (_x17 << 1ull))
|
||||
#define _x19 (_x18 | (_x18 << 2ull))
|
||||
#define _x20 (_x5 | _x19)
|
||||
case 12: return _x20;
|
||||
#define _x21 (x & 12ull)
|
||||
#define _x22 (_x21 << 2ull)
|
||||
#define _x23 (_x22 | (_x22 << 2ull))
|
||||
#define _x24 (_x6 | _x23)
|
||||
case 13: return _x24;
|
||||
#define _x25 (x & 4ull)
|
||||
#define _x26 (_x25 << 2ull)
|
||||
#define _x27 (_x26 | (_x26 << 1ull))
|
||||
#define _x28 (x & 8ull)
|
||||
#define _x29 (_x28 << 3ull)
|
||||
#define _x30 (_x29 | (_x29 << 1ull))
|
||||
#define _x31 (_x27 | _x30)
|
||||
#define _x32 (_x10 | _x31)
|
||||
case 14: return _x32;
|
||||
#define _x33 (x & 255ull)
|
||||
#define _x34 _x33
|
||||
case 15: return _x34;
|
||||
#define _x35 (_x13 | (_x13 << 8ull))
|
||||
case 16: return _x35;
|
||||
#define _x36 (_x14 | (_x14 << 8ull))
|
||||
case 17: return _x36;
|
||||
#define _x37 (_x15 | (_x15 << 8ull))
|
||||
case 18: return _x37;
|
||||
#define _x38 (_x16 | (_x16 << 8ull))
|
||||
case 19: return _x38;
|
||||
#define _x39 (_x20 | (_x20 << 8ull))
|
||||
case 20: return _x39;
|
||||
#define _x40 (_x24 | (_x24 << 8ull))
|
||||
case 21: return _x40;
|
||||
#define _x41 (_x32 | (_x32 << 8ull))
|
||||
case 22: return _x41;
|
||||
#define _x42 (_x34 | (_x34 << 8ull))
|
||||
case 23: return _x42;
|
||||
#define _x43 (_x7 << 7ull)
|
||||
#define _x44 (_x43 | (_x43 << 1ull))
|
||||
#define _x45 (_x44 | (_x44 << 2ull))
|
||||
#define _x46 (_x45 | (_x45 << 4ull))
|
||||
#define _x47 (_x13 | _x46)
|
||||
case 24: return _x47;
|
||||
#define _x48 (_x21 << 6ull)
|
||||
#define _x49 (_x48 | (_x48 << 2ull))
|
||||
#define _x50 (_x49 | (_x49 << 4ull))
|
||||
#define _x51 (_x14 | _x50)
|
||||
case 25: return _x51;
|
||||
#define _x52 (_x25 << 6ull)
|
||||
#define _x53 (_x52 | (_x52 << 1ull))
|
||||
#define _x54 (_x28 << 7ull)
|
||||
#define _x55 (_x54 | (_x54 << 1ull))
|
||||
#define _x56 (_x53 | _x55)
|
||||
#define _x57 (_x56 | (_x56 << 4ull))
|
||||
#define _x58 (_x15 | _x57)
|
||||
case 26: return _x58;
|
||||
#define _x59 (x & 240ull)
|
||||
#define _x60 (_x59 << 4ull)
|
||||
#define _x61 (_x60 | (_x60 << 4ull))
|
||||
#define _x62 (_x16 | _x61)
|
||||
case 27: return _x62;
|
||||
#define _x63 (_x53 | (_x53 << 2ull))
|
||||
#define _x64 (_x28 << 9ull)
|
||||
#define _x65 (_x64 | (_x64 << 1ull))
|
||||
#define _x66 (_x65 | (_x65 << 2ull))
|
||||
#define _x67 (_x63 | _x66)
|
||||
#define _x68 (_x20 | _x67)
|
||||
case 28: return _x68;
|
||||
#define _x69 (x & 48ull)
|
||||
#define _x70 (_x69 << 4ull)
|
||||
#define _x71 (_x70 | (_x70 << 2ull))
|
||||
#define _x72 (x & 192ull)
|
||||
#define _x73 (_x72 << 6ull)
|
||||
#define _x74 (_x73 | (_x73 << 2ull))
|
||||
#define _x75 (_x71 | _x74)
|
||||
#define _x76 (_x24 | _x75)
|
||||
case 29: return _x76;
|
||||
#define _x77 (x & 16ull)
|
||||
#define _x78 (_x77 << 4ull)
|
||||
#define _x79 (_x78 | (_x78 << 1ull))
|
||||
#define _x80 (x & 32ull)
|
||||
#define _x81 (_x80 << 5ull)
|
||||
#define _x82 (_x81 | (_x81 << 1ull))
|
||||
#define _x83 (_x79 | _x82)
|
||||
#define _x84 (x & 64ull)
|
||||
#define _x85 (_x84 << 6ull)
|
||||
#define _x86 (_x85 | (_x85 << 1ull))
|
||||
#define _x87 (x & 128ull)
|
||||
#define _x88 (_x87 << 7ull)
|
||||
#define _x89 (_x88 | (_x88 << 1ull))
|
||||
#define _x90 (_x86 | _x89)
|
||||
#define _x91 (_x83 | _x90)
|
||||
#define _x92 (_x32 | _x91)
|
||||
case 30: return _x92;
|
||||
#define _x93 (x & 65535ull)
|
||||
#define _x94 _x93
|
||||
case 31: return _x94;
|
||||
#define _x95 (_x35 | (_x35 << 16ull))
|
||||
case 32: return _x95;
|
||||
#define _x96 (_x36 | (_x36 << 16ull))
|
||||
case 33: return _x96;
|
||||
#define _x97 (_x37 | (_x37 << 16ull))
|
||||
case 34: return _x97;
|
||||
#define _x98 (_x38 | (_x38 << 16ull))
|
||||
case 35: return _x98;
|
||||
#define _x99 (_x39 | (_x39 << 16ull))
|
||||
case 36: return _x99;
|
||||
#define _x100 (_x40 | (_x40 << 16ull))
|
||||
case 37: return _x100;
|
||||
#define _x101 (_x41 | (_x41 << 16ull))
|
||||
case 38: return _x101;
|
||||
#define _x102 (_x42 | (_x42 << 16ull))
|
||||
case 39: return _x102;
|
||||
#define _x103 (_x47 | (_x47 << 16ull))
|
||||
case 40: return _x103;
|
||||
#define _x104 (_x51 | (_x51 << 16ull))
|
||||
case 41: return _x104;
|
||||
#define _x105 (_x58 | (_x58 << 16ull))
|
||||
case 42: return _x105;
|
||||
#define _x106 (_x62 | (_x62 << 16ull))
|
||||
case 43: return _x106;
|
||||
#define _x107 (_x68 | (_x68 << 16ull))
|
||||
case 44: return _x107;
|
||||
#define _x108 (_x76 | (_x76 << 16ull))
|
||||
case 45: return _x108;
|
||||
#define _x109 (_x92 | (_x92 << 16ull))
|
||||
case 46: return _x109;
|
||||
#define _x110 (_x94 | (_x94 << 16ull))
|
||||
case 47: return _x110;
|
||||
#define _x111 (_x7 << 15ull)
|
||||
#define _x112 (_x111 | (_x111 << 1ull))
|
||||
#define _x113 (_x112 | (_x112 << 2ull))
|
||||
#define _x114 (_x113 | (_x113 << 4ull))
|
||||
#define _x115 (_x114 | (_x114 << 8ull))
|
||||
#define _x116 (_x35 | _x115)
|
||||
case 48: return _x116;
|
||||
#define _x117 (_x21 << 14ull)
|
||||
#define _x118 (_x117 | (_x117 << 2ull))
|
||||
#define _x119 (_x118 | (_x118 << 4ull))
|
||||
#define _x120 (_x119 | (_x119 << 8ull))
|
||||
#define _x121 (_x36 | _x120)
|
||||
case 49: return _x121;
|
||||
#define _x122 (_x25 << 14ull)
|
||||
#define _x123 (_x122 | (_x122 << 1ull))
|
||||
#define _x124 (_x28 << 15ull)
|
||||
#define _x125 (_x124 | (_x124 << 1ull))
|
||||
#define _x126 (_x123 | _x125)
|
||||
#define _x127 (_x126 | (_x126 << 4ull))
|
||||
#define _x128 (_x127 | (_x127 << 8ull))
|
||||
#define _x129 (_x37 | _x128)
|
||||
case 50: return _x129;
|
||||
#define _x130 (_x59 << 12ull)
|
||||
#define _x131 (_x130 | (_x130 << 4ull))
|
||||
#define _x132 (_x131 | (_x131 << 8ull))
|
||||
#define _x133 (_x38 | _x132)
|
||||
case 51: return _x133;
|
||||
#define _x134 (_x123 | (_x123 << 2ull))
|
||||
#define _x135 (_x28 << 17ull)
|
||||
#define _x136 (_x135 | (_x135 << 1ull))
|
||||
#define _x137 (_x136 | (_x136 << 2ull))
|
||||
#define _x138 (_x134 | _x137)
|
||||
#define _x139 (_x138 | (_x138 << 8ull))
|
||||
#define _x140 (_x39 | _x139)
|
||||
case 52: return _x140;
|
||||
#define _x141 (_x69 << 12ull)
|
||||
#define _x142 (_x141 | (_x141 << 2ull))
|
||||
#define _x143 (_x72 << 14ull)
|
||||
#define _x144 (_x143 | (_x143 << 2ull))
|
||||
#define _x145 (_x142 | _x144)
|
||||
#define _x146 (_x145 | (_x145 << 8ull))
|
||||
#define _x147 (_x40 | _x146)
|
||||
case 53: return _x147;
|
||||
#define _x148 (_x77 << 12ull)
|
||||
#define _x149 (_x148 | (_x148 << 1ull))
|
||||
#define _x150 (_x80 << 13ull)
|
||||
#define _x151 (_x150 | (_x150 << 1ull))
|
||||
#define _x152 (_x149 | _x151)
|
||||
#define _x153 (_x84 << 14ull)
|
||||
#define _x154 (_x153 | (_x153 << 1ull))
|
||||
#define _x155 (_x87 << 15ull)
|
||||
#define _x156 (_x155 | (_x155 << 1ull))
|
||||
#define _x157 (_x154 | _x156)
|
||||
#define _x158 (_x152 | _x157)
|
||||
#define _x159 (_x158 | (_x158 << 8ull))
|
||||
#define _x160 (_x41 | _x159)
|
||||
case 54: return _x160;
|
||||
#define _x161 (x & 65280ull)
|
||||
#define _x162 (_x161 << 8ull)
|
||||
#define _x163 (_x162 | (_x162 << 8ull))
|
||||
#define _x164 (_x42 | _x163)
|
||||
case 55: return _x164;
|
||||
#define _x165 (_x134 | (_x134 << 4ull))
|
||||
#define _x166 (_x28 << 21ull)
|
||||
#define _x167 (_x166 | (_x166 << 1ull))
|
||||
#define _x168 (_x167 | (_x167 << 2ull))
|
||||
#define _x169 (_x168 | (_x168 << 4ull))
|
||||
#define _x170 (_x165 | _x169)
|
||||
#define _x171 (_x47 | _x170)
|
||||
case 56: return _x171;
|
||||
#define _x172 (_x142 | (_x142 << 4ull))
|
||||
#define _x173 (_x72 << 18ull)
|
||||
#define _x174 (_x173 | (_x173 << 2ull))
|
||||
#define _x175 (_x174 | (_x174 << 4ull))
|
||||
#define _x176 (_x172 | _x175)
|
||||
#define _x177 (_x51 | _x176)
|
||||
case 57: return _x177;
|
||||
#define _x178 (_x152 | (_x152 << 4ull))
|
||||
#define _x179 (_x84 << 18ull)
|
||||
#define _x180 (_x179 | (_x179 << 1ull))
|
||||
#define _x181 (_x87 << 19ull)
|
||||
#define _x182 (_x181 | (_x181 << 1ull))
|
||||
#define _x183 (_x180 | _x182)
|
||||
#define _x184 (_x183 | (_x183 << 4ull))
|
||||
#define _x185 (_x178 | _x184)
|
||||
#define _x186 (_x58 | _x185)
|
||||
case 58: return _x186;
|
||||
#define _x187 (x & 3840ull)
|
||||
#define _x188 (_x187 << 8ull)
|
||||
#define _x189 (_x188 | (_x188 << 4ull))
|
||||
#define _x190 (x & 61440ull)
|
||||
#define _x191 (_x190 << 12ull)
|
||||
#define _x192 (_x191 | (_x191 << 4ull))
|
||||
#define _x193 (_x189 | _x192)
|
||||
#define _x194 (_x62 | _x193)
|
||||
case 59: return _x194;
|
||||
#define _x195 (_x149 | (_x149 << 2ull))
|
||||
#define _x196 (_x80 << 15ull)
|
||||
#define _x197 (_x196 | (_x196 << 1ull))
|
||||
#define _x198 (_x197 | (_x197 << 2ull))
|
||||
#define _x199 (_x195 | _x198)
|
||||
#define _x200 (_x180 | (_x180 << 2ull))
|
||||
#define _x201 (_x87 << 21ull)
|
||||
#define _x202 (_x201 | (_x201 << 1ull))
|
||||
#define _x203 (_x202 | (_x202 << 2ull))
|
||||
#define _x204 (_x200 | _x203)
|
||||
#define _x205 (_x199 | _x204)
|
||||
#define _x206 (_x68 | _x205)
|
||||
case 60: return _x206;
|
||||
#define _x207 (x & 768ull)
|
||||
#define _x208 (_x207 << 8ull)
|
||||
#define _x209 (_x208 | (_x208 << 2ull))
|
||||
#define _x210 (x & 3072ull)
|
||||
#define _x211 (_x210 << 10ull)
|
||||
#define _x212 (_x211 | (_x211 << 2ull))
|
||||
#define _x213 (_x209 | _x212)
|
||||
#define _x214 (x & 12288ull)
|
||||
#define _x215 (_x214 << 12ull)
|
||||
#define _x216 (_x215 | (_x215 << 2ull))
|
||||
#define _x217 (x & 49152ull)
|
||||
#define _x218 (_x217 << 14ull)
|
||||
#define _x219 (_x218 | (_x218 << 2ull))
|
||||
#define _x220 (_x216 | _x219)
|
||||
#define _x221 (_x213 | _x220)
|
||||
#define _x222 (_x76 | _x221)
|
||||
case 61: return _x222;
|
||||
#define _x223 (x & 256ull)
|
||||
#define _x224 (_x223 << 8ull)
|
||||
#define _x225 (_x224 | (_x224 << 1ull))
|
||||
#define _x226 (x & 512ull)
|
||||
#define _x227 (_x226 << 9ull)
|
||||
#define _x228 (_x227 | (_x227 << 1ull))
|
||||
#define _x229 (_x225 | _x228)
|
||||
#define _x230 (x & 1024ull)
|
||||
#define _x231 (_x230 << 10ull)
|
||||
#define _x232 (_x231 | (_x231 << 1ull))
|
||||
#define _x233 (x & 2048ull)
|
||||
#define _x234 (_x233 << 11ull)
|
||||
#define _x235 (_x234 | (_x234 << 1ull))
|
||||
#define _x236 (_x232 | _x235)
|
||||
#define _x237 (_x229 | _x236)
|
||||
#define _x238 (x & 4096ull)
|
||||
#define _x239 (_x238 << 12ull)
|
||||
#define _x240 (_x239 | (_x239 << 1ull))
|
||||
#define _x241 (x & 8192ull)
|
||||
#define _x242 (_x241 << 13ull)
|
||||
#define _x243 (_x242 | (_x242 << 1ull))
|
||||
#define _x244 (_x240 | _x243)
|
||||
#define _x245 (x & 16384ull)
|
||||
#define _x246 (_x245 << 14ull)
|
||||
#define _x247 (_x246 | (_x246 << 1ull))
|
||||
#define _x248 (x & 32768ull)
|
||||
#define _x249 (_x248 << 15ull)
|
||||
#define _x250 (_x249 | (_x249 << 1ull))
|
||||
#define _x251 (_x247 | _x250)
|
||||
#define _x252 (_x244 | _x251)
|
||||
#define _x253 (_x237 | _x252)
|
||||
#define _x254 (_x92 | _x253)
|
||||
case 62: return _x254;
|
||||
#define _x255 (x & 4294967295ull)
|
||||
#define _x256 _x255
|
||||
case 63: return _x256;
|
||||
#define _x257 (_x95 | (_x95 << 32ull))
|
||||
case 64: return _x257;
|
||||
#define _x258 (_x96 | (_x96 << 32ull))
|
||||
case 65: return _x258;
|
||||
#define _x259 (_x97 | (_x97 << 32ull))
|
||||
case 66: return _x259;
|
||||
#define _x260 (_x98 | (_x98 << 32ull))
|
||||
case 67: return _x260;
|
||||
#define _x261 (_x99 | (_x99 << 32ull))
|
||||
case 68: return _x261;
|
||||
#define _x262 (_x100 | (_x100 << 32ull))
|
||||
case 69: return _x262;
|
||||
#define _x263 (_x101 | (_x101 << 32ull))
|
||||
case 70: return _x263;
|
||||
#define _x264 (_x102 | (_x102 << 32ull))
|
||||
case 71: return _x264;
|
||||
#define _x265 (_x103 | (_x103 << 32ull))
|
||||
case 72: return _x265;
|
||||
#define _x266 (_x104 | (_x104 << 32ull))
|
||||
case 73: return _x266;
|
||||
#define _x267 (_x105 | (_x105 << 32ull))
|
||||
case 74: return _x267;
|
||||
#define _x268 (_x106 | (_x106 << 32ull))
|
||||
case 75: return _x268;
|
||||
#define _x269 (_x107 | (_x107 << 32ull))
|
||||
case 76: return _x269;
|
||||
#define _x270 (_x108 | (_x108 << 32ull))
|
||||
case 77: return _x270;
|
||||
#define _x271 (_x109 | (_x109 << 32ull))
|
||||
case 78: return _x271;
|
||||
#define _x272 (_x110 | (_x110 << 32ull))
|
||||
case 79: return _x272;
|
||||
#define _x273 (_x116 | (_x116 << 32ull))
|
||||
case 80: return _x273;
|
||||
#define _x274 (_x121 | (_x121 << 32ull))
|
||||
case 81: return _x274;
|
||||
#define _x275 (_x129 | (_x129 << 32ull))
|
||||
case 82: return _x275;
|
||||
#define _x276 (_x133 | (_x133 << 32ull))
|
||||
case 83: return _x276;
|
||||
#define _x277 (_x140 | (_x140 << 32ull))
|
||||
case 84: return _x277;
|
||||
#define _x278 (_x147 | (_x147 << 32ull))
|
||||
case 85: return _x278;
|
||||
#define _x279 (_x160 | (_x160 << 32ull))
|
||||
case 86: return _x279;
|
||||
#define _x280 (_x164 | (_x164 << 32ull))
|
||||
case 87: return _x280;
|
||||
#define _x281 (_x171 | (_x171 << 32ull))
|
||||
case 88: return _x281;
|
||||
#define _x282 (_x177 | (_x177 << 32ull))
|
||||
case 89: return _x282;
|
||||
#define _x283 (_x186 | (_x186 << 32ull))
|
||||
case 90: return _x283;
|
||||
#define _x284 (_x194 | (_x194 << 32ull))
|
||||
case 91: return _x284;
|
||||
#define _x285 (_x206 | (_x206 << 32ull))
|
||||
case 92: return _x285;
|
||||
#define _x286 (_x222 | (_x222 << 32ull))
|
||||
case 93: return _x286;
|
||||
#define _x287 (_x254 | (_x254 << 32ull))
|
||||
case 94: return _x287;
|
||||
#define _x288 (_x256 | (_x256 << 32ull))
|
||||
case 95: return _x288;
|
||||
#define _x289 (_x7 << 31ull)
|
||||
#define _x290 (_x289 | (_x289 << 1ull))
|
||||
#define _x291 (_x290 | (_x290 << 2ull))
|
||||
#define _x292 (_x291 | (_x291 << 4ull))
|
||||
#define _x293 (_x292 | (_x292 << 8ull))
|
||||
#define _x294 (_x293 | (_x293 << 16ull))
|
||||
#define _x295 (_x95 | _x294)
|
||||
case 96: return _x295;
|
||||
#define _x296 (_x21 << 30ull)
|
||||
#define _x297 (_x296 | (_x296 << 2ull))
|
||||
#define _x298 (_x297 | (_x297 << 4ull))
|
||||
#define _x299 (_x298 | (_x298 << 8ull))
|
||||
#define _x300 (_x299 | (_x299 << 16ull))
|
||||
#define _x301 (_x96 | _x300)
|
||||
case 97: return _x301;
|
||||
#define _x302 (_x25 << 30ull)
|
||||
#define _x303 (_x302 | (_x302 << 1ull))
|
||||
#define _x304 (_x28 << 31ull)
|
||||
#define _x305 (_x304 | (_x304 << 1ull))
|
||||
#define _x306 (_x303 | _x305)
|
||||
#define _x307 (_x306 | (_x306 << 4ull))
|
||||
#define _x308 (_x307 | (_x307 << 8ull))
|
||||
#define _x309 (_x308 | (_x308 << 16ull))
|
||||
#define _x310 (_x97 | _x309)
|
||||
case 98: return _x310;
|
||||
#define _x311 (_x59 << 28ull)
|
||||
#define _x312 (_x311 | (_x311 << 4ull))
|
||||
#define _x313 (_x312 | (_x312 << 8ull))
|
||||
#define _x314 (_x313 | (_x313 << 16ull))
|
||||
#define _x315 (_x98 | _x314)
|
||||
case 99: return _x315;
|
||||
#define _x316 (_x303 | (_x303 << 2ull))
|
||||
#define _x317 (_x28 << 33ull)
|
||||
#define _x318 (_x317 | (_x317 << 1ull))
|
||||
#define _x319 (_x318 | (_x318 << 2ull))
|
||||
#define _x320 (_x316 | _x319)
|
||||
#define _x321 (_x320 | (_x320 << 8ull))
|
||||
#define _x322 (_x321 | (_x321 << 16ull))
|
||||
#define _x323 (_x99 | _x322)
|
||||
case 100: return _x323;
|
||||
#define _x324 (_x69 << 28ull)
|
||||
#define _x325 (_x324 | (_x324 << 2ull))
|
||||
#define _x326 (_x72 << 30ull)
|
||||
#define _x327 (_x326 | (_x326 << 2ull))
|
||||
#define _x328 (_x325 | _x327)
|
||||
#define _x329 (_x328 | (_x328 << 8ull))
|
||||
#define _x330 (_x329 | (_x329 << 16ull))
|
||||
#define _x331 (_x100 | _x330)
|
||||
case 101: return _x331;
|
||||
#define _x332 (_x77 << 28ull)
|
||||
#define _x333 (_x332 | (_x332 << 1ull))
|
||||
#define _x334 (_x80 << 29ull)
|
||||
#define _x335 (_x334 | (_x334 << 1ull))
|
||||
#define _x336 (_x333 | _x335)
|
||||
#define _x337 (_x84 << 30ull)
|
||||
#define _x338 (_x337 | (_x337 << 1ull))
|
||||
#define _x339 (_x87 << 31ull)
|
||||
#define _x340 (_x339 | (_x339 << 1ull))
|
||||
#define _x341 (_x338 | _x340)
|
||||
#define _x342 (_x336 | _x341)
|
||||
#define _x343 (_x342 | (_x342 << 8ull))
|
||||
#define _x344 (_x343 | (_x343 << 16ull))
|
||||
#define _x345 (_x101 | _x344)
|
||||
case 102: return _x345;
|
||||
#define _x346 (_x161 << 24ull)
|
||||
#define _x347 (_x346 | (_x346 << 8ull))
|
||||
#define _x348 (_x347 | (_x347 << 16ull))
|
||||
#define _x349 (_x102 | _x348)
|
||||
case 103: return _x349;
|
||||
#define _x350 (_x316 | (_x316 << 4ull))
|
||||
#define _x351 (_x28 << 37ull)
|
||||
#define _x352 (_x351 | (_x351 << 1ull))
|
||||
#define _x353 (_x352 | (_x352 << 2ull))
|
||||
#define _x354 (_x353 | (_x353 << 4ull))
|
||||
#define _x355 (_x350 | _x354)
|
||||
#define _x356 (_x355 | (_x355 << 16ull))
|
||||
#define _x357 (_x103 | _x356)
|
||||
case 104: return _x357;
|
||||
#define _x358 (_x325 | (_x325 << 4ull))
|
||||
#define _x359 (_x72 << 34ull)
|
||||
#define _x360 (_x359 | (_x359 << 2ull))
|
||||
#define _x361 (_x360 | (_x360 << 4ull))
|
||||
#define _x362 (_x358 | _x361)
|
||||
#define _x363 (_x362 | (_x362 << 16ull))
|
||||
#define _x364 (_x104 | _x363)
|
||||
case 105: return _x364;
|
||||
#define _x365 (_x336 | (_x336 << 4ull))
|
||||
#define _x366 (_x84 << 34ull)
|
||||
#define _x367 (_x366 | (_x366 << 1ull))
|
||||
#define _x368 (_x87 << 35ull)
|
||||
#define _x369 (_x368 | (_x368 << 1ull))
|
||||
#define _x370 (_x367 | _x369)
|
||||
#define _x371 (_x370 | (_x370 << 4ull))
|
||||
#define _x372 (_x365 | _x371)
|
||||
#define _x373 (_x372 | (_x372 << 16ull))
|
||||
#define _x374 (_x105 | _x373)
|
||||
case 106: return _x374;
|
||||
#define _x375 (_x187 << 24ull)
|
||||
#define _x376 (_x375 | (_x375 << 4ull))
|
||||
#define _x377 (_x190 << 28ull)
|
||||
#define _x378 (_x377 | (_x377 << 4ull))
|
||||
#define _x379 (_x376 | _x378)
|
||||
#define _x380 (_x379 | (_x379 << 16ull))
|
||||
#define _x381 (_x106 | _x380)
|
||||
case 107: return _x381;
|
||||
#define _x382 (_x333 | (_x333 << 2ull))
|
||||
#define _x383 (_x80 << 31ull)
|
||||
#define _x384 (_x383 | (_x383 << 1ull))
|
||||
#define _x385 (_x384 | (_x384 << 2ull))
|
||||
#define _x386 (_x382 | _x385)
|
||||
#define _x387 (_x367 | (_x367 << 2ull))
|
||||
#define _x388 (_x87 << 37ull)
|
||||
#define _x389 (_x388 | (_x388 << 1ull))
|
||||
#define _x390 (_x389 | (_x389 << 2ull))
|
||||
#define _x391 (_x387 | _x390)
|
||||
#define _x392 (_x386 | _x391)
|
||||
#define _x393 (_x392 | (_x392 << 16ull))
|
||||
#define _x394 (_x107 | _x393)
|
||||
case 108: return _x394;
|
||||
#define _x395 (_x207 << 24ull)
|
||||
#define _x396 (_x395 | (_x395 << 2ull))
|
||||
#define _x397 (_x210 << 26ull)
|
||||
#define _x398 (_x397 | (_x397 << 2ull))
|
||||
#define _x399 (_x396 | _x398)
|
||||
#define _x400 (_x214 << 28ull)
|
||||
#define _x401 (_x400 | (_x400 << 2ull))
|
||||
#define _x402 (_x217 << 30ull)
|
||||
#define _x403 (_x402 | (_x402 << 2ull))
|
||||
#define _x404 (_x401 | _x403)
|
||||
#define _x405 (_x399 | _x404)
|
||||
#define _x406 (_x405 | (_x405 << 16ull))
|
||||
#define _x407 (_x108 | _x406)
|
||||
case 109: return _x407;
|
||||
#define _x408 (_x223 << 24ull)
|
||||
#define _x409 (_x408 | (_x408 << 1ull))
|
||||
#define _x410 (_x226 << 25ull)
|
||||
#define _x411 (_x410 | (_x410 << 1ull))
|
||||
#define _x412 (_x409 | _x411)
|
||||
#define _x413 (_x230 << 26ull)
|
||||
#define _x414 (_x413 | (_x413 << 1ull))
|
||||
#define _x415 (_x233 << 27ull)
|
||||
#define _x416 (_x415 | (_x415 << 1ull))
|
||||
#define _x417 (_x414 | _x416)
|
||||
#define _x418 (_x412 | _x417)
|
||||
#define _x419 (_x238 << 28ull)
|
||||
#define _x420 (_x419 | (_x419 << 1ull))
|
||||
#define _x421 (_x241 << 29ull)
|
||||
#define _x422 (_x421 | (_x421 << 1ull))
|
||||
#define _x423 (_x420 | _x422)
|
||||
#define _x424 (_x245 << 30ull)
|
||||
#define _x425 (_x424 | (_x424 << 1ull))
|
||||
#define _x426 (_x248 << 31ull)
|
||||
#define _x427 (_x426 | (_x426 << 1ull))
|
||||
#define _x428 (_x425 | _x427)
|
||||
#define _x429 (_x423 | _x428)
|
||||
#define _x430 (_x418 | _x429)
|
||||
#define _x431 (_x430 | (_x430 << 16ull))
|
||||
#define _x432 (_x109 | _x431)
|
||||
case 110: return _x432;
|
||||
#define _x433 (x & 4294901760ull)
|
||||
#define _x434 (_x433 << 16ull)
|
||||
#define _x435 (_x434 | (_x434 << 16ull))
|
||||
#define _x436 (_x110 | _x435)
|
||||
case 111: return _x436;
|
||||
#define _x437 (_x350 | (_x350 << 8ull))
|
||||
#define _x438 (_x28 << 45ull)
|
||||
#define _x439 (_x438 | (_x438 << 1ull))
|
||||
#define _x440 (_x439 | (_x439 << 2ull))
|
||||
#define _x441 (_x440 | (_x440 << 4ull))
|
||||
#define _x442 (_x441 | (_x441 << 8ull))
|
||||
#define _x443 (_x437 | _x442)
|
||||
#define _x444 (_x116 | _x443)
|
||||
case 112: return _x444;
|
||||
#define _x445 (_x358 | (_x358 << 8ull))
|
||||
#define _x446 (_x72 << 42ull)
|
||||
#define _x447 (_x446 | (_x446 << 2ull))
|
||||
#define _x448 (_x447 | (_x447 << 4ull))
|
||||
#define _x449 (_x448 | (_x448 << 8ull))
|
||||
#define _x450 (_x445 | _x449)
|
||||
#define _x451 (_x121 | _x450)
|
||||
case 113: return _x451;
|
||||
#define _x452 (_x365 | (_x365 << 8ull))
|
||||
#define _x453 (_x84 << 42ull)
|
||||
#define _x454 (_x453 | (_x453 << 1ull))
|
||||
#define _x455 (_x87 << 43ull)
|
||||
#define _x456 (_x455 | (_x455 << 1ull))
|
||||
#define _x457 (_x454 | _x456)
|
||||
#define _x458 (_x457 | (_x457 << 4ull))
|
||||
#define _x459 (_x458 | (_x458 << 8ull))
|
||||
#define _x460 (_x452 | _x459)
|
||||
#define _x461 (_x129 | _x460)
|
||||
case 114: return _x461;
|
||||
#define _x462 (_x376 | (_x376 << 8ull))
|
||||
#define _x463 (_x190 << 36ull)
|
||||
#define _x464 (_x463 | (_x463 << 4ull))
|
||||
#define _x465 (_x464 | (_x464 << 8ull))
|
||||
#define _x466 (_x462 | _x465)
|
||||
#define _x467 (_x133 | _x466)
|
||||
case 115: return _x467;
|
||||
#define _x468 (_x386 | (_x386 << 8ull))
|
||||
#define _x469 (_x454 | (_x454 << 2ull))
|
||||
#define _x470 (_x87 << 45ull)
|
||||
#define _x471 (_x470 | (_x470 << 1ull))
|
||||
#define _x472 (_x471 | (_x471 << 2ull))
|
||||
#define _x473 (_x469 | _x472)
|
||||
#define _x474 (_x473 | (_x473 << 8ull))
|
||||
#define _x475 (_x468 | _x474)
|
||||
#define _x476 (_x140 | _x475)
|
||||
case 116: return _x476;
|
||||
#define _x477 (_x399 | (_x399 << 8ull))
|
||||
#define _x478 (_x214 << 36ull)
|
||||
#define _x479 (_x478 | (_x478 << 2ull))
|
||||
#define _x480 (_x217 << 38ull)
|
||||
#define _x481 (_x480 | (_x480 << 2ull))
|
||||
#define _x482 (_x479 | _x481)
|
||||
#define _x483 (_x482 | (_x482 << 8ull))
|
||||
#define _x484 (_x477 | _x483)
|
||||
#define _x485 (_x147 | _x484)
|
||||
case 117: return _x485;
|
||||
#define _x486 (_x418 | (_x418 << 8ull))
|
||||
#define _x487 (_x238 << 36ull)
|
||||
#define _x488 (_x487 | (_x487 << 1ull))
|
||||
#define _x489 (_x241 << 37ull)
|
||||
#define _x490 (_x489 | (_x489 << 1ull))
|
||||
#define _x491 (_x488 | _x490)
|
||||
#define _x492 (_x245 << 38ull)
|
||||
#define _x493 (_x492 | (_x492 << 1ull))
|
||||
#define _x494 (_x248 << 39ull)
|
||||
#define _x495 (_x494 | (_x494 << 1ull))
|
||||
#define _x496 (_x493 | _x495)
|
||||
#define _x497 (_x491 | _x496)
|
||||
#define _x498 (_x497 | (_x497 << 8ull))
|
||||
#define _x499 (_x486 | _x498)
|
||||
#define _x500 (_x160 | _x499)
|
||||
case 118: return _x500;
|
||||
#define _x501 (x & 16711680ull)
|
||||
#define _x502 (_x501 << 16ull)
|
||||
#define _x503 (_x502 | (_x502 << 8ull))
|
||||
#define _x504 (x & 4278190080ull)
|
||||
#define _x505 (_x504 << 24ull)
|
||||
#define _x506 (_x505 | (_x505 << 8ull))
|
||||
#define _x507 (_x503 | _x506)
|
||||
#define _x508 (_x164 | _x507)
|
||||
case 119: return _x508;
|
||||
#define _x509 (_x382 | (_x382 << 4ull))
|
||||
#define _x510 (_x80 << 35ull)
|
||||
#define _x511 (_x510 | (_x510 << 1ull))
|
||||
#define _x512 (_x511 | (_x511 << 2ull))
|
||||
#define _x513 (_x512 | (_x512 << 4ull))
|
||||
#define _x514 (_x509 | _x513)
|
||||
#define _x515 (_x469 | (_x469 << 4ull))
|
||||
#define _x516 (_x87 << 49ull)
|
||||
#define _x517 (_x516 | (_x516 << 1ull))
|
||||
#define _x518 (_x517 | (_x517 << 2ull))
|
||||
#define _x519 (_x518 | (_x518 << 4ull))
|
||||
#define _x520 (_x515 | _x519)
|
||||
#define _x521 (_x514 | _x520)
|
||||
#define _x522 (_x171 | _x521)
|
||||
case 120: return _x522;
|
||||
#define _x523 (_x396 | (_x396 << 4ull))
|
||||
#define _x524 (_x210 << 30ull)
|
||||
#define _x525 (_x524 | (_x524 << 2ull))
|
||||
#define _x526 (_x525 | (_x525 << 4ull))
|
||||
#define _x527 (_x523 | _x526)
|
||||
#define _x528 (_x479 | (_x479 << 4ull))
|
||||
#define _x529 (_x217 << 42ull)
|
||||
#define _x530 (_x529 | (_x529 << 2ull))
|
||||
#define _x531 (_x530 | (_x530 << 4ull))
|
||||
#define _x532 (_x528 | _x531)
|
||||
#define _x533 (_x527 | _x532)
|
||||
#define _x534 (_x177 | _x533)
|
||||
case 121: return _x534;
|
||||
#define _x535 (_x412 | (_x412 << 4ull))
|
||||
#define _x536 (_x230 << 30ull)
|
||||
#define _x537 (_x536 | (_x536 << 1ull))
|
||||
#define _x538 (_x233 << 31ull)
|
||||
#define _x539 (_x538 | (_x538 << 1ull))
|
||||
#define _x540 (_x537 | _x539)
|
||||
#define _x541 (_x540 | (_x540 << 4ull))
|
||||
#define _x542 (_x535 | _x541)
|
||||
#define _x543 (_x491 | (_x491 << 4ull))
|
||||
#define _x544 (_x245 << 42ull)
|
||||
#define _x545 (_x544 | (_x544 << 1ull))
|
||||
#define _x546 (_x248 << 43ull)
|
||||
#define _x547 (_x546 | (_x546 << 1ull))
|
||||
#define _x548 (_x545 | _x547)
|
||||
#define _x549 (_x548 | (_x548 << 4ull))
|
||||
#define _x550 (_x543 | _x549)
|
||||
#define _x551 (_x542 | _x550)
|
||||
#define _x552 (_x186 | _x551)
|
||||
case 122: return _x552;
|
||||
#define _x553 (x & 983040ull)
|
||||
#define _x554 (_x553 << 16ull)
|
||||
#define _x555 (_x554 | (_x554 << 4ull))
|
||||
#define _x556 (x & 15728640ull)
|
||||
#define _x557 (_x556 << 20ull)
|
||||
#define _x558 (_x557 | (_x557 << 4ull))
|
||||
#define _x559 (_x555 | _x558)
|
||||
#define _x560 (x & 251658240ull)
|
||||
#define _x561 (_x560 << 24ull)
|
||||
#define _x562 (_x561 | (_x561 << 4ull))
|
||||
#define _x563 (x & 4026531840ull)
|
||||
#define _x564 (_x563 << 28ull)
|
||||
#define _x565 (_x564 | (_x564 << 4ull))
|
||||
#define _x566 (_x562 | _x565)
|
||||
#define _x567 (_x559 | _x566)
|
||||
#define _x568 (_x194 | _x567)
|
||||
case 123: return _x568;
|
||||
#define _x569 (_x409 | (_x409 << 2ull))
|
||||
#define _x570 (_x226 << 27ull)
|
||||
#define _x571 (_x570 | (_x570 << 1ull))
|
||||
#define _x572 (_x571 | (_x571 << 2ull))
|
||||
#define _x573 (_x569 | _x572)
|
||||
#define _x574 (_x537 | (_x537 << 2ull))
|
||||
#define _x575 (_x233 << 33ull)
|
||||
#define _x576 (_x575 | (_x575 << 1ull))
|
||||
#define _x577 (_x576 | (_x576 << 2ull))
|
||||
#define _x578 (_x574 | _x577)
|
||||
#define _x579 (_x573 | _x578)
|
||||
#define _x580 (_x488 | (_x488 << 2ull))
|
||||
#define _x581 (_x241 << 39ull)
|
||||
#define _x582 (_x581 | (_x581 << 1ull))
|
||||
#define _x583 (_x582 | (_x582 << 2ull))
|
||||
#define _x584 (_x580 | _x583)
|
||||
#define _x585 (_x545 | (_x545 << 2ull))
|
||||
#define _x586 (_x248 << 45ull)
|
||||
#define _x587 (_x586 | (_x586 << 1ull))
|
||||
#define _x588 (_x587 | (_x587 << 2ull))
|
||||
#define _x589 (_x585 | _x588)
|
||||
#define _x590 (_x584 | _x589)
|
||||
#define _x591 (_x579 | _x590)
|
||||
#define _x592 (_x206 | _x591)
|
||||
case 124: return _x592;
|
||||
#define _x593 (x & 196608ull)
|
||||
#define _x594 (_x593 << 16ull)
|
||||
#define _x595 (_x594 | (_x594 << 2ull))
|
||||
#define _x596 (x & 786432ull)
|
||||
#define _x597 (_x596 << 18ull)
|
||||
#define _x598 (_x597 | (_x597 << 2ull))
|
||||
#define _x599 (_x595 | _x598)
|
||||
#define _x600 (x & 3145728ull)
|
||||
#define _x601 (_x600 << 20ull)
|
||||
#define _x602 (_x601 | (_x601 << 2ull))
|
||||
#define _x603 (x & 12582912ull)
|
||||
#define _x604 (_x603 << 22ull)
|
||||
#define _x605 (_x604 | (_x604 << 2ull))
|
||||
#define _x606 (_x602 | _x605)
|
||||
#define _x607 (_x599 | _x606)
|
||||
#define _x608 (x & 50331648ull)
|
||||
#define _x609 (_x608 << 24ull)
|
||||
#define _x610 (_x609 | (_x609 << 2ull))
|
||||
#define _x611 (x & 201326592ull)
|
||||
#define _x612 (_x611 << 26ull)
|
||||
#define _x613 (_x612 | (_x612 << 2ull))
|
||||
#define _x614 (_x610 | _x613)
|
||||
#define _x615 (x & 805306368ull)
|
||||
#define _x616 (_x615 << 28ull)
|
||||
#define _x617 (_x616 | (_x616 << 2ull))
|
||||
#define _x618 (x & 3221225472ull)
|
||||
#define _x619 (_x618 << 30ull)
|
||||
#define _x620 (_x619 | (_x619 << 2ull))
|
||||
#define _x621 (_x617 | _x620)
|
||||
#define _x622 (_x614 | _x621)
|
||||
#define _x623 (_x607 | _x622)
|
||||
#define _x624 (_x222 | _x623)
|
||||
case 125: return _x624;
|
||||
#define _x625 (x & 65536ull)
|
||||
#define _x626 (_x625 << 16ull)
|
||||
#define _x627 (_x626 | (_x626 << 1ull))
|
||||
#define _x628 (x & 131072ull)
|
||||
#define _x629 (_x628 << 17ull)
|
||||
#define _x630 (_x629 | (_x629 << 1ull))
|
||||
#define _x631 (_x627 | _x630)
|
||||
#define _x632 (x & 262144ull)
|
||||
#define _x633 (_x632 << 18ull)
|
||||
#define _x634 (_x633 | (_x633 << 1ull))
|
||||
#define _x635 (x & 524288ull)
|
||||
#define _x636 (_x635 << 19ull)
|
||||
#define _x637 (_x636 | (_x636 << 1ull))
|
||||
#define _x638 (_x634 | _x637)
|
||||
#define _x639 (_x631 | _x638)
|
||||
#define _x640 (x & 1048576ull)
|
||||
#define _x641 (_x640 << 20ull)
|
||||
#define _x642 (_x641 | (_x641 << 1ull))
|
||||
#define _x643 (x & 2097152ull)
|
||||
#define _x644 (_x643 << 21ull)
|
||||
#define _x645 (_x644 | (_x644 << 1ull))
|
||||
#define _x646 (_x642 | _x645)
|
||||
#define _x647 (x & 4194304ull)
|
||||
#define _x648 (_x647 << 22ull)
|
||||
#define _x649 (_x648 | (_x648 << 1ull))
|
||||
#define _x650 (x & 8388608ull)
|
||||
#define _x651 (_x650 << 23ull)
|
||||
#define _x652 (_x651 | (_x651 << 1ull))
|
||||
#define _x653 (_x649 | _x652)
|
||||
#define _x654 (_x646 | _x653)
|
||||
#define _x655 (_x639 | _x654)
|
||||
#define _x656 (x & 16777216ull)
|
||||
#define _x657 (_x656 << 24ull)
|
||||
#define _x658 (_x657 | (_x657 << 1ull))
|
||||
#define _x659 (x & 33554432ull)
|
||||
#define _x660 (_x659 << 25ull)
|
||||
#define _x661 (_x660 | (_x660 << 1ull))
|
||||
#define _x662 (_x658 | _x661)
|
||||
#define _x663 (x & 67108864ull)
|
||||
#define _x664 (_x663 << 26ull)
|
||||
#define _x665 (_x664 | (_x664 << 1ull))
|
||||
#define _x666 (x & 134217728ull)
|
||||
#define _x667 (_x666 << 27ull)
|
||||
#define _x668 (_x667 | (_x667 << 1ull))
|
||||
#define _x669 (_x665 | _x668)
|
||||
#define _x670 (_x662 | _x669)
|
||||
#define _x671 (x & 268435456ull)
|
||||
#define _x672 (_x671 << 28ull)
|
||||
#define _x673 (_x672 | (_x672 << 1ull))
|
||||
#define _x674 (x & 536870912ull)
|
||||
#define _x675 (_x674 << 29ull)
|
||||
#define _x676 (_x675 | (_x675 << 1ull))
|
||||
#define _x677 (_x673 | _x676)
|
||||
#define _x678 (x & 1073741824ull)
|
||||
#define _x679 (_x678 << 30ull)
|
||||
#define _x680 (_x679 | (_x679 << 1ull))
|
||||
#define _x681 (x & 2147483648ull)
|
||||
#define _x682 (_x681 << 31ull)
|
||||
#define _x683 (_x682 | (_x682 << 1ull))
|
||||
#define _x684 (_x680 | _x683)
|
||||
#define _x685 (_x677 | _x684)
|
||||
#define _x686 (_x670 | _x685)
|
||||
#define _x687 (_x655 | _x686)
|
||||
#define _x688 (_x254 | _x687)
|
||||
case 126: return _x688;
|
||||
case 127: return x;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
|
||||
def consecutive(S):
|
||||
for k in range(len(S)-1):
|
||||
if S[k] + 1 != S[k+1]:
|
||||
return False
|
||||
return True
|
||||
|
||||
def shift(x, k):
|
||||
if k == 0:
|
||||
return x
|
||||
if k < 0:
|
||||
return "(%s >> %dull)" % (x,-k)
|
||||
return "(%s << %dull)" % (x, k)
|
||||
|
||||
def hash(r, hashcons):
|
||||
if r in hashcons:
|
||||
return hashcons[r]
|
||||
id = "_x%d" % len(hashcons)
|
||||
print ("#define %s %s" % (id, r))
|
||||
hashcons[r] = id
|
||||
return id
|
||||
|
||||
def compile(S, offset, hashcons):
|
||||
if consecutive(S):
|
||||
k = S[0]
|
||||
l = len(S)
|
||||
if l == 64:
|
||||
return "x"
|
||||
mask = ((1 << l)-1) << k
|
||||
return hash(shift(hash("(x & %dull)" % mask, hashcons), offset - k), hashcons)
|
||||
l2 = len(S) >> 1
|
||||
S1 = S[0:l2]
|
||||
S2 = S[l2:]
|
||||
if S1 == S2:
|
||||
r1 = compile(S1, offset, hashcons)
|
||||
return hash("(%s | (%s << %dull))" % (r1, r1, l2), hashcons)
|
||||
r1 = compile(S1, offset, hashcons)
|
||||
r2 = compile(S2, offset + l2, hashcons)
|
||||
return hash("(%s | %s)" % (r1, r2), hashcons)
|
||||
|
||||
def mems2index(mems, bound):
|
||||
k = 0
|
||||
i = 0
|
||||
for m in mems:
|
||||
if m:
|
||||
k |= (1 << i)
|
||||
i += 1
|
||||
k |= (1 << i)
|
||||
return k
|
||||
|
||||
def precompute(mems, bound, hashcons):
|
||||
K = 0
|
||||
j = 0
|
||||
coeff = {}
|
||||
deficit = {}
|
||||
for m in mems:
|
||||
if m:
|
||||
coeff[K] = (1 << j)
|
||||
deficit[K] = j - K
|
||||
K += 1
|
||||
j += 1
|
||||
indices = []
|
||||
for j in range(1 << len(mems)):
|
||||
k = 0
|
||||
for i in range(K):
|
||||
if 0 != (j & coeff[i]):
|
||||
k += (1 << i)
|
||||
indices += [k]
|
||||
idx = mems2index(mems, bound)
|
||||
instr = compile(indices, 0, hashcons)
|
||||
print(" case %d: return %s;" % (idx, instr))
|
||||
|
||||
def create_mems(mems, n):
|
||||
if n == 0:
|
||||
return ([], mems)
|
||||
prefix, m1 = create_mems(mems, n - 1)
|
||||
m2 = [m + [False] for m in m1]
|
||||
m3 = [m + [True] for m in m1]
|
||||
return prefix + m1, m2 + m3
|
||||
|
||||
def combinations(n, m, hashcons):
|
||||
prefix, S = create_mems([[]], 6)
|
||||
mems = prefix + S
|
||||
for mem in mems:
|
||||
precompute(mem, m, hashcons)
|
||||
|
||||
hashcons = {}
|
||||
combinations(7, 7, hashcons)
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -21,7 +21,8 @@ Notes:
|
|||
--*/
|
||||
#pragma once
|
||||
|
||||
#include "sat_types.h"
|
||||
#include "sat/sat_types.h"
|
||||
#include "sat/sat_clause.h"
|
||||
|
||||
namespace sat {
|
||||
class justification;
|
||||
|
|
|
|||
|
|
@ -229,9 +229,6 @@ namespace sat {
|
|||
literal r = roots[v];
|
||||
SASSERT(v != r.var());
|
||||
|
||||
if (m_solver.m_cut_simplifier)
|
||||
m_solver.m_cut_simplifier->set_root(v, r);
|
||||
|
||||
bool set_root = m_solver.set_root(l, r);
|
||||
TRACE(elim_eqs, tout << l << " " << r << "\n";);
|
||||
if (m_solver.is_assumption(v) || (m_solver.is_external(v) && (m_solver.is_incremental() || !set_root))) {
|
||||
|
|
|
|||
|
|
@ -1,289 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2020 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
sat_lut_finder.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
lut finder
|
||||
|
||||
Author:
|
||||
|
||||
Nikolaj Bjorner 2020-01-02
|
||||
|
||||
Notes:
|
||||
|
||||
|
||||
--*/
|
||||
|
||||
#include "sat/sat_lut_finder.h"
|
||||
#include "sat/sat_solver.h"
|
||||
|
||||
namespace sat {
|
||||
|
||||
void lut_finder::operator()(clause_vector& clauses) {
|
||||
m_removed_clauses.reset();
|
||||
unsigned max_size = m_max_lut_size;
|
||||
// we better have enough bits in the combination mask to
|
||||
// handle clauses up to max_size.
|
||||
// max_size = 5 -> 32 bits
|
||||
// max_size = 6 -> 64 bits
|
||||
SASSERT(sizeof(m_combination)*8 >= (1ull << static_cast<uint64_t>(max_size)));
|
||||
init_clause_filter();
|
||||
for (unsigned i = 0; i <= 6; ++i) {
|
||||
m_masks[i] = cut::effect_mask(i);
|
||||
}
|
||||
m_var_position.resize(s.num_vars());
|
||||
for (clause* cp : clauses) {
|
||||
cp->unmark_used();
|
||||
}
|
||||
for (; max_size > 2; --max_size) {
|
||||
for (clause* cp : clauses) {
|
||||
clause& c = *cp;
|
||||
if (c.size() == max_size && !c.was_removed() && !c.is_learned() && !c.was_used()) {
|
||||
check_lut(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
m_clause_filters.clear();
|
||||
|
||||
for (clause* cp : clauses) cp->unmark_used();
|
||||
for (clause* cp : m_removed_clauses) cp->mark_used();
|
||||
std::function<bool(clause*)> not_used = [](clause* cp) { return !cp->was_used(); };
|
||||
clauses.filter_update(not_used);
|
||||
}
|
||||
|
||||
void lut_finder::check_lut(clause& c) {
|
||||
SASSERT(c.size() > 2);
|
||||
unsigned filter = get_clause_filter(c);
|
||||
s.init_visited();
|
||||
unsigned mask = 0, i = 0;
|
||||
m_vars.reset();
|
||||
m_clause.reset();
|
||||
for (literal l : c) {
|
||||
m_clause.push_back(l);
|
||||
}
|
||||
// ensure that variables in returned LUT are sorted
|
||||
std::sort(m_clause.begin(), m_clause.end());
|
||||
for (literal l : m_clause) {
|
||||
m_vars.push_back(l.var());
|
||||
m_var_position[l.var()] = i;
|
||||
s.mark_visited(l.var());
|
||||
mask |= (l.sign() << (i++));
|
||||
}
|
||||
m_clauses_to_remove.reset();
|
||||
m_clauses_to_remove.push_back(&c);
|
||||
m_combination = 0;
|
||||
m_num_combinations = 0;
|
||||
set_combination(mask);
|
||||
c.mark_used();
|
||||
for (literal l : c) {
|
||||
for (auto const& cf : m_clause_filters[l.var()]) {
|
||||
if ((filter == (filter | cf.m_filter)) &&
|
||||
!cf.m_clause->was_used() &&
|
||||
extract_lut(*cf.m_clause)) {
|
||||
add_lut();
|
||||
return;
|
||||
}
|
||||
}
|
||||
// TBD: replace by BIG
|
||||
// loop over binary clauses in watch list
|
||||
for (watched const & w : s.get_wlist(l)) {
|
||||
if (w.is_binary_clause() && s.is_visited(w.get_literal().var()) && w.get_literal().index() < l.index()) {
|
||||
if (extract_lut(~l, w.get_literal())) {
|
||||
add_lut();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
l.neg();
|
||||
for (watched const & w : s.get_wlist(l)) {
|
||||
if (w.is_binary_clause() && s.is_visited(w.get_literal().var()) && w.get_literal().index() < l.index()) {
|
||||
if (extract_lut(~l, w.get_literal())) {
|
||||
add_lut();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void lut_finder::add_lut() {
|
||||
DEBUG_CODE(for (clause* cp : m_clauses_to_remove) VERIFY(cp->was_used()););
|
||||
m_removed_clauses.append(m_clauses_to_remove);
|
||||
bool_var v;
|
||||
uint64_t lut = convert_combination(m_vars, v);
|
||||
TRACE(aig_simplifier,
|
||||
for (clause* cp : m_clauses_to_remove) {
|
||||
tout << *cp << "\n" << v << ": " << m_vars << "\n";
|
||||
}
|
||||
display_mask(tout, lut, 1u << m_vars.size()) << "\n";);
|
||||
m_on_lut(lut, m_vars, v);
|
||||
}
|
||||
|
||||
bool lut_finder::extract_lut(literal l1, literal l2) {
|
||||
SASSERT(s.m_visited.is_visited(l1.var()));
|
||||
SASSERT(s.m_visited.is_visited(l2.var()));
|
||||
m_missing.reset();
|
||||
unsigned mask = 0;
|
||||
for (unsigned i = 0; i < m_vars.size(); ++i) {
|
||||
if (m_vars[i] == l1.var()) {
|
||||
mask |= (l1.sign() << i);
|
||||
}
|
||||
else if (m_vars[i] == l2.var()) {
|
||||
mask |= (l2.sign() << i);
|
||||
}
|
||||
else {
|
||||
m_missing.push_back(i);
|
||||
}
|
||||
}
|
||||
return update_combinations(mask);
|
||||
}
|
||||
|
||||
bool lut_finder::extract_lut(clause& c2) {
|
||||
for (literal l : c2) {
|
||||
if (!s.is_visited(l.var()))
|
||||
return false;
|
||||
}
|
||||
if (c2.size() == m_vars.size()) {
|
||||
m_clauses_to_remove.push_back(&c2);
|
||||
c2.mark_used();
|
||||
}
|
||||
// insert missing
|
||||
unsigned mask = 0;
|
||||
m_missing.reset();
|
||||
SASSERT(c2.size() <= m_vars.size());
|
||||
for (unsigned i = 0; i < m_vars.size(); ++i) {
|
||||
m_clause[i] = null_literal;
|
||||
}
|
||||
for (literal l : c2) {
|
||||
unsigned pos = m_var_position[l.var()];
|
||||
m_clause[pos] = l;
|
||||
}
|
||||
for (unsigned j = 0; j < m_vars.size(); ++j) {
|
||||
literal lit = m_clause[j];
|
||||
if (lit == null_literal) {
|
||||
m_missing.push_back(j);
|
||||
}
|
||||
else {
|
||||
mask |= (m_clause[j].sign() << j);
|
||||
}
|
||||
}
|
||||
return update_combinations(mask);
|
||||
}
|
||||
|
||||
void lut_finder::set_combination(unsigned mask) {
|
||||
if (!get_combination(mask)) {
|
||||
m_combination |= (1ull << mask);
|
||||
m_num_combinations++;
|
||||
}
|
||||
}
|
||||
|
||||
bool lut_finder::update_combinations(unsigned mask) {
|
||||
unsigned num_missing = m_missing.size();
|
||||
for (unsigned k = 0; k < (1ul << num_missing); ++k) {
|
||||
unsigned mask2 = mask;
|
||||
for (unsigned i = 0; i < num_missing; ++i) {
|
||||
if ((k & (1 << i)) != 0) {
|
||||
mask2 |= 1ul << m_missing[i];
|
||||
}
|
||||
}
|
||||
set_combination(mask2);
|
||||
}
|
||||
return lut_is_defined(m_vars.size());
|
||||
}
|
||||
|
||||
bool lut_finder::lut_is_defined(unsigned sz) {
|
||||
if (m_num_combinations < (1ull << (sz/2)))
|
||||
return false;
|
||||
for (unsigned i = sz; i-- > 0; ) {
|
||||
if (lut_is_defined(i, sz))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief check if all output combinations for variable i are defined.
|
||||
*/
|
||||
bool lut_finder::lut_is_defined(unsigned i, unsigned sz) {
|
||||
uint64_t c = m_combination | (m_combination >> (1ull << (uint64_t)i));
|
||||
uint64_t m = m_masks[i];
|
||||
if (sz < 6) m &= ((1ull << (1ull << sz)) - 1);
|
||||
return (c & m) == m;
|
||||
}
|
||||
|
||||
/**
|
||||
* find variable where it is defined
|
||||
* convert bit-mask to truth table for that variable.
|
||||
* remove variable from vars,
|
||||
* return truth table.
|
||||
*/
|
||||
|
||||
uint64_t lut_finder::convert_combination(bool_var_vector& vars, bool_var& v) {
|
||||
SASSERT(lut_is_defined(vars.size()));
|
||||
unsigned i = 0;
|
||||
for (i = vars.size(); i-- > 0; ) {
|
||||
if (lut_is_defined(i, vars.size())) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
SASSERT(i < vars.size());
|
||||
v = vars[i];
|
||||
vars.erase(v);
|
||||
uint64_t r = 0;
|
||||
uint64_t m = m_masks[i];
|
||||
unsigned offset = 0;
|
||||
// example, if i = 2, then we are examining
|
||||
// how m_combination evaluates at position xy0uv
|
||||
// If it evaluates to 0, then it has to evaluate to 1 on position xy1uv
|
||||
// Offset keeps track of the value of xyuv
|
||||
//
|
||||
for (unsigned j = 0; j < 64; ++j) {
|
||||
if (0 != (m & (1ull << j))) {
|
||||
if (0 != (m_combination & (1ull << j))) {
|
||||
r |= 1ull << offset;
|
||||
}
|
||||
++offset;
|
||||
}
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
void lut_finder::init_clause_filter() {
|
||||
m_clause_filters.reset();
|
||||
m_clause_filters.resize(s.num_vars());
|
||||
init_clause_filter(s.m_clauses);
|
||||
init_clause_filter(s.m_learned);
|
||||
}
|
||||
|
||||
void lut_finder::init_clause_filter(clause_vector& clauses) {
|
||||
for (clause* cp : clauses) {
|
||||
clause& c = *cp;
|
||||
if (c.size() <= m_max_lut_size && s.all_distinct(c)) {
|
||||
clause_filter cf(get_clause_filter(c), cp);
|
||||
for (literal l : c) {
|
||||
m_clause_filters[l.var()].push_back(cf);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsigned lut_finder::get_clause_filter(clause const& c) {
|
||||
unsigned filter = 0;
|
||||
for (literal l : c) {
|
||||
filter |= 1 << ((l.var() % 32));
|
||||
}
|
||||
return filter;
|
||||
}
|
||||
|
||||
std::ostream& lut_finder::display_mask(std::ostream& out, uint64_t mask, unsigned sz) const {
|
||||
for (unsigned i = 0; i < sz; ++i) {
|
||||
out << ((0 != (((mask >> i)) & 0x1)) ? "1" : "0");
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,79 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2020 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
sat_lut_finder.h
|
||||
|
||||
Abstract:
|
||||
|
||||
lut finder
|
||||
|
||||
Author:
|
||||
|
||||
Nikolaj Bjorner 2020-02-03
|
||||
|
||||
Notes:
|
||||
|
||||
Find LUT with small input fan-ins
|
||||
|
||||
--*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "util/params.h"
|
||||
#include "util/statistics.h"
|
||||
#include "sat/sat_clause.h"
|
||||
#include "sat/sat_types.h"
|
||||
#include "sat/sat_solver.h"
|
||||
|
||||
namespace sat {
|
||||
|
||||
class lut_finder {
|
||||
solver& s;
|
||||
struct clause_filter {
|
||||
unsigned m_filter;
|
||||
clause* m_clause;
|
||||
clause_filter(unsigned f, clause* cp):
|
||||
m_filter(f), m_clause(cp) {}
|
||||
};
|
||||
unsigned m_max_lut_size;
|
||||
vector<svector<clause_filter>> m_clause_filters; // index of clauses.
|
||||
uint64_t m_combination; // bit-mask of parities that have been found
|
||||
unsigned m_num_combinations;
|
||||
clause_vector m_clauses_to_remove; // remove clauses that become luts
|
||||
unsigned_vector m_var_position; // position of var in main clause
|
||||
bool_var_vector m_vars; // reference to variables being tested for LUT
|
||||
literal_vector m_clause; // reference clause with literals sorted according to main clause
|
||||
unsigned_vector m_missing; // set of indices not occurring in clause.
|
||||
uint64_t m_masks[7];
|
||||
clause_vector m_removed_clauses;
|
||||
std::function<void (uint64_t, svector<bool_var> const& vars, bool_var v)> m_on_lut;
|
||||
|
||||
void set_combination(unsigned mask);
|
||||
inline bool get_combination(unsigned mask) const { return (m_combination & (1ull << mask)) != 0; }
|
||||
bool lut_is_defined(unsigned sz);
|
||||
bool lut_is_defined(unsigned i, unsigned sz);
|
||||
uint64_t convert_combination(bool_var_vector& vars, bool_var& v);
|
||||
void check_lut(clause& c);
|
||||
void add_lut();
|
||||
bool extract_lut(literal l1, literal l2);
|
||||
bool extract_lut(clause& c2);
|
||||
bool update_combinations(unsigned mask);
|
||||
void init_clause_filter();
|
||||
void init_clause_filter(clause_vector& clauses);
|
||||
unsigned get_clause_filter(clause const& c);
|
||||
std::ostream& display_mask(std::ostream& out, uint64_t mask, unsigned sz) const;
|
||||
|
||||
public:
|
||||
lut_finder(solver& s) : s(s), m_max_lut_size(5) {
|
||||
memset(m_masks, 0, sizeof(uint64_t)*7);
|
||||
}
|
||||
|
||||
void set(std::function<void (uint64_t, bool_var_vector const&, bool_var)>& f) { m_on_lut = f; }
|
||||
|
||||
unsigned max_lut_size() const { return m_max_lut_size; }
|
||||
void operator()(clause_vector& clauses);
|
||||
|
||||
};
|
||||
}
|
||||
|
|
@ -32,7 +32,6 @@ Revision History:
|
|||
#include "sat/sat_ddfw_wrapper.h"
|
||||
#include "sat/sat_prob.h"
|
||||
#include "sat/sat_anf_simplifier.h"
|
||||
#include "sat/sat_cut_simplifier.h"
|
||||
#if defined(_MSC_VER) && !defined(_M_ARM) && !defined(_M_ARM64)
|
||||
# include <xmmintrin.h>
|
||||
#endif
|
||||
|
|
@ -2105,11 +2104,7 @@ namespace sat {
|
|||
anf();
|
||||
anf.collect_statistics(m_aux_stats);
|
||||
// TBD: throttle anf_delay based on yield
|
||||
}
|
||||
|
||||
if (m_cut_simplifier && m_simplifications > m_config.m_cut_delay && !inconsistent()) {
|
||||
(*m_cut_simplifier)();
|
||||
}
|
||||
}
|
||||
|
||||
if (m_config.m_inprocess_out.is_non_empty_string()) {
|
||||
std::ofstream fout(m_config.m_inprocess_out.str());
|
||||
|
|
@ -3707,7 +3702,6 @@ namespace sat {
|
|||
SASSERT(new_v + 1 == m_justification.size()); // there are no active variables that have higher values
|
||||
literal lit = literal(new_v, false);
|
||||
m_user_scope_literals.push_back(lit);
|
||||
m_cut_simplifier = nullptr; // for simplicity, wipe it out
|
||||
if (m_ext)
|
||||
m_ext->user_push();
|
||||
TRACE(sat, tout << "user_push: " << lit << "\n";);
|
||||
|
|
@ -3766,9 +3760,6 @@ namespace sat {
|
|||
m_slow_glue_backup.set_alpha(m_config.m_slow_glue_avg);
|
||||
m_trail_avg.set_alpha(m_config.m_slow_glue_avg);
|
||||
|
||||
if (m_config.m_cut_simplify && !m_cut_simplifier && m_user_scope_literals.empty()) {
|
||||
m_cut_simplifier = alloc(cut_simplifier, *this);
|
||||
}
|
||||
}
|
||||
|
||||
void solver::collect_param_descrs(param_descrs & d) {
|
||||
|
|
@ -3788,7 +3779,6 @@ namespace sat {
|
|||
m_probing.collect_statistics(st);
|
||||
if (m_ext) m_ext->collect_statistics(st);
|
||||
if (m_local_search) m_local_search->collect_statistics(st);
|
||||
if (m_cut_simplifier) m_cut_simplifier->collect_statistics(st);
|
||||
st.copy(m_aux_stats);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -39,7 +39,6 @@ Revision History:
|
|||
#include "sat/sat_simplifier.h"
|
||||
#include "sat/sat_scc.h"
|
||||
#include "sat/sat_asymm_branch.h"
|
||||
#include "sat/sat_cut_simplifier.h"
|
||||
#include "sat/sat_probing.h"
|
||||
#include "sat/sat_mus.h"
|
||||
#include "sat/sat_drat.h"
|
||||
|
|
@ -97,7 +96,6 @@ namespace sat {
|
|||
config m_config;
|
||||
stats m_stats;
|
||||
scoped_ptr<extension> m_ext;
|
||||
scoped_ptr<cut_simplifier> m_cut_simplifier;
|
||||
parallel* m_par;
|
||||
drat m_drat; // DRAT for generating proofs
|
||||
clause_allocator m_cls_allocator[2];
|
||||
|
|
@ -222,7 +220,6 @@ namespace sat {
|
|||
friend class scc;
|
||||
friend class pb::solver;
|
||||
friend class anf_simplifier;
|
||||
friend class cut_simplifier;
|
||||
friend class parallel;
|
||||
friend class lookahead;
|
||||
friend class local_search;
|
||||
|
|
@ -450,7 +447,6 @@ namespace sat {
|
|||
bool is_incremental() const { return m_config.m_incremental; }
|
||||
extension* get_extension() const override { return m_ext.get(); }
|
||||
void set_extension(extension* e) override;
|
||||
cut_simplifier* get_cut_simplifier() override { return m_cut_simplifier.get(); }
|
||||
bool set_root(literal l, literal r);
|
||||
void flush_roots();
|
||||
typedef std::pair<literal, literal> bin_clause;
|
||||
|
|
|
|||
|
|
@ -23,7 +23,6 @@ Revision History:
|
|||
|
||||
namespace sat {
|
||||
|
||||
class cut_simplifier;
|
||||
class extension;
|
||||
|
||||
class solver_core {
|
||||
|
|
@ -58,8 +57,6 @@ namespace sat {
|
|||
// hooks for extension solver. really just ba_solver atm.
|
||||
virtual extension* get_extension() const { return nullptr; }
|
||||
virtual void set_extension(extension* e) { if (e) throw default_exception("optional API not supported"); }
|
||||
|
||||
virtual cut_simplifier* get_cut_simplifier() { return nullptr; }
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ Author:
|
|||
--*/
|
||||
#pragma once
|
||||
|
||||
#include "util/union_find.h"
|
||||
#include "ast/ast_trail.h"
|
||||
#include "sat/smt/sat_th.h"
|
||||
#include "ast/array_decl_plugin.h"
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ Author:
|
|||
--*/
|
||||
#pragma once
|
||||
|
||||
#include "util/union_find.h"
|
||||
#include "sat/smt/sat_th.h"
|
||||
#include "sat/smt/bv_ackerman.h"
|
||||
#include "ast/rewriter/bit_blaster/bit_blaster.h"
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ Author:
|
|||
--*/
|
||||
#pragma once
|
||||
|
||||
#include "util/union_find.h"
|
||||
#include "sat/smt/sat_th.h"
|
||||
#include "ast/datatype_decl_plugin.h"
|
||||
#include "ast/array_decl_plugin.h"
|
||||
|
|
|
|||
|
|
@ -38,7 +38,6 @@ Notes:
|
|||
#include "model/model_v2_pp.h"
|
||||
#include "tactic/tactic.h"
|
||||
#include "ast/converters/generic_model_converter.h"
|
||||
#include "sat/sat_cut_simplifier.h"
|
||||
#include "sat/sat_drat.h"
|
||||
#include "sat/tactic/goal2sat.h"
|
||||
#include "sat/smt/pb_solver.h"
|
||||
|
|
@ -76,7 +75,6 @@ struct goal2sat::imp : public sat::sat_internalizer {
|
|||
bool m_default_external;
|
||||
bool m_euf = false;
|
||||
bool m_top_level = false;
|
||||
sat::literal_vector aig_lits;
|
||||
|
||||
imp(ast_manager & _m, params_ref const & p, sat::solver_core & s, atom2bool_var & map, dep2asm_map& dep2asm, bool default_external):
|
||||
m(_m),
|
||||
|
|
@ -91,10 +89,6 @@ struct goal2sat::imp : public sat::sat_internalizer {
|
|||
updt_params(p);
|
||||
}
|
||||
|
||||
sat::cut_simplifier* aig() {
|
||||
return m_solver.get_cut_simplifier();
|
||||
}
|
||||
|
||||
void updt_params(params_ref const & p) {
|
||||
sat_params sp(p);
|
||||
m_ite_extra = p.get_bool("ite_extra", true);
|
||||
|
|
@ -440,16 +434,11 @@ struct goal2sat::imp : public sat::sat_internalizer {
|
|||
|
||||
m_result_stack.push_back(~l);
|
||||
lits = m_result_stack.end() - num - 1;
|
||||
if (aig()) {
|
||||
aig_lits.reset();
|
||||
aig_lits.append(num, lits);
|
||||
}
|
||||
|
||||
// remark: mk_clause may perform destructive updated to lits.
|
||||
// I have to execute it after the binary mk_clause above.
|
||||
mk_clause(num+1, lits, mk_tseitin(num+1, lits));
|
||||
if (aig())
|
||||
aig()->add_or(l, num, aig_lits.data());
|
||||
|
||||
|
||||
m_solver.set_phase(~l);
|
||||
m_result_stack.shrink(old_sz);
|
||||
if (sign)
|
||||
|
|
@ -497,14 +486,7 @@ struct goal2sat::imp : public sat::sat_internalizer {
|
|||
}
|
||||
m_result_stack.push_back(l);
|
||||
lits = m_result_stack.end() - num - 1;
|
||||
if (aig()) {
|
||||
aig_lits.reset();
|
||||
aig_lits.append(num, lits);
|
||||
}
|
||||
mk_clause(num+1, lits, mk_tseitin(num+1, lits));
|
||||
if (aig()) {
|
||||
aig()->add_and(l, num, aig_lits.data());
|
||||
}
|
||||
mk_clause(num+1, lits, mk_tseitin(num+1, lits));
|
||||
m_solver.set_phase(l);
|
||||
if (sign)
|
||||
l.neg();
|
||||
|
|
@ -546,7 +528,6 @@ struct goal2sat::imp : public sat::sat_internalizer {
|
|||
mk_clause(~t, ~e, l, mk_tseitin(~t, ~e, l));
|
||||
mk_clause(t, e, ~l, mk_tseitin(t, e, ~l));
|
||||
}
|
||||
if (aig()) aig()->add_ite(l, c, t, e);
|
||||
if (sign)
|
||||
l.neg();
|
||||
|
||||
|
|
@ -645,7 +626,6 @@ struct goal2sat::imp : public sat::sat_internalizer {
|
|||
mk_clause(~l, ~l1, l2, mk_tseitin(~l, ~l1, l2));
|
||||
mk_clause(l, l1, l2, mk_tseitin(l, l1, l2));
|
||||
mk_clause(l, ~l1, ~l2, mk_tseitin(l, ~l1, ~l2));
|
||||
if (aig()) aig()->add_iff(l, l1, l2);
|
||||
|
||||
cache(t, l);
|
||||
if (sign)
|
||||
|
|
|
|||
|
|
@ -38,7 +38,6 @@ Notes:
|
|||
#include "model/model_v2_pp.h"
|
||||
#include "tactic/tactic.h"
|
||||
#include "ast/converters/generic_model_converter.h"
|
||||
#include "sat/sat_cut_simplifier.h"
|
||||
#include "sat/sat_drat.h"
|
||||
#include "sat/tactic/sat2goal.h"
|
||||
#include "sat/smt/pb_solver.h"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue