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:
parent
c3ed06915c
commit
6b4ddf352d
6 changed files with 169 additions and 129 deletions
|
@ -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
|
||||||
|
|
|
@ -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;
|
|
@ -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; }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
Loading…
Add table
Add a link
Reference in a new issue