mirror of
https://github.com/Z3Prover/z3
synced 2025-06-07 06:33:23 +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:
parent
f8562380d6
commit
75c87a2869
3 changed files with 102 additions and 6 deletions
|
@ -50,6 +50,7 @@ namespace dd {
|
||||||
|
|
||||||
void pdd_manager::reset(unsigned_vector const& level2var) {
|
void pdd_manager::reset(unsigned_vector const& level2var) {
|
||||||
reset_op_cache();
|
reset_op_cache();
|
||||||
|
m_factor_cache.reset();
|
||||||
m_node_table.reset();
|
m_node_table.reset();
|
||||||
m_nodes.reset();
|
m_nodes.reset();
|
||||||
m_free_nodes.reset();
|
m_free_nodes.reset();
|
||||||
|
@ -691,27 +692,36 @@ namespace dd {
|
||||||
* factor p into lc*v^degree + rest
|
* factor p into lc*v^degree + rest
|
||||||
* such that degree(rest, v) < degree
|
* such that degree(rest, v) < degree
|
||||||
* Initial implementation is very naive
|
* Initial implementation is very naive
|
||||||
* - memoize intermediary results
|
|
||||||
*/
|
*/
|
||||||
void pdd_manager::factor(pdd const& p, unsigned v, unsigned degree, pdd& lc, pdd& rest) {
|
void pdd_manager::factor(pdd const& p, unsigned v, unsigned degree, pdd& lc, pdd& rest) {
|
||||||
unsigned level_v = m_var2level[v];
|
unsigned level_v = m_var2level[v];
|
||||||
if (degree == 0) {
|
if (degree == 0) {
|
||||||
lc = p;
|
lc = p;
|
||||||
rest = zero();
|
rest = zero();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
else if (level(p.root) < level_v) {
|
if (level(p.root) < level_v) {
|
||||||
lc = zero();
|
lc = zero();
|
||||||
rest = p;
|
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 lc1 = zero(), rest1 = zero();
|
||||||
pdd vv = mk_var(p.var());
|
pdd vv = mk_var(p.var());
|
||||||
factor(p.hi(), v, degree, lc, rest);
|
factor(p.hi(), v, degree, lc, rest);
|
||||||
factor(p.lo(), v, degree, lc1, rest1);
|
factor(p.lo(), v, degree, lc1, rest1);
|
||||||
lc += lc1;
|
|
||||||
rest += rest1;
|
|
||||||
lc *= vv;
|
lc *= vv;
|
||||||
rest *= vv;
|
rest *= vv;
|
||||||
|
lc += lc1;
|
||||||
|
rest += rest1;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
unsigned d = 0;
|
unsigned d = 0;
|
||||||
|
@ -733,6 +743,8 @@ namespace dd {
|
||||||
rest = p;
|
rest = p;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
e.m_lc = lc.root;
|
||||||
|
e.m_rest = rest.root;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1169,6 +1181,8 @@ namespace dd {
|
||||||
m_op_cache.insert(e);
|
m_op_cache.insert(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_factor_cache.reset();
|
||||||
|
|
||||||
m_node_table.reset();
|
m_node_table.reset();
|
||||||
// re-populate node cache
|
// re-populate node cache
|
||||||
for (unsigned i = m_nodes.size(); i-- > 2; ) {
|
for (unsigned i = m_nodes.size(); i-- > 2; ) {
|
||||||
|
|
|
@ -140,9 +140,44 @@ namespace dd {
|
||||||
|
|
||||||
typedef ptr_hashtable<op_entry, hash_entry, eq_entry> op_table;
|
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;
|
svector<node> m_nodes;
|
||||||
vector<rational> m_values;
|
vector<rational> m_values;
|
||||||
op_table m_op_cache;
|
op_table m_op_cache;
|
||||||
|
factor_table m_factor_cache;
|
||||||
node_table m_node_table;
|
node_table m_node_table;
|
||||||
mpq_table m_mpq_table;
|
mpq_table m_mpq_table;
|
||||||
svector<PDD> m_pdd_stack;
|
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 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); }
|
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); }
|
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(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); }
|
pdd subst_val(unsigned v, rational const& val) const { return m.subst_val(*this, v, val); }
|
||||||
|
|
|
@ -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::order_lm();
|
||||||
dd::test::mod4_operations();
|
dd::test::mod4_operations();
|
||||||
dd::test::degree_of_variables();
|
dd::test::degree_of_variables();
|
||||||
|
dd::test::factor();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue