3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-04-23 09:05:31 +00:00

Test and memoize pdd factoring (#5163)

* Test and fix pdd_manager::factor

* Memoize pdd_manager::factor

* Fix Windows build (maybe)
This commit is contained in:
Jakob Rath 2021-04-09 19:13:39 +02:00 committed by GitHub
parent c85db571ab
commit 62fac88a0d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 102 additions and 6 deletions

View file

@ -50,6 +50,7 @@ namespace dd {
void pdd_manager::reset(unsigned_vector const& level2var) {
reset_op_cache();
m_factor_cache.reset();
m_node_table.reset();
m_nodes.reset();
m_free_nodes.reset();
@ -691,27 +692,36 @@ namespace dd {
* factor p into lc*v^degree + rest
* such that degree(rest, v) < degree
* Initial implementation is very naive
* - memoize intermediary results
*/
void pdd_manager::factor(pdd const& p, unsigned v, unsigned degree, pdd& lc, pdd& rest) {
unsigned level_v = m_var2level[v];
if (degree == 0) {
lc = p;
rest = zero();
return;
}
else if (level(p.root) < level_v) {
if (level(p.root) < level_v) {
lc = zero();
rest = p;
return;
}
else if (level(p.root) > level_v) {
// Memoize nontrivial cases
auto* et = m_factor_cache.insert_if_not_there2({p.root, v, degree});
factor_entry& e = et->get_data();
if (e.is_valid()) {
lc = pdd(e.m_lc, this);
rest = pdd(e.m_rest, this);
return;
}
if (level(p.root) > level_v) {
pdd lc1 = zero(), rest1 = zero();
pdd vv = mk_var(p.var());
factor(p.hi(), v, degree, lc, rest);
factor(p.lo(), v, degree, lc1, rest1);
lc += lc1;
rest += rest1;
lc *= vv;
rest *= vv;
lc += lc1;
rest += rest1;
}
else {
unsigned d = 0;
@ -733,6 +743,8 @@ namespace dd {
rest = p;
}
}
e.m_lc = lc.root;
e.m_rest = rest.root;
}
@ -1169,6 +1181,8 @@ namespace dd {
m_op_cache.insert(e);
}
m_factor_cache.reset();
m_node_table.reset();
// re-populate node cache
for (unsigned i = m_nodes.size(); i-- > 2; ) {

View file

@ -140,9 +140,44 @@ namespace dd {
typedef ptr_hashtable<op_entry, hash_entry, eq_entry> op_table;
struct factor_entry {
factor_entry(PDD p, unsigned v, unsigned degree):
m_p(p),
m_v(v),
m_degree(degree),
m_lc(UINT_MAX),
m_rest(UINT_MAX)
{}
factor_entry(): m_p(0), m_v(0), m_degree(0), m_lc(UINT_MAX), m_rest(UINT_MAX) {}
PDD m_p; // input
unsigned m_v; // input
unsigned m_degree; // input
PDD m_lc; // output
PDD m_rest; // output
bool is_valid() { return m_lc != UINT_MAX; }
unsigned hash() const { return mk_mix(m_p, m_v, m_degree); }
};
struct hash_factor_entry {
unsigned operator()(factor_entry const& e) const { return e.hash(); }
};
struct eq_factor_entry {
bool operator()(factor_entry const& a, factor_entry const& b) const {
return a.m_p == b.m_p && a.m_v == b.m_v && a.m_degree == b.m_degree;
}
};
typedef hashtable<factor_entry, hash_factor_entry, eq_factor_entry> factor_table;
svector<node> m_nodes;
vector<rational> m_values;
op_table m_op_cache;
factor_table m_factor_cache;
node_table m_node_table;
mpq_table m_mpq_table;
svector<PDD> m_pdd_stack;
@ -361,7 +396,7 @@ namespace dd {
pdd rev_sub(rational const& r) const { return m.sub(m.mk_val(r), *this); }
pdd reduce(pdd const& other) const { return m.reduce(*this, other); }
bool different_leading_term(pdd const& other) const { return m.different_leading_term(*this, other); }
void factor(unsigned v, unsigned degree, pdd& lc, pdd& rest) { m.factor(*this, v, degree, lc, rest); }
void factor(unsigned v, unsigned degree, pdd& lc, pdd& rest) const { m.factor(*this, v, degree, lc, rest); }
pdd subst_val(vector<std::pair<unsigned, rational>> const& s) const { return m.subst_val(*this, s); }
pdd subst_val(unsigned v, rational const& val) const { return m.subst_val(*this, v, val); }

View file

@ -381,6 +381,52 @@ public :
}
}
static void factor() {
std::cout << "factor\n";
pdd_manager m(4, pdd_manager::mod2N_e, 3);
unsigned const va = 0;
unsigned const vb = 1;
unsigned const vc = 2;
unsigned const vd = 3;
pdd const a = m.mk_var(va);
pdd const b = m.mk_var(vb);
pdd const c = m.mk_var(vc);
pdd const d = m.mk_var(vd);
auto test_one = [&m](pdd const& p, unsigned v, unsigned d) {
pdd lc = m.zero();
pdd rest = m.zero();
std::cout << "Factoring p = " << p << " by v" << v << "^" << d << "\n";
p.factor(v, d, lc, rest);
std::cout << " lc = " << lc << "\n";
std::cout << " rest = " << rest << "\n";
pdd x = m.mk_var(v);
pdd x_pow_d = m.one();
for (unsigned i = 0; i < d; ++i) {
x_pow_d *= x;
}
SASSERT( p == lc * x_pow_d + rest );
SASSERT( d == 0 || rest.degree(v) < d );
SASSERT( d != 0 || rest.is_zero() );
};
auto test_multiple = [=](pdd const& p) {
for (auto v : {va, vb, vc, vd}) {
for (unsigned d = 0; d <= 5; ++d) {
test_one(p, v, d);
}
}
};
test_multiple( b );
test_multiple( b*b*b );
test_multiple( b + c );
test_multiple( a*a*a*a*a + a*a*a*b + a*a*b*b + c );
test_multiple( c*c*c*c*c + b*b*b*c + 3*b*c*c + a );
test_multiple( (a + b) * (b + c) * (c + d) * (d + a) );
}
};
}
@ -396,4 +442,5 @@ void tst_pdd() {
dd::test::order_lm();
dd::test::mod4_operations();
dd::test::degree_of_variables();
dd::test::factor();
}