mirror of
https://github.com/Z3Prover/z3
synced 2025-04-23 17:15:31 +00:00
reorganizing the code
Signed-off-by: Leonardo de Moura <leonardo@microsoft.com>
This commit is contained in:
parent
61bd5a69ec
commit
12a255e36b
195 changed files with 11 additions and 526 deletions
2
src/dead/spc/README
Normal file
2
src/dead/spc/README
Normal file
|
@ -0,0 +1,2 @@
|
|||
Superposition Calculus.
|
||||
This module is currently disabled.
|
214
src/dead/spc/fvi.h
Normal file
214
src/dead/spc/fvi.h
Normal file
|
@ -0,0 +1,214 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
fvi.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Feature Vector Indexing.
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2008-02-01.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _FVI_H_
|
||||
#define _FVI_H_
|
||||
|
||||
#include"splay_tree_map.h"
|
||||
#include"hashtable.h"
|
||||
#include"vector.h"
|
||||
|
||||
/**
|
||||
\brief A feature vector indexing for objects of type T *.
|
||||
|
||||
ToVector is a functor for converting T into a vector of natural numbers.
|
||||
It should provide a method:
|
||||
- void operator(T * d, unsigned * f);
|
||||
This method should fill the vector f with the features of d.
|
||||
|
||||
Hash: functor for computing the hashcode of T *.
|
||||
|
||||
Eq : functor for comparing T pointers.
|
||||
*/
|
||||
template<typename T, typename ToVector, typename Hash, typename Eq=ptr_eq<T> >
|
||||
class fvi : private ToVector {
|
||||
public:
|
||||
struct statistics {
|
||||
unsigned m_size;
|
||||
unsigned m_num_nodes;
|
||||
unsigned m_num_leaves;
|
||||
unsigned m_min_leaf_size;
|
||||
unsigned m_avg_leaf_size;
|
||||
unsigned m_max_leaf_size;
|
||||
statistics() { reset(); }
|
||||
|
||||
void reset() {
|
||||
m_size = m_num_nodes = m_num_leaves = m_avg_leaf_size = m_max_leaf_size = 0;
|
||||
m_min_leaf_size = UINT_MAX;
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
struct ucompare {
|
||||
int operator()(unsigned i1, unsigned i2) const {
|
||||
if (i1 < i2) return -1;
|
||||
if (i1 > i2) return 1;
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
struct node {
|
||||
node() {}
|
||||
virtual ~node() {}
|
||||
virtual bool is_leaf() const = 0;
|
||||
};
|
||||
|
||||
typedef splay_tree_map<unsigned, node *, ucompare> children;
|
||||
|
||||
struct non_leaf : public node {
|
||||
children m_children;
|
||||
non_leaf() {}
|
||||
|
||||
struct delete_children {
|
||||
void operator()(unsigned k, node * n) const {
|
||||
dealloc(n);
|
||||
}
|
||||
};
|
||||
|
||||
virtual ~non_leaf() {
|
||||
delete_children visitor;
|
||||
m_children.visit(visitor);
|
||||
m_children.reset();
|
||||
}
|
||||
|
||||
virtual bool is_leaf() const { return false; }
|
||||
};
|
||||
|
||||
typedef ptr_hashtable<T, Hash, Eq> set;
|
||||
|
||||
struct leaf : public node {
|
||||
set m_set;
|
||||
leaf() {}
|
||||
virtual ~leaf() {}
|
||||
virtual bool is_leaf() const { return true; }
|
||||
};
|
||||
|
||||
unsigned m_num_features;
|
||||
svector<unsigned> m_tmp_buffer;
|
||||
non_leaf * m_root;
|
||||
|
||||
struct stop {};
|
||||
|
||||
template<typename Visitor>
|
||||
void visit_leaf(leaf * n, Visitor & v, bool le) const {
|
||||
typename set::iterator it = n->m_set.begin();
|
||||
typename set::iterator end = n->m_set.end();
|
||||
for (; it != end; ++it)
|
||||
if (!v(*it))
|
||||
throw stop();
|
||||
}
|
||||
|
||||
template<typename Visitor>
|
||||
struct non_leaf_visitor {
|
||||
fvi const & m_owner;
|
||||
unsigned m_fidx;
|
||||
Visitor & m_visitor;
|
||||
bool m_le;
|
||||
|
||||
non_leaf_visitor(fvi const & o, unsigned fidx, Visitor & v, bool le):
|
||||
m_owner(o), m_fidx(fidx), m_visitor(v), m_le(le) {}
|
||||
|
||||
void operator()(unsigned k, node * n) {
|
||||
if (n->is_leaf())
|
||||
m_owner.visit_leaf(static_cast<leaf*>(n), m_visitor, m_le);
|
||||
else
|
||||
m_owner.visit_non_leaf(static_cast<non_leaf*>(n), m_fidx + 1, m_visitor, m_le);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Visitor>
|
||||
void visit_non_leaf(non_leaf * n, unsigned fidx, Visitor & v, bool le) const {
|
||||
// Remark: this function is recursive, but there is no risk
|
||||
// of stack overflow since the number of features is small.
|
||||
non_leaf_visitor<Visitor> v2(*this, fidx, v, le);
|
||||
if (le)
|
||||
n->m_children.visit_le(v2, m_tmp_buffer[fidx]);
|
||||
else
|
||||
n->m_children.visit_ge(v2, m_tmp_buffer[fidx]);
|
||||
}
|
||||
|
||||
#ifdef Z3DEBUG
|
||||
bool m_visiting;
|
||||
#endif
|
||||
|
||||
void to_fvector(T * d) const {
|
||||
fvi * _this = const_cast<fvi *>(this);
|
||||
_this->ToVector::operator()(d, _this->m_tmp_buffer.c_ptr());
|
||||
}
|
||||
|
||||
struct non_leaf_stat_visitor {
|
||||
fvi const & m_owner;
|
||||
statistics & m_stats;
|
||||
non_leaf_stat_visitor(fvi const & o, statistics & st):m_owner(o), m_stats(st) {}
|
||||
void operator()(unsigned k, node * n);
|
||||
};
|
||||
|
||||
void stats(leaf * n, statistics & result) const;
|
||||
void stats(non_leaf * n, statistics & result) const;
|
||||
|
||||
struct non_leaf_collect_visitor {
|
||||
fvi const & m_owner;
|
||||
ptr_vector<T> & m_elems;
|
||||
non_leaf_collect_visitor(fvi const & o, ptr_vector<T> & elems):m_owner(o), m_elems(elems) {}
|
||||
void operator()(unsigned k, node * n);
|
||||
};
|
||||
|
||||
void collect(leaf * n, ptr_vector<T> & result) const;
|
||||
void collect(non_leaf * n, ptr_vector<T> & result) const;
|
||||
|
||||
public:
|
||||
fvi(unsigned num_features, ToVector const & t = ToVector());
|
||||
~fvi() { reset(); dealloc(m_root); }
|
||||
|
||||
void insert(T * d);
|
||||
bool contains(T * d) const;
|
||||
void erase(T * d);
|
||||
void reset();
|
||||
|
||||
/**
|
||||
\brief Traverse the elements that have features smaller (greater) or equal than the one of the given element.
|
||||
|
||||
For each visited element the following method of v is executed:
|
||||
|
||||
- bool operator()(T * d)
|
||||
|
||||
If false is returned, the traversal is aborted.
|
||||
|
||||
\warning The object cannot be updated during the traversal.
|
||||
*/
|
||||
template<typename Visitor>
|
||||
void visit(T * d, Visitor & v, bool le = true) const {
|
||||
DEBUG_CODE(const_cast<fvi*>(this)->m_visiting = true;);
|
||||
to_fvector(d);
|
||||
try {
|
||||
visit_non_leaf(m_root, 0, v, le);
|
||||
}
|
||||
catch (stop) {
|
||||
}
|
||||
DEBUG_CODE(const_cast<fvi*>(this)->m_visiting = false;);
|
||||
}
|
||||
|
||||
void stats(statistics & result) const;
|
||||
|
||||
/**
|
||||
\brief Copy to result the set of elements stored in the index.
|
||||
*/
|
||||
void collect(ptr_vector<T> & result) const;
|
||||
};
|
||||
|
||||
#endif /* _FVI_H_ */
|
199
src/dead/spc/fvi_def.h
Normal file
199
src/dead/spc/fvi_def.h
Normal file
|
@ -0,0 +1,199 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
fvi_def.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Feature Vector Indexing.
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2008-02-01.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _FVI_DEF_H_
|
||||
#define _FVI_DEF_H_
|
||||
|
||||
#include"fvi.h"
|
||||
#include"splay_tree_def.h"
|
||||
#include"buffer.h"
|
||||
|
||||
template<typename T, typename ToVector, typename Hash, typename Eq>
|
||||
fvi<T, ToVector, Hash, Eq>::fvi(unsigned num_features, ToVector const & t):
|
||||
ToVector(t),
|
||||
m_num_features(num_features),
|
||||
m_root(0) {
|
||||
m_tmp_buffer.resize(num_features, 0);
|
||||
m_root = alloc(non_leaf);
|
||||
SASSERT(num_features >= 2);
|
||||
DEBUG_CODE(m_visiting = false;);
|
||||
}
|
||||
|
||||
template<typename T, typename ToVector, typename Hash, typename Eq>
|
||||
void fvi<T, ToVector, Hash, Eq>::reset() {
|
||||
SASSERT(!m_visiting);
|
||||
dealloc(m_root);
|
||||
m_root = alloc(non_leaf);
|
||||
}
|
||||
|
||||
template<typename T, typename ToVector, typename Hash, typename Eq>
|
||||
void fvi<T, ToVector, Hash, Eq>::insert(T * d) {
|
||||
SASSERT(!m_visiting);
|
||||
to_fvector(d);
|
||||
non_leaf * n = m_root;
|
||||
unsigned i = 0;
|
||||
for (; i < m_num_features - 1; i++) {
|
||||
node * child = 0;
|
||||
if (!n->m_children.find(m_tmp_buffer[i], child)) {
|
||||
child = alloc(non_leaf);
|
||||
n->m_children.insert(m_tmp_buffer[i], child);
|
||||
}
|
||||
SASSERT(child);
|
||||
SASSERT(!child->is_leaf());
|
||||
n = static_cast<non_leaf*>(child);
|
||||
}
|
||||
node * l = 0;
|
||||
SASSERT(i == m_num_features - 1);
|
||||
if (!n->m_children.find(m_tmp_buffer[i], l)) {
|
||||
l = alloc(leaf);
|
||||
n->m_children.insert(m_tmp_buffer[i], l);
|
||||
}
|
||||
SASSERT(l);
|
||||
SASSERT(l->is_leaf());
|
||||
static_cast<leaf*>(l)->m_set.insert(d);
|
||||
}
|
||||
|
||||
template<typename T, typename ToVector, typename Hash, typename Eq>
|
||||
bool fvi<T, ToVector, Hash, Eq>::contains(T * d) const {
|
||||
to_fvector(d);
|
||||
non_leaf * n = m_root;
|
||||
node * child;
|
||||
unsigned i = 0;
|
||||
for (; i < m_num_features - 1; i++) {
|
||||
if (!n->m_children.find(m_tmp_buffer[i], child))
|
||||
return false;
|
||||
SASSERT(child);
|
||||
SASSERT(!child->is_leaf());
|
||||
n = static_cast<non_leaf*>(child);
|
||||
}
|
||||
SASSERT(i == m_num_features - 1);
|
||||
return
|
||||
n->m_children.find(m_tmp_buffer[i], child) &&
|
||||
static_cast<leaf*>(child)->m_set.contains(d);
|
||||
}
|
||||
|
||||
template<typename T, typename ToVector, typename Hash, typename Eq>
|
||||
void fvi<T, ToVector, Hash, Eq>::erase(T * d) {
|
||||
SASSERT(!m_visiting);
|
||||
SASSERT(contains(d));
|
||||
ptr_buffer<non_leaf> path;
|
||||
to_fvector(d);
|
||||
non_leaf * n = m_root;
|
||||
node * child;
|
||||
unsigned i = 0;
|
||||
for (; i < m_num_features - 1; i++) {
|
||||
path.push_back(n);
|
||||
if (!n->m_children.find(m_tmp_buffer[i], child)) {
|
||||
UNREACHABLE();
|
||||
}
|
||||
SASSERT(child);
|
||||
SASSERT(!child->is_leaf());
|
||||
n = static_cast<non_leaf*>(child);
|
||||
}
|
||||
path.push_back(n);
|
||||
SASSERT(i == m_num_features - 1);
|
||||
if (!n->m_children.find(m_tmp_buffer[i], child)) {
|
||||
UNREACHABLE();
|
||||
}
|
||||
SASSERT(child);
|
||||
SASSERT(child->is_leaf());
|
||||
leaf * l = static_cast<leaf*>(child);
|
||||
l->m_set.erase(d);
|
||||
if (l->m_set.empty()) {
|
||||
dealloc(l);
|
||||
while (true) {
|
||||
non_leaf * n = path.back();
|
||||
n->m_children.erase(m_tmp_buffer[i]);
|
||||
path.pop_back();
|
||||
i--;
|
||||
if (!n->m_children.empty() || n == m_root)
|
||||
break;
|
||||
dealloc(n);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T, typename ToVector, typename Hash, typename Eq>
|
||||
void fvi<T, ToVector, Hash, Eq>::non_leaf_stat_visitor::operator()(unsigned k, node * n) {
|
||||
if (n->is_leaf())
|
||||
m_owner.stats(static_cast<leaf*>(n), m_stats);
|
||||
else
|
||||
m_owner.stats(static_cast<non_leaf*>(n), m_stats);
|
||||
}
|
||||
|
||||
template<typename T, typename ToVector, typename Hash, typename Eq>
|
||||
void fvi<T, ToVector, Hash, Eq>::stats(leaf * n, statistics & result) const {
|
||||
unsigned sz = n->m_set.size();
|
||||
result.m_size += sz;
|
||||
if (sz > result.m_max_leaf_size)
|
||||
result.m_max_leaf_size = sz;
|
||||
if (sz < result.m_min_leaf_size)
|
||||
result.m_min_leaf_size = sz;
|
||||
result.m_num_leaves ++;
|
||||
result.m_num_nodes ++;
|
||||
}
|
||||
|
||||
template<typename T, typename ToVector, typename Hash, typename Eq>
|
||||
void fvi<T, ToVector, Hash, Eq>::stats(non_leaf * n, statistics & result) const {
|
||||
result.m_num_nodes++;
|
||||
// Remark: this function is recursive, but there is no risk
|
||||
// of stack overflow since the number of features is small.
|
||||
non_leaf_stat_visitor v(*this, result);
|
||||
n->m_children.visit(v);
|
||||
}
|
||||
|
||||
template<typename T, typename ToVector, typename Hash, typename Eq>
|
||||
void fvi<T, ToVector, Hash, Eq>::stats(statistics & result) const {
|
||||
result.reset();
|
||||
stats(m_root, result);
|
||||
if (m_root->m_children.empty())
|
||||
result.m_min_leaf_size = 0;
|
||||
if (result.m_num_leaves > 0)
|
||||
result.m_avg_leaf_size = result.m_size / result.m_num_leaves;
|
||||
}
|
||||
|
||||
template<typename T, typename ToVector, typename Hash, typename Eq>
|
||||
void fvi<T, ToVector, Hash, Eq>::non_leaf_collect_visitor::operator()(unsigned k, node * n) {
|
||||
if (n->is_leaf())
|
||||
m_owner.collect(static_cast<leaf*>(n), m_elems);
|
||||
else
|
||||
m_owner.collect(static_cast<non_leaf*>(n), m_elems);
|
||||
}
|
||||
|
||||
template<typename T, typename ToVector, typename Hash, typename Eq>
|
||||
void fvi<T, ToVector, Hash, Eq>::collect(leaf * n, ptr_vector<T> & result) const {
|
||||
typename set::iterator it = n->m_set.begin();
|
||||
typename set::iterator end = n->m_set.end();
|
||||
for (; it != end; ++it)
|
||||
result.push_back(*it);
|
||||
}
|
||||
|
||||
template<typename T, typename ToVector, typename Hash, typename Eq>
|
||||
void fvi<T, ToVector, Hash, Eq>::collect(non_leaf * n, ptr_vector<T> & result) const {
|
||||
// Remark: this function is recursive, but there is no risk
|
||||
// of stack overflow since the number of features is small.
|
||||
non_leaf_collect_visitor v(*this, result);
|
||||
n->m_children.visit(v);
|
||||
}
|
||||
|
||||
template<typename T, typename ToVector, typename Hash, typename Eq>
|
||||
void fvi<T, ToVector, Hash, Eq>::collect(ptr_vector<T> & result) const {
|
||||
collect(m_root, result);
|
||||
}
|
||||
|
||||
#endif /* _FVI_DEF_H_ */
|
276
src/dead/spc/kbo.cpp
Normal file
276
src/dead/spc/kbo.cpp
Normal file
|
@ -0,0 +1,276 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
kbo.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Knuth-Bendix ordering.
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2008-01-28.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#include"kbo.h"
|
||||
#include"ast_pp.h"
|
||||
|
||||
inline unsigned kbo::f_weight(func_decl * f) const {
|
||||
// TODO
|
||||
return 1;
|
||||
}
|
||||
|
||||
inline unsigned kbo::var_weight() const {
|
||||
return m_var_weight;
|
||||
}
|
||||
|
||||
inline void kbo::reset() {
|
||||
m_weight_balance = 0;
|
||||
m_deltas.reset();
|
||||
m_num_pos = 0;
|
||||
m_num_neg = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Increase the balance of the given variable.
|
||||
*/
|
||||
inline void kbo::inc(expr_offset v) {
|
||||
SASSERT(is_var(v.get_expr()));
|
||||
int val;
|
||||
unsigned v_idx = to_var(v.get_expr())->get_idx();
|
||||
unsigned offset = v.get_offset();
|
||||
if (m_deltas.find(v_idx, offset, val)) {
|
||||
if (val == -1)
|
||||
m_num_neg--;
|
||||
else if (val == 0)
|
||||
m_num_pos++;
|
||||
m_deltas.insert(v_idx, offset, val + 1);
|
||||
}
|
||||
else {
|
||||
m_deltas.insert(v_idx, offset, 1);
|
||||
m_num_pos ++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Decreate the balance of the given variable.
|
||||
*/
|
||||
inline void kbo::dec(expr_offset v) {
|
||||
int val;
|
||||
unsigned v_idx = to_var(v.get_expr())->get_idx();
|
||||
unsigned offset = v.get_offset();
|
||||
if (m_deltas.find(v_idx, offset, val)) {
|
||||
if (val == 0)
|
||||
m_num_neg++;
|
||||
else if (val == 1)
|
||||
m_num_pos--;
|
||||
m_deltas.insert(v_idx, offset, val - 1);
|
||||
}
|
||||
else {
|
||||
m_deltas.insert(v_idx, offset, -1);
|
||||
m_num_neg ++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Accumulate the variables and weight balance of t. Return
|
||||
true if t contains target_var.
|
||||
*/
|
||||
template<bool pos>
|
||||
bool kbo::VWBc(expr_offset t, expr_offset target_var) {
|
||||
SASSERT(target_var.get_expr() == 0 || is_var(target_var.get_expr()));
|
||||
svector<expr_offset> & todo = m_vwbc_todo;
|
||||
expr_offset s;
|
||||
bool found = false;
|
||||
unsigned j;
|
||||
SASSERT(todo.empty());
|
||||
todo.push_back(t);
|
||||
while (!todo.empty()) {
|
||||
t = todo.back();
|
||||
if (t == target_var)
|
||||
found = true;
|
||||
expr * n = t.get_expr();
|
||||
unsigned offset = t.get_offset();
|
||||
todo.pop_back();
|
||||
switch (n->get_kind()) {
|
||||
case AST_VAR:
|
||||
if (m_subst && m_subst->find(to_var(n), offset, s))
|
||||
todo.push_back(s);
|
||||
else if (pos) {
|
||||
inc(t);
|
||||
m_weight_balance += var_weight();
|
||||
}
|
||||
else {
|
||||
dec(t);
|
||||
m_weight_balance -= var_weight();
|
||||
}
|
||||
break;
|
||||
case AST_APP:
|
||||
if (pos)
|
||||
m_weight_balance += f_weight(to_app(n)->get_decl());
|
||||
else
|
||||
m_weight_balance -= f_weight(to_app(n)->get_decl());
|
||||
j = to_app(n)->get_num_args();
|
||||
while (j > 0) {
|
||||
--j;
|
||||
todo.push_back(expr_offset(to_app(n)->get_arg(j), offset));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
break;
|
||||
}
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
template<bool pos>
|
||||
inline void kbo::VWB(expr_offset t, unsigned idx) {
|
||||
expr_offset null(0, 0);
|
||||
app * n = to_app(t.get_expr());
|
||||
unsigned num = n->get_num_args();
|
||||
for (; idx < num; idx++)
|
||||
VWBc<pos>(expr_offset(n->get_arg(idx), t.get_offset()), null);
|
||||
}
|
||||
|
||||
inline bool is_unary_app(expr * n) {
|
||||
return is_app(n) && to_app(n)->get_num_args() == 1;
|
||||
}
|
||||
|
||||
inline kbo::result kbo::no_neg() const {
|
||||
return m_num_neg == 0 ? GREATER : UNCOMPARABLE;
|
||||
}
|
||||
|
||||
inline kbo::result kbo::no_pos() const {
|
||||
return m_num_pos == 0 ? LESSER : UNCOMPARABLE;
|
||||
}
|
||||
|
||||
order::result kbo::compare(expr_offset const & t1, expr_offset const & t2, substitution * s) {
|
||||
reset();
|
||||
m_subst = s;
|
||||
|
||||
if (t1 == t2)
|
||||
return EQUAL;
|
||||
|
||||
expr * n1 = t1.get_expr();
|
||||
expr * n2 = t2.get_expr();
|
||||
|
||||
// f(s) >_{kbo} f(t) iff s >_{kbo} t
|
||||
while (is_unary_app(n1) && is_unary_app(n2) && to_app(n1)->get_decl() == to_app(n2)->get_decl()) {
|
||||
n1 = to_app(n1)->get_arg(0);
|
||||
n2 = to_app(n2)->get_arg(0);
|
||||
}
|
||||
|
||||
svector<entry> & todo = m_compare_todo;
|
||||
SASSERT(todo.empty());
|
||||
todo.push_back(entry(find(expr_offset(n1, t1.get_offset())),
|
||||
find(expr_offset(n2, t2.get_offset())),
|
||||
0));
|
||||
|
||||
result res = UNKNOWN;
|
||||
|
||||
while (!todo.empty()) {
|
||||
entry & e = todo.back();
|
||||
expr_offset t1 = e.m_t1;
|
||||
expr_offset t2 = e.m_t2;
|
||||
expr * n1 = t1.get_expr();
|
||||
expr * n2 = t2.get_expr();
|
||||
TRACE("kbo", tout << "processing with idx: " << e.m_idx << "\n" <<
|
||||
mk_pp(n1, m_manager) << "\n" << mk_pp(n2, m_manager) << "\n";
|
||||
tout << "wb : " << m_weight_balance << "\n";);
|
||||
SASSERT(!is_quantifier(n1) && !is_quantifier(n2));
|
||||
bool v1 = is_var(n1);
|
||||
bool v2 = is_var(n2);
|
||||
if (v1 && v2) {
|
||||
todo.pop_back();
|
||||
inc(t1);
|
||||
dec(t2);
|
||||
res = t1 == t2 ? EQUAL : UNCOMPARABLE;
|
||||
}
|
||||
else if (v1) {
|
||||
todo.pop_back();
|
||||
res = VWBc<false>(t2, t1) ? LESSER : UNCOMPARABLE;
|
||||
inc(t1);
|
||||
m_weight_balance += var_weight();
|
||||
}
|
||||
else if (v2) {
|
||||
todo.pop_back();
|
||||
res = VWBc<true>(t1, t2) ? GREATER : UNCOMPARABLE;
|
||||
dec(t2);
|
||||
m_weight_balance -= var_weight();
|
||||
}
|
||||
else {
|
||||
func_decl * f = to_app(n1)->get_decl();
|
||||
func_decl * g = to_app(n2)->get_decl();
|
||||
result lex;
|
||||
if (f != g || to_app(n1)->get_num_args() != to_app(n2)->get_num_args()) {
|
||||
VWB<true>(t1, 0);
|
||||
VWB<false>(t2, 0);
|
||||
lex = UNCOMPARABLE;
|
||||
}
|
||||
else {
|
||||
unsigned & idx = e.m_idx;
|
||||
// when idx > 0, res contains the result for child (idx - 1)
|
||||
if (idx > 0 && res != EQUAL) {
|
||||
VWB<true>(t1, idx);
|
||||
VWB<false>(t2, idx);
|
||||
lex = res;
|
||||
}
|
||||
else if (idx == to_app(n1)->get_num_args()) {
|
||||
// all children were visited
|
||||
lex = EQUAL;
|
||||
}
|
||||
else if (idx < to_app(n1)->get_num_args()) {
|
||||
expr_offset c1 = find(expr_offset(to_app(n1)->get_arg(idx), t1.get_offset()));
|
||||
expr_offset c2 = find(expr_offset(to_app(n2)->get_arg(idx), t2.get_offset()));
|
||||
idx++; // move curr entry child idx
|
||||
entry new_entry(c1, c2, 0);
|
||||
todo.push_back(new_entry);
|
||||
continue; // process child before continuing
|
||||
}
|
||||
}
|
||||
|
||||
todo.pop_back();
|
||||
m_weight_balance += f_weight(f);
|
||||
m_weight_balance -= f_weight(g);
|
||||
|
||||
if (m_weight_balance > 0)
|
||||
res = no_neg();
|
||||
else if (m_weight_balance < 0)
|
||||
res = no_pos();
|
||||
else if (f_greater(f, g))
|
||||
res = no_neg();
|
||||
else if (f_greater(g, f))
|
||||
res = no_pos();
|
||||
else if (f != g)
|
||||
res = UNCOMPARABLE;
|
||||
else if (lex == EQUAL)
|
||||
res = EQUAL;
|
||||
else if (lex == GREATER)
|
||||
res = no_neg();
|
||||
else if (lex == LESSER)
|
||||
res = no_pos();
|
||||
else
|
||||
res = UNCOMPARABLE;
|
||||
}
|
||||
TRACE("kbo", tout << "result: " << res << "\n";);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
bool kbo::greater(expr_offset const & t1, expr_offset const & t2, substitution * s) {
|
||||
return compare(t1, t2, s) == GREATER;
|
||||
}
|
||||
|
||||
int kbo::compare_ge(expr_offset const & t1, expr_offset const & t2, substitution * s) {
|
||||
switch (compare(t1, t2, s)) {
|
||||
case GREATER: return 1;
|
||||
case EQUAL: return 0;
|
||||
default: return -1;
|
||||
}
|
||||
}
|
70
src/dead/spc/kbo.h
Normal file
70
src/dead/spc/kbo.h
Normal file
|
@ -0,0 +1,70 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
kbo.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Knuth-Bendix ordering.
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2008-01-28.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _KBO_H_
|
||||
#define _KBO_H_
|
||||
|
||||
#include"order.h"
|
||||
|
||||
class kbo : public order {
|
||||
struct entry {
|
||||
expr_offset m_t1;
|
||||
expr_offset m_t2;
|
||||
unsigned m_idx;
|
||||
entry():m_idx(UINT_MAX) {}
|
||||
entry(expr_offset const & t1, expr_offset const & t2, unsigned idx):
|
||||
m_t1(t1), m_t2(t2), m_idx(idx) {}
|
||||
};
|
||||
|
||||
unsigned m_var_weight;
|
||||
int m_weight_balance;
|
||||
var_offset_map<int> m_deltas;
|
||||
unsigned m_num_pos;
|
||||
unsigned m_num_neg;
|
||||
svector<expr_offset> m_vwbc_todo;
|
||||
svector<entry> m_compare_todo;
|
||||
|
||||
unsigned f_weight(func_decl * f) const;
|
||||
unsigned var_weight() const;
|
||||
|
||||
void reset();
|
||||
void inc(expr_offset v);
|
||||
void dec(expr_offset v);
|
||||
|
||||
template<bool pos>
|
||||
bool VWBc(expr_offset t, expr_offset target_var);
|
||||
|
||||
template<bool pos>
|
||||
void VWB(expr_offset t, unsigned idx);
|
||||
|
||||
result no_neg() const;
|
||||
result no_pos() const;
|
||||
|
||||
public:
|
||||
kbo(ast_manager & m, precedence * p, unsigned var_weight = 1):order(m, p), m_var_weight(var_weight) {}
|
||||
virtual ~kbo() {}
|
||||
virtual void reserve(unsigned num_offsets, unsigned num_vars) { m_deltas.reserve(num_offsets, num_vars); }
|
||||
virtual void reserve_offsets(unsigned num_offsets) { m_deltas.reserve_offsets(num_offsets); }
|
||||
virtual void reserve_vars(unsigned num_vars) { m_deltas.reserve_vars(num_vars); }
|
||||
virtual result compare(expr_offset const & t1, expr_offset const & t2, substitution * s);
|
||||
result compare(expr * t1, expr * t2) { return compare(expr_offset(t1, 0), expr_offset(t2, 0), 0); }
|
||||
virtual bool greater(expr_offset const & t1, expr_offset const & t2, substitution * s);
|
||||
virtual int compare_ge(expr_offset const & t1, expr_offset const & t2, substitution * s);
|
||||
};
|
||||
|
||||
#endif /* _KBO_H_ */
|
184
src/dead/spc/lpo.cpp
Normal file
184
src/dead/spc/lpo.cpp
Normal file
|
@ -0,0 +1,184 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
lpo.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Lexicographical Path Ordering
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2008-02-01.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#include"lpo.h"
|
||||
|
||||
/**
|
||||
\brief Check whether the variable in t1 occurs in t2.
|
||||
*/
|
||||
bool lpo::occurs(expr_offset const & t1, expr_offset const & t2) {
|
||||
SASSERT(is_var(t1.get_expr()));
|
||||
if (is_ground(t2.get_expr()))
|
||||
return false;
|
||||
m_todo.reset();
|
||||
m_todo.push_back(t2);
|
||||
while (!m_todo.empty()) {
|
||||
expr_offset t = m_todo.back();
|
||||
m_todo.pop_back();
|
||||
t = find(t);
|
||||
expr * n = t.get_expr();
|
||||
if (is_ground(n))
|
||||
continue;
|
||||
unsigned offset = t.get_offset();
|
||||
unsigned j;
|
||||
switch (n->get_kind()) {
|
||||
case AST_VAR:
|
||||
if (t == t1)
|
||||
return true;
|
||||
break;
|
||||
case AST_APP:
|
||||
j = to_app(n)->get_num_args();
|
||||
while (j > 0) {
|
||||
--j;
|
||||
expr * arg = to_app(n)->get_arg(j);
|
||||
if (!is_ground(arg))
|
||||
m_todo.push_back(expr_offset(arg, offset));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool lpo::greater(expr_offset s, expr_offset t, unsigned depth) {
|
||||
return lpo::compare(s, t, depth) == GREATER;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Return true if s >_{lpo} t_i forall children t_i of t.
|
||||
*/
|
||||
bool lpo::dominates_args(expr_offset s, expr_offset t, unsigned depth) {
|
||||
SASSERT(is_app(t.get_expr()));
|
||||
unsigned num_args = to_app(t.get_expr())->get_num_args();
|
||||
unsigned off = t.get_offset();
|
||||
for (unsigned i = 0; i < num_args; i++) {
|
||||
expr * t_i = to_app(t.get_expr())->get_arg(i);
|
||||
if (!greater(s, expr_offset(t_i, off), depth+1))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Return true if s_i >=_{lpo} t for some arg s_i of s.
|
||||
*/
|
||||
bool lpo::arg_dominates_expr(expr_offset s, expr_offset t, unsigned depth) {
|
||||
SASSERT(is_app(s.get_expr()));
|
||||
unsigned num_args = to_app(s.get_expr())->get_num_args();
|
||||
unsigned off = s.get_offset();
|
||||
for (unsigned i = 0; i < num_args; i++) {
|
||||
expr * s_i = to_app(s.get_expr())->get_arg(i);
|
||||
result r = compare(expr_offset(s_i, off), t, depth+1);
|
||||
if (r == EQUAL || r == GREATER)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
order::result lpo::lex_compare(expr_offset s, expr_offset t, unsigned depth) {
|
||||
SASSERT(is_app(s.get_expr()));
|
||||
SASSERT(is_app(t.get_expr()));
|
||||
app * _s = to_app(s.get_expr());
|
||||
app * _t = to_app(t.get_expr());
|
||||
unsigned num_args1 = _s->get_num_args();
|
||||
unsigned num_args2 = _t->get_num_args();
|
||||
unsigned num_args = std::min(num_args1, num_args2);
|
||||
unsigned off1 = s.get_offset();
|
||||
unsigned off2 = t.get_offset();
|
||||
result r = EQUAL;
|
||||
for (unsigned i = 0; i < num_args; i++) {
|
||||
r = compare(expr_offset(_s->get_arg(i), off1), expr_offset(_t->get_arg(i), off2), depth+1);
|
||||
if (r != EQUAL)
|
||||
break;
|
||||
}
|
||||
if (r == EQUAL) {
|
||||
if (num_args1 > num_args2)
|
||||
return GREATER;
|
||||
if (num_args1 < num_args2)
|
||||
return NOT_GTEQ;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
inline order::result lpo::compare_core(expr_offset s, expr_offset t, unsigned depth) {
|
||||
s = find(s);
|
||||
t = find(t);
|
||||
|
||||
if (max_depth(depth))
|
||||
return UNKNOWN;
|
||||
|
||||
if (is_var(s.get_expr()))
|
||||
return s == t ? EQUAL : UNCOMPARABLE;
|
||||
else if (is_var(t.get_expr()))
|
||||
return occurs(t, s) ? GREATER : UNCOMPARABLE;
|
||||
else {
|
||||
func_decl * f = to_app(s.get_expr())->get_decl();
|
||||
func_decl * g = to_app(t.get_expr())->get_decl();
|
||||
if (f_greater(f, g))
|
||||
return dominates_args(s, t, depth) ? GREATER : NOT_GTEQ;
|
||||
else if (f != g)
|
||||
return arg_dominates_expr(s, t, depth) ? GREATER : NOT_GTEQ;
|
||||
else {
|
||||
result r = lex_compare(s, t, depth);
|
||||
if (r == GREATER) {
|
||||
if (dominates_args(s, t, depth))
|
||||
return GREATER;
|
||||
}
|
||||
else if (r == EQUAL)
|
||||
return EQUAL;
|
||||
return to_app(s.get_expr())->get_num_args() > 1 && arg_dominates_expr(s, t, depth) ? GREATER : NOT_GTEQ;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
order::result lpo::compare(expr_offset s, expr_offset t, unsigned depth) {
|
||||
TRACE("lpo", tout << "comparing:\n" << mk_pp(s.get_expr(), m_manager) << "\n" << mk_pp(t.get_expr(), m_manager) << "\n";);
|
||||
result r = compare_core(s, t, depth);
|
||||
TRACE("lpo", tout << "result of comparing:\n" << mk_pp(s.get_expr(), m_manager) << "\n" << mk_pp(t.get_expr(), m_manager) << "\nresult: " << r << "\n";);
|
||||
return r;
|
||||
}
|
||||
|
||||
bool lpo::greater(expr_offset const & t1, expr_offset const & t2, substitution * s) {
|
||||
m_subst = s;
|
||||
return greater(t1, t2, static_cast<unsigned>(0));
|
||||
}
|
||||
|
||||
order::result lpo::compare(expr_offset const & t1, expr_offset const & t2, substitution * s) {
|
||||
m_subst = s;
|
||||
result r = compare(t1, t2, static_cast<unsigned>(0));
|
||||
if (r != NOT_GTEQ)
|
||||
return r;
|
||||
r = compare(t2, t1, static_cast<unsigned>(0));
|
||||
if (r == GREATER)
|
||||
return LESSER;
|
||||
if (r == UNKNOWN)
|
||||
return UNKNOWN;
|
||||
return UNCOMPARABLE;
|
||||
}
|
||||
|
||||
int lpo::compare_ge(expr_offset const & t1, expr_offset const & t2, substitution * s) {
|
||||
m_subst = s;
|
||||
result r = compare(t1, t2, static_cast<unsigned>(0));
|
||||
switch (r) {
|
||||
case GREATER: return 1;
|
||||
case EQUAL: return 0;
|
||||
default: return -1;
|
||||
}
|
||||
}
|
49
src/dead/spc/lpo.h
Normal file
49
src/dead/spc/lpo.h
Normal file
|
@ -0,0 +1,49 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
lpo.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Lexicographical Path Ordering
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2008-02-01.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _LPO_H_
|
||||
#define _LPO_H_
|
||||
|
||||
#include"order.h"
|
||||
#include"vector.h"
|
||||
#include"map.h"
|
||||
|
||||
class lpo : public order {
|
||||
svector<expr_offset> m_todo;
|
||||
|
||||
bool occurs(expr_offset const & t1, expr_offset const & t2);
|
||||
bool greater(expr_offset s, expr_offset t, unsigned depth);
|
||||
bool dominates_args(expr_offset s, expr_offset t, unsigned depth);
|
||||
bool arg_dominates_expr(expr_offset s, expr_offset t, unsigned depth);
|
||||
result lex_compare(expr_offset s, expr_offset t, unsigned depth);
|
||||
result compare_core(expr_offset s, expr_offset t, unsigned depth);
|
||||
result compare(expr_offset s, expr_offset t, unsigned depth);
|
||||
bool max_depth(unsigned d) { /* TODO */ return false; }
|
||||
public:
|
||||
lpo(ast_manager & m, precedence * p):order(m, p) {}
|
||||
virtual ~lpo() {}
|
||||
|
||||
virtual result compare(expr_offset const & t1, expr_offset const & t2, substitution * s);
|
||||
result compare(expr * t1, expr * t2) { return compare(expr_offset(t1, 0), expr_offset(t2, 0), static_cast<substitution*>(0)); }
|
||||
|
||||
virtual bool greater(expr_offset const & t1, expr_offset const & t2, substitution * s);
|
||||
bool greater(expr_offset const & t1, expr_offset const & t2) { return greater(t1, t2); }
|
||||
virtual int compare_ge(expr_offset const & t1, expr_offset const & t2, substitution * s);
|
||||
};
|
||||
|
||||
#endif /* _LPO_H_ */
|
56
src/dead/spc/marker.h
Normal file
56
src/dead/spc/marker.h
Normal file
|
@ -0,0 +1,56 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
marker.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Auxiliary object for managing markings
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2008-02-07.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _MARKER_H_
|
||||
#define _MARKER_H_
|
||||
|
||||
#include"vector.h"
|
||||
|
||||
/**
|
||||
\brief Keep track of all marked objects. Unmark them when the method
|
||||
unmark or destructor is invoked.
|
||||
*/
|
||||
template<typename T>
|
||||
class marker {
|
||||
ptr_vector<T> m_to_unmark;
|
||||
public:
|
||||
~marker() {
|
||||
unmark();
|
||||
}
|
||||
|
||||
void mark(T * obj) {
|
||||
obj->set_mark(true);
|
||||
m_to_unmark.push_back(obj);
|
||||
}
|
||||
|
||||
bool is_marked(T * obj) const {
|
||||
return obj->is_marked();
|
||||
}
|
||||
|
||||
void unmark() {
|
||||
typename ptr_vector<T>::iterator it = m_to_unmark.begin();
|
||||
typename ptr_vector<T>::iterator end = m_to_unmark.end();
|
||||
for (; it != end; ++it) {
|
||||
T * obj = *it;
|
||||
obj->set_mark(false);
|
||||
}
|
||||
m_to_unmark.reset();
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* _MARKER_H_ */
|
88
src/dead/spc/normalize_vars.cpp
Normal file
88
src/dead/spc/normalize_vars.cpp
Normal file
|
@ -0,0 +1,88 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
normalize_vars.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
<abstract>
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2008-02-16.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#include"normalize_vars.h"
|
||||
|
||||
expr * normalize_vars::operator()(expr * n) {
|
||||
SASSERT(m_todo.empty());
|
||||
m_todo.push_back(n);
|
||||
while (!m_todo.empty()) {
|
||||
n = m_todo.back();
|
||||
if (m_cache.contains(n)) {
|
||||
m_todo.pop_back();
|
||||
continue;
|
||||
}
|
||||
if (is_var(n)) {
|
||||
m_todo.pop_back();
|
||||
unsigned idx = to_var(n)->get_idx();
|
||||
var * new_var = m_map.get(idx, 0);
|
||||
if (new_var == 0) {
|
||||
new_var = m_manager.mk_var(m_next_var, to_var(n)->get_sort());
|
||||
m_next_var++;
|
||||
m_new_vars.push_back(new_var);
|
||||
m_map.setx(idx, new_var, 0);
|
||||
}
|
||||
SASSERT(new_var->get_sort() == to_var(n)->get_sort());
|
||||
m_cache.insert(n, new_var);
|
||||
}
|
||||
else {
|
||||
SASSERT(is_app(n));
|
||||
bool visited = true;
|
||||
unsigned num_args = to_app(n)->get_num_args();
|
||||
unsigned j = num_args;
|
||||
while (j > 0) {
|
||||
--j;
|
||||
expr * child = to_app(n)->get_arg(j);
|
||||
if (!m_cache.contains(child)) {
|
||||
m_todo.push_back(child);
|
||||
visited = false;
|
||||
}
|
||||
}
|
||||
if (visited) {
|
||||
m_todo.pop_back();
|
||||
m_new_children.reset();
|
||||
bool modified = false;
|
||||
for (unsigned i = 0; i < num_args; i++) {
|
||||
expr * child = to_app(n)->get_arg(i);
|
||||
expr * new_child = 0;
|
||||
m_cache.find(child, new_child);
|
||||
SASSERT(new_child);
|
||||
if (child != new_child)
|
||||
modified = true;
|
||||
m_new_children.push_back(new_child);
|
||||
}
|
||||
if (!modified)
|
||||
m_cache.insert(n, n);
|
||||
else
|
||||
m_cache.insert(n, m_manager.mk_app(to_app(n)->get_decl(), m_new_children.size(), m_new_children.c_ptr()));
|
||||
}
|
||||
}
|
||||
}
|
||||
expr * r = 0;
|
||||
m_cache.find(n, r);
|
||||
SASSERT(r);
|
||||
return r;
|
||||
}
|
||||
|
||||
void normalize_vars::reset() {
|
||||
m_cache.reset();
|
||||
m_map.reset();
|
||||
m_new_vars.reset();
|
||||
m_next_var = 0;
|
||||
}
|
||||
|
47
src/dead/spc/normalize_vars.h
Normal file
47
src/dead/spc/normalize_vars.h
Normal file
|
@ -0,0 +1,47 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
normalize_vars.h
|
||||
|
||||
Abstract:
|
||||
|
||||
<abstract>
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2008-02-16.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _NORMALIZE_VARS_H_
|
||||
#define _NORMALIZE_VARS_H_
|
||||
|
||||
#include"ast.h"
|
||||
#include"obj_hashtable.h"
|
||||
|
||||
class normalize_vars {
|
||||
ast_manager & m_manager;
|
||||
var_ref_vector m_new_vars;
|
||||
unsigned m_next_var;
|
||||
ptr_vector<var> m_map;
|
||||
typedef obj_map<expr, expr *> cache;
|
||||
cache m_cache;
|
||||
ptr_vector<expr> m_todo;
|
||||
ptr_vector<expr> m_new_children;
|
||||
public:
|
||||
normalize_vars(ast_manager & m):
|
||||
m_manager(m),
|
||||
m_new_vars(m) {
|
||||
}
|
||||
|
||||
expr * operator()(expr * n);
|
||||
void reset();
|
||||
unsigned get_num_vars() const { return m_new_vars.size(); }
|
||||
var * const * get_vars() const { return m_new_vars.c_ptr(); }
|
||||
};
|
||||
|
||||
#endif /* _NORMALIZE_VARS_H_ */
|
||||
|
51
src/dead/spc/order.cpp
Normal file
51
src/dead/spc/order.cpp
Normal file
|
@ -0,0 +1,51 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
order.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
<abstract>
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2008-02-15.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#include"order.h"
|
||||
|
||||
bool order::equal(expr_offset const & _t1, expr_offset const & _t2, substitution * s) {
|
||||
if (_t1 == _t2)
|
||||
return true;
|
||||
if (s == 0)
|
||||
return false;
|
||||
m_eq_todo.reset();
|
||||
m_eq_todo.push_back(expr_offset_pair(_t1, _t2));
|
||||
while (!m_eq_todo.empty()) {
|
||||
expr_offset_pair const & p = m_eq_todo.back();
|
||||
expr_offset t1 = find(p.first);
|
||||
expr_offset t2 = find(p.second);
|
||||
m_eq_todo.pop_back();
|
||||
if (t1 == t2)
|
||||
continue;
|
||||
expr * n1 = t1.get_expr();
|
||||
expr * n2 = t2.get_expr();
|
||||
if (!is_app(n1) || !is_app(n2))
|
||||
return false;
|
||||
if (to_app(n1)->get_decl() != to_app(n2)->get_decl())
|
||||
return false;
|
||||
if (to_app(n1)->get_num_args() != to_app(n2)->get_num_args())
|
||||
return false;
|
||||
unsigned num = to_app(n1)->get_num_args();
|
||||
for (unsigned i = 0; i < num; i++)
|
||||
m_eq_todo.push_back(expr_offset_pair(expr_offset(to_app(n1)->get_arg(i), t1.get_offset()),
|
||||
expr_offset(to_app(n2)->get_arg(i), t2.get_offset())));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
87
src/dead/spc/order.h
Normal file
87
src/dead/spc/order.h
Normal file
|
@ -0,0 +1,87 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
order.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Abstract class for term orderings.
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2008-01-28.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _ORDER_H_
|
||||
#define _ORDER_H_
|
||||
|
||||
#include"substitution.h"
|
||||
#include"precedence.h"
|
||||
#include"trace.h"
|
||||
|
||||
class order {
|
||||
protected:
|
||||
ast_manager & m_manager;
|
||||
precedence * m_precedence;
|
||||
substitution * m_subst;
|
||||
|
||||
typedef std::pair<expr_offset, expr_offset> expr_offset_pair;
|
||||
svector<expr_offset_pair> m_eq_todo;
|
||||
|
||||
expr_offset find(expr_offset t) {
|
||||
while (m_subst && is_var(t.get_expr()) && m_subst->find(to_var(t.get_expr()), t.get_offset(), t))
|
||||
;
|
||||
return t;
|
||||
}
|
||||
|
||||
bool f_greater(func_decl * f, func_decl * g) const {
|
||||
bool r = m_precedence->compare(f, g) > 0;
|
||||
TRACE("order", tout << f->get_name() << " greater than " << g->get_name() << " == " << r << "\n";);
|
||||
return r;
|
||||
}
|
||||
public:
|
||||
enum result {
|
||||
UNKNOWN,
|
||||
UNCOMPARABLE,
|
||||
EQUAL,
|
||||
GREATER,
|
||||
LESSER,
|
||||
NOT_GTEQ
|
||||
};
|
||||
static bool ok(result r) { return r == EQUAL || r == GREATER || r == LESSER; }
|
||||
order(ast_manager & m, precedence * p):m_manager(m), m_precedence(p) { SASSERT(p); }
|
||||
virtual ~order() { dealloc(m_precedence); }
|
||||
virtual void reserve(unsigned num_offsets, unsigned num_vars) {}
|
||||
virtual void reserve_offsets(unsigned num_offsets) {}
|
||||
virtual void reserve_vars(unsigned num_vars) {}
|
||||
ast_manager & get_manager() { return m_manager; }
|
||||
|
||||
virtual result compare(expr_offset const & t1, expr_offset const & t2, substitution * s) = 0;
|
||||
result compare(expr * t1, expr * t2, unsigned offset, substitution * s) { return compare(expr_offset(t1, offset), expr_offset(t2, offset), s); }
|
||||
result compare(expr * t1, expr * t2) { return compare(expr_offset(t1, 0), expr_offset(t2, 0), 0); }
|
||||
virtual bool greater(expr_offset const & t1, expr_offset const & t2, substitution * s) = 0;
|
||||
bool greater(expr * t1, expr * t2) { return greater(expr_offset(t1,0), expr_offset(t2,0), 0); }
|
||||
bool greater(expr * t1, expr * t2, substitution * s) { return greater(expr_offset(t1,0), expr_offset(t2,0), s); }
|
||||
bool greater(expr * t1, expr * t2, unsigned offset, substitution * s) {
|
||||
return greater(expr_offset(t1, offset), expr_offset(t2, offset), s);
|
||||
}
|
||||
/**
|
||||
\brief Return a value > 0 if t1 is greater than t2, 0 if t1 == t2, and < 0 otherwise (uncomparable, unknown, lesser).
|
||||
*/
|
||||
virtual int compare_ge(expr_offset const & t1, expr_offset const & t2, substitution * s) = 0;
|
||||
|
||||
/**
|
||||
\brief Return true if the given terms are equal modulo the given substitution
|
||||
*/
|
||||
bool equal(expr_offset const & t1, expr_offset const & t2, substitution * s);
|
||||
|
||||
bool equal(expr * t1, expr * t2, unsigned offset = 0, substitution * s = 0) {
|
||||
return equal(expr_offset(t1, offset), expr_offset(t2, offset), s);
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* _ORDER_H_ */
|
191
src/dead/spc/precedence.cpp
Normal file
191
src/dead/spc/precedence.cpp
Normal file
|
@ -0,0 +1,191 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
precedence.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
<abstract>
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2008-02-08.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#include"precedence.h"
|
||||
#include"warning.h"
|
||||
|
||||
lex_precedence::lex_precedence(unsigned n, precedence ** ps):
|
||||
m_precedences(n, ps) {
|
||||
}
|
||||
|
||||
lex_precedence::~lex_precedence() {
|
||||
std::for_each(m_precedences.begin(), m_precedences.end(), delete_proc<precedence>());
|
||||
}
|
||||
|
||||
int lex_precedence::compare(func_decl * f, func_decl * g) {
|
||||
int r = 0;
|
||||
ptr_vector<precedence>::iterator it = m_precedences.begin();
|
||||
ptr_vector<precedence>::iterator end = m_precedences.end();
|
||||
for (; it != end; ++it) {
|
||||
r = (*it)->compare(f, g);
|
||||
if (r != 0)
|
||||
return r;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
inv_precedence::inv_precedence(precedence * p):
|
||||
m_precedence(p) {
|
||||
SASSERT(p);
|
||||
}
|
||||
|
||||
inv_precedence::~inv_precedence() {
|
||||
dealloc(m_precedence);
|
||||
}
|
||||
|
||||
int inv_precedence::compare(func_decl * f, func_decl * g) {
|
||||
return m_precedence->compare(g, f);
|
||||
}
|
||||
|
||||
int arbitrary_precedence::compare(func_decl * f, func_decl * g) {
|
||||
return static_cast<int>(f->get_decl_id()) - static_cast<int>(g->get_decl_id());
|
||||
}
|
||||
|
||||
int arity_precedence::compare(func_decl * f, func_decl * g) {
|
||||
return static_cast<int>(f->get_arity()) - static_cast<int>(g->get_arity());
|
||||
}
|
||||
|
||||
int interpreted_precedence::compare(func_decl * f, func_decl * g) {
|
||||
return static_cast<int>(f->get_family_id() == null_family_id) - static_cast<int>(g->get_family_id() == null_family_id);
|
||||
}
|
||||
|
||||
inline int ext_precedence::get_func_pos(func_decl * f) {
|
||||
unsigned id = f->get_decl_id();
|
||||
return m_cached.get(id, m_undefined);
|
||||
}
|
||||
|
||||
int ext_precedence::compare(func_decl * f, func_decl * g) {
|
||||
return get_func_pos(f) - get_func_pos(g);
|
||||
}
|
||||
|
||||
ext_precedence::ext_precedence(ast_manager & m, unsigned num_decls, func_decl ** decls):
|
||||
m_undefined(num_decls),
|
||||
m_cached_domain(m) {
|
||||
for (unsigned i = 0; i < num_decls; i++) {
|
||||
m_cached.setx(decls[i]->get_decl_id(), i, m_undefined);
|
||||
m_cached_domain.push_back(decls[i]);
|
||||
}
|
||||
}
|
||||
|
||||
ext_precedence::~ext_precedence() {
|
||||
}
|
||||
|
||||
int abstract_user_precedence::get_decl_pos(decl * d) {
|
||||
unsigned id = d->get_decl_id();
|
||||
int pos = m_cached.get(id, -1);
|
||||
if (pos == -1) {
|
||||
if (!m_symbol2pos.find(d->get_name(), pos))
|
||||
pos = m_undefined;
|
||||
m_cached.setx(id, pos, -1);
|
||||
SASSERT(pos != -1);
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
|
||||
abstract_user_precedence::abstract_user_precedence(ast_manager & m, unsigned num_syms, symbol * syms):
|
||||
m_undefined(num_syms),
|
||||
m_cached_domain(m) {
|
||||
for (unsigned i = 0; i < num_syms; i++)
|
||||
m_symbol2pos.insert(syms[i], i);
|
||||
}
|
||||
|
||||
abstract_user_precedence::~abstract_user_precedence() {
|
||||
}
|
||||
|
||||
int user_precedence::compare(func_decl * f, func_decl * g) {
|
||||
return get_decl_pos(f) - get_decl_pos(g);
|
||||
}
|
||||
|
||||
int user_sort_precedence::compare(func_decl * f, func_decl * g) {
|
||||
return get_decl_pos(f->get_range()) - get_decl_pos(g->get_range());
|
||||
}
|
||||
|
||||
static precedence * mk_default_precedence(ast_manager & m, order_params const & params) {
|
||||
ptr_buffer<precedence> ps;
|
||||
if (!params.m_order_precedence.empty())
|
||||
ps.push_back(alloc(user_precedence, m, params.m_order_precedence.size(), params.m_order_precedence.c_ptr()));
|
||||
ps.push_back(alloc(interpreted_precedence));
|
||||
ps.push_back(alloc(arity_precedence));
|
||||
ps.push_back(alloc(arbitrary_precedence));
|
||||
return alloc(lex_precedence, ps.size(), ps.c_ptr());
|
||||
}
|
||||
|
||||
static precedence * mk_inv_precedence(bool inv, precedence * p) {
|
||||
return inv ? alloc(inv_precedence,p) : p;
|
||||
}
|
||||
|
||||
static precedence * mk_lex_precedence(ptr_buffer<precedence> const & ps) {
|
||||
unsigned sz = ps.size();
|
||||
if (sz == 0)
|
||||
return alloc(arbitrary_precedence);
|
||||
else if (sz == 1)
|
||||
return ps[0];
|
||||
else
|
||||
return alloc(lex_precedence, sz, ps.c_ptr());
|
||||
}
|
||||
|
||||
precedence * mk_precedence(ast_manager & m, order_params const & params) {
|
||||
if (params.m_order_precedence_gen.empty())
|
||||
return mk_default_precedence(m, params);
|
||||
|
||||
symbol user("user");
|
||||
symbol definition("definition");
|
||||
symbol interpreted("interpreted");
|
||||
symbol frequency("frequency");
|
||||
symbol arity("arity");
|
||||
symbol arbitrary("arbitrary");
|
||||
symbol inv("-");
|
||||
|
||||
ptr_buffer<precedence> ps;
|
||||
|
||||
svector<symbol>::const_iterator it = params.m_order_precedence_gen.begin();
|
||||
svector<symbol>::const_iterator end = params.m_order_precedence_gen.end();
|
||||
bool prev_inv = false;
|
||||
for (; it != end; ++it) {
|
||||
symbol curr = *it;
|
||||
if (curr == user) {
|
||||
if (params.m_order_precedence.empty())
|
||||
ps.push_back(mk_inv_precedence(prev_inv, alloc(user_precedence, m, params.m_order_precedence.size(), params.m_order_precedence.c_ptr())));
|
||||
}
|
||||
else if (curr == definition) {
|
||||
warning_msg("definition precedence was not implement yet.");
|
||||
}
|
||||
else if (curr == interpreted) {
|
||||
ps.push_back(mk_inv_precedence(prev_inv, alloc(interpreted_precedence)));
|
||||
}
|
||||
else if (curr == frequency) {
|
||||
warning_msg("frequency precedence was not implement yet.");
|
||||
}
|
||||
else if (curr == arity) {
|
||||
ps.push_back(mk_inv_precedence(prev_inv, alloc(arity_precedence)));
|
||||
}
|
||||
else if (curr == arbitrary) {
|
||||
ps.push_back(mk_inv_precedence(prev_inv, alloc(arbitrary_precedence)));
|
||||
// it is pointless to continue, arbitrary_precedence is a total order
|
||||
return mk_lex_precedence(ps);
|
||||
}
|
||||
else if (curr == inv) {
|
||||
prev_inv = true;
|
||||
}
|
||||
else {
|
||||
warning_msg("invalid precedence generator: ignoring atom '%s'.", curr.bare_str());
|
||||
}
|
||||
}
|
||||
|
||||
return mk_lex_precedence(ps);
|
||||
}
|
142
src/dead/spc/precedence.h
Normal file
142
src/dead/spc/precedence.h
Normal file
|
@ -0,0 +1,142 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
precedence.h
|
||||
|
||||
Abstract:
|
||||
|
||||
<abstract>
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2008-02-08.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _PRECEDENCE_H_
|
||||
#define _PRECEDENCE_H_
|
||||
|
||||
#include"ast.h"
|
||||
#include"order_params.h"
|
||||
|
||||
/**
|
||||
\brief Abstract functor used to implement an order on function symbols.
|
||||
*/
|
||||
class precedence {
|
||||
public:
|
||||
virtual ~precedence() {}
|
||||
virtual int compare(func_decl * f, func_decl * g) = 0;
|
||||
bool operator()(func_decl * f, func_decl * g) { return compare(f, g) < 0; }
|
||||
};
|
||||
|
||||
/**
|
||||
\brief Compose different precedence functors using lexicographical order.
|
||||
*/
|
||||
class lex_precedence : public precedence {
|
||||
ptr_vector<precedence> m_precedences;
|
||||
public:
|
||||
lex_precedence(unsigned n, precedence ** ps);
|
||||
virtual ~lex_precedence();
|
||||
virtual int compare(func_decl * f, func_decl * g);
|
||||
};
|
||||
|
||||
/**
|
||||
\brief Invert functor
|
||||
*/
|
||||
class inv_precedence : public precedence {
|
||||
precedence * m_precedence;
|
||||
public:
|
||||
inv_precedence(precedence * p);
|
||||
virtual ~inv_precedence();
|
||||
virtual int compare(func_decl * f, func_decl * g);
|
||||
};
|
||||
|
||||
/**
|
||||
\brief An arbitrary total order based on the func_decl ids.
|
||||
*/
|
||||
class arbitrary_precedence : public precedence {
|
||||
public:
|
||||
virtual int compare(func_decl * f, func_decl * g);
|
||||
};
|
||||
|
||||
/**
|
||||
\brief Precedence based on the arity.
|
||||
|
||||
\remark This is not a total order, so it must be combined
|
||||
with other precedence functors (e.g., arbitrary_precedence).
|
||||
*/
|
||||
class arity_precedence : public precedence {
|
||||
public:
|
||||
virtual int compare(func_decl * f, func_decl * g);
|
||||
};
|
||||
|
||||
/**
|
||||
\brief Interpreted function symbols are smaller.
|
||||
*/
|
||||
class interpreted_precedence : public precedence {
|
||||
public:
|
||||
virtual int compare(func_decl * f, func_decl * g);
|
||||
};
|
||||
|
||||
/**
|
||||
\brief A precedence given as a sequence of func_decls.
|
||||
This functor is used to encapsulate automatically/externally generated
|
||||
precedences.
|
||||
*/
|
||||
class ext_precedence : public precedence {
|
||||
unsigned m_undefined; // position for func_decl's not specified by the user.
|
||||
int_vector m_cached; // mapping: decl -> int
|
||||
decl_ref_vector m_cached_domain;
|
||||
|
||||
int get_func_pos(func_decl * f);
|
||||
public:
|
||||
ext_precedence(ast_manager & m, unsigned num_decls, func_decl ** decls);
|
||||
virtual ~ext_precedence();
|
||||
virtual int compare(func_decl * f, func_decl * g);
|
||||
};
|
||||
|
||||
/**
|
||||
\brief Abstract class for user precedences based on
|
||||
function or sort symbols.
|
||||
*/
|
||||
class abstract_user_precedence : public precedence {
|
||||
protected:
|
||||
symbol_table<int> m_symbol2pos;
|
||||
unsigned m_undefined; // position for symbols not specified by the user.
|
||||
int_vector m_cached; // mapping: decl -> int
|
||||
decl_ref_vector m_cached_domain;
|
||||
|
||||
int get_decl_pos(decl * d);
|
||||
public:
|
||||
abstract_user_precedence(ast_manager & m, unsigned num_syms, symbol * syms);
|
||||
virtual ~abstract_user_precedence();
|
||||
};
|
||||
|
||||
/**
|
||||
\brief A user defined precedence given as a sequence of symbols.
|
||||
|
||||
\remark User provided precedences are usually not total.
|
||||
*/
|
||||
class user_precedence : public abstract_user_precedence {
|
||||
public:
|
||||
user_precedence(ast_manager & m, unsigned num_syms, symbol * syms):abstract_user_precedence(m, num_syms, syms) {}
|
||||
virtual int compare(func_decl * f, func_decl * g);
|
||||
};
|
||||
|
||||
/**
|
||||
\brief A user defined precedence given as a sequence of sort symbols.
|
||||
The functions are ordered based on their range sort.
|
||||
*/
|
||||
class user_sort_precedence : public abstract_user_precedence {
|
||||
public:
|
||||
user_sort_precedence(ast_manager & m, unsigned num_syms, symbol * syms):abstract_user_precedence(m, num_syms, syms) {}
|
||||
virtual int compare(func_decl * f, func_decl * g);
|
||||
};
|
||||
|
||||
precedence * mk_precedence(ast_manager & m, order_params const & params);
|
||||
|
||||
#endif /* _PRECEDENCE_H_ */
|
||||
|
155
src/dead/spc/preprocessor.cpp
Normal file
155
src/dead/spc/preprocessor.cpp
Normal file
|
@ -0,0 +1,155 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
preprocessor.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Preprocessor
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2008-01-17.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#include"ast_pp.h"
|
||||
#include"ast_ll_pp.h"
|
||||
#include"preprocessor.h"
|
||||
#include"for_each_expr.h"
|
||||
#include"num_occurs.h"
|
||||
|
||||
preprocessor::preprocessor(ast_manager & m, defined_names & d, simplifier & s, preprocessor_params & p):
|
||||
m_params(p),
|
||||
m_manager(m),
|
||||
m_simp(s),
|
||||
m_nnf(m, d, p),
|
||||
m_cnf(m, d, p),
|
||||
m_der(m),
|
||||
m_push_app_ite(s, p.m_lift_ite == LI_CONSERVATIVE),
|
||||
m_cnf_todo(m),
|
||||
m_cnf_todo_prs(m),
|
||||
m_push_todo(m),
|
||||
m_push_todo_prs(m) {
|
||||
switch (m_params.m_cnf_mode) {
|
||||
case CNF_QUANT:
|
||||
if (m_params.m_nnf_mode == NNF_SKOLEM)
|
||||
m_params.m_nnf_mode = NNF_QUANT;
|
||||
break;
|
||||
case CNF_OPPORTUNISTIC:
|
||||
if (m_params.m_nnf_mode == NNF_SKOLEM)
|
||||
m_params.m_nnf_mode = NNF_QUANT;
|
||||
break;
|
||||
case CNF_FULL:
|
||||
m_params.m_nnf_mode = NNF_FULL;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef _TRACE
|
||||
struct num_occurs_pp {
|
||||
|
||||
ast_manager & m_manager;
|
||||
std::ostream & m_out;
|
||||
num_occurs m_occurs;
|
||||
|
||||
num_occurs_pp(ast_manager & m, std::ostream & out, expr * root):
|
||||
m_manager(m),
|
||||
m_out(out) {
|
||||
m_occurs(root);
|
||||
}
|
||||
void operator()(var * n) {}
|
||||
void operator()(app * n) {
|
||||
unsigned val = m_occurs.get_num_occs(n);
|
||||
if (val > 1 && m_manager.is_bool(n))
|
||||
m_out << "#" << n->get_id() << " -> " << val << " " << n->get_ref_count() << "\n";
|
||||
}
|
||||
void operator()(quantifier * n) {}
|
||||
};
|
||||
#endif
|
||||
|
||||
void preprocessor::operator()(expr * e, proof * in_pr, expr_ref_vector & result, proof_ref_vector & result_prs) {
|
||||
m_cnf_todo.reset();
|
||||
m_cnf_todo_prs.reset();
|
||||
|
||||
expr_ref r1(m_manager);
|
||||
proof_ref pr1(m_manager);
|
||||
m_simp(e, r1, pr1);
|
||||
in_pr = m_manager.mk_modus_ponens(in_pr, pr1);
|
||||
|
||||
expr_ref r2(m_manager);
|
||||
proof_ref pr2(m_manager);
|
||||
m_nnf(r1, m_cnf_todo, m_cnf_todo_prs, r2, pr2);
|
||||
in_pr = m_manager.mk_modus_ponens(in_pr, pr2);
|
||||
|
||||
TRACE("preprocessor", tout << mk_ll_pp(r2, m_manager);
|
||||
num_occurs_pp proc(m_manager, tout, r2);
|
||||
for_each_expr(proc, r2););
|
||||
|
||||
m_cnf_todo.push_back(r2);
|
||||
m_cnf_todo_prs.push_back(in_pr);
|
||||
|
||||
unsigned sz = m_cnf_todo.size();
|
||||
for (unsigned i = 0; i < sz; i++) {
|
||||
m_push_todo.reset();
|
||||
m_push_todo_prs.reset();
|
||||
|
||||
expr * e = m_cnf_todo.get(i);
|
||||
if (m_params.m_lift_ite != LI_NONE) {
|
||||
m_push_app_ite(e, r1, pr1);
|
||||
}
|
||||
else {
|
||||
r1 = e;
|
||||
pr1 = 0;
|
||||
}
|
||||
|
||||
TRACE("preprocessor", tout << mk_ll_pp(r1, m_manager););
|
||||
|
||||
expr_ref aux(r1, m_manager);
|
||||
m_simp(aux, r1, pr2);
|
||||
pr1 = m_manager.mk_transitivity(pr1, pr2);
|
||||
|
||||
TRACE("preprocessor", tout << mk_ll_pp(r1, m_manager););
|
||||
|
||||
aux = r1;
|
||||
m_der(aux, r1, pr2);
|
||||
pr1 = m_manager.mk_transitivity(pr1, pr2);
|
||||
|
||||
TRACE("preprocessor", tout << mk_ll_pp(r1, m_manager););
|
||||
|
||||
if (m_manager.proofs_enabled())
|
||||
in_pr = m_manager.mk_modus_ponens(m_cnf_todo_prs.get(i), pr1);
|
||||
else
|
||||
in_pr = 0;
|
||||
|
||||
aux = r1;
|
||||
m_cnf(aux, m_push_todo, m_push_todo_prs, r1, pr1);
|
||||
m_push_todo.push_back(r1);
|
||||
|
||||
TRACE("preprocessor", tout << mk_ll_pp(r1, m_manager););
|
||||
|
||||
if (m_manager.proofs_enabled()) {
|
||||
in_pr = m_manager.mk_modus_ponens(in_pr, pr1);
|
||||
m_push_todo_prs.push_back(in_pr);
|
||||
}
|
||||
|
||||
unsigned sz2 = m_push_todo.size();
|
||||
for (unsigned j = 0; j < sz2; j++) {
|
||||
expr * e = m_push_todo.get(j);
|
||||
m_simp(e, r1, pr1);
|
||||
|
||||
TRACE("preprocessor", tout << mk_ll_pp(r1, m_manager););
|
||||
|
||||
if (m_manager.proofs_enabled())
|
||||
in_pr = m_manager.mk_modus_ponens(m_push_todo_prs.get(j), pr1);
|
||||
else
|
||||
in_pr = 0;
|
||||
push_assertion(m_manager, r1, in_pr, result, result_prs);
|
||||
}
|
||||
}
|
||||
}
|
51
src/dead/spc/preprocessor.h
Normal file
51
src/dead/spc/preprocessor.h
Normal file
|
@ -0,0 +1,51 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
preprocessor.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Preprocess AST before adding them to the logical context
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2008-01-17.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _PREPROCESSOR_H_
|
||||
#define _PREPROCESSOR_H_
|
||||
|
||||
#include"preprocessor_params.h"
|
||||
#include"simplifier.h"
|
||||
#include"pattern_inference.h"
|
||||
#include"nnf.h"
|
||||
#include"cnf.h"
|
||||
#include"der.h"
|
||||
#include"push_app_ite.h"
|
||||
|
||||
/**
|
||||
\brief Functor used to preprocess expressions before adding them to
|
||||
the logical context.
|
||||
*/
|
||||
class preprocessor {
|
||||
preprocessor_params & m_params;
|
||||
ast_manager & m_manager;
|
||||
simplifier & m_simp;
|
||||
nnf m_nnf;
|
||||
cnf m_cnf;
|
||||
der_star m_der;
|
||||
push_app_ite m_push_app_ite;
|
||||
expr_ref_vector m_cnf_todo;
|
||||
proof_ref_vector m_cnf_todo_prs;
|
||||
expr_ref_vector m_push_todo;
|
||||
proof_ref_vector m_push_todo_prs;
|
||||
public:
|
||||
preprocessor(ast_manager & m, defined_names & d, simplifier & s, preprocessor_params & p);
|
||||
void operator()(expr * e, proof * in_pr, expr_ref_vector & result, proof_ref_vector & result_prs);
|
||||
};
|
||||
|
||||
#endif /* _PREPROCESSOR_H_ */
|
107
src/dead/spc/sparse_use_list.h
Normal file
107
src/dead/spc/sparse_use_list.h
Normal file
|
@ -0,0 +1,107 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
sparse_use_list.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Sparse use list index.
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2008-02-13.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _SPARSE_USE_LIST_H_
|
||||
#define _SPARSE_USE_LIST_H_
|
||||
|
||||
#include"ast.h"
|
||||
#include"obj_hashtable.h"
|
||||
|
||||
/**
|
||||
\brief (Generic sparse) use-list data-structure.
|
||||
*/
|
||||
template<typename T, typename Set>
|
||||
class sparse_use_list {
|
||||
typedef obj_map<T, Set *> use_list;
|
||||
use_list m_use_list;
|
||||
|
||||
public:
|
||||
typedef typename Set::iterator iterator;
|
||||
sparse_use_list() {}
|
||||
~sparse_use_list() {
|
||||
reset();
|
||||
}
|
||||
|
||||
void insert(typename Set::data const & parent, T * child) {
|
||||
Set * parents = 0;
|
||||
if (!m_use_list.find(child, parents)) {
|
||||
parents = alloc(Set);
|
||||
m_use_list.insert(child, parents);
|
||||
}
|
||||
SASSERT(parents);
|
||||
parents->insert(parent);
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Return 0 if child did not contain any parents.
|
||||
Return 1, if child does not have more parents after
|
||||
removing parent.
|
||||
Return 2 otherwise.
|
||||
*/
|
||||
unsigned erase(typename Set::data const & parent, T * child) {
|
||||
Set * parents = 0;
|
||||
if (m_use_list.find(child, parents)) {
|
||||
parents->erase(parent);
|
||||
if (parents->empty()) {
|
||||
dealloc(parents);
|
||||
m_use_list.erase(child);
|
||||
return 1;
|
||||
}
|
||||
return 2;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void reset() {
|
||||
typename use_list::iterator it = m_use_list.begin();
|
||||
typename use_list::iterator end = m_use_list.end();
|
||||
for (; it != end; ++it)
|
||||
dealloc(it->m_value);
|
||||
m_use_list.reset();
|
||||
}
|
||||
|
||||
Set * get_parents(T * e) {
|
||||
Set * parents = 0;
|
||||
m_use_list.find(e, parents);
|
||||
return parents;
|
||||
}
|
||||
|
||||
iterator begin(T * e) {
|
||||
Set * parents = 0;
|
||||
m_use_list.find(e, parents);
|
||||
SASSERT(parents);
|
||||
return parents->begin();
|
||||
}
|
||||
|
||||
iterator end(T * e) {
|
||||
Set * parents = 0;
|
||||
m_use_list.find(e, parents);
|
||||
SASSERT(parents);
|
||||
return parents->end();
|
||||
}
|
||||
|
||||
bool empty(T * e) const {
|
||||
Set * parents = 0;
|
||||
if (m_use_list.find(e, parents))
|
||||
return parents->empty();
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* _SPARSE_USE_LIST_H_ */
|
||||
|
170
src/dead/spc/spc_asserted_literals.cpp
Normal file
170
src/dead/spc/spc_asserted_literals.cpp
Normal file
|
@ -0,0 +1,170 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
spc_asserted_literals.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
<abstract>
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2008-02-14.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
#include"spc_asserted_literals.h"
|
||||
#include"ast_pp.h"
|
||||
|
||||
namespace spc {
|
||||
|
||||
asserted_literals::asserted_literals(ast_manager & m):
|
||||
m_manager(m),
|
||||
m_subst(m),
|
||||
m_tmp_eq1(2),
|
||||
m_tmp_eq2(2) {
|
||||
for (unsigned i = 0; i < 2; i++) {
|
||||
m_st[i] = alloc(substitution_tree, m_manager);
|
||||
m_expr2clause[i] = alloc(expr2clause);
|
||||
}
|
||||
m_subst.reserve_offsets(3);
|
||||
}
|
||||
|
||||
asserted_literals::~asserted_literals() {
|
||||
for (unsigned i = 0; i < 2; i++) {
|
||||
dealloc(m_st[i]);
|
||||
dealloc(m_expr2clause[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void asserted_literals::insert(clause * cls) {
|
||||
if (cls->get_num_literals() == 1) {
|
||||
TRACE("asserted_literals", tout << "inserting clause into asserted_literals index:\n";
|
||||
cls->display(tout, m_manager); tout << "\n";);
|
||||
literal const & l = cls->get_literal(0);
|
||||
unsigned neg = static_cast<unsigned>(l.sign());
|
||||
expr * atom = l.atom();
|
||||
m_st[neg]->insert(to_app(atom));
|
||||
m_expr2clause[neg]->insert(atom, cls);
|
||||
m_subst.reserve_vars(m_st[neg]->get_approx_num_regs());
|
||||
}
|
||||
}
|
||||
|
||||
void asserted_literals::erase(clause * cls) {
|
||||
if (cls->get_num_literals() == 1) {
|
||||
literal const & l = cls->get_literal(0);
|
||||
unsigned neg = static_cast<unsigned>(l.sign());
|
||||
expr * atom = l.atom();
|
||||
m_expr2clause[neg]->erase(atom);
|
||||
m_st[neg]->erase(to_app(atom));
|
||||
}
|
||||
}
|
||||
|
||||
void asserted_literals::reset() {
|
||||
for (unsigned i = 0; i < 2; i++) {
|
||||
m_st[i]->reset();
|
||||
m_expr2clause[i]->reset();
|
||||
}
|
||||
}
|
||||
|
||||
struct asserted_literals_visitor : public st_visitor {
|
||||
expr * m_target;
|
||||
asserted_literals_visitor(substitution & s):st_visitor(s), m_target(0) {}
|
||||
virtual bool operator()(expr * e) {
|
||||
m_target = e;
|
||||
return false; // stop
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
\brief Return an unit clause that is a generalization
|
||||
of the given literal.
|
||||
Return 0 if such clause does not exist.
|
||||
*/
|
||||
clause * asserted_literals::gen(expr * atom, bool n) {
|
||||
if (is_app(atom)) {
|
||||
TRACE("asserted_literals", tout << "checking if there is generalizer for: " << n << "\n" <<
|
||||
mk_pp(atom, m_manager) << "\n";);
|
||||
unsigned neg = static_cast<unsigned>(n);
|
||||
m_subst.reset_subst();
|
||||
asserted_literals_visitor visitor(m_subst);
|
||||
TRACE("asserted_literals_bug", tout << "query: " << mk_pp(atom, m_manager) << "\n"; m_st[neg]->display(tout);
|
||||
m_subst.display(tout););
|
||||
m_st[neg]->gen(to_app(atom), visitor);
|
||||
if (visitor.m_target != 0) {
|
||||
clause * cls = 0;
|
||||
m_expr2clause[neg]->find(visitor.m_target, cls);
|
||||
SASSERT(cls);
|
||||
return cls;
|
||||
}
|
||||
if (m_manager.is_eq(atom)) {
|
||||
m_subst.reset();
|
||||
m_tmp_eq1.copy_swapping_args(to_app(atom));
|
||||
m_st[neg]->gen(m_tmp_eq1.get_app(), visitor);
|
||||
if (visitor.m_target != 0) {
|
||||
clause * cls = 0;
|
||||
m_expr2clause[neg]->find(visitor.m_target, cls);
|
||||
SASSERT(cls);
|
||||
return cls;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Return an unit clause that is a generalization
|
||||
of the equality (= lhs rhs)
|
||||
Return 0 if such clause does not exist.
|
||||
*/
|
||||
clause * asserted_literals::gen_eq(expr * lhs, expr * rhs) {
|
||||
expr * args[2] = { lhs, rhs };
|
||||
func_decl_ref eq_decl(m_manager.mk_func_decl(m_manager.get_basic_family_id(), OP_EQ, 0, 0, 2, args), m_manager);
|
||||
m_tmp_eq2.set_decl(eq_decl);
|
||||
m_tmp_eq2.set_arg(0, lhs);
|
||||
m_tmp_eq2.set_arg(1, rhs);
|
||||
return gen(m_tmp_eq2.get_app(), false);
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Return a unit equality clause (= s t) that (eq) subsumes (= lhs rhs).
|
||||
That is, lhs and rhs have the form u[s'] and u[t'] and there is
|
||||
a substitution sigma s.t. sigma(s) = s' and sigma(t) = t'.
|
||||
Return 0 if such clause does not exist.
|
||||
*/
|
||||
clause * asserted_literals::subsumes(expr * lhs, expr * rhs) {
|
||||
while (true) {
|
||||
TRACE("eq_subsumption", tout << "eq_subsumption loop:\n" << mk_pp(lhs, m_manager) << "\n" <<
|
||||
mk_pp(rhs, m_manager) << "\n";);
|
||||
clause * subsumer = gen_eq(lhs, rhs);
|
||||
if (subsumer)
|
||||
return subsumer;
|
||||
if (!is_app(lhs) || !is_app(rhs) ||
|
||||
to_app(lhs)->get_decl() != to_app(rhs)->get_decl() ||
|
||||
to_app(lhs)->get_num_args() != to_app(rhs)->get_num_args())
|
||||
return 0;
|
||||
expr * d1 = 0;
|
||||
expr * d2 = 0;
|
||||
unsigned num_args = to_app(lhs)->get_num_args();
|
||||
for (unsigned i = 0; i < num_args; i++) {
|
||||
expr * c1 = to_app(lhs)->get_arg(i);
|
||||
expr * c2 = to_app(rhs)->get_arg(i);
|
||||
if (c1 != c2) {
|
||||
if (d1)
|
||||
return 0;
|
||||
d1 = c1;
|
||||
d2 = c2;
|
||||
}
|
||||
}
|
||||
SASSERT(d1);
|
||||
lhs = d1;
|
||||
rhs = d2;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
};
|
69
src/dead/spc/spc_asserted_literals.h
Normal file
69
src/dead/spc/spc_asserted_literals.h
Normal file
|
@ -0,0 +1,69 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
spc_asserted_literals.h
|
||||
|
||||
Abstract:
|
||||
|
||||
<abstract>
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2008-02-14.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _SPC_ASSERTED_LITERALS_H_
|
||||
#define _SPC_ASSERTED_LITERALS_H_
|
||||
|
||||
#include"spc_clause.h"
|
||||
#include"substitution_tree.h"
|
||||
#include"obj_hashtable.h"
|
||||
|
||||
namespace spc {
|
||||
|
||||
/**
|
||||
\brief Index for the asserted literals in the logical context.
|
||||
|
||||
This index is used to implement forward unit subsumption,
|
||||
equality subsumption, positive simplify-reflect, and
|
||||
negative simplify-reflect.
|
||||
*/
|
||||
class asserted_literals {
|
||||
protected:
|
||||
typedef obj_map<expr, clause*> expr2clause;
|
||||
ast_manager & m_manager;
|
||||
substitution_tree * m_st[2];
|
||||
expr2clause * m_expr2clause[2];
|
||||
substitution m_subst;
|
||||
tmp_app m_tmp_eq1;
|
||||
tmp_app m_tmp_eq2;
|
||||
public:
|
||||
asserted_literals(ast_manager & m);
|
||||
~asserted_literals();
|
||||
|
||||
void insert(clause * cls);
|
||||
void erase(clause * cls);
|
||||
void reset();
|
||||
void reserve_vars(unsigned num_vars) { m_subst.reserve_vars(num_vars); }
|
||||
|
||||
clause * gen(literal const & l) {
|
||||
return gen(l.atom(), l.sign());
|
||||
}
|
||||
|
||||
clause * gen(expr * atom, bool neg);
|
||||
clause * gen_eq(expr * lhs, expr * rhs);
|
||||
clause * subsumes(expr * lhs, expr * rhs);
|
||||
|
||||
bool has_pos_literals() const { return !m_st[0]->empty(); }
|
||||
bool has_neg_literals() const { return !m_st[1]->empty(); }
|
||||
bool has_literals() const { return has_pos_literals() || has_neg_literals(); }
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
#endif /* _SPC_ASSERTED_LITERALS_H_ */
|
||||
|
287
src/dead/spc/spc_clause.cpp
Normal file
287
src/dead/spc/spc_clause.cpp
Normal file
|
@ -0,0 +1,287 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
spc_clause.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Superposition Calculus Clause
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2008-02-02.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#include"spc_clause.h"
|
||||
#include"splay_tree_def.h"
|
||||
|
||||
template class splay_tree<spc::clause *, spc::clause::compare>;
|
||||
|
||||
namespace spc {
|
||||
|
||||
clause::clause(ast_manager & m, unsigned num_lits, literal * lits, justification * p, unsigned scope_lvl):
|
||||
m_id(UINT_MAX),
|
||||
m_time(UINT_MAX),
|
||||
m_scope_lvl(scope_lvl),
|
||||
m_bidx(UINT_MAX),
|
||||
m_processed(false),
|
||||
m_indexed(false),
|
||||
m_has_sel_lit(false),
|
||||
m_justification(p) {
|
||||
|
||||
set_fields(num_lits, lits);
|
||||
|
||||
m_num_lits_capacity = m_num_lits[0] + m_num_lits[1];
|
||||
|
||||
memcpy(m_lits, lits, sizeof(literal) * get_num_literals());
|
||||
|
||||
for (unsigned i = 0; i < num_lits; i++)
|
||||
m.inc_ref(m_lits[i].atom());
|
||||
m_justification->inc_ref();
|
||||
m_justification->set_owner(this);
|
||||
|
||||
sort_literals();
|
||||
}
|
||||
|
||||
clause * clause::mk(ast_manager & m, unsigned num_lits, literal * lits, justification * p, unsigned scope_lvl) {
|
||||
void * mem = m.get_allocator().allocate(sizeof(clause) + num_lits * sizeof(literal));
|
||||
return new (mem) clause(m, num_lits, lits, p, scope_lvl);
|
||||
}
|
||||
|
||||
void clause::init(unsigned id, unsigned time) {
|
||||
SASSERT(m_id == UINT_MAX);
|
||||
SASSERT(m_time == UINT_MAX);
|
||||
|
||||
m_id = id;
|
||||
m_time = time;
|
||||
m_proof_depth = 0;
|
||||
|
||||
justification_stat j_stat;
|
||||
get_justification_stat(m_justification, j_stat);
|
||||
|
||||
m_proof_depth = j_stat.m_proof_depth;
|
||||
|
||||
if (j_stat.m_max_scope_lvl > m_scope_lvl)
|
||||
m_scope_lvl = j_stat.m_max_scope_lvl;
|
||||
|
||||
update_parents(j_stat.m_parent_clauses);
|
||||
}
|
||||
|
||||
void clause::update_parents(ptr_buffer<clause> & parents) {
|
||||
ptr_buffer<clause>::iterator it = parents.begin();
|
||||
ptr_buffer<clause>::iterator end = parents.end();
|
||||
for (; it != end; ++it) {
|
||||
clause * parent = *it;
|
||||
parent->add_child(this);
|
||||
}
|
||||
}
|
||||
|
||||
void clause::deallocate(ast_manager & m) {
|
||||
|
||||
justification_stat j_stat;
|
||||
get_justification_stat(get_justification(), j_stat);
|
||||
|
||||
ptr_buffer<clause>::iterator it = j_stat.m_parent_clauses.begin();
|
||||
ptr_buffer<clause>::iterator end = j_stat.m_parent_clauses.end();
|
||||
for (; it != end; ++it) {
|
||||
clause * parent = *it;
|
||||
parent->del_child(this);
|
||||
}
|
||||
|
||||
dec_ref(get_justification(), m);
|
||||
|
||||
unsigned num_lits = get_num_literals();
|
||||
for (unsigned i = 0; i < num_lits; i++)
|
||||
m.dec_ref(get_literal(i).atom());
|
||||
|
||||
unsigned capacity = get_num_literals_capacity();
|
||||
this->~clause();
|
||||
m.get_allocator().deallocate(sizeof(clause) + capacity * sizeof(literal), this);
|
||||
}
|
||||
|
||||
void clause::select_literal(unsigned idx) {
|
||||
SASSERT(idx < get_num_literals());
|
||||
m_lits[idx].set_selected(true);
|
||||
m_has_sel_lit = true;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Return true if l is maximal in the clause, given a substitution s.
|
||||
|
||||
s(l) is considered maximal if there is no literal l' in the clause such s(l') is greater
|
||||
than s(l).
|
||||
*/
|
||||
bool clause::is_maximal(order & o, literal const & l, unsigned offset, substitution * s) const {
|
||||
unsigned num_lits = get_num_literals();
|
||||
for (unsigned i = 0; i < num_lits; i++) {
|
||||
literal const & l_prime = m_lits[i];
|
||||
if (l != l_prime && greater(o, l_prime, l, offset, s))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Return true if l is a maximal selected literal in the clause, given a substitution s.
|
||||
|
||||
s(l) is considered maximal selected literal if there is no
|
||||
selected literal l' in the clause such s(l') is greater than s(l).
|
||||
*/
|
||||
bool clause::is_sel_maximal(order & o, literal const & l, unsigned offset, substitution * s) const {
|
||||
if (!l.is_selected())
|
||||
return false;
|
||||
unsigned num_lits = get_num_literals();
|
||||
for (unsigned i = 0; i < num_lits; i++) {
|
||||
literal const & l_prime = m_lits[i];
|
||||
if (l != l_prime && l_prime.is_selected() && greater(o, l_prime, l, offset, s))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Return true if l is eligible for resolution.
|
||||
*/
|
||||
bool clause::is_eligible_for_resolution(order & o, literal const & l, unsigned offset, substitution * s) const {
|
||||
if (has_sel_lit())
|
||||
return is_sel_maximal(o, l, offset, s);
|
||||
else
|
||||
return is_maximal(o, l, offset, s);
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Return true if l is eligible for paramodulation.
|
||||
*/
|
||||
bool clause::is_eligible_for_paramodulation(order & o, literal const & l, unsigned offset, substitution * s) const {
|
||||
return !has_sel_lit() && is_maximal(o, l, offset, s);
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Try to orient literals.
|
||||
*/
|
||||
void clause::try_to_orient_literals(order & o) {
|
||||
o.reserve_vars(get_num_vars());
|
||||
unsigned num_lits = get_num_literals();
|
||||
for (unsigned i = 0; i < num_lits; i++) {
|
||||
literal & l = m_lits[i];
|
||||
l.try_to_orient(o);
|
||||
}
|
||||
}
|
||||
|
||||
void clause::set_fields(unsigned num_lits, literal * lits) {
|
||||
clause_stat c_stat;
|
||||
get_clause_stat(num_lits, lits, c_stat);
|
||||
|
||||
m_num_vars = c_stat.m_max_var_idx + 1;
|
||||
m_sym_count = c_stat.m_sym_count;
|
||||
m_const_count = c_stat.m_const_count;
|
||||
m_depth = c_stat.m_depth;
|
||||
m_num_lits[0] = c_stat.m_num_lits[0];
|
||||
m_num_lits[1] = c_stat.m_num_lits[1];
|
||||
m_ground = c_stat.m_ground;
|
||||
}
|
||||
|
||||
struct lit_lt {
|
||||
bool operator()(literal const & l1, literal const & l2) const {
|
||||
if (l1.is_ground() > l2.is_ground())
|
||||
return true;
|
||||
if (l1.is_ground() != l2.is_ground())
|
||||
return false;
|
||||
if (l1.get_approx_depth() > l2.get_approx_depth())
|
||||
return true;
|
||||
if (l1.get_approx_depth() != l2.get_approx_depth())
|
||||
return false;
|
||||
if (l1.get_approx_sym_count() > l2.get_approx_sym_count())
|
||||
return true;
|
||||
if (l1.get_approx_sym_count() != l2.get_approx_sym_count())
|
||||
return false;
|
||||
if (l1.get_approx_const_count() > l2.get_approx_const_count())
|
||||
return true;
|
||||
if (l1.get_approx_const_count() != l2.get_approx_const_count())
|
||||
return false;
|
||||
return l1.get_id() < l2.get_id();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
\brief Sort literals to improve the performance of subsumption tests.
|
||||
*/
|
||||
void clause::sort_literals() {
|
||||
DEBUG_CODE({
|
||||
unsigned num_lits = get_num_literals();
|
||||
for (unsigned i = 0; i < num_lits; i++) {
|
||||
SASSERT(m_lits[i].has_stats());
|
||||
}
|
||||
});
|
||||
std::sort(m_lits, m_lits + get_num_literals(), lit_lt());
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Replace clause literal with the given literals.
|
||||
Use the given justification to justify the new clause.
|
||||
*/
|
||||
void clause::update_lits(ast_manager & m, unsigned num_lits, literal * lits, justification * j) {
|
||||
unsigned old_num_lits = get_num_literals();
|
||||
SASSERT(num_lits <= old_num_lits);
|
||||
|
||||
for (unsigned i = 0; i < num_lits; i++)
|
||||
m.inc_ref(lits[i].atom());
|
||||
|
||||
for (unsigned i = 0; i < old_num_lits; i++)
|
||||
m.dec_ref(m_lits[i].atom());
|
||||
|
||||
for (unsigned i = 0; i < num_lits; i++)
|
||||
m_lits[i] = lits[i];
|
||||
|
||||
set_fields(num_lits, m_lits);
|
||||
|
||||
SASSERT(get_num_literals() == num_lits);
|
||||
|
||||
j->inc_ref();
|
||||
m_justification->set_owner(0); // release ownership
|
||||
dec_ref(m_justification, m);
|
||||
m_justification = j;
|
||||
m_justification->set_owner(this);
|
||||
|
||||
sort_literals();
|
||||
|
||||
justification_stat j_stat;
|
||||
get_justification_stat(m_justification, j_stat);
|
||||
|
||||
m_proof_depth = j_stat.m_proof_depth;
|
||||
|
||||
SASSERT(m_scope_lvl == j_stat.m_max_scope_lvl);
|
||||
|
||||
update_parents(j_stat.m_parent_clauses);
|
||||
}
|
||||
|
||||
void clause::display(std::ostream & out, ast_manager & m, bool detailed) {
|
||||
if (get_num_literals() == 0) {
|
||||
out << "empty-clause";
|
||||
return;
|
||||
}
|
||||
out << "#" << m_id << ": (clause ";
|
||||
spc::display(out, get_num_literals(), m_lits, m, detailed);
|
||||
out << ")";
|
||||
if (m_processed)
|
||||
out << "*";
|
||||
}
|
||||
|
||||
void get_clause_stat(unsigned num_lits, literal * lits, clause_stat & stat) {
|
||||
for (unsigned i = 0; i < num_lits; i++) {
|
||||
literal_stat c;
|
||||
lits[i].get_stat(c);
|
||||
stat.m_sym_count += c.m_sym_count;
|
||||
stat.m_depth = std::max(stat.m_depth, c.m_depth);
|
||||
stat.m_max_var_idx = std::max(stat.m_max_var_idx, c.m_max_var_idx);
|
||||
stat.m_const_count += c.m_const_count;
|
||||
stat.m_ground &= c.m_ground;
|
||||
stat.m_num_lits[static_cast<unsigned>(lits[i].sign())]++;
|
||||
}
|
||||
}
|
||||
|
||||
};
|
152
src/dead/spc/spc_clause.h
Normal file
152
src/dead/spc/spc_clause.h
Normal file
|
@ -0,0 +1,152 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
spc_clause.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Superposition Calculus Clause
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2008-02-02.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _SPC_CLAUSE_H_
|
||||
#define _SPC_CLAUSE_H_
|
||||
|
||||
#include"ast.h"
|
||||
#include"splay_tree.h"
|
||||
#include"use_list.h"
|
||||
#include"spc_literal.h"
|
||||
#include"spc_justification.h"
|
||||
#include"use_list.h"
|
||||
|
||||
namespace spc {
|
||||
|
||||
class context;
|
||||
|
||||
/**
|
||||
\brief Superposition Calculus clause.
|
||||
*/
|
||||
class clause {
|
||||
struct compare {
|
||||
// ignoring potential overflow/underflow
|
||||
int operator()(clause * c1, clause * c2) const {
|
||||
return static_cast<int>(c1->get_id()) - static_cast<int>(c2->get_id());
|
||||
}
|
||||
};
|
||||
public:
|
||||
typedef splay_tree<clause *, compare> set;
|
||||
private:
|
||||
unsigned m_id; // clause unique id
|
||||
unsigned m_time; // how old is the clause.
|
||||
unsigned m_num_vars; // approx. number of variables (i.e., max_var_id + 1)
|
||||
unsigned m_sym_count; // number of symbols
|
||||
unsigned m_const_count; // number of constants
|
||||
unsigned m_depth; // depth (i.e., max depth of a literal)
|
||||
unsigned m_proof_depth;
|
||||
unsigned m_scope_lvl; // which scope level owns the clause
|
||||
unsigned m_num_lits[2]; // number of positive [0] and negative [1] literals.
|
||||
unsigned m_num_lits_capacity; // some of the clause literals can be simplified and removed, this field contains the original number of literals (used for GC).
|
||||
unsigned m_bidx; // position on the backtracking stack
|
||||
bool m_ground:1;
|
||||
bool m_processed:1;
|
||||
bool m_indexed:1;
|
||||
bool m_has_sel_lit:1;
|
||||
justification * m_justification;
|
||||
set m_children;
|
||||
literal m_lits[0];
|
||||
friend class context;
|
||||
|
||||
void set_fields(unsigned num_lits, literal * lits);
|
||||
unsigned get_bidx() const { return m_bidx; }
|
||||
void init(unsigned idx, unsigned time);
|
||||
void update_parents(ptr_buffer<clause> & parents);
|
||||
void set_bidx(unsigned idx) { SASSERT(m_bidx == UINT_MAX); m_bidx = idx; }
|
||||
void add_child(clause * c) { m_children.insert(c); }
|
||||
void del_child(clause * c) { m_children.erase(c); }
|
||||
void set_processed(bool f) { m_processed = f; }
|
||||
void set_indexed(bool f) { m_indexed = f; }
|
||||
void sort_literals();
|
||||
/**
|
||||
\brief Release ownership of the justification.
|
||||
*/
|
||||
justification * release_justification() { justification * r = m_justification; m_justification = 0; return r; }
|
||||
|
||||
clause(ast_manager & m, unsigned num_lits, literal * lits, justification * p, unsigned scope_lvl);
|
||||
|
||||
public:
|
||||
static clause * mk(ast_manager & m, unsigned num_lits, literal * lits, justification * p, unsigned scope_lvl);
|
||||
void deallocate(ast_manager & m);
|
||||
|
||||
unsigned get_id() const { SASSERT(m_id != UINT_MAX); return m_id; }
|
||||
unsigned get_time() const { return m_time; }
|
||||
unsigned get_symbol_count() const { return m_sym_count; }
|
||||
unsigned get_proof_depth() const { return m_proof_depth; }
|
||||
unsigned get_num_literals() const { return m_num_lits[0] + m_num_lits[1]; }
|
||||
unsigned get_num_literals_capacity() const { return m_num_lits_capacity; }
|
||||
unsigned get_num_pos_literals() const { return m_num_lits[0]; }
|
||||
unsigned get_num_neg_literals() const { return m_num_lits[1]; }
|
||||
unsigned get_depth() const { return m_depth; }
|
||||
unsigned get_const_count() const { return m_const_count; }
|
||||
unsigned get_scope_lvl() const { return m_scope_lvl; }
|
||||
unsigned get_num_vars() const { return m_num_vars; }
|
||||
bool empty() const { return m_num_lits[0] == 0 && m_num_lits[1] == 0; }
|
||||
literal const & get_literal(unsigned idx) const { return m_lits[idx]; }
|
||||
literal & get_literal(unsigned idx) { return m_lits[idx]; }
|
||||
literal * get_literals() const { return const_cast<literal*>(m_lits); }
|
||||
justification * get_justification() const { return m_justification; }
|
||||
bool is_processed() const { return m_processed; }
|
||||
bool is_indexed() const { return m_indexed; }
|
||||
bool is_ground() const { return m_ground; }
|
||||
void select_literal(unsigned idx);
|
||||
bool is_maximal(order & o, literal const & l, unsigned offset = 0, substitution * s = 0) const;
|
||||
bool is_sel_maximal(order & o, literal const & l, unsigned offset = 0, substitution * s = 0) const ;
|
||||
bool is_eligible_for_resolution(order & o, literal const & l, unsigned offset = 0, substitution * s = 0) const;
|
||||
bool is_eligible_for_paramodulation(order & o, literal const & l, unsigned offset = 0, substitution * s = 0) const;
|
||||
bool has_sel_lit() const { return m_has_sel_lit; }
|
||||
void try_to_orient_literals(order & o);
|
||||
void update_lits(ast_manager & m, unsigned num_lits, literal * lits, justification * j);
|
||||
|
||||
void display(std::ostream & out, ast_manager & m, bool detailed = false);
|
||||
unsigned hash() const { return m_id; }
|
||||
};
|
||||
|
||||
typedef ptr_vector<clause> clause_vector;
|
||||
|
||||
/**
|
||||
\brief Clause Statistics (used to build clauses, subsumption, etc).
|
||||
*/
|
||||
struct clause_stat : public expr_stat {
|
||||
unsigned m_num_lits[2];
|
||||
clause_stat() {
|
||||
m_num_lits[0] = 0;
|
||||
m_num_lits[1] = 0;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
\brief Compute the statistics for a clause with num_lits
|
||||
literals lits, and store the results in stat.
|
||||
*/
|
||||
void get_clause_stat(unsigned num_lits, literal * lits, clause_stat & stat);
|
||||
|
||||
/**
|
||||
\brief A mapping from clause-id's to clauses
|
||||
*/
|
||||
class id2clause {
|
||||
ptr_vector<clause> m_clauses;
|
||||
public:
|
||||
void insert(clause * c) { return m_clauses.setx(c->get_id(), c, 0); }
|
||||
void erase(clause * c) { unsigned id = c->get_id(); if (id < m_clauses.size()) m_clauses[id] = 0; }
|
||||
clause * operator()(unsigned id) const { return m_clauses.get(id, 0); }
|
||||
};
|
||||
};
|
||||
|
||||
#endif /* _SPC_CLAUSE_H_ */
|
||||
|
58
src/dead/spc/spc_clause_pos_set.h
Normal file
58
src/dead/spc/spc_clause_pos_set.h
Normal file
|
@ -0,0 +1,58 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
spc_clause_pos_set.h
|
||||
|
||||
Abstract:
|
||||
|
||||
A set of pairs (clause, index).
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2008-02-16.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _SPC_CLAUSE_POS_SET_H_
|
||||
#define _SPC_CLAUSE_POS_SET_H_
|
||||
|
||||
#include"hashtable.h"
|
||||
|
||||
namespace spc {
|
||||
|
||||
typedef std::pair<clause *, unsigned> clause_pos_pair;
|
||||
|
||||
class clause_pos_entry {
|
||||
clause_pos_pair m_data;
|
||||
public:
|
||||
typedef clause_pos_pair data;
|
||||
clause_pos_entry() { m_data.first = 0; }
|
||||
unsigned get_hash() const { return m_data.first->get_id(); }
|
||||
bool is_free() const { return m_data.first == 0; }
|
||||
bool is_deleted() const { return m_data.first == reinterpret_cast<clause *>(1); }
|
||||
bool is_used() const {
|
||||
return m_data.first != reinterpret_cast<clause *>(0) && m_data.first != reinterpret_cast<clause *>(1);
|
||||
}
|
||||
clause_pos_pair const & get_data() const { return m_data; }
|
||||
clause_pos_pair & get_data() { return m_data; }
|
||||
void set_data(clause_pos_pair const & d) {
|
||||
SASSERT(d.first != 0 && d.first != reinterpret_cast<clause*>(1));
|
||||
m_data = d;
|
||||
}
|
||||
void set_hash(unsigned h) { SASSERT(m_data.first->get_id() == h); }
|
||||
void mark_as_deleted() { m_data.first = reinterpret_cast<clause *>(1); }
|
||||
void mark_as_free() { m_data.first = 0; }
|
||||
};
|
||||
|
||||
struct clause_pos_pair_hash {
|
||||
unsigned operator()(clause_pos_pair const & p) const { return p.first->get_id(); }
|
||||
};
|
||||
|
||||
typedef core_hashtable<clause_pos_entry, clause_pos_pair_hash, default_eq<clause_pos_pair> > clause_pos_set;
|
||||
};
|
||||
|
||||
#endif /* _SPC_CLAUSE_POS_SET_H_ */
|
||||
|
121
src/dead/spc/spc_clause_selection.cpp
Normal file
121
src/dead/spc/spc_clause_selection.cpp
Normal file
|
@ -0,0 +1,121 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
spc_clause_selection.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Superposition Calculus Clause Selection
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2008-02-02.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#include"spc_clause_selection.h"
|
||||
|
||||
namespace spc {
|
||||
|
||||
const unsigned default_heap_size = 1024;
|
||||
|
||||
clause_selection::clause_selection(unsigned num_heaps, clause_eval * const * fs, unsigned * slot_size):
|
||||
m_curr_slot(0),
|
||||
m_counter(0),
|
||||
m_fs(num_heaps, fs) {
|
||||
SASSERT(num_heaps > 0);
|
||||
for (unsigned i = 0; i < num_heaps; i++) {
|
||||
m_heaps.push_back(alloc(heap<lt>, default_heap_size, lt(m_id2clause, *(fs[i]))));
|
||||
SASSERT(slot_size[i] > 0);
|
||||
m_slot_size.push_back(slot_size[i]);
|
||||
}
|
||||
}
|
||||
|
||||
clause_selection::~clause_selection() {
|
||||
std::for_each(m_heaps.begin(), m_heaps.end(), delete_proc<heap<lt> >());
|
||||
std::for_each(m_fs.begin(), m_fs.end(), delete_proc<clause_eval>());
|
||||
}
|
||||
|
||||
void clause_selection::reserve(unsigned cid) {
|
||||
unsigned capacity = m_heaps[0]->get_bounds();
|
||||
if (cid >= capacity) {
|
||||
unsigned new_capacity = 2 * cid + 1;
|
||||
SASSERT(cid < new_capacity);
|
||||
ptr_vector<heap<lt> >::iterator it = m_heaps.begin();
|
||||
ptr_vector<heap<lt> >::iterator end = m_heaps.end();
|
||||
for (; it != end; ++it) {
|
||||
heap<lt> * h = *it;
|
||||
h->reserve(new_capacity);;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void clause_selection::reset() {
|
||||
ptr_vector<heap<lt> >::iterator it = m_heaps.begin();
|
||||
ptr_vector<heap<lt> >::iterator end = m_heaps.end();
|
||||
for (; it != end; ++it) {
|
||||
heap<lt> * h = *it;
|
||||
h->reset();
|
||||
}
|
||||
}
|
||||
|
||||
void clause_selection::insert(clause * c) {
|
||||
reserve(c->get_id());
|
||||
m_id2clause.insert(c);
|
||||
ptr_vector<heap<lt> >::iterator it = m_heaps.begin();
|
||||
ptr_vector<heap<lt> >::iterator end = m_heaps.end();
|
||||
for (; it != end; ++it) {
|
||||
heap<lt> * h = *it;
|
||||
h->insert(c->get_id());
|
||||
}
|
||||
}
|
||||
|
||||
void clause_selection::erase(clause * c) {
|
||||
// remark: it is not necessary to remove c from m_id2clause
|
||||
ptr_vector<heap<lt> >::iterator it = m_heaps.begin();
|
||||
ptr_vector<heap<lt> >::iterator end = m_heaps.end();
|
||||
SASSERT(it != end);
|
||||
if (!(*it)->contains(c->get_id()))
|
||||
return;
|
||||
for (; it != end; ++it) {
|
||||
heap<lt> * h = *it;
|
||||
h->erase(c->get_id());
|
||||
}
|
||||
}
|
||||
|
||||
bool clause_selection::empty() const {
|
||||
ptr_vector<heap<lt> >::const_iterator it = m_heaps.begin();
|
||||
ptr_vector<heap<lt> >::const_iterator end = m_heaps.end();
|
||||
for (; it != end; ++it)
|
||||
if (!(*it)->empty())
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
clause * clause_selection::get_best() {
|
||||
heap<lt> * h = m_heaps[m_curr_slot];
|
||||
if (h->empty())
|
||||
return 0;
|
||||
unsigned cid = m_heaps[m_curr_slot]->erase_min();
|
||||
clause * c = m_id2clause(cid);
|
||||
SASSERT(c);
|
||||
// remove clause from the other heaps
|
||||
unsigned num_heaps = m_heaps.size();
|
||||
for (unsigned i = 0; i < num_heaps; i++) {
|
||||
if (m_curr_slot != i)
|
||||
m_heaps[i]->erase(cid);
|
||||
}
|
||||
// remark: it is not necessary to remove c from m_id2clause
|
||||
m_counter++;
|
||||
if (m_counter >= m_slot_size[m_curr_slot]) {
|
||||
m_counter = 0;
|
||||
m_curr_slot++;
|
||||
if (m_curr_slot >= m_slot_size.size())
|
||||
m_curr_slot = 0;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
};
|
85
src/dead/spc/spc_clause_selection.h
Normal file
85
src/dead/spc/spc_clause_selection.h
Normal file
|
@ -0,0 +1,85 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
spc_clause_selection.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Superposition Calculus Clause Selection
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2008-02-02.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _SPC_CLAUSE_SELECTION_H_
|
||||
#define _SPC_CLAUSE_SELECTION_H_
|
||||
|
||||
#include"spc_clause.h"
|
||||
#include"heap.h"
|
||||
|
||||
namespace spc {
|
||||
|
||||
/**
|
||||
\brief Abstract functor for evaluating how 'good' a clause is.
|
||||
Smaller values mean better clauses.
|
||||
*/
|
||||
struct clause_eval {
|
||||
virtual ~clause_eval() {}
|
||||
virtual unsigned operator()(clause * c) const = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
\brief Clause selection heuristic. It supports different priority queues.
|
||||
*/
|
||||
class clause_selection {
|
||||
class lt {
|
||||
id2clause & m_id2clause;
|
||||
clause_eval & m_func;
|
||||
public:
|
||||
lt(id2clause & m, clause_eval & f):
|
||||
m_id2clause(m), m_func(f) {}
|
||||
bool operator()(int cidx1, int cidx2) const {
|
||||
return m_func(m_id2clause(cidx1)) < m_func(m_id2clause(cidx2));
|
||||
}
|
||||
};
|
||||
|
||||
id2clause m_id2clause;
|
||||
ptr_vector<heap<lt> > m_heaps;
|
||||
unsigned_vector m_slot_size;
|
||||
unsigned m_curr_slot;
|
||||
unsigned m_counter;
|
||||
ptr_vector<clause_eval> m_fs;
|
||||
void reserve(unsigned cid);
|
||||
public:
|
||||
clause_selection(unsigned num_heaps, clause_eval * const * fs, unsigned * slots);
|
||||
~clause_selection();
|
||||
void insert(clause * c);
|
||||
void erase(clause * c);
|
||||
bool empty() const;
|
||||
void reset();
|
||||
clause * get_best();
|
||||
};
|
||||
|
||||
struct symbol_count_clause_eval : public clause_eval {
|
||||
virtual ~symbol_count_clause_eval() {}
|
||||
virtual unsigned operator()(clause * c) const { return c->get_symbol_count(); }
|
||||
};
|
||||
|
||||
struct time_clause_eval : public clause_eval {
|
||||
virtual ~time_clause_eval() {}
|
||||
virtual unsigned operator()(clause * c) const { return c->get_time(); }
|
||||
};
|
||||
|
||||
struct proof_depth_clause_eval : public clause_eval {
|
||||
virtual ~proof_depth_clause_eval() {}
|
||||
virtual unsigned operator()(clause * c) const { return c->get_proof_depth(); }
|
||||
};
|
||||
};
|
||||
|
||||
#endif /* _SPC_CLAUSE_SELECTION_H_ */
|
||||
|
504
src/dead/spc/spc_context.cpp
Normal file
504
src/dead/spc/spc_context.cpp
Normal file
|
@ -0,0 +1,504 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
spc_context.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Superposition Calculus Engine
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2008-02-02.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#include"spc_context.h"
|
||||
#include"buffer.h"
|
||||
#include"ast_pp.h"
|
||||
#include"ast_ll_pp.h"
|
||||
#include"ast_smt2_pp.h"
|
||||
#include"warning.h"
|
||||
|
||||
namespace spc {
|
||||
|
||||
context::context(ast_manager & m, order & o, clause_selection & cs, literal_selection & ls, simplifier & s, spc_params & params):
|
||||
m_manager(m),
|
||||
m_params(params),
|
||||
m_alloc(m.get_allocator()),
|
||||
m_order(o),
|
||||
m_cls_sel(cs),
|
||||
m_lit_sel(ls),
|
||||
m_simplifier(s),
|
||||
m_time(0),
|
||||
m_scope_lvl(0),
|
||||
m_sem_taut(m),
|
||||
m_asserted_literals(m),
|
||||
m_rewriter(m, s, m_order, m_asserted_literals),
|
||||
m_der(m),
|
||||
m_subsumption(m, m_asserted_literals, params),
|
||||
m_eq_resolution(m, m_order, m_stats),
|
||||
m_factoring(m, m_order, m_stats),
|
||||
m_superposition(m, m_order, m_stats),
|
||||
m_unsat(0) {
|
||||
m_order.reserve_offsets(3);
|
||||
}
|
||||
|
||||
context::~context() {
|
||||
reset();
|
||||
}
|
||||
|
||||
void context::reset() {
|
||||
m_cls_sel.reset();
|
||||
m_time = 0;
|
||||
m_scope_lvl = 0;
|
||||
|
||||
if (m_unsat)
|
||||
m_unsat = 0;
|
||||
for (unsigned i = 0; i <= m_scope_lvl; i++) {
|
||||
del_clauses(i);
|
||||
if (i < m_clauses_to_unfreeze.size())
|
||||
m_clauses_to_unfreeze[i].reset();
|
||||
}
|
||||
|
||||
m_asserted_literals.reset();
|
||||
m_rewriter.reset();
|
||||
m_subsumption.reset();
|
||||
m_superposition.reset();
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Insert the given clause into the indexes of processed clauses.
|
||||
*/
|
||||
void context::insert_index(clause * cls) {
|
||||
TRACE("insert_index", tout << "indexing clause, num_vars: " << cls->get_num_vars() << "\n";
|
||||
cls->display(tout, m_manager); tout << "\n";);
|
||||
m_order.reserve_vars(cls->get_num_vars());
|
||||
m_lit_sel(cls);
|
||||
m_asserted_literals.insert(cls);
|
||||
m_rewriter.insert(cls);
|
||||
m_subsumption.insert(cls);
|
||||
m_superposition.insert(cls);
|
||||
cls->set_indexed(true);
|
||||
}
|
||||
|
||||
void context::erase_index(clause * cls) {
|
||||
if (cls->is_indexed()) {
|
||||
m_asserted_literals.erase(cls);
|
||||
m_rewriter.erase(cls);
|
||||
m_subsumption.erase(cls);
|
||||
m_superposition.erase(cls);
|
||||
cls->set_indexed(false);
|
||||
}
|
||||
}
|
||||
|
||||
void context::set_conflict(clause * cls) {
|
||||
SASSERT(cls->get_num_literals() == 0);
|
||||
m_unsat = cls;
|
||||
if (m_params.m_spc_trace) {
|
||||
cls->display(std::cout, m_manager); std::cout << " ";
|
||||
cls->get_justification()->display(std::cout);
|
||||
std::cout << "\n";
|
||||
std::cout.flush();
|
||||
}
|
||||
}
|
||||
|
||||
void context::del_clause(clause * cls) {
|
||||
TRACE("context", tout << "deleting clause:\n"; cls->display(tout, m_manager); tout << "\n";);
|
||||
m_stats.m_num_del_clause++;
|
||||
|
||||
erase_index(cls);
|
||||
if (!cls->is_processed())
|
||||
m_cls_sel.erase(cls);
|
||||
|
||||
unsigned scope_lvl = cls->get_scope_lvl();
|
||||
unsigned bidx = cls->get_bidx();
|
||||
m_clauses_to_delete[scope_lvl][bidx] = 0;
|
||||
|
||||
cls->deallocate(m_manager);
|
||||
}
|
||||
|
||||
void context::freeze_clause_until(clause * cls, unsigned scope_lvl) {
|
||||
if (cls->get_scope_lvl() >= scope_lvl) {
|
||||
del_clause(cls);
|
||||
return;
|
||||
}
|
||||
TRACE("context", tout << "freezing clause until: " << scope_lvl << ":\n"; cls->display(tout, m_manager); tout << "\n";);
|
||||
if (scope_lvl >= m_clauses_to_unfreeze.size())
|
||||
m_clauses_to_unfreeze.resize(scope_lvl+1, clause_vector());
|
||||
|
||||
erase_index(cls);
|
||||
cls->set_processed(false);
|
||||
|
||||
m_clauses_to_unfreeze[scope_lvl].push_back(cls);
|
||||
}
|
||||
|
||||
void context::unfreeze_clause(clause * cls) {
|
||||
TRACE("context", tout << "unfreezing clausel: "; cls->display(tout, m_manager); tout << "\n";);
|
||||
SASSERT(!cls->is_processed());
|
||||
m_cls_sel.insert(cls);
|
||||
}
|
||||
|
||||
void context::init_clause(clause * cls) {
|
||||
m_stats.m_num_mk_clause++;
|
||||
|
||||
cls->init(m_cls_id_gen.mk(), m_time);
|
||||
m_time++;
|
||||
unsigned scope_lvl = cls->get_scope_lvl();
|
||||
|
||||
if (scope_lvl >= m_clauses_to_delete.size())
|
||||
m_clauses_to_delete.resize(scope_lvl+1, clause_vector());
|
||||
|
||||
clause_vector & cv = m_clauses_to_delete[scope_lvl];
|
||||
unsigned bidx = cv.size();
|
||||
cv.push_back(cls);
|
||||
cls->set_bidx(bidx);
|
||||
}
|
||||
|
||||
clause * context::mk_clause(unsigned num_lits, literal * lits, justification * p, unsigned scope_lvl) {
|
||||
clause * cls = clause::mk(m_manager, num_lits, lits, p, scope_lvl);
|
||||
init_clause(cls);
|
||||
return cls;
|
||||
}
|
||||
|
||||
void context::assert_expr(expr * n, proof * p, unsigned scope_lvl) {
|
||||
TRACE("spc_assert_expr", tout << mk_ismt2_pp(n, m_manager) << "\n";);
|
||||
SASSERT(scope_lvl <= m_scope_lvl);
|
||||
justification_ref ref(m_manager);
|
||||
ref = justification_proof_wrapper::mk(p, m_manager);
|
||||
assert_expr(n, ref, scope_lvl);
|
||||
}
|
||||
|
||||
void invalid_clause(expr * n) {
|
||||
warning_msg("ignoring formula containing an universally quantified boolean variable.");
|
||||
}
|
||||
|
||||
void context::assert_expr(expr * n, justification * p, unsigned scope_lvl) {
|
||||
SASSERT(scope_lvl <= m_scope_lvl);
|
||||
buffer<literal> lits;
|
||||
if (is_forall(n))
|
||||
n = to_quantifier(n)->get_expr();
|
||||
if (m_manager.is_or(n)) {
|
||||
unsigned num = to_app(n)->get_num_args();
|
||||
for (unsigned i = 0; i < num; i++) {
|
||||
expr * c = to_app(n)->get_arg(i);
|
||||
bool is_neg = m_manager.is_not(c);
|
||||
if (is_var(c) || (is_neg && is_var(to_app(c)->get_arg(0)))) {
|
||||
invalid_clause(n);
|
||||
return;
|
||||
}
|
||||
if (is_neg)
|
||||
lits.push_back(literal(to_app(c)->get_arg(0), true));
|
||||
else
|
||||
lits.push_back(literal(c, false));
|
||||
}
|
||||
}
|
||||
else if (m_manager.is_false(n)) {
|
||||
// skip
|
||||
}
|
||||
else if (m_manager.is_not(n)) {
|
||||
if (is_var(to_app(n)->get_arg(0))) {
|
||||
invalid_clause(n);
|
||||
return;
|
||||
}
|
||||
lits.push_back(literal(to_app(n)->get_arg(0), true));
|
||||
}
|
||||
else {
|
||||
if (is_var(n)) {
|
||||
invalid_clause(n);
|
||||
return;
|
||||
}
|
||||
lits.push_back(literal(n, false));
|
||||
}
|
||||
|
||||
if (trivial(lits.size(), lits.c_ptr()))
|
||||
return;
|
||||
|
||||
clause * cls = mk_clause(lits.size(), lits.c_ptr(), p, scope_lvl);
|
||||
m_cls_sel.insert(cls);
|
||||
if (cls->get_num_literals() == 0)
|
||||
set_conflict(cls);
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Return true if the given clause (set of literals) is trivial.
|
||||
That is, it contains the literal s = s or complementary literals.
|
||||
*/
|
||||
bool context::trivial(unsigned num_lits, literal * lits) {
|
||||
SASSERT(m_found_literals.empty());
|
||||
for (unsigned i = 0; i < num_lits; i++) {
|
||||
literal l = lits[i];
|
||||
if (m_found_literals.contains_neg(l) || l.is_true(m_manager)) {
|
||||
m_found_literals.reset();
|
||||
m_stats.m_num_trivial++;
|
||||
return true;
|
||||
}
|
||||
m_found_literals.insert(l);
|
||||
}
|
||||
m_found_literals.reset();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool context::trivial(clause * cls) {
|
||||
return trivial(cls->get_num_literals(), cls->get_literals());
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Simplify the given clause using the set of processed clauses.
|
||||
Return the simplified clause.
|
||||
*/
|
||||
clause * context::simplify(clause * cls) {
|
||||
clause * old_cls = cls;
|
||||
m_der(cls);
|
||||
cls = m_rewriter(old_cls);
|
||||
if (cls != old_cls) {
|
||||
// freeze old clause until simplified clause is deleted.
|
||||
freeze_clause_until(old_cls, cls->get_scope_lvl());
|
||||
init_clause(cls);
|
||||
m_stats.m_num_simplified++;
|
||||
}
|
||||
m_der(cls);
|
||||
return cls;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Use the given clause to simplify the set of processed clauses.
|
||||
|
||||
\remark: processed clauses that can be simplified, are moved to the
|
||||
set of unprocessed clauses.
|
||||
*/
|
||||
void context::simplify_processed(clause * cls) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Return true if the clause is redundant.
|
||||
*/
|
||||
bool context::redundant(clause * cls) {
|
||||
int r_scope_lvl = -1;
|
||||
if (trivial(cls)) {
|
||||
TRACE("redundant", tout << "clause is trivial:\n"; cls->display(tout, m_manager); tout << "\n";);
|
||||
r_scope_lvl = 0;
|
||||
}
|
||||
else if (m_sem_taut(cls->get_num_literals(), cls->get_literals())) {
|
||||
TRACE("redundant", tout << "clause is a semantic tautology:\n"; cls->display(tout, m_manager); tout << "\n";);
|
||||
r_scope_lvl = 0;
|
||||
}
|
||||
else {
|
||||
clause * subsumer = m_subsumption.forward(cls);
|
||||
if (subsumer != 0) {
|
||||
TRACE("redundant", tout << "clause was subsumed: "; cls->display(tout, m_manager);
|
||||
tout << "\nsubsumer:\n"; subsumer->display(tout, m_manager); tout << "\n";);
|
||||
r_scope_lvl = subsumer->get_scope_lvl();
|
||||
m_stats.m_num_subsumed++;
|
||||
}
|
||||
}
|
||||
|
||||
if (r_scope_lvl >= 0) {
|
||||
m_stats.m_num_redundant++;
|
||||
TRACE("spc_saturate", tout << "clause is redundant until level: " << r_scope_lvl << " ...\n";);
|
||||
freeze_clause_until(cls, r_scope_lvl);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Process a newly generated clause.
|
||||
*/
|
||||
void context::process_new_clause(clause * cls) {
|
||||
if (cls) {
|
||||
SASSERT(cls->get_justification() != 0);
|
||||
init_clause(cls);
|
||||
if (trivial(cls)) {
|
||||
del_clause(cls);
|
||||
return;
|
||||
}
|
||||
cls = simplify(cls);
|
||||
if (trivial(cls)) {
|
||||
del_clause(cls);
|
||||
return;
|
||||
}
|
||||
// if (!redundant(cls)) {
|
||||
m_cls_sel.insert(cls);
|
||||
if (cls->get_num_literals() == 0)
|
||||
set_conflict(cls);
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Apply superposition (left&right), resolution, (equality) factoring, and equality resolution
|
||||
with the given clause and the set of processed clauses.
|
||||
*/
|
||||
void context::generate(clause * cls) {
|
||||
m_new_clauses.reset();
|
||||
m_eq_resolution(cls, m_new_clauses);
|
||||
m_factoring(cls, m_new_clauses);
|
||||
m_superposition(cls, m_new_clauses);
|
||||
|
||||
ptr_vector<clause>::iterator it = m_new_clauses.begin();
|
||||
ptr_vector<clause>::iterator end = m_new_clauses.end();
|
||||
for (; it != end; ++it) {
|
||||
TRACE("spc_generate", tout << "new generated clause:\n"; (*it)->display(tout, m_manager); tout << "\n";);
|
||||
process_new_clause(*it);
|
||||
}
|
||||
}
|
||||
|
||||
void context::saturate(unsigned threshold) {
|
||||
if (inconsistent())
|
||||
return;
|
||||
TRACE("spc_saturate", tout << "initial state:\n"; display(tout););
|
||||
unsigned i = 0;
|
||||
ptr_buffer<clause> to_simplify;
|
||||
while (i < threshold && !processed_all()) {
|
||||
i++;
|
||||
m_stats.m_num_processed++;
|
||||
clause * cls = m_cls_sel.get_best();
|
||||
if (m_params.m_spc_trace) {
|
||||
cls->display(std::cout, m_manager); std::cout << " ";
|
||||
cls->get_justification()->display(std::cout);
|
||||
std::cout << "\n";
|
||||
std::cout.flush();
|
||||
}
|
||||
cls->set_processed(true);
|
||||
TRACE("spc_saturate", tout << "get best: "; cls->display(tout, m_manager); tout << "\n";);
|
||||
cls = simplify(cls);
|
||||
|
||||
TRACE("spc_saturate", tout << "clause after simplification: "; cls->display(tout, m_manager); tout << "\n";);
|
||||
if (redundant(cls))
|
||||
continue;
|
||||
if (cls->empty()) {
|
||||
set_conflict(cls);
|
||||
break;
|
||||
}
|
||||
cls->try_to_orient_literals(m_order);
|
||||
simplify_processed(cls);
|
||||
insert_index(cls);
|
||||
generate(cls);
|
||||
if (inconsistent())
|
||||
break;
|
||||
}
|
||||
|
||||
TRACE("spc_saturate", tout << "final state:\n"; display(tout););
|
||||
|
||||
#if 0
|
||||
IF_VERBOSE(10000,
|
||||
display(std::cout););
|
||||
display_statistics(std::cout);
|
||||
if (m_unsat && m_manager.fine_grain_proofs()) {
|
||||
std::cout << mk_ll_pp(m_unsat->get_justification()->get_proof(), m_manager);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void context::push_scope() {
|
||||
m_scope_lvl++;
|
||||
m_time_trail.push_back(m_time);
|
||||
}
|
||||
|
||||
void context::del_clauses(unsigned scope_lvl) {
|
||||
if (scope_lvl < m_clauses_to_delete.size()) {
|
||||
clause_vector & cv = m_clauses_to_delete[m_scope_lvl];
|
||||
clause_vector::iterator it = cv.begin();
|
||||
clause_vector::iterator end = cv.end();
|
||||
for (; it != end; ++it) {
|
||||
clause * cls = *it;
|
||||
if (cls)
|
||||
del_clause(cls);
|
||||
}
|
||||
cv.reset();
|
||||
}
|
||||
}
|
||||
|
||||
void context::unfreeze_clauses(unsigned scope_lvl) {
|
||||
if (scope_lvl < m_clauses_to_unfreeze.size()) {
|
||||
clause_vector & cv = m_clauses_to_unfreeze[m_scope_lvl];
|
||||
clause_vector::iterator it = cv.begin();
|
||||
clause_vector::iterator end = cv.end();
|
||||
for (; it != end; ++it)
|
||||
unfreeze_clause(*it);
|
||||
cv.reset();
|
||||
}
|
||||
}
|
||||
|
||||
void context::pop_scope(unsigned num_scopes) {
|
||||
SASSERT(num_scopes >= m_scope_lvl);
|
||||
unsigned new_lvl = m_scope_lvl - num_scopes;
|
||||
m_time = m_time_trail[new_lvl];
|
||||
m_time_trail.shrink(new_lvl);
|
||||
|
||||
if (m_unsat && new_lvl < m_unsat->get_scope_lvl())
|
||||
m_unsat = 0;
|
||||
|
||||
while (m_scope_lvl > new_lvl) {
|
||||
del_clauses(m_scope_lvl);
|
||||
unfreeze_clauses(m_scope_lvl);
|
||||
m_scope_lvl --;
|
||||
}
|
||||
}
|
||||
|
||||
void context::display(std::ostream & out, vector<clause_vector> const & cvs, unsigned scope_lvl, bool frozen) const {
|
||||
if (scope_lvl < cvs.size()) {
|
||||
bool first = true;
|
||||
clause_vector const & cv = cvs[scope_lvl];
|
||||
clause_vector::const_iterator it = cv.begin();
|
||||
clause_vector::const_iterator end = cv.end();
|
||||
for (; it != end; ++it) {
|
||||
clause * cls = *it;
|
||||
if (cls) {
|
||||
if (first) {
|
||||
out << "level " << scope_lvl << ":\n";
|
||||
first = false;
|
||||
}
|
||||
cls->display(out, m_manager);
|
||||
if (frozen)
|
||||
out << " [frozen]";
|
||||
out << "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void context::display(std::ostream & out) const {
|
||||
for (unsigned i = 0; i <= m_scope_lvl; i++) {
|
||||
display(out, m_clauses_to_delete, i, false);
|
||||
display(out, m_clauses_to_unfreeze, i, true);
|
||||
}
|
||||
}
|
||||
|
||||
void context::display_statistics(std::ostream & out) const {
|
||||
m_stats.display(out);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Generate new clauses
|
||||
|
||||
5) Object equality resolution 1
|
||||
|
||||
(R or X = i)
|
||||
==>
|
||||
sigma(R)
|
||||
|
||||
sigma = { X -> j }
|
||||
where i and j are distinct objects
|
||||
sigma(X = i) is not smaller or equal than any other literal in the clause
|
||||
|
||||
6) Object equality resolution 2
|
||||
|
||||
(R or X = Y)
|
||||
==>
|
||||
sigma(R)
|
||||
|
||||
sigma = { X -> i, Y -> j }
|
||||
For every pair of distinct objects i and j
|
||||
sigma(X = Y) is not smaller or equal than any other literal in the clause
|
||||
|
||||
*/
|
||||
|
||||
};
|
122
src/dead/spc/spc_context.h
Normal file
122
src/dead/spc/spc_context.h
Normal file
|
@ -0,0 +1,122 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
spc_context.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Superposition Calculus Engine
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2008-02-02.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _SPC_CONTEXT_H_
|
||||
#define _SPC_CONTEXT_H_
|
||||
|
||||
#include"spc_params.h"
|
||||
#include"spc_clause.h"
|
||||
#include"spc_clause_selection.h"
|
||||
#include"spc_literal_selection.h"
|
||||
#include"spc_semantic_tautology.h"
|
||||
#include"spc_rewriter.h"
|
||||
#include"spc_asserted_literals.h"
|
||||
#include"spc_subsumption.h"
|
||||
#include"spc_eq_resolution.h"
|
||||
#include"spc_factoring.h"
|
||||
#include"spc_superposition.h"
|
||||
#include"spc_statistics.h"
|
||||
#include"spc_der.h"
|
||||
#include"substitution_tree.h"
|
||||
#include"order.h"
|
||||
|
||||
namespace spc {
|
||||
|
||||
/**
|
||||
\brief Logical context of the superposition calculus engine.
|
||||
*/
|
||||
class context {
|
||||
public:
|
||||
statistics m_stats;
|
||||
protected:
|
||||
typedef clause::set clause_set;
|
||||
|
||||
ast_manager & m_manager;
|
||||
spc_params & m_params;
|
||||
small_object_allocator & m_alloc;
|
||||
order & m_order;
|
||||
clause_selection & m_cls_sel;
|
||||
literal_selection & m_lit_sel;
|
||||
simplifier & m_simplifier;
|
||||
unsigned m_time;
|
||||
unsigned m_scope_lvl;
|
||||
id_gen m_cls_id_gen;
|
||||
found_literals m_found_literals;
|
||||
semantic_tautology m_sem_taut;
|
||||
asserted_literals m_asserted_literals;
|
||||
rewriter m_rewriter;
|
||||
der m_der;
|
||||
subsumption m_subsumption;
|
||||
eq_resolution m_eq_resolution;
|
||||
factoring m_factoring;
|
||||
superposition m_superposition;
|
||||
vector<clause_vector> m_clauses_to_unfreeze;
|
||||
vector<clause_vector> m_clauses_to_delete;
|
||||
unsigned_vector m_time_trail;
|
||||
clause * m_unsat;
|
||||
ptr_vector<clause> m_new_clauses;
|
||||
|
||||
void insert_index(clause * cls);
|
||||
void erase_index(clause * cls);
|
||||
|
||||
void init_clause(clause * cls);
|
||||
clause * mk_clause(unsigned num_lits, literal * lits, justification * p, unsigned scope_lvl);
|
||||
|
||||
void del_clause(clause * cls);
|
||||
void del_clauses(unsigned scope_lvl);
|
||||
|
||||
void freeze_clause_until(clause * cls, unsigned scope_lvl);
|
||||
void unfreeze_clause(clause * cls);
|
||||
void unfreeze_clauses(unsigned scope_lvl);
|
||||
|
||||
bool trivial(unsigned num_lits, literal * lits);
|
||||
bool trivial(clause * cls);
|
||||
clause * simplify(clause * cls);
|
||||
void simplify_processed(clause * cls);
|
||||
bool redundant(clause * cls);
|
||||
void generate(clause * cls);
|
||||
void process_new_clause(clause * cls);
|
||||
|
||||
void display(std::ostream & out, vector<clause_vector> const & cvs, unsigned scope_lvl, bool frozen) const;
|
||||
|
||||
void set_conflict(clause * cls);
|
||||
|
||||
public:
|
||||
context(ast_manager & m, order & o, clause_selection & cs, literal_selection & ls, simplifier & s, spc_params & params);
|
||||
~context();
|
||||
|
||||
simplifier & get_simplifier() { return m_simplifier; }
|
||||
order & get_order() { return m_order; }
|
||||
ast_manager & get_manager() { return m_manager; }
|
||||
|
||||
unsigned get_scope_lvl() const { return m_scope_lvl; }
|
||||
|
||||
void assert_expr(expr * n, proof * p, unsigned scope_lvl = 0);
|
||||
void assert_expr(expr * n, justification * p, unsigned scope_lvl = 0);
|
||||
void saturate(unsigned threshold);
|
||||
bool inconsistent() const { return m_unsat != 0; }
|
||||
bool processed_all() const { return m_cls_sel.empty(); }
|
||||
void push_scope();
|
||||
void pop_scope(unsigned num_scopes);
|
||||
void reset();
|
||||
void display(std::ostream & out) const;
|
||||
void display_statistics(std::ostream & out) const;
|
||||
};
|
||||
};
|
||||
|
||||
#endif /* _SPC_CONTEXT_H_ */
|
135
src/dead/spc/spc_decl_plugin.cpp
Normal file
135
src/dead/spc/spc_decl_plugin.cpp
Normal file
|
@ -0,0 +1,135 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
spc_decl_plugin.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
<abstract>
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2008-02-12.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#include"spc_decl_plugin.h"
|
||||
|
||||
std::ostream & operator<<(std::ostream & out, spc_op_kind k) {
|
||||
switch (k) {
|
||||
case PR_DEMODULATION: out << "demod"; break;
|
||||
case PR_SPC_REWRITE: out << "rewrite"; break;
|
||||
case PR_SPC_RESOLUTION: out << "res"; break;
|
||||
case PR_SUPERPOSITION: out << "sup"; break;
|
||||
case PR_EQUALITY_RESOLUTION: out << "eq_res"; break;
|
||||
case PR_FACTORING: out << "fact"; break;
|
||||
case PR_SPC_DER: out << "der"; break;
|
||||
case PR_SPC_ASSERTED: out << "asserted"; break;
|
||||
default: out << "unknown"; break;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
spc_decl_plugin::spc_decl_plugin() :
|
||||
m_demodulation("demod"),
|
||||
m_spc_rewrite("sp-rw"),
|
||||
m_spc_resolution("sp-res"),
|
||||
m_superposition("sp"),
|
||||
m_equality_resolution("eq-res"),
|
||||
m_factoring("fact"),
|
||||
m_spc_der("spc-der") {
|
||||
}
|
||||
|
||||
spc_decl_plugin::~spc_decl_plugin() {
|
||||
}
|
||||
|
||||
sort * spc_decl_plugin::mk_sort(decl_kind k, unsigned num_parameters, parameter const* parameters) {
|
||||
UNREACHABLE();
|
||||
return 0;
|
||||
}
|
||||
|
||||
func_decl * spc_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
|
||||
unsigned arity, sort * const * domain, sort * range) {
|
||||
|
||||
#define MK_PROOF(SYM) m_manager->mk_func_decl(SYM, arity, domain, m_manager->mk_proof_sort(), func_decl_info(m_family_id, k))
|
||||
|
||||
SASSERT(num_parameters == 0);
|
||||
switch (k) {
|
||||
/*
|
||||
#1: (forall (x) (= t[x] s[x]))
|
||||
[demod #1] (= t[a] s[a])
|
||||
*/
|
||||
case PR_DEMODULATION: return MK_PROOF(m_demodulation);
|
||||
/*
|
||||
Justifies a rewriting (simplification step) in the superposition engine.
|
||||
It has n+1 antecedents. The first antecedent is the clause being simplified.
|
||||
The other antecedents are demodulators.
|
||||
The consequent is the simplied clause.
|
||||
*/
|
||||
case PR_SPC_REWRITE: return MK_PROOF(m_spc_rewrite);
|
||||
/*
|
||||
Resolution proof:
|
||||
|
||||
#1: (or C l)
|
||||
#2: (or D (not l'))
|
||||
[sp-res #1 #2]: sigma(or C D)
|
||||
|
||||
where sigma is the mgu of l and l'
|
||||
|
||||
*/
|
||||
case PR_SPC_RESOLUTION: return MK_PROOF(m_spc_resolution);
|
||||
/*
|
||||
Superposition proof:
|
||||
|
||||
#1: (or (= s t) R)
|
||||
#2: D[u]
|
||||
[sp #1 #2]: sigma(or R D[t])
|
||||
|
||||
where sigma is the mgu(u, s)
|
||||
*/
|
||||
case PR_SUPERPOSITION: return MK_PROOF(m_superposition);
|
||||
/*
|
||||
Equality resolution proof:
|
||||
|
||||
#1: (or (not (= s t)) R)
|
||||
[eq-res #1]: sigma R
|
||||
|
||||
where sigma is the mgu of s and t.
|
||||
*/
|
||||
case PR_EQUALITY_RESOLUTION: return MK_PROOF(m_equality_resolution);
|
||||
/*
|
||||
Proof object for factoring and equality-factoring:
|
||||
|
||||
#1: (or P[t] P[s] R)
|
||||
[fact #1]: sigma(or P[t] R)
|
||||
|
||||
where sigma is the mgu(t,s)
|
||||
|
||||
#1: (or (= s t) (= u v) R)
|
||||
[fact #1]: sigma(or (not (= t v)) (= u v) R)
|
||||
|
||||
where sigma = mgu(s, u)
|
||||
*/
|
||||
case PR_FACTORING: return MK_PROOF(m_factoring);
|
||||
/*
|
||||
Proof object for destructive equality resolution:
|
||||
|
||||
#1: (or (not (= x t)) C[x])
|
||||
[spc-der #1]: C[t]
|
||||
|
||||
t does not contain x.
|
||||
|
||||
Several variables may be eliminated simultaneously.
|
||||
*/
|
||||
case PR_SPC_DER: return MK_PROOF(m_spc_der);
|
||||
default:
|
||||
UNREACHABLE();
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
61
src/dead/spc/spc_decl_plugin.h
Normal file
61
src/dead/spc/spc_decl_plugin.h
Normal file
|
@ -0,0 +1,61 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
spc_decl_plugin.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Proof declarations for Superposition Calculus Engine.
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2008-02-12.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _SPC_DECL_PLUGIN_H_
|
||||
#define _SPC_DECL_PLUGIN_H_
|
||||
|
||||
#include"ast.h"
|
||||
|
||||
enum spc_op_kind {
|
||||
PR_DEMODULATION,
|
||||
PR_SPC_REWRITE,
|
||||
PR_SPC_RESOLUTION,
|
||||
PR_SUPERPOSITION,
|
||||
PR_EQUALITY_RESOLUTION,
|
||||
PR_FACTORING,
|
||||
PR_SPC_DER,
|
||||
PR_SPC_ASSERTED,
|
||||
PR_SPC_LAST_ID
|
||||
};
|
||||
|
||||
std::ostream & operator<<(std::ostream & out, spc_op_kind k);
|
||||
|
||||
class spc_decl_plugin : public decl_plugin {
|
||||
symbol m_demodulation;
|
||||
symbol m_spc_rewrite;
|
||||
symbol m_spc_resolution;
|
||||
symbol m_superposition;
|
||||
symbol m_equality_resolution;
|
||||
symbol m_factoring;
|
||||
symbol m_spc_der;
|
||||
|
||||
public:
|
||||
spc_decl_plugin();
|
||||
|
||||
virtual ~spc_decl_plugin();
|
||||
|
||||
virtual decl_plugin * mk_fresh() { return alloc(spc_decl_plugin); }
|
||||
|
||||
virtual sort * mk_sort(decl_kind k, unsigned num_parameters, parameter const* parameters);
|
||||
|
||||
virtual func_decl * mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
|
||||
unsigned arity, sort * const * domain, sort * range);
|
||||
};
|
||||
|
||||
#endif /* _SPC_DECL_PLUGIN_H_ */
|
||||
|
80
src/dead/spc/spc_der.cpp
Normal file
80
src/dead/spc/spc_der.cpp
Normal file
|
@ -0,0 +1,80 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
spc_der.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
<abstract>
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2008-02-17.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#include"spc_der.h"
|
||||
#include"occurs.h"
|
||||
|
||||
namespace spc {
|
||||
|
||||
der::der(ast_manager & m):
|
||||
m_manager(m),
|
||||
m_subst(m),
|
||||
m_spc_fid(m.get_family_id("spc")) {
|
||||
m_subst.reserve_offsets(1);
|
||||
}
|
||||
|
||||
void der::apply(clause * cls, unsigned j, expr * lhs, expr * rhs) {
|
||||
TRACE("der", tout << "applying der at: " << j << "\n"; cls->display(tout, m_manager); tout << "\n";);
|
||||
m_subst.reserve_vars(cls->get_num_vars());
|
||||
m_subst.reset();
|
||||
m_subst.insert(expr_offset(lhs, 0), expr_offset(rhs, 0));
|
||||
literal_buffer new_lits(m_manager);
|
||||
unsigned num_lits = cls->get_num_literals();
|
||||
for (unsigned i = 0; i < num_lits; i++) {
|
||||
if (i != j) {
|
||||
literal const & l = cls->get_literal(i);
|
||||
expr_ref new_atom(m_manager);
|
||||
m_subst.apply(l.atom(), new_atom);
|
||||
new_lits.push_back(literal(new_atom, l.sign()));
|
||||
}
|
||||
}
|
||||
justification * js = mk_der_justification(m_manager, m_spc_fid, cls->get_justification(), new_lits.size(), new_lits.c_ptr());
|
||||
cls->update_lits(m_manager, new_lits.size(), new_lits.c_ptr(), js);
|
||||
}
|
||||
|
||||
bool der::apply(clause * cls) {
|
||||
unsigned num_lits = cls->get_num_literals();
|
||||
for (unsigned i = 0; i < num_lits; i++) {
|
||||
literal const & l = cls->get_literal(i);
|
||||
if (l.sign() && m_manager.is_eq(l.atom())) {
|
||||
expr * lhs = l.lhs();
|
||||
expr * rhs = l.rhs();
|
||||
if (is_var(lhs) && !occurs(lhs, rhs)) {
|
||||
apply(cls, i, lhs, rhs);
|
||||
return true;
|
||||
}
|
||||
else if (is_var(rhs) && !occurs(rhs, lhs)) {
|
||||
apply(cls, i, rhs, lhs);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Clause cls is destructively updated.
|
||||
*/
|
||||
void der::operator()(clause * cls) {
|
||||
while(apply(cls))
|
||||
;
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
52
src/dead/spc/spc_der.h
Normal file
52
src/dead/spc/spc_der.h
Normal file
|
@ -0,0 +1,52 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
spc_der.h
|
||||
|
||||
Abstract:
|
||||
|
||||
<abstract>
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2008-02-17.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _SPC_DER_H_
|
||||
#define _SPC_DER_H_
|
||||
|
||||
#include"spc_clause.h"
|
||||
|
||||
namespace spc {
|
||||
|
||||
/**
|
||||
\brief Functor for applying destructive equality resolution.
|
||||
This is similar to the Functor in der.h, but this one applies
|
||||
the simplification on clauses instead of ast's.
|
||||
|
||||
x != s or R
|
||||
==>
|
||||
sigma(R)
|
||||
|
||||
where
|
||||
sigma = mgu(x, s)
|
||||
*/
|
||||
class der {
|
||||
ast_manager & m_manager;
|
||||
substitution m_subst;
|
||||
unsigned_vector m_to_keep;
|
||||
family_id m_spc_fid;
|
||||
void apply(clause * cls, unsigned j, expr * lhs, expr * rhs);
|
||||
bool apply(clause * cls);
|
||||
public:
|
||||
der(ast_manager & m);
|
||||
void operator()(clause * cls);
|
||||
};
|
||||
};
|
||||
|
||||
#endif /* _SPC_DER_H_ */
|
||||
|
44
src/dead/spc/spc_eq_resolution.cpp
Normal file
44
src/dead/spc/spc_eq_resolution.cpp
Normal file
|
@ -0,0 +1,44 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
spc_eq_resolution.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
<abstract>
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2008-02-14.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#include"spc_eq_resolution.h"
|
||||
|
||||
namespace spc {
|
||||
|
||||
/**
|
||||
\brief Apply equality resolution rule on the given clause.
|
||||
Store the produced clauses in new_clauses.
|
||||
*/
|
||||
void eq_resolution::operator()(clause * cls, ptr_vector<clause> & new_clauses) {
|
||||
m_subst.reserve_vars(cls->get_num_vars());
|
||||
unsigned num = cls->get_num_literals();
|
||||
for (unsigned i = 0; i < num; i++) {
|
||||
literal const & l = cls->get_literal(i);
|
||||
expr * atom = l.atom();
|
||||
if (l.sign() && m_manager.is_eq(atom)) {
|
||||
expr * lhs = to_app(atom)->get_arg(0);
|
||||
expr * rhs = to_app(atom)->get_arg(1);
|
||||
m_subst.reset();
|
||||
if (m_unifier(lhs, rhs, m_subst, false) && cls->is_eligible_for_resolution(m_order, l, 0, &m_subst)) {
|
||||
m_stats.m_num_eq_resolution++;
|
||||
new_clauses.push_back(mk_result(cls, i));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
50
src/dead/spc/spc_eq_resolution.h
Normal file
50
src/dead/spc/spc_eq_resolution.h
Normal file
|
@ -0,0 +1,50 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
spc_eq_resolution.h
|
||||
|
||||
Abstract:
|
||||
|
||||
<abstract>
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2008-02-14.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _SPC_EQ_RESOLUTION_H_
|
||||
#define _SPC_EQ_RESOLUTION_H_
|
||||
|
||||
#include"spc_unary_inference.h"
|
||||
#include"spc_statistics.h"
|
||||
|
||||
namespace spc {
|
||||
|
||||
/**
|
||||
\brief Functor for applying equality resolution.
|
||||
|
||||
s != t or R
|
||||
==>
|
||||
sigma(R)
|
||||
*/
|
||||
class eq_resolution : public unary_inference {
|
||||
protected:
|
||||
statistics & m_stats;
|
||||
family_id m_spc_fid;
|
||||
virtual justification * mk_justification(justification * parent, unsigned num_lits, literal * new_lits) {
|
||||
return mk_eq_res_justification(m_manager, m_spc_fid, parent, num_lits, new_lits);
|
||||
}
|
||||
public:
|
||||
eq_resolution(ast_manager & m, order & ord, statistics & stats):unary_inference(m, ord), m_stats(stats), m_spc_fid(m.get_family_id("spc")) {}
|
||||
virtual ~eq_resolution() {}
|
||||
void operator()(clause * cls, ptr_vector<clause> & new_clauses);
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
#endif /* _SPC_EQ_RESOLUTION_H_ */
|
||||
|
156
src/dead/spc/spc_factoring.cpp
Normal file
156
src/dead/spc/spc_factoring.cpp
Normal file
|
@ -0,0 +1,156 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
spc_factoring.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
<abstract>
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2008-02-14.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#include"spc_factoring.h"
|
||||
|
||||
namespace spc {
|
||||
|
||||
/**
|
||||
\brief Create a new clause by removing literal at position j, apply substitution m_subst,
|
||||
and adding a disequality lhs != rhs.
|
||||
*/
|
||||
clause * factoring::mk_eq_fact_result(clause * cls, unsigned j, expr * lhs, expr * rhs) {
|
||||
sbuffer<literal> new_literals;
|
||||
|
||||
expr_ref new_eq(m_manager.mk_eq(lhs, rhs), m_manager);
|
||||
expr_ref new_eq_after_subst(m_manager);
|
||||
m_subst.apply(new_eq, new_eq_after_subst);
|
||||
new_literals.push_back(literal(new_eq_after_subst, true));
|
||||
|
||||
unsigned num = cls->get_num_literals();
|
||||
for (unsigned i = 0; i < num; i++) {
|
||||
if (i != j) {
|
||||
literal const & l = cls->get_literal(i);
|
||||
expr_ref new_atom(m_manager);
|
||||
m_subst.apply(l.atom(), new_atom);
|
||||
new_literals.push_back(literal(new_atom, l.sign()));
|
||||
}
|
||||
}
|
||||
|
||||
justification * js = mk_factoring_justification(m_manager, m_spc_fid, cls->get_justification(), new_literals.size(),
|
||||
new_literals.c_ptr());
|
||||
clause * new_cls = clause::mk(m_manager, new_literals.size(), new_literals.c_ptr(), js, cls->get_scope_lvl());
|
||||
m_stats.m_num_eq_factoring++;
|
||||
return new_cls;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Try to apply equality factoring using the eq literal stored at position j.
|
||||
Assume lhs and rhs are the left hand side of this equality (they may be swapped).
|
||||
*/
|
||||
void factoring::try_eq_factoring(clause * cls, unsigned j, expr * lhs, expr * rhs, ptr_vector<clause> & new_clauses) {
|
||||
literal const & l1 = cls->get_literal(j);
|
||||
sort * s = m_manager.get_sort(lhs);
|
||||
unsigned num_lits = cls->get_num_literals();
|
||||
for (unsigned i = 0; i < num_lits; i++) {
|
||||
literal const & l2 = cls->get_literal(i);
|
||||
if (i == j)
|
||||
continue;
|
||||
if (l2.sign())
|
||||
continue;
|
||||
expr * atom = l2.atom();
|
||||
if (!m_manager.is_eq(atom))
|
||||
continue;
|
||||
expr * lhs2 = to_app(atom)->get_arg(0);
|
||||
if (m_manager.get_sort(lhs2) != s)
|
||||
continue;
|
||||
expr * rhs2 = to_app(atom)->get_arg(1);
|
||||
m_subst.reset();
|
||||
if (m_unifier(lhs, lhs2, m_subst, false) &&
|
||||
(l1.is_oriented() || !m_order.greater(rhs, lhs, &m_subst)) &&
|
||||
cls->is_eligible_for_paramodulation(m_order, l1, 0, &m_subst)) {
|
||||
new_clauses.push_back(mk_eq_fact_result(cls, j, rhs, rhs2));
|
||||
}
|
||||
m_subst.reset();
|
||||
if (m_unifier(lhs, rhs2, m_subst, false) &&
|
||||
(l1.is_oriented() || !m_order.greater(rhs, lhs, &m_subst)) &&
|
||||
cls->is_eligible_for_paramodulation(m_order, l1, 0, &m_subst)) {
|
||||
new_clauses.push_back(mk_eq_fact_result(cls, j, rhs, lhs2));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Try to apply equality factoring using the eq literal stored at position i.
|
||||
*/
|
||||
void factoring::try_eq_factoring(clause * cls, unsigned i, ptr_vector<clause> & new_clauses) {
|
||||
if (cls->get_num_pos_literals() <= 1)
|
||||
return;
|
||||
literal const & l = cls->get_literal(i);
|
||||
app * eq = to_app(l.atom());
|
||||
expr * lhs = eq->get_arg(0);
|
||||
expr * rhs = eq->get_arg(1);
|
||||
if (l.is_oriented()) {
|
||||
if (!l.is_left())
|
||||
std::swap(lhs, rhs);
|
||||
try_eq_factoring(cls, i, lhs, rhs, new_clauses);
|
||||
}
|
||||
else {
|
||||
try_eq_factoring(cls, i, lhs, rhs, new_clauses);
|
||||
try_eq_factoring(cls, i, rhs, lhs, new_clauses);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Try to apply (ordering) factoring rule.
|
||||
*/
|
||||
void factoring::try_factoring(clause * cls, unsigned j, ptr_vector<clause> & new_clauses) {
|
||||
literal const & l1 = cls->get_literal(j);
|
||||
if (l1.sign() && cls->get_num_neg_literals() <= 1)
|
||||
return;
|
||||
if (!l1.sign() && cls->get_num_pos_literals() <= 1)
|
||||
return;
|
||||
unsigned num = cls->get_num_literals();
|
||||
for (unsigned i = 0; i < num; i++) {
|
||||
if (i == j)
|
||||
continue;
|
||||
literal const & l2 = cls->get_literal(i);
|
||||
if (l1.sign() != l2.sign())
|
||||
continue;
|
||||
m_subst.reset();
|
||||
if (m_unifier(l1.atom(), l2.atom(), m_subst, false) &&
|
||||
cls->is_eligible_for_resolution(m_order, l1, 0, &m_subst)) {
|
||||
new_clauses.push_back(mk_result(cls, i));
|
||||
m_stats.m_num_factoring++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Apply factoring rule on the given clause.
|
||||
Store the produced clauses into new_clauses.
|
||||
*/
|
||||
void factoring::operator()(clause * cls, ptr_vector<clause> & new_clauses) {
|
||||
if (cls->get_num_pos_literals() <= 1 && cls->get_num_neg_literals() <= 1)
|
||||
return;
|
||||
|
||||
m_subst.reserve_vars(cls->get_num_vars());
|
||||
unsigned num = cls->get_num_literals();
|
||||
for (unsigned i = 0; i < num; i++) {
|
||||
literal const & l = cls->get_literal(i);
|
||||
expr * atom = l.atom();
|
||||
// remark: if the clause has selected literals then the literal will not be eligible
|
||||
// for paramodulation and eq_resolution will not be applied.
|
||||
if (!l.sign() && m_manager.is_eq(atom) && !cls->has_sel_lit())
|
||||
try_eq_factoring(cls, i, new_clauses);
|
||||
if (l.is_selected() || !cls->has_sel_lit())
|
||||
try_factoring(cls, i, new_clauses);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
66
src/dead/spc/spc_factoring.h
Normal file
66
src/dead/spc/spc_factoring.h
Normal file
|
@ -0,0 +1,66 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
spc_factoring.h
|
||||
|
||||
Abstract:
|
||||
|
||||
<abstract>
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2008-02-14.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _SPC_FACTORING_H_
|
||||
#define _SPC_FACTORING_H_
|
||||
|
||||
#include"spc_unary_inference.h"
|
||||
#include"spc_statistics.h"
|
||||
|
||||
namespace spc {
|
||||
|
||||
/**
|
||||
\brief Functor for applying factoring.
|
||||
|
||||
- Equality Factoring
|
||||
s = t or u = v or R
|
||||
==>
|
||||
sigma(t != v or u = v or R)
|
||||
|
||||
sigma = mgu(s, u)
|
||||
sigma(s) not greater than sigma(t)
|
||||
sigma(s = t) is eligible for paramodulation.
|
||||
|
||||
- Factoring
|
||||
P(t) or P(s) or R
|
||||
==>
|
||||
sigma(P(t) or R)
|
||||
|
||||
sigma = mgu(t,s)
|
||||
sigma(P(t)) is eligible for resolution.
|
||||
*/
|
||||
class factoring : public unary_inference {
|
||||
protected:
|
||||
statistics & m_stats;
|
||||
family_id m_spc_fid;
|
||||
virtual justification * mk_justification(justification * parent, unsigned num_lits, literal * new_lits) {
|
||||
return mk_factoring_justification(m_manager, m_spc_fid, parent, num_lits, new_lits);
|
||||
}
|
||||
clause * mk_eq_fact_result(clause * cls, unsigned j, expr * lhs, expr * rhs);
|
||||
void try_eq_factoring(clause * cls, unsigned j, expr * lhs, expr * rhs, ptr_vector<clause> & new_clauses);
|
||||
void try_eq_factoring(clause * cls, unsigned i, ptr_vector<clause> & new_clauses);
|
||||
void try_factoring(clause * cls, unsigned j, ptr_vector<clause> & new_clauses);
|
||||
public:
|
||||
factoring(ast_manager & m, order & ord, statistics & stats):unary_inference(m, ord), m_stats(stats), m_spc_fid(m.get_family_id("spc")) {}
|
||||
virtual ~factoring() {}
|
||||
void operator()(clause * cls, ptr_vector<clause> & new_clauses);
|
||||
};
|
||||
};
|
||||
|
||||
#endif /* _SPC_FACTORING_H_ */
|
||||
|
184
src/dead/spc/spc_justification.cpp
Normal file
184
src/dead/spc/spc_justification.cpp
Normal file
|
@ -0,0 +1,184 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
spc_justification.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
<abstract>
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2008-02-08.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#include"spc_justification.h"
|
||||
#include"spc_clause.h"
|
||||
#include"marker.h"
|
||||
|
||||
namespace spc {
|
||||
|
||||
void get_justification_stat(justification * p, justification_stat & stat) {
|
||||
// Remark: justification objects that are not associated
|
||||
// with clauses may be shared. That is, they may be parent of
|
||||
// several different justification objects.
|
||||
marker<justification> m;
|
||||
ptr_buffer<justification> todo;
|
||||
todo.push_back(p);
|
||||
while (!todo.empty()) {
|
||||
justification * p = todo.back();
|
||||
todo.pop_back();
|
||||
if (!m.is_marked(p)) {
|
||||
m.mark(p);
|
||||
clause * cls = p->get_clause();
|
||||
if (cls) {
|
||||
if (cls->get_proof_depth() > stat.m_proof_depth)
|
||||
stat.m_proof_depth = cls->get_proof_depth();
|
||||
if (cls->get_scope_lvl() > stat.m_max_scope_lvl)
|
||||
stat.m_max_scope_lvl = cls->get_scope_lvl();
|
||||
stat.m_parent_clauses.push_back(cls);
|
||||
}
|
||||
else {
|
||||
p->get_parents(todo);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void justification::display(std::ostream & out) {
|
||||
out << "[" << get_rule_id();
|
||||
ptr_buffer<justification> ps;
|
||||
get_parents(ps);
|
||||
unsigned sz = ps.size();
|
||||
for (unsigned i = 0; i < sz; i++) {
|
||||
out << " ";
|
||||
justification * js = ps[i];
|
||||
clause * cls = js->get_clause();
|
||||
if (cls)
|
||||
out << "#" << cls->get_id();
|
||||
else
|
||||
js->display(out);
|
||||
}
|
||||
out << "]";
|
||||
}
|
||||
|
||||
justification * justification_proof_wrapper::mk(proof * p, ast_manager & m) {
|
||||
void * mem = m.get_allocator().allocate(sizeof(justification_proof_wrapper));
|
||||
return new (mem) justification_proof_wrapper(p, m);
|
||||
}
|
||||
|
||||
proof * justification_proof_wrapper::get_proof() const {
|
||||
return m_proof;
|
||||
}
|
||||
|
||||
unsigned justification_proof_wrapper::del_eh(ast_manager & m) {
|
||||
m.dec_ref(m_proof);
|
||||
return sizeof(justification_proof_wrapper);
|
||||
}
|
||||
|
||||
void dec_ref(justification * p, ast_manager & m) {
|
||||
if (p->dec_ref()) {
|
||||
ptr_buffer<justification> to_delete;
|
||||
ptr_buffer<justification> parents;
|
||||
to_delete.push_back(p);
|
||||
while (!to_delete.empty()) {
|
||||
justification * p = to_delete.back();
|
||||
to_delete.pop_back();
|
||||
SASSERT(p->get_ref_count() == 0);
|
||||
parents.reset();
|
||||
p->get_parents(parents);
|
||||
ptr_buffer<justification>::iterator it = parents.begin();
|
||||
ptr_buffer<justification>::iterator end = parents.end();
|
||||
for (; it != end; ++it) {
|
||||
justification * parent = *it;
|
||||
if (parent->dec_ref())
|
||||
to_delete.push_back(parent);
|
||||
}
|
||||
unsigned sz = p->del_eh(m);
|
||||
p->~justification();
|
||||
m.get_allocator().deallocate(sz, p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Return a proof for a new clause formed by the literals lits[0] ... lits[num_lits - 1].
|
||||
This clause was produced using a main clause C, where the proof of C is \c main_pr,
|
||||
and the auxiliary proofs auxs[0] ... aux[num_auxs-1].
|
||||
|
||||
\remark If fine_grain_proofs() is false, then 0 is returned.
|
||||
*/
|
||||
proof * mk_proof(ast_manager & m, family_id spc_fid, spc_op_kind pid, unsigned num_lits, literal * lits, proof * main_pr,
|
||||
unsigned num_auxs, proof * const * auxs) {
|
||||
if (m.fine_grain_proofs()) {
|
||||
expr * new_fact_body = mk_or(m, num_lits, lits);
|
||||
|
||||
SASSERT(main_pr);
|
||||
SASSERT(m.has_fact(main_pr));
|
||||
expr * fact = m.get_fact(main_pr);
|
||||
expr * new_fact = 0;
|
||||
if (is_quantifier(fact))
|
||||
new_fact = m.update_quantifier(to_quantifier(fact), new_fact_body);
|
||||
else
|
||||
new_fact = new_fact_body;
|
||||
|
||||
ptr_buffer<expr> args;
|
||||
args.push_back(main_pr);
|
||||
args.append(num_auxs, (expr**) auxs);
|
||||
args.push_back(new_fact);
|
||||
|
||||
return m.mk_app(spc_fid, pid, args.size(), args.c_ptr());
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
justification * rewrite_justification::mk(ast_manager & m, justification * head,
|
||||
unsigned num_demodulators, justification * const * demodulators, proof * pr) {
|
||||
void * mem = m.get_allocator().allocate(get_obj_size(num_demodulators, m.fine_grain_proofs()));
|
||||
return new (mem) rewrite_justification(m, head, num_demodulators, demodulators, pr);
|
||||
}
|
||||
|
||||
rewrite_justification::rewrite_justification(ast_manager & m, justification * head,
|
||||
unsigned num_demodulators, justification * const * demodulators, proof * pr):
|
||||
m_num_demodulators(num_demodulators) {
|
||||
SASSERT(m.fine_grain_proofs() == (pr != 0));
|
||||
m_fields[0] = head;
|
||||
head->inc_ref();
|
||||
for (unsigned i = 0; i < num_demodulators; i++) {
|
||||
m_fields[i+1] = demodulators[i];
|
||||
demodulators[i]->inc_ref();
|
||||
}
|
||||
if (m.fine_grain_proofs()) {
|
||||
SASSERT(pr);
|
||||
m_fields[num_demodulators+1] = pr;
|
||||
m.inc_ref(pr);
|
||||
}
|
||||
}
|
||||
|
||||
void rewrite_justification::get_parents(ptr_buffer<justification> & parents) {
|
||||
unsigned num_parents = m_num_demodulators+1;
|
||||
for (unsigned i = 0; i < num_parents; i++)
|
||||
parents.push_back(reinterpret_cast<justification*>(m_fields[i]));
|
||||
}
|
||||
|
||||
proof * rewrite_justification::get_proof() const {
|
||||
return reinterpret_cast<proof*>(m_fields[m_num_demodulators+1]);
|
||||
}
|
||||
|
||||
unsigned rewrite_justification::del_eh(ast_manager & m) {
|
||||
if (m.fine_grain_proofs()) {
|
||||
m.dec_ref(reinterpret_cast<proof*>(m_fields[m_num_demodulators+1]));
|
||||
return get_obj_size(m_num_demodulators, true);
|
||||
}
|
||||
return get_obj_size(m_num_demodulators, false);
|
||||
}
|
||||
|
||||
proof * mk_rewrite_proof(ast_manager & m, family_id spc_fid, unsigned num_lits, literal * lits, proof * main_pr,
|
||||
unsigned num_auxs, proof * const * auxs) {
|
||||
return mk_proof(m, spc_fid, PR_SPC_REWRITE, num_lits, lits, main_pr, num_auxs, auxs);
|
||||
}
|
||||
};
|
337
src/dead/spc/spc_justification.h
Normal file
337
src/dead/spc/spc_justification.h
Normal file
|
@ -0,0 +1,337 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
spc_justification.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Proof-like objects for tracking dependencies in the superposition
|
||||
calculus engine, and generating proofs.
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2008-02-02.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _SPC_JUSTIFICATION_H_
|
||||
#define _SPC_JUSTIFICATION_H_
|
||||
|
||||
#include"ast.h"
|
||||
#include"spc_literal.h"
|
||||
#include"spc_decl_plugin.h"
|
||||
|
||||
namespace spc {
|
||||
|
||||
class clause;
|
||||
|
||||
/**
|
||||
\brief Proof-like object use to track dependencies and produce
|
||||
proofs.
|
||||
|
||||
\remark All justification objects must be allocated using the
|
||||
small_object_allocator in ast_manager.
|
||||
*/
|
||||
class justification {
|
||||
clause * m_owner;
|
||||
unsigned m_ref_count:30;
|
||||
unsigned m_mark:1;
|
||||
unsigned m_assumption:1;
|
||||
|
||||
friend class clause;
|
||||
void set_owner(clause * cls) { m_owner = cls; }
|
||||
|
||||
public:
|
||||
justification(bool assumption = false):
|
||||
m_owner(0),
|
||||
m_ref_count(0),
|
||||
m_mark(false),
|
||||
m_assumption(assumption) {
|
||||
}
|
||||
|
||||
virtual ~justification() {}
|
||||
|
||||
void inc_ref() {
|
||||
m_ref_count++;
|
||||
}
|
||||
|
||||
bool dec_ref() {
|
||||
SASSERT(m_ref_count > 0);
|
||||
m_ref_count--;
|
||||
return m_ref_count == 0;
|
||||
}
|
||||
|
||||
unsigned get_ref_count() {
|
||||
return m_ref_count;
|
||||
}
|
||||
|
||||
void set_mark(bool f) { m_mark = f; }
|
||||
|
||||
bool is_marked() const { return m_mark; }
|
||||
|
||||
/**
|
||||
\brief Return the clause justified by this object.
|
||||
|
||||
\remark for some justification objects that clause is
|
||||
supressed. Example: intermediate steps.
|
||||
*/
|
||||
clause * get_clause() { return m_owner; }
|
||||
|
||||
/**
|
||||
\brief Return the expr justified by this object.
|
||||
This method returns a non null value only when
|
||||
proof generation is enabled.
|
||||
*/
|
||||
virtual expr * get_expr(ast_manager & m) { return 0; }
|
||||
|
||||
/**
|
||||
\brief Return a non-zero value if the justification
|
||||
is wrapping a proof object.
|
||||
*/
|
||||
virtual proof * get_proof() const { return 0; }
|
||||
|
||||
/**
|
||||
\brief Return the parent justifications.
|
||||
*/
|
||||
virtual void get_parents(ptr_buffer<justification> & parents) {}
|
||||
|
||||
/**
|
||||
\brief Return the name of the rule used.
|
||||
*/
|
||||
virtual spc_op_kind get_rule_id() = 0;
|
||||
|
||||
/**
|
||||
\brief Return true if the justification is an external assumption.
|
||||
*/
|
||||
bool assumption() const { return m_assumption; }
|
||||
|
||||
void display(std::ostream & out);
|
||||
|
||||
/**
|
||||
\brief This method is invoked before the object is deleted.
|
||||
Return the amount of memory consumed by this object.
|
||||
*/
|
||||
virtual unsigned del_eh(ast_manager & m) = 0;
|
||||
};
|
||||
|
||||
struct justification_stat {
|
||||
unsigned m_proof_depth;
|
||||
unsigned m_max_scope_lvl;
|
||||
ptr_buffer<clause> m_parent_clauses;
|
||||
justification_stat():
|
||||
m_proof_depth(0),
|
||||
m_max_scope_lvl(0) {
|
||||
}
|
||||
};
|
||||
|
||||
void get_justification_stat(justification * p, justification_stat & stat);
|
||||
|
||||
void dec_ref(justification * p, ast_manager & m);
|
||||
|
||||
/**
|
||||
\brief Smart pointer for justification objects.
|
||||
*/
|
||||
class justification_ref {
|
||||
justification * m_obj;
|
||||
ast_manager & m_manager;
|
||||
void inc_ref() { if (m_obj) m_obj->inc_ref(); }
|
||||
void dec_ref() { if (m_obj) spc::dec_ref(m_obj, m_manager); }
|
||||
public:
|
||||
justification_ref(ast_manager & m):m_obj(0), m_manager(m) {}
|
||||
justification_ref(justification * j, ast_manager & m):
|
||||
m_obj(j), m_manager(m) {
|
||||
inc_ref();
|
||||
}
|
||||
~justification_ref() {
|
||||
dec_ref();
|
||||
}
|
||||
operator justification*() const { return m_obj; }
|
||||
operator bool() const { return m_obj != 0; }
|
||||
bool operator!() const { return m_obj == 0; }
|
||||
justification * operator->() const { return m_obj; }
|
||||
justification const & operator*() const { return *m_obj; }
|
||||
justification_ref & operator=(justification * n) {
|
||||
if (n)
|
||||
n->inc_ref();
|
||||
dec_ref();
|
||||
m_obj = n;
|
||||
return *this;
|
||||
}
|
||||
justification_ref & operator=(justification_ref & n) {
|
||||
SASSERT(&m_manager == &n.m_manager);
|
||||
n.inc_ref();
|
||||
dec_ref();
|
||||
m_obj = n.m_obj;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
class justification_proof_wrapper : public justification {
|
||||
proof * m_proof;
|
||||
justification_proof_wrapper(proof * p, ast_manager & m):m_proof(p) { m.inc_ref(m_proof); }
|
||||
public:
|
||||
static justification * mk(proof * p, ast_manager & m);
|
||||
virtual ~justification_proof_wrapper() {}
|
||||
virtual proof * get_proof() const;
|
||||
virtual spc_op_kind get_rule_id() { return PR_SPC_ASSERTED; };
|
||||
virtual unsigned del_eh(ast_manager & m);
|
||||
};
|
||||
|
||||
proof * mk_proof(ast_manager & m, family_id spc_fid, spc_op_kind pid, unsigned num_lits, literal * lits, proof * main_pr, unsigned num_auxs,
|
||||
proof * const * auxs);
|
||||
|
||||
/**
|
||||
\brief Justification for rewriting steps: demodulation, duplicate literal deletion, resolved literal deletion.
|
||||
*/
|
||||
class rewrite_justification : public justification {
|
||||
unsigned m_num_demodulators;
|
||||
void * m_fields[0];
|
||||
static unsigned get_obj_size(unsigned num_demodulators, bool fine_grain) {
|
||||
return sizeof(rewrite_justification) + (num_demodulators + (fine_grain ? 2 : 1)) * sizeof(void *);
|
||||
}
|
||||
rewrite_justification(ast_manager & m, justification * head,
|
||||
unsigned num_demodulators, justification * const * demodulators, proof * pr);
|
||||
public:
|
||||
static justification * mk(ast_manager & m, justification * head,
|
||||
unsigned num_demodulators, justification * const * demodulators, proof * pr = 0);
|
||||
virtual ~rewrite_justification() {}
|
||||
virtual proof * get_proof() const;
|
||||
virtual spc_op_kind get_rule_id() { return PR_SPC_REWRITE; }
|
||||
virtual void get_parents(ptr_buffer<justification> & parents);
|
||||
virtual unsigned del_eh(ast_manager & m);
|
||||
};
|
||||
|
||||
proof * mk_rewrite_proof(ast_manager & m, family_id spc_fid, unsigned num_lits, literal * lits, proof * main_pr, unsigned num_auxs,
|
||||
proof * const * auxs);
|
||||
|
||||
template<spc_op_kind Kind>
|
||||
class unary_justification : public justification {
|
||||
protected:
|
||||
justification * m_parent;
|
||||
proof * m_proof;
|
||||
|
||||
unary_justification(ast_manager & m, justification * p, proof * pr):
|
||||
m_parent(p),
|
||||
m_proof(pr) {
|
||||
p->inc_ref();
|
||||
SASSERT(m.fine_grain_proofs() == (pr != 0));
|
||||
if (m.fine_grain_proofs())
|
||||
m.inc_ref(pr);
|
||||
}
|
||||
|
||||
public:
|
||||
virtual proof * get_proof() const {
|
||||
return m_proof;
|
||||
}
|
||||
|
||||
virtual void get_parents(ptr_buffer<justification> & parents) {
|
||||
parents.push_back(m_parent);
|
||||
}
|
||||
|
||||
virtual unsigned del_eh(ast_manager & m) {
|
||||
if (m.fine_grain_proofs())
|
||||
m.dec_ref(m_proof);
|
||||
return sizeof(unary_justification);
|
||||
}
|
||||
|
||||
virtual spc_op_kind get_rule_id() {
|
||||
return Kind;
|
||||
}
|
||||
|
||||
static justification * mk(ast_manager & m, family_id spc_fid, justification * p, unsigned num_lits, literal * lits) {
|
||||
proof * pr = 0;
|
||||
if (m.fine_grain_proofs())
|
||||
pr = mk_proof(m, spc_fid, Kind, num_lits, lits, p->get_proof(), 0, 0);
|
||||
void * mem = m.get_allocator().allocate(sizeof(unary_justification));
|
||||
return new (mem) unary_justification(m, p, pr);
|
||||
}
|
||||
};
|
||||
|
||||
inline justification * mk_eq_res_justification(ast_manager & m, family_id spc_fid, justification * p, unsigned num_lits, literal * lits) {
|
||||
return unary_justification<PR_EQUALITY_RESOLUTION>::mk(m, spc_fid, p, num_lits, lits);
|
||||
}
|
||||
|
||||
inline justification * mk_factoring_justification(ast_manager & m, family_id spc_fid, justification * p, unsigned num_lits, literal * lits) {
|
||||
return unary_justification<PR_FACTORING>::mk(m, spc_fid, p, num_lits, lits);
|
||||
}
|
||||
|
||||
inline justification * mk_der_justification(ast_manager & m, family_id spc_fid, justification * p, unsigned num_lits, literal * lits) {
|
||||
return unary_justification<PR_SPC_DER>::mk(m, spc_fid, p, num_lits, lits);
|
||||
}
|
||||
|
||||
template<spc_op_kind Kind>
|
||||
class binary_justification : public justification {
|
||||
protected:
|
||||
justification * m_parent1;
|
||||
justification * m_parent2;
|
||||
proof * m_proof;
|
||||
|
||||
binary_justification(ast_manager & m, justification * p1, justification * p2, proof * pr):
|
||||
m_parent1(p1),
|
||||
m_parent2(p2),
|
||||
m_proof(pr) {
|
||||
p1->inc_ref();
|
||||
p2->inc_ref();
|
||||
SASSERT(m.fine_grain_proofs() == (pr != 0));
|
||||
if (m.fine_grain_proofs())
|
||||
m.inc_ref(pr);
|
||||
}
|
||||
|
||||
public:
|
||||
virtual proof * get_proof() const {
|
||||
return m_proof;
|
||||
}
|
||||
|
||||
virtual void get_parents(ptr_buffer<justification> & parents) {
|
||||
parents.push_back(m_parent1);
|
||||
parents.push_back(m_parent2);
|
||||
}
|
||||
|
||||
virtual unsigned del_eh(ast_manager & m) {
|
||||
if (m.fine_grain_proofs())
|
||||
m.dec_ref(m_proof);
|
||||
return sizeof(binary_justification);
|
||||
}
|
||||
|
||||
virtual spc_op_kind get_rule_id() {
|
||||
return Kind;
|
||||
}
|
||||
|
||||
static justification * mk(ast_manager & m, family_id spc_fid, justification * p1, justification * p2, unsigned num_lits, literal * lits,
|
||||
unsigned num_vars, var * const * vars) {
|
||||
proof * pr = 0;
|
||||
if (m.fine_grain_proofs()) {
|
||||
ptr_buffer<sort> sorts;
|
||||
sbuffer<symbol> names;
|
||||
for (unsigned i = 0; i < num_vars; i++) {
|
||||
sorts.push_back(vars[num_vars - i - 1]->get_sort());
|
||||
names.push_back(symbol(num_vars - i - 1));
|
||||
}
|
||||
expr * body = mk_or(m, num_lits, lits);
|
||||
expr * new_fact = 0;
|
||||
if (num_vars == 0)
|
||||
new_fact = body;
|
||||
else
|
||||
new_fact = m.mk_forall(sorts.size(), sorts.c_ptr(), names.c_ptr(), body);
|
||||
pr = m.mk_app(spc_fid, Kind, p1->get_proof(), p2->get_proof(), new_fact);
|
||||
}
|
||||
void * mem = m.get_allocator().allocate(sizeof(binary_justification));
|
||||
return new (mem) binary_justification(m, p1, p2, pr);
|
||||
}
|
||||
};
|
||||
|
||||
inline justification * mk_superposition_justification(ast_manager & m, family_id spc_fid, justification * p1, justification * p2,
|
||||
unsigned num_lits, literal * lits, unsigned num_vars, var * const * vars) {
|
||||
return binary_justification<PR_SUPERPOSITION>::mk(m, spc_fid, p1, p2, num_lits, lits, num_vars, vars);
|
||||
}
|
||||
|
||||
inline justification * mk_resolution_justification(ast_manager & m, family_id spc_fid, justification * p1, justification * p2,
|
||||
unsigned num_lits, literal * lits, unsigned num_vars, var * const * vars) {
|
||||
return binary_justification<PR_SPC_RESOLUTION>::mk(m, spc_fid, p1, p2, num_lits, lits, num_vars, vars);
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* _SPC_JUSTIFICATION_H_ */
|
432
src/dead/spc/spc_literal.cpp
Normal file
432
src/dead/spc/spc_literal.cpp
Normal file
|
@ -0,0 +1,432 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
spc_literal.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Superposition Calculus literal
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2008-02-02.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#include"spc_literal.h"
|
||||
#include"ast_pp.h"
|
||||
|
||||
namespace spc {
|
||||
|
||||
void literal::try_to_orient(order & o) {
|
||||
ast_manager & m = o.get_manager();
|
||||
if (!m_sign && m.is_eq(m_atom)) {
|
||||
expr * lhs = to_app(m_atom)->get_arg(0);
|
||||
expr * rhs = to_app(m_atom)->get_arg(1);
|
||||
TRACE("spc_orient", tout << "trying to orient:\n" << mk_pp(lhs, m) << "\n" << mk_pp(rhs, m) << "\n";);
|
||||
switch (o.compare(lhs, rhs)) {
|
||||
case order::GREATER:
|
||||
m_oriented = true;
|
||||
m_left = true;
|
||||
TRACE("spc_orient", tout << "greater\n";);
|
||||
return;
|
||||
case order::LESSER:
|
||||
m_oriented = true;
|
||||
m_left = false;
|
||||
TRACE("spc_orient", tout << "smaller\n";);
|
||||
return;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void literal::get_stat(literal_stat & stat) {
|
||||
get_expr_stat(m_atom, stat);
|
||||
m_stats = true;
|
||||
m_ground = stat.m_ground;
|
||||
m_sym_count = stat.m_sym_count > SYM_COUNT_MAX ? SYM_COUNT_MAX : stat.m_sym_count;
|
||||
m_depth = stat.m_depth > DEPTH_MAX ? DEPTH_MAX : stat.m_depth;
|
||||
m_const_count = stat.m_const_count > CONST_COUNT_MAX ? CONST_COUNT_MAX : stat.m_const_count;
|
||||
}
|
||||
|
||||
expr * literal::to_expr(ast_manager & m) const {
|
||||
if (is_true(m))
|
||||
return m.mk_true();
|
||||
else if (is_false(m))
|
||||
return m.mk_false();
|
||||
else if (m_sign)
|
||||
return m.mk_not(m_atom);
|
||||
else
|
||||
return m_atom;
|
||||
}
|
||||
|
||||
void literal::display(std::ostream & out, ast_manager & m, bool detailed) const {
|
||||
pp_params p;
|
||||
p.m_pp_single_line = true;
|
||||
|
||||
if (m_sign)
|
||||
out << "(not ";
|
||||
|
||||
if (m_oriented) {
|
||||
expr * lhs = to_app(m_atom)->get_arg(0);
|
||||
expr * rhs = to_app(m_atom)->get_arg(1);
|
||||
if (!m_left)
|
||||
std::swap(lhs, rhs);
|
||||
out << "(-> ";
|
||||
ast_pp(out, lhs, m, p);
|
||||
out << " ";
|
||||
ast_pp(out, rhs, m, p);
|
||||
out << ")";
|
||||
}
|
||||
else {
|
||||
ast_pp(out, m_atom, m, p);
|
||||
}
|
||||
|
||||
if (m_sign)
|
||||
out << ")";
|
||||
|
||||
if (detailed && m_stats) {
|
||||
out << "[" << m_ground << ", " << m_depth << ", " << m_sym_count << ", " << m_const_count << "]";
|
||||
}
|
||||
|
||||
if (m_selected)
|
||||
out << "$";
|
||||
if (m_p_indexed)
|
||||
out << "!";
|
||||
if (m_r_indexed)
|
||||
out << "@";
|
||||
}
|
||||
|
||||
void display(std::ostream & out, unsigned num_lists, literal * lits, ast_manager & m, bool detailed) {
|
||||
for (unsigned i = 0; i < num_lists; i++) {
|
||||
if (i > 0) out << " ";
|
||||
lits[i].display(out, m, detailed);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Given an eq literal store in lhs and rhs the left and right hand sides. If they can be oriented
|
||||
given the substitution s, then return true, and make lhs the maximal one.
|
||||
*/
|
||||
bool can_orient(order & o, literal const & l, unsigned offset, substitution * s, expr * & lhs, expr * & rhs) {
|
||||
SASSERT(o.get_manager().is_eq(l.atom()));
|
||||
lhs = l.lhs();
|
||||
rhs = l.rhs();
|
||||
if (l.is_oriented()) {
|
||||
if (!l.is_left())
|
||||
std::swap(lhs, rhs);
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
order::result comp = o.compare(lhs, rhs, offset, s);
|
||||
if (comp == order::GREATER)
|
||||
return true;
|
||||
else if (comp == order::LESSER) {
|
||||
std::swap(lhs, rhs);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Compare literal signs. Negative sign is bigger than the positive one.
|
||||
*/
|
||||
inline order::result compare_signs(bool sign1, bool sign2) {
|
||||
if (sign1 && !sign2)
|
||||
return order::GREATER;
|
||||
else if (!sign1 && sign2)
|
||||
return order::LESSER;
|
||||
else
|
||||
return order::EQUAL;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Compare two literals (modulo a substitution) using the given term ordering.
|
||||
*/
|
||||
order::result compare(order & o, literal const & l1, literal const & l2, unsigned offset, substitution * s) {
|
||||
ast_manager & m = o.get_manager();
|
||||
expr * n1 = l1.atom();
|
||||
expr * n2 = l2.atom();
|
||||
bool is_eq1 = m.is_eq(n1);
|
||||
bool is_eq2 = m.is_eq(n2);
|
||||
if (is_eq1 && is_eq2) {
|
||||
expr * lhs1 = 0;
|
||||
expr * rhs1 = 0;
|
||||
expr * lhs2 = 0;
|
||||
expr * rhs2 = 0;
|
||||
bool oriented1 = can_orient(o, l1, offset, s, lhs1, rhs1);
|
||||
bool oriented2 = can_orient(o, l2, offset, s, lhs2, rhs2);
|
||||
if (oriented1) {
|
||||
// equation 1 can be oriented
|
||||
if (oriented2) {
|
||||
// equation 2 can be oriented
|
||||
// both equations are oriented
|
||||
SASSERT(oriented1);
|
||||
SASSERT(oriented2);
|
||||
order::result r = o.compare(lhs1, lhs2, offset, s);
|
||||
if (r == order::EQUAL) {
|
||||
if (l1.pos()) {
|
||||
if (l2.pos())
|
||||
return o.compare(rhs1, rhs2, offset, s);
|
||||
else
|
||||
return order::LESSER;
|
||||
}
|
||||
else {
|
||||
if (l2.pos())
|
||||
return order::GREATER;
|
||||
else
|
||||
return o.compare(rhs1, rhs2, offset, s);
|
||||
}
|
||||
}
|
||||
return r;
|
||||
}
|
||||
else {
|
||||
// equation 2 cannot be oriented
|
||||
SASSERT(oriented1);
|
||||
SASSERT(!oriented2);
|
||||
SASSERT(o.compare(lhs1, rhs1, offset, s) == order::GREATER);
|
||||
if (o.equal(lhs1, lhs2, offset, s)) {
|
||||
order::result r = o.compare(rhs1, rhs2, offset, s);
|
||||
if (r == order::EQUAL)
|
||||
return compare_signs(l1.sign(), l2.sign());
|
||||
return r;
|
||||
}
|
||||
if (o.equal(lhs1, rhs2, offset, s)) {
|
||||
order::result r = o.compare(rhs1, lhs2, offset, s);
|
||||
if (r == order::EQUAL)
|
||||
return compare_signs(l1.sign(), l2.sign());
|
||||
return r;
|
||||
}
|
||||
order::result lhs1_lhs2 = o.compare(lhs1, lhs2, offset, s);
|
||||
order::result lhs1_rhs2 = o.compare(lhs1, rhs2, offset, s);
|
||||
if (lhs1_lhs2 == lhs1_rhs2)
|
||||
return lhs1_lhs2;
|
||||
order::result rhs1_rhs2 = o.compare(rhs1, rhs2, offset, s);
|
||||
if (lhs1_lhs2 == rhs1_rhs2)
|
||||
return lhs1_lhs2;
|
||||
if (lhs1_rhs2 == order::LESSER && rhs1_rhs2 == order::LESSER)
|
||||
return order::LESSER;
|
||||
order::result rhs1_lhs2 = o.compare(rhs1, lhs2, offset, s);
|
||||
if (lhs1_lhs2 == order::LESSER && rhs1_lhs2 == order::LESSER)
|
||||
return order::LESSER;
|
||||
return order::UNCOMPARABLE;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// equation 1 cannot be oriented
|
||||
if (oriented2) {
|
||||
SASSERT(!oriented1);
|
||||
SASSERT(oriented2);
|
||||
// equation 2 can be oriented
|
||||
if (o.equal(lhs1, lhs2, offset, s)) {
|
||||
order::result r = o.compare(rhs1, rhs2, offset, s);
|
||||
if (r == order::EQUAL)
|
||||
return compare_signs(l1.sign(), l2.sign());
|
||||
return r;
|
||||
}
|
||||
if (o.equal(rhs1, lhs2, offset, s)) {
|
||||
order::result r = o.compare(lhs1, rhs2, offset, s);
|
||||
if (r == order::EQUAL)
|
||||
return compare_signs(l1.sign(), l2.sign());
|
||||
return r;
|
||||
}
|
||||
order::result lhs1_lhs2 = o.compare(lhs1, lhs2, offset, s);
|
||||
order::result rhs1_lhs2 = o.compare(rhs1, lhs2, offset, s);
|
||||
if (lhs1_lhs2 == rhs1_lhs2)
|
||||
return lhs1_lhs2;
|
||||
order::result rhs1_rhs2 = o.compare(rhs1, rhs2, offset, s);
|
||||
if (lhs1_lhs2 == rhs1_rhs2)
|
||||
return lhs1_lhs2;
|
||||
if (rhs1_lhs2 == order::GREATER && rhs1_rhs2 == order::GREATER)
|
||||
return order::GREATER;
|
||||
order::result lhs1_rhs2 = o.compare(lhs1, rhs2, offset, s);
|
||||
if (lhs1_lhs2 == order::GREATER && lhs1_rhs2 == order::GREATER)
|
||||
return order::GREATER;
|
||||
return order::UNCOMPARABLE;
|
||||
}
|
||||
else {
|
||||
SASSERT(!oriented1);
|
||||
SASSERT(!oriented2);
|
||||
if (o.equal(lhs1, lhs2, offset, s)) {
|
||||
order::result r = o.compare(rhs1, rhs2, offset, s);
|
||||
if (r == order::EQUAL)
|
||||
return compare_signs(l1.sign(), l2.sign());
|
||||
return r;
|
||||
}
|
||||
if (o.equal(rhs1, lhs2, offset, s)) {
|
||||
order::result r = o.compare(lhs1, rhs2, offset, s);
|
||||
if (r == order::EQUAL)
|
||||
return compare_signs(l1.sign(), l2.sign());
|
||||
return r;
|
||||
}
|
||||
if (o.equal(lhs1, rhs2, offset, s)) {
|
||||
order::result r = o.compare(rhs1, lhs2, offset, s);
|
||||
if (r == order::EQUAL)
|
||||
return compare_signs(l1.sign(), l2.sign());
|
||||
return r;
|
||||
}
|
||||
if (o.equal(rhs1, rhs2, offset, s)) {
|
||||
order::result r = o.compare(lhs1, lhs2, offset, s);
|
||||
if (r == order::EQUAL)
|
||||
return compare_signs(l1.sign(), l2.sign());
|
||||
return r;
|
||||
}
|
||||
|
||||
order::result r;
|
||||
order::result aux;
|
||||
switch (o.compare(lhs1, lhs2, offset, s)) {
|
||||
case order::GREATER:
|
||||
r = o.compare(lhs1, rhs2, offset, s);
|
||||
if (r == order::GREATER)
|
||||
return order::GREATER;
|
||||
aux = o.compare(rhs1, rhs2, offset, s);
|
||||
if (aux == order::GREATER)
|
||||
return order::GREATER;
|
||||
if (r == order::LESSER && aux == order::LESSER)
|
||||
return order::LESSER;
|
||||
SASSERT(r != order::EQUAL);
|
||||
SASSERT(aux != order::EQUAL);
|
||||
return order::UNCOMPARABLE;
|
||||
case order::LESSER:
|
||||
r = o.compare(rhs1, lhs2, offset, s);
|
||||
if (r == order::LESSER)
|
||||
return order::LESSER;
|
||||
aux = o.compare(rhs1, rhs2, offset, s);
|
||||
if (aux == order::LESSER)
|
||||
return order::LESSER;
|
||||
if (r == order::GREATER && aux == order::GREATER)
|
||||
return order::GREATER;
|
||||
SASSERT(r != order::EQUAL);
|
||||
SASSERT(aux != order::EQUAL);
|
||||
return order::UNCOMPARABLE;
|
||||
case order::EQUAL:
|
||||
UNREACHABLE();
|
||||
return order::UNKNOWN;
|
||||
default:
|
||||
switch (o.compare(lhs1, rhs2, offset, s)) {
|
||||
case order::GREATER:
|
||||
if (o.compare(rhs1, lhs2, offset, s) == order::GREATER)
|
||||
return order::GREATER;
|
||||
return order::UNCOMPARABLE;
|
||||
case order::LESSER:
|
||||
if (o.compare(rhs1, lhs2, offset, s) == order::LESSER ||
|
||||
o.compare(rhs1, rhs2, offset, s) == order::LESSER)
|
||||
return order::LESSER;
|
||||
return order::UNCOMPARABLE;
|
||||
case order::EQUAL:
|
||||
UNREACHABLE();
|
||||
return order::UNKNOWN;
|
||||
default:
|
||||
if (o.compare(rhs1, lhs2, offset, s) == order::GREATER &&
|
||||
o.compare(rhs1, rhs2, offset, s) == order::GREATER)
|
||||
return order::GREATER;
|
||||
return order::UNCOMPARABLE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (is_eq1) {
|
||||
expr * lhs1 = l1.lhs();
|
||||
expr * rhs1 = l1.rhs();
|
||||
if (l1.is_oriented() && !l1.is_left())
|
||||
std::swap(lhs1, rhs1);
|
||||
order::result r = o.compare(lhs1, n2, offset, s);
|
||||
if (!l1.is_oriented() || r != order::GREATER) {
|
||||
order::result r2 = o.compare(rhs1, n2, offset, s);
|
||||
if (r2 == order::GREATER)
|
||||
return order::GREATER;
|
||||
else if (r != r2)
|
||||
return order::UNCOMPARABLE;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
else if (is_eq2) {
|
||||
expr * lhs2 = l2.lhs();
|
||||
expr * rhs2 = l2.rhs();
|
||||
if (l2.is_oriented() && !l2.is_left())
|
||||
std::swap(lhs2, rhs2);
|
||||
order::result r = o.compare(n1, lhs2, offset, s);
|
||||
if (!l1.is_oriented() || r != order::LESSER) {
|
||||
order::result r2 = o.compare(n1, rhs2, offset, s);
|
||||
if (r2 == order::LESSER)
|
||||
return order::LESSER;
|
||||
else if (r != r2)
|
||||
return order::UNCOMPARABLE;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
else {
|
||||
order::result r = o.compare(n1, n2, offset, s);
|
||||
if (r == order::EQUAL)
|
||||
return compare_signs(l1.sign(), l2.sign());
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
bool greater(order & o, literal const & l1, literal const & l2, unsigned offset, substitution * s) {
|
||||
order::result r = compare(o, l1, l2, offset, s);
|
||||
TRACE("literal_order", ast_manager & m = o.get_manager();
|
||||
tout << "comparing ";
|
||||
l1.display(tout, m);
|
||||
tout << " ";
|
||||
l2.display(tout, m);
|
||||
tout << " : " << r << "\n";);
|
||||
return r == order::GREATER;
|
||||
}
|
||||
|
||||
void found_literals::insert(literal const & l) {
|
||||
unsigned id = l.get_id();
|
||||
m_marks.reserve(id+1);
|
||||
if (!m_marks.get(id)) {
|
||||
m_marks.set(id);
|
||||
m_lit_ids.push_back(id);
|
||||
}
|
||||
}
|
||||
|
||||
bool found_literals::contains(literal const & l) const {
|
||||
unsigned id = l.get_id();
|
||||
return id < m_marks.size() && m_marks.get(id);
|
||||
}
|
||||
|
||||
bool found_literals::contains_neg(literal const & l) const {
|
||||
unsigned id = l.get_neg_id();
|
||||
return id < m_marks.size() && m_marks.get(id);
|
||||
}
|
||||
|
||||
void found_literals::reset() {
|
||||
unsigned_vector::iterator it = m_lit_ids.begin();
|
||||
unsigned_vector::iterator end = m_lit_ids.end();
|
||||
for (; it != end; ++it)
|
||||
m_marks.unset(*it);
|
||||
m_lit_ids.reset();
|
||||
}
|
||||
|
||||
void literal_buffer::reset() {
|
||||
buffer<literal>::iterator it = m_lits.begin();
|
||||
buffer<literal>::iterator end = m_lits.end();
|
||||
for (; it != end; ++it)
|
||||
m_manager.dec_ref(it->atom());
|
||||
m_lits.reset();
|
||||
}
|
||||
|
||||
|
||||
expr * mk_or(ast_manager & m, unsigned num_lists, literal * lits) {
|
||||
if (num_lists == 0)
|
||||
return m.mk_false();
|
||||
else if (num_lists == 1)
|
||||
return lits[0].to_expr(m);
|
||||
else {
|
||||
ptr_buffer<expr> new_exprs;
|
||||
for (unsigned i = 0; i < num_lists; i++)
|
||||
new_exprs.push_back(lits[i].to_expr(m));
|
||||
return m.mk_or(new_exprs.size(), new_exprs.c_ptr());
|
||||
}
|
||||
}
|
||||
|
||||
};
|
212
src/dead/spc/spc_literal.h
Normal file
212
src/dead/spc/spc_literal.h
Normal file
|
@ -0,0 +1,212 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
spc_literal.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Superposition Calculus literal
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2008-02-02.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _SPC_LITERAL_H_
|
||||
#define _SPC_LITERAL_H_
|
||||
|
||||
#include"ast.h"
|
||||
#include"order.h"
|
||||
#include"expr_stat.h"
|
||||
|
||||
namespace spc {
|
||||
typedef expr_stat literal_stat;
|
||||
|
||||
#define DEPTH_NUM_BITS 4
|
||||
#define DEPTH_MAX ((1 << DEPTH_NUM_BITS) - 1)
|
||||
#define CONST_COUNT_NUM_BITS 4
|
||||
#define CONST_COUNT_MAX ((1 << CONST_COUNT_NUM_BITS) - 1)
|
||||
#define SYM_COUNT_NUM_BITS 16
|
||||
#define SYM_COUNT_MAX ((1 << SYM_COUNT_NUM_BITS) - 1)
|
||||
|
||||
/**
|
||||
\brief Superposition Calculus literal.
|
||||
*/
|
||||
class literal {
|
||||
expr * m_atom;
|
||||
unsigned m_sign:1; // true if a negative literal.
|
||||
unsigned m_oriented:1; // true if it is an oriented equality.
|
||||
unsigned m_left:1; // true if the largest term is on the left-hand-side of the equality (only meaningful if m_oriented == true).
|
||||
unsigned m_selected:1; // true if it is a selected literal.
|
||||
unsigned m_stats:1; // true if the following fields were initialized.
|
||||
unsigned m_ground:1; // true if it is a ground literal
|
||||
unsigned m_p_indexed:1; // true if the literal was inserted into the p (paramodulation) superposition index.
|
||||
unsigned m_r_indexed:1; // true if the literal was inserted into the r (resolution) superposition index.
|
||||
unsigned m_depth:DEPTH_NUM_BITS; // approx. depth
|
||||
unsigned m_const_count:CONST_COUNT_NUM_BITS; // approx. number of constants
|
||||
unsigned m_sym_count:SYM_COUNT_NUM_BITS; // approx. size
|
||||
|
||||
friend class clause;
|
||||
|
||||
void set_selected(bool f) {
|
||||
m_selected = f;
|
||||
}
|
||||
|
||||
public:
|
||||
literal():
|
||||
m_atom(0),
|
||||
m_sign(false),
|
||||
m_oriented(false),
|
||||
m_left(false),
|
||||
m_selected(false),
|
||||
m_stats(false),
|
||||
m_ground(false),
|
||||
m_p_indexed(false),
|
||||
m_r_indexed(false),
|
||||
m_depth(0),
|
||||
m_const_count(0),
|
||||
m_sym_count(0) {
|
||||
}
|
||||
|
||||
literal(expr * atom, bool sign = false):
|
||||
m_atom(atom),
|
||||
m_sign(sign),
|
||||
m_oriented(false),
|
||||
m_left(false),
|
||||
m_selected(false),
|
||||
m_stats(false),
|
||||
m_ground(false),
|
||||
m_p_indexed(false),
|
||||
m_r_indexed(false),
|
||||
m_depth(0),
|
||||
m_const_count(0),
|
||||
m_sym_count(0) {
|
||||
}
|
||||
|
||||
bool sign() const { return m_sign; }
|
||||
bool pos() const { return !m_sign; }
|
||||
bool neg() const { return m_sign; }
|
||||
bool is_oriented() const { return m_oriented; }
|
||||
bool is_left() const { return m_left; }
|
||||
bool is_selected() const { return m_selected; }
|
||||
expr * atom() const { return m_atom; }
|
||||
expr * lhs() const { return to_app(m_atom)->get_arg(0); }
|
||||
expr * rhs() const { return to_app(m_atom)->get_arg(1); }
|
||||
unsigned get_id() const { return m_sign ? (to_app(m_atom)->get_id() << 1) + 1 : (to_app(m_atom)->get_id() << 1); }
|
||||
unsigned get_neg_id() const { return m_sign ? (to_app(m_atom)->get_id() << 1) : (to_app(m_atom)->get_id() << 1) + 1; }
|
||||
|
||||
bool operator==(literal const & other) const { return m_atom == other.m_atom && m_sign == other.m_sign; }
|
||||
bool operator!=(literal const & other) const { return !operator==(other); }
|
||||
|
||||
void set_p_indexed(bool f) { m_p_indexed = f; }
|
||||
void set_r_indexed(bool f) { m_r_indexed = f; }
|
||||
bool is_p_indexed() const { return m_p_indexed; }
|
||||
bool is_r_indexed() const { return m_r_indexed; }
|
||||
|
||||
void try_to_orient(order & o);
|
||||
bool is_true(ast_manager & m) const {
|
||||
return
|
||||
(!m_sign && m.is_true(m_atom)) ||
|
||||
(!m_sign && m.is_eq(m_atom) && to_app(m_atom)->get_arg(0) == to_app(m_atom)->get_arg(1)) ||
|
||||
(m_sign && m.is_false(m_atom));
|
||||
}
|
||||
bool is_false(ast_manager & m) const {
|
||||
return
|
||||
(m_sign && m.is_true(m_atom)) ||
|
||||
(m_sign && m.is_eq(m_atom) && to_app(m_atom)->get_arg(0) == to_app(m_atom)->get_arg(1)) ||
|
||||
(!m_sign && m.is_false(m_atom));
|
||||
}
|
||||
expr * to_expr(ast_manager & m) const;
|
||||
|
||||
/**
|
||||
\brief Collect literal statistics
|
||||
*/
|
||||
void get_stat(literal_stat & stat);
|
||||
void init_stat() { literal_stat st; get_stat(st); }
|
||||
bool has_stats() const { return m_stats; }
|
||||
bool is_ground() const { SASSERT(m_stats); return m_ground; }
|
||||
unsigned get_approx_depth() const { SASSERT(m_stats); return m_depth; }
|
||||
unsigned get_approx_const_count() const { SASSERT(m_stats); return m_const_count; }
|
||||
unsigned get_approx_sym_count() const { SASSERT(m_stats); return m_sym_count; }
|
||||
|
||||
void display(std::ostream & out, ast_manager & m, bool detailed = false) const;
|
||||
};
|
||||
|
||||
COMPILE_TIME_ASSERT(sizeof(expr*) != 4 || sizeof(literal) == sizeof(expr *) + sizeof(unsigned)); // 32 bit machine
|
||||
COMPILE_TIME_ASSERT(sizeof(expr*) != 8 || sizeof(literal) == sizeof(expr *) + sizeof(unsigned) + /* a structure must be aligned */ sizeof(unsigned)); // 64 bit machine
|
||||
|
||||
void display(std::ostream & out, unsigned num_lists, literal * lits, ast_manager & m, bool detailed = false);
|
||||
|
||||
order::result compare(order & o, literal const & l1, literal const & l2, unsigned offset = 0, substitution * s = 0);
|
||||
bool greater(order & o, literal const & l1, literal const & l2, unsigned offset = 0, substitution * s = 0);
|
||||
bool is_maximal(order & o, unsigned num_lists, literal * lits, literal const & l, unsigned offset = 0, substitution * s = 0);
|
||||
bool is_sel_maximal(order & o, unsigned num_lists, literal * lits, literal const & l, unsigned offset = 0, substitution * s = 0);
|
||||
|
||||
/**
|
||||
\brief Set of found literals.
|
||||
|
||||
This object is used to implement duplicate literal elimination, ans syntatic tautology.
|
||||
*/
|
||||
class found_literals {
|
||||
bit_vector m_marks;
|
||||
unsigned_vector m_lit_ids;
|
||||
public:
|
||||
/**
|
||||
\brief Insert the given literal into the set.
|
||||
*/
|
||||
void insert(literal const & l);
|
||||
|
||||
/**
|
||||
\brief Return true if the set contains \c l.
|
||||
*/
|
||||
bool contains(literal const & l) const;
|
||||
|
||||
/**
|
||||
\brief Return true if the set contains the negation of \c l.
|
||||
*/
|
||||
bool contains_neg(literal const & l) const;
|
||||
|
||||
bool empty() const { return m_lit_ids.empty(); }
|
||||
|
||||
/**
|
||||
\brief Remove all literals from the set.
|
||||
*/
|
||||
void reset();
|
||||
};
|
||||
|
||||
class literal_buffer {
|
||||
ast_manager & m_manager;
|
||||
buffer<literal> m_lits;
|
||||
public:
|
||||
literal_buffer(ast_manager & m):
|
||||
m_manager(m) {
|
||||
}
|
||||
|
||||
~literal_buffer() {
|
||||
reset();
|
||||
}
|
||||
|
||||
void push_back(literal const & l) {
|
||||
m_manager.inc_ref(l.atom());
|
||||
m_lits.push_back(l);
|
||||
}
|
||||
|
||||
void reset();
|
||||
|
||||
unsigned size() const {
|
||||
return m_lits.size();
|
||||
}
|
||||
|
||||
literal * c_ptr() const {
|
||||
return m_lits.c_ptr();
|
||||
}
|
||||
};
|
||||
|
||||
expr * mk_or(ast_manager & m, unsigned num_lists, literal * lits);
|
||||
};
|
||||
|
||||
#endif /* _SPC_LITERAL_H_ */
|
107
src/dead/spc/spc_literal_selection.cpp
Normal file
107
src/dead/spc/spc_literal_selection.cpp
Normal file
|
@ -0,0 +1,107 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
spc_literal_selection.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Superposition Calculus Literal Selection
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2008-02-05.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#include"spc_literal_selection.h"
|
||||
#include"expr_stat.h"
|
||||
|
||||
namespace spc {
|
||||
|
||||
void diff_literal_selection::operator()(clause * cls) {
|
||||
bool found = false;
|
||||
unsigned target = UINT_MAX;
|
||||
unsigned best_count = 0;
|
||||
unsigned num = cls->get_num_literals();
|
||||
for (unsigned i = 0; i < num; i++) {
|
||||
literal & l = cls->get_literal(i);
|
||||
if (l.sign()) {
|
||||
unsigned count;
|
||||
if (m_manager.is_eq(l.atom())) {
|
||||
unsigned c1 = get_symbol_count(to_app(l.atom())->get_arg(0));
|
||||
unsigned c2 = get_symbol_count(to_app(l.atom())->get_arg(1));
|
||||
count = c1 >= c2 ? c1 - c2 : c2 - c1;
|
||||
}
|
||||
else {
|
||||
count = get_symbol_count(l.atom());
|
||||
}
|
||||
if (count > best_count) {
|
||||
found = true;
|
||||
target = i;
|
||||
best_count = count;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (found)
|
||||
cls->select_literal(target);
|
||||
}
|
||||
|
||||
void complex_literal_selection::operator()(clause * cls) {
|
||||
// look for x != y
|
||||
unsigned num = cls->get_num_literals();
|
||||
for (unsigned i = 0; i < num; i++) {
|
||||
literal & l = cls->get_literal(i);
|
||||
if (l.sign() && m_manager.is_eq(l.atom()) && is_var(to_app(l.atom())->get_arg(0)) && is_var(to_app(l.atom())->get_arg(1))) {
|
||||
cls->select_literal(i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// look for min ground neg literal
|
||||
bool found = false;
|
||||
unsigned target = UINT_MAX;
|
||||
unsigned best_count = UINT_MAX;
|
||||
for (unsigned i = 0; i < num; i++) {
|
||||
literal & l = cls->get_literal(i);
|
||||
if (l.sign() && is_ground(l.atom())) {
|
||||
unsigned count = get_symbol_count(l.atom());
|
||||
if (count < best_count) {
|
||||
found = true;
|
||||
target = i;
|
||||
best_count = count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (found) {
|
||||
cls->select_literal(target);
|
||||
return;
|
||||
}
|
||||
|
||||
diff_literal_selection::operator()(cls);
|
||||
}
|
||||
|
||||
void max_no_selection::operator()(clause * cls) {
|
||||
unsigned num_lits = cls->get_num_literals();
|
||||
for (unsigned i = 0; i < num_lits; i++) {
|
||||
literal const & l1 = cls->get_literal(i);
|
||||
if (!l1.sign()) {
|
||||
unsigned j = 0;
|
||||
for (; j < num_lits; j++) {
|
||||
if (i != j) {
|
||||
literal const & l2 = cls->get_literal(j);
|
||||
if (!greater(m_order, l1, l2))
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (j == num_lits)
|
||||
return; // clause has maximal positive literal.
|
||||
}
|
||||
}
|
||||
diff_literal_selection::operator()(cls);
|
||||
}
|
||||
|
||||
};
|
95
src/dead/spc/spc_literal_selection.h
Normal file
95
src/dead/spc/spc_literal_selection.h
Normal file
|
@ -0,0 +1,95 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
spc_literal_selection.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Superposition Calculus Literal Selection
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2008-02-05.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _SPC_LITERAL_SELECTION_H_
|
||||
#define _SPC_LITERAL_SELECTION_H_
|
||||
|
||||
#include"spc_clause.h"
|
||||
#include"order.h"
|
||||
|
||||
namespace spc {
|
||||
|
||||
/**
|
||||
\brief Abstract functor for literal selection.
|
||||
*/
|
||||
class literal_selection {
|
||||
public:
|
||||
virtual ~literal_selection() {}
|
||||
/**
|
||||
\brief Updates the selected status flag of the literals of the given clause.
|
||||
*/
|
||||
virtual void operator()(clause * cls) = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
\brief Never selects a literal. This strategy is supposed to be good for planning problems
|
||||
of TPTP.
|
||||
*/
|
||||
class no_literal_selection : public literal_selection {
|
||||
public:
|
||||
virtual void operator()(clause * cls) {}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
\brief Selects a negative literal l with the largest V(l)
|
||||
where V is defined as:
|
||||
|
||||
- difference in symbol count for the left-right hand sides of equalities, .
|
||||
|
||||
- symbol count for other predicates
|
||||
|
||||
*/
|
||||
class diff_literal_selection : public literal_selection {
|
||||
protected:
|
||||
ast_manager & m_manager;
|
||||
public:
|
||||
diff_literal_selection(ast_manager & m):m_manager(m) {}
|
||||
virtual void operator()(clause * cls);
|
||||
};
|
||||
|
||||
/**
|
||||
\brief Selects a negative literal using the following algo:
|
||||
|
||||
- if there is x != y, select it.
|
||||
|
||||
- else if there is negative ground literal, select the smallest one.
|
||||
|
||||
- else if use the approach in diff_literal_selection.
|
||||
*/
|
||||
class complex_literal_selection : public diff_literal_selection {
|
||||
public:
|
||||
complex_literal_selection(ast_manager & m):diff_literal_selection(m) {}
|
||||
virtual void operator()(clause * cls);
|
||||
};
|
||||
|
||||
/**
|
||||
\brief Similar to diff_literal_selection, but a literal
|
||||
is not selected if the clause contains a positive literal
|
||||
greater than all other literals.
|
||||
*/
|
||||
class max_no_selection : public diff_literal_selection {
|
||||
order & m_order;
|
||||
public:
|
||||
max_no_selection(order & o):diff_literal_selection(o.get_manager()), m_order(o) {}
|
||||
virtual void operator()(clause * cls);
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
#endif /* _SPC_LITERAL_SELECTION_H_ */
|
132
src/dead/spc/spc_prover.cpp
Normal file
132
src/dead/spc/spc_prover.cpp
Normal file
|
@ -0,0 +1,132 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
spc_prover.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Stand-alone SPC prover (it is mainly for debugging purposes).
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2008-02-08.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#include"spc_prover.h"
|
||||
#include"spc_decl_plugin.h"
|
||||
#include"for_each_expr.h"
|
||||
|
||||
namespace spc {
|
||||
prover::prover(ast_manager & m, front_end_params & params):
|
||||
m_manager(m),
|
||||
m_params(params),
|
||||
m_simplifier(m),
|
||||
m_defined_names(m),
|
||||
m_preprocessor(m, m_defined_names, m_simplifier, params),
|
||||
m_order(0),
|
||||
m_cls_sel(0),
|
||||
m_lit_sel(0),
|
||||
m_context(0),
|
||||
m_exprs(m),
|
||||
m_expr_proofs(m),
|
||||
m_has_theories(false) {
|
||||
|
||||
family_id fid = m_manager.get_family_id("spc");
|
||||
if (!m_manager.has_plugin(fid))
|
||||
m_manager.register_plugin(fid, alloc(spc_decl_plugin));
|
||||
|
||||
// This piece of code shows why the old model for passing parameters is broken.
|
||||
// spc::prover must overwrite some parameters, but this modification affects other
|
||||
// components. :-(
|
||||
// TODO: move everything to the new params_ref object
|
||||
params.m_nnf_mode = NNF_FULL;
|
||||
params.m_cnf_mode = CNF_FULL;
|
||||
params.m_lift_ite = LI_CONSERVATIVE;
|
||||
|
||||
basic_simplifier_plugin * basic = alloc(basic_simplifier_plugin, m_manager);
|
||||
m_simplifier.register_plugin(basic);
|
||||
m_simplifier.register_plugin(alloc(arith_simplifier_plugin, m_manager, *basic, params));
|
||||
}
|
||||
|
||||
prover::~prover() {
|
||||
if (m_context) {
|
||||
dealloc(m_context);
|
||||
dealloc(m_lit_sel);
|
||||
dealloc(m_cls_sel);
|
||||
dealloc(m_order);
|
||||
}
|
||||
}
|
||||
|
||||
void prover::init() {
|
||||
if (m_context)
|
||||
return;
|
||||
precedence * p = mk_precedence(m_manager, m_params);
|
||||
|
||||
// TODO use params to configure the following functors.
|
||||
m_order = alloc(kbo, m_manager, p);
|
||||
|
||||
clause_eval * evals[2] = { alloc(symbol_count_clause_eval), alloc(time_clause_eval) };
|
||||
unsigned slots[2] = { 10, 1 };
|
||||
m_cls_sel = alloc(clause_selection, 2, evals, slots);
|
||||
|
||||
m_lit_sel = alloc(max_no_selection, *m_order);
|
||||
// m_lit_sel = new complex_literal_selection(m_manager);
|
||||
// m_lit_sel = new diff_literal_selection(m_manager);
|
||||
// m_lit_sel = new no_literal_selection(); // new diff_literal_selection(m_manager);
|
||||
// END TODO
|
||||
|
||||
m_context = alloc(context, m_manager, *m_order, *m_cls_sel, *m_lit_sel, m_simplifier, m_params);
|
||||
}
|
||||
|
||||
struct has_theories_proc {
|
||||
ast_manager & m_manager;
|
||||
has_theories_proc(ast_manager & m):m_manager(m) {}
|
||||
struct found {};
|
||||
void operator()(var * n) {}
|
||||
void operator()(app * n) { if (!m_manager.is_builtin_family_id(n->get_family_id())) throw found(); }
|
||||
void operator()(quantifier * n) {}
|
||||
};
|
||||
|
||||
bool has_theories(ast_manager & m, expr * e) {
|
||||
has_theories_proc p(m);
|
||||
try {
|
||||
for_each_expr(p, e);
|
||||
}
|
||||
catch (has_theories_proc::found) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void prover::assert_expr(expr * e) {
|
||||
if (!m_has_theories && has_theories(m_manager, e))
|
||||
m_has_theories = true;
|
||||
TRACE("spc_assert", tout << mk_pp(e, m_manager) << "\nhas_theories: " << m_has_theories << "\n";);
|
||||
m_preprocessor(e, m_manager.mk_asserted(e), m_exprs, m_expr_proofs);
|
||||
}
|
||||
|
||||
lbool prover::check() {
|
||||
init();
|
||||
unsigned sz = m_exprs.size();
|
||||
for (unsigned i = 0; i < sz; i++) {
|
||||
expr * curr = m_exprs.get(i);
|
||||
proof * p = m_manager.proofs_enabled() ? m_expr_proofs.get(i) : m_manager.mk_undef_proof();
|
||||
m_context->assert_expr(curr, p);
|
||||
}
|
||||
m_exprs.reset();
|
||||
m_expr_proofs.reset();
|
||||
|
||||
m_context->saturate(m_params.m_spc_num_iterations);
|
||||
if (m_context->inconsistent())
|
||||
return l_false;
|
||||
else if (m_context->processed_all())
|
||||
return m_has_theories ? l_undef : l_true;
|
||||
else
|
||||
return l_undef;
|
||||
}
|
||||
};
|
||||
|
59
src/dead/spc/spc_prover.h
Normal file
59
src/dead/spc/spc_prover.h
Normal file
|
@ -0,0 +1,59 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
spc_prover.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Stand-alone SPC prover (it is mainly for debugging purposes).
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2008-02-08.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _SPC_PROVER_H_
|
||||
#define _SPC_PROVER_H_
|
||||
|
||||
#include"spc_context.h"
|
||||
#include"front_end_params.h"
|
||||
#include"kbo.h"
|
||||
#include"lpo.h"
|
||||
#include"basic_simplifier_plugin.h"
|
||||
#include"arith_simplifier_plugin.h"
|
||||
#include"preprocessor.h"
|
||||
#include"defined_names.h"
|
||||
#include"lbool.h"
|
||||
|
||||
namespace spc {
|
||||
class prover {
|
||||
ast_manager & m_manager;
|
||||
front_end_params & m_params;
|
||||
simplifier m_simplifier;
|
||||
defined_names m_defined_names;
|
||||
preprocessor m_preprocessor;
|
||||
order * m_order;
|
||||
clause_selection * m_cls_sel;
|
||||
literal_selection * m_lit_sel;
|
||||
context * m_context;
|
||||
expr_ref_vector m_exprs;
|
||||
proof_ref_vector m_expr_proofs;
|
||||
bool m_has_theories;
|
||||
|
||||
void init();
|
||||
|
||||
public:
|
||||
prover(ast_manager & m, front_end_params & params);
|
||||
~prover();
|
||||
void assert_expr(expr * e);
|
||||
lbool check();
|
||||
void display_statistics(std::ostream & out) const { if (m_context) m_context->display_statistics(out); }
|
||||
};
|
||||
};
|
||||
|
||||
#endif /* _SPC_PROVER_H_ */
|
||||
|
269
src/dead/spc/spc_rewriter.cpp
Normal file
269
src/dead/spc/spc_rewriter.cpp
Normal file
|
@ -0,0 +1,269 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
spc_rewrite.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
<abstract>
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2008-02-12.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#include"spc_rewriter.h"
|
||||
#include"spc_decl_plugin.h"
|
||||
#include"ast_pp.h"
|
||||
|
||||
namespace spc {
|
||||
|
||||
rewriter::rewriter(ast_manager & m, simplifier & simp, order & ord, asserted_literals & al):
|
||||
simplifier(m),
|
||||
m_asserted_literals(al),
|
||||
m_order(ord),
|
||||
m_spc_fid(m.get_family_id("spc")),
|
||||
m_subst(m),
|
||||
m_st(m),
|
||||
m_visitor(m_order, m_subst, m_cls_use_list) {
|
||||
|
||||
reserve_offsets(3);
|
||||
|
||||
borrow_plugins(simp);
|
||||
}
|
||||
|
||||
rewriter::~rewriter() {
|
||||
release_plugins();
|
||||
}
|
||||
|
||||
inline void rewriter::reserve_vars(unsigned num_vars) {
|
||||
m_subst.reserve_vars(num_vars);
|
||||
m_order.reserve_vars(num_vars);
|
||||
m_asserted_literals.reserve_vars(num_vars);
|
||||
}
|
||||
|
||||
void rewriter::reserve_offsets(unsigned num_offsets) {
|
||||
m_subst.reserve_offsets(num_offsets);
|
||||
m_order.reserve_offsets(num_offsets);
|
||||
}
|
||||
|
||||
inline bool rewriter::demodulator(clause * cls) const {
|
||||
if (cls->get_num_literals() != 1)
|
||||
return false;
|
||||
literal const & l = cls->get_literal(0);
|
||||
return !l.sign() && m_manager.is_eq(l.atom());
|
||||
}
|
||||
|
||||
inline void rewriter::insert(clause * cls, expr * source) {
|
||||
if (!is_var(source)) {
|
||||
TRACE("rewriter_detail", tout << "inserting into rewriter index:\n"; cls->display(tout, m_manager); tout << "\n";);
|
||||
flush_cache();
|
||||
m_st.insert(to_app(source));
|
||||
m_cls_use_list.insert(cls, source);
|
||||
}
|
||||
}
|
||||
|
||||
void rewriter::insert(clause * cls) {
|
||||
if (demodulator(cls)) {
|
||||
reserve_vars(cls->get_num_vars());
|
||||
literal const & l = cls->get_literal(0);
|
||||
app * eq = to_app(l.atom());
|
||||
if (l.is_oriented()) {
|
||||
expr * source = l.is_left() ? eq->get_arg(0) : eq->get_arg(1);
|
||||
insert(cls, source);
|
||||
}
|
||||
else {
|
||||
insert(cls, eq->get_arg(0));
|
||||
insert(cls, eq->get_arg(1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline void rewriter::erase(clause * cls, expr * source) {
|
||||
if (!is_var(source)) {
|
||||
flush_cache();
|
||||
m_cls_use_list.erase(cls, source);
|
||||
if (m_cls_use_list.empty(source))
|
||||
m_st.erase(to_app(source));
|
||||
}
|
||||
}
|
||||
|
||||
void rewriter::erase(clause * cls) {
|
||||
if (demodulator(cls)) {
|
||||
literal const & l = cls->get_literal(0);
|
||||
app * eq = to_app(l.atom());
|
||||
if (l.is_oriented()) {
|
||||
expr * source = l.is_left() ? eq->get_arg(0) : eq->get_arg(1);
|
||||
erase(cls, source);
|
||||
}
|
||||
else {
|
||||
erase(cls, eq->get_arg(0));
|
||||
erase(cls, eq->get_arg(1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool rewriter::visitor::operator()(expr * e) {
|
||||
if (m_cls_use_list.empty(e))
|
||||
return true; // continue;
|
||||
clause_use_list::iterator it = m_cls_use_list.begin(e);
|
||||
clause_use_list::iterator end = m_cls_use_list.end(e);
|
||||
for (; it != end; ++it) {
|
||||
m_clause = *it;
|
||||
SASSERT(m_clause->get_num_literals() == 1);
|
||||
literal & l = m_clause->get_literal(0);
|
||||
expr * atom = l.atom();
|
||||
SASSERT(!l.sign() && m_manager.is_eq(atom));
|
||||
SASSERT(to_app(atom)->get_arg(0) == e || to_app(atom)->get_arg(1) == e);
|
||||
m_source = to_app(atom)->get_arg(0);
|
||||
m_target = to_app(atom)->get_arg(1);
|
||||
if (m_source != e)
|
||||
std::swap(m_source, m_target);
|
||||
SASSERT(m_source == e);
|
||||
TRACE("rewriter", tout << "found generalization:\n" << mk_pp(m_source, m_manager) << "\n" <<
|
||||
mk_pp(m_target, m_manager) << "\nsubstitution\n";
|
||||
m_subst.display(tout); tout << "m_subst: " << &m_subst << "\n";
|
||||
tout << "checking ordering constraints...\n";);
|
||||
if (l.is_oriented() || m_order.greater(expr_offset(m_source, 1), expr_offset(m_target, 1), &m_subst)) {
|
||||
m_found = true;
|
||||
return false; // stop
|
||||
}
|
||||
TRACE("rewriter", tout << "failed ordering constraints...\n";);
|
||||
}
|
||||
return true; // continue
|
||||
}
|
||||
|
||||
void rewriter::save_justification(justification * j) {
|
||||
if (std::find(m_justifications.begin(), m_justifications.end(), j) == m_justifications.end())
|
||||
m_justifications.push_back(j);
|
||||
}
|
||||
|
||||
proof * rewriter::mk_demodulation_proof(expr * old_expr, expr * new_expr, proof * parent) {
|
||||
if (m_manager.fine_grain_proofs()) {
|
||||
SASSERT(parent);
|
||||
return m_manager.mk_app(m_spc_fid, PR_DEMODULATION, parent, m_manager.mk_eq(old_expr, new_expr));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void rewriter::reset() {
|
||||
m_st.reset();
|
||||
m_cls_use_list.reset();
|
||||
}
|
||||
|
||||
void rewriter::reduce_literal(literal const & l, literal & l_r, proof * & l_pr) {
|
||||
if (m_st.empty()) {
|
||||
l_r = l;
|
||||
l_pr = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
expr * atom = l.atom();
|
||||
expr * r;
|
||||
proof * r_pr;
|
||||
m_proofs.reset();
|
||||
while (true) {
|
||||
reduce_core(atom);
|
||||
get_cached(atom, r, r_pr);
|
||||
if (m_manager.fine_grain_proofs() && r_pr)
|
||||
m_proofs.push_back(r_pr);
|
||||
if (atom == r)
|
||||
break;
|
||||
atom = r;
|
||||
}
|
||||
l_r = literal(atom, l.sign());
|
||||
if (m_manager.fine_grain_proofs())
|
||||
l_pr = m_proofs.empty() ? 0 : m_manager.mk_transitivity(m_proofs.size(), m_proofs.c_ptr());
|
||||
}
|
||||
|
||||
clause * rewriter::operator()(clause * cls) {
|
||||
reserve_vars(cls->get_num_vars());
|
||||
SASSERT(m_found_literals.empty());
|
||||
m_justifications.reset();
|
||||
m_max_scope_lvl = cls->get_scope_lvl();
|
||||
|
||||
literal_buffer new_literals(m_manager);
|
||||
proof_ref_buffer new_proofs(m_manager);
|
||||
bool changed = false;
|
||||
|
||||
unsigned num_lits = cls->get_num_literals();
|
||||
for (unsigned i = 0; i < num_lits; i++) {
|
||||
literal & l = cls->get_literal(i);
|
||||
literal l_r;
|
||||
proof * l_pr = 0;
|
||||
reduce_literal(l, l_r, l_pr);
|
||||
|
||||
if (l != l_r) {
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (!l_r.is_false(m_manager) && !m_found_literals.contains(l_r)) {
|
||||
m_found_literals.insert(l_r);
|
||||
|
||||
// apply simplify reflect rules
|
||||
expr * atom = l_r.atom();
|
||||
clause * unit = 0;
|
||||
TRACE("rewriter", tout << "adding literal: " << mk_pp(atom, m_manager) << "\n";);
|
||||
if (l_r.sign()) {
|
||||
if (m_manager.is_eq(atom))
|
||||
unit = m_asserted_literals.subsumes(to_app(atom)->get_arg(0), to_app(atom)->get_arg(1));
|
||||
else
|
||||
unit = m_asserted_literals.gen(atom, false);
|
||||
}
|
||||
else {
|
||||
// check if there is a generalization of the negation of the current literal.
|
||||
unit = m_asserted_literals.gen(atom, true);
|
||||
}
|
||||
|
||||
if (unit) {
|
||||
// new literal was resolved
|
||||
justification * j = unit->get_justification();
|
||||
m_justifications.push_back(j);
|
||||
changed = true;
|
||||
}
|
||||
else {
|
||||
// keep new literal
|
||||
new_literals.push_back(l_r);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// removed duplicate or resolved literal.
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (m_manager.fine_grain_proofs() && l_pr != 0) {
|
||||
new_proofs.push_back(l_pr);
|
||||
}
|
||||
}
|
||||
|
||||
m_found_literals.reset();
|
||||
|
||||
if (!changed) {
|
||||
m_found_literals.reset();
|
||||
return cls;
|
||||
}
|
||||
|
||||
proof * new_pr = mk_rewrite_proof(m_manager, m_spc_fid, new_literals.size(), new_literals.c_ptr(), cls->get_justification()->get_proof(),
|
||||
new_proofs.size(), new_proofs.c_ptr());
|
||||
|
||||
justification * new_j = rewrite_justification::mk(m_manager, cls->get_justification(), m_justifications.size(), m_justifications.c_ptr(), new_pr);
|
||||
|
||||
if (m_max_scope_lvl == cls->get_scope_lvl()) {
|
||||
// peform destructive update
|
||||
cls->update_lits(m_manager, new_literals.size(), new_literals.c_ptr(), new_j);
|
||||
return cls;
|
||||
}
|
||||
else {
|
||||
SASSERT(m_max_scope_lvl > cls->get_scope_lvl());
|
||||
// create new clause
|
||||
// the old clause will be frozen
|
||||
return clause::mk(m_manager, new_literals.size(), new_literals.c_ptr(), new_j, m_max_scope_lvl);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
122
src/dead/spc/spc_rewriter.h
Normal file
122
src/dead/spc/spc_rewriter.h
Normal file
|
@ -0,0 +1,122 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
spc_rewriter.h
|
||||
|
||||
Abstract:
|
||||
|
||||
<abstract>
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2008-02-11.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _SPC_REWRITER_H_
|
||||
#define _SPC_REWRITER_H_
|
||||
|
||||
#include"simplifier.h"
|
||||
#include"order.h"
|
||||
#include"substitution_tree.h"
|
||||
#include"spc_clause.h"
|
||||
#include"spc_asserted_literals.h"
|
||||
#include"sparse_use_list.h"
|
||||
|
||||
namespace spc {
|
||||
|
||||
/**
|
||||
\brief Apply rewriting steps using demodulation rule:
|
||||
|
||||
C[s] ==> C[sigma(r)]
|
||||
when
|
||||
|
||||
l = r is a known equality (demodulator)
|
||||
sigma(l) = s
|
||||
sigma(l) > sigma(r)
|
||||
|
||||
It also applies the following rules:
|
||||
|
||||
- Duplicate literal deletion
|
||||
|
||||
- Resolved literal deletion
|
||||
|
||||
- Positive simplify reflect
|
||||
s = t, (u[p <- sigma(s)] != u[p <- sigma(t)] or R)
|
||||
==>
|
||||
R
|
||||
|
||||
- Negative simplify reflect
|
||||
s != t (sigma(s = t) or R)
|
||||
===>
|
||||
R
|
||||
*/
|
||||
class rewriter : public simplifier {
|
||||
protected:
|
||||
typedef sparse_use_list<expr, ptr_vector<clause> > clause_use_list;
|
||||
asserted_literals & m_asserted_literals;
|
||||
order & m_order;
|
||||
family_id m_spc_fid;
|
||||
|
||||
substitution m_subst;
|
||||
substitution_tree m_st; // index for potential demodulators left-hand-side
|
||||
clause_use_list m_cls_use_list; // index for demodulators left-hand-side to equation.
|
||||
found_literals m_found_literals;
|
||||
|
||||
ptr_vector<justification> m_justifications;
|
||||
|
||||
struct visitor : public st_visitor {
|
||||
ast_manager & m_manager;
|
||||
order & m_order;
|
||||
clause_use_list & m_cls_use_list;
|
||||
bool m_found;
|
||||
clause * m_clause;
|
||||
expr * m_source;
|
||||
expr * m_target;
|
||||
|
||||
visitor(order & ord, substitution & subst, clause_use_list & ul):
|
||||
st_visitor(subst), m_manager(ord.get_manager()), m_order(ord), m_cls_use_list(ul) {
|
||||
}
|
||||
|
||||
virtual bool operator()(expr * e);
|
||||
};
|
||||
|
||||
unsigned m_max_scope_lvl; // maximal scope level used during rewrite.
|
||||
visitor m_visitor;
|
||||
|
||||
proof * mk_demodulation_proof(expr * old_expr, expr * new_expr, proof * parent);
|
||||
|
||||
bool demodulator(clause * cls) const;
|
||||
void insert(clause * cls, expr * source);
|
||||
void erase(clause * cls, expr * source);
|
||||
void reserve_vars(unsigned num_vars);
|
||||
void reserve_offsets(unsigned num_offsets);
|
||||
void save_justification(justification * j);
|
||||
|
||||
void reduce_literal(literal const & l, literal & l_r, proof * & l_pr);
|
||||
|
||||
public:
|
||||
rewriter(ast_manager & m, simplifier & s, order & ord, asserted_literals & al);
|
||||
virtual ~rewriter();
|
||||
|
||||
/**
|
||||
\brief Insert clause into rewriter indexes
|
||||
*/
|
||||
void insert(clause * cls);
|
||||
|
||||
/**
|
||||
\brief Remove clause from rewriter indexes
|
||||
*/
|
||||
void erase(clause * cls);
|
||||
|
||||
clause * operator()(clause * cls);
|
||||
|
||||
void reset();
|
||||
};
|
||||
};
|
||||
|
||||
#endif /* _SPC_REWRITER_H_ */
|
||||
|
234
src/dead/spc/spc_semantic_tautology.cpp
Normal file
234
src/dead/spc/spc_semantic_tautology.cpp
Normal file
|
@ -0,0 +1,234 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
spc_semantic_tautology.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
<abstract>
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2008-02-11.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#include"spc_semantic_tautology.h"
|
||||
#include"ast_pp.h"
|
||||
|
||||
namespace spc {
|
||||
|
||||
expr * find(expr2expr & f, expr * n) {
|
||||
#ifdef _TRACE
|
||||
expr * _n = n;
|
||||
#endif
|
||||
ptr_buffer<expr> path;
|
||||
expr * next;
|
||||
while (f.find(n, next)) {
|
||||
path.push_back(n);
|
||||
n = next;
|
||||
}
|
||||
ptr_buffer<expr>::iterator it = path.begin();
|
||||
ptr_buffer<expr>::iterator end = path.end();
|
||||
for (; it != end; ++it) {
|
||||
expr * prev = *it;
|
||||
f.insert(prev, n);
|
||||
}
|
||||
SASSERT(n);
|
||||
TRACE("semantic_tautology_detail", tout << "find(#" << _n->get_id() << ") = #" << n->get_id() << "\n";);
|
||||
return n;
|
||||
}
|
||||
|
||||
semantic_tautology::semantic_tautology(ast_manager & m):
|
||||
m_manager(m),
|
||||
m_cg_table(DEFAULT_HASHTABLE_INITIAL_CAPACITY, cg_hash(m_manager, m_find), cg_eq(m_find)) {
|
||||
}
|
||||
|
||||
unsigned semantic_tautology::cg_hash::operator()(app * n) const {
|
||||
TRACE("semantic_tautology_detail", tout << "hash code of:\n" << mk_pp(n, m_manager) << "\n";);
|
||||
unsigned r = get_composite_hash<app *, k_hash, c_hash>(n, n->get_num_args(), m_k_hash, m_c_hash);
|
||||
TRACE("semantic_tautology_detail", tout << "result: " << r << "\n";);
|
||||
return r;
|
||||
}
|
||||
|
||||
bool semantic_tautology::cg_eq::operator()(app * n1, app * n2) const {
|
||||
if (n1->get_decl() != n2->get_decl() || n1->get_num_args() != n2->get_num_args())
|
||||
return false;
|
||||
unsigned num_args = n1->get_num_args();
|
||||
for (unsigned i = 0; i < num_args; i++)
|
||||
if (spc::find(m_find, n1->get_arg(i)) != spc::find(m_find, n2->get_arg(i)))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool semantic_tautology::is_target(unsigned num_lits, literal * lits) {
|
||||
bool has_diseq = false;
|
||||
bool has_non_diseq = false;
|
||||
for (unsigned i = 0; i < num_lits; i++) {
|
||||
literal const & l = lits[i];
|
||||
if (l.sign() && m_manager.is_eq(l.atom()))
|
||||
has_diseq = true;
|
||||
else
|
||||
has_non_diseq = true;
|
||||
}
|
||||
return has_diseq && has_non_diseq;
|
||||
}
|
||||
|
||||
void semantic_tautology::reset() {
|
||||
m_region.reset();
|
||||
m_init_todo.reset();
|
||||
m_todo.reset();
|
||||
m_already_found.reset();
|
||||
m_use_list.reset();
|
||||
m_find.reset();
|
||||
m_size.reset();
|
||||
m_cg_table.reset();
|
||||
}
|
||||
|
||||
void semantic_tautology::update_use_list(app * parent, expr * child) {
|
||||
list<app*> * use_list = 0;
|
||||
m_use_list.find(child, use_list);
|
||||
use_list = new (m_region) list<app*>(parent, use_list);
|
||||
m_use_list.insert(child, use_list);
|
||||
}
|
||||
|
||||
inline void semantic_tautology::push_init_core(expr * n) {
|
||||
if (is_app(n) && to_app(n)->get_num_args() > 0)
|
||||
m_init_todo.push_back(to_app(n));
|
||||
}
|
||||
|
||||
inline void semantic_tautology::push_init(expr * atom) {
|
||||
if (m_manager.is_eq(atom)) {
|
||||
push_init_core(to_app(atom)->get_arg(0));
|
||||
push_init_core(to_app(atom)->get_arg(1));
|
||||
}
|
||||
else
|
||||
push_init_core(atom);
|
||||
}
|
||||
|
||||
void semantic_tautology::init_use_list() {
|
||||
while (!m_init_todo.empty()) {
|
||||
app * n = m_init_todo.back();
|
||||
m_init_todo.pop_back();
|
||||
if (!m_already_found.contains(n)) {
|
||||
unsigned num_args = n->get_num_args();
|
||||
SASSERT(num_args > 0);
|
||||
m_cg_table.insert(n);
|
||||
m_already_found.insert(n);
|
||||
for (unsigned i = 0; i < num_args; i++) {
|
||||
expr * c = n->get_arg(i);
|
||||
update_use_list(n, c);
|
||||
push_init_core(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void semantic_tautology::init(unsigned num_lits, literal * lits) {
|
||||
reset();
|
||||
for (unsigned i = 0; i < num_lits; i++) {
|
||||
literal const & l = lits[i];
|
||||
expr * atom = l.atom();
|
||||
push_init(atom);
|
||||
if (l.sign() && m_manager.is_eq(atom))
|
||||
m_todo.push_back(expr_pair(to_app(atom)->get_arg(0), to_app(atom)->get_arg(1)));
|
||||
}
|
||||
init_use_list();
|
||||
}
|
||||
|
||||
void semantic_tautology::remove_parents(expr * n1) {
|
||||
list<app*> * use_list = 0;
|
||||
m_use_list.find(n1, use_list);
|
||||
while (use_list) {
|
||||
TRACE("semantic_tautology", tout << "removing parent from cg_table:\n" << mk_pp(use_list->head(), m_manager) << "\n";);
|
||||
m_cg_table.erase(use_list->head());
|
||||
use_list = use_list->tail();
|
||||
}
|
||||
}
|
||||
|
||||
void semantic_tautology::restore_parents(expr * n1, expr * n2) {
|
||||
list<app*> * use_list = 0;
|
||||
m_use_list.find(n1, use_list);
|
||||
while (use_list) {
|
||||
app * parent = use_list->head();
|
||||
app * other = 0;
|
||||
if (m_cg_table.find(parent, other)) {
|
||||
TRACE("semantic_tautology", tout << "new congruence:\n" << mk_pp(parent, m_manager) << "\n" << mk_pp(other, m_manager) << "\n";);
|
||||
if (parent != other)
|
||||
m_todo.push_back(expr_pair(parent, other));
|
||||
}
|
||||
else {
|
||||
TRACE("semantic_tautology", tout << "restoring parent to cg_table:\n" << mk_pp(parent, m_manager) << "\n";);
|
||||
m_cg_table.insert(parent);
|
||||
update_use_list(parent, n2);
|
||||
}
|
||||
use_list = use_list->tail();
|
||||
}
|
||||
}
|
||||
|
||||
void semantic_tautology::assert_eq(expr * n1, expr * n2) {
|
||||
n1 = find(n1);
|
||||
n2 = find(n2);
|
||||
if (n1 == n2)
|
||||
return;
|
||||
TRACE("semantic_tautology", tout << "processing equality:\n" << mk_pp(n1, m_manager) << " " << n1->get_id() << "\n" <<
|
||||
mk_pp(n2, m_manager) << " " << n2->get_id() << "\n";);
|
||||
unsigned sz1 = 1;
|
||||
unsigned sz2 = 1;
|
||||
m_size.find(n1, sz1);
|
||||
m_size.find(n2, sz2);
|
||||
if (sz1 > sz2)
|
||||
std::swap(n1, n2);
|
||||
remove_parents(n1);
|
||||
TRACE("semantic_tautology", tout << "merging equivalence classes\n";);
|
||||
m_find.insert(n1, n2);
|
||||
m_size.insert(n2, sz1 + sz2);
|
||||
restore_parents(n1, n2);
|
||||
}
|
||||
|
||||
void semantic_tautology::process_eqs() {
|
||||
while (!m_todo.empty()) {
|
||||
expr_pair const & p = m_todo.back();
|
||||
expr * lhs = p.first;
|
||||
expr * rhs = p.second;
|
||||
m_todo.pop_back();
|
||||
assert_eq(lhs, rhs);
|
||||
}
|
||||
}
|
||||
|
||||
bool semantic_tautology::contains_complement(unsigned num_lits, literal * lits, unsigned i, bool sign, expr * atom) {
|
||||
atom = find(atom);
|
||||
for (unsigned j = i + 1; j < num_lits; j++) {
|
||||
literal const & l = lits[j];
|
||||
if (l.sign() != sign && find(l.atom()) == atom)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool semantic_tautology::is_tautology(unsigned num_lits, literal * lits) {
|
||||
for (unsigned i = 0; i < num_lits; i++) {
|
||||
literal const & l = lits[i];
|
||||
expr * atom = l.atom();
|
||||
if (!l.sign() && m_manager.is_eq(atom) && find(to_app(atom)->get_arg(0)) == find(to_app(atom)->get_arg(1)))
|
||||
return true;
|
||||
if (!m_manager.is_eq(atom) && contains_complement(num_lits, lits, i, l.sign(), atom))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool semantic_tautology::operator()(unsigned num_lits, literal * lits) {
|
||||
if (!is_target(num_lits, lits))
|
||||
return false;
|
||||
init(num_lits, lits);
|
||||
process_eqs();
|
||||
bool r = is_tautology(num_lits, lits);
|
||||
TRACE("semantic_tautology", display(tout, num_lits, lits, m_manager); tout << "\nis semantic tautology: " << r << "\n";);
|
||||
return r;
|
||||
}
|
||||
|
||||
};
|
114
src/dead/spc/spc_semantic_tautology.h
Normal file
114
src/dead/spc/spc_semantic_tautology.h
Normal file
|
@ -0,0 +1,114 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
spc_semantic_tautology.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Semantic tautology detection
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2008-02-11.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _SPC_SEMANTIC_TAUTOLOGY_H_
|
||||
#define _SPC_SEMANTIC_TAUTOLOGY_H_
|
||||
|
||||
#include"spc_literal.h"
|
||||
#include"list.h"
|
||||
#include"obj_hashtable.h"
|
||||
#include"map.h"
|
||||
|
||||
namespace spc {
|
||||
|
||||
typedef obj_map<expr, expr *> expr2expr;
|
||||
|
||||
expr * find(expr2expr & f, expr * e);
|
||||
|
||||
/**
|
||||
\brief Functor for detecting semantic tautology.
|
||||
A clause C is a semantic tautology if it has the following form:
|
||||
|
||||
s_1 != t_1 or ... or s_n != t_n or s = t or R
|
||||
|
||||
sigma(s_1 = t_1), ..., sigma(s_n t_n) |= sigma(s = t)
|
||||
where sigma maps variables to constants.
|
||||
*/
|
||||
class semantic_tautology {
|
||||
typedef std::pair<expr *, expr *> expr_pair;
|
||||
|
||||
typedef obj_hashtable<expr> already_found;
|
||||
typedef expr2expr find_map;
|
||||
typedef obj_map<expr, list<app*> *> use_list;
|
||||
typedef obj_map<expr, unsigned> size_map;
|
||||
|
||||
struct k_hash {
|
||||
unsigned operator()(app * n) const { return n->get_decl()->get_id(); }
|
||||
};
|
||||
|
||||
struct c_hash {
|
||||
find_map & m_find;
|
||||
c_hash(find_map & f):m_find(f) {}
|
||||
unsigned operator()(app * n, unsigned i) const {
|
||||
unsigned id = spc::find(m_find, n->get_arg(i))->get_id();
|
||||
TRACE("semantic_tautology_detail", tout << "child(" << i << ") = #" << id << "\n";);
|
||||
return id;
|
||||
}
|
||||
};
|
||||
|
||||
struct cg_hash {
|
||||
ast_manager & m_manager;
|
||||
k_hash m_k_hash;
|
||||
c_hash m_c_hash;
|
||||
cg_hash(ast_manager & m, find_map & f):m_manager(m), m_c_hash(f) {}
|
||||
unsigned operator()(app * n) const;
|
||||
};
|
||||
|
||||
struct cg_eq {
|
||||
find_map & m_find;
|
||||
cg_eq(find_map & f):m_find(f) {}
|
||||
bool operator()(app * n1, app * n2) const;
|
||||
};
|
||||
|
||||
typedef ptr_hashtable<app, cg_hash, cg_eq> cg_table;
|
||||
|
||||
ast_manager & m_manager;
|
||||
region m_region;
|
||||
ptr_vector<app> m_init_todo;
|
||||
svector<expr_pair> m_todo;
|
||||
already_found m_already_found;
|
||||
use_list m_use_list;
|
||||
find_map m_find;
|
||||
size_map m_size;
|
||||
cg_table m_cg_table;
|
||||
|
||||
bool is_target(unsigned num_lits, literal * lits);
|
||||
void reset();
|
||||
void update_use_list(app * parent, expr * child);
|
||||
void push_init_core(expr * n);
|
||||
void push_init(expr * atom);
|
||||
void init_use_list();
|
||||
void init(unsigned num_lits, literal * lits);
|
||||
expr * find(expr * n) { return spc::find(m_find, n); }
|
||||
void remove_parents(expr * n1);
|
||||
void restore_parents(expr * n1, expr * n2);
|
||||
void assert_eq(expr * n1, expr * n2);
|
||||
void process_eqs();
|
||||
bool contains_complement(unsigned num_lits, literal * lits, unsigned i, bool sign, expr * atom);
|
||||
bool is_tautology(unsigned num_lits, literal * lits);
|
||||
|
||||
public:
|
||||
semantic_tautology(ast_manager & m);
|
||||
|
||||
bool operator()(unsigned num_lits, literal * lits);
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
#endif /* _SPC_SEMANTIC_TAUTOLOGY_H_ */
|
||||
|
54
src/dead/spc/spc_statistics.cpp
Normal file
54
src/dead/spc/spc_statistics.cpp
Normal file
|
@ -0,0 +1,54 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
spc_statistics.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
<abstract>
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2008-02-17.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#include"spc_statistics.h"
|
||||
|
||||
namespace spc {
|
||||
|
||||
void statistics::reset() {
|
||||
m_num_mk_clause = 0;
|
||||
m_num_del_clause = 0;
|
||||
m_num_processed = 0;
|
||||
m_num_superposition = 0;
|
||||
m_num_resolution = 0;
|
||||
m_num_eq_factoring = 0;
|
||||
m_num_factoring = 0;
|
||||
m_num_eq_resolution = 0;
|
||||
m_num_trivial = 0;
|
||||
m_num_simplified = 0;
|
||||
m_num_subsumed = 0;
|
||||
m_num_redundant = 0;
|
||||
}
|
||||
|
||||
void statistics::display(std::ostream & out) const {
|
||||
out << "num. mk. clause: " << m_num_mk_clause << "\n";
|
||||
out << "num. del. clause: " << m_num_del_clause << "\n";
|
||||
out << "num. processed: " << m_num_processed << "\n";
|
||||
out << "num. superposition: " << m_num_superposition << "\n";
|
||||
out << "num. resolution: " << m_num_resolution << "\n";
|
||||
out << "num. eq. factoring: " << m_num_eq_factoring << "\n";
|
||||
out << "num. factoring: " << m_num_factoring << "\n";
|
||||
out << "num. eq. resol.: " << m_num_eq_resolution << "\n";
|
||||
out << "num. simplified: " << m_num_simplified << "\n";
|
||||
out << "num. redundant: " << m_num_redundant << "\n";
|
||||
out << " num. trivial: " << m_num_trivial << "\n";
|
||||
out << " num. subsumed: " << m_num_subsumed << "\n";
|
||||
}
|
||||
|
||||
};
|
||||
|
49
src/dead/spc/spc_statistics.h
Normal file
49
src/dead/spc/spc_statistics.h
Normal file
|
@ -0,0 +1,49 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
spc_statistics.h
|
||||
|
||||
Abstract:
|
||||
|
||||
<abstract>
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2008-02-17.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _SPC_STATISTICS_H_
|
||||
#define _SPC_STATISTICS_H_
|
||||
|
||||
#include<iostream>
|
||||
|
||||
namespace spc {
|
||||
|
||||
struct statistics {
|
||||
unsigned m_num_mk_clause;
|
||||
unsigned m_num_del_clause;
|
||||
unsigned m_num_processed;
|
||||
unsigned m_num_superposition;
|
||||
unsigned m_num_resolution;
|
||||
unsigned m_num_eq_factoring;
|
||||
unsigned m_num_factoring;
|
||||
unsigned m_num_eq_resolution;
|
||||
unsigned m_num_trivial;
|
||||
unsigned m_num_simplified;
|
||||
unsigned m_num_subsumed;
|
||||
unsigned m_num_redundant;
|
||||
statistics() {
|
||||
reset();
|
||||
}
|
||||
|
||||
void reset();
|
||||
void display(std::ostream & out) const;
|
||||
};
|
||||
};
|
||||
|
||||
#endif /* _SPC_STATISTICS_H_ */
|
||||
|
698
src/dead/spc/spc_subsumption.cpp
Normal file
698
src/dead/spc/spc_subsumption.cpp
Normal file
|
@ -0,0 +1,698 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
spc_subsumption.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
<abstract>
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2008-02-13.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#include"spc_subsumption.h"
|
||||
#include"fvi_def.h"
|
||||
#include"ast_pp.h"
|
||||
|
||||
namespace spc {
|
||||
|
||||
/**
|
||||
\brief Return true if literal l2 is an instance of l1.
|
||||
|
||||
When ResetSubst == true, m_subst is reset before trying to match l1 and l2.
|
||||
|
||||
When ResetSubst == false, it is assumed that m_subst.push_scope was invoked
|
||||
before invoking match_literal.
|
||||
*/
|
||||
template<bool ResetSubst>
|
||||
bool subsumption::match_literal(literal const & l1, literal const & l2) {
|
||||
if (l1.sign() == l2.sign()) {
|
||||
expr * atom1 = l1.atom();
|
||||
expr * atom2 = l2.atom();
|
||||
bool is_eq1 = m_manager.is_eq(atom1);
|
||||
bool is_eq2 = m_manager.is_eq(atom2);
|
||||
if (is_eq1 && is_eq2) {
|
||||
expr * lhs1 = to_app(atom1)->get_arg(0);
|
||||
expr * rhs1 = to_app(atom1)->get_arg(1);
|
||||
expr * lhs2 = to_app(atom2)->get_arg(0);
|
||||
expr * rhs2 = to_app(atom2)->get_arg(1);
|
||||
if (ResetSubst)
|
||||
m_subst.reset_subst();
|
||||
|
||||
if (m_matcher(lhs1, lhs2, m_subst) && m_matcher(rhs1, rhs2, m_subst))
|
||||
return true;
|
||||
|
||||
if (ResetSubst)
|
||||
m_subst.reset_subst();
|
||||
else {
|
||||
// I'm assuming push_scope was invoked before executing match_literal
|
||||
// So, pop_scope is equivalent to a local reset.
|
||||
m_subst.pop_scope();
|
||||
m_subst.push_scope();
|
||||
}
|
||||
|
||||
return (m_matcher(lhs1, rhs2, m_subst) && m_matcher(rhs1, lhs2, m_subst));
|
||||
}
|
||||
else if (!is_eq1 && !is_eq2) {
|
||||
if (ResetSubst)
|
||||
m_subst.reset_subst();
|
||||
return m_matcher(atom1, atom2, m_subst);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Return true if for every literal l1 in lits1 there is a
|
||||
literal l2 in lits2 such that l2 is an instance of l1.
|
||||
*/
|
||||
bool subsumption::can_subsume(unsigned num_lits1, literal * lits1, unsigned num_lits2, literal * lits2) {
|
||||
for (unsigned i = 0; i < num_lits1; i++) {
|
||||
literal const & l1 = lits1[i];
|
||||
unsigned j = 0;
|
||||
for (; j < num_lits2; j++) {
|
||||
literal const & l2 = lits2[j];
|
||||
if (match_literal<true>(l1, l2))
|
||||
break;
|
||||
}
|
||||
if (j == num_lits2)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Return true if cls1 can subsume cls2. It performs a series of quick checks.
|
||||
*/
|
||||
bool subsumption::quick_check(clause * cls1, clause * cls2) {
|
||||
return
|
||||
cls1->get_symbol_count() <= cls2->get_symbol_count() &&
|
||||
cls1->get_const_count() <= cls2->get_const_count() &&
|
||||
cls1->get_depth() <= cls2->get_depth() &&
|
||||
cls1->get_num_pos_literals() <= cls2->get_num_pos_literals() &&
|
||||
cls1->get_num_neg_literals() <= cls2->get_num_neg_literals() &&
|
||||
(!cls1->is_ground() || cls2->is_ground());
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Return true if the set of literals lits1 subsumes the set of literals lits2.
|
||||
*/
|
||||
bool subsumption::subsumes_core(unsigned num_lits1, literal * lits1, unsigned num_lits2, literal * lits2) {
|
||||
enum state {
|
||||
INVOKE, DECIDE, BACKTRACK, RETURN
|
||||
};
|
||||
|
||||
if (num_lits1 == 0)
|
||||
return true;
|
||||
|
||||
m_stack.reset();
|
||||
m_subst.reset();
|
||||
|
||||
m_stack.push_back(assoc(0, 0));
|
||||
state st = DECIDE;
|
||||
|
||||
unsigned i;
|
||||
assoc * top;
|
||||
unsigned counter = 0;
|
||||
#ifdef _TRACE
|
||||
unsigned opt = 0;
|
||||
unsigned nopt = 0;
|
||||
#endif
|
||||
while (true && counter < 5000000) {
|
||||
counter++;
|
||||
switch (st) {
|
||||
case INVOKE:
|
||||
SASSERT(!m_stack.empty());
|
||||
i = m_stack.back().first + 1;
|
||||
if (i >= num_lits1) {
|
||||
TRACE("subsumption", tout << "subsumption result: YES.\n";);
|
||||
TRACE_CODE({
|
||||
if (counter > 10000) {
|
||||
TRACE("subsumption_perf",
|
||||
tout << "subsumption succeeded: " << counter << " " << opt << " " << nopt << "\n";
|
||||
tout << "literals1:\n"; display(tout, num_lits1, lits1, m_manager); tout << "\n";
|
||||
tout << "literals2:\n"; display(tout, num_lits2, lits2, m_manager); tout << "\n";);
|
||||
}
|
||||
});
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
m_stack.push_back(assoc(i, 0));
|
||||
st = DECIDE;
|
||||
}
|
||||
break;
|
||||
case DECIDE:
|
||||
top = &(m_stack.back());
|
||||
m_subst.push_scope();
|
||||
if (match_literal<false>(lits1[top->first], lits2[top->second]))
|
||||
st = INVOKE;
|
||||
else
|
||||
st = BACKTRACK;
|
||||
break;
|
||||
case BACKTRACK:
|
||||
top = &(m_stack.back());
|
||||
top->second++;
|
||||
m_subst.pop_scope();
|
||||
if (top->second >= num_lits2)
|
||||
st = RETURN;
|
||||
else
|
||||
st = DECIDE;
|
||||
break;
|
||||
case RETURN:
|
||||
top = &(m_stack.back());
|
||||
m_stack.pop_back();
|
||||
if (m_stack.empty()) {
|
||||
// no more alternatives
|
||||
TRACE("subsumption", tout << "subsumption result: NO\n";);
|
||||
TRACE_CODE({
|
||||
if (counter > 10000) {
|
||||
TRACE("subsumption_perf",
|
||||
tout << "subsumption failed: " << counter << " " << opt << " " << nopt << "\n";
|
||||
tout << "literals1:\n"; display(tout, num_lits1, lits1, m_manager); tout << "\n";
|
||||
tout << "literals2:\n"; display(tout, num_lits2, lits2, m_manager); tout << "\n";);
|
||||
}
|
||||
});
|
||||
return false;
|
||||
}
|
||||
if (m_subst.top_scope_has_bindings()) {
|
||||
TRACE_CODE(nopt++;);
|
||||
st = BACKTRACK;
|
||||
}
|
||||
else {
|
||||
TRACE_CODE(opt++;);
|
||||
#ifdef Z3DEBUG
|
||||
unsigned num_bindings = m_subst.get_num_bindings();
|
||||
#endif
|
||||
m_subst.pop_scope();
|
||||
SASSERT(num_bindings == m_subst.get_num_bindings());
|
||||
st = RETURN;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Return true if the set of ground literals lits1 subsumes the set of ground literals lits2.
|
||||
*/
|
||||
bool subsumption::ground_subsumes_core(unsigned num_lits1, literal * lits1, unsigned num_lits2, literal * lits2) {
|
||||
for (unsigned i = 0; i < num_lits1; i++) {
|
||||
literal const & l1 = lits1[i];
|
||||
unsigned j = 0;
|
||||
for (; j < num_lits2; j++) {
|
||||
literal const & l2 = lits2[j];
|
||||
if (l1 == l2)
|
||||
break;
|
||||
}
|
||||
if (j == num_lits2)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Return true if the literal l1 subsumes the set of literals lits2.
|
||||
*/
|
||||
bool subsumption::subsumes_core(literal const & l1, unsigned num_lits2, literal * lits2) {
|
||||
for (unsigned i = 0; i < num_lits2; i++) {
|
||||
if (match_literal<true>(l1, lits2[i]))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
subsumption::subsumption(ast_manager & m, asserted_literals & al, spc_params & params):
|
||||
m_manager(m),
|
||||
m_params(params),
|
||||
m_asserted_literals(al),
|
||||
m_subst(m),
|
||||
m_matcher(m),
|
||||
m_found_decls(m),
|
||||
m_index(0),
|
||||
m_num_processed_clauses(0),
|
||||
m_opt_threshold(params.m_initial_subsumption_index_opt) {
|
||||
|
||||
m_subst.reserve_offsets(1);
|
||||
|
||||
init_indexes();
|
||||
}
|
||||
|
||||
subsumption::~subsumption() {
|
||||
if (m_index)
|
||||
dealloc(m_index);
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Return true if cls1 subsumes cls2
|
||||
*/
|
||||
bool subsumption::operator()(clause * cls1, clause * cls2) {
|
||||
TRACE("subsumption_detail", tout << "checking if:\n"; cls1->display(tout, m_manager); tout << "\nsubsumes\n";
|
||||
cls2->display(tout, m_manager); tout << "\n";);
|
||||
if (!quick_check(cls1, cls2)) {
|
||||
TRACE("subsumption_detail", tout << "failed quick check\n";);
|
||||
return false;
|
||||
}
|
||||
|
||||
m_subst.reserve_vars(std::max(cls1->get_num_vars(), cls2->get_num_vars()));
|
||||
unsigned num_lits1 = cls1->get_num_literals();
|
||||
unsigned num_lits2 = cls2->get_num_literals();
|
||||
literal * lits1 = cls1->get_literals();
|
||||
literal * lits2 = cls2->get_literals();
|
||||
if (cls1->is_ground() && cls2->is_ground())
|
||||
return ground_subsumes_core(num_lits1, lits1, num_lits2, lits2);
|
||||
if (num_lits1 == 1)
|
||||
return subsumes_core(lits1[0], num_lits2, lits2);
|
||||
// TODO: REMOVE true below... using it for debugging purposes.
|
||||
if (true || cls1->get_num_neg_literals() >= 3 || cls1->get_num_pos_literals() >= 3)
|
||||
if (!can_subsume(num_lits1, lits1, num_lits2, lits2)) {
|
||||
TRACE("subsumption_detail", tout << "failed can_subsume\n";);
|
||||
return false;
|
||||
}
|
||||
return subsumes_core(num_lits1, lits1, num_lits2, lits2);
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Update the set of function symbols found in the clause being inserted into the index,
|
||||
and the set of clauses found since the index started to be built.
|
||||
|
||||
Return true if the function symbol should be tracked.
|
||||
*/
|
||||
bool subsumption::mark_func_decl(func_decl * f) {
|
||||
if (m_refining_index) {
|
||||
if (!m_cls_found_decl_set.contains(f)) {
|
||||
// update set of func_decls in the curr clause
|
||||
m_cls_found_decl_set.insert(f);
|
||||
m_cls_found_decls.push_back(f);
|
||||
// update global set of founf func_decls
|
||||
unsigned id = f->get_decl_id();
|
||||
m_found_decl_set.reserve(id+1);
|
||||
if (!m_found_decl_set.get(id)) {
|
||||
m_found_decl_set.set(id);
|
||||
m_found_decls.push_back(f);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
unsigned id = f->get_decl_id();
|
||||
// if func_decl was not found yet, then ignore it.
|
||||
if (id < m_found_decl_set.size() && m_found_decl_set.get(id)) {
|
||||
if (!m_cls_found_decl_set.contains(f)) {
|
||||
// update set of func_decls in the curr clause
|
||||
m_cls_found_decl_set.insert(f);
|
||||
m_cls_found_decls.push_back(f);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Increment the number of occurrences of a function symbol in the clause being
|
||||
inserted into the index.
|
||||
*/
|
||||
void subsumption::inc_f_count(func_decl * f, bool neg) {
|
||||
decl2nat & f_count = m_f_count[static_cast<unsigned>(neg)];
|
||||
unsigned val;
|
||||
if (f_count.find(f, val)) {
|
||||
f_count.insert(f, val + 1);
|
||||
}
|
||||
else {
|
||||
f_count.insert(f, 1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Update the min/max num. of occurrences of func symbol in a clause.
|
||||
*/
|
||||
void subsumption::update_min_max(func_decl * f) {
|
||||
for (unsigned is_neg = 0; is_neg < 1; is_neg++) {
|
||||
decl2nat & f_count = m_f_count[is_neg];
|
||||
decl2nat & f_min = m_f_min[is_neg];
|
||||
decl2nat & f_max = m_f_max[is_neg];
|
||||
unsigned count;
|
||||
if (f_count.find(f, count)) {
|
||||
unsigned old_count;
|
||||
if (!f_min.find(f, old_count) || old_count > count) {
|
||||
f_min.insert(f, count);
|
||||
}
|
||||
if (!f_max.find(f, old_count) || old_count < count) {
|
||||
f_max.insert(f, count);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Compute the number of occurences of function symbols in
|
||||
a clause.
|
||||
*/
|
||||
void subsumption::update_neg_pos_func_counts(clause * cls) {
|
||||
m_f_count[0].reset();
|
||||
m_f_count[1].reset();
|
||||
m_cls_found_decl_set.reset();
|
||||
m_cls_found_decls.reset();
|
||||
ptr_buffer<expr> todo;
|
||||
unsigned num_lits = cls->get_num_literals();
|
||||
for (unsigned i = 0; i < num_lits; i++) {
|
||||
literal const & l = cls->get_literal(i);
|
||||
bool is_neg = l.sign();
|
||||
expr * n = l.atom();
|
||||
todo.push_back(n);
|
||||
while (!todo.empty()) {
|
||||
n = todo.back();
|
||||
todo.pop_back();
|
||||
if (is_app(n)) {
|
||||
func_decl * f = to_app(n)->get_decl();
|
||||
if (fvi_candidate(f) && mark_func_decl(f))
|
||||
inc_f_count(f, is_neg);
|
||||
unsigned num = to_app(n)->get_num_args();
|
||||
for (unsigned i = 0; i < num; i++)
|
||||
todo.push_back(to_app(n)->get_arg(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (m_refining_index) {
|
||||
ptr_vector<func_decl>::iterator it = m_cls_found_decls.begin();
|
||||
ptr_vector<func_decl>::iterator end = m_cls_found_decls.end();
|
||||
for (; it != end; ++it) {
|
||||
func_decl * f = *it;
|
||||
update_min_max(f);
|
||||
unsigned val;
|
||||
if (m_f_freq.find(f, val))
|
||||
m_f_freq.insert(f, val + 1);
|
||||
else
|
||||
m_f_freq.insert(f, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Store in m_feature_vector the value for the features of cls.
|
||||
*/
|
||||
void subsumption::compute_features(clause * cls, unsigned * fvector) {
|
||||
unsigned num = m_features.size();
|
||||
for (unsigned i = 0; i < num; i++) {
|
||||
feature & f = m_features[i];
|
||||
switch (f.m_kind) {
|
||||
case F_GROUND:
|
||||
fvector[i] = cls->is_ground();
|
||||
break;
|
||||
case F_NUM_POS_LITS:
|
||||
fvector[i] = cls->get_num_pos_literals();
|
||||
break;
|
||||
case F_NUM_NEG_LITS:
|
||||
fvector[i] = cls->get_num_neg_literals();
|
||||
break;
|
||||
case F_DEPTH:
|
||||
fvector[i] = cls->get_depth();
|
||||
break;
|
||||
case F_CONST_COUNT:
|
||||
fvector[i] = cls->get_const_count();
|
||||
break;
|
||||
case F_SYM_COUNT:
|
||||
fvector[i] = cls->get_symbol_count();
|
||||
break;
|
||||
case F_NUM_NEG_FUNCS: {
|
||||
unsigned val;
|
||||
if (m_f_count[1].find(f.m_decl, val))
|
||||
fvector[i] = val;
|
||||
else
|
||||
fvector[i] = 0;
|
||||
break;
|
||||
}
|
||||
case F_NUM_POS_FUNCS: {
|
||||
unsigned val;
|
||||
if (m_f_count[0].find(f.m_decl, val))
|
||||
fvector[i] = val;
|
||||
else
|
||||
fvector[i] = 0;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
TRACE("subsumption_features",
|
||||
tout << "features of: "; cls->display(tout, m_manager); tout << "\n";
|
||||
for (unsigned i = 0; i < num; i++) {
|
||||
tout << fvector[i] << " ";
|
||||
}
|
||||
tout << "\n";);
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Initialise indexes for forward/backward subsumption.
|
||||
*/
|
||||
void subsumption::init_indexes() {
|
||||
// index for forward/backward subsumption
|
||||
// start with simple set of features
|
||||
m_features.push_back(feature(F_GROUND));
|
||||
m_features.push_back(feature(F_NUM_POS_LITS));
|
||||
m_features.push_back(feature(F_NUM_NEG_LITS));
|
||||
m_features.push_back(feature(F_DEPTH));
|
||||
m_features.push_back(feature(F_CONST_COUNT));
|
||||
m_features.push_back(feature(F_SYM_COUNT));
|
||||
m_index = alloc(index, m_features.size(), to_feature_vector(*this));
|
||||
}
|
||||
|
||||
unsigned subsumption::get_value_range(func_decl * f, bool neg) const {
|
||||
unsigned i = static_cast<unsigned>(neg);
|
||||
unsigned min;
|
||||
unsigned max;
|
||||
if (!m_f_min[i].find(f, min))
|
||||
min = 0;
|
||||
if (!m_f_max[i].find(f, max))
|
||||
max = 0;
|
||||
SASSERT(min <= max);
|
||||
return max - min;
|
||||
}
|
||||
|
||||
inline unsigned subsumption::get_value_range(func_decl * f) const {
|
||||
return std::max(get_value_range(f, false), get_value_range(f, true));
|
||||
}
|
||||
|
||||
bool subsumption::f_lt::operator()(func_decl * f1, func_decl * f2) const {
|
||||
unsigned vrange1 = m_owner.get_value_range(f1);
|
||||
unsigned vrange2 = m_owner.get_value_range(f2);
|
||||
if (vrange1 < vrange2)
|
||||
return true;
|
||||
if (vrange1 == vrange2)
|
||||
return f1->get_id() < f2->get_id();
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Optimize the index for (non unit) forward subsumption and
|
||||
backward subsumption.
|
||||
*/
|
||||
void subsumption::optimize_feature_index() {
|
||||
ptr_vector<clause> clauses;
|
||||
m_index->collect(clauses);
|
||||
|
||||
dealloc(m_index);
|
||||
m_features.reset();
|
||||
|
||||
ptr_vector<func_decl> targets;
|
||||
unsigned sz = m_found_decls.size();
|
||||
for (unsigned i = 0; i < sz; i++) {
|
||||
func_decl * f = m_found_decls.get(i);
|
||||
unsigned val;
|
||||
if (m_f_freq.find(f, val) && val > m_params.m_min_func_freq_subsumption_index && get_value_range(f) > 0)
|
||||
targets.push_back(f);
|
||||
}
|
||||
|
||||
|
||||
f_lt lt(*this);
|
||||
std::sort(targets.begin(), targets.end(), lt);
|
||||
|
||||
m_features.push_back(feature(F_GROUND));
|
||||
m_features.push_back(feature(F_NUM_POS_LITS));
|
||||
m_features.push_back(feature(F_NUM_NEG_LITS));
|
||||
m_features.push_back(feature(F_DEPTH));
|
||||
|
||||
ptr_vector<func_decl>::iterator it = targets.begin();
|
||||
ptr_vector<func_decl>::iterator end = targets.end();
|
||||
for (; it != end; ++it) {
|
||||
func_decl * f = *it;
|
||||
if (get_value_range(f, false) > 1)
|
||||
m_features.push_back(feature(f, false));
|
||||
if (get_value_range(f, true) > 1)
|
||||
m_features.push_back(feature(f, true));
|
||||
if (m_features.size() > m_params.m_max_subsumption_index_features)
|
||||
break;
|
||||
}
|
||||
|
||||
m_features.push_back(feature(F_CONST_COUNT));
|
||||
m_features.push_back(feature(F_SYM_COUNT));
|
||||
m_index = alloc(index, m_features.size(), to_feature_vector(*this));
|
||||
m_num_processed_clauses = 0;
|
||||
unsigned new_threshold = static_cast<unsigned>(m_opt_threshold * m_params.m_factor_subsumption_index_opt);
|
||||
if (new_threshold > m_opt_threshold)
|
||||
m_opt_threshold = new_threshold;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Insert cls into the indexes used for forward/backward subsumption.
|
||||
*/
|
||||
void subsumption::insert(clause * cls) {
|
||||
TRACE("subsumption", tout << "adding clause to subsumption index: " << cls << "\n"; cls->display(tout, m_manager); tout << "\n";);
|
||||
unsigned num_lits = cls->get_num_literals();
|
||||
if (num_lits > 1 || m_params.m_backward_subsumption) {
|
||||
m_index->insert(cls);
|
||||
SASSERT(m_index->contains(cls));
|
||||
m_num_processed_clauses++;
|
||||
if (m_num_processed_clauses > m_opt_threshold)
|
||||
optimize_feature_index();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Remove cls from the indexes used for forward/backward subsumption.
|
||||
*/
|
||||
void subsumption::erase(clause * cls) {
|
||||
TRACE("subsumption", tout << "removing clause from subsumption index:" << cls << "\n"; cls->display(tout, m_manager); tout << "\n";
|
||||
tout << "num lits.: " << cls->get_num_literals() << ", backward_sub: " << m_params.m_backward_subsumption << "\n";);
|
||||
unsigned num_lits = cls->get_num_literals();
|
||||
if (num_lits > 1 || m_params.m_backward_subsumption)
|
||||
m_index->erase(cls);
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Reset the indexes used for forward/backward subsumption.
|
||||
*/
|
||||
void subsumption::reset() {
|
||||
if (m_index)
|
||||
m_index->reset();
|
||||
m_num_processed_clauses = 0;
|
||||
m_opt_threshold = m_params.m_initial_subsumption_index_opt;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Return an unit clause C in the index that subsumes cls.
|
||||
Return 0 if such clause does not exist.
|
||||
*/
|
||||
clause * subsumption::unit_forward(clause * cls) {
|
||||
if (!m_asserted_literals.has_literals())
|
||||
return 0;
|
||||
m_asserted_literals.reserve_vars(cls->get_num_vars());
|
||||
unsigned num_lits = cls->get_num_literals();
|
||||
for (unsigned i = 0; i < num_lits; i++) {
|
||||
literal const & l = cls->get_literal(i);
|
||||
clause * subsumer = m_asserted_literals.gen(l);
|
||||
if (subsumer)
|
||||
return subsumer;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct non_unit_subsumption_visitor {
|
||||
subsumption & m_owner;
|
||||
clause * m_new_clause;
|
||||
clause * m_subsumer;
|
||||
non_unit_subsumption_visitor(subsumption & owner, clause * new_clause):
|
||||
m_owner(owner),
|
||||
m_new_clause(new_clause),
|
||||
m_subsumer(0) {
|
||||
}
|
||||
bool operator()(clause * candidate) {
|
||||
TRACE("subsumption_index", tout << "considering candidate:\n"; candidate->display(tout, m_owner.get_manager()); tout << "\n";);
|
||||
if (candidate->get_num_literals() > 1 && m_owner(candidate, m_new_clause)) {
|
||||
m_subsumer = candidate;
|
||||
return false; // stop subsumer was found
|
||||
}
|
||||
return true; // continue;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
\brief Return a non unit clause C in the index that subsumes cls.
|
||||
Return 0 if such clause does not exist.
|
||||
*/
|
||||
clause * subsumption::non_unit_forward(clause * cls) {
|
||||
non_unit_subsumption_visitor visitor(*this, cls);
|
||||
m_index->visit(cls, visitor, true);
|
||||
return visitor.m_subsumer;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Return a unit equality clause (= s t) that (eq) subsumes cls.
|
||||
That is, cls contains a literal (= u[s'] u[t']) and there is
|
||||
a substitution sigma s.t. sigma(s) = s' and sigma(t) = t'.
|
||||
Return 0 if such clause does not exist.
|
||||
*/
|
||||
clause * subsumption::eq_subsumption(clause * cls) {
|
||||
if (!m_asserted_literals.has_pos_literals())
|
||||
return 0;
|
||||
m_asserted_literals.reserve_vars(cls->get_num_vars());
|
||||
unsigned num_lits = cls->get_num_literals();
|
||||
for (unsigned i = 0; i < num_lits; i++) {
|
||||
literal const & l = cls->get_literal(i);
|
||||
expr * atom = l.atom();
|
||||
if (!l.sign() && m_manager.is_eq(atom)) {
|
||||
expr * lhs = to_app(atom)->get_arg(0);
|
||||
expr * rhs = to_app(atom)->get_arg(1);
|
||||
clause * subsumer = m_asserted_literals.subsumes(lhs, rhs);
|
||||
if (subsumer) {
|
||||
TRACE("eq_subsumption", tout << "equality subsumption:\n"; cls->display(tout, m_manager);
|
||||
tout << "\nis subsumed by:\n"; subsumer->display(tout, m_manager); tout << "\n";);
|
||||
return subsumer;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Return a clause C in the index (i.e., insert(C) was invoked) that subsumes cls.
|
||||
Return 0 if such clause does not exist.
|
||||
*/
|
||||
clause * subsumption::forward(clause * cls) {
|
||||
TRACE("subsumption", tout << "trying forward subsumption:\n"; cls->display(tout, m_manager); tout << "\n";);
|
||||
clause * subsumer = unit_forward(cls);
|
||||
if (subsumer)
|
||||
return subsumer;
|
||||
subsumer = non_unit_forward(cls);
|
||||
if (subsumer)
|
||||
return subsumer;
|
||||
if (m_params.m_equality_subsumption)
|
||||
return eq_subsumption(cls);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct backward_subsumption_visitor {
|
||||
subsumption & m_owner;
|
||||
clause * m_new_clause;
|
||||
ptr_buffer<clause> & m_result;
|
||||
backward_subsumption_visitor(subsumption & owner, clause * new_clause, ptr_buffer<clause> & result):
|
||||
m_owner(owner),
|
||||
m_new_clause(new_clause),
|
||||
m_result(result) {
|
||||
}
|
||||
|
||||
bool operator()(clause * candidate) {
|
||||
if (m_owner(m_new_clause, candidate))
|
||||
m_result.push_back(candidate);
|
||||
return true; // always continue in backward subsumption
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
\brief Store in result the set of clauses in the index that are subsumes by cls.
|
||||
*/
|
||||
void subsumption::backward(clause * cls, ptr_buffer<clause> & result) {
|
||||
if (m_params.m_backward_subsumption) {
|
||||
backward_subsumption_visitor visitor(*this, cls, result);
|
||||
m_index->visit(cls, visitor, false);
|
||||
}
|
||||
}
|
||||
};
|
156
src/dead/spc/spc_subsumption.h
Normal file
156
src/dead/spc/spc_subsumption.h
Normal file
|
@ -0,0 +1,156 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
spc_subsumption.h
|
||||
|
||||
Abstract:
|
||||
|
||||
<abstract>
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2008-02-13.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _SPC_SUBSUMPTION_H_
|
||||
#define _SPC_SUBSUMPTION_H_
|
||||
|
||||
#include"spc_asserted_literals.h"
|
||||
#include"matcher.h"
|
||||
#include"fvi.h"
|
||||
#include"spc_params.h"
|
||||
#include"obj_hashtable.h"
|
||||
|
||||
namespace spc {
|
||||
|
||||
class subsumption {
|
||||
ast_manager & m_manager;
|
||||
spc_params & m_params;
|
||||
asserted_literals & m_asserted_literals;
|
||||
substitution m_subst;
|
||||
matcher m_matcher;
|
||||
|
||||
// A pair representing the association between l1 and l2 where
|
||||
// first is the position of l1 in lits1 and second the position of l2 in
|
||||
// lits2.
|
||||
typedef std::pair<unsigned, unsigned> assoc;
|
||||
typedef vector<assoc> stack;
|
||||
stack m_stack;
|
||||
|
||||
template<bool ResetSubst>
|
||||
bool match_literal(literal const & l1, literal const & l2);
|
||||
|
||||
bool can_subsume(unsigned num_lits1, literal * lits1, unsigned num_lits2, literal * lits2);
|
||||
bool quick_check(clause * cls1, clause * cls2);
|
||||
bool subsumes_core(unsigned num_lits1, literal * lits1, unsigned num_lits2, literal * lits2);
|
||||
bool subsumes_core(literal const & l1, unsigned num_lits2, literal * lits2);
|
||||
bool ground_subsumes_core(unsigned num_lits1, literal * lits1, unsigned num_lits2, literal * lits2);
|
||||
|
||||
enum feature_kind {
|
||||
F_GROUND,
|
||||
F_NUM_POS_LITS,
|
||||
F_NUM_NEG_LITS,
|
||||
F_DEPTH,
|
||||
F_CONST_COUNT,
|
||||
F_SYM_COUNT,
|
||||
F_NUM_NEG_FUNCS,
|
||||
F_NUM_POS_FUNCS
|
||||
};
|
||||
|
||||
struct feature {
|
||||
feature_kind m_kind;
|
||||
func_decl * m_decl;
|
||||
feature(feature_kind k = F_GROUND):m_kind(k) {}
|
||||
feature(func_decl * decl, bool neg):m_kind(neg ? F_NUM_NEG_FUNCS : F_NUM_POS_FUNCS), m_decl(decl) {}
|
||||
};
|
||||
|
||||
vector<feature> m_features;
|
||||
|
||||
bit_vector m_found_decl_set;
|
||||
func_decl_ref_vector m_found_decls; // domain of m_found_decl_set;
|
||||
|
||||
/**
|
||||
\brief Return true if the function symbol is considered for feature vector indexing.
|
||||
*/
|
||||
bool fvi_candidate(func_decl * f) {
|
||||
return f->get_family_id() == null_family_id || f->get_arity() > 0;
|
||||
}
|
||||
|
||||
typedef obj_hashtable<func_decl> found_func_decl_set;
|
||||
found_func_decl_set m_cls_found_decl_set; // temporary set used to track the func_decl's found in a clause
|
||||
ptr_vector<func_decl> m_cls_found_decls;
|
||||
|
||||
bool mark_func_decl(func_decl * f);
|
||||
|
||||
typedef obj_map<func_decl, unsigned> decl2nat;
|
||||
bool m_refining_index; // if true keep collecting data to refine index.
|
||||
decl2nat m_f_count[2]; // temporary field used to track the num. of occurs. of function symbols in neg/pos literals.
|
||||
decl2nat m_f_min[2];
|
||||
decl2nat m_f_max[2];
|
||||
decl2nat m_f_freq;
|
||||
|
||||
void inc_f_count(func_decl * f, bool neg);
|
||||
void update_min_max(func_decl * f);
|
||||
void update_neg_pos_func_counts(clause * cls);
|
||||
|
||||
void compute_features(clause * cls, unsigned * fvector);
|
||||
|
||||
struct to_feature_vector;
|
||||
friend struct to_feature_vector;
|
||||
|
||||
struct to_feature_vector {
|
||||
subsumption & m_owner;
|
||||
to_feature_vector(subsumption & o):m_owner(o) {}
|
||||
void operator()(clause * cls, unsigned * fvector) {
|
||||
m_owner.compute_features(cls, fvector);
|
||||
}
|
||||
};
|
||||
|
||||
typedef fvi<clause, to_feature_vector, obj_ptr_hash<clause>, ptr_eq<clause> > index;
|
||||
index * m_index;
|
||||
unsigned m_num_processed_clauses;
|
||||
unsigned m_opt_threshold;
|
||||
|
||||
void init_indexes();
|
||||
|
||||
struct f_lt;
|
||||
friend struct f_lt;
|
||||
|
||||
unsigned get_value_range(func_decl * f, bool neg) const;
|
||||
unsigned get_value_range(func_decl * f) const;
|
||||
|
||||
struct f_lt {
|
||||
subsumption & m_owner;
|
||||
f_lt(subsumption & o):m_owner(o) {}
|
||||
bool operator()(func_decl * f1, func_decl * f2) const;
|
||||
};
|
||||
|
||||
void optimize_feature_index();
|
||||
|
||||
clause * unit_forward(clause * cls);
|
||||
clause * non_unit_forward(clause * cls);
|
||||
clause * eq_subsumption(expr * lhs, expr * rhs);
|
||||
clause * eq_subsumption(clause * cls);
|
||||
|
||||
public:
|
||||
subsumption(ast_manager & m, asserted_literals & al, spc_params & params);
|
||||
~subsumption();
|
||||
|
||||
bool operator()(clause * cls1, clause * cls2);
|
||||
void insert(clause * cls);
|
||||
void erase(clause * cls);
|
||||
void reset();
|
||||
clause * forward(clause * cls);
|
||||
void backward(clause * cls, ptr_buffer<clause> & result);
|
||||
|
||||
ast_manager & get_manager() { return m_manager; }
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
#endif /* _SPC_SUBSUMPTION_H_ */
|
||||
|
531
src/dead/spc/spc_superposition.cpp
Normal file
531
src/dead/spc/spc_superposition.cpp
Normal file
|
@ -0,0 +1,531 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
spc_superposition.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
<abstract>
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2008-02-15.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#include"spc_superposition.h"
|
||||
#include"ast_pp.h"
|
||||
|
||||
namespace spc {
|
||||
|
||||
superposition::superposition(ast_manager & m, order & o, statistics & s):
|
||||
m_manager(m),
|
||||
m_order(o),
|
||||
m_stats(s),
|
||||
m_subst(m),
|
||||
m_p(m),
|
||||
m_r(m),
|
||||
m_normalize_vars(m),
|
||||
m_spc_fid(m.get_family_id("spc")) {
|
||||
m_subst.reserve_offsets(3);
|
||||
m_deltas[0] = 0;
|
||||
m_deltas[1] = 0;
|
||||
}
|
||||
|
||||
superposition::~superposition() {
|
||||
}
|
||||
|
||||
void superposition::insert_p(clause * cls, expr * lhs, unsigned i) {
|
||||
m_p.insert(lhs);
|
||||
m_subst.reserve_vars(m_p.get_approx_num_regs());
|
||||
m_p2clause_set.insert(clause_pos_pair(cls, i), lhs);
|
||||
}
|
||||
|
||||
void superposition::insert_p(clause * cls, literal & l, unsigned i) {
|
||||
l.set_p_indexed(true);
|
||||
expr * atom = l.atom();
|
||||
if (!m_manager.is_eq(atom))
|
||||
return;
|
||||
if (l.is_oriented())
|
||||
insert_p(cls, l.is_left() ? l.lhs() : l.rhs(), i);
|
||||
else {
|
||||
insert_p(cls, l.lhs(), i);
|
||||
insert_p(cls, l.rhs(), i);
|
||||
}
|
||||
}
|
||||
|
||||
void superposition::insert_r(clause * cls, expr * n, unsigned i, bool lhs) {
|
||||
if (is_app(n)) {
|
||||
unsigned idx = (i << 1) | static_cast<unsigned>(lhs);
|
||||
|
||||
clause_pos_pair new_pair(cls, idx);
|
||||
SASSERT(m_todo.empty());
|
||||
m_todo.push_back(to_app(n));
|
||||
while (!m_todo.empty()) {
|
||||
app * n = m_todo.back();
|
||||
m_todo.pop_back();
|
||||
clause_pos_set * s = m_r2clause_set.get_parents(n);
|
||||
if (s == 0 || !s->contains(new_pair)) {
|
||||
m_r.insert(n);
|
||||
m_r2clause_set.insert(new_pair, n);
|
||||
unsigned num_args = n->get_num_args();
|
||||
for (unsigned i = 0; i < num_args; i++) {
|
||||
expr * c = n->get_arg(i);
|
||||
if (is_app(c))
|
||||
m_todo.push_back(to_app(c));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void superposition::insert_r(clause * cls, literal & l, unsigned i) {
|
||||
l.set_r_indexed(true);
|
||||
expr * atom = l.atom();
|
||||
if (m_manager.is_eq(atom)) {
|
||||
expr * lhs = l.lhs();
|
||||
expr * rhs = l.rhs();
|
||||
if (l.is_oriented()) {
|
||||
bool left = true;
|
||||
if (!l.is_left()) {
|
||||
left = false;
|
||||
std::swap(lhs, rhs);
|
||||
}
|
||||
insert_r(cls, lhs, i, left);
|
||||
}
|
||||
else {
|
||||
insert_r(cls, lhs, i, true);
|
||||
insert_r(cls, rhs, i, false);
|
||||
}
|
||||
}
|
||||
else {
|
||||
insert_r(cls, atom, i, false);
|
||||
}
|
||||
m_subst.reserve_vars(m_r.get_approx_num_regs());
|
||||
}
|
||||
|
||||
void superposition::insert(clause * cls) {
|
||||
unsigned num_lits = cls->get_num_literals();
|
||||
for (unsigned i = 0; i < num_lits; i++) {
|
||||
literal & l = cls->get_literal(i);
|
||||
if (l.is_p_indexed() || cls->is_eligible_for_paramodulation(m_order, l)) {
|
||||
if (!l.sign() && m_manager.is_eq(l.atom()))
|
||||
insert_p(cls, l, i);
|
||||
insert_r(cls, l, i);
|
||||
}
|
||||
else if (l.is_r_indexed() || cls->is_eligible_for_resolution(m_order, l)) {
|
||||
insert_r(cls, l, i);
|
||||
}
|
||||
}
|
||||
TRACE("superposition_detail",
|
||||
tout << "adding clause: "; cls->display(tout, m_manager); tout << "\n";
|
||||
tout << "p index:\n";
|
||||
m_p.display(tout);
|
||||
tout << "r index:\n";
|
||||
m_r.display(tout););
|
||||
}
|
||||
|
||||
void superposition::erase_p(clause * cls, expr * lhs, unsigned i) {
|
||||
m_p2clause_set.erase(clause_pos_pair(cls, i), lhs);
|
||||
if (m_p2clause_set.empty(lhs))
|
||||
m_p.erase(lhs);
|
||||
}
|
||||
|
||||
void superposition::erase_p(clause * cls, literal & l, unsigned i) {
|
||||
expr * atom = l.atom();
|
||||
if (!m_manager.is_eq(atom))
|
||||
return;
|
||||
if (l.is_oriented())
|
||||
erase_p(cls, l.is_left() ? l.lhs() : l.rhs(), i);
|
||||
else {
|
||||
erase_p(cls, l.lhs(), i);
|
||||
erase_p(cls, l.rhs(), i);
|
||||
}
|
||||
}
|
||||
|
||||
void superposition::erase_r(clause * cls, literal & l, unsigned i) {
|
||||
clause_pos_pair pair(cls, i);
|
||||
|
||||
expr * atom = l.atom();
|
||||
SASSERT(is_app(atom));
|
||||
SASSERT(m_todo.empty());
|
||||
m_todo.push_back(to_app(atom));
|
||||
|
||||
while (!m_todo.empty()) {
|
||||
app * n = m_todo.back();
|
||||
m_todo.pop_back();
|
||||
switch (m_r2clause_set.erase(pair, n)) {
|
||||
case 0: // pair is not a parent of n
|
||||
break;
|
||||
case 1: // pair is the last parent of n
|
||||
m_r.erase(n);
|
||||
default:
|
||||
unsigned num_args = n->get_num_args();
|
||||
for (unsigned i = 0; i < num_args; i++) {
|
||||
expr * c = n->get_arg(i);
|
||||
if (is_app(c))
|
||||
m_todo.push_back(to_app(c));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void superposition::erase(clause * cls) {
|
||||
unsigned num_lits = cls->get_num_literals();
|
||||
for (unsigned i = 0; i < num_lits; i++) {
|
||||
literal & l = cls->get_literal(i);
|
||||
if (l.is_p_indexed())
|
||||
erase_p(cls, l, i);
|
||||
if (l.is_r_indexed())
|
||||
erase_r(cls, l, i);
|
||||
}
|
||||
}
|
||||
|
||||
void superposition::reset() {
|
||||
m_p.reset();
|
||||
m_p2clause_set.reset();
|
||||
m_r.reset();
|
||||
m_r2clause_set.reset();
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Copy to result the literals of s except literal at position idx. Apply the substitution m_subst,
|
||||
assuming that the variables of s are in the variable bank offset. The deltas for each bank are
|
||||
stored in m_deltas.
|
||||
*/
|
||||
void superposition::copy_literals(clause * s, unsigned idx, unsigned offset, literal_buffer & result) {
|
||||
unsigned num_lits = s->get_num_literals();
|
||||
for (unsigned i = 0; i < num_lits; i++)
|
||||
if (i != idx) {
|
||||
literal const & l = s->get_literal(i);
|
||||
expr_ref new_atom(m_manager);
|
||||
m_subst.apply(2, m_deltas, expr_offset(l.atom(), offset), new_atom);
|
||||
TRACE("superposition_copy", tout << "i: " << i << ", idx: " << idx << ", offset: " << offset << "\natom:\n";
|
||||
tout << mk_pp(l.atom(), m_manager) << "\nnew_atom:\n" << mk_pp(new_atom, m_manager) << "\n";);
|
||||
result.push_back(literal(new_atom, l.sign()));
|
||||
}
|
||||
}
|
||||
|
||||
void superposition::normalize_literals(unsigned num_lits, literal * lits, literal_buffer & result) {
|
||||
m_normalize_vars.reset();
|
||||
for (unsigned i = 0; i < num_lits; i++) {
|
||||
literal const & l = lits[i];
|
||||
result.push_back(literal(m_normalize_vars(l.atom()), l.sign()));
|
||||
}
|
||||
}
|
||||
|
||||
void superposition::mk_sp_clause(unsigned num_lits, literal * lits, justification * p1, justification * p2) {
|
||||
literal_buffer new_literals(m_manager);
|
||||
normalize_literals(num_lits, lits, new_literals);
|
||||
justification * js = mk_superposition_justification(m_manager, m_spc_fid, p1, p2,
|
||||
new_literals.size(), new_literals.c_ptr(),
|
||||
m_normalize_vars.get_num_vars(), m_normalize_vars.get_vars());
|
||||
clause * new_cls = clause::mk(m_manager, new_literals.size(), new_literals.c_ptr(), js, 0);
|
||||
m_new_clauses->push_back(new_cls);
|
||||
TRACE("superposition", tout << "new superposition clause:\n"; new_cls->display(tout, m_manager); tout << "\n";);
|
||||
m_stats.m_num_superposition++;
|
||||
}
|
||||
|
||||
void superposition::mk_res_clause(unsigned num_lits, literal * lits, justification * p1, justification * p2) {
|
||||
literal_buffer new_literals(m_manager);
|
||||
normalize_literals(num_lits, lits, new_literals);
|
||||
justification * js = mk_resolution_justification(m_manager, m_spc_fid, p1, p2,
|
||||
new_literals.size(), new_literals.c_ptr(),
|
||||
m_normalize_vars.get_num_vars(), m_normalize_vars.get_vars());
|
||||
clause * new_cls = clause::mk(m_manager, new_literals.size(), new_literals.c_ptr(), js, 0);
|
||||
m_new_clauses->push_back(new_cls);
|
||||
TRACE("superposition", tout << "new resolution clause:\n"; new_cls->display(tout, m_manager); tout << "\n";);
|
||||
m_stats.m_num_resolution++;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Given the equation (= lhs rhs) of the clause being
|
||||
added, try to apply resolution where the clause being added
|
||||
is the main clause in the superposition rule.
|
||||
*/
|
||||
void superposition::try_superposition_main(expr * lhs, expr * rhs) {
|
||||
m_lhs = lhs;
|
||||
m_rhs = rhs;
|
||||
m_subst.reset_subst();
|
||||
TRACE("spc_superposition", tout << "try_superposition_main, lhs:\n" << mk_pp(m_lhs, m_manager) << "\nrhs:\n" << mk_pp(m_rhs, m_manager) << "\n";
|
||||
tout << "substitution:\n"; m_subst.display(tout););
|
||||
r_visitor v(*this, m_subst);
|
||||
m_r.unify(lhs, v);
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Try to apply superposition rule using the clause
|
||||
being added (m_clause) as main clause, and its literal m_lit
|
||||
as the equation.
|
||||
*/
|
||||
void superposition::try_superposition_main() {
|
||||
expr * lhs = m_lit->lhs();
|
||||
expr * rhs = m_lit->rhs();
|
||||
TRACE("spc_superposition", tout << "trying superposition:\n" << mk_pp(lhs, m_manager) << "\n" << mk_pp(rhs, m_manager) << "\nis_oriented: " << m_lit->is_oriented() << "\n";);
|
||||
if (m_lit->is_oriented()) {
|
||||
if (!m_lit->is_left())
|
||||
std::swap(lhs, rhs);
|
||||
try_superposition_main(lhs, rhs);
|
||||
}
|
||||
else {
|
||||
try_superposition_main(lhs, rhs);
|
||||
try_superposition_main(rhs, lhs);
|
||||
}
|
||||
}
|
||||
|
||||
void superposition::found_r(expr * r) {
|
||||
TRACE("spc_superposition", tout << "found_r:\n" << mk_pp(r, m_manager) << "\n";
|
||||
tout << "substitution:\n"; m_subst.display(tout););
|
||||
if (m_r2clause_set.empty(r))
|
||||
return;
|
||||
TRACE("spc_superposition", tout << "r2clause is not empty.\n";);
|
||||
if (!m_lit->is_oriented() && m_order.greater(m_rhs, m_lhs, &m_subst))
|
||||
return;
|
||||
TRACE("spc_superposition", tout << "order restriction was met.\n";);
|
||||
if (!m_clause->is_eligible_for_paramodulation(m_order, *m_lit, 0, &m_subst))
|
||||
return;
|
||||
TRACE("spc_superposition", tout << "literal is eligible for paramodulation.\n";);
|
||||
r2clause_set::iterator it = m_r2clause_set.begin(r);
|
||||
r2clause_set::iterator end = m_r2clause_set.end(r);
|
||||
for (; it != end; ++it) {
|
||||
clause_pos_pair & p = *it;
|
||||
clause * aux_cls = p.first;
|
||||
unsigned aux_idx = p.second >> 1;
|
||||
//
|
||||
// The following optimization is incorrect (if statement).
|
||||
// For example, it prevents the Z3 from proving the trivial benchmark
|
||||
// c = X,
|
||||
// a != b
|
||||
// using the order a < b < c
|
||||
//
|
||||
// To prove, this example we need to generate the clause Y = X by applying superposition of c = X on itself.
|
||||
// We can see that by renaming the first clause to c = Y, and then, substituting c in the original by Y.
|
||||
//
|
||||
// Actually, this optimization is correct when the set of variables in m_lhs is a superset of the set of variables in m_rhs,
|
||||
// because in this case, the new literal will be equivalent to true. In the example above, this is not the case,
|
||||
// since m_lhs does not contain any variable, and m_rhs contains one.
|
||||
//
|
||||
|
||||
//
|
||||
// if (r == m_lhs && m_clause == aux_cls && m_idx == aux_idx)
|
||||
// continue;
|
||||
//
|
||||
bool in_lhs = (p.second & 1) != 0;
|
||||
TRACE("spc_superposition", tout << "aux_cls:\n"; aux_cls->display(tout, m_manager); tout << "\naux_idx: " << aux_cls << ", in_lhs: " << in_lhs << "\n";);
|
||||
literal & aux_lit = aux_cls->get_literal(aux_idx);
|
||||
if (!aux_cls->is_eligible_for_resolution(m_order, aux_lit, 1, &m_subst))
|
||||
continue;
|
||||
literal_buffer new_literals(m_manager);
|
||||
m_subst.reset_cache();
|
||||
if (m_manager.is_eq(aux_lit.atom())) {
|
||||
expr * lhs = aux_lit.lhs();
|
||||
expr * rhs = aux_lit.rhs();
|
||||
TRACE("spc_superposition", tout << "aux_lit lhs:\n" << mk_pp(lhs, m_manager) << "\nrhs:\n" << mk_pp(rhs, m_manager) << "\n";);
|
||||
if (!in_lhs)
|
||||
std::swap(lhs, rhs);
|
||||
if (!aux_lit.is_oriented() && m_order.greater(rhs, lhs, 1, &m_subst)) {
|
||||
TRACE("spc_superposition", tout << "failed order constraint.\n";);
|
||||
continue;
|
||||
}
|
||||
expr_ref new_lhs(m_manager), new_rhs(m_manager);
|
||||
m_subst.apply(2, m_deltas, expr_offset(lhs, 1), expr_offset(r, 1), expr_offset(m_rhs, 0), new_lhs);
|
||||
m_subst.apply(2, m_deltas, expr_offset(rhs, 1), new_rhs);
|
||||
TRACE("spc_superposition", tout << "aux_lit new_lhs:\n" << mk_pp(new_lhs, m_manager) << "\nnew_rhs:\n" << mk_pp(new_rhs, m_manager) << "\n";);
|
||||
expr * new_eq = m_manager.mk_eq(new_lhs, new_rhs);
|
||||
new_literals.push_back(literal(new_eq, aux_lit.sign()));
|
||||
}
|
||||
else {
|
||||
expr_ref new_atom(m_manager);
|
||||
m_subst.apply(2, m_deltas, expr_offset(aux_lit.atom(), 1), new_atom);
|
||||
new_literals.push_back(literal(new_atom, aux_lit.sign()));
|
||||
}
|
||||
copy_literals(m_clause, m_idx, 0, new_literals);
|
||||
copy_literals(aux_cls, aux_idx, 1, new_literals);
|
||||
TRACE("superposition", tout << "found r target: " << mk_pp(r, m_manager) << " for \n" <<
|
||||
mk_pp(m_lhs, m_manager) << "\nmain clause: "; m_clause->display(tout, m_manager);
|
||||
tout << "\naux clause: "; aux_cls->display(tout, m_manager); tout << "\nat pos: " <<
|
||||
aux_idx << "\n";);
|
||||
mk_sp_clause(new_literals.size(), new_literals.c_ptr(), m_clause->get_justification(), aux_cls->get_justification());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Try to apply superposition rule using the clause
|
||||
being added (m_clause) as the aux clause, and its literal m_lit
|
||||
as the target.
|
||||
*/
|
||||
void superposition::try_superposition_aux() {
|
||||
TRACE("superposition_aux", tout << "superposition aux:\n"; m_clause->display(tout, m_manager);
|
||||
tout << "\nusing literal: " << m_idx << "\n";);
|
||||
if (m_manager.is_eq(m_lit->atom())) {
|
||||
expr * lhs = m_lit->lhs();
|
||||
expr * rhs = m_lit->rhs();
|
||||
if (m_lit->is_oriented()) {
|
||||
if (!m_lit->is_left())
|
||||
std::swap(lhs, rhs);
|
||||
try_superposition_aux(lhs, rhs);
|
||||
}
|
||||
else {
|
||||
try_superposition_aux(lhs, rhs);
|
||||
try_superposition_aux(rhs, lhs);
|
||||
}
|
||||
}
|
||||
else {
|
||||
try_superposition_aux(m_lit->atom(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Use the clause being added as the auxiliary clause in the superposition rule.
|
||||
*/
|
||||
void superposition::try_superposition_aux(expr * lhs, expr * rhs) {
|
||||
TRACE("superposition_aux", tout << "try_superposition_aux\n" << mk_pp(lhs, m_manager) << "\n" << mk_pp(rhs, m_manager) << "\n";);
|
||||
if (is_var(lhs))
|
||||
return;
|
||||
m_lhs = lhs;
|
||||
m_rhs = rhs;
|
||||
SASSERT(m_todo.empty());
|
||||
m_todo.push_back(to_app(lhs));
|
||||
while (!m_todo.empty()) {
|
||||
m_target = m_todo.back();
|
||||
m_todo.pop_back();
|
||||
m_subst.reset_subst();
|
||||
p_visitor v(*this, m_subst);
|
||||
TRACE("superposition_aux", tout << "trying to find unifier for:\n" << mk_pp(m_target, m_manager) << "\n";);
|
||||
m_p.unify(m_target, v);
|
||||
unsigned j = m_target->get_num_args();
|
||||
while (j > 0) {
|
||||
--j;
|
||||
expr * arg = m_target->get_arg(j);
|
||||
if (is_app(arg))
|
||||
m_todo.push_back(to_app(arg));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void superposition::found_p(expr * p) {
|
||||
TRACE("superposition_found_p", tout << "found p:\n" << mk_pp(p, m_manager) << "\n";);
|
||||
if (m_p2clause_set.empty(p)) {
|
||||
TRACE("superposition_found_p", tout << "clause set is empty.\n";);
|
||||
return;
|
||||
}
|
||||
if (m_rhs && !m_lit->is_oriented() && m_order.greater(m_rhs, m_lhs, &m_subst)) {
|
||||
TRACE("superposition_found_p", tout << "aux clause failed not rhs > lhs constraint.\n";);
|
||||
return;
|
||||
}
|
||||
if (!m_clause->is_eligible_for_resolution(m_order, *m_lit, 0, &m_subst)) {
|
||||
TRACE("superposition_found_p", tout << "aux literal is not eligible for resolution.\n";);
|
||||
return;
|
||||
}
|
||||
p2clause_set::iterator it = m_p2clause_set.begin(p);
|
||||
p2clause_set::iterator end = m_p2clause_set.end(p);
|
||||
for (; it != end; ++it) {
|
||||
clause_pos_pair & pair = *it;
|
||||
clause * main_cls = pair.first;
|
||||
TRACE("superposition_found_p", tout << "p clause:\n"; main_cls->display(tout, m_manager); tout << "\n";);
|
||||
unsigned lit_idx = pair.second;
|
||||
if (p == m_lhs && m_clause == main_cls && m_idx == lit_idx)
|
||||
continue;
|
||||
literal const & main_lit = main_cls->get_literal(lit_idx);
|
||||
SASSERT(m_manager.is_eq(main_lit.atom()));
|
||||
expr * lhs = main_lit.lhs();
|
||||
expr * rhs = main_lit.rhs();
|
||||
if (rhs == p)
|
||||
std::swap(lhs, rhs);
|
||||
SASSERT(lhs == p);
|
||||
TRACE("superposition_found_p", tout << "lhs: " << mk_pp(lhs, m_manager) << "\nrhs: " << mk_pp(rhs, m_manager) << "\n";);
|
||||
if (!main_lit.is_oriented() && m_order.greater(rhs, lhs, 1, &m_subst))
|
||||
continue;
|
||||
if (!main_cls->is_eligible_for_paramodulation(m_order, main_lit, 1, &m_subst))
|
||||
continue;
|
||||
literal_buffer new_literals(m_manager);
|
||||
m_subst.reset_cache();
|
||||
TRACE("superposition_found_p", tout << "creating new_lhs\n";);
|
||||
expr_ref new_lhs(m_manager);
|
||||
m_subst.apply(2, m_deltas, expr_offset(m_lhs, 0), expr_offset(m_target, 0), expr_offset(rhs, 1), new_lhs);
|
||||
// FIX: m_subst.reset_cache();
|
||||
TRACE("superposition_found_p", tout << "new_lhs: " << mk_pp(new_lhs, m_manager) << "\n";
|
||||
m_subst.display(tout););
|
||||
expr * new_atom = 0;
|
||||
if (m_rhs) {
|
||||
TRACE("superposition_found_p", tout << "creating new_rhs\n";);
|
||||
expr_ref new_rhs(m_manager);
|
||||
m_subst.apply(2, m_deltas, expr_offset(m_rhs, 0), new_rhs);
|
||||
TRACE("superposition_found_p", tout << "new_rhs: " << mk_pp(new_rhs, m_manager) << "\n";);
|
||||
new_atom = m_manager.mk_eq(new_lhs, new_rhs);
|
||||
}
|
||||
else
|
||||
new_atom = new_lhs;
|
||||
TRACE("superposition_found_p", tout << "new_atom: " << mk_pp(new_atom, m_manager) << "\n"; m_subst.display(tout););
|
||||
new_literals.push_back(literal(new_atom, m_lit->sign()));
|
||||
TRACE("superposition_found_p", tout << "copying literals\n";);
|
||||
copy_literals(main_cls, lit_idx, 1, new_literals);
|
||||
copy_literals(m_clause, m_idx, 0, new_literals);
|
||||
TRACE("superposition", tout << "found p target: " << mk_pp(p, m_manager) << " for \n" <<
|
||||
mk_pp(m_lhs, m_manager) << "\nmain clause: "; main_cls->display(tout, m_manager);
|
||||
tout << "\naux clause: "; m_clause->display(tout, m_manager); tout << "\n";);
|
||||
mk_sp_clause(new_literals.size(), new_literals.c_ptr(), main_cls->get_justification(), m_clause->get_justification());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Try to apply resolution rule using the clause being added (m_clause).
|
||||
*/
|
||||
void superposition::try_resolution() {
|
||||
m_subst.reset_subst();
|
||||
res_visitor v(*this, m_subst);
|
||||
m_r.unify(m_lit->atom(), v);
|
||||
}
|
||||
|
||||
void superposition::found_res(expr * r) {
|
||||
if (m_r2clause_set.empty(r))
|
||||
return;
|
||||
if (!m_clause->is_eligible_for_resolution(m_order, *m_lit, 0, &m_subst))
|
||||
return;
|
||||
r2clause_set::iterator it = m_r2clause_set.begin(r);
|
||||
r2clause_set::iterator end = m_r2clause_set.end(r);
|
||||
for (; it != end; ++it) {
|
||||
clause_pos_pair & pair = *it;
|
||||
clause * aux_cls = pair.first;
|
||||
unsigned aux_idx = pair.second >> 1;
|
||||
literal const & aux_lit = aux_cls->get_literal(aux_idx);
|
||||
if (aux_lit.sign() == m_lit->sign())
|
||||
continue;
|
||||
if (aux_lit.atom() != r)
|
||||
continue;
|
||||
if (!aux_cls->is_eligible_for_resolution(m_order, aux_lit, 1, &m_subst))
|
||||
continue;
|
||||
literal_buffer new_literals(m_manager);
|
||||
m_subst.reset_cache();
|
||||
copy_literals(m_clause, m_idx, 0, new_literals);
|
||||
copy_literals(aux_cls, aux_idx, 1, new_literals);
|
||||
mk_res_clause(new_literals.size(), new_literals.c_ptr(), m_clause->get_justification(), aux_cls->get_justification());
|
||||
}
|
||||
}
|
||||
|
||||
void superposition::operator()(clause * cls, ptr_vector<clause> & new_clauses) {
|
||||
m_subst.reserve_vars(cls->get_num_vars());
|
||||
m_clause = cls;
|
||||
m_new_clauses = &new_clauses;
|
||||
SASSERT(m_deltas[0] == 0);
|
||||
m_deltas[1] = m_clause->get_num_vars();
|
||||
unsigned num_lits = cls->get_num_literals();
|
||||
for (m_idx = 0; m_idx < num_lits; m_idx++) {
|
||||
m_lit = &(cls->get_literal(m_idx));
|
||||
bool is_eq = m_manager.is_eq(m_lit->atom());
|
||||
if (!m_lit->sign() && m_lit->is_p_indexed() && is_eq)
|
||||
try_superposition_main();
|
||||
if (m_lit->is_r_indexed()) {
|
||||
try_superposition_aux();
|
||||
if (!is_eq)
|
||||
try_resolution();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
147
src/dead/spc/spc_superposition.h
Normal file
147
src/dead/spc/spc_superposition.h
Normal file
|
@ -0,0 +1,147 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
spc_superposition.h
|
||||
|
||||
Abstract:
|
||||
|
||||
<abstract>
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2008-02-15.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _SPC_SUPERPOSITION_H_
|
||||
#define _SPC_SUPERPOSITION_H_
|
||||
|
||||
#include"spc_clause.h"
|
||||
#include"spc_clause_pos_set.h"
|
||||
#include"substitution_tree.h"
|
||||
#include"obj_hashtable.h"
|
||||
#include"sparse_use_list.h"
|
||||
#include"normalize_vars.h"
|
||||
#include"spc_statistics.h"
|
||||
|
||||
namespace spc {
|
||||
|
||||
/**
|
||||
\brief Functor for applying the superposition right/left rules.
|
||||
|
||||
- Superposition Left
|
||||
s = t or S, u != v or R
|
||||
==>
|
||||
sigma(u[p<-t] != v or S or R)
|
||||
|
||||
sigma is the mgu(u|p, s)
|
||||
sigma(s) not greater than sigma(t)
|
||||
sigma(u) not greater than sigma(v)
|
||||
sigma(s = t) is eligible for paramodulation
|
||||
sigma(u != v) is eligible for resolution
|
||||
u|p is not a variable
|
||||
|
||||
|
||||
- Superposition Right
|
||||
s = t or S, u = v or R
|
||||
==>
|
||||
sigma(u[p<-t] != v or S or R)
|
||||
|
||||
Same restrictions of Superposition Left
|
||||
|
||||
This functor also applied binary resolution rule.
|
||||
|
||||
We say the left clause is the main clause in the superposition.
|
||||
*/
|
||||
class superposition {
|
||||
ast_manager & m_manager;
|
||||
order & m_order;
|
||||
statistics & m_stats;
|
||||
substitution m_subst;
|
||||
|
||||
// indexes for left clause
|
||||
substitution_tree m_p; // potential left hand sides for superposition
|
||||
typedef sparse_use_list<expr, svector<clause_pos_pair> > p2clause_set;
|
||||
p2clause_set m_p2clause_set;
|
||||
|
||||
void insert_p(clause * cls, expr * lhs, unsigned i);
|
||||
void insert_p(clause * cls, literal & l, unsigned i);
|
||||
|
||||
void erase_p(clause * cls, expr * lhs, unsigned i);
|
||||
void erase_p(clause * cls, literal & l, unsigned i);
|
||||
|
||||
// indexes for right clause
|
||||
substitution_tree m_r; // potential targets for superposition
|
||||
typedef sparse_use_list<expr, clause_pos_set> r2clause_set;
|
||||
r2clause_set m_r2clause_set;
|
||||
ptr_vector<app> m_todo;
|
||||
|
||||
void insert_r(clause * cls, expr * n, unsigned i, bool lhs);
|
||||
void insert_r(clause * cls, literal & l, unsigned i);
|
||||
void erase_r(clause * cls, literal & l, unsigned i);
|
||||
|
||||
normalize_vars m_normalize_vars;
|
||||
|
||||
// temporary fields...
|
||||
ptr_vector<clause> * m_new_clauses;
|
||||
clause * m_clause;
|
||||
literal * m_lit;
|
||||
expr * m_lhs;
|
||||
expr * m_rhs;
|
||||
app * m_target;
|
||||
unsigned m_idx;
|
||||
unsigned m_deltas[2];
|
||||
family_id m_spc_fid;
|
||||
|
||||
void normalize_literals(unsigned num_lits, literal * lits, literal_buffer & result);
|
||||
void copy_literals(clause * s, unsigned idx, unsigned offset, literal_buffer & result);
|
||||
void mk_sp_clause(unsigned num_lits, literal * lits, justification * p1, justification * p2);
|
||||
void mk_res_clause(unsigned num_lits, literal * lits, justification * p1, justification * p2);
|
||||
void try_superposition_main(expr * lhs, expr * rhs);
|
||||
void try_superposition_main();
|
||||
void found_r(expr * r);
|
||||
void try_superposition_aux(expr * lhs, expr * rhs);
|
||||
void try_superposition_aux();
|
||||
void found_p(expr * p);
|
||||
void try_resolution();
|
||||
void found_res(expr * r);
|
||||
|
||||
friend struct r_visitor;
|
||||
struct r_visitor : public st_visitor {
|
||||
superposition & m_owner;
|
||||
r_visitor(superposition & o, substitution & s):st_visitor(s), m_owner(o) {}
|
||||
virtual bool operator()(expr * e) { m_owner.found_r(e); return true; /* continue */ }
|
||||
};
|
||||
|
||||
friend struct p_visitor;
|
||||
struct p_visitor : public st_visitor {
|
||||
superposition & m_owner;
|
||||
p_visitor(superposition & o, substitution & s):st_visitor(s), m_owner(o) {}
|
||||
virtual bool operator()(expr * e) { m_owner.found_p(e); return true; /* continue */ }
|
||||
};
|
||||
|
||||
friend struct res_visitor;
|
||||
struct res_visitor : public st_visitor {
|
||||
superposition & m_owner;
|
||||
res_visitor(superposition & o, substitution & s):st_visitor(s), m_owner(o) {}
|
||||
virtual bool operator()(expr * e) { m_owner.found_res(e); return true; /* continue */ }
|
||||
};
|
||||
|
||||
public:
|
||||
superposition(ast_manager & m, order & o, statistics & stats);
|
||||
~superposition();
|
||||
|
||||
void insert(clause * cls);
|
||||
void erase(clause * cls);
|
||||
void reset();
|
||||
|
||||
void operator()(clause * cls, ptr_vector<clause> & new_clauses);
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
#endif /* _SPC_SUPERPOSITION_H_ */
|
||||
|
52
src/dead/spc/spc_unary_inference.cpp
Normal file
52
src/dead/spc/spc_unary_inference.cpp
Normal file
|
@ -0,0 +1,52 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
spc_unary_inference.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
<abstract>
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2008-02-14.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#include"spc_unary_inference.h"
|
||||
|
||||
namespace spc {
|
||||
|
||||
unary_inference::unary_inference(ast_manager & m, order & ord):
|
||||
m_manager(m),
|
||||
m_order(ord),
|
||||
m_subst(m),
|
||||
m_unifier(m) {
|
||||
m_subst.reserve_offsets(1);
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Create the result clause. The literal at position j of \c cls in removed,
|
||||
and the substitution m_subst is applied to the resultant clause.
|
||||
*/
|
||||
clause * unary_inference::mk_result(clause * cls, unsigned j) {
|
||||
sbuffer<literal> new_literals;
|
||||
unsigned num = cls->get_num_literals();
|
||||
for (unsigned i = 0; i < num; i++) {
|
||||
if (i != j) {
|
||||
literal const & l = cls->get_literal(i);
|
||||
expr_ref new_atom(m_manager);
|
||||
m_subst.apply(l.atom(), new_atom);
|
||||
new_literals.push_back(literal(new_atom, l.sign()));
|
||||
}
|
||||
}
|
||||
|
||||
justification * js = mk_justification(cls->get_justification(), new_literals.size(), new_literals.c_ptr());
|
||||
clause * new_cls = clause::mk(m_manager, new_literals.size(), new_literals.c_ptr(), js, cls->get_scope_lvl());
|
||||
return new_cls;
|
||||
}
|
||||
|
||||
};
|
48
src/dead/spc/spc_unary_inference.h
Normal file
48
src/dead/spc/spc_unary_inference.h
Normal file
|
@ -0,0 +1,48 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
spc_unary_inference.h
|
||||
|
||||
Abstract:
|
||||
|
||||
<abstract>
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2008-02-14.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _SPC_UNARY_INFERENCE_H_
|
||||
#define _SPC_UNARY_INFERENCE_H_
|
||||
|
||||
#include"spc_clause.h"
|
||||
#include"unifier.h"
|
||||
|
||||
namespace spc {
|
||||
|
||||
/**
|
||||
\brief Superclass for eq_resolution and factoring.
|
||||
*/
|
||||
class unary_inference {
|
||||
protected:
|
||||
ast_manager & m_manager;
|
||||
order & m_order;
|
||||
substitution m_subst;
|
||||
unifier m_unifier;
|
||||
|
||||
clause * mk_result(clause * cls, unsigned j);
|
||||
virtual justification * mk_justification(justification * parent, unsigned num_lits, literal * new_lits) = 0;
|
||||
public:
|
||||
unary_inference(ast_manager & m, order & ord);
|
||||
virtual ~unary_inference() {}
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif /* _SPC_UNARY_INFERENCE_H_ */
|
||||
|
180
src/dead/spc/splay_tree.h
Normal file
180
src/dead/spc/splay_tree.h
Normal file
|
@ -0,0 +1,180 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
splay_tree.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Splay trees
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2008-01-31.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _SPLAY_TREE_H_
|
||||
#define _SPLAY_TREE_H_
|
||||
|
||||
#include"util.h"
|
||||
#include"buffer.h"
|
||||
|
||||
template<typename Key, typename Compare>
|
||||
class splay_tree : private Compare {
|
||||
struct cell {
|
||||
Key m_key;
|
||||
cell * m_left;
|
||||
cell * m_right;
|
||||
|
||||
cell():m_left(0), m_right(0) {}
|
||||
cell(Key const & k, cell * l = 0, cell * r = 0):
|
||||
m_key(k), m_left(l), m_right(r) {}
|
||||
};
|
||||
|
||||
cell * m_root;
|
||||
int compare(Key const & k1, Key const & k2) const { return Compare::operator()(k1, k2); }
|
||||
cell * splay(cell * c, Key const & k);
|
||||
|
||||
void display_core(std::ostream & out, cell * c) const {
|
||||
if (c) {
|
||||
out << "(" << c->m_key << " ";
|
||||
display_core(out, c->m_left);
|
||||
out << " ";
|
||||
display_core(out, c->m_right);
|
||||
out << ")";
|
||||
}
|
||||
else
|
||||
out << "null";
|
||||
}
|
||||
|
||||
public:
|
||||
splay_tree(Compare const & c = Compare()):
|
||||
Compare(c),
|
||||
m_root(0) {}
|
||||
|
||||
~splay_tree() {
|
||||
m_root = 0;
|
||||
}
|
||||
|
||||
void insert(Key const & k);
|
||||
|
||||
bool find(Key const & k, Key & r) const;
|
||||
|
||||
void erase(Key const & k);
|
||||
|
||||
void reset();
|
||||
|
||||
bool empty() const { return m_root == 0; }
|
||||
|
||||
bool singleton() const { return m_root != 0 && m_root->m_left == 0 && m_root->m_right == 0; }
|
||||
|
||||
/**
|
||||
\brief Visit nodes in the splay tree in ascending order.
|
||||
The Visitor functor should provide the following methods:
|
||||
|
||||
- bool visit_left(Key const & k)
|
||||
return true if the left child should be visited
|
||||
|
||||
- bool visit_right(Key const & k)
|
||||
return true if the right child should be visited
|
||||
|
||||
- void operator()(Key const & k)
|
||||
do something with the key.
|
||||
*/
|
||||
template<typename Visitor>
|
||||
void visit_core(Visitor & v) {
|
||||
typedef std::pair<cell *, bool> entry;
|
||||
if (m_root) {
|
||||
buffer<entry> todo;
|
||||
todo.push_back(entry(m_root, false));
|
||||
while (!todo.empty()) {
|
||||
entry & curr = todo.back();
|
||||
cell * c = curr.first;
|
||||
if (!curr.second) {
|
||||
curr.second = true;
|
||||
if (c->m_left && v.visit_left(c->m_key))
|
||||
todo.push_back(entry(c->m_left, false));
|
||||
}
|
||||
else {
|
||||
v(c->m_key);
|
||||
todo.pop_back();
|
||||
if (c->m_right && v.visit_right(c->m_key))
|
||||
todo.push_back(entry(c->m_right, false));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Visitor>
|
||||
struct all_visitor_wrapper {
|
||||
Visitor & m_visitor;
|
||||
all_visitor_wrapper(Visitor & v):m_visitor(v) {}
|
||||
bool visit_right(Key const & k) { return true; }
|
||||
bool visit_left(Key const & k) { return true; }
|
||||
void operator()(Key const & k) { m_visitor.operator()(k); }
|
||||
};
|
||||
|
||||
/**
|
||||
\brief Visit all nodes in the splay tree in ascending order.
|
||||
|
||||
- void operator()(Key const & k)
|
||||
do something with the key pair.
|
||||
*/
|
||||
template<typename Visitor>
|
||||
void visit(Visitor & v) {
|
||||
all_visitor_wrapper<Visitor> w(v);
|
||||
visit_core(w);
|
||||
}
|
||||
|
||||
template<typename Visitor, bool LE>
|
||||
struct visitor_wrapper {
|
||||
Visitor & m_visitor;
|
||||
splay_tree & m_tree;
|
||||
Key m_key;
|
||||
visitor_wrapper(Visitor & v, splay_tree & t, Key const & k):m_visitor(v), m_tree(t), m_key(k) {}
|
||||
bool visit_left(Key const & k) {
|
||||
return LE || m_tree.compare(k, m_key) > 0;
|
||||
}
|
||||
bool visit_right(Key const & k) {
|
||||
return !LE || m_tree.compare(k, m_key) < 0;
|
||||
}
|
||||
void operator()(Key const & k) {
|
||||
if ((LE && m_tree.compare(k, m_key) <= 0) ||
|
||||
(!LE && m_tree.compare(k, m_key) >= 0))
|
||||
m_visitor.operator()(k);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
\brief Visit all nodes with keys less than or equal to k.
|
||||
|
||||
- void operator()(Key const & k)
|
||||
do something with the key.
|
||||
*/
|
||||
template<typename Visitor>
|
||||
void visit_le(Visitor & v, Key const & k) {
|
||||
visitor_wrapper<Visitor, true> w(v, *this, k);
|
||||
visit_core(w);
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Visit all nodes with keys greater than or equal to k.
|
||||
|
||||
- void operator()(Key const & k)
|
||||
do something with the key.
|
||||
*/
|
||||
template<typename Visitor>
|
||||
void visit_ge(Visitor & v, Key const & k) {
|
||||
visitor_wrapper<Visitor, false> w(v, *this, k);
|
||||
visit_core(w);
|
||||
}
|
||||
|
||||
void display(std::ostream & out) const {
|
||||
display_core(out, m_root);
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
152
src/dead/spc/splay_tree_def.h
Normal file
152
src/dead/spc/splay_tree_def.h
Normal file
|
@ -0,0 +1,152 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
splay_tree_def.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Splay trees
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2008-01-31.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _SPLAY_TREE_DEF_H_
|
||||
#define _SPLAY_TREE_DEF_H_
|
||||
|
||||
#include"splay_tree.h"
|
||||
|
||||
template<typename Key, typename Compare>
|
||||
typename splay_tree<Key, Compare>::cell * splay_tree<Key, Compare>::splay(cell * root, Key const & k) {
|
||||
if (!root)
|
||||
return 0;
|
||||
|
||||
cell aux;
|
||||
cell * tmp;
|
||||
cell * left = &aux;
|
||||
cell * right = &aux;
|
||||
cell * t = root;
|
||||
|
||||
while (true) {
|
||||
int r = compare(k, t->m_key);
|
||||
if (r < 0) {
|
||||
if (!t->m_left)
|
||||
break;
|
||||
if (compare(k, t->m_left->m_key) < 0) {
|
||||
tmp = t->m_left;
|
||||
t->m_left = tmp->m_right;
|
||||
tmp->m_right = t;
|
||||
t = tmp;
|
||||
if (!t->m_left)
|
||||
break;
|
||||
}
|
||||
right->m_left = t;
|
||||
right = t;
|
||||
t = t->m_left;
|
||||
}
|
||||
else if (r > 0) {
|
||||
if (!t->m_right)
|
||||
break;
|
||||
if (compare(k, t->m_right->m_key) > 0) {
|
||||
tmp = t->m_right;
|
||||
t->m_right = tmp->m_left;
|
||||
tmp->m_left = t;
|
||||
t = tmp;
|
||||
if (!t->m_right)
|
||||
break;
|
||||
|
||||
}
|
||||
left->m_right = t;
|
||||
left = t;
|
||||
t = t->m_right;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
left->m_right = t->m_left;
|
||||
right->m_left = t->m_right;
|
||||
t->m_left = aux.m_right;
|
||||
t->m_right = aux.m_left;
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
template<typename Key, typename Compare>
|
||||
void splay_tree<Key, Compare>::insert(Key const & k) {
|
||||
if (!m_root)
|
||||
m_root = alloc(cell, k);
|
||||
else {
|
||||
m_root = splay(m_root, k);
|
||||
int r = compare(k, m_root->m_key);
|
||||
if (r < 0) {
|
||||
cell * new_cell = alloc(cell, k, m_root->m_left, m_root);
|
||||
m_root->m_left = 0;
|
||||
m_root = new_cell;
|
||||
}
|
||||
else if (r > 0) {
|
||||
cell * new_cell = alloc(cell, k, m_root, m_root->m_right);
|
||||
m_root->m_right = 0;
|
||||
m_root = new_cell;
|
||||
}
|
||||
else
|
||||
m_root->m_key = k;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Key, typename Compare>
|
||||
bool splay_tree<Key, Compare>::find(Key const & k, Key & r) const {
|
||||
if (m_root) {
|
||||
splay_tree<Key, Compare> * _this = const_cast<splay_tree<Key, Compare> *>(this);
|
||||
_this->m_root = _this->splay(m_root, k);
|
||||
if (compare(k, m_root->m_key) == 0) {
|
||||
r = m_root->m_key;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template<typename Key, typename Compare>
|
||||
void splay_tree<Key, Compare>::erase(Key const & k) {
|
||||
if (m_root) {
|
||||
m_root = splay(m_root, k);
|
||||
if (compare(k, m_root->m_key) == 0) {
|
||||
cell * to_delete = m_root;
|
||||
if (m_root->m_left) {
|
||||
cell * aux = splay(m_root->m_left, k);
|
||||
SASSERT(!aux->m_right);
|
||||
aux->m_right = m_root->m_right;
|
||||
m_root = aux;
|
||||
}
|
||||
else
|
||||
m_root = m_root->m_right;
|
||||
|
||||
dealloc(to_delete);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Key, typename Compare>
|
||||
void splay_tree<Key, Compare>::reset() {
|
||||
ptr_buffer<cell> todo;
|
||||
if (m_root)
|
||||
todo.push_back(m_root);
|
||||
while (!todo.empty()) {
|
||||
cell * c = todo.back();
|
||||
todo.pop_back();
|
||||
if (c->m_left)
|
||||
todo.push_back(c->m_left);
|
||||
if (c->m_right)
|
||||
todo.push_back(c->m_right);
|
||||
dealloc(c);
|
||||
}
|
||||
m_root = 0;
|
||||
}
|
||||
|
||||
#endif /* _SPLAY_TREE_DEF_H_ */
|
114
src/dead/spc/splay_tree_map.h
Normal file
114
src/dead/spc/splay_tree_map.h
Normal file
|
@ -0,0 +1,114 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
splay_tree_map.h
|
||||
|
||||
Abstract:
|
||||
|
||||
A mapping as a splay tree.
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2008-02-02.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _SPLAY_TREE_MAP_H_
|
||||
#define _SPLAY_TREE_MAP_H_
|
||||
|
||||
#include"splay_tree.h"
|
||||
|
||||
template<typename Key, typename Data, typename Compare>
|
||||
class splay_tree_map {
|
||||
typedef std::pair<Key, Data> entry;
|
||||
|
||||
struct entry_compare : private Compare {
|
||||
entry_compare(Compare const & c):Compare(c) {}
|
||||
int operator()(entry const & e1, entry const & e2) const {
|
||||
return Compare::operator()(e1.first, e2.first);
|
||||
}
|
||||
};
|
||||
|
||||
typedef splay_tree<entry, entry_compare> tree;
|
||||
|
||||
tree m_tree;
|
||||
|
||||
template<typename Visitor>
|
||||
struct core_visitor_wrapper {
|
||||
Visitor & m_visitor;
|
||||
core_visitor_wrapper(Visitor & v):m_visitor(v) {}
|
||||
bool visit_right(entry const & k) { return m_visitor.visit_right(k.first); }
|
||||
bool visit_left(entry const & k) { return m_visitor.visit_left(k.first); }
|
||||
void operator()(entry const & k) { m_visitor.operator()(k.first, k.second); }
|
||||
};
|
||||
|
||||
template<typename Visitor>
|
||||
struct visitor_wrapper {
|
||||
Visitor & m_visitor;
|
||||
visitor_wrapper(Visitor & v):m_visitor(v) {}
|
||||
void operator()(entry const & k) { m_visitor.operator()(k.first, k.second); }
|
||||
};
|
||||
|
||||
public:
|
||||
splay_tree_map(Compare const & c = Compare()):
|
||||
m_tree(entry_compare(c)) {}
|
||||
|
||||
void insert(Key const & k, Data const & d) {
|
||||
m_tree.insert(entry(k, d));
|
||||
}
|
||||
|
||||
bool find(Key const & k, Data & r) const {
|
||||
entry e(k, r);
|
||||
if (m_tree.find(e, e)) {
|
||||
r = e.second;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void erase(Key const & k) {
|
||||
entry e;
|
||||
e.first = k;
|
||||
m_tree.erase(e);
|
||||
}
|
||||
|
||||
void reset() { m_tree.reset(); }
|
||||
|
||||
bool empty() const { return m_tree.empty(); }
|
||||
|
||||
void display(std::ostream & out) const { m_tree.display(out); }
|
||||
|
||||
template<typename Visitor>
|
||||
void visit_core(Visitor & v) {
|
||||
core_visitor_wrapper<Visitor> w(v);
|
||||
m_tree.visit_core(w);
|
||||
}
|
||||
|
||||
template<typename Visitor>
|
||||
void visit(Visitor & v) {
|
||||
visitor_wrapper<Visitor> w(v);
|
||||
m_tree.visit(w);
|
||||
}
|
||||
|
||||
template<typename Visitor>
|
||||
void visit_le(Visitor & v, Key const & k) {
|
||||
visitor_wrapper<Visitor> w(v);
|
||||
entry e;
|
||||
e.first = k;
|
||||
m_tree.visit_le(w, e);
|
||||
}
|
||||
|
||||
template<typename Visitor>
|
||||
void visit_ge(Visitor & v, Key const & k) {
|
||||
visitor_wrapper<Visitor> w(v);
|
||||
entry e;
|
||||
e.first = k;
|
||||
m_tree.visit_ge(w, e);
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* _SPLAY_TREE_MAP_H_ */
|
||||
|
90
src/dead/spc/use_list.cpp
Normal file
90
src/dead/spc/use_list.cpp
Normal file
|
@ -0,0 +1,90 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
use_list.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
Use list term index.
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2008-02-04.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#include"use_list.h"
|
||||
|
||||
void app_use_list::inc_ref(app * n) {
|
||||
if (n->get_num_args() == 0)
|
||||
return; // ignore constants
|
||||
unsigned id = n->get_id();
|
||||
unsigned c = m_ref_counter.get(id, 0);
|
||||
m_ref_counter.setx(id, c+1, 0);
|
||||
if (c == 0)
|
||||
m_todo.push_back(n);
|
||||
}
|
||||
|
||||
void app_use_list::dec_ref(app * n) {
|
||||
if (n->get_num_args() == 0)
|
||||
return; // ignore constants
|
||||
unsigned id = n->get_id();
|
||||
SASSERT(m_ref_counter[id] > 0);
|
||||
m_ref_counter[id]--;
|
||||
if (m_ref_counter[id] == 0)
|
||||
m_todo.push_back(n);
|
||||
}
|
||||
|
||||
void app_use_list::insert(expr * n) {
|
||||
if (is_var(n))
|
||||
return; // nothing to index
|
||||
SASSERT(m_todo.empty());
|
||||
inc_ref(to_app(n));
|
||||
while (!m_todo.empty()) {
|
||||
app * n = m_todo.back();
|
||||
unsigned num_args = n->get_num_args();
|
||||
for (unsigned i = 0; i < num_args; i++) {
|
||||
expr * c = n->get_arg(i);
|
||||
if (is_var(c)) {
|
||||
if (!m_ignore_vars)
|
||||
use_list<app*>::insert(n, c);
|
||||
}
|
||||
else {
|
||||
SASSERT(is_app(c));
|
||||
use_list<app*>::insert(n, c);
|
||||
inc_ref(to_app(c));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void app_use_list::erase(expr * n) {
|
||||
if (is_var(n))
|
||||
return; // nothing to index
|
||||
SASSERT(m_todo.empty());
|
||||
dec_ref(to_app(n));
|
||||
while (!m_todo.empty()) {
|
||||
app * n = m_todo.back();
|
||||
unsigned num_args = n->get_num_args();
|
||||
for (unsigned i = 0; i < num_args; i++) {
|
||||
expr * c = n->get_arg(i);
|
||||
if (is_var(c)) {
|
||||
if (!m_ignore_vars)
|
||||
use_list<app*>::erase(n, c);
|
||||
}
|
||||
else {
|
||||
SASSERT(is_app(c));
|
||||
use_list<app*>::erase(n, c);
|
||||
dec_ref(to_app(c));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void app_use_list::reset() {
|
||||
use_list<app*>::reset();
|
||||
m_ref_counter.reset();
|
||||
}
|
120
src/dead/spc/use_list.h
Normal file
120
src/dead/spc/use_list.h
Normal file
|
@ -0,0 +1,120 @@
|
|||
/*++
|
||||
Copyright (c) 2006 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
use_list.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Use list expression index.
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo de Moura (leonardo) 2008-02-04.
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
#ifndef _USE_LIST_H_
|
||||
#define _USE_LIST_H_
|
||||
|
||||
#include"ast.h"
|
||||
#include"vector.h"
|
||||
|
||||
/**
|
||||
\brief Generic use-list data-structure.
|
||||
*/
|
||||
template<typename T>
|
||||
class use_list {
|
||||
typedef vector<T> set;
|
||||
vector<set> m_use_list;
|
||||
public:
|
||||
typedef typename set::const_iterator iterator;
|
||||
use_list() {}
|
||||
|
||||
void insert(T const & parent, expr * child) {
|
||||
unsigned id = child->get_id();
|
||||
if (id >= m_use_list.size())
|
||||
m_use_list.resize(id+1, set());
|
||||
set & s = m_use_list[id];
|
||||
s.push_back(parent);
|
||||
}
|
||||
|
||||
void erase(T const & parent, expr * child) {
|
||||
unsigned id = child->get_id();
|
||||
if (id >= m_use_list.size())
|
||||
return;
|
||||
set & s = m_use_list[id];
|
||||
s.erase(parent);
|
||||
}
|
||||
|
||||
void reset() {
|
||||
m_use_list.reset();
|
||||
}
|
||||
|
||||
iterator begin(expr * e) const {
|
||||
unsigned id = e->get_id();
|
||||
if (id >= m_use_list.size())
|
||||
return 0;
|
||||
return m_use_list[id].begin();
|
||||
}
|
||||
|
||||
iterator end(expr * e) const {
|
||||
unsigned id = e->get_id();
|
||||
if (id >= m_use_list.size())
|
||||
return 0;
|
||||
return m_use_list[id].end();
|
||||
}
|
||||
|
||||
bool empty(expr * e) const {
|
||||
unsigned id = e->get_id();
|
||||
if (id >= m_use_list.size())
|
||||
return true;
|
||||
return m_use_list[id].empty();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
\brief Index for tracking the uses of an expression. It is a
|
||||
mapping from expressions to expressions. For example, consider the
|
||||
term (f a (g a)), the constant a is used by f and g applications.
|
||||
|
||||
\remark The expressions inserted in this index should not contain
|
||||
quantifiers.
|
||||
|
||||
\warning This index will not increase the reference counter of the
|
||||
indexed expressions.
|
||||
*/
|
||||
class app_use_list : use_list<app*> {
|
||||
|
||||
bool m_ignore_vars; //!< when true, variables are not indexed
|
||||
unsigned_vector m_ref_counter;
|
||||
ptr_vector<app> m_todo;
|
||||
|
||||
void inc_ref(app * n);
|
||||
void dec_ref(app * n);
|
||||
|
||||
public:
|
||||
/**
|
||||
\brief If ignore_vars = true, then the index will not track
|
||||
the use of variables.
|
||||
*/
|
||||
app_use_list(bool ignore_vars = true):
|
||||
m_ignore_vars(ignore_vars) {
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Update the use list of all direct/indirect children of n.
|
||||
*/
|
||||
void insert(expr * n);
|
||||
|
||||
/**
|
||||
\brief Remove n (and its unreachable direct/indirect children) from the index.
|
||||
*/
|
||||
void erase(expr * n);
|
||||
|
||||
void reset();
|
||||
};
|
||||
|
||||
#endif /* _USE_LIST_H_ */
|
Loading…
Add table
Add a link
Reference in a new issue