3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-06-02 12:21:21 +00:00

remove watch, hoist orbit to track used variables

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
Nikolaj Bjorner 2020-01-02 00:39:50 -08:00
parent 1d0572354b
commit c1032c3403
6 changed files with 46 additions and 117 deletions

View file

@ -285,7 +285,12 @@ namespace dd {
if (level_p > level_q) { if (level_p > level_q) {
push(apply_rec(lo(p), q, op)); push(apply_rec(lo(p), q, op));
push(apply_rec(hi(p), q, op)); push(apply_rec(hi(p), q, op));
r = make_node(level_p, read(2), read(1)); if (read(2) == lo(p) && read(1) == hi(p)) {
r = p;
}
else {
r = make_node(level_p, read(2), read(1));
}
} }
else { else {
SASSERT(level_p == level_q); SASSERT(level_p == level_q);

View file

@ -56,7 +56,6 @@
#include "math/grobner/pdd_simplifier.h" #include "math/grobner/pdd_simplifier.h"
#include "math/simplex/bit_matrix.h" #include "math/simplex/bit_matrix.h"
#include "util/uint_set.h"
namespace dd { namespace dd {
@ -395,34 +394,42 @@ namespace dd {
vector<pdd> eqs, simp_eqs; vector<pdd> eqs, simp_eqs;
for (auto* e : s.m_to_simplify) if (!e->dep()) eqs.push_back(e->poly()); for (auto* e : s.m_to_simplify) if (!e->dep()) eqs.push_back(e->poly());
for (auto* e : s.m_processed) if (!e->dep()) eqs.push_back(e->poly()); for (auto* e : s.m_processed) if (!e->dep()) eqs.push_back(e->poly());
exlin_augment(eqs); vector<uint_set> orbits(s.m.num_vars());
simplify_exlin(eqs, simp_eqs); init_orbits(eqs, orbits);
exlin_augment(orbits, eqs);
simplify_exlin(orbits, eqs, simp_eqs);
for (pdd const& p : simp_eqs) { for (pdd const& p : simp_eqs) {
s.add(p); s.add(p);
} }
return !simp_eqs.empty() && simplify_linear_step(false); return !simp_eqs.empty() && simplify_linear_step(false);
} }
/** void simplifier::init_orbits(vector<pdd> const& eqs, vector<uint_set>& orbits) {
augment set of equations by multiplying with selected variables. for (pdd const& p : eqs) {
Uses orbits to prune which variables are multiplied.
TBD: could also prune added polynomials based on a maximal degree.
*/
void simplifier::exlin_augment(vector<pdd>& eqs) {
unsigned nv = s.m.num_vars();
vector<uint_set> orbits(nv);
random_gen rand(s.m_config.m_random_seed);
unsigned modest_num_eqs = std::min(eqs.size(), 500u);
unsigned max_xlin_eqs = modest_num_eqs*modest_num_eqs + eqs.size();
for (pdd p : eqs) {
auto const& fv = p.free_vars(); auto const& fv = p.free_vars();
for (unsigned i = fv.size(); i-- > 0; ) { for (unsigned i = fv.size(); i-- > 0; ) {
orbits[fv[i]].insert(fv[i]); // if v is used, it is in its own orbit.
for (unsigned j = i; j-- > 0; ) { for (unsigned j = i; j-- > 0; ) {
orbits[fv[i]].insert(fv[j]); orbits[fv[i]].insert(fv[j]);
orbits[fv[j]].insert(fv[i]); orbits[fv[j]].insert(fv[i]);
} }
} }
} }
}
/**
augment set of equations by multiplying with selected variables.
Uses orbits to prune which variables are multiplied.
TBD: could also prune added polynomials based on a maximal degree.
TBD: for large systems, extract cluster of polynomials based on sampling orbits
*/
void simplifier::exlin_augment(vector<uint_set> const& orbits, vector<pdd>& eqs) {
unsigned nv = s.m.num_vars();
random_gen rand(s.m_config.m_random_seed);
unsigned modest_num_eqs = std::min(eqs.size(), 500u);
unsigned max_xlin_eqs = modest_num_eqs*modest_num_eqs + eqs.size();
TRACE("dd.solver", tout << "augment " << nv << "\n"; TRACE("dd.solver", tout << "augment " << nv << "\n";
for (auto const& o : orbits) tout << o.num_elems() << "\n"; for (auto const& o : orbits) tout << o.num_elems() << "\n";
); );
@ -435,7 +442,7 @@ namespace dd {
pdd pv = s.m.mk_var(v); pdd pv = s.m.mk_var(v);
for (pdd p : eqs) { for (pdd p : eqs) {
for (unsigned w : p.free_vars()) { for (unsigned w : p.free_vars()) {
if (orbitv.contains(w)) { if (v != w && orbitv.contains(w)) {
n_eqs.push_back(pv * p); n_eqs.push_back(pv * p);
break; break;
} }
@ -453,7 +460,7 @@ namespace dd {
if (orbitv.empty()) continue; if (orbitv.empty()) continue;
pdd pv = s.m.mk_var(v); pdd pv = s.m.mk_var(v);
for (unsigned w : orbitv) { for (unsigned w : orbitv) {
if (v > w) continue; if (v >= w) continue;
pdd pw = s.m.mk_var(w); pdd pw = s.m.mk_var(w);
for (pdd p : eqs) { for (pdd p : eqs) {
if (n_eqs.size() > max_xlin_eqs) { if (n_eqs.size() > max_xlin_eqs) {
@ -474,7 +481,7 @@ namespace dd {
TRACE("dd.solver", for (pdd const& p : eqs) tout << p << "\n";); TRACE("dd.solver", for (pdd const& p : eqs) tout << p << "\n";);
} }
void simplifier::simplify_exlin(vector<pdd> const& eqs, vector<pdd>& simp_eqs) { void simplifier::simplify_exlin(vector<uint_set> const& orbits, vector<pdd> const& eqs, vector<pdd>& simp_eqs) {
// create variables for each non-constant monomial. // create variables for each non-constant monomial.
u_map<unsigned> mon2idx; u_map<unsigned> mon2idx;
@ -497,9 +504,11 @@ namespace dd {
// insert variables last. // insert variables last.
unsigned nv = s.m.num_vars(); unsigned nv = s.m.num_vars();
for (unsigned v = 0; v < nv; ++v) { for (unsigned v = 0; v < nv; ++v) {
pdd r = s.m.mk_var(v); if (!orbits[v].empty()) { // not all variables are used.
mon2idx.insert(r.index(), idx2mon.size()); pdd r = s.m.mk_var(v);
idx2mon.push_back(r); mon2idx.insert(r.index(), idx2mon.size());
idx2mon.push_back(r);
}
} }
bit_matrix bm; bit_matrix bm;

View file

@ -13,6 +13,7 @@
--*/ --*/
#pragma once #pragma once
#include "util/uint_set.h"
#include "math/grobner/pdd_solver.h" #include "math/grobner/pdd_solver.h"
namespace dd { namespace dd {
@ -46,8 +47,9 @@ private:
bool simplify_elim_dual_step(); bool simplify_elim_dual_step();
bool simplify_leaf_step(); bool simplify_leaf_step();
bool simplify_exlin(); bool simplify_exlin();
void exlin_augment(vector<pdd>& eqs); void init_orbits(vector<pdd> const& eqs, vector<uint_set>& orbits);
void simplify_exlin(vector<pdd> const& eqs, vector<pdd>& simp_eqs); void exlin_augment(vector<uint_set> const& orbits, vector<pdd>& eqs);
void simplify_exlin(vector<uint_set> const& orbits, vector<pdd> const& eqs, vector<pdd>& simp_eqs);
}; };

View file

@ -47,18 +47,6 @@ namespace dd {
- add a to S - add a to S
- simplify A using a - simplify A using a
Apply a watch list to filter out relevant elements of S
Index leading_term_watch: Var -> Equation*
Only need to simplify equations that contain eliminated variable.
The watch list can be used to index into equations that are useful to simplify.
A Bloom filter on leading term could further speed up test whether reduction applies.
For p in A:
populate watch list by maxvar(p) |-> p
For p in S:
do not occur in watch list
- the variable ordering should be chosen from a candidate model M, - the variable ordering should be chosen from a candidate model M,
in a way that is compatible with weights that draw on the number of occurrences in a way that is compatible with weights that draw on the number of occurrences
in polynomials with violated evaluations and with the maximal slack (degree of freedom). in polynomials with violated evaluations and with the maximal slack (degree of freedom).
@ -67,12 +55,6 @@ namespace dd {
slack is computed from interval assignments to variables, and is an interval in which x can possibly move slack is computed from interval assignments to variables, and is an interval in which x can possibly move
(an over-approximation). (an over-approximation).
The alternative version maintains the following invariant:
- polynomials not in the watch list cannot be simplified using a
Justification:
- elements in S have no variables watched
- elements in A are always reduced modulo all variables above the current x_i.
*/ */
@ -99,7 +81,6 @@ namespace dd {
DEBUG_CODE(invariant();); DEBUG_CODE(invariant(););
} }
catch (pdd_manager::mem_out) { catch (pdd_manager::mem_out) {
m_watch.reset();
IF_VERBOSE(2, verbose_stream() << "mem-out\n"); IF_VERBOSE(2, verbose_stream() << "mem-out\n");
// don't reduce further // don't reduce further
} }
@ -161,8 +142,7 @@ namespace dd {
/* /*
Use the given equation to simplify equations in set Use the given equation to simplify equations in set
*/ */
void solver::simplify_using(equation_vector& set, equation const& eq) { void solver::simplify_using(equation_vector& set, equation const& eq) {
struct scoped_update { struct scoped_update {
equation_vector& set; equation_vector& set;
unsigned i, j, sz; unsigned i, j, sz;
@ -195,9 +175,8 @@ namespace dd {
else if (simplified && changed_leading_term) { else if (simplified && changed_leading_term) {
SASSERT(target.state() == processed); SASSERT(target.state() == processed);
push_equation(to_simplify, target); push_equation(to_simplify, target);
if (!m_watch.empty()) { if (!m_var2level.empty()) {
m_levelp1 = std::max(m_var2level[target.poly().var()]+1, m_levelp1); m_levelp1 = std::max(m_var2level[target.poly().var()]+1, m_levelp1);
add_to_watch(target);
} }
} }
else { else {
@ -276,7 +255,6 @@ namespace dd {
if (!e) return false; if (!e) return false;
scoped_process sd(*this, e); scoped_process sd(*this, e);
equation& eq = *e; equation& eq = *e;
SASSERT(!m_watch[eq.poly().var()].contains(e));
SASSERT(eq.state() == to_simplify); SASSERT(eq.state() == to_simplify);
simplify_using(eq, m_processed); simplify_using(eq, m_processed);
if (is_trivial(eq)) { sd.e = nullptr; retire(e); return true; } if (is_trivial(eq)) { sd.e = nullptr; retire(e); return true; }
@ -286,7 +264,7 @@ namespace dd {
if (done()) return false; if (done()) return false;
TRACE("dd.solver", display(tout << "eq = ", eq);); TRACE("dd.solver", display(tout << "eq = ", eq););
superpose(eq); superpose(eq);
simplify_watch(eq); simplify_using(m_to_simplify, eq);
if (done()) return false; if (done()) return false;
if (!m_too_complex) sd.done(); if (!m_too_complex) sd.done();
return true; return true;
@ -300,58 +278,14 @@ namespace dd {
m_level2var[i] = l2v[i]; m_level2var[i] = l2v[i];
m_var2level[l2v[i]] = i; m_var2level[l2v[i]] = i;
} }
m_watch.reset();
m_watch.reserve(m_level2var.size());
m_levelp1 = m_level2var.size(); m_levelp1 = m_level2var.size();
for (equation* eq : m_to_simplify) add_to_watch(*eq);
}
void solver::add_to_watch(equation& eq) {
SASSERT(eq.state() == to_simplify);
pdd const& p = eq.poly();
if (!p.is_val()) {
m_watch[p.var()].push_back(&eq);
}
}
void solver::simplify_watch(equation const& eq) {
unsigned v = eq.poly().var();
auto& watch = m_watch[v];
unsigned j = 0;
for (equation* _target : watch) {
equation& target = *_target;
SASSERT(target.state() == to_simplify);
SASSERT(target.poly().var() == v);
bool changed_leading_term = false;
if (!done()) {
try_simplify_using(target, eq, changed_leading_term);
}
if (is_trivial(target)) {
pop_equation(target);
retire(&target);
}
else if (is_conflict(target)) {
pop_equation(target);
set_conflict(target);
}
else if (target.poly().var() != v) {
// move to other watch list
m_watch[target.poly().var()].push_back(_target);
}
else {
// keep watching same variable
watch[j++] = _target;
}
}
watch.shrink(j);
} }
solver::equation* solver::pick_next() { solver::equation* solver::pick_next() {
while (m_levelp1 > 0) { while (m_levelp1 > 0) {
unsigned v = m_level2var[m_levelp1-1]; unsigned v = m_level2var[m_levelp1-1];
equation_vector const& watch = m_watch[v];
equation* eq = nullptr; equation* eq = nullptr;
for (equation* curr : watch) { for (equation* curr : m_to_simplify) {
pdd const& p = curr->poly(); pdd const& p = curr->poly();
if (curr->state() == to_simplify && p.var() == v) { if (curr->state() == to_simplify && p.var() == v) {
if (!eq || is_simpler(*curr, *eq)) if (!eq || is_simpler(*curr, *eq))
@ -360,7 +294,6 @@ namespace dd {
} }
if (eq) { if (eq) {
pop_equation(eq); pop_equation(eq);
m_watch[eq->poly().var()].erase(eq);
return eq; return eq;
} }
--m_levelp1; --m_levelp1;
@ -384,7 +317,6 @@ namespace dd {
m_processed.reset(); m_processed.reset();
m_to_simplify.reset(); m_to_simplify.reset();
m_stats.reset(); m_stats.reset();
m_watch.reset();
m_level2var.reset(); m_level2var.reset();
m_var2level.reset(); m_var2level.reset();
m_conflict = nullptr; m_conflict = nullptr;
@ -398,9 +330,8 @@ namespace dd {
} }
push_equation(to_simplify, eq); push_equation(to_simplify, eq);
if (!m_watch.empty()) { if (!m_var2level.empty()) {
m_levelp1 = std::max(m_var2level[p.var()]+1, m_levelp1); m_levelp1 = std::max(m_var2level[p.var()]+1, m_levelp1);
add_to_watch(*eq);
} }
update_stats_max_degree_and_size(*eq); update_stats_max_degree_and_size(*eq);
} }
@ -524,28 +455,12 @@ namespace dd {
// equations in to_simplify have correct indices // equations in to_simplify have correct indices
// they are labeled as non-processed // they are labeled as non-processed
// their top-most variable is watched
i = 0; i = 0;
for (auto* e : m_to_simplify) { for (auto* e : m_to_simplify) {
VERIFY(e->idx() == i); VERIFY(e->idx() == i);
VERIFY(e->state() == to_simplify); VERIFY(e->state() == to_simplify);
pdd const& p = e->poly(); pdd const& p = e->poly();
VERIFY(!p.is_val()); VERIFY(!p.is_val());
CTRACE("dd.solver", !m_watch.empty() && !m_watch[p.var()].contains(e),
display(tout << "not watched: ", *e) << "\n";);
VERIFY(m_watch.empty() || m_watch[p.var()].contains(e));
++i;
}
// the watch list consists of equations in to_simplify
// they watch the top most variable in poly
i = 0;
for (auto const& w : m_watch) {
for (equation* e : w) {
VERIFY(!e->poly().is_val());
VERIFY(e->poly().var() == i);
VERIFY(e->state() == to_simplify);
VERIFY(m_to_simplify.contains(e));
}
++i; ++i;
} }
} }

View file

@ -147,14 +147,11 @@ private:
bool is_too_complex(const equation& eq) const { return is_too_complex(eq.poly()); } bool is_too_complex(const equation& eq) const { return is_too_complex(eq.poly()); }
bool is_too_complex(const pdd& p) const { return p.tree_size() > m_config.m_expr_size_limit; } bool is_too_complex(const pdd& p) const { return p.tree_size() > m_config.m_expr_size_limit; }
vector<equation_vector> m_watch; // watch list mapping variables to vector of equations where they occur (generally a subset)
unsigned m_levelp1; // index into level+1 unsigned m_levelp1; // index into level+1
unsigned_vector m_level2var; // level -> var unsigned_vector m_level2var; // level -> var
unsigned_vector m_var2level; // var -> level unsigned_vector m_var2level; // var -> level
void init_saturate(); void init_saturate();
void simplify_watch(equation const& eq);
void add_to_watch(equation& eq);
void del_equation(equation& eq) { del_equation(&eq); } void del_equation(equation& eq) { del_equation(&eq); }
void del_equation(equation* eq); void del_equation(equation* eq);

View file

@ -49,6 +49,7 @@ std::ostream& bit_matrix::row::display(std::ostream& out) const {
void bit_matrix::reset(unsigned num_columns) { void bit_matrix::reset(unsigned num_columns) {
m_region.reset(); m_region.reset();
m_rows.reset();
m_num_columns = num_columns; m_num_columns = num_columns;
m_num_chunks = (num_columns + 63)/64; m_num_chunks = (num_columns + 63)/64;
} }