3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-06-06 14:13:23 +00:00

port fixes from lev's branch. Rename pdd_grobner to pdd_solver

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
Nikolaj Bjorner 2019-12-31 15:02:18 -08:00
parent c3ed06915c
commit 6b4ddf352d
6 changed files with 169 additions and 129 deletions

View file

@ -1,7 +1,7 @@
z3_add_component(grobner z3_add_component(grobner
SOURCES SOURCES
grobner.cpp grobner.cpp
pdd_grobner.cpp pdd_solver.cpp
COMPONENT_DEPENDENCIES COMPONENT_DEPENDENCIES
ast ast
dd dd

View file

@ -3,7 +3,7 @@
Abstract: Abstract:
Grobner core based on pdd representation of polynomials Solver core based on pdd representation of polynomials
Author: Author:
Nikolaj Bjorner (nbjorner) Nikolaj Bjorner (nbjorner)
@ -11,7 +11,7 @@
--*/ --*/
#include "math/grobner/pdd_grobner.h" #include "math/grobner/pdd_solver.h"
#include "util/uint_set.h" #include "util/uint_set.h"
namespace dd { namespace dd {
@ -115,43 +115,41 @@ namespace dd {
*/ */
grobner::grobner(reslimit& lim, pdd_manager& m) : solver::solver(reslimit& lim, pdd_manager& m) :
m(m), m(m),
m_limit(lim), m_limit(lim),
m_conflict(nullptr) m_conflict(nullptr)
{} {}
grobner::~grobner() { solver::~solver() {
reset(); reset();
} }
void grobner::saturate() { void solver::saturate() {
simplify(); simplify();
if (is_tuned()) tuned_init(); tuned_init();
TRACE("grobner", display(tout);); TRACE("dd.solver", display(tout););
try { try {
while (!done() && step()) { while (!done() && step()) {
TRACE("grobner", display(tout);); TRACE("dd.solver", display(tout););
DEBUG_CODE(invariant();); DEBUG_CODE(invariant(););
IF_VERBOSE(3, display_statistics(verbose_stream()));
} }
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");
// don't reduce further // don't reduce further
} }
} }
bool grobner::step() { bool solver::step() {
m_stats.m_compute_steps++; m_stats.m_compute_steps++;
return is_tuned() ? tuned_step() : basic_step(); return tuned_step();
} }
bool grobner::basic_step() { void solver::scoped_process::done() {
return basic_step(pick_next());
}
grobner::scoped_process::~scoped_process() {
if (e) {
pdd p = e->poly(); pdd p = e->poly();
SASSERT(!p.is_val()); SASSERT(!p.is_val());
if (p.hi().is_val()) { if (p.hi().is_val()) {
@ -160,24 +158,19 @@ namespace dd {
else { else {
g.push_equation(processed, e); g.push_equation(processed, e);
} }
e = nullptr;
}
solver::scoped_process::~scoped_process() {
if (e) {
pdd p = e->poly();
SASSERT(!p.is_val());
g.push_equation(processed, e);
} }
} }
bool grobner::basic_step(equation* e) {
if (!e) return false;
scoped_process sd(*this, e);
equation& eq = *e;
TRACE("grobner", display(tout << "eq = ", eq); display(tout););
SASSERT(eq.state() == to_simplify);
if (!simplify_using(eq, m_processed)) return false;
if (is_trivial(eq)) { sd.e = nullptr; retire(e); return true; }
if (check_conflict(eq)) { sd.e = nullptr; return false; }
if (!simplify_using(m_processed, eq)) return false;
superpose(eq);
return simplify_using(m_to_simplify, eq);
}
grobner::equation* grobner::pick_next() { solver::equation* solver::pick_next() {
equation* eq = nullptr; equation* eq = nullptr;
for (auto* curr : m_to_simplify) { for (auto* curr : m_to_simplify) {
if (!eq || is_simpler(*curr, *eq)) { if (!eq || is_simpler(*curr, *eq)) {
@ -188,7 +181,7 @@ namespace dd {
return eq; return eq;
} }
void grobner::simplify() { void solver::simplify() {
try { try {
while (!done() && while (!done() &&
(simplify_linear_step(true) || (simplify_linear_step(true) ||
@ -199,22 +192,24 @@ namespace dd {
/*simplify_elim_dual_step() ||*/ /*simplify_elim_dual_step() ||*/
false)) { false)) {
DEBUG_CODE(invariant();); DEBUG_CODE(invariant(););
TRACE("grobner", display(tout);); TRACE("dd.solver", display(tout););
} }
} }
catch (pdd_manager::mem_out) { catch (pdd_manager::mem_out) {
// done reduce // done reduce
DEBUG_CODE(invariant(););
} }
} }
struct grobner::compare_top_var { struct solver::compare_top_var {
bool operator()(equation* a, equation* b) const { bool operator()(equation* a, equation* b) const {
return a->poly().var() < b->poly().var(); return a->poly().var() < b->poly().var();
} }
}; };
bool grobner::simplify_linear_step(bool binary) { bool solver::simplify_linear_step(bool binary) {
TRACE("grobner", tout << "binary " << binary << "\n";); TRACE("dd.solver", tout << "binary " << binary << "\n";);
IF_VERBOSE(2, verbose_stream() << "binary " << binary << "\n");
equation_vector linear; equation_vector linear;
for (equation* e : m_to_simplify) { for (equation* e : m_to_simplify) {
pdd p = e->poly(); pdd p = e->poly();
@ -232,17 +227,21 @@ namespace dd {
\brief simplify linear equations by using top variable as solution. \brief simplify linear equations by using top variable as solution.
The linear equation is moved to set of solved equations. The linear equation is moved to set of solved equations.
*/ */
bool grobner::simplify_linear_step(equation_vector& linear) { bool solver::simplify_linear_step(equation_vector& linear) {
if (linear.empty()) return false; if (linear.empty()) return false;
use_list_t use_list = get_use_list(); use_list_t use_list = get_use_list();
compare_top_var ctv; compare_top_var ctv;
std::stable_sort(linear.begin(), linear.end(), ctv); std::stable_sort(linear.begin(), linear.end(), ctv);
equation_vector trivial; equation_vector trivial;
unsigned j = 0; unsigned j = 0;
bool has_conflict = false;
for (equation* src : linear) { for (equation* src : linear) {
if (has_conflict) {
break;
}
unsigned v = src->poly().var(); unsigned v = src->poly().var();
equation_vector const& uses = use_list[v]; equation_vector const& uses = use_list[v];
TRACE("grobner", TRACE("dd.solver",
display(tout << "uses of: ", *src) << "\n"; display(tout << "uses of: ", *src) << "\n";
for (equation* e : uses) { for (equation* e : uses) {
display(tout, *e) << "\n"; display(tout, *e) << "\n";
@ -266,7 +265,7 @@ namespace dd {
else if (is_conflict(dst)) { else if (is_conflict(dst)) {
pop_equation(dst); pop_equation(dst);
set_conflict(dst); set_conflict(dst);
return true; has_conflict = true;
} }
else if (changed_leading_term) { else if (changed_leading_term) {
pop_equation(dst); pop_equation(dst);
@ -280,16 +279,18 @@ namespace dd {
linear[j++] = src; linear[j++] = src;
} }
} }
if (!has_conflict) {
linear.shrink(j); linear.shrink(j);
for (equation* src : linear) { for (equation* src : linear) {
pop_equation(src); pop_equation(src);
push_equation(solved, src); push_equation(solved, src);
} }
}
for (equation* e : trivial) { for (equation* e : trivial) {
del_equation(e); del_equation(e);
} }
DEBUG_CODE(invariant();); DEBUG_CODE(invariant(););
return j > 0; return j > 0 || has_conflict;
} }
/** /**
@ -298,8 +299,9 @@ namespace dd {
px + q, px - ry px + q, px - ry
since px = ry since px = ry
*/ */
bool grobner::simplify_cc_step() { bool solver::simplify_cc_step() {
TRACE("grobner", tout << "cc\n";); TRACE("dd.solver", tout << "cc\n";);
IF_VERBOSE(2, verbose_stream() << "cc\n");
u_map<equation*> los; u_map<equation*> los;
bool reduced = false; bool reduced = false;
unsigned j = 0; unsigned j = 0;
@ -331,8 +333,9 @@ namespace dd {
/** /**
\brief remove ax+b from p if x occurs as a leaf in p and a is a constant. \brief remove ax+b from p if x occurs as a leaf in p and a is a constant.
*/ */
bool grobner::simplify_leaf_step() { bool solver::simplify_leaf_step() {
TRACE("grobner", tout << "leaf\n";); TRACE("dd.solver", tout << "leaf\n";);
IF_VERBOSE(2, verbose_stream() << "leaf\n");
use_list_t use_list = get_use_list(); use_list_t use_list = get_use_list();
equation_vector leaves; equation_vector leaves;
for (unsigned i = 0; i < m_to_simplify.size(); ++i) { for (unsigned i = 0; i < m_to_simplify.size(); ++i) {
@ -373,8 +376,9 @@ namespace dd {
/** /**
\brief treat equations as processed if top variable occurs only once. \brief treat equations as processed if top variable occurs only once.
*/ */
bool grobner::simplify_elim_pure_step() { bool solver::simplify_elim_pure_step() {
TRACE("grobner", tout << "pure\n";); TRACE("dd.solver", tout << "pure\n";);
IF_VERBOSE(2, verbose_stream() << "pure\n");
use_list_t use_list = get_use_list(); use_list_t use_list = get_use_list();
unsigned j = 0; unsigned j = 0;
for (equation* e : m_to_simplify) { for (equation* e : m_to_simplify) {
@ -398,7 +402,7 @@ namespace dd {
\brief \brief
reduce equations where top variable occurs only twice and linear in one of the occurrences. reduce equations where top variable occurs only twice and linear in one of the occurrences.
*/ */
bool grobner::simplify_elim_dual_step() { bool solver::simplify_elim_dual_step() {
use_list_t use_list = get_use_list(); use_list_t use_list = get_use_list();
unsigned j = 0; unsigned j = 0;
bool reduced = false; bool reduced = false;
@ -459,7 +463,7 @@ namespace dd {
} }
} }
void grobner::add_to_use(equation* e, use_list_t& use_list) { void solver::add_to_use(equation* e, use_list_t& use_list) {
unsigned_vector const& fv = m.free_vars(e->poly()); unsigned_vector const& fv = m.free_vars(e->poly());
for (unsigned v : fv) { for (unsigned v : fv) {
use_list.reserve(v + 1); use_list.reserve(v + 1);
@ -467,7 +471,7 @@ namespace dd {
} }
} }
void grobner::remove_from_use(equation* e, use_list_t& use_list) { void solver::remove_from_use(equation* e, use_list_t& use_list) {
unsigned_vector const& fv = m.free_vars(e->poly()); unsigned_vector const& fv = m.free_vars(e->poly());
for (unsigned v : fv) { for (unsigned v : fv) {
use_list.reserve(v + 1); use_list.reserve(v + 1);
@ -475,7 +479,7 @@ namespace dd {
} }
} }
void grobner::remove_from_use(equation* e, use_list_t& use_list, unsigned except_v) { void solver::remove_from_use(equation* e, use_list_t& use_list, unsigned except_v) {
unsigned_vector const& fv = m.free_vars(e->poly()); unsigned_vector const& fv = m.free_vars(e->poly());
for (unsigned v : fv) { for (unsigned v : fv) {
if (v != except_v) { if (v != except_v) {
@ -485,7 +489,7 @@ namespace dd {
} }
} }
grobner::use_list_t grobner::get_use_list() { solver::use_list_t solver::get_use_list() {
use_list_t use_list; use_list_t use_list;
for (equation * e : m_to_simplify) { for (equation * e : m_to_simplify) {
add_to_use(e, use_list); add_to_use(e, use_list);
@ -496,7 +500,7 @@ namespace dd {
return use_list; return use_list;
} }
void grobner::superpose(equation const & eq) { void solver::superpose(equation const & eq) {
for (equation* target : m_processed) { for (equation* target : m_processed) {
superpose(eq, *target); superpose(eq, *target);
} }
@ -505,7 +509,7 @@ namespace dd {
/* /*
Use a set of equations to simplify eq Use a set of equations to simplify eq
*/ */
bool grobner::simplify_using(equation& eq, equation_vector const& eqs) { void solver::simplify_using(equation& eq, equation_vector const& eqs) {
bool simplified, changed_leading_term; bool simplified, changed_leading_term;
do { do {
simplified = false; simplified = false;
@ -520,20 +524,37 @@ namespace dd {
} }
while (simplified && !eq.poly().is_val()); while (simplified && !eq.poly().is_val());
TRACE("grobner", display(tout << "simplification result: ", eq);); TRACE("dd.solver", display(tout << "simplification result: ", eq););
return !done();
} }
/* /*
Use the given equation to simplify equations in set Use the given equation to simplify equations in set
*/ */
bool grobner::simplify_using(equation_vector& set, equation const& eq) { void solver::simplify_using(equation_vector& set, equation const& eq) {
unsigned j = 0, sz = set.size();
for (unsigned i = 0; i < sz; ++i) { struct scoped_update {
equation& target = *set[i]; equation_vector& set;
unsigned i, j, sz;
scoped_update(equation_vector& set): set(set), i(0), j(0), sz(set.size()) {}
void nextj() {
set[j] = set[i];
set[i]->set_index(j++);
}
~scoped_update() {
for (; i < sz; ++i) {
nextj();
}
set.shrink(j);
}
};
scoped_update sr(set);
for (; sr.i < sr.sz; ++sr.i) {
equation& target = *set[sr.i];
bool changed_leading_term = false; bool changed_leading_term = false;
bool simplified = !done() && try_simplify_using(target, eq, changed_leading_term); bool simplified = true;
simplified = !done() && try_simplify_using(target, eq, changed_leading_term);
if (simplified && is_trivial(target)) { if (simplified && is_trivial(target)) {
retire(&target); retire(&target);
} }
@ -549,12 +570,9 @@ namespace dd {
} }
} }
else { else {
set[j] = set[i]; sr.nextj();
target.set_index(j++);
} }
} }
set.shrink(j);
return !done();
} }
/* /*
@ -562,17 +580,21 @@ namespace dd {
return true if the target was simplified. return true if the target was simplified.
set changed_leading_term if the target is in the m_processed set and the leading term changed. set changed_leading_term if the target is in the m_processed set and the leading term changed.
*/ */
bool grobner::try_simplify_using(equation& dst, equation const& src, bool& changed_leading_term) { bool solver::try_simplify_using(equation& dst, equation const& src, bool& changed_leading_term) {
if (&src == &dst) { if (&src == &dst) {
return false; return false;
} }
m_stats.m_simplified++; m_stats.m_simplified++;
pdd t = src.poly(); pdd t = src.poly();
pdd r = dst.poly().reduce(t); pdd r = dst.poly().reduce(t);
if (r == dst.poly() || is_too_complex(r)) { if (r == dst.poly()){
return false; return false;
} }
TRACE("grobner", if (is_too_complex(r)) {
m_too_complex = true;
return false;
}
TRACE("dd.solver",
tout << "reduce: " << dst.poly() << "\n"; tout << "reduce: " << dst.poly() << "\n";
tout << "using: " << t << "\n"; tout << "using: " << t << "\n";
tout << "to: " << r << "\n";); tout << "to: " << r << "\n";);
@ -583,13 +605,13 @@ namespace dd {
return true; return true;
} }
void grobner::simplify_using(equation & dst, equation const& src, bool& changed_leading_term) { void solver::simplify_using(equation & dst, equation const& src, bool& changed_leading_term) {
if (&src == &dst) return; if (&src == &dst) return;
m_stats.m_simplified++; m_stats.m_simplified++;
pdd t = src.poly(); pdd t = src.poly();
pdd r = dst.poly().reduce(t); pdd r = dst.poly().reduce(t);
changed_leading_term = dst.state() == processed && m.different_leading_term(r, dst.poly()); changed_leading_term = dst.state() == processed && m.different_leading_term(r, dst.poly());
TRACE("grobner", TRACE("dd.solver",
tout << "reduce: " << dst.poly() << "\n"; tout << "reduce: " << dst.poly() << "\n";
tout << "using: " << t << "\n"; tout << "using: " << t << "\n";
tout << "to: " << r << "\n";); tout << "to: " << r << "\n";);
@ -603,34 +625,42 @@ 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
*/ */
void grobner::superpose(equation const& eq1, equation const& eq2) { void solver::superpose(equation const& eq1, equation const& eq2) {
TRACE("grobner_d", display(tout << "eq1=", eq1); display(tout << "eq2=", eq2);); TRACE("dd.solver_d", display(tout << "eq1=", eq1); display(tout << "eq2=", eq2););
pdd r(m); pdd r(m);
if (m.try_spoly(eq1.poly(), eq2.poly(), r) && if (m.try_spoly(eq1.poly(), eq2.poly(), r) && !r.is_zero()) {
!r.is_zero() && !is_too_complex(r)) { if (is_too_complex(r)) {
m_too_complex = true;
}
else {
m_stats.m_superposed++; 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()));
} }
} }
}
bool grobner::tuned_step() { bool solver::tuned_step() {
equation* e = tuned_pick_next(); equation* e = tuned_pick_next();
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(!m_watch[eq.poly().var()].contains(e));
SASSERT(eq.state() == to_simplify); SASSERT(eq.state() == to_simplify);
if (!simplify_using(eq, m_processed)) return false; 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; }
if (check_conflict(eq)) { sd.e = nullptr; return false; } if (check_conflict(eq)) { sd.e = nullptr; return false; }
if (!simplify_using(m_processed, eq)) return false; m_too_complex = false;
TRACE("grobner", display(tout << "eq = ", eq);); simplify_using(m_processed, eq);
if (done()) return false;
TRACE("dd.solver", display(tout << "eq = ", eq););
superpose(eq); superpose(eq);
simplify_watch(eq); simplify_watch(eq);
if (done()) return false;
if (!m_too_complex) sd.done();
return true; return true;
} }
void grobner::tuned_init() { void solver::tuned_init() {
unsigned_vector const& l2v = m.get_level2var(); unsigned_vector const& l2v = m.get_level2var();
m_level2var.resize(l2v.size()); m_level2var.resize(l2v.size());
m_var2level.resize(l2v.size()); m_var2level.resize(l2v.size());
@ -644,16 +674,15 @@ namespace dd {
for (equation* eq : m_to_simplify) add_to_watch(*eq); for (equation* eq : m_to_simplify) add_to_watch(*eq);
} }
void grobner::add_to_watch(equation& eq) { void solver::add_to_watch(equation& eq) {
SASSERT(eq.state() == to_simplify); SASSERT(eq.state() == to_simplify);
SASSERT(is_tuned());
pdd const& p = eq.poly(); pdd const& p = eq.poly();
if (!p.is_val()) { if (!p.is_val()) {
m_watch[p.var()].push_back(&eq); m_watch[p.var()].push_back(&eq);
} }
} }
void grobner::simplify_watch(equation const& eq) { void solver::simplify_watch(equation const& eq) {
unsigned v = eq.poly().var(); unsigned v = eq.poly().var();
auto& watch = m_watch[v]; auto& watch = m_watch[v];
unsigned j = 0; unsigned j = 0;
@ -685,7 +714,7 @@ namespace dd {
watch.shrink(j); watch.shrink(j);
} }
grobner::equation* grobner::tuned_pick_next() { solver::equation* solver::tuned_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_vector const& watch = m_watch[v];
@ -707,7 +736,7 @@ namespace dd {
return nullptr; return nullptr;
} }
grobner::equation_vector const& grobner::equations() { solver::equation_vector const& solver::equations() {
m_all_eqs.reset(); m_all_eqs.reset();
for (equation* eq : m_solved) m_all_eqs.push_back(eq); for (equation* eq : m_solved) m_all_eqs.push_back(eq);
for (equation* eq : m_to_simplify) m_all_eqs.push_back(eq); for (equation* eq : m_to_simplify) m_all_eqs.push_back(eq);
@ -715,7 +744,7 @@ namespace dd {
return m_all_eqs; return m_all_eqs;
} }
void grobner::reset() { void solver::reset() {
for (equation* e : m_solved) dealloc(e); for (equation* e : m_solved) dealloc(e);
for (equation* e : m_to_simplify) dealloc(e); for (equation* e : m_to_simplify) dealloc(e);
for (equation* e : m_processed) dealloc(e); for (equation* e : m_processed) dealloc(e);
@ -729,7 +758,7 @@ namespace dd {
m_conflict = nullptr; m_conflict = nullptr;
} }
void grobner::add(pdd const& p, u_dependency * dep) { void solver::add(pdd const& p, u_dependency * dep) {
if (p.is_zero()) return; if (p.is_zero()) return;
equation * eq = alloc(equation, p, dep); equation * eq = alloc(equation, p, dep);
if (check_conflict(*eq)) { if (check_conflict(*eq)) {
@ -744,18 +773,19 @@ namespace dd {
update_stats_max_degree_and_size(*eq); update_stats_max_degree_and_size(*eq);
} }
bool grobner::canceled() { bool solver::canceled() {
return m_limit.get_cancel_flag(); return m_limit.get_cancel_flag();
} }
bool grobner::done() { bool solver::done() {
return return
m_to_simplify.size() + m_processed.size() >= m_config.m_eqs_threshold || m_to_simplify.size() + m_processed.size() >= m_config.m_eqs_threshold ||
canceled() || canceled() ||
m_stats.m_compute_steps > m_config.m_max_steps ||
m_conflict != nullptr; m_conflict != nullptr;
} }
grobner::equation_vector& grobner::get_queue(equation const& eq) { solver::equation_vector& solver::get_queue(equation const& eq) {
switch (eq.state()) { switch (eq.state()) {
case processed: return m_processed; case processed: return m_processed;
case to_simplify: return m_to_simplify; case to_simplify: return m_to_simplify;
@ -765,12 +795,12 @@ namespace dd {
return m_to_simplify; return m_to_simplify;
} }
void grobner::del_equation(equation* eq) { void solver::del_equation(equation* eq) {
pop_equation(eq); pop_equation(eq);
retire(eq); retire(eq);
} }
void grobner::pop_equation(equation& eq) { void solver::pop_equation(equation& eq) {
equation_vector& v = get_queue(eq); equation_vector& v = get_queue(eq);
unsigned idx = eq.idx(); unsigned idx = eq.idx();
if (idx != v.size() - 1) { if (idx != v.size() - 1) {
@ -781,43 +811,52 @@ namespace dd {
v.pop_back(); v.pop_back();
} }
void grobner::push_equation(eq_state st, equation& eq) { void solver::push_equation(eq_state st, equation& eq) {
SASSERT(st != to_simplify || !eq.poly().is_val());
SASSERT(st != processed || !eq.poly().is_val());
eq.set_state(st); eq.set_state(st);
equation_vector& v = get_queue(eq); equation_vector& v = get_queue(eq);
eq.set_index(v.size()); eq.set_index(v.size());
v.push_back(&eq); v.push_back(&eq);
} }
void grobner::update_stats_max_degree_and_size(const equation& e) { void solver::update_stats_max_degree_and_size(const equation& e) {
m_stats.m_max_expr_size = std::max(m_stats.m_max_expr_size, e.poly().tree_size()); m_stats.m_max_expr_size = std::max(m_stats.m_max_expr_size, e.poly().tree_size());
m_stats.m_max_expr_degree = std::max(m_stats.m_max_expr_degree, e.poly().degree()); m_stats.m_max_expr_degree = std::max(m_stats.m_max_expr_degree, e.poly().degree());
} }
void grobner::collect_statistics(statistics& st) const { void solver::collect_statistics(statistics& st) const {
st.update("steps", m_stats.m_compute_steps); st.update("dd.solver.steps", m_stats.m_compute_steps);
st.update("simplified", m_stats.m_simplified); st.update("dd.solver.simplified", m_stats.m_simplified);
st.update("superposed", m_stats.m_superposed); st.update("dd.solver.superposed", m_stats.m_superposed);
st.update("degree", m_stats.m_max_expr_degree); st.update("dd.solver.processed", m_processed.size());
st.update("size", m_stats.m_max_expr_size); st.update("dd.solver.solved", m_solved.size());
st.update("dd.solver.to_simplify", m_to_simplify.size());
st.update("dd.solver.degree", m_stats.m_max_expr_degree);
st.update("dd.solver.size", m_stats.m_max_expr_size);
} }
std::ostream& grobner::display(std::ostream & out, const equation & eq) const { std::ostream& solver::display(std::ostream & out, const equation & eq) const {
out << eq.poly() << "\n"; out << eq.poly() << "\n";
if (m_print_dep) 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& solver::display(std::ostream& out) const {
out << "solved\n"; for (auto e : m_solved) display(out, *e); out << "solved\n"; for (auto e : m_solved) display(out, *e);
out << "processed\n"; for (auto e : m_processed) display(out, *e); out << "processed\n"; for (auto e : m_processed) display(out, *e);
out << "to_simplify\n"; for (auto e : m_to_simplify) display(out, *e); out << "to_simplify\n"; for (auto e : m_to_simplify) display(out, *e);
return display_statistics(out);
}
std::ostream& solver::display_statistics(std::ostream& out) const {
statistics st; statistics st;
collect_statistics(st); collect_statistics(st);
st.display(out); st.display(out);
return out; return out;
} }
void grobner::invariant() const { void solver::invariant() const {
// equations in processed have correct indices // equations in processed have correct indices
// they are labled as processed // they are labled as processed
unsigned i = 0; unsigned i = 0;
@ -860,7 +899,7 @@ namespace dd {
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("grobner", !m_watch.empty() && !m_watch[p.var()].contains(e), CTRACE("dd.solver", !m_watch.empty() && !m_watch[p.var()].contains(e),
display(tout << "not watched: ", *e) << "\n";); display(tout << "not watched: ", *e) << "\n";);
VERIFY(m_watch.empty() || m_watch[p.var()].contains(e)); VERIFY(m_watch.empty() || m_watch[p.var()].contains(e));
++i; ++i;

View file

@ -28,7 +28,7 @@
namespace dd { namespace dd {
class grobner { class solver {
public: public:
struct stats { struct stats {
unsigned m_simplified; unsigned m_simplified;
@ -43,11 +43,11 @@ public:
struct config { struct config {
unsigned m_eqs_threshold; unsigned m_eqs_threshold;
unsigned m_expr_size_limit; unsigned m_expr_size_limit;
enum { basic, tuned } m_algorithm; unsigned m_max_steps;
config() : config() :
m_eqs_threshold(UINT_MAX), m_eqs_threshold(UINT_MAX),
m_expr_size_limit(UINT_MAX), m_expr_size_limit(UINT_MAX),
m_algorithm(tuned) m_max_steps(UINT_MAX)
{} {}
}; };
@ -95,9 +95,10 @@ private:
mutable u_dependency_manager m_dep_manager; mutable u_dependency_manager m_dep_manager;
equation_vector m_all_eqs; equation_vector m_all_eqs;
equation* m_conflict; equation* m_conflict;
bool m_too_complex;
public: public:
grobner(reslimit& lim, pdd_manager& m); solver(reslimit& lim, pdd_manager& m);
~grobner(); ~solver();
void operator=(print_dep_t& pd) { m_print_dep = pd; } void operator=(print_dep_t& pd) { m_print_dep = pd; }
void operator=(config const& c) { m_config = c; } void operator=(config const& c) { m_config = c; }
@ -115,18 +116,19 @@ public:
void collect_statistics(statistics & st) const; void collect_statistics(statistics & st) const;
std::ostream& display(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;
std::ostream& display_statistics(std::ostream& out) const;
const stats& get_stats() const { return m_stats; }
stats& get_stats() { return m_stats; }
private: private:
bool step(); bool step();
bool basic_step();
bool basic_step(equation* e);
equation* pick_next(); equation* pick_next();
bool canceled(); bool canceled();
bool done(); bool done();
void 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_using(equation& eq, equation_vector const& eqs); void simplify_using(equation& eq, equation_vector const& eqs);
bool simplify_using(equation_vector& set, equation const& eq); void simplify_using(equation_vector& set, equation const& eq);
void simplify_using(equation & dst, equation const& src, bool& changed_leading_term); void simplify_using(equation & dst, equation const& src, bool& changed_leading_term);
bool try_simplify_using(equation& target, equation const& source, bool& changed_leading_term); bool try_simplify_using(equation& target, equation const& source, bool& changed_leading_term);
@ -177,15 +179,14 @@ private:
void invariant() const; void invariant() const;
struct scoped_process { struct scoped_process {
grobner& g; solver& g;
equation* e; equation* e;
scoped_process(grobner& g, equation* e): g(g), e(e) {} void done();
scoped_process(solver& g, equation* e): g(g), e(e) {}
~scoped_process(); ~scoped_process();
}; };
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_basic() const { return m_config.m_algorithm == config::basic; }
}; };
} }

View file

@ -83,7 +83,7 @@ add_executable(test-z3
parray.cpp parray.cpp
pb2bv.cpp pb2bv.cpp
pdd.cpp pdd.cpp
pdd_grobner.cpp pdd_solver.cpp
permutation.cpp permutation.cpp
polynomial.cpp polynomial.cpp
polynorm.cpp polynorm.cpp

View file

@ -254,7 +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(pdd_solver);
TST(solver_pool); TST(solver_pool);
//TST_ARGV(hs); //TST_ARGV(hs);
} }

View file

@ -1,5 +1,5 @@
#include "util/rlimit.h" #include "util/rlimit.h"
#include "math/grobner/pdd_grobner.h" #include "math/grobner/pdd_solver.h"
#include "ast/bv_decl_plugin.h" #include "ast/bv_decl_plugin.h"
#include "ast/ast_util.h" #include "ast/ast_util.h"
@ -247,7 +247,7 @@ namespace dd {
} }
} }
void tst_pdd_grobner() { void tst_pdd_solver() {
dd::test1(); dd::test1();
dd::test2(); dd::test2();
} }