3
0
Fork 0
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:
Leonardo de Moura 2012-10-24 14:47:40 -07:00
parent 61bd5a69ec
commit 12a255e36b
195 changed files with 11 additions and 526 deletions

2
src/dead/spc/README Normal file
View file

@ -0,0 +1,2 @@
Superposition Calculus.
This module is currently disabled.

214
src/dead/spc/fvi.h Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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_ */

View 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;
}

View 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
View 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
View 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
View 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
View 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_ */

View 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);
}
}
}

View 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_ */

View 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_ */

View 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;
}
};

View 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
View 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
View 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_ */

View 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_ */

View 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;
}
};

View 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_ */

View 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
View 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_ */

View 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;
}
}

View 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
View 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
View 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_ */

View 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));
}
}
}
}
};

View 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_ */

View 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);
}
}
};

View 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_ */

View 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);
}
};

View 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_ */

View 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
View 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_ */

View 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);
}
};

View 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
View 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
View 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_ */

View 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
View 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_ */

View 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;
}
};

View 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_ */

View 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";
}
};

View 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_ */

View 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);
}
}
};

View 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_ */

View 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();
}
}
}
};

View 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_ */

View 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;
}
};

View 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
View 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

View 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_ */

View 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
View 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
View 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_ */