mirror of
https://github.com/Z3Prover/z3
synced 2026-06-01 06:37:49 +00:00
fix bug where we need to cover the whole resolvent in the path when bubbling up
This commit is contained in:
parent
279c7d4d46
commit
b42db215c4
1 changed files with 57 additions and 44 deletions
|
|
@ -203,58 +203,71 @@ namespace search_tree {
|
||||||
}
|
}
|
||||||
|
|
||||||
void try_resolve_upwards(node<Config>* p) {
|
void try_resolve_upwards(node<Config>* p) {
|
||||||
while (p) {
|
while (p) {
|
||||||
auto left = p->left();
|
auto left = p->left();
|
||||||
auto right = p->right();
|
auto right = p->right();
|
||||||
if (!left || !right) return;
|
if (!left || !right) return;
|
||||||
|
|
||||||
// only attempt when both children are closed and at least one has a core
|
|
||||||
if (left->get_status() != status::closed || right->get_status() != status::closed) return;
|
|
||||||
if (!left->has_core() || !right->has_core()) return;
|
|
||||||
|
|
||||||
auto resolvent = compute_sibling_resolvent(left, right);
|
// only attempt when both children are closed and each has a core
|
||||||
if (resolvent.empty()) {
|
if (left->get_status() != status::closed || right->get_status() != status::closed) return;
|
||||||
// sibling resolvent empty => p and its subtree are unsat
|
if (!left->has_core() || !right->has_core()) return;
|
||||||
p->set_core(resolvent); // empty core
|
|
||||||
close_node(p);
|
|
||||||
|
|
||||||
// continue upward in case parent's sibling can now resolve
|
auto resolvent = compute_sibling_resolvent(left, right);
|
||||||
p = p->parent();
|
|
||||||
|
|
||||||
continue;
|
// empty resolvent → subtree is UNSAT
|
||||||
}
|
if (resolvent.empty()) {
|
||||||
if (p->has_core()) {
|
p->set_core(resolvent); // empty core
|
||||||
// if new core is same as existing core, stop (skip the more complicated subsumption check for now)
|
close_node(p);
|
||||||
if (resolvent == p->get_core()) return;
|
p = p->parent();
|
||||||
}
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
node<Config>* bubble = p;
|
// if p already has the same core, nothing more to do
|
||||||
|
if (p->has_core() && resolvent == p->get_core())
|
||||||
|
return;
|
||||||
|
|
||||||
// is every literal in resolvent on the path from bubble up to root?
|
//
|
||||||
// If yes, move bubble up. If not, stop.
|
// Bubble to the highest ancestor where ALL literals in the resolvent
|
||||||
// Eventually, the resolvent is attached at the lowest ancestor that “covers” all those literals.
|
// are present somewhere on the path from that ancestor to root
|
||||||
bool can_bubble = true;
|
//
|
||||||
while (bubble) {
|
node<Config>* candidate = p;
|
||||||
for (auto const& l : resolvent) {
|
node<Config>* attach_here = p; // fallback
|
||||||
bool found = false;
|
|
||||||
for (node<Config>* q = bubble; q; q = q->parent()) {
|
|
||||||
if (q->get_literal() == l) { found = true; break; }
|
|
||||||
}
|
|
||||||
if (!found) { can_bubble = false; break; }
|
|
||||||
}
|
|
||||||
if (!can_bubble) break;
|
|
||||||
bubble = bubble->parent();
|
|
||||||
}
|
|
||||||
if (!bubble) bubble = p; // fallback in case nothing bubbled
|
|
||||||
|
|
||||||
// attach resolvent to the bubbled node and close it
|
while (candidate) {
|
||||||
bubble->set_core(resolvent);
|
bool all_found = true;
|
||||||
close_node(bubble);
|
|
||||||
|
|
||||||
// continue upward from parent of bubbled node
|
for (auto const& r : resolvent) {
|
||||||
p = bubble->parent();
|
bool found = false;
|
||||||
|
for (node<Config>* q = candidate; q; q = q->parent()) {
|
||||||
|
if (q->get_literal() == r) {
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!found) {
|
||||||
|
all_found = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (all_found) {
|
||||||
|
attach_here = candidate; // bubble up to this node
|
||||||
|
}
|
||||||
|
|
||||||
|
candidate = candidate->parent();
|
||||||
|
}
|
||||||
|
|
||||||
|
// attach the resolvent and close the subtree at attach_here
|
||||||
|
if (!attach_here->has_core() || attach_here->get_core() != resolvent) {
|
||||||
|
attach_here->set_core(resolvent);
|
||||||
|
close_node(attach_here);
|
||||||
|
}
|
||||||
|
|
||||||
|
// continue upward from parent of attach_here
|
||||||
|
p = attach_here->parent();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
tree(literal const& null_literal) : m_null_literal(null_literal) {
|
tree(literal const& null_literal) : m_null_literal(null_literal) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue