mirror of
https://github.com/Z3Prover/z3
synced 2025-06-23 06:13:40 +00:00
added notes
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
parent
3aff0bd7db
commit
77868f3d96
4 changed files with 75 additions and 35 deletions
|
@ -369,13 +369,6 @@ namespace dd {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// a = s*x + t, where s is a constant, b = u*x + v, where u is a constant.
|
|
||||||
// since x is the maximal variable, it does not occur in t or v.
|
|
||||||
// thus, both a and b are linear in x
|
|
||||||
bool pdd_manager::spoly_is_invertible(pdd const& a, pdd const& b) {
|
|
||||||
return !a.is_val() && !b.is_val() && a.hi().is_val() && b.hi().is_val() && a.var() == b.var();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Compare leading monomials.
|
* Compare leading monomials.
|
||||||
* The pdd format makes lexicographic comparison easy: compare based on
|
* The pdd format makes lexicographic comparison easy: compare based on
|
||||||
|
@ -426,6 +419,23 @@ namespace dd {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Determine whether p is a linear polynomials.
|
||||||
|
A linear polynomial is of the form x*v1 + y*v2 + .. + vn,
|
||||||
|
where v1, v2, .., vn are values.
|
||||||
|
*/
|
||||||
|
bool pdd_manager::is_linear(PDD p) {
|
||||||
|
while (true) {
|
||||||
|
if (is_val(p)) return true;
|
||||||
|
if (!is_val(hi(p))) return false;
|
||||||
|
p = lo(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool pdd_manager::is_linear(pdd const& p) {
|
||||||
|
return is_linear(p.root);
|
||||||
|
}
|
||||||
|
|
||||||
void pdd_manager::push(PDD b) {
|
void pdd_manager::push(PDD b) {
|
||||||
m_pdd_stack.push_back(b);
|
m_pdd_stack.push_back(b);
|
||||||
}
|
}
|
||||||
|
|
|
@ -240,11 +240,12 @@ namespace dd {
|
||||||
pdd mul(rational const& c, pdd const& b);
|
pdd mul(rational const& c, pdd const& b);
|
||||||
pdd reduce(pdd const& a, pdd const& b);
|
pdd reduce(pdd const& a, pdd const& b);
|
||||||
|
|
||||||
|
bool is_linear(PDD p);
|
||||||
|
bool is_linear(pdd const& p);
|
||||||
|
|
||||||
// create an spoly r if leading monomials of a and b overlap
|
// create an spoly r if leading monomials of a and b overlap
|
||||||
bool try_spoly(pdd const& a, pdd const& b, pdd& r);
|
bool try_spoly(pdd const& a, pdd const& b, pdd& r);
|
||||||
|
|
||||||
// true if b can be computed using a and the result of spoly
|
|
||||||
bool spoly_is_invertible(pdd const& a, pdd const& b);
|
|
||||||
bool lt(pdd const& a, pdd const& b);
|
bool lt(pdd const& a, pdd const& b);
|
||||||
bool different_leading_term(pdd const& a, pdd const& b);
|
bool different_leading_term(pdd const& a, pdd const& b);
|
||||||
double tree_size(pdd const& p);
|
double tree_size(pdd const& p);
|
||||||
|
@ -274,6 +275,7 @@ namespace dd {
|
||||||
rational const& val() const { SASSERT(is_val()); return m->val(root); }
|
rational const& val() const { SASSERT(is_val()); return m->val(root); }
|
||||||
bool is_val() const { return m->is_val(root); }
|
bool is_val() const { return m->is_val(root); }
|
||||||
bool is_zero() const { return m->is_zero(root); }
|
bool is_zero() const { return m->is_zero(root); }
|
||||||
|
bool is_linear() const { return m->is_linear(root); }
|
||||||
|
|
||||||
pdd operator+(pdd const& other) const { return m->add(*this, other); }
|
pdd operator+(pdd const& other) const { return m->add(*this, other); }
|
||||||
pdd operator-(pdd const& other) const { return m->sub(*this, other); }
|
pdd operator-(pdd const& other) const { return m->sub(*this, other); }
|
||||||
|
|
|
@ -40,7 +40,6 @@ namespace dd {
|
||||||
- if a does not contains x_i, put it back into A and pick again (determine whether possible)
|
- if a does not contains x_i, put it back into A and pick again (determine whether possible)
|
||||||
- for s in S:
|
- for s in S:
|
||||||
b = superpose(a, s)
|
b = superpose(a, s)
|
||||||
if superposition is invertible, then remove s
|
|
||||||
add b to A
|
add b to A
|
||||||
- add a to S
|
- add a to S
|
||||||
- simplify A using a
|
- simplify A using a
|
||||||
|
@ -72,12 +71,46 @@ namespace dd {
|
||||||
- elements in S have no variables watched
|
- elements in S have no variables watched
|
||||||
- elements in A are always reduced modulo all variables above the current x_i.
|
- elements in A are always reduced modulo all variables above the current x_i.
|
||||||
|
|
||||||
Invertible rules:
|
|
||||||
when p, q are linear in x, e.g., is of the form p = k*x + a, q = l*x + b
|
TBD:
|
||||||
where k, l are constant and x is maximal, then
|
|
||||||
from l*a - k*b and k*x + a we have the equality lkx+al+kb-al, which is lx+b
|
Linear Elimination:
|
||||||
So we can throw away q after superposition without losing solutions.
|
- comprises of a simplification pass that puts linear equations in to_processed
|
||||||
- this corresponds to triangulating a matrix during Gauss.
|
- so before simplifying with respect to the variable ordering, eliminate linear equalities.
|
||||||
|
|
||||||
|
Extended Linear Simplification (as exploited in Bosphorus AAAI 2019):
|
||||||
|
- multiply each polynomial by one variable from their orbits.
|
||||||
|
- The orbit of a varible are the variables that occur in the same monomial as it in some polynomial.
|
||||||
|
- The extended set of polynomials is fed to a linear Gauss Jordan Eliminator that extracts
|
||||||
|
additional linear equalities.
|
||||||
|
- Bosphorus uses M4RI to perform efficient GJE to scale on large bit-matrices.
|
||||||
|
|
||||||
|
Long distance vanishing polynomials (used by PolyCleaner ICCAD 2019):
|
||||||
|
- identify polynomials p, q, such that p*q = 0
|
||||||
|
- main case is half-adders and full adders (p := x + y, q := x * y) over GF2
|
||||||
|
because (x+y)*x*y = 0 over GF2
|
||||||
|
To work beyond GF2 we would need to rely on simplification with respect to asserted equalities.
|
||||||
|
The method seems rather specific to hardware multipliers so not clear it is useful to
|
||||||
|
generalize.
|
||||||
|
- find monomials that contain pairs of vanishing polynomials, transitively
|
||||||
|
withtout actually inlining.
|
||||||
|
Then color polynomial variables w by p, resp, q if they occur in polynomial equalities
|
||||||
|
w - r = 0, such that all paths in r contain a node colored by p, resp q.
|
||||||
|
polynomial variables that get colored by both p and q can be set to 0.
|
||||||
|
When some variable gets colored, other variables can be colored.
|
||||||
|
- We can walk pdd nodes by level to perform coloring in a linear sweep.
|
||||||
|
PDD nodes that are equal to 0 using some equality are marked as definitions.
|
||||||
|
First walk definitions to search for vanishing polynomial pairs.
|
||||||
|
Given two definition polynomials d1, d2, it must be the case that
|
||||||
|
level(lo(d1)) = level(lo(d1)) for the polynomial lo(d1)*lo(d2) to be vanishing.
|
||||||
|
Then starting from the lowest level examine pdd nodes.
|
||||||
|
The the current node be called p, check if the pdd node is used in an equation
|
||||||
|
w - r = 0, in which case, w inherits the labels from r.
|
||||||
|
Otherwise, label the node by the intersection of vanishing polynomials from lo(p) and hi(p).
|
||||||
|
|
||||||
|
Eliminating multiplier variables, but not adders [Kaufmann et al FMCAD 2019 for GF2];
|
||||||
|
- Only apply GB saturation with respect to variables that are part of multipliers.
|
||||||
|
- Perhaps this amounts to figuring out whether a variable is used in an xor or more
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -136,17 +169,9 @@ namespace dd {
|
||||||
}
|
}
|
||||||
|
|
||||||
void grobner::superpose(equation const & eq) {
|
void grobner::superpose(equation const & eq) {
|
||||||
unsigned j = 0;
|
|
||||||
for (equation* target : m_processed) {
|
for (equation* target : m_processed) {
|
||||||
if (superpose(eq, *target)) {
|
retire(target);
|
||||||
retire(target);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
target->set_index(j);
|
|
||||||
m_processed[j++] = target;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
m_processed.shrink(j);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -228,14 +253,14 @@ namespace dd {
|
||||||
/*
|
/*
|
||||||
let eq1: ab+q=0, and eq2: ac+e=0, then qc - eb = 0
|
let eq1: ab+q=0, and eq2: ac+e=0, then qc - eb = 0
|
||||||
*/
|
*/
|
||||||
bool grobner::superpose(equation const& eq1, equation const& eq2) {
|
void grobner::superpose(equation const& eq1, equation const& eq2) {
|
||||||
TRACE("grobner_d", tout << "eq1="; display(tout, eq1) << "eq2="; display(tout, eq2););
|
TRACE("grobner_d", display(tout << "eq1=", eq1); display(tout << "eq2=", eq2););
|
||||||
pdd r(m);
|
pdd r(m);
|
||||||
if (!m.try_spoly(eq1.poly(), eq2.poly(), r)) return false;
|
if (m.try_spoly(eq1.poly(), eq2.poly(), r) &&
|
||||||
m_stats.m_superposed++;
|
!r.is_zero() && !is_too_complex(r)) {
|
||||||
if (r.is_zero() || is_too_complex(r)) return false;
|
m_stats.m_superposed++;
|
||||||
add(r, m_dep_manager.mk_join(eq1.dep(), eq2.dep()));
|
add(r, m_dep_manager.mk_join(eq1.dep(), eq2.dep()));
|
||||||
return is_tuned() && m.spoly_is_invertible(eq1.poly(), eq2.poly());
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool grobner::tuned_step() {
|
bool grobner::tuned_step() {
|
||||||
|
@ -249,7 +274,7 @@ namespace dd {
|
||||||
if (is_trivial(eq)) { sd.e = nullptr; retire(e); return true; }
|
if (is_trivial(eq)) { sd.e = nullptr; retire(e); return true; }
|
||||||
if (check_conflict(eq)) return false;
|
if (check_conflict(eq)) return false;
|
||||||
if (!simplify_using(m_processed, eq)) return false;
|
if (!simplify_using(m_processed, eq)) return false;
|
||||||
TRACE("grobner", tout << "eq = "; display(tout, eq););
|
TRACE("grobner", display(tout << "eq = ", eq););
|
||||||
superpose(eq);
|
superpose(eq);
|
||||||
return simplify_to_simplify(eq);
|
return simplify_to_simplify(eq);
|
||||||
}
|
}
|
||||||
|
@ -357,7 +382,10 @@ namespace dd {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool grobner::done() {
|
bool grobner::done() {
|
||||||
return m_to_simplify.size() + m_processed.size() >= m_config.m_eqs_threshold || canceled() || m_conflict != nullptr;
|
return
|
||||||
|
m_to_simplify.size() + m_processed.size() >= m_config.m_eqs_threshold ||
|
||||||
|
canceled() ||
|
||||||
|
m_conflict != nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void grobner::del_equation(equation& eq) {
|
void grobner::del_equation(equation& eq) {
|
||||||
|
|
|
@ -114,7 +114,7 @@ private:
|
||||||
equation* pick_next();
|
equation* pick_next();
|
||||||
bool canceled();
|
bool canceled();
|
||||||
bool done();
|
bool done();
|
||||||
bool superpose(equation const& eq1, equation const& eq2);
|
void superpose(equation const& eq1, equation const& eq2);
|
||||||
void superpose(equation const& eq);
|
void superpose(equation const& eq);
|
||||||
bool simplify_source_target(equation const& source, equation& target, bool& changed_leading_term);
|
bool simplify_source_target(equation const& source, equation& target, bool& changed_leading_term);
|
||||||
bool simplify_using(equation_vector& set, equation const& eq);
|
bool simplify_using(equation_vector& set, equation const& eq);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue