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

add simplifiation pass

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
Nikolaj Bjorner 2020-02-22 11:21:53 -08:00
parent ab9bcfdcce
commit d1e95a133b
10 changed files with 115 additions and 36 deletions

View file

@ -18,6 +18,7 @@
#include "util/trace.h" #include "util/trace.h"
#include "sat/sat_aig_cuts.h" #include "sat/sat_aig_cuts.h"
#include "sat/sat_solver.h" #include "sat/sat_solver.h"
#include "sat/sat_lut_finder.h"
namespace sat { namespace sat {
@ -762,6 +763,34 @@ namespace sat {
cut2def(on_clause, c, literal(v, true)); 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(0, verbose_stream() << "#don't cares " << dont_cares << "\n");
}
struct aig_cuts::validator { struct aig_cuts::validator {
aig_cuts& t; aig_cuts& t;
params_ref p; params_ref p;

View file

@ -227,6 +227,8 @@ namespace sat {
cut_eval simulate(unsigned num_rounds); cut_eval simulate(unsigned num_rounds);
void simplify();
std::ostream& display(std::ostream& out) const; std::ostream& display(std::ostream& out) const;
}; };

View file

@ -107,6 +107,7 @@ namespace sat {
m_cut_delay = p.cut_delay(); m_cut_delay = p.cut_delay();
m_cut_lut = p.cut_lut(); m_cut_lut = p.cut_lut();
m_cut_xor = p.cut_xor(); m_cut_xor = p.cut_xor();
m_cut_dont_cares = p.cut_dont_cares();
m_lookahead_simplify = p.lookahead_simplify(); m_lookahead_simplify = p.lookahead_simplify();
m_lookahead_double = p.lookahead_double(); m_lookahead_double = p.lookahead_double();
m_lookahead_simplify_bca = p.lookahead_simplify_bca(); m_lookahead_simplify_bca = p.lookahead_simplify_bca();

View file

@ -124,6 +124,7 @@ namespace sat {
unsigned m_cut_delay; unsigned m_cut_delay;
bool m_cut_lut; bool m_cut_lut;
bool m_cut_xor; bool m_cut_xor;
bool m_cut_dont_cares;
bool m_anf_simplify; bool m_anf_simplify;
unsigned m_anf_delay; unsigned m_anf_delay;
bool m_anf_exlin; bool m_anf_exlin;

View file

@ -192,6 +192,7 @@ namespace sat {
m_aig_cuts.add_node(head, ite_op, 3, args); m_aig_cuts.add_node(head, ite_op, 3, args);
m_stats.m_xites++; m_stats.m_xites++;
}; };
aig_finder af(s); aig_finder af(s);
af.set(on_and); af.set(on_and);
af.set(on_ite); af.set(on_ite);
@ -231,13 +232,15 @@ namespace sat {
xf.set(on_xor); xf.set(on_xor);
xf(clauses); 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.c_ptr());
};
if (s.m_config.m_cut_lut) { if (s.m_config.m_cut_lut) {
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.c_ptr());
};
lut_finder lf(s); lut_finder lf(s);
lf.set(on_lut); lf.set(on_lut);
lf(clauses); lf(clauses);
@ -567,11 +570,12 @@ namespace sat {
} }
void cut_simplifier::add_dont_cares(vector<cut_set> const& cuts) { void cut_simplifier::add_dont_cares(vector<cut_set> const& cuts) {
if (!m_config.m_enable_dont_cares) if (!s.m_config.m_cut_dont_cares)
return; return;
cuts2bins(cuts); cuts2bins(cuts);
bins2dont_cares(); bins2dont_cares();
dont_cares2cuts(cuts); dont_cares2cuts(cuts);
m_aig_cuts.simplify();
} }
/** /**

View file

@ -89,6 +89,15 @@ namespace sat {
m_cuts[m_size++] = 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) { 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]); if (m_var != UINT_MAX && on_del) on_del(m_var, m_cuts[idx]);
m_cuts[idx] = m_cuts[--m_size]; m_cuts[idx] = m_cuts[--m_size];
@ -166,6 +175,56 @@ namespace sat {
return true; 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, sat-sweep evaluation. Given 64 bits worth of possible values per variable,
find possible values for function table encoded by cut. find possible values for function table encoded by cut.

View file

@ -160,6 +160,10 @@ namespace sat {
return true; return true;
} }
void remove_elem(unsigned i);
static uint64_t effect_mask(unsigned i);
std::ostream& display(std::ostream& out) const; std::ostream& display(std::ostream& out) const;
static std::ostream& display_table(std::ostream& out, unsigned num_input, uint64_t table); static std::ostream& display_table(std::ostream& out, unsigned num_input, uint64_t table);
@ -196,6 +200,7 @@ namespace sat {
std::swap(m_cuts, other.m_cuts); std::swap(m_cuts, other.m_cuts);
} }
void evict(on_update_t& on_del, unsigned idx); 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; std::ostream& display(std::ostream& out) const;
}; };

View file

@ -32,7 +32,9 @@ namespace sat {
// max_size = 6 -> 64 bits // max_size = 6 -> 64 bits
SASSERT(sizeof(m_combination)*8 >= (1ull << static_cast<uint64_t>(max_size))); SASSERT(sizeof(m_combination)*8 >= (1ull << static_cast<uint64_t>(max_size)));
init_clause_filter(); init_clause_filter();
for (unsigned i = 0; i <= 6; ++i) init_mask(i); for (unsigned i = 0; i <= 6; ++i) {
m_masks[i] = cut::effect_mask(i);
}
m_var_position.resize(s.num_vars()); m_var_position.resize(s.num_vars());
for (clause* cp : clauses) { for (clause* cp : clauses) {
cp->unmark_used(); cp->unmark_used();
@ -203,31 +205,6 @@ namespace sat {
return false; return false;
} }
/**
* \brief create the masks
* i = 0: 101010101010101
* i = 1: 1100110011001100
* i = 2: 1111000011110000
* i = 3: 111111110000000011111111
*/
void lut_finder::init_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;
}
}
m_masks[i] = m;
}
/** /**
* \brief check if all output combinations for variable i are defined. * \brief check if all output combinations for variable i are defined.
*/ */

View file

@ -61,7 +61,6 @@ namespace sat {
bool extract_lut(literal l1, literal l2); bool extract_lut(literal l1, literal l2);
bool extract_lut(clause& c2); bool extract_lut(clause& c2);
bool update_combinations(unsigned mask); bool update_combinations(unsigned mask);
void init_mask(unsigned i);
void init_clause_filter(); void init_clause_filter();
void init_clause_filter(clause_vector& clauses); void init_clause_filter(clause_vector& clauses);
unsigned get_clause_filter(clause const& c); unsigned get_clause_filter(clause const& c);
@ -75,5 +74,6 @@ namespace sat {
unsigned max_lut_size() const { return m_max_lut_size; } unsigned max_lut_size() const { return m_max_lut_size; }
void operator()(clause_vector& clauses); void operator()(clause_vector& clauses);
}; };
} }

View file

@ -77,6 +77,7 @@ def_module_params('sat',
('cut.delay', UINT, 2, 'delay cut simplification by in-processing round'), ('cut.delay', UINT, 2, 'delay cut simplification by in-processing round'),
('cut.lut', BOOL, False, 'extract luts from clauses 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.xor', BOOL, False, 'extract xors from clauses for cut simplification'),
('cut.dont_cares', BOOL, True, 'integrate dont cares with cuts'),
('lookahead.cube.cutoff', SYMBOL, 'depth', 'cutoff type used to create lookahead cubes: depth, freevars, psat, adaptive_freevars, adaptive_psat'), ('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. # - 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. # So if the value is 10, at most 1024 cubes will be generated of length 10.