mirror of
https://github.com/Z3Prover/z3
synced 2025-04-22 16:45:31 +00:00
Ported model_search and model_node from pdr into spacer
This commit is contained in:
parent
478d7c790e
commit
ece2e53c98
3 changed files with 329 additions and 0 deletions
|
@ -26,6 +26,7 @@ z3_add_component(spacer
|
|||
spacer_json.cpp
|
||||
spacer_iuc_proof.cpp
|
||||
spacer_mbc.cpp
|
||||
spacer_pdr.cpp
|
||||
COMPONENT_DEPENDENCIES
|
||||
arith_tactics
|
||||
core_tactics
|
||||
|
|
221
src/muz/spacer/spacer_pdr.cpp
Normal file
221
src/muz/spacer/spacer_pdr.cpp
Normal file
|
@ -0,0 +1,221 @@
|
|||
/**++
|
||||
Copyright (c) 2018 Arie Gurfinkel
|
||||
|
||||
Module Name:
|
||||
|
||||
spacer_pdr.h
|
||||
|
||||
Abstract:
|
||||
|
||||
SPACER gPDR strategy implementation
|
||||
|
||||
Author:
|
||||
|
||||
Arie Gurfinkel
|
||||
|
||||
Based on muz/pdr
|
||||
|
||||
Notes:
|
||||
|
||||
--*/
|
||||
#include "muz/spacer/spacer_pdr.h"
|
||||
|
||||
namespace spacer {
|
||||
model_node::model_node(model_node* parent, pob_ref &pob):
|
||||
m_pob(pob), m_parent(parent), m_next(nullptr), m_prev(nullptr),
|
||||
m_orig_level(m_pob->level()), m_depth(0),
|
||||
m_closed(false) {
|
||||
SASSERT(m_pob);
|
||||
if (m_parent) m_parent->add_child(*this);
|
||||
}
|
||||
|
||||
void model_node::add_child(model_node &kid) {
|
||||
m_children.push_back(this);
|
||||
SASSERT(level() == kid.level() + 1);
|
||||
SASSERT(level() > 0);
|
||||
kid.m_depth = m_depth + 1;
|
||||
if (is_closed()) set_open();
|
||||
}
|
||||
|
||||
unsigned model_node::index_in_parent() const {
|
||||
if (!m_parent) return 0;
|
||||
for (unsigned i = 0, sz = m_parent->children().size(); i < sz; ++i) {
|
||||
if (this == m_parent->children().get(i)) return i;
|
||||
}
|
||||
UNREACHABLE();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void model_node::check_pre_closed() {
|
||||
for (auto *kid : m_children) {if (kid->is_open()) return;}
|
||||
|
||||
set_pre_closed();
|
||||
model_node* p = m_parent;
|
||||
while (p && p->is_1closed()) {
|
||||
p->set_pre_closed();
|
||||
p = p->parent();
|
||||
}
|
||||
}
|
||||
void model_node::set_open() {
|
||||
SASSERT(m_closed);
|
||||
m_closed = false;
|
||||
model_node* p = parent();
|
||||
while (p && p->is_closed()) {
|
||||
p->m_closed = false;
|
||||
p = p->parent();
|
||||
}
|
||||
}
|
||||
|
||||
void model_node::detach(model_node*& qhead) {
|
||||
if (!in_queue()) return;
|
||||
SASSERT(children().empty());
|
||||
if (this == m_next) {
|
||||
SASSERT(m_prev == this);
|
||||
SASSERT(this == qhead);
|
||||
qhead = nullptr;
|
||||
}
|
||||
else {
|
||||
m_next->m_prev = m_prev;
|
||||
m_prev->m_next = m_next;
|
||||
if (this == qhead) qhead = m_next;
|
||||
}
|
||||
|
||||
// detach
|
||||
m_prev = nullptr;
|
||||
m_next = nullptr;
|
||||
}
|
||||
|
||||
|
||||
// insert node n after this in the queue
|
||||
// requires: this is in a queue or this == n
|
||||
void model_node::insert_after(model_node* n) {
|
||||
SASSERT(!in_queue());
|
||||
if (this == n) {
|
||||
m_next = n;
|
||||
m_prev = n;
|
||||
}
|
||||
else {
|
||||
n->m_next = m_next;
|
||||
m_next->m_prev = n;
|
||||
m_next = n;
|
||||
n->m_prev = this;
|
||||
}
|
||||
}
|
||||
|
||||
void model_search::reset() {
|
||||
m_cache.reset();
|
||||
if (m_root) {
|
||||
erase_children(*m_root, false);
|
||||
remove_node(*m_root, false);
|
||||
dealloc(m_root);
|
||||
m_root = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
model_node* model_search::pop_front() {
|
||||
if (!m_qhead) return nullptr;
|
||||
model_node *res = m_qhead;
|
||||
res->detach(m_qhead);
|
||||
return res;
|
||||
}
|
||||
|
||||
void model_search::add_leaf(model_node& n) {
|
||||
SASSERT(n.children().empty());
|
||||
model_nodes ns;
|
||||
model_nodes& nodes = cache(n).insert_if_not_there2(n.post(), ns)->get_data().m_value;
|
||||
if (nodes.contains(&n)) return;
|
||||
|
||||
nodes.push_back(&n);
|
||||
if (nodes.size() == 1) {
|
||||
SASSERT(n.is_open());
|
||||
enqueue_leaf(n);
|
||||
}
|
||||
else n.set_pre_closed();
|
||||
}
|
||||
|
||||
void model_search::enqueue_leaf(model_node& n) {
|
||||
SASSERT(n.is_open());
|
||||
// queue is empty, initialize it with n
|
||||
if (!m_qhead) {
|
||||
m_qhead = &n;
|
||||
m_qhead->insert_after(m_qhead);
|
||||
}
|
||||
// insert n after m_qhead
|
||||
else if (m_bfs) {
|
||||
m_qhead->insert_after(&n);
|
||||
}
|
||||
// insert n after m_qhead()->next()
|
||||
else {
|
||||
m_qhead->next()->insert_after(&n);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void model_search::set_root(model_node* root) {
|
||||
reset();
|
||||
m_root = root;
|
||||
SASSERT(m_root);
|
||||
SASSERT(m_root->children().empty());
|
||||
SASSERT(cache(*root).empty());
|
||||
// XXX Don't get why 1 is legal here
|
||||
cache(*root).insert(root->post(), 1);
|
||||
enqueue_leaf(*root);
|
||||
}
|
||||
|
||||
void model_search::backtrack_level(bool uses_level, model_node& n) {
|
||||
SASSERT(m_root);
|
||||
if (uses_level) {NOT_IMPLEMENTED_YET();}
|
||||
if (uses_level && m_root->level() > n.level()) {
|
||||
n.increase_level();
|
||||
enqueue_leaf(n);
|
||||
}
|
||||
else {
|
||||
model_node* p = n.parent();
|
||||
if (p) {
|
||||
erase_children(*p, true);
|
||||
enqueue_leaf(*p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
obj_map<expr, ptr_vector<model_node> >& model_search::cache(model_node const& n) {
|
||||
unsigned l = n.orig_level();
|
||||
if (l >= m_cache.size()) m_cache.resize(l + 1);
|
||||
return m_cache[l];
|
||||
}
|
||||
|
||||
void model_search::erase_children(model_node& n, bool backtrack) {
|
||||
ptr_vector<model_node> todo, nodes;
|
||||
todo.append(n.children());
|
||||
// detach n from queue
|
||||
n.detach(m_qhead);
|
||||
n.reset();
|
||||
while (!todo.empty()) {
|
||||
model_node* m = todo.back();
|
||||
todo.pop_back();
|
||||
nodes.push_back(m);
|
||||
todo.append(m->children());
|
||||
remove_node(*m, backtrack);
|
||||
}
|
||||
std::for_each(nodes.begin(), nodes.end(), delete_proc<model_node>());
|
||||
}
|
||||
|
||||
// removes node from the search tree and from the cache
|
||||
void model_search::remove_node(model_node& n, bool backtrack) {
|
||||
model_nodes& nodes = cache(n).find(n.post());
|
||||
nodes.erase(&n);
|
||||
n.detach(m_qhead);
|
||||
// TBD: siblings would also fail if n is not a goal.
|
||||
if (!nodes.empty() && backtrack &&
|
||||
nodes[0]->children().empty() && nodes[0]->is_closed()) {
|
||||
model_node* n1 = nodes[0];
|
||||
n1->set_open();
|
||||
enqueue_leaf(*n1);
|
||||
}
|
||||
|
||||
if (nodes.empty()) cache(n).remove(n.post());
|
||||
}
|
||||
|
||||
|
||||
}
|
107
src/muz/spacer/spacer_pdr.h
Normal file
107
src/muz/spacer/spacer_pdr.h
Normal file
|
@ -0,0 +1,107 @@
|
|||
/**++
|
||||
Copyright (c) 2018 Arie Gurfinkel
|
||||
|
||||
Module Name:
|
||||
|
||||
spacer_pdr.h
|
||||
|
||||
Abstract:
|
||||
|
||||
SPACER gPDR strategy implementation
|
||||
|
||||
Author:
|
||||
|
||||
Arie Gurfinkel
|
||||
|
||||
Based on muz/pdr
|
||||
|
||||
Notes:
|
||||
|
||||
--*/
|
||||
#ifndef _SPACER_PDR_H_
|
||||
#define _SPACER_PDR_H_
|
||||
|
||||
#include "muz/spacer/spacer_context.h"
|
||||
|
||||
namespace spacer {
|
||||
// structure for counter-example search.
|
||||
class model_node {
|
||||
pob_ref m_pob; // proof obligation
|
||||
model_node* m_parent; // parent in the search tree
|
||||
ptr_vector<model_node> m_children; // children in the search tree
|
||||
model_node* m_next; // next element of an in-place circular queue
|
||||
model_node* m_prev; // prev element of an in-place circular queue
|
||||
unsigned m_orig_level; // level at which this search node was created
|
||||
unsigned m_depth; //
|
||||
bool m_closed; // whether the pob is derivable
|
||||
public:
|
||||
model_node(model_node* parent, pob_ref &pob);
|
||||
void add_child(model_node &kid);
|
||||
|
||||
expr *post() const {return m_pob->post();}
|
||||
unsigned level() const { return m_pob->level(); }
|
||||
unsigned orig_level() const { return m_orig_level; }
|
||||
unsigned depth() const { return m_depth; }
|
||||
void increase_level() { m_pob->inc_level(); }
|
||||
const pob_ref &pob() const { return m_pob; }
|
||||
ptr_vector<model_node> const& children() { return m_children; }
|
||||
pred_transformer& pt() const { return m_pob->pt(); }
|
||||
model_node* parent() const { return m_parent; }
|
||||
// order in children of the parent
|
||||
unsigned index_in_parent() const;
|
||||
|
||||
bool is_closed() const { return m_closed; }
|
||||
bool is_open() const { return !is_closed(); }
|
||||
|
||||
// closed or has children and they are all closed
|
||||
bool is_1closed() {
|
||||
if (is_closed()) return true;
|
||||
if (m_children.empty()) return false;
|
||||
for (auto kid : m_children) {if (kid->is_open()) return false;}
|
||||
return true;
|
||||
}
|
||||
|
||||
void check_pre_closed();
|
||||
void set_pre_closed() {m_closed = true;}
|
||||
|
||||
void set_closed() {m_closed = true;}
|
||||
void set_open();
|
||||
void reset() {m_children.reset();}
|
||||
|
||||
/// queue
|
||||
|
||||
// remove this node from the given queue
|
||||
void detach(model_node*& qhead);
|
||||
void insert_after(model_node* n);
|
||||
model_node* next() const {return m_next;}
|
||||
bool in_queue() {return m_next && m_prev;}
|
||||
};
|
||||
|
||||
class model_search {
|
||||
typedef ptr_vector<model_node> model_nodes;
|
||||
bool m_bfs;
|
||||
model_node* m_root;
|
||||
model_node* m_qhead;
|
||||
vector<obj_map<expr, model_nodes > > m_cache;
|
||||
obj_map<expr, model_nodes>& cache(model_node const& n);
|
||||
void erase_children(model_node& n, bool backtrack);
|
||||
void remove_node(model_node& n, bool backtrack);
|
||||
void add_leaf(model_node* n); // add leaf to priority queue.
|
||||
|
||||
public:
|
||||
model_search(bool bfs): m_bfs(bfs), m_root(nullptr), m_qhead(nullptr) {}
|
||||
~model_search() {reset();}
|
||||
|
||||
void set_root(model_node* n);
|
||||
|
||||
void reset();
|
||||
model_node* pop_front();
|
||||
void add_leaf(model_node& n); // add fresh node.
|
||||
model_node& get_root() const { return *m_root; }
|
||||
void backtrack_level(bool uses_level, model_node& n);
|
||||
void remove_goal(model_node& n);
|
||||
|
||||
void enqueue_leaf(model_node &n);
|
||||
};
|
||||
}
|
||||
#endif
|
Loading…
Add table
Add a link
Reference in a new issue