mirror of
https://github.com/Z3Prover/z3
synced 2025-06-22 05:43:39 +00:00
initial unit test for pdd_grobner
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
parent
3fca59ac84
commit
58be42d2a9
6 changed files with 104 additions and 34 deletions
|
@ -761,7 +761,7 @@ namespace dd {
|
||||||
first = false;
|
first = false;
|
||||||
rational c = abs(m.first);
|
rational c = abs(m.first);
|
||||||
m.second.reverse();
|
m.second.reverse();
|
||||||
if (!c.is_one()) {
|
if (!c.is_one() || m.second.empty()) {
|
||||||
out << c;
|
out << c;
|
||||||
if (!m.second.empty()) out << "*";
|
if (!m.second.empty()) out << "*";
|
||||||
}
|
}
|
||||||
|
|
|
@ -112,16 +112,15 @@ namespace dd {
|
||||||
bool grobner::basic_step() {
|
bool grobner::basic_step() {
|
||||||
equation* e = pick_next();
|
equation* e = pick_next();
|
||||||
if (!e) return false;
|
if (!e) return false;
|
||||||
|
scoped_detach sd(*this, e);
|
||||||
equation& eq = *e;
|
equation& eq = *e;
|
||||||
|
TRACE("grobner", display(tout << "eq = ", eq); display(tout););
|
||||||
SASSERT(!eq.is_processed());
|
SASSERT(!eq.is_processed());
|
||||||
if (!simplify_using(eq, m_processed)) return false;
|
if (!simplify_using(eq, m_processed)) return false;
|
||||||
if (eliminate(eq)) 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_equation(tout, eq););
|
|
||||||
superpose(eq);
|
superpose(eq);
|
||||||
eq.set_processed(true);
|
|
||||||
m_processed.push_back(e);
|
|
||||||
return simplify_using(m_to_simplify, eq);
|
return simplify_using(m_to_simplify, eq);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -156,7 +155,7 @@ namespace dd {
|
||||||
*/
|
*/
|
||||||
bool grobner::simplify_using(equation& eq, equation_vector const& eqs) {
|
bool grobner::simplify_using(equation& eq, equation_vector const& eqs) {
|
||||||
bool simplified, changed_leading_term;
|
bool simplified, changed_leading_term;
|
||||||
TRACE("grobner", tout << "simplifying: "; display_equation(tout, eq); tout << "using equalities of size " << eqs.size() << "\n";);
|
TRACE("grobner", display(tout << "simplifying: ", eq); tout << "using equalities of size " << eqs.size() << "\n";);
|
||||||
do {
|
do {
|
||||||
simplified = false;
|
simplified = false;
|
||||||
for (equation* p : eqs) {
|
for (equation* p : eqs) {
|
||||||
|
@ -170,7 +169,7 @@ namespace dd {
|
||||||
}
|
}
|
||||||
while (simplified && !eq.poly().is_val());
|
while (simplified && !eq.poly().is_val());
|
||||||
|
|
||||||
TRACE("grobner", tout << "simplification result: "; display_equation(tout, eq););
|
TRACE("grobner", display(tout << "simplification result: ", eq););
|
||||||
|
|
||||||
check_conflict(eq);
|
check_conflict(eq);
|
||||||
return !done();
|
return !done();
|
||||||
|
@ -209,12 +208,12 @@ namespace dd {
|
||||||
bool grobner::simplify_source_target(equation const& source, equation& target, bool& changed_leading_term) {
|
bool grobner::simplify_source_target(equation const& source, equation& target, bool& changed_leading_term) {
|
||||||
TRACE("grobner", tout << "simplifying: " << target.poly() << "\nusing: " << source.poly() << "\n";);
|
TRACE("grobner", tout << "simplifying: " << target.poly() << "\nusing: " << source.poly() << "\n";);
|
||||||
m_stats.m_simplified++;
|
m_stats.m_simplified++;
|
||||||
pdd t = target.poly();
|
pdd t = source.poly();
|
||||||
pdd r = source.poly().reduce(t);
|
pdd r = target.poly().reduce(t);
|
||||||
if (r == source.poly() || is_too_complex(r)) {
|
if (r == target.poly() || is_too_complex(r)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
changed_leading_term = target.is_processed() && m.different_leading_term(r, source.poly());
|
changed_leading_term = target.is_processed() && m.different_leading_term(r, target.poly());
|
||||||
target = r;
|
target = r;
|
||||||
target = m_dep_manager.mk_join(target.dep(), source.dep());
|
target = m_dep_manager.mk_join(target.dep(), source.dep());
|
||||||
update_stats_max_degree_and_size(target);
|
update_stats_max_degree_and_size(target);
|
||||||
|
@ -230,7 +229,7 @@ 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) {
|
bool grobner::superpose(equation const& eq1, equation const& eq2) {
|
||||||
TRACE("grobner_d", tout << "eq1="; display_equation(tout, eq1) << "eq2="; display_equation(tout, eq2););
|
TRACE("grobner_d", tout << "eq1="; display(tout, eq1) << "eq2="; display(tout, 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)) return false;
|
||||||
m_stats.m_superposed++;
|
m_stats.m_superposed++;
|
||||||
|
@ -242,29 +241,28 @@ namespace dd {
|
||||||
bool grobner::tuned_step() {
|
bool grobner::tuned_step() {
|
||||||
equation* e = tuned_pick_next();
|
equation* e = tuned_pick_next();
|
||||||
if (!e) return false;
|
if (!e) return false;
|
||||||
|
scoped_detach sd(*this, e);
|
||||||
equation& eq = *e;
|
equation& eq = *e;
|
||||||
SASSERT(!m_watch[eq.poly().var()].contains(e));
|
SASSERT(!m_watch[eq.poly().var()].contains(e));
|
||||||
SASSERT(!eq.is_processed());
|
SASSERT(!eq.is_processed());
|
||||||
if (!simplify_using(eq, m_processed)) return false;
|
if (!simplify_using(eq, m_processed)) return false;
|
||||||
if (eliminate(eq)) 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_equation(tout, eq););
|
TRACE("grobner", tout << "eq = "; display(tout, eq););
|
||||||
superpose(eq);
|
superpose(eq);
|
||||||
eq.set_processed(true);
|
|
||||||
m_processed.push_back(e);
|
|
||||||
return simplify_to_simplify(eq);
|
return simplify_to_simplify(eq);
|
||||||
}
|
}
|
||||||
|
|
||||||
void grobner::tuned_init() {
|
void grobner::tuned_init() {
|
||||||
// TBD: extract free variables, order them, set pointer into variable list.
|
// TBD: extract free variables, order them, set pointer into variable list.
|
||||||
NOT_IMPLEMENTED_YET();
|
NOT_IMPLEMENTED_YET();
|
||||||
m_watch.reserve(m_vars.size());
|
m_watch.reserve(m_level2var.size());
|
||||||
|
m_levelp1 = m_level2var.size();
|
||||||
for (equation* eq : m_to_simplify) add_to_watch(*eq);
|
for (equation* eq : m_to_simplify) add_to_watch(*eq);
|
||||||
SASSERT(m_processed.empty());
|
SASSERT(m_processed.empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
// watch top variable
|
|
||||||
void grobner::add_to_watch(equation& eq) {
|
void grobner::add_to_watch(equation& eq) {
|
||||||
SASSERT(!eq.is_processed());
|
SASSERT(!eq.is_processed());
|
||||||
pdd const& p = eq.poly();
|
pdd const& p = eq.poly();
|
||||||
|
@ -274,12 +272,12 @@ namespace dd {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool grobner::simplify_to_simplify(equation const& eq) {
|
bool grobner::simplify_to_simplify(equation const& eq) {
|
||||||
unsigned v = m_vars[m_var];
|
unsigned v = eq.poly().var();
|
||||||
auto& watch = m_watch[v];
|
auto& watch = m_watch[v];
|
||||||
unsigned j = 0;
|
unsigned j = 0;
|
||||||
for (equation* _target : watch) {
|
for (equation* _target : watch) {
|
||||||
equation& target = *_target;
|
equation& target = *_target;
|
||||||
if (target.is_processed()) continue;
|
SASSERT(!target.is_processed());
|
||||||
bool changed_leading_term = false;
|
bool changed_leading_term = false;
|
||||||
bool simplified = !done() && simplify_source_target(eq, target, changed_leading_term);
|
bool simplified = !done() && simplify_source_target(eq, target, changed_leading_term);
|
||||||
if (simplified && is_trivial(target)) {
|
if (simplified && is_trivial(target)) {
|
||||||
|
@ -299,8 +297,8 @@ namespace dd {
|
||||||
}
|
}
|
||||||
|
|
||||||
grobner::equation* grobner::tuned_pick_next() {
|
grobner::equation* grobner::tuned_pick_next() {
|
||||||
while (m_var < m_vars.size()) {
|
while (m_levelp1 > 0) {
|
||||||
unsigned v = m_vars[m_var];
|
unsigned v = m_level2var[m_levelp1-1];
|
||||||
equation_vector const& watch = m_watch[v];
|
equation_vector const& watch = m_watch[v];
|
||||||
equation* eq = nullptr;
|
equation* eq = nullptr;
|
||||||
for (equation* curr : watch) {
|
for (equation* curr : watch) {
|
||||||
|
@ -315,7 +313,7 @@ namespace dd {
|
||||||
m_watch[eq->poly().var()].erase(eq);
|
m_watch[eq->poly().var()].erase(eq);
|
||||||
return eq;
|
return eq;
|
||||||
}
|
}
|
||||||
++m_var;
|
--m_levelp1;
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
@ -340,7 +338,9 @@ namespace dd {
|
||||||
if (p.is_zero()) return;
|
if (p.is_zero()) return;
|
||||||
equation * eq = alloc(equation, p, dep, m_to_simplify.size());
|
equation * eq = alloc(equation, p, dep, m_to_simplify.size());
|
||||||
m_to_simplify.push_back(eq);
|
m_to_simplify.push_back(eq);
|
||||||
check_conflict(*eq);
|
if (!check_conflict(*eq) && is_tuned()) {
|
||||||
|
m_levelp1 = std::max(m_var2level[p.var()]+1, m_levelp1);
|
||||||
|
}
|
||||||
update_stats_max_degree_and_size(*eq);
|
update_stats_max_degree_and_size(*eq);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -384,15 +384,15 @@ namespace dd {
|
||||||
st.update("size", m_stats.m_max_expr_size);
|
st.update("size", m_stats.m_max_expr_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::ostream& grobner::display_equation(std::ostream & out, const equation & eq) const {
|
std::ostream& grobner::display(std::ostream & out, const equation & eq) const {
|
||||||
out << "expr = " << eq.poly() << "\n";
|
out << eq.poly() << "\n";
|
||||||
m_print_dep(eq.dep(), out);
|
if (m_print_dep) m_print_dep(eq.dep(), out);
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::ostream& grobner::display(std::ostream& out) const {
|
std::ostream& grobner::display(std::ostream& out) const {
|
||||||
out << "processed\n"; for (auto e : m_processed) display_equation(out, *e);
|
out << "processed\n"; for (auto e : m_processed) display(out, *e);
|
||||||
out << "to_simplify\n"; for (auto e : m_to_simplify) display_equation(out, *e);
|
out << "to_simplify\n"; for (auto e : m_to_simplify) display(out, *e);
|
||||||
statistics st;
|
statistics st;
|
||||||
collect_statistics(st);
|
collect_statistics(st);
|
||||||
st.display(out);
|
st.display(out);
|
||||||
|
|
|
@ -37,6 +37,7 @@ public:
|
||||||
unsigned m_superposed;
|
unsigned m_superposed;
|
||||||
unsigned m_compute_steps;
|
unsigned m_compute_steps;
|
||||||
void reset() { memset(this, 0, sizeof(*this)); }
|
void reset() { memset(this, 0, sizeof(*this)); }
|
||||||
|
stats() { reset(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct config {
|
struct config {
|
||||||
|
@ -50,7 +51,6 @@ public:
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
|
||||||
class equation {
|
class equation {
|
||||||
bool m_processed; //!< state
|
bool m_processed; //!< state
|
||||||
unsigned m_idx; //!< unique index
|
unsigned m_idx; //!< unique index
|
||||||
|
@ -73,6 +73,7 @@ private:
|
||||||
void set_processed(bool p) { m_processed = p; }
|
void set_processed(bool p) { m_processed = p; }
|
||||||
void set_index(unsigned idx) { m_idx = idx; }
|
void set_index(unsigned idx) { m_idx = idx; }
|
||||||
};
|
};
|
||||||
|
private:
|
||||||
|
|
||||||
typedef ptr_vector<equation> equation_vector;
|
typedef ptr_vector<equation> equation_vector;
|
||||||
typedef std::function<void (u_dependency* d, std::ostream& out)> print_dep_t;
|
typedef std::function<void (u_dependency* d, std::ostream& out)> print_dep_t;
|
||||||
|
@ -95,7 +96,8 @@ public:
|
||||||
void operator=(config const& c) { m_config = c; }
|
void operator=(config const& c) { m_config = c; }
|
||||||
|
|
||||||
void reset();
|
void reset();
|
||||||
void add(pdd const&, u_dependency * dep);
|
void add(pdd const& p) { add(p, nullptr); }
|
||||||
|
void add(pdd const& p, u_dependency * dep);
|
||||||
|
|
||||||
void saturate();
|
void saturate();
|
||||||
|
|
||||||
|
@ -103,7 +105,7 @@ public:
|
||||||
u_dependency_manager& dep() const { return m_dep_manager; }
|
u_dependency_manager& dep() const { return m_dep_manager; }
|
||||||
|
|
||||||
void collect_statistics(statistics & st) const;
|
void collect_statistics(statistics & st) const;
|
||||||
std::ostream& display_equation(std::ostream& out, const equation& eq) const;
|
std::ostream& display(std::ostream& out, const equation& eq) const;
|
||||||
std::ostream& display(std::ostream& out) const;
|
std::ostream& display(std::ostream& out) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -129,8 +131,9 @@ private:
|
||||||
|
|
||||||
// tuned implementation
|
// tuned implementation
|
||||||
vector<equation_vector> m_watch; // watch list mapping variables to vector of equations where they occur (generally a subset)
|
vector<equation_vector> m_watch; // watch list mapping variables to vector of equations where they occur (generally a subset)
|
||||||
unsigned m_var; // index into vars with current variable
|
unsigned m_levelp1; // index into level+1
|
||||||
unsigned_vector m_vars; // variables sorted by priority, higher priority first.
|
unsigned_vector m_level2var; // level -> var
|
||||||
|
unsigned_vector m_var2level; // var -> level
|
||||||
|
|
||||||
bool tuned_step();
|
bool tuned_step();
|
||||||
void tuned_init();
|
void tuned_init();
|
||||||
|
@ -146,6 +149,18 @@ private:
|
||||||
void push_equation(equation& eq, equation_vector& v);
|
void push_equation(equation& eq, equation_vector& v);
|
||||||
|
|
||||||
void invariant() const;
|
void invariant() const;
|
||||||
|
struct scoped_detach {
|
||||||
|
grobner& g;
|
||||||
|
equation* e;
|
||||||
|
scoped_detach(grobner& g, equation* e): g(g), e(e) {}
|
||||||
|
~scoped_detach() {
|
||||||
|
if (e) {
|
||||||
|
e->set_processed(true);
|
||||||
|
e->set_index(g.m_processed.size());
|
||||||
|
g.m_processed.push_back(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
void update_stats_max_degree_and_size(const equation& e);
|
void update_stats_max_degree_and_size(const equation& e);
|
||||||
bool is_tuned() const { return m_config.m_algorithm == config::tuned; }
|
bool is_tuned() const { return m_config.m_algorithm == config::tuned; }
|
||||||
|
|
|
@ -83,6 +83,7 @@ add_executable(test-z3
|
||||||
parray.cpp
|
parray.cpp
|
||||||
pb2bv.cpp
|
pb2bv.cpp
|
||||||
pdd.cpp
|
pdd.cpp
|
||||||
|
pdd_grobner.cpp
|
||||||
permutation.cpp
|
permutation.cpp
|
||||||
polynomial.cpp
|
polynomial.cpp
|
||||||
polynorm.cpp
|
polynorm.cpp
|
||||||
|
|
|
@ -254,6 +254,7 @@ int main(int argc, char ** argv) {
|
||||||
TST_ARGV(cnf_backbones);
|
TST_ARGV(cnf_backbones);
|
||||||
TST(bdd);
|
TST(bdd);
|
||||||
TST(pdd);
|
TST(pdd);
|
||||||
|
TST(pdd_grobner);
|
||||||
TST(solver_pool);
|
TST(solver_pool);
|
||||||
//TST_ARGV(hs);
|
//TST_ARGV(hs);
|
||||||
}
|
}
|
||||||
|
|
53
src/test/pdd_grobner.cpp
Normal file
53
src/test/pdd_grobner.cpp
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
#include "util/rlimit.h"
|
||||||
|
#include "math/grobner/pdd_grobner.h"
|
||||||
|
|
||||||
|
namespace dd {
|
||||||
|
void print_eqs(ptr_vector<grobner::equation> const& eqs) {
|
||||||
|
std::cout << "eqs\n";
|
||||||
|
for (grobner::equation* e : eqs) {
|
||||||
|
std::cout << e->poly() << "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void test1() {
|
||||||
|
pdd_manager m(4);
|
||||||
|
reslimit lim;
|
||||||
|
pdd v0 = m.mk_var(0);
|
||||||
|
pdd v1 = m.mk_var(1);
|
||||||
|
pdd v2 = m.mk_var(2);
|
||||||
|
pdd v3 = m.mk_var(3);
|
||||||
|
|
||||||
|
grobner gb(lim, m);
|
||||||
|
gb.add(v1*v2 + v1*v3);
|
||||||
|
gb.add(v1 - 1);
|
||||||
|
print_eqs(gb.equations());
|
||||||
|
gb.saturate();
|
||||||
|
print_eqs(gb.equations());
|
||||||
|
gb.reset();
|
||||||
|
|
||||||
|
gb.add(v1*v1*v2 + v2*v3);
|
||||||
|
gb.add(v1*v1*v2 + v2*v1);
|
||||||
|
gb.saturate();
|
||||||
|
print_eqs(gb.equations());
|
||||||
|
gb.reset();
|
||||||
|
|
||||||
|
gb.add(v1*v1*v2 + v2*v1);
|
||||||
|
gb.add(v1*v1*v2 + v2*v1);
|
||||||
|
gb.saturate();
|
||||||
|
print_eqs(gb.equations());
|
||||||
|
gb.reset();
|
||||||
|
|
||||||
|
gb.add(v1*v3*v3 + v3*v1 + 2);
|
||||||
|
gb.add(v1*v3*v3 + v3*v1);
|
||||||
|
gb.add(v3*v1 + v1*v2 + v2*v3);
|
||||||
|
gb.add(v3*v1 + v1*v2 + v2*v3 + v1);
|
||||||
|
gb.add(v3*v1 + v1*v2 + v2*v3 + v2);
|
||||||
|
gb.saturate();
|
||||||
|
print_eqs(gb.equations());
|
||||||
|
gb.reset();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void tst_pdd_grobner() {
|
||||||
|
dd::test1();
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue