mirror of
https://github.com/Z3Prover/z3
synced 2025-04-22 16:45:31 +00:00
fix 2808
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
parent
6ad55cc8f6
commit
1f9aff04df
5 changed files with 48 additions and 69 deletions
|
@ -366,7 +366,7 @@ namespace dd {
|
|||
// 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_var() && b.is_var() && a.hi().is_val() && b.hi().is_val() && a.var() == b.var();
|
||||
return !a.is_val() && !b.is_val() && a.hi().is_val() && b.hi().is_val() && a.var() == b.var();
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -617,22 +617,8 @@ namespace dd {
|
|||
}
|
||||
|
||||
unsigned_vector const& pdd_manager::free_vars(pdd const& p) {
|
||||
return free_vars_except(p, zero());
|
||||
}
|
||||
|
||||
unsigned_vector const& pdd_manager::free_vars_except(pdd const& p, pdd const& q) {
|
||||
init_mark();
|
||||
m_free_vars.reset();
|
||||
m_todo.push_back(q.root);
|
||||
while (!m_todo.empty()) {
|
||||
PDD r = m_todo.back();
|
||||
m_todo.pop_back();
|
||||
if (is_val(r) || is_marked(r)) continue;
|
||||
set_mark(r);
|
||||
set_mark(m_var2pdd[var(r)]);
|
||||
if (!is_marked(lo(r))) m_todo.push_back(lo(r));
|
||||
if (!is_marked(hi(r))) m_todo.push_back(hi(r));
|
||||
}
|
||||
m_todo.push_back(p.root);
|
||||
while (!m_todo.empty()) {
|
||||
PDD r = m_todo.back();
|
||||
|
|
|
@ -246,7 +246,6 @@ namespace dd {
|
|||
double tree_size(pdd const& p);
|
||||
|
||||
unsigned_vector const& free_vars(pdd const& p);
|
||||
unsigned_vector const& free_vars_except(pdd const& p, pdd const& q);
|
||||
|
||||
std::ostream& display(std::ostream& out);
|
||||
std::ostream& display(std::ostream& out, pdd const& b);
|
||||
|
@ -269,7 +268,6 @@ namespace dd {
|
|||
pdd hi() const { return pdd(m->hi(root), m); }
|
||||
unsigned var() const { return m->var(root); }
|
||||
rational const& val() const { SASSERT(is_val()); return m->val(root); }
|
||||
bool is_var() const { return !m->is_val(root); }
|
||||
bool is_val() const { return m->is_val(root); }
|
||||
bool is_zero() const { return m->is_zero(root); }
|
||||
|
||||
|
|
|
@ -55,7 +55,7 @@ namespace dd {
|
|||
For p in A:
|
||||
populate watch list by maxvar(p) |-> p
|
||||
For p in S:
|
||||
populate watch list by vars(p) |-> p
|
||||
do not occur in watch list
|
||||
|
||||
- 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
|
||||
|
@ -69,7 +69,7 @@ namespace dd {
|
|||
The alternative version maintains the following invariant:
|
||||
- polynomials not in the watch list cannot be simplified using a
|
||||
Justification:
|
||||
- elements in S have all variables watched
|
||||
- elements in S have no variables watched
|
||||
- elements in A are always reduced modulo all variables above the current x_i.
|
||||
|
||||
Invertible rules:
|
||||
|
@ -106,12 +106,7 @@ namespace dd {
|
|||
|
||||
bool grobner::step() {
|
||||
m_stats.m_compute_steps++;
|
||||
if (is_tuned()) {
|
||||
return tuned_step();
|
||||
}
|
||||
else {
|
||||
return basic_step();
|
||||
}
|
||||
return is_tuned() ? tuned_step() : basic_step();
|
||||
}
|
||||
|
||||
bool grobner::basic_step() {
|
||||
|
@ -226,20 +221,6 @@ namespace dd {
|
|||
if (changed_leading_term) {
|
||||
target.set_processed(false);
|
||||
}
|
||||
if (is_tuned()) {
|
||||
if (r == t) {
|
||||
// noop
|
||||
}
|
||||
else if (changed_leading_term) {
|
||||
add_to_watch(target);
|
||||
}
|
||||
else if (target.is_processed()) {
|
||||
add_diff_to_watch(target, t);
|
||||
}
|
||||
else {
|
||||
add_to_watch(target);
|
||||
}
|
||||
}
|
||||
|
||||
TRACE("grobner", tout << "simplified " << target.poly() << "\n";);
|
||||
return true;
|
||||
|
@ -262,8 +243,9 @@ namespace dd {
|
|||
equation* e = tuned_pick_next();
|
||||
if (!e) return false;
|
||||
equation& eq = *e;
|
||||
SASSERT(!m_watch[eq.poly().var()].contains(e));
|
||||
SASSERT(!eq.is_processed());
|
||||
if (!simplify_watch(eq, true)) return false;
|
||||
if (!simplify_using(eq, m_processed)) return false;
|
||||
if (eliminate(eq)) return true;
|
||||
if (check_conflict(eq)) return false;
|
||||
if (!simplify_using(m_processed, eq)) return false;
|
||||
|
@ -271,8 +253,7 @@ namespace dd {
|
|||
superpose(eq);
|
||||
eq.set_processed(true);
|
||||
m_processed.push_back(e);
|
||||
add_diff_to_watch(eq, m.zero());
|
||||
return simplify_watch(eq, false);
|
||||
return simplify_to_simplify(eq);
|
||||
}
|
||||
|
||||
void grobner::tuned_init() {
|
||||
|
@ -292,23 +273,13 @@ namespace dd {
|
|||
}
|
||||
}
|
||||
|
||||
// add all variables in q but not p into watch.
|
||||
void grobner::add_diff_to_watch(equation& eq, pdd const& p) {
|
||||
SASSERT(eq.is_processed());
|
||||
pdd const& q = eq.poly();
|
||||
if (is_tuned() && !q.is_val()) {
|
||||
for (unsigned v : m.free_vars_except(q, p)) {
|
||||
m_watch[v].push_back(&eq);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool grobner::simplify_watch(equation const& eq, bool is_processed) {
|
||||
bool grobner::simplify_to_simplify(equation const& eq) {
|
||||
unsigned v = m_vars[m_var];
|
||||
auto& watch = m_watch[v];
|
||||
unsigned j = 0;
|
||||
for (equation* _target : watch) {
|
||||
equation& target = *_target;
|
||||
if (target.is_processed()) continue;
|
||||
bool changed_leading_term = false;
|
||||
bool simplified = !done() && simplify_source_target(eq, target, changed_leading_term);
|
||||
if (simplified && is_trivial(target)) {
|
||||
|
@ -341,6 +312,7 @@ namespace dd {
|
|||
}
|
||||
if (eq) {
|
||||
pop_equation(eq->idx(), m_to_simplify);
|
||||
m_watch[eq->poly().var()].erase(eq);
|
||||
return eq;
|
||||
}
|
||||
++m_var;
|
||||
|
@ -428,16 +400,37 @@ namespace dd {
|
|||
}
|
||||
|
||||
void grobner::invariant() const {
|
||||
// equations in processed have correct indices
|
||||
// they are labled as processed
|
||||
unsigned i = 0;
|
||||
for (auto* e : m_processed) {
|
||||
SASSERT(e->is_processed());
|
||||
SASSERT(e->idx() == i);
|
||||
VERIFY(e->is_processed());
|
||||
VERIFY(e->idx() == i);
|
||||
++i;
|
||||
}
|
||||
// equations in to_simplify have correct indices
|
||||
// they are labeled as non-processed
|
||||
// their top-most variable is watched
|
||||
i = 0;
|
||||
for (auto* e : m_to_simplify) {
|
||||
SASSERT(!e->is_processed());
|
||||
SASSERT(e->idx() == i);
|
||||
VERIFY(!e->is_processed());
|
||||
VERIFY(e->idx() == i);
|
||||
if (is_tuned()) {
|
||||
pdd const& p = e->poly();
|
||||
VERIFY(p.is_val() || 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 const* e : w) {
|
||||
VERIFY(!e->poly().is_val());
|
||||
VERIFY(e->poly().var() == i);
|
||||
VERIFY(!e->is_processed());
|
||||
VERIFY(m_to_simplify.contains(e));
|
||||
}
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -135,14 +135,11 @@ private:
|
|||
bool tuned_step();
|
||||
void tuned_init();
|
||||
equation* tuned_pick_next();
|
||||
bool simplify_watch(equation const& eq, bool is_processed);
|
||||
bool simplify_to_simplify(equation const& eq);
|
||||
void add_to_watch(equation& eq);
|
||||
void add_diff_to_watch(equation& eq, pdd const& p);
|
||||
|
||||
void del_equation(equation& eq);
|
||||
void retire(equation* eq) {
|
||||
if (is_tuned())
|
||||
for (auto v : m.free_vars(eq->poly())) m_watch[v].erase(eq);
|
||||
dealloc(eq);
|
||||
}
|
||||
void pop_equation(unsigned idx, equation_vector& v);
|
||||
|
|
|
@ -1080,7 +1080,6 @@ namespace qe {
|
|||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool is_unit() const {
|
||||
return m_children.size() == 1 &&
|
||||
m_branch_index.empty();
|
||||
|
@ -1430,7 +1429,7 @@ namespace qe {
|
|||
// set sub-formula
|
||||
m_fml = fml;
|
||||
normalize(m_fml, m_root.pos_atoms(), m_root.neg_atoms());
|
||||
expr_ref f(m_fml);
|
||||
expr_ref f(m_fml);
|
||||
get_max_relevant(get_is_relevant(), f, m_subfml);
|
||||
if (f.get() != m_subfml.get()) {
|
||||
m_fml = f;
|
||||
|
@ -1465,6 +1464,11 @@ namespace qe {
|
|||
|
||||
if (!is_sat) {
|
||||
fml = m.mk_false();
|
||||
if (m_fml.get() != m_subfml.get()) {
|
||||
scoped_ptr<expr_replacer> rp = mk_default_expr_replacer(m);
|
||||
rp->apply_substitution(to_app(m_subfml.get()), fml, m_fml);
|
||||
fml = m_fml;
|
||||
}
|
||||
reset();
|
||||
m_solver.pop(1);
|
||||
return;
|
||||
|
@ -2227,7 +2231,9 @@ namespace qe {
|
|||
}
|
||||
|
||||
void expr_quant_elim::operator()(expr* assumption, expr* fml, expr_ref& result) {
|
||||
TRACE("qe", tout << "elim input\n" << mk_ismt2_pp(fml, m) << "\n";);
|
||||
TRACE("qe",
|
||||
if (assumption) tout << "elim assumption\n" << mk_ismt2_pp(assumption, m) << "\n";
|
||||
tout << "elim input\n" << mk_ismt2_pp(fml, m) << "\n";);
|
||||
expr_ref_vector bound(m);
|
||||
result = fml;
|
||||
m_assumption = assumption;
|
||||
|
@ -2312,14 +2318,13 @@ namespace qe {
|
|||
case AST_APP: {
|
||||
app* a = to_app(e);
|
||||
expr_ref_vector args(m);
|
||||
unsigned num_args = a->get_num_args();
|
||||
bool all_visited = true;
|
||||
for (unsigned i = 0; i < num_args; ++i) {
|
||||
if (m_visited.find(a->get_arg(i), r)) {
|
||||
for (expr* arg : *a) {
|
||||
if (m_visited.find(arg, r)) {
|
||||
args.push_back(r);
|
||||
}
|
||||
else {
|
||||
todo.push_back(a->get_arg(i));
|
||||
todo.push_back(arg);
|
||||
all_visited = false;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue