3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-04-22 16:45: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-20 22:03:58 -07:00
parent 2b8fb6c718
commit 492484c5aa
125 changed files with 632 additions and 390 deletions

View file

@ -1,430 +0,0 @@
/*++
Copyright (c) 2011 Microsoft Corporation
Module Name:
assertion_set.cpp
Abstract:
Assertion set.
Author:
Leonardo de Moura (leonardo) 2011-04-20
Revision History:
--*/
#include"assertion_set.h"
#include"cmd_context.h"
#include"ast_ll_pp.h"
#include"ast_smt2_pp.h"
#include"for_each_expr.h"
void assertion_set::copy(assertion_set & target) const {
if (this == &target)
return;
m().copy(m_forms, target.m_forms);
m().copy(m_proofs, target.m_proofs);
target.m_inconsistent = m_inconsistent;
}
void assertion_set::push_back(expr * f, proof * pr) {
if (m().is_true(f))
return;
if (m().is_false(f)) {
m().del(m_forms);
m().del(m_proofs);
m_inconsistent = true;
}
else {
SASSERT(!m_inconsistent);
}
m().push_back(m_forms, f);
if (m().proofs_enabled())
m().push_back(m_proofs, pr);
}
void assertion_set::quick_process(bool save_first, expr * & f) {
if (!m().is_and(f) && !(m().is_not(f) && m().is_or(to_app(f)->get_arg(0)))) {
if (!save_first) {
push_back(f, 0);
}
return;
}
typedef std::pair<expr *, bool> expr_pol;
sbuffer<expr_pol, 64> todo;
todo.push_back(expr_pol(f, true));
while (!todo.empty()) {
if (m_inconsistent)
return;
expr_pol p = todo.back();
expr * curr = p.first;
bool pol = p.second;
todo.pop_back();
if (pol && m().is_and(curr)) {
app * t = to_app(curr);
unsigned i = t->get_num_args();
while (i > 0) {
--i;
todo.push_back(expr_pol(t->get_arg(i), true));
}
}
else if (!pol && m().is_or(curr)) {
app * t = to_app(curr);
unsigned i = t->get_num_args();
while (i > 0) {
--i;
todo.push_back(expr_pol(t->get_arg(i), false));
}
}
else if (m().is_not(curr)) {
todo.push_back(expr_pol(to_app(curr)->get_arg(0), !pol));
}
else {
if (!pol)
curr = m().mk_not(curr);
if (save_first) {
f = curr;
save_first = false;
}
else {
push_back(curr, 0);
}
}
}
}
void assertion_set::process_and(bool save_first, app * f, proof * pr, expr_ref & out_f, proof_ref & out_pr) {
unsigned num = f->get_num_args();
for (unsigned i = 0; i < num; i++) {
if (m_inconsistent)
return;
slow_process(save_first && i == 0, f->get_arg(i), m().mk_and_elim(pr, i), out_f, out_pr);
}
}
void assertion_set::process_not_or(bool save_first, app * f, proof * pr, expr_ref & out_f, proof_ref & out_pr) {
unsigned num = f->get_num_args();
for (unsigned i = 0; i < num; i++) {
if (m_inconsistent)
return;
expr * child = f->get_arg(i);
if (m().is_not(child)) {
expr * not_child = to_app(child)->get_arg(0);
slow_process(save_first && i == 0, not_child, m().mk_not_or_elim(pr, i), out_f, out_pr);
}
else {
expr_ref not_child(m());
not_child = m().mk_not(child);
slow_process(save_first && i == 0, not_child, m().mk_not_or_elim(pr, i), out_f, out_pr);
}
}
}
void assertion_set::slow_process(bool save_first, expr * f, proof * pr, expr_ref & out_f, proof_ref & out_pr) {
if (m().is_and(f))
process_and(save_first, to_app(f), pr, out_f, out_pr);
else if (m().is_not(f) && m().is_or(to_app(f)->get_arg(0)))
process_not_or(save_first, to_app(to_app(f)->get_arg(0)), pr, out_f, out_pr);
else if (save_first) {
out_f = f;
out_pr = pr;
}
else {
push_back(f, pr);
}
}
void assertion_set::slow_process(expr * f, proof * pr) {
expr_ref out_f(m());
proof_ref out_pr(m());
slow_process(false, f, pr, out_f, out_pr);
}
void assertion_set::assert_expr(expr * f, proof * pr) {
SASSERT(m().proofs_enabled() == (pr != 0 && !m().is_undef_proof(pr)));
if (m_inconsistent)
return;
if (m().proofs_enabled())
slow_process(f, pr);
else
quick_process(false, f);
}
void assertion_set::update(unsigned i, expr * f, proof * pr) {
SASSERT(m().proofs_enabled() == (pr != 0 && !m().is_undef_proof(pr)));
if (m_inconsistent)
return;
if (m().proofs_enabled()) {
expr_ref out_f(m());
proof_ref out_pr(m());
slow_process(true, f, pr, out_f, out_pr);
if (!m_inconsistent) {
if (m().is_false(out_f)) {
push_back(out_f, out_pr);
}
else {
m().set(m_forms, i, out_f);
m().set(m_proofs, i, out_pr);
}
}
}
else {
quick_process(true, f);
if (!m_inconsistent) {
if (m().is_false(f))
push_back(f, 0);
else
m().set(m_forms, i, f);
}
}
}
void assertion_set::reset() {
m().del(m_forms);
m().del(m_proofs);
m_inconsistent = false;
}
void assertion_set::display(cmd_context & ctx, std::ostream & out) const {
out << "(assertion-set";
unsigned sz = size();
for (unsigned i = 0; i < sz; i++) {
out << "\n ";
ctx.display(out, form(i), 2);
}
out << ")" << std::endl;
}
void assertion_set::display(cmd_context & ctx) const {
display(ctx, ctx.regular_stream());
}
void assertion_set::display(std::ostream & out) const {
out << "(assertion-set";
unsigned sz = size();
for (unsigned i = 0; i < sz; i++) {
out << "\n ";
out << mk_ismt2_pp(form(i), m(), 2);
}
out << ")" << std::endl;
}
void assertion_set::display_as_and(std::ostream & out) const {
ptr_buffer<expr> args;
unsigned sz = size();
for (unsigned i = 0; i < sz; i++)
args.push_back(form(i));
expr_ref tmp(m());
tmp = m().mk_and(args.size(), args.c_ptr());
out << mk_ismt2_pp(tmp, m()) << "\n";
}
void assertion_set::display_ll(std::ostream & out) const {
unsigned sz = size();
for (unsigned i = 0; i < sz; i++) {
out << mk_ll_pp(form(i), m()) << "\n";
}
}
/**
\brief Assumes that the formula is already in CNF.
*/
void assertion_set::display_dimacs(std::ostream & out) const {
obj_map<expr, unsigned> expr2var;
unsigned num_vars = 0;
unsigned num_cls = size();
for (unsigned i = 0; i < num_cls; i++) {
expr * f = form(i);
unsigned num_lits;
expr * const * lits;
if (m().is_or(f)) {
num_lits = to_app(f)->get_num_args();
lits = to_app(f)->get_args();
}
else {
num_lits = 1;
lits = &f;
}
for (unsigned j = 0; j < num_lits; j++) {
expr * l = lits[j];
if (m().is_not(l))
l = to_app(l)->get_arg(0);
if (expr2var.contains(l))
continue;
num_vars++;
expr2var.insert(l, num_vars);
}
}
out << "p cnf " << num_vars << " " << num_cls << "\n";
for (unsigned i = 0; i < num_cls; i++) {
expr * f = form(i);
unsigned num_lits;
expr * const * lits;
if (m().is_or(f)) {
num_lits = to_app(f)->get_num_args();
lits = to_app(f)->get_args();
}
else {
num_lits = 1;
lits = &f;
}
for (unsigned j = 0; j < num_lits; j++) {
expr * l = lits[j];
if (m().is_not(l)) {
out << "-";
l = to_app(l)->get_arg(0);
}
unsigned id = UINT_MAX;
expr2var.find(l, id);
SASSERT(id != UINT_MAX);
out << id << " ";
}
out << "0\n";
}
}
unsigned assertion_set::num_exprs() const {
expr_fast_mark1 visited;
unsigned sz = size();
unsigned r = 0;
for (unsigned i = 0; i < sz; i++) {
r += get_num_exprs(form(i), visited);
}
return r;
}
/**
\brief Eliminate true formulas.
*/
void assertion_set::elim_true() {
unsigned sz = size();
unsigned j = 0;
for (unsigned i = 0; i < sz; i++) {
expr * f = form(i);
if (m().is_true(f))
continue;
if (i == j) {
j++;
continue;
}
m().set(m_forms, j, f);
if (m().proofs_enabled())
m().set(m_proofs, j, m().get(m_proofs, i));
j++;
}
for (; j < sz; j++) {
m().pop_back(m_forms);
if (m().proofs_enabled())
m().pop_back(m_proofs);
}
}
void assertion_set::elim_redundancies() {
if (inconsistent())
return;
expr_ref_fast_mark1 neg_lits(m());
expr_ref_fast_mark2 pos_lits(m());
unsigned sz = size();
unsigned j = 0;
for (unsigned i = 0; i < sz; i++) {
expr * f = form(i);
if (m().is_true(f))
continue;
if (m().is_not(f)) {
expr * atom = to_app(f)->get_arg(0);
if (neg_lits.is_marked(atom))
continue;
if (pos_lits.is_marked(atom)) {
proof * p = 0;
if (m().proofs_enabled()) {
proof * pr1 = 0;
proof * pr2 = pr(i);
for (unsigned j = 0; j < i; j++) {
if (form(j) == atom) {
pr1 = pr(j);
break;
}
}
SASSERT(pr1);
proof * prs[2] = { pr1, pr2 };
p = m().mk_unit_resolution(2, prs);
}
push_back(m().mk_false(), p);
return;
}
neg_lits.mark(atom);
}
else {
if (pos_lits.is_marked(f))
continue;
if (neg_lits.is_marked(f)) {
proof * p = 0;
if (m().proofs_enabled()) {
proof * pr1 = 0;
proof * pr2 = pr(i);
for (unsigned j = 0; j < i; j++) {
expr * curr = form(j);
expr * atom;
if (m().is_not(curr, atom) && atom == f) {
pr1 = pr(j);
break;
}
}
SASSERT(pr1);
proof * prs[2] = { pr1, pr2 };
p = m().mk_unit_resolution(2, prs);
}
push_back(m().mk_false(), p);
return;
}
pos_lits.mark(f);
}
if (i == j) {
j++;
continue;
}
m().set(m_forms, j, f);
if (m().proofs_enabled())
m().set(m_proofs, j, pr(i));
j++;
}
for (; j < sz; j++) {
m().pop_back(m_forms);
if (m().proofs_enabled())
m().pop_back(m_proofs);
}
}
/**
\brief Assert expressions from ctx into t.
*/
void assert_exprs_from(cmd_context const & ctx, assertion_set & t) {
ptr_vector<expr>::const_iterator it = ctx.begin_assertions();
ptr_vector<expr>::const_iterator end = ctx.end_assertions();
for (; it != end; ++it) {
t.assert_expr(*it);
}
}
/**
\brief Translate the assertion set to a new one that uses a different ast_manager.
*/
assertion_set * assertion_set::translate(ast_translation & translator) const {
ast_manager & m_to = translator.to();
assertion_set * res = alloc(assertion_set, m_to);
unsigned sz = m().size(m_forms);
for (unsigned i = 0; i < sz; i++) {
res->m().push_back(res->m_forms, translator(m().get(m_forms, i)));
if (m_to.proofs_enabled())
res->m().push_back(res->m_proofs, translator(m().get(m_proofs, i)));
}
res->m_inconsistent = m_inconsistent;
return res;
}

View file

@ -1,98 +0,0 @@
/*++
Copyright (c) 2011 Microsoft Corporation
Module Name:
assertion_set.h
Abstract:
Assertion set.
Author:
Leonardo de Moura (leonardo) 2011-04-20
Revision History:
--*/
#ifndef _ASSERTION_SET_H_
#define _ASSERTION_SET_H_
#include"ast.h"
#include"ast_translation.h"
#include"for_each_expr.h"
class cmd_context;
class assertion_set {
ast_manager & m_manager;
bool m_inconsistent;
expr_array m_forms;
expr_array m_proofs;
void push_back(expr * f, proof * pr);
void quick_process(bool save_first, expr * & f);
void process_and(bool save_first, app * f, proof * pr, expr_ref & out_f, proof_ref & out_pr);
void process_not_or(bool save_first, app * f, proof * pr, expr_ref & out_f, proof_ref & out_pr);
void slow_process(bool save_first, expr * f, proof * pr, expr_ref & out_f, proof_ref & out_pr);
void slow_process(expr * f, proof * pr);
public:
assertion_set(ast_manager & m):m_manager(m), m_inconsistent(false) {}
~assertion_set() { reset(); }
ast_manager & m() const { return m_manager; }
bool inconsistent() const { return m_inconsistent; }
void reset();
void copy(assertion_set & target) const;
void assert_expr(expr * f, proof * pr);
void assert_expr(expr * f) {
assert_expr(f, m().mk_asserted(f));
}
unsigned size() const { return m().size(m_forms); }
unsigned num_exprs() const;
expr * form(unsigned i) const { return m().get(m_forms, i); }
proof * pr(unsigned i) const { return m().proofs_enabled() ? static_cast<proof*>(m().get(m_proofs, i)) : 0; }
void update(unsigned i, expr * f, proof * pr = 0);
void elim_true();
void elim_redundancies();
void display(cmd_context & ctx, std::ostream & out) const;
void display(cmd_context & ctx) const;
void display(std::ostream & out) const;
void display_ll(std::ostream & out) const;
void display_as_and(std::ostream & out) const;
void display_dimacs(std::ostream & out) const;
assertion_set * translate(ast_translation & translator) const;
};
void assert_exprs_from(cmd_context const & ctx, assertion_set & t);
template<typename ForEachProc>
void for_each_expr_as(ForEachProc& proc, assertion_set const& s) {
expr_mark visited;
for (unsigned i = 0; i < s.size(); ++i) {
for_each_expr(proc, visited, s.form(i));
}
}
#endif

View file

@ -1,122 +0,0 @@
/*++
Copyright (c) 2011 Microsoft Corporation
Module Name:
assertion_set_rewriter.cpp
Abstract:
Apply rewriting rules in an assertion set.
Author:
Leonardo (leonardo) 2011-04-27
Notes:
--*/
#include"assertion_set_rewriter.h"
#include"th_rewriter.h"
#include"ast_smt2_pp.h"
#include"assertion_set_util.h"
struct assertion_set_rewriter::imp {
ast_manager & m_manager;
th_rewriter m_r;
unsigned m_num_steps;
imp(ast_manager & m, params_ref const & p):
m_manager(m),
m_r(m, p),
m_num_steps(0) {
}
ast_manager & m() const { return m_manager; }
void set_cancel(bool f) {
m_r.set_cancel(f);
}
void reset() {
m_r.reset();
m_num_steps = 0;
}
void operator()(assertion_set & s) {
SASSERT(is_well_sorted(s));
as_st_report report("simplifier", s);
TRACE("before_simplifier", s.display(tout););
m_num_steps = 0;
if (s.inconsistent())
return;
expr_ref new_curr(m());
proof_ref new_pr(m());
unsigned size = s.size();
for (unsigned idx = 0; idx < size; idx++) {
if (s.inconsistent())
break;
expr * curr = s.form(idx);
m_r(curr, new_curr, new_pr);
m_num_steps += m_r.get_num_steps();
if (m().proofs_enabled()) {
proof * pr = s.pr(idx);
new_pr = m().mk_modus_ponens(pr, new_pr);
}
s.update(idx, new_curr, new_pr);
}
TRACE("after_simplifier_bug", s.display(tout););
s.elim_redundancies();
TRACE("after_simplifier", s.display(tout););
SASSERT(is_well_sorted(s));
}
unsigned get_num_steps() const { return m_num_steps; }
};
assertion_set_rewriter::assertion_set_rewriter(ast_manager & m, params_ref const & p):
m_params(p) {
m_imp = alloc(imp, m, p);
}
assertion_set_rewriter::~assertion_set_rewriter() {
dealloc(m_imp);
}
void assertion_set_rewriter::updt_params(params_ref const & p) {
m_params = p;
m_imp->m_r.updt_params(p);
}
void assertion_set_rewriter::get_param_descrs(param_descrs & r) {
th_rewriter::get_param_descrs(r);
}
void assertion_set_rewriter::operator()(assertion_set & s) {
m_imp->operator()(s);
}
void assertion_set_rewriter::set_cancel(bool f) {
if (m_imp)
m_imp->set_cancel(f);
}
void assertion_set_rewriter::cleanup() {
ast_manager & m = m_imp->m();
imp * d = m_imp;
#pragma omp critical (as_st_cancel)
{
m_imp = 0;
}
dealloc(d);
d = alloc(imp, m, m_params);
#pragma omp critical (as_st_cancel)
{
m_imp = d;
}
}
unsigned assertion_set_rewriter::get_num_steps() const {
return m_imp->get_num_steps();
}

View file

@ -1,56 +0,0 @@
/*++
Copyright (c) 2011 Microsoft Corporation
Module Name:
assertion_set_rewriter.h
Abstract:
Apply rewriting rules in an assertion set.
Author:
Leonardo (leonardo) 2011-04-22
Notes:
--*/
#ifndef _ASSERTION_SET_REWRITER_H_
#define _ASSERTION_SET_REWRITER_H_
#include"assertion_set_strategy.h"
class assertion_set_rewriter : public assertion_set_strategy {
struct imp;
imp * m_imp;
params_ref m_params;
public:
assertion_set_rewriter(ast_manager & m, params_ref const & ref = params_ref());
virtual ~assertion_set_rewriter();
virtual void updt_params(params_ref const & p);
static void get_param_descrs(param_descrs & r);
virtual void collect_param_descrs(param_descrs & r) { get_param_descrs(r); }
/**
\brief Apply rewriting/simplification rules on the assertion set \c s.
*/
void operator()(assertion_set & s);
virtual void operator()(assertion_set & s, model_converter_ref & mc) {
operator()(s);
mc = 0;
}
virtual void cleanup();
unsigned get_num_steps() const;
virtual void set_cancel(bool f);
};
inline as_st * mk_simplifier(ast_manager & m, params_ref const & p = params_ref()) {
return clean(alloc(assertion_set_rewriter, m, p));
}
#endif

File diff suppressed because it is too large Load diff

View file

@ -1,228 +0,0 @@
/*++
Copyright (c) 2011 Microsoft Corporation
Module Name:
assertion_set_strategy.h
Abstract:
Abstract strategy for assertion sets, and simple combinators.
Author:
Leonardo (leonardo) 2011-05-17
Notes:
--*/
#ifndef _AS_STRATEGY_H_
#define _AS_STRATEGY_H_
#include"params.h"
#include"assertion_set.h"
#include"model_converter.h"
#include"statistics.h"
#include"strategy_exception.h"
#include"lbool.h"
#include"assertion_set_util.h"
struct front_end_params;
class progress_callback;
// minimum verbosity level for strategies
#define ST_VERBOSITY_LVL 10
class as_st_report {
struct imp;
imp * m_imp;
public:
as_st_report(char const * id, assertion_set & s);
~as_st_report();
};
void report_st_progress(char const * id, unsigned val);
/**
\brief Abstract assertion-set strategy.
*/
class assertion_set_strategy {
unsigned m_ref_count;
public:
assertion_set_strategy():m_ref_count(0) {}
virtual ~assertion_set_strategy() {}
void inc_ref() { m_ref_count++; }
void dec_ref() { SASSERT(m_ref_count > 0); m_ref_count--; if (m_ref_count == 0) dealloc(this); }
virtual void updt_params(params_ref const & p) {}
virtual void collect_param_descrs(param_descrs & r) {}
void cancel();
void reset_cancel();
virtual void set_cancel(bool f) {}
virtual void operator()(assertion_set & s, model_converter_ref & mc) = 0;
virtual void collect_statistics(statistics & st) const {}
virtual void reset_statistics() {}
virtual void cleanup() = 0;
virtual void reset() { cleanup(); }
// for backward compatibility
virtual void set_front_end_params(front_end_params & p) {}
virtual void set_logic(symbol const & l) {}
virtual void set_progress_callback(progress_callback * callback) {}
};
bool is_equal(assertion_set const & s1, assertion_set const & s2);
// dummy for using ref_vector
struct assertion_set_strategy_context {
static void inc_ref(assertion_set_strategy * st) { st->inc_ref(); }
static void dec_ref(assertion_set_strategy * st) { st->dec_ref(); }
};
typedef assertion_set_strategy as_st;
typedef assertion_set_strategy_context as_st_ctx;
typedef ref<as_st> as_st_ref;
typedef ref_vector<as_st, as_st_ctx> as_st_ref_vector;
typedef ref_buffer<as_st, as_st_ctx> as_st_ref_buffer;
as_st * and_then(unsigned num, as_st * const * sts);
as_st * and_then(as_st * st1, as_st * st2);
as_st * and_then(as_st * st1, as_st * st2, as_st * st3);
as_st * and_then(as_st * st1, as_st * st2, as_st * st3, as_st * st4);
as_st * and_then(as_st * st1, as_st * st2, as_st * st3, as_st * st4, as_st * st5);
as_st * and_then(as_st * st1, as_st * st2, as_st * st3, as_st * st4, as_st * st5, as_st * st6);
as_st * and_then(as_st * st1, as_st * st2, as_st * st3, as_st * st4, as_st * st5, as_st * st6, as_st * st7);
as_st * and_then(as_st * st1, as_st * st2, as_st * st3, as_st * st4, as_st * st5, as_st * st6, as_st * st7, as_st * st8);
as_st * and_then(as_st * st1, as_st * st2, as_st * st3, as_st * st4, as_st * st5, as_st * st6, as_st * st7, as_st * st8, as_st * st9);
as_st * and_then(as_st * st1, as_st * st2, as_st * st3, as_st * st4, as_st * st5, as_st * st6, as_st * st7, as_st * st8, as_st * st9, as_st * st10);
as_st * or_else(unsigned num, as_st * const * sts);
as_st * or_else(as_st * st1, as_st * st2);
as_st * or_else(as_st * st1, as_st * st2, as_st * st3);
as_st * or_else(as_st * st1, as_st * st2, as_st * st3, as_st * st4);
as_st * or_else(as_st * st1, as_st * st2, as_st * st3, as_st * st4, as_st * st5);
as_st * or_else(as_st * st1, as_st * st2, as_st * st3, as_st * st4, as_st * st5, as_st * st6);
as_st * or_else(as_st * st1, as_st * st2, as_st * st3, as_st * st4, as_st * st5, as_st * st6, as_st * st7);
as_st * or_else(as_st * st1, as_st * st2, as_st * st3, as_st * st4, as_st * st5, as_st * st6, as_st * st7, as_st * st8);
as_st * or_else(as_st * st1, as_st * st2, as_st * st3, as_st * st4, as_st * st5, as_st * st6, as_st * st7, as_st * st8, as_st * st9);
as_st * or_else(as_st * st1, as_st * st2, as_st * st3, as_st * st4, as_st * st5, as_st * st6, as_st * st7, as_st * st8, as_st * st9, as_st * st10);
as_st * par(unsigned num, as_st * const * sts);
as_st * par(as_st * st1, as_st * st2);
as_st * par(as_st * st1, as_st * st2, as_st * st3);
as_st * par(as_st * st1, as_st * st2, as_st * st3, as_st * st4);
as_st * round_robin(unsigned num, as_st * const * sts, unsigned start, unsigned end, unsigned delta);
as_st * round_robin(as_st * st1, as_st * st2, unsigned start, unsigned end, unsigned delta);
as_st * round_robin(as_st * st1, as_st * st2, as_st * st3, unsigned start, unsigned end, unsigned delta);
as_st * round_robin(as_st * st1, as_st * st2, as_st * st3, as_st * st4, unsigned start, unsigned end, unsigned delta);
as_st * try_for(as_st * st, unsigned msecs);
as_st * clean(as_st * st);
as_st * using_params(as_st * st, params_ref const & p);
as_st * noop();
as_st * trace_mc(as_st * st);
as_st * filter_is_sat(as_st* st, bool const& unless_condition);
as_st * filter_is_unsat(as_st* st, bool const& unless_condition);
as_st * mk_report_verbose_st(char const* msg, unsigned lvl);
as_st * repeat(as_st * st, unsigned max = UINT_MAX);
class wrapper_as_st : public as_st {
protected:
as_st * m_st;
public:
wrapper_as_st(as_st * s): m_st(s) { SASSERT(s); s->inc_ref(); }
virtual ~wrapper_as_st();
virtual void operator()(assertion_set& s, model_converter_ref& mc) { (*m_st)(s, mc); }
virtual void cleanup(void) { m_st->cleanup(); }
virtual void collect_statistics(statistics & st) const { m_st->collect_statistics(st); }
virtual void reset_statistics() { m_st->reset_statistics(); }
virtual void set_front_end_params(front_end_params & p) { m_st->set_front_end_params(p); }
virtual void updt_params(params_ref const & p) { m_st->updt_params(p); }
virtual void collect_param_descrs(param_descrs & r) { m_st->collect_param_descrs(r); }
virtual void reset() { m_st->reset(); }
virtual void set_logic(symbol const& l) { m_st->set_logic(l); }
virtual void set_progress_callback(progress_callback * callback) { m_st->set_progress_callback(callback); }
protected:
virtual void set_cancel(bool f) { if (m_st) m_st->set_cancel(f); }
};
class as_test {
unsigned m_ref_count;
public:
as_test():m_ref_count(0) {}
void inc_ref() { m_ref_count++; }
void dec_ref() { SASSERT(m_ref_count > 0); m_ref_count--; if (m_ref_count == 0) dealloc(this); }
virtual bool operator()(assertion_set const & s) const = 0;
};
as_test * check_mem(unsigned l);
as_test * check_as_size(unsigned l);
as_test * check_decided();
as_st * cond(as_test * c, as_st * t, as_st * e);
as_st * mk_smt_solver_core(bool candidate_models = false);
as_st * mk_smt_solver(bool auto_config = true, bool candidate_models = false);
void exec(as_st * st, assertion_set & s, model_converter_ref & mc);
lbool check_sat(as_st * st, assertion_set & s, model_ref & md, proof_ref & pr, std::string & reason_unknown);
class assertion_set_strategy_factory {
public:
virtual ~assertion_set_strategy_factory() {}
virtual as_st * operator()(ast_manager & m, params_ref const & p) = 0;
};
typedef assertion_set_strategy_factory as_st_f;
as_st * fail();
as_st * fail_if_not_decided(as_st * st);
as_st * fail_if_sat();
as_st * fail_if_unsat();
as_st * fail_if_not_small(unsigned sz);
as_st * fail_if_not_small_set(unsigned sz);
#define MK_FAIL_IF(NAME, TEST, MSG) \
class NAME ## _st : public assertion_set_strategy { \
public: \
virtual void operator()(assertion_set & s, model_converter_ref & mc) { if (TEST) throw strategy_exception(MSG); } \
virtual void cleanup() {} \
}; \
inline as_st * NAME() { return alloc(NAME ## _st); }
as_st * par_or(ast_manager & m, unsigned num, as_st_f * const * stfs);
#define MK_ST_FACTORY(NAME, CODE) \
class NAME : public assertion_set_strategy_factory { \
public: \
virtual ~NAME() {} \
virtual as_st * operator()(ast_manager & m, params_ref const & p) { CODE } \
};
#define MK_SIMPLE_ST_FACTORY(NAME, ST) MK_ST_FACTORY(NAME, return ST;)
MK_SIMPLE_ST_FACTORY(smt_solver_stf, mk_smt_solver());
struct is_qfbv_test : public as_test {
virtual bool operator()(assertion_set const & s) const { return is_qfbv(s); }
};
struct is_qflia_test : public as_test {
virtual bool operator()(assertion_set const & s) const { return is_qflia(s); }
};
struct is_qflra_test : public as_test {
virtual bool operator()(assertion_set const & s) const { return is_qflra(s); }
};
inline as_test * is_qfbv() { return alloc(is_qfbv_test); }
inline as_test * is_qflia() { return alloc(is_qflia_test); }
inline as_test * is_qflra() { return alloc(is_qflra_test); }
#endif

View file

@ -1,220 +0,0 @@
/*++
Copyright (c) 2011 Microsoft Corporation
Module Name:
assertion_set_util.cpp
Abstract:
Assertion set goodies
Author:
Leonardo de Moura (leonardo) 2011-04-28
Revision History:
--*/
#include"assertion_set_util.h"
#include"well_sorted.h"
#include"for_each_expr.h"
#include"bv_decl_plugin.h"
#include"arith_decl_plugin.h"
void as_shared_occs::operator()(assertion_set const & s) {
m_occs.reset();
shared_occs_mark visited;
unsigned sz = s.size();
for (unsigned i = 0; i < sz; i++) {
expr * t = s.form(i);
m_occs(t, visited);
}
}
bool is_well_sorted(assertion_set const & s) {
unsigned sz = s.size();
for (unsigned i = 0; i < sz; i++) {
expr * t = s.form(i);
if (!is_well_sorted(s.m(), t))
return false;
}
return true;
}
struct is_non_propositional {
struct found {};
ast_manager & m;
is_non_propositional(ast_manager & _m):m(_m) {}
void operator()(var *) { throw found(); }
void operator()(quantifier *) { throw found(); }
void operator()(app * n) {
if (!m.is_bool(n))
throw found();
family_id fid = n->get_family_id();
if (fid == m.get_basic_family_id())
return;
if (is_uninterp_const(n))
return;
throw found();
}
};
struct is_non_qfbv {
struct found {};
ast_manager & m;
bv_util u;
is_non_qfbv(ast_manager & _m):m(_m), u(m) {}
void operator()(var *) { throw found(); }
void operator()(quantifier *) { throw found(); }
void operator()(app * n) {
if (!m.is_bool(n) && !u.is_bv(n))
throw found();
family_id fid = n->get_family_id();
if (fid == m.get_basic_family_id())
return;
if (fid == u.get_family_id())
return;
if (is_uninterp_const(n))
return;
throw found();
}
};
bool is_propositional(assertion_set const & s) {
return !test<is_non_propositional>(s);
}
bool is_qfbv(assertion_set const & s) {
return !test<is_non_qfbv>(s);
}
struct is_non_qflira {
struct found {};
ast_manager & m;
arith_util u;
bool m_int;
bool m_real;
is_non_qflira(ast_manager & _m, bool _int, bool _real):m(_m), u(m), m_int(_int), m_real(_real) {}
void operator()(var *) { throw found(); }
void operator()(quantifier *) { throw found(); }
bool compatible_sort(app * n) const {
if (m.is_bool(n))
return true;
if (m_int && u.is_int(n))
return true;
if (m_real && u.is_real(n))
return true;
return false;
}
void operator()(app * n) {
if (!compatible_sort(n))
throw found();
family_id fid = n->get_family_id();
if (fid == m.get_basic_family_id())
return;
if (fid == u.get_family_id()) {
switch (n->get_decl_kind()) {
case OP_LE: case OP_GE: case OP_LT: case OP_GT:
case OP_ADD: case OP_NUM:
return;
case OP_MUL:
if (n->get_num_args() != 2)
throw found();
if (!u.is_numeral(n->get_arg(0)))
throw found();
return;
case OP_TO_REAL:
if (!m_real)
throw found();
break;
default:
throw found();
}
return;
}
if (is_uninterp_const(n))
return;
throw found();
}
};
bool is_qflia(assertion_set const & s) {
is_non_qflira proc(s.m(), true, false);
return !test(s, proc);
}
bool is_qflra(assertion_set const & s) {
is_non_qflira proc(s.m(), false, true);
return !test(s, proc);
}
bool is_qflira(assertion_set const & s) {
is_non_qflira proc(s.m(), true, true);
return !test(s, proc);
}
bool is_lp(assertion_set const & s) {
ast_manager & m = s.m();
arith_util u(m);
unsigned sz = s.size();
for (unsigned i = 0; i < sz; i++) {
expr * f = s.form(i);
bool sign = false;
while (m.is_not(f, f))
sign = !sign;
if (m.is_eq(f) && !sign) {
if (m.get_sort(to_app(f)->get_arg(0))->get_family_id() != u.get_family_id())
return false;
continue;
}
if (u.is_le(f) || u.is_ge(f) || u.is_lt(f) || u.is_gt(f))
continue;
return false;
}
return true;
}
bool is_ilp(assertion_set const & s) {
if (!is_qflia(s))
return false;
if (has_term_ite(s))
return false;
return is_lp(s);
}
bool is_mip(assertion_set const & s) {
if (!is_qflira(s))
return false;
if (has_term_ite(s))
return false;
return is_lp(s);
}
struct has_term_ite_proc {
struct found {};
ast_manager & m;
has_term_ite_proc(ast_manager & _m):m(_m) {}
void operator()(var *) {}
void operator()(quantifier *) {}
void operator()(app * n) { if (m.is_term_ite(n)) throw found(); }
};
bool has_term_ite(assertion_set const & s) {
return test<has_term_ite_proc>(s);
}

View file

@ -1,91 +0,0 @@
/*++
Copyright (c) 2011 Microsoft Corporation
Module Name:
assertion_set_util.h
Abstract:
Assertion set goodies
Author:
Leonardo de Moura (leonardo) 2011-04-28
Revision History:
--*/
#ifndef _ASSERTION_SET_UTIL_H_
#define _ASSERTION_SET_UTIL_H_
#include"assertion_set.h"
#include"shared_occs.h"
/**
\brief Functor for computing the set of shared occurrences in an assertion set.
It is essentially a wrapper for shared_occs functor.
*/
class as_shared_occs {
shared_occs m_occs;
public:
as_shared_occs(ast_manager & m, bool track_atomic = false, bool visit_quantifiers = true, bool visit_patterns = false):
m_occs(m, track_atomic, visit_quantifiers, visit_patterns) {
}
void operator()(assertion_set const & s);
bool is_shared(expr * t) { return m_occs.is_shared(t); }
unsigned num_shared() const { return m_occs.num_shared(); }
void reset() { return m_occs.reset(); }
void cleanup() { return m_occs.cleanup(); }
void display(std::ostream & out, ast_manager & m) const { m_occs.display(out, m); }
};
bool is_well_sorted(assertion_set const & s);
// Return true if the assertion set is propositional logic
bool is_propositional(assertion_set const & s);
// Return true if the assertion set is in QF_BV
bool is_qfbv(assertion_set const & s);
// Return true if the assertion set is in QF_LIA
bool is_qflia(assertion_set const & s);
// Return true if the assertion set is in QF_LRA
bool is_qflra(assertion_set const & s);
// Return true if the assertion set is in QF_LIRA
bool is_qflira(assertion_set const & s);
// Return true if the assertion set is in ILP problem (that is QF_LIA without boolean structure)
bool is_ilp(assertion_set const & s);
// Return true if the assertion set is in MIP problem (that is QF_LIRA without boolean structure)
bool is_mip(assertion_set const & s);
bool has_term_ite(assertion_set const & s);
inline bool is_decided(assertion_set const & s) { return s.size() == 0 || s.inconsistent(); }
template<typename Predicate>
bool test(assertion_set const & s, Predicate & proc) {
expr_fast_mark1 visited;
try {
unsigned sz = s.size();
for (unsigned i = 0; i < sz; i++)
quick_for_each_expr(proc, visited, s.form(i));
}
catch (typename Predicate::found) {
return true;
}
return false;
}
template<typename Predicate>
bool test(assertion_set const & s) {
Predicate proc(s.m());
return test(s, proc);
}
#endif

View file

@ -1,526 +0,0 @@
/*++
Copyright (c) 2006 Microsoft Corporation
Module Name:
cnf.cpp
Abstract:
<abstract>
Author:
Leonardo de Moura (leonardo) 2008-01-23.
Revision History:
--*/
#include"cnf.h"
#include"ast_pp.h"
#include"ast_ll_pp.h"
unsigned cnf_entry::hash() const {
unsigned a = m_node->get_id();
unsigned b = m_polarity;
unsigned c = m_in_q;
mix(a,b,c);
return c;
}
bool cnf_entry::operator==(cnf_entry const & k) const {
return m_node == k.m_node && m_polarity == k.m_polarity && m_in_q == k.m_in_q;
}
cnf_cache::cnf_cache(ast_manager & m):
m_manager(m) {
}
void cnf_cache::insert(cnf_entry const & k, expr * r, proof * pr) {
SASSERT(!m_cache.contains(k));
m_manager.inc_ref(r);
m_manager.inc_ref(pr);
m_cache.insert(k, expr_proof_pair(r, pr));
}
void cnf_cache::reset() {
cache::iterator it = m_cache.begin();
cache::iterator end = m_cache.end();
for (; it != end; ++it) {
expr_proof_pair & pair = (*it).m_value;
m_manager.dec_ref(pair.first);
m_manager.dec_ref(pair.second);
}
m_cache.reset();
}
void cnf::cache_result(expr * e, bool in_q, expr * r, proof * pr) {
SASSERT(r);
TRACE("cnf", tout << "caching result for: " << e->get_id() << " " << r->get_id() << "\n";);
m_cache.insert(cnf_entry(e, true, in_q), r, pr);
}
void cnf::visit(expr * n, bool in_q, bool & visited) {
if (!is_cached(n, in_q)) {
m_todo.push_back(std::make_pair(n, in_q));
visited = false;
}
}
bool cnf::visit_children(expr * n, bool in_q) {
bool visited = true;
switch(n->get_kind()) {
case AST_APP:
if (m_manager.is_or(n) || m_manager.is_and(n) || m_manager.is_label(n)) {
unsigned j = to_app(n)->get_num_args();
while (j > 0) {
--j;
visit(to_app(n)->get_arg(j), in_q, visited);
}
}
break;
case AST_QUANTIFIER:
visit(to_quantifier(n)->get_expr(), true, visited);
break;
default:
break;
}
return visited;
}
void cnf::reduce1(expr * n, bool in_q) {
switch(n->get_kind()) {
case AST_APP:
if (m_manager.is_or(n))
reduce1_or(to_app(n), in_q);
else if (m_manager.is_and(n))
reduce1_and(to_app(n), in_q);
else if (m_manager.is_label(n))
reduce1_label(to_app(n), in_q);
else
cache_result(n, in_q, n, 0);
break;
case AST_QUANTIFIER:
reduce1_quantifier(to_quantifier(n), in_q);
break;
default:
cache_result(n, in_q, n, 0);
break;
}
}
void cnf::get_args(app * n, bool in_q, ptr_buffer<expr> & new_args, ptr_buffer<proof> & new_arg_prs) {
unsigned num = n->get_num_args();
for (unsigned i = 0; i < num; i++) {
expr * new_arg = 0;
proof * new_arg_pr = 0;
get_cached(n->get_arg(i), in_q, new_arg, new_arg_pr);
SASSERT(new_arg);
new_args.push_back(new_arg);
if (new_arg_pr)
new_arg_prs.push_back(new_arg_pr);
}
}
void cnf::flat_args(func_decl * d, ptr_buffer<expr> const & args, ptr_buffer<expr> & flat_args) {
ptr_buffer<expr>::const_iterator it = args.begin();
ptr_buffer<expr>::const_iterator end = args.end();
for (; it != end; ++it) {
expr * arg = *it;
if (is_app_of(arg, d))
flat_args.append(to_app(arg)->get_num_args(), to_app(arg)->get_args());
else
flat_args.push_back(arg);
}
}
/**
\brief Return the approximated size of distributing OR over AND on
(OR args[0] .... args[sz-1])
*/
approx_nat cnf::approx_result_size_for_disj(ptr_buffer<expr> const & args) {
approx_nat r(1);
ptr_buffer<expr>::const_iterator it = args.begin();
ptr_buffer<expr>::const_iterator end = args.end();
for (; it != end; ++it) {
expr * arg = *it;
if (m_manager.is_and(arg))
r *= to_app(arg)->get_num_args();
}
return r;
}
/**
\brief Return true if it is too expensive to process the disjunction of args
*/
inline bool cnf::is_too_expensive(approx_nat approx_result_size, ptr_buffer<expr> const & args) {
// (OR A (AND B C)) is always considered cheap.
if (args.size() == 2 && (!m_manager.is_and(args[0]) || !m_manager.is_and(args[1])))
return false;
return !(approx_result_size < m_params.m_cnf_factor);
}
/**
\brief Create a (positive) name for the expressions of the form (AND ...) in args.
Store the result in new_args.
*/
void cnf::name_args(ptr_buffer<expr> const & args, expr_ref_buffer & new_args, proof_ref_buffer & new_arg_prs) {
ptr_buffer<expr>::const_iterator it = args.begin();
ptr_buffer<expr>::const_iterator end = args.end();
for (; it != end; ++it) {
expr * arg = *it;
if (m_manager.is_and(arg)) {
expr_ref new_def(m_manager);
proof_ref new_def_pr(m_manager);
app_ref new_arg(m_manager);
proof_ref new_arg_pr(m_manager);
if (m_defined_names.mk_pos_name(to_app(arg), new_def, new_def_pr, new_arg, new_arg_pr)) {
m_todo_defs.push_back(new_def);
if (m_manager.proofs_enabled())
m_todo_proofs.push_back(new_def_pr);
}
new_args.push_back(new_arg);
if (m_manager.fine_grain_proofs())
new_arg_prs.push_back(new_arg_pr);
else
m_coarse_proofs.push_back(new_arg_pr);
}
else
new_args.push_back(arg);
}
}
void cnf::distribute(app * n, app * & r, proof * & pr) {
SASSERT(m_manager.is_or(n));
buffer<unsigned> sz;
buffer<unsigned> it;
ptr_buffer<expr> new_args;
unsigned num = n->get_num_args();
for (unsigned i = 0; i < num; i++) {
expr * arg = n->get_arg(i);
it.push_back(0);
if (m_manager.is_and(arg))
sz.push_back(to_app(arg)->get_num_args());
else
sz.push_back(1);
}
do {
ptr_buffer<expr> lits;
for (unsigned i = 0; i < num; i++) {
expr * arg = n->get_arg(i);
if (m_manager.is_and(arg)) {
SASSERT(it[i] < to_app(arg)->get_num_args());
lits.push_back(to_app(arg)->get_arg(it[i]));
}
else {
SASSERT(it[i] == 0);
lits.push_back(arg);
}
}
app * n = m_manager.mk_or(lits.size(), lits.c_ptr());
new_args.push_back(n);
}
while (product_iterator_next(sz.size(), sz.c_ptr(), it.c_ptr()));
SASSERT(!new_args.empty());
if (new_args.size() == 1)
r = to_app(new_args[0]);
else
r = m_manager.mk_and(new_args.size(), new_args.c_ptr());
pr = 0;
if (m_manager.fine_grain_proofs() && r != n)
pr = m_manager.mk_iff_oeq(m_manager.mk_distributivity(n, r));
}
void cnf::push_quant(quantifier * q, expr * & r, proof * & pr) {
SASSERT(is_forall(q));
expr * e = q->get_expr();
pr = 0;
if (m_manager.is_and(e)) {
expr_ref_buffer new_args(m_manager);
unsigned num = to_app(e)->get_num_args();
for (unsigned i = 0; i < num; i++) {
quantifier_ref aux(m_manager);
aux = m_manager.update_quantifier(q, 0, 0, 0, 0, to_app(e)->get_arg(i));
expr_ref new_arg(m_manager);
elim_unused_vars(m_manager, aux, new_arg);
new_args.push_back(new_arg);
}
r = m_manager.mk_and(new_args.size(), new_args.c_ptr());
if (m_manager.fine_grain_proofs())
pr = m_manager.mk_iff_oeq(m_manager.mk_push_quant(q, r));
}
else {
r = q;
}
}
void cnf::reduce1_or(app * n, bool in_q) {
ptr_buffer<expr> new_args;
ptr_buffer<proof> new_arg_prs;
get_args(n, in_q, new_args, new_arg_prs);
expr * r;
proof * pr = 0;
if (in_q || m_params.m_cnf_mode == CNF_OPPORTUNISTIC || m_params.m_cnf_mode == CNF_FULL) {
ptr_buffer<expr> f_args;
flat_args(n->get_decl(), new_args, f_args);
TRACE("cnf_or", for (unsigned i = 0; i < f_args.size(); i++) tout << mk_pp(f_args[i], m_manager) << "\n";);
approx_nat result_size = approx_result_size_for_disj(f_args);
TRACE("cnf_or", tout << mk_pp(n, m_manager) << "\napprox. result: " << result_size << "\n";);
if (m_params.m_cnf_mode != CNF_OPPORTUNISTIC || result_size < m_params.m_cnf_factor) {
expr_ref_buffer cheap_args(m_manager);
proof_ref_buffer cheap_args_pr(m_manager);
bool named_args;
if (is_too_expensive(result_size, f_args)) {
named_args = true;
name_args(f_args, cheap_args, cheap_args_pr);
}
else {
named_args = false;
cheap_args.append(f_args.size(), f_args.c_ptr());
}
app_ref r1(m_manager);
r1 = m_manager.mk_or(cheap_args.size(), cheap_args.c_ptr());
// Proof gen support ---------------------------
// r1 is (OR cheap_args) it is only built if proofs are enabled.
// p1 is a proof for (= n r1)
proof * p1 = 0;
if (m_manager.fine_grain_proofs()) {
proof * prs[3];
app * r[2];
r[0] = m_manager.mk_or(new_args.size(), new_args.c_ptr());
prs[0] = n == r[0] ? 0 : m_manager.mk_oeq_congruence(n, r[0], new_arg_prs.size(), new_arg_prs.c_ptr());
r[1] = m_manager.mk_or(f_args.size(), f_args.c_ptr());
prs[1] = r[0] == r[1] ? 0 : m_manager.mk_iff_oeq(m_manager.mk_rewrite(r[0], r[1]));
prs[2] = r[1] == r1 ? 0 : m_manager.mk_oeq_congruence(r[1], r1, cheap_args_pr.size(), cheap_args_pr.c_ptr());
p1 = m_manager.mk_transitivity(3, prs);
}
// --------------------------------------------
expr_ref r2(m_manager);
proof_ref p2(m_manager);
m_pull.pull_quant2(r1, r2, p2);
if (is_quantifier(r2)) {
expr * e = to_quantifier(r2)->get_expr();
SASSERT(m_manager.is_or(e));
app * d_r;
proof * d_pr;
distribute(to_app(e), d_r, d_pr);
quantifier_ref r3(m_manager);
r3 = m_manager.update_quantifier(to_quantifier(r2), d_r);
proof * push_pr;
push_quant(r3, r, push_pr);
if (m_manager.fine_grain_proofs()) {
// p1 is a proof of n == r1
// p2 is a proof of r1 == r2
p2 = p2 == 0 ? 0 : m_manager.mk_iff_oeq(p2);
proof * p3 = r2 == r3 ? 0 : m_manager.mk_oeq_quant_intro(to_quantifier(r2), r3, d_pr);
CTRACE("cnf_or", p1, tout << "p1:\n" << mk_pp(m_manager.get_fact(p1), m_manager) << "\n";);
CTRACE("cnf_or", p2, tout << "p2:\n" << mk_pp(m_manager.get_fact(p2), m_manager) << "\n";);
CTRACE("cnf_or", p3, tout << "p3:\n" << mk_pp(m_manager.get_fact(p3), m_manager) << "\n";);
TRACE("cnf_or", tout << "r2 == r3: " << (r2 == r3) << "\n"
<< mk_pp(r2, m_manager) << "\n" << mk_pp(r3, m_manager) << "\n";);
pr = m_manager.mk_transitivity(p1, p2, p3, push_pr);
}
cache_result(n, in_q, r, pr);
}
else {
SASSERT(p2 == 0);
SASSERT(r1 == r2);
SASSERT(m_manager.is_or(r2));
app * r3;
distribute(to_app(r2), r3, pr);
r = r3;
pr = m_manager.mk_transitivity(p1, pr);
cache_result(n, in_q, r, pr);
}
return;
}
}
r = m_manager.mk_or(new_args.size(), new_args.c_ptr());
if (m_manager.fine_grain_proofs() && n != r)
pr = m_manager.mk_oeq_congruence(n, to_app(r), new_arg_prs.size(), new_arg_prs.c_ptr());
cache_result(n, in_q, r, pr);
}
void cnf::reduce1_and(app * n, bool in_q) {
ptr_buffer<expr> new_args;
ptr_buffer<proof> new_arg_prs;
get_args(n, in_q, new_args, new_arg_prs);
app * r;
proof * pr = 0;
if (in_q || m_params.m_cnf_mode == CNF_OPPORTUNISTIC || m_params.m_cnf_mode == CNF_FULL) {
ptr_buffer<expr> f_args;
flat_args(n->get_decl(), new_args, f_args);
r = m_manager.mk_and(f_args.size(), f_args.c_ptr());
if (m_manager.fine_grain_proofs() && n != r) {
app * r0 = m_manager.mk_and(new_args.size(), new_args.c_ptr());
proof * p0 = r0 == n ? 0 : m_manager.mk_oeq_congruence(n, r0, new_arg_prs.size(), new_arg_prs.c_ptr());
proof * p1 = r0 == r ? 0 : m_manager.mk_iff_oeq(m_manager.mk_rewrite(r0, r));
pr = m_manager.mk_transitivity(p0, p1);
}
}
else {
r = m_manager.mk_and(new_args.size(), new_args.c_ptr());
if (m_manager.fine_grain_proofs() && n != r)
pr = m_manager.mk_oeq_congruence(n, r, new_arg_prs.size(), new_arg_prs.c_ptr());
}
cache_result(n, in_q, r, pr);
}
void cnf::reduce1_label(app * n, bool in_q) {
expr * r;
proof * pr = 0;
expr * new_arg;
proof * new_arg_pr;
get_cached(n->get_arg(0), true, new_arg, new_arg_pr);
if (in_q || m_params.m_cnf_mode == CNF_FULL) {
// TODO: in the current implementation, labels are removed during CNF translation.
// This is satisfactory for Boogie, since it does not use labels inside quantifiers,
// and we only need CNF_QUANT for Superposition Calculus.
r = new_arg;
if (m_manager.fine_grain_proofs()) {
proof * p0 = m_manager.mk_iff_oeq(m_manager.mk_rewrite(n, n->get_arg(0)));
pr = m_manager.mk_transitivity(p0, new_arg_pr);
}
}
else {
r = m_manager.mk_app(n->get_decl(), new_arg);
if (m_manager.fine_grain_proofs() && n != r)
pr = m_manager.mk_oeq_congruence(n, to_app(r), 1, &new_arg_pr);
}
cache_result(n, in_q, r, pr);
}
void cnf::reduce1_quantifier(quantifier * q, bool in_q) {
expr * new_expr;
proof * new_expr_pr;
get_cached(q->get_expr(), true, new_expr, new_expr_pr);
expr_ref r(m_manager);
proof_ref pr(m_manager);
if (m_manager.is_and(new_expr) && q->is_forall()) {
quantifier_ref q1(m_manager);
q1 = m_manager.update_quantifier(q, new_expr);
expr_ref q2(m_manager);
proof_ref p2(m_manager);
m_pull.pull_quant2(q1, q2, p2);
expr * q3;
proof * p3;
push_quant(to_quantifier(q2), q3, p3);
r = q3;
if (m_manager.fine_grain_proofs()) {
proof * p1 = q == q1 ? 0 : m_manager.mk_oeq_quant_intro(q, q1, new_expr_pr);
p2 = p2 == 0 ? 0 : m_manager.mk_iff_oeq(p2);
pr = m_manager.mk_transitivity(p1, p2, p3);
}
}
else if ((m_manager.is_or(new_expr) || is_forall(new_expr)) && q->is_forall()) {
quantifier_ref q1(m_manager);
q1 = m_manager.update_quantifier(q, new_expr);
m_pull.pull_quant2(q1, r, pr);
if (m_manager.fine_grain_proofs()) {
pr = pr == 0 ? 0 : m_manager.mk_iff_oeq(pr);
proof * p1 = q == q1 ? 0 : m_manager.mk_oeq_quant_intro(q, q1, new_expr_pr);
pr = m_manager.mk_transitivity(p1, pr);
}
}
else {
r = m_manager.update_quantifier(q, new_expr);
if (m_manager.fine_grain_proofs() && r != q)
pr = q == r ? 0 : m_manager.mk_oeq_quant_intro(q, to_quantifier(r), new_expr_pr);
}
cache_result(q, in_q, r, pr);
TRACE("cnf_quant", tout << mk_pp(q, m_manager) << "\n" << mk_pp(r, m_manager) << "\n";);
}
cnf::cnf(ast_manager & m, defined_names & n, cnf_params & params):
m_params(params),
m_manager(m),
m_defined_names(n),
m_pull(m),
m_cache(m),
m_todo_defs(m),
m_todo_proofs(m),
m_coarse_proofs(m) {
}
cnf::~cnf() {
}
void cnf::reduce(expr * n, expr_ref & r, proof_ref & pr) {
m_coarse_proofs.reset();
m_todo.reset();
m_todo.push_back(expr_bool_pair(n, false));
while (!m_todo.empty()) {
expr_bool_pair pair = m_todo.back();
expr * n = pair.first;
bool in_q = pair.second;
if (is_cached(n, in_q)) {
m_todo.pop_back();
}
else if (visit_children(n, in_q)) {
m_todo.pop_back();
reduce1(n, in_q);
}
}
expr * r2;
proof * pr2;
get_cached(n, false, r2, pr2);
r = r2;
switch (m_manager.proof_mode()) {
case PGM_DISABLED:
pr = m_manager.mk_undef_proof();
break;
case PGM_COARSE:
remove_duplicates(m_coarse_proofs);
pr = n == r2 ? m_manager.mk_reflexivity(n) : m_manager.mk_cnf_star(n, r2, m_coarse_proofs.size(), m_coarse_proofs.c_ptr());
break;
case PGM_FINE:
pr = pr2 == 0 ? m_manager.mk_reflexivity(n) : pr2;
break;
}
}
void cnf::operator()(expr * n, expr_ref_vector & new_defs, proof_ref_vector & new_def_proofs, expr_ref & r, proof_ref & pr) {
if (m_params.m_cnf_mode == CNF_DISABLED) {
r = n;
pr = m_manager.mk_reflexivity(n);
return;
}
reset();
reduce(n, r, pr);
for (unsigned i = 0; i < m_todo_defs.size(); i++) {
expr_ref dr(m_manager);
proof_ref dpr(m_manager);
reduce(m_todo_defs.get(i), dr, dpr);
m_result_defs.push_back(dr);
if (m_manager.proofs_enabled()) {
proof * new_pr = m_manager.mk_modus_ponens(m_todo_proofs.get(i), dpr);
m_result_def_proofs.push_back(new_pr);
}
else
m_result_def_proofs.push_back(m_manager.mk_undef_proof());
}
std::reverse(m_result_defs.begin(), m_result_defs.end());
new_defs.append(m_result_defs.size(), m_result_defs.c_ptr());
std::reverse(m_result_def_proofs.begin(), m_result_def_proofs.end());
new_def_proofs.append(m_result_def_proofs.size(), m_result_def_proofs.c_ptr());
}
void cnf::reset() {
m_cache.reset();
m_todo.reset();
m_todo_defs.reset();
m_todo_proofs.reset();
m_result_defs.reset();
m_result_def_proofs.reset();
}

121
lib/cnf.h
View file

@ -1,121 +0,0 @@
/*++
Copyright (c) 2006 Microsoft Corporation
Module Name:
cnf.h
Abstract:
CNF translation
Author:
Leonardo de Moura (leonardo) 2008-01-17.
Revision History:
--*/
#ifndef _CNF_H_
#define _CNF_H_
#include"cnf_params.h"
#include"pull_quant.h"
#include"nnf.h"
#include"approx_nat.h"
/**
\brief Entry into the todo list of the CNF translator. It is also used as the key in the CNF cache.
*/
struct cnf_entry {
expr * m_node;
bool m_polarity:1;
bool m_in_q:1;
cnf_entry():m_node(0), m_polarity(false), m_in_q(false) {}
cnf_entry(expr * n, bool p, bool in_q):m_node(n), m_polarity(p), m_in_q(in_q) {}
unsigned hash() const;
bool operator==(cnf_entry const & k) const;
};
/**
\brief Cache for CNF transformation. It is a mapping from (expr, polarity, in_q) -> (expr, proof)
*/
class cnf_cache {
public:
typedef std::pair<expr *, proof *> expr_proof_pair;
typedef map<cnf_entry, expr_proof_pair, obj_hash<cnf_entry>, default_eq<cnf_entry> > cache;
ast_manager & m_manager;
cache m_cache;
public:
cnf_cache(ast_manager & m);
~cnf_cache() { reset(); }
void insert(cnf_entry const & k, expr * r, proof * pr);
bool contains(cnf_entry const & k) const { return m_cache.contains(k); }
void get(cnf_entry const & k, expr * & r, proof * & pr) const { expr_proof_pair tmp; m_cache.find(k, tmp); r = tmp.first; pr = tmp.second; }
void reset();
};
/**
\brief Functor for converting expressions into CNF. The functor can
optionally process subformulas nested in quantifiers. New names may be
introduced for subformulas that are too expensive to be put into CNF.
NNF translation must be applied before converting to CNF.
- To use CNF_QUANT, we must use at least NNF_QUANT
- To use CNF_OPPORTUNISTIC, we must use at least NNF_QUANT
- To use CNF_FULL, we must use NNF_FULL
*/
class cnf {
typedef std::pair<expr *, bool> expr_bool_pair;
cnf_params & m_params;
ast_manager & m_manager;
defined_names & m_defined_names;
pull_quant m_pull;
cnf_cache m_cache;
svector<expr_bool_pair> m_todo;
expr_ref_vector m_todo_defs;
proof_ref_vector m_todo_proofs;
ptr_vector<expr> m_result_defs;
ptr_vector<proof> m_result_def_proofs;
proof_ref_vector m_coarse_proofs;
void cache_result(expr * e, bool in_q, expr * r, proof * pr);
void get_cached(expr * n, bool in_q, expr * & r, proof * & pr) const { m_cache.get(cnf_entry(n, true, in_q), r, pr); }
bool is_cached(expr * n, bool in_q) const { return m_cache.contains(cnf_entry(n, true, in_q)); }
void visit(expr * n, bool in_q, bool & visited);
bool visit_children(expr * n, bool in_q);
void get_args(app * n, bool in_q, ptr_buffer<expr> & new_args, ptr_buffer<proof> & new_arg_prs);
void flat_args(func_decl * d, ptr_buffer<expr> const & args, ptr_buffer<expr> & flat_args);
approx_nat approx_result_size_for_disj(ptr_buffer<expr> const & args);
bool is_too_expensive(approx_nat approx_result_size, ptr_buffer<expr> const & args);
void name_args(ptr_buffer<expr> const & args, expr_ref_buffer & new_args, proof_ref_buffer & new_arg_prs);
void distribute(app * arg, app * & r, proof * & pr);
void push_quant(quantifier * q, expr * & r, proof * & pr);
void reduce1(expr * n, bool in_q);
void reduce1_or(app * n, bool in_q);
void reduce1_and(app * n, bool in_q);
void reduce1_label(app * n, bool in_q);
void reduce1_quantifier(quantifier * q, bool in_q);
void reduce(expr * n, expr_ref & r, proof_ref & pr);
public:
cnf(ast_manager & m, defined_names & n, cnf_params & params);
~cnf();
void operator()(expr * n, // [IN] expression that should be put into CNF
expr_ref_vector & new_defs, // [OUT] new definitions
proof_ref_vector & new_def_proofs, // [OUT] proofs of the new definitions
expr_ref & r, // [OUT] resultant expression
proof_ref & p // [OUT] proof for (~ n r)
);
void reset();
};
#endif /* _CNF_H_ */

View file

@ -1,316 +0,0 @@
char const * g_pattern_database =
"(benchmark patterns \n"
" :status unknown \n"
" :logic ALL \n"
" :extrafuns ((?f1 Int Int Int Int) (?f2 Int Int Int) (?f3 Int Int Int) (?f4 Int Int Int)\n"
" (?f5 Int Int Int) (?f6 Int Int) (?f7 Int Int) (?f8 Int Int Int) (?f9 Int Int Int)\n"
" (?f10 Int) (?f11 Int) (?f12 Int Int) (?f13 Int Int) (?f14 Int Int Int) \n"
" (?f15 Int Int) (?f16 Int Int) (?f17 Int Int) (?f18 Int Int) (?f19 Int Int)\n"
" (?f20 Int Int) (?f21 Int) (?f22 Int) (?f23 Int) (?f24 Int Int) (?f25 Int Int)\n"
" )\n"
"\n"
" :formula (forall (a Int) (i Int) (e Int) \n"
" (= (?f2 (?f1 a i e) i) e)\n"
" :pats { (?f1 a i e) }\n"
" :weight { 0 })\n"
"\n"
" :formula (forall (a Int) (i Int) (j Int) (e Int) \n"
" (or (= i j) (= (?f2 (?f1 a i e) j) (?f2 a j)))\n"
" :pats { (?f2 (?f1 a i e) j) }\n"
" :weight { 0 })\n"
"\n"
" :formula (forall (t0 Int) (t1 Int) (t2 Int) \n"
" (or (not (= (?f3 t0 t1) 1))\n"
" (not (= (?f3 t1 t2) 1))\n"
" (= (?f3 t0 t2) 1))\n"
" :pats { (?f3 t0 t1) (?f3 t1 t2) })\n"
"\n"
" :formula (forall (t0 Int) (t1 Int) \n"
" (or (not (= (?f3 t0 t1) 1))\n"
" (not (= (?f3 t1 t0) 1))\n"
" (= t0 t1))\n"
" :pats { (?f3 t0 t1) (?f3 t1 t0) })\n"
"\n"
" :formula (forall (t0 Int) (t1 Int) (t2 Int) \n"
" (or (not (= (?f3 t0 (?f4 t1 t2)) 1))\n"
" (= (?f5 t2 t0) (?f4 t1 t2)))\n"
" :pats { (?f3 t0 (?f4 t1 t2)) })\n"
"\n"
" :formula (forall (t Int) \n"
" (= (?f25 (?f24 t)) t)\n"
" :pats { (?f24 t) })\n"
"\n"
" :formula (forall (t0 Int) (t1 Int) \n"
" (iff (= (?f3 t0 (?f6 t1)) 1)\n"
" (not (or (not (= t0 (?f6 (?f7 t0))))\n"
" (not (= (?f3 (?f7 t0) t1) 1)))))\n"
" :pats { (?f3 t0 (?f6 t1)) })\n"
"\n"
" :formula (forall (x Int) (t Int) \n"
" (or (not (= (?f8 x t) 1))\n"
" (= (?f9 x t) x))\n"
" :pats { (?f9 x t) })\n"
"\n"
" :formula (forall (x Int) (t Int) \n"
" (or (not (= (?f3 t ?f10) 1))\n"
" (iff (= (?f8 x t) 1)\n"
" (or (= x ?f11)\n"
" (= (?f3 (?f12 x) t) 1))))\n"
" :pats { (?f3 t ?f10) (?f8 x t) })\n"
"\n"
" :formula (forall (e Int) (a Int) (i Int) \n"
" (= (?f8 (?f2 (?f2 (?f13 e) a) i)\n"
" (?f7 (?f12 a))) 1)\n"
" :pats { (?f2 (?f2 (?f13 e) a) i) })\n"
"\n"
" :formula (forall (x Int) (f Int) (a0 Int) \n"
" (or (<= (+ a0 (* -1 (?f15 f))) 0)\n"
" (not (= (?f14 x a0) 1))\n"
" (= (?f14 (?f2 f x) a0) 1))\n"
" :pats { (?f14 (?f2 f x) a0) })\n"
"\n"
" :formula (forall (a Int) (e Int) (i Int) (a0 Int) \n"
" (or (<= (+ a0 (* -1 (?f16 e))) 0)\n"
" (not (= (?f14 a a0) 1))\n"
" (= (?f14 (?f2 (?f2 e a) i) a0) 1))\n"
" :pats { (?f14 (?f2 (?f2 e a) i) a0) })\n"
"\n"
" :formula (forall (S Int) \n"
" (= (?f2 (?f18 S) (?f17 (?f18 S))) 1)\n"
" :pats { (?f2 (?f18 S) (?f17 (?f18 S))) })\n"
"\n"
" :formula (forall (s Int) \n"
" (or (not (= 1 (?f19 s)))\n"
" (= (?f3 (?f12 s) ?f23) 1))\n"
" :pats { (?f19 s) })\n"
"\n"
" :formula (forall (t Int) \n"
" (not (or (= (?f20 t) ?f11)\n"
" (not (= (?f8 (?f20 t) ?f21) 1))\n"
" (not (= (?f14 (?f20 t) ?f22) 1))))\n"
" :pats { (?f20 t) })\n"
"\n"
" :extrafuns ((?f26 Int Int Int Int) \n"
" (?f27 Int Int Int Int Int))\n"
" \n"
" :formula (forall (A Int) (o Int) (f Int) (v Int)\n"
" (= (?f26 (?f27 A o f v) o f) v)\n"
" :pats { (?f27 A o f v) }\n"
" :weight { 0 }) \n"
"\n"
" :formula (forall (A Int) (o Int) (f Int) (p Int) (g Int) (v Int)\n"
" (or (= o p) (= (?f26 (?f27 A o f v) p g) (?f26 A p g)))\n"
" :pats { (?f26 (?f27 A o f v) p g) }\n"
" :weight { 0 })\n"
"\n"
" :formula (forall (A Int) (o Int) (f Int) (p Int) (g Int) (v Int)\n"
" (or (= f g) (= (?f26 (?f27 A o f v) p g) (?f26 A p g)))\n"
" :pats { (?f26 (?f27 A o f v) p g) }\n"
" :weight { 0 })\n"
"\n"
" :extrapreds ((?f28 Int Int))\n"
"\n"
" :formula (forall (t Int) (u Int) (v Int)\n"
" (or (not (?f28 t u))\n"
" (not (?f28 u v))\n"
" (?f28 t v))\n"
" :pat {(?f28 t u) (?f28 u v)})\n"
"\n"
" :formula (forall (t Int) (u Int)\n"
" (or (not (?f28 t u))\n"
" (not (?f28 u t))\n"
" (= t u))\n"
" :pat {(?f28 t u) (?f28 u t)})\n"
"\n"
" :extrafuns ((?f29 Int Int) (?f30 Int Int) (?f31 Int Int Int) (?f32 Int) (?f33 Int) (?f34 Int Int Int)\n"
" (?f35 Int Int) (?f36 Int) (?f37 Int) (?f38 Int) (?f39 Int Int) (?f40 Int)\n"
" (?f41 Int) (?f42 Int Int) (?f43 Int Int) (?f44 Int) (?f45 Int Int))\n"
"\n"
" :formula (forall (x Int) (p Int)\n"
" (or (not (?f28 (?f30 (?f31 x p)) ?f32))\n"
" (not (= (?f31 x p) p))\n"
" (= x p))\n"
" :pat { (?f28 (?f30 (?f31 x p)) ?f32)} )\n"
" \n"
" :formula (forall (h Int) (o Int) (f Int) (T Int)\n"
" (or \n"
" (not (= (?f39 h) ?f33))\n"
" (= (?f26 h o (?f34 f T)) ?f36)\n"
" (not (or (not (= (?f26 h (?f26 h o (?f34 f T)) ?f37) o))\n"
" (not (= (?f26 h (?f26 h o (?f34 f T)) ?f38) T)))))\n"
" :pat {(?f26 h o (?f34 f T))})\n"
"\n"
" :formula (forall (h Int) (o Int) (f Int)\n"
" (or\n"
" (not (= (?f39 h) ?f33))\n"
" (= (?f26 h o (?f35 f)) ?f36)\n"
" (not (or (not (= (?f26 h (?f26 h o (?f35 f)) ?f37) (?f26 h o ?f37)))\n"
" (not (= (?f26 h (?f26 h o (?f35 f)) ?f38) (?f26 h o ?f38))))))\n"
" :pat {(?f26 h o (?f35 f))})\n"
" \n"
" :formula (forall (h Int) (o Int)\n"
" (or \n"
" (not (= (?f39 h) ?f33))\n"
" (= (?f26 h o ?f38) ?f44)\n"
" (not (?f28 (?f26 h (?f26 h o ?f37) ?f41) (?f26 h o ?f38)))\n"
" (= (?f26 h (?f26 h o ?f37) ?f40) (?f42 (?f26 h o ?f38)))\n"
" (not (or (not (= (?f26 h o ?f41) (?f43 o)))\n"
" (not (= (?f26 h o ?f40) (?f43 o))))))\n"
" :pat {(?f28 (?f26 h (?f26 h o ?f37) ?f41) (?f26 h o ?f38))})\n"
"\n"
" :formula (forall (T Int) (h Int)\n"
" (or (not (= (?f39 h) ?f33))\n"
" (= (?f26 h (?f45 T) ?f38) ?f44))\n"
" :pat {(?f26 h (?f45 T) ?f38)})\n"
"\n"
" :extrafuns ((?f46 Int Int Int)\n"
" (?f47 Int Int Int)\n"
" (?f48 Int Int Int)\n"
" (?f49 Int)\n"
" (?f50 Int Int Int)\n"
" (?f51 Int Int Int)\n"
" (?f52 Int Int)\n"
" )\n"
"\n"
" :formula (forall (a Int) (T Int) (i Int) (r Int) (heap Int)\n"
" (or (not (= (?f39 heap) ?f33))\n"
" (not (?f28 (?f43 a) (?f46 T r)))\n"
" (= (?f47 (?f48 (?f26 heap a ?f49) i) T) ?f33))\n"
" :pat {(?f28 (?f43 a) (?f46 T r)) (?f48 (?f26 heap a ?f49) i)})\n"
"\n"
" :formula (forall (a Int) (T Int) (r Int)\n"
" (or (= a ?f36) \n"
" (not (?f28 (?f43 a) (?f46 T r)))\n"
" (= (?f52 a) r))\n"
" :pat {(?f28 (?f43 a) (?f46 T r))})\n"
"\n"
" :extrafuns ((?f53 Int Int Int)\n"
" (?f54 Int Int)\n"
" (?f55 Int)\n"
" (?f56 Int Int)\n"
" (?f57 Int)\n"
" (?f58 Int)\n"
" (?f59 Int Int Int)\n"
" (?f60 Int Int Int)\n"
" (?f61 Int Int Int)\n"
" )\n"
"\n"
" :extrapreds ((?f62 Int Int))\n"
" \n"
" :formula (forall (T Int) (ET Int) (r Int)\n"
" (or (not (?f28 T (?f53 ET r)))\n"
" (= (?f54 T) ?f55))\n"
" :pat {(?f28 T (?f53 ET r))})\n"
"\n"
" :formula (forall (A Int) (r Int) (T Int)\n"
" (or\n"
" (not (?f28 T (?f46 A r)))\n"
" (not (or (not (= T (?f46 (?f56 T) r)))\n"
" (not (?f28 (?f56 T) A)))))\n"
" :pat {(?f28 T (?f46 A r))})\n"
"\n"
" :formula (forall (A Int) (r Int) (T Int)\n"
" (or (not (?f28 T (?f53 A r)))\n"
" (= T (?f53 A r)))\n"
" :pat {(?f28 T (?f53 A r))})\n"
"\n"
" :extrafuns ((?f63 Int Int Int)\n"
" (?f64 Int Int Int)\n"
" )\n"
"\n"
" :formula (forall (A Int) (B Int) (C Int)\n"
" (or (not (?f28 C (?f63 B A)))\n"
" (= (?f64 C A) B))\n"
" :pat {(?f28 C (?f63 B A))})\n"
" \n"
" :formula (forall (o Int) (T Int)\n"
" (iff (= (?f47 o T) ?f33)\n"
" (or (= o ?f36)\n"
" (?f28 (?f43 o) T)))\n"
" :pat {(?f47 o T)})\n"
"\n"
" :formula (forall (o Int) (T Int)\n"
" (iff (= (?f51 o T) ?f33)\n"
" (or (= o ?f36)\n"
" (not (= (?f47 o T) ?f33))))\n"
" :pat {(?f51 o T)})\n"
"\n"
" :formula (forall (h Int) (o Int)\n"
" (or (not (= (?f39 h) ?f33))\n"
" (= o ?f36)\n"
" (not (?f28 (?f43 o) ?f57))\n"
" (not (or (not (= (?f26 h o ?f41) (?f43 o)))\n"
" (not (= (?f26 h o ?f40) (?f43 o))))))\n"
" :pat {(?f28 (?f43 o) ?f57) (?f26 h o ?f41)})\n"
"\n"
" :formula (forall (h Int) (o Int) (f Int) (T Int)\n"
" (or (not (= (?f39 h) ?f33))\n"
" (?f62 (?f26 h o (?f60 f T)) T))\n"
" :pat {(?f26 h o (?f60 f T))})\n"
"\n"
" :formula (forall (h Int) (o Int) (f Int)\n"
" (or\n"
" (not (= (?f39 h) ?f33))\n"
" (not (= (?f26 h o ?f58) ?f33))\n"
" (= (?f61 h (?f26 h o f)) ?f33))\n"
" :pat {(?f61 h (?f26 h o f))})\n"
"\n"
" :formula (forall (h Int) (s Int) (f Int)\n"
" (or (not (= (?f61 h s) ?f33))\n"
" (= (?f61 h (?f59 s f)) ?f33))\n"
" :pat {(?f61 h (?f59 s f))})\n"
"\n"
" :extrapreds ((?f65 Int Int))\n"
"\n"
" :formula (forall (x Int) (f Int) (a0 Int)\n"
" (or (<= (+ a0 (* -1 (?f15 f))) 0)\n"
" (not (?f65 x a0))\n"
" (?f65 (?f2 f x) a0))\n"
" :pat {(?f65 (?f2 f x) a0)})\n"
"\n"
" :formula (forall (a Int) (e Int) (i Int) (a0 Int) \n"
" (or (<= (+ a0 (* -1 (?f16 e))) 0)\n"
" (not (?f65 a a0))\n"
" (?f65 (?f2 (?f2 e a) i) a0))\n"
" :pats { (?f65 (?f2 (?f2 e a) i) a0) })\n"
"\n"
" :formula (forall (e Int) (a Int) (i Int) \n"
" (= (?f8 (?f2 (?f2 (?f13 e) a) i)\n"
" (?f7 (?f12 a))) ?f33)\n"
" :pats { (?f2 (?f2 (?f13 e) a) i) })\n"
"\n"
" :formula (forall (t0 Int) (t1 Int)\n"
" (iff (?f28 t0 (?f6 t1))\n"
" (not (or (not (= t0 (?f6 (?f7 t0))))\n"
" (not (?f28 (?f7 t0) t1)))))\n"
" :pat {(?f28 t0 (?f6 t1))})\n"
"\n"
" :formula (forall (t0 Int) (t1 Int) (t2 Int) \n"
" (or (not (?f28 t0 (?f4 t1 t2)))\n"
" (= (?f5 t2 t0) (?f4 t1 t2)))\n"
" :pats { (?f28 t0 (?f4 t1 t2)) })\n"
"\n"
" :formula (forall (t0 Int) (t1 Int) \n"
" (iff (?f28 t0 (?f6 t1))\n"
" (not (or (not (= t0 (?f6 (?f7 t0))))\n"
" (not (?f28 (?f7 t0) t1)))))\n"
" :pats { (?f28 t0 (?f6 t1)) })\n"
"\n"
" :formula (forall (x Int) (t Int) \n"
" (or (not (= (?f8 x t) ?f33))\n"
" (= (?f9 x t) x))\n"
" :pats { (?f9 x t) })\n"
"\n"
" :formula (forall (x Int) (t Int) \n"
" (or (not (?f28 t ?f10))\n"
" (iff (= (?f8 x t) ?f33)\n"
" (or (= x ?f11)\n"
" (?f28 (?f12 x) t))))\n"
" :pats { (?f28 t ?f10) (?f8 x t) })\n"
"\n"
" :formula (forall (e Int) (a Int) (i Int) \n"
" (= (?f8 (?f2 (?f2 (?f13 e) a) i)\n"
" (?f7 (?f12 a))) 1)\n"
" :pats { (?f2 (?f2 (?f13 e) a) i) })\n"
" )\n"
;

View file

@ -1,314 +0,0 @@
(benchmark patterns
:status unknown
:logic ALL
:extrafuns ((?store Int Int Int Int) (?select Int Int Int) (?PO Int Int Int) (?asChild Int Int Int)
(?classDown Int Int Int) (?array Int Int) (?elemtype Int Int) (?is Int Int Int) (?cast Int Int Int)
(?Object Int) (?null Int) (?typeof Int Int) (?asElems Int Int) (?isAllocated Int Int Int)
(?fClosedTime Int Int) (?eClosedTime Int Int) (?max Int Int) (?asLockSet Int Int) (?isNewArray Int Int)
(?classLiteral Int Int) (?Class Int) (?alloc Int) (?arrayType Int) (?f Int Int) (?finv Int Int)
)
:formula (forall (a Int) (i Int) (e Int)
(= (?select (?store a i e) i) e)
:pats { (?store a i e) }
:weight { 0 })
:formula (forall (a Int) (i Int) (j Int) (e Int)
(or (= i j) (= (?select (?store a i e) j) (?select a j)))
:pats { (?select (?store a i e) j) }
:weight { 0 })
:formula (forall (t0 Int) (t1 Int) (t2 Int)
(or (not (= (?PO t0 t1) 1))
(not (= (?PO t1 t2) 1))
(= (?PO t0 t2) 1))
:pats { (?PO t0 t1) (?PO t1 t2) })
:formula (forall (t0 Int) (t1 Int)
(or (not (= (?PO t0 t1) 1))
(not (= (?PO t1 t0) 1))
(= t0 t1))
:pats { (?PO t0 t1) (?PO t1 t0) })
:formula (forall (t0 Int) (t1 Int) (t2 Int)
(or (not (= (?PO t0 (?asChild t1 t2)) 1))
(= (?classDown t2 t0) (?asChild t1 t2)))
:pats { (?PO t0 (?asChild t1 t2)) })
:formula (forall (t Int)
(= (?finv (?f t)) t)
:pats { (?f t) })
:formula (forall (t0 Int) (t1 Int)
(iff (= (?PO t0 (?array t1)) 1)
(not (or (not (= t0 (?array (?elemtype t0))))
(not (= (?PO (?elemtype t0) t1) 1)))))
:pats { (?PO t0 (?array t1)) })
:formula (forall (x Int) (t Int)
(or (not (= (?is x t) 1))
(= (?cast x t) x))
:pats { (?cast x t) })
:formula (forall (x Int) (t Int)
(or (not (= (?PO t ?Object) 1))
(iff (= (?is x t) 1)
(or (= x ?null)
(= (?PO (?typeof x) t) 1))))
:pats { (?PO t ?Object) (?is x t) })
:formula (forall (e Int) (a Int) (i Int)
(= (?is (?select (?select (?asElems e) a) i)
(?elemtype (?typeof a))) 1)
:pats { (?select (?select (?asElems e) a) i) })
:formula (forall (x Int) (f Int) (a0 Int)
(or (<= (+ a0 (* -1 (?fClosedTime f))) 0)
(not (= (?isAllocated x a0) 1))
(= (?isAllocated (?select f x) a0) 1))
:pats { (?isAllocated (?select f x) a0) })
:formula (forall (a Int) (e Int) (i Int) (a0 Int)
(or (<= (+ a0 (* -1 (?eClosedTime e))) 0)
(not (= (?isAllocated a a0) 1))
(= (?isAllocated (?select (?select e a) i) a0) 1))
:pats { (?isAllocated (?select (?select e a) i) a0) })
:formula (forall (S Int)
(= (?select (?asLockSet S) (?max (?asLockSet S))) 1)
:pats { (?select (?asLockSet S) (?max (?asLockSet S))) })
:formula (forall (s Int)
(or (not (= 1 (?isNewArray s)))
(= (?PO (?typeof s) ?arrayType) 1))
:pats { (?isNewArray s) })
:formula (forall (t Int)
(not (or (= (?classLiteral t) ?null)
(not (= (?is (?classLiteral t) ?Class) 1))
(not (= (?isAllocated (?classLiteral t) ?alloc) 1))))
:pats { (?classLiteral t) })
:extrafuns ((?select2 Int Int Int Int)
(?store2 Int Int Int Int Int))
:formula (forall (A Int) (o Int) (f Int) (v Int)
(= (?select2 (?store2 A o f v) o f) v)
:pats { (?store2 A o f v) }
:weight { 0 })
:formula (forall (A Int) (o Int) (f Int) (p Int) (g Int) (v Int)
(or (= o p) (= (?select2 (?store2 A o f v) p g) (?select2 A p g)))
:pats { (?select2 (?store2 A o f v) p g) }
:weight { 0 })
:formula (forall (A Int) (o Int) (f Int) (p Int) (g Int) (v Int)
(or (= f g) (= (?select2 (?store2 A o f v) p g) (?select2 A p g)))
:pats { (?select2 (?store2 A o f v) p g) }
:weight { 0 })
:extrapreds ((?subtypes Int Int))
:formula (forall (t Int) (u Int) (v Int)
(or (not (?subtypes t u))
(not (?subtypes u v))
(?subtypes t v))
:pat {(?subtypes t u) (?subtypes u v)})
:formula (forall (t Int) (u Int)
(or (not (?subtypes t u))
(not (?subtypes u t))
(= t u))
:pat {(?subtypes t u) (?subtypes u t)})
:extrafuns ((?Unbox Int Int) (?UnboxedType Int Int) (?Box Int Int Int) (?System.Object Int) (?Smt.true Int) (?AsRepField Int Int Int)
(?AsPeerField Int Int) (?nullObject Int) (?ownerRef_ Int) (?ownerFrame_ Int) (IntsHeap Int Int) (?localinv_ Int)
(?inv_ Int) (?BaseClass_ Int Int) (?typeof_ Int Int) (?PeerGroupPlaceholder_ Int) (?ClassRepr Int Int))
:formula (forall (x Int) (p Int)
(or (not (?subtypes (?UnboxedType (?Box x p)) ?System.Object))
(not (= (?Box x p) p))
(= x p))
:pat { (?subtypes (?UnboxedType (?Box x p)) ?System.Object)} )
:formula (forall (h Int) (o Int) (f Int) (T Int)
(or
(not (= (IntsHeap h) ?Smt.true))
(= (?select2 h o (?AsRepField f T)) ?nullObject)
(not (or (not (= (?select2 h (?select2 h o (?AsRepField f T)) ?ownerRef_) o))
(not (= (?select2 h (?select2 h o (?AsRepField f T)) ?ownerFrame_) T)))))
:pat {(?select2 h o (?AsRepField f T))})
:formula (forall (h Int) (o Int) (f Int)
(or
(not (= (IntsHeap h) ?Smt.true))
(= (?select2 h o (?AsPeerField f)) ?nullObject)
(not (or (not (= (?select2 h (?select2 h o (?AsPeerField f)) ?ownerRef_) (?select2 h o ?ownerRef_)))
(not (= (?select2 h (?select2 h o (?AsPeerField f)) ?ownerFrame_) (?select2 h o ?ownerFrame_))))))
:pat {(?select2 h o (?AsPeerField f))})
:formula (forall (h Int) (o Int)
(or
(not (= (IntsHeap h) ?Smt.true))
(= (?select2 h o ?ownerFrame_) ?PeerGroupPlaceholder_)
(not (?subtypes (?select2 h (?select2 h o ?ownerRef_) ?inv_) (?select2 h o ?ownerFrame_)))
(= (?select2 h (?select2 h o ?ownerRef_) ?localinv_) (?BaseClass_ (?select2 h o ?ownerFrame_)))
(not (or (not (= (?select2 h o ?inv_) (?typeof_ o)))
(not (= (?select2 h o ?localinv_) (?typeof_ o))))))
:pat {(?subtypes (?select2 h (?select2 h o ?ownerRef_) ?inv_) (?select2 h o ?ownerFrame_))})
:formula (forall (T Int) (h Int)
(or (not (= (IntsHeap h) ?Smt.true))
(= (?select2 h (?ClassRepr T) ?ownerFrame_) ?PeerGroupPlaceholder_))
:pat {(?select2 h (?ClassRepr T) ?ownerFrame_)})
:extrafuns ((?RefArray Int Int Int)
(Ints_ Int Int Int)
(?RefArrayGet Int Int Int)
(?elements_ Int)
(?NonNullRefArray Int Int Int)
(IntsNotNull_ Int Int Int)
(?Rank_ Int Int)
)
:formula (forall (a Int) (T Int) (i Int) (r Int) (heap Int)
(or (not (= (IntsHeap heap) ?Smt.true))
(not (?subtypes (?typeof_ a) (?RefArray T r)))
(= (Ints_ (?RefArrayGet (?select2 heap a ?elements_) i) T) ?Smt.true))
:pat {(?subtypes (?typeof_ a) (?RefArray T r)) (?RefArrayGet (?select2 heap a ?elements_) i)})
:formula (forall (a Int) (T Int) (r Int)
(or (= a ?nullObject)
(not (?subtypes (?typeof_ a) (?RefArray T r)))
(= (?Rank_ a) r))
:pat {(?subtypes (?typeof_ a) (?RefArray T r))})
:extrafuns ((?ValueArray Int Int Int)
(?ArrayCategory_ Int Int)
(?ArrayCategoryValue_ Int)
(?ElementType_ Int Int)
(?System.Array Int)
(?allocated_ Int)
(?StructGet_ Int Int Int)
(?AsRangeField Int Int Int)
(IntsAllocated Int Int Int)
)
:extrapreds ((IntnRange Int Int))
:formula (forall (T Int) (ET Int) (r Int)
(or (not (?subtypes T (?ValueArray ET r)))
(= (?ArrayCategory_ T) ?ArrayCategoryValue_))
:pat {(?subtypes T (?ValueArray ET r))})
:formula (forall (A Int) (r Int) (T Int)
(or
(not (?subtypes T (?RefArray A r)))
(not (or (not (= T (?RefArray (?ElementType_ T) r)))
(not (?subtypes (?ElementType_ T) A)))))
:pat {(?subtypes T (?RefArray A r))})
:formula (forall (A Int) (r Int) (T Int)
(or (not (?subtypes T (?ValueArray A r)))
(= T (?ValueArray A r)))
:pat {(?subtypes T (?ValueArray A r))})
:extrafuns ((?AsDirectSubClass Int Int Int)
(?OneClassDown Int Int Int)
)
:formula (forall (A Int) (B Int) (C Int)
(or (not (?subtypes C (?AsDirectSubClass B A)))
(= (?OneClassDown C A) B))
:pat {(?subtypes C (?AsDirectSubClass B A))})
:formula (forall (o Int) (T Int)
(iff (= (Ints_ o T) ?Smt.true)
(or (= o ?nullObject)
(?subtypes (?typeof_ o) T)))
:pat {(Ints_ o T)})
:formula (forall (o Int) (T Int)
(iff (= (IntsNotNull_ o T) ?Smt.true)
(or (= o ?nullObject)
(not (= (Ints_ o T) ?Smt.true))))
:pat {(IntsNotNull_ o T)})
:formula (forall (h Int) (o Int)
(or (not (= (IntsHeap h) ?Smt.true))
(= o ?nullObject)
(not (?subtypes (?typeof_ o) ?System.Array))
(not (or (not (= (?select2 h o ?inv_) (?typeof_ o)))
(not (= (?select2 h o ?localinv_) (?typeof_ o))))))
:pat {(?subtypes (?typeof_ o) ?System.Array) (?select2 h o ?inv_)})
:formula (forall (h Int) (o Int) (f Int) (T Int)
(or (not (= (IntsHeap h) ?Smt.true))
(IntnRange (?select2 h o (?AsRangeField f T)) T))
:pat {(?select2 h o (?AsRangeField f T))})
:formula (forall (h Int) (o Int) (f Int)
(or
(not (= (IntsHeap h) ?Smt.true))
(not (= (?select2 h o ?allocated_) ?Smt.true))
(= (IntsAllocated h (?select2 h o f)) ?Smt.true))
:pat {(IntsAllocated h (?select2 h o f))})
:formula (forall (h Int) (s Int) (f Int)
(or (not (= (IntsAllocated h s) ?Smt.true))
(= (IntsAllocated h (?StructGet_ s f)) ?Smt.true))
:pat {(IntsAllocated h (?StructGet_ s f))})
:extrapreds ((?isAllocated_ Int Int))
:formula (forall (x Int) (f Int) (a0 Int)
(or (<= (+ a0 (* -1 (?fClosedTime f))) 0)
(not (?isAllocated_ x a0))
(?isAllocated_ (?select f x) a0))
:pat {(?isAllocated_ (?select f x) a0)})
:formula (forall (a Int) (e Int) (i Int) (a0 Int)
(or (<= (+ a0 (* -1 (?eClosedTime e))) 0)
(not (?isAllocated_ a a0))
(?isAllocated_ (?select (?select e a) i) a0))
:pats { (?isAllocated_ (?select (?select e a) i) a0) })
:formula (forall (e Int) (a Int) (i Int)
(= (?is (?select (?select (?asElems e) a) i)
(?elemtype (?typeof a))) ?Smt.true)
:pats { (?select (?select (?asElems e) a) i) })
:formula (forall (t0 Int) (t1 Int)
(iff (?subtypes t0 (?array t1))
(not (or (not (= t0 (?array (?elemtype t0))))
(not (?subtypes (?elemtype t0) t1)))))
:pat {(?subtypes t0 (?array t1))})
:formula (forall (t0 Int) (t1 Int) (t2 Int)
(or (not (?subtypes t0 (?asChild t1 t2)))
(= (?classDown t2 t0) (?asChild t1 t2)))
:pats { (?subtypes t0 (?asChild t1 t2)) })
:formula (forall (t0 Int) (t1 Int)
(iff (?subtypes t0 (?array t1))
(not (or (not (= t0 (?array (?elemtype t0))))
(not (?subtypes (?elemtype t0) t1)))))
:pats { (?subtypes t0 (?array t1)) })
:formula (forall (x Int) (t Int)
(or (not (= (?is x t) ?Smt.true))
(= (?cast x t) x))
:pats { (?cast x t) })
:formula (forall (x Int) (t Int)
(or (not (?subtypes t ?Object))
(iff (= (?is x t) ?Smt.true)
(or (= x ?null)
(?subtypes (?typeof x) t))))
:pats { (?subtypes t ?Object) (?is x t) })
:formula (forall (e Int) (a Int) (i Int)
(= (?is (?select (?select (?asElems e) a) i)
(?elemtype (?typeof a))) 1)
:pats { (?select (?select (?asElems e) a) i) })
)

View file

@ -1,226 +0,0 @@
/*++
Copyright (c) 2006 Microsoft Corporation
Module Name:
defined_names.cpp
Abstract:
<abstract>
Author:
Leonardo de Moura (leonardo) 2008-01-14.
Revision History:
--*/
#include"defined_names.h"
#include"used_vars.h"
#include"var_subst.h"
#include"ast_smt2_pp.h"
#include"ast_pp.h"
defined_names::impl::impl(ast_manager & m, char const * prefix):
m_manager(m),
m_exprs(m),
m_names(m),
m_apply_proofs(m) {
if (prefix)
m_z3name = prefix;
}
defined_names::impl::~impl() {
}
/**
\brief Given an expression \c e that may contain free variables, return an application (sk x_1 ... x_n),
where sk is a fresh variable name, and x_i's are the free variables of \c e.
Store in var_sorts and var_names information about the free variables of \c e. This data
is used to create an universal quantifier over the definition of the new name.
*/
app * defined_names::impl::gen_name(expr * e, sort_ref_buffer & var_sorts, buffer<symbol> & var_names) {
used_vars uv;
uv(e);
unsigned num_vars = uv.get_max_found_var_idx_plus_1();
ptr_buffer<expr> new_args;
ptr_buffer<sort> domain;
for (unsigned i = 0; i < num_vars; i++) {
sort * s = uv.get(i);
if (s) {
domain.push_back(s);
new_args.push_back(m_manager.mk_var(i, s));
var_sorts.push_back(s);
}
else {
var_sorts.push_back(m_manager.mk_bool_sort()); // could be any sort.
}
var_names.push_back(symbol(i));
}
sort * range = m_manager.get_sort(e);
func_decl * new_skolem_decl = m_manager.mk_fresh_func_decl(m_z3name, symbol::null, domain.size(), domain.c_ptr(), range);
app * n = m_manager.mk_app(new_skolem_decl, new_args.size(), new_args.c_ptr());
TRACE("mk_definition_bug", tout << "gen_name: " << mk_ismt2_pp(n, m_manager) << "\n";
for (unsigned i = 0; i < var_sorts.size(); i++) tout << mk_pp(var_sorts[i], m_manager) << " ";
tout << "\n";);
return n;
}
/**
\brief Cache \c n as a name for expression \c e.
*/
void defined_names::impl::cache_new_name(expr * e, app * n) {
m_expr2name.insert(e, n);
m_exprs.push_back(e);
m_names.push_back(n);
}
/**
\brief Cache \c pr as a proof that m_expr2name[e] is a name for expression \c e.
*/
void defined_names::impl::cache_new_name_intro_proof(expr * e, proof * pr) {
SASSERT(m_expr2name.contains(e));
m_expr2proof.insert(e, pr);
m_apply_proofs.push_back(pr);
}
/**
\brief Given a definition conjunct \c def of the name \c name, store in \c result this definition.
A quantifier is added around \c def_conjunct, if sorts and names are not empty.
In this case, The application \c name is used as a pattern for the new quantifier.
*/
void defined_names::impl::bound_vars(sort_ref_buffer const & sorts, buffer<symbol> const & names, expr * def_conjunct, app * name, expr_ref & result) {
SASSERT(sorts.size() == names.size());
if (sorts.empty())
result = def_conjunct;
else {
expr * patterns[1] = { m_manager.mk_pattern(name) };
quantifier_ref q(m_manager);
q = m_manager.mk_forall(sorts.size(),
sorts.c_ptr(),
names.c_ptr(),
def_conjunct,
1, symbol::null, symbol::null,
1, patterns);
TRACE("mk_definition_bug", tout << "before elim_unused_vars:\n" << mk_ismt2_pp(q, m_manager) << "\n";);
elim_unused_vars(m_manager, q, result);
TRACE("mk_definition_bug", tout << "after elim_unused_vars:\n" << mk_ismt2_pp(result, m_manager) << "\n";);
}
}
/**
\brief Given a definition conjunct \c def of the name \c name, store in \c result this definition.
A quantifier is added around \c def_conjunct, if sorts and names are not empty.
In this case, The application \c name is used as a pattern for the new quantifier.
*/
void defined_names::impl::bound_vars(sort_ref_buffer const & sorts, buffer<symbol> const & names, expr * def_conjunct, app * name, expr_ref_buffer & result) {
expr_ref tmp(m_manager);
bound_vars(sorts, names, def_conjunct, name, tmp);
result.push_back(tmp);
}
#define MK_OR m_manager.mk_or
#define MK_NOT m_manager.mk_not
#define MK_EQ m_manager.mk_eq
void defined_names::impl::mk_definition(expr * e, app * n, sort_ref_buffer & var_sorts, buffer<symbol> const & var_names, expr_ref & new_def) {
expr_ref_buffer defs(m_manager);
if (m_manager.is_bool(e)) {
bound_vars(var_sorts, var_names, MK_OR(MK_NOT(n), e), n, defs);
bound_vars(var_sorts, var_names, MK_OR(n, MK_NOT(e)), n, defs);
}
else if (m_manager.is_term_ite(e)) {
bound_vars(var_sorts, var_names, MK_OR(MK_NOT(to_app(e)->get_arg(0)), MK_EQ(n, to_app(e)->get_arg(1))), n, defs);
bound_vars(var_sorts, var_names, MK_OR(to_app(e)->get_arg(0), MK_EQ(n, to_app(e)->get_arg(2))), n, defs);
}
else {
bound_vars(var_sorts, var_names, MK_EQ(e, n), n, defs);
}
new_def = defs.size() == 1 ? defs[0] : m_manager.mk_and(defs.size(), defs.c_ptr());
}
void defined_names::pos_impl::mk_definition(expr * e, app * n, sort_ref_buffer & var_sorts, buffer<symbol> const & var_names, expr_ref & new_def) {
bound_vars(var_sorts, var_names, MK_OR(MK_NOT(n), e), n, new_def);
}
bool defined_names::impl::mk_name(expr * e, expr_ref & new_def, proof_ref & new_def_pr, app_ref & n, proof_ref & pr) {
TRACE("mk_definition_bug", tout << "making name for:\n" << mk_ismt2_pp(e, m_manager) << "\n";);
app * n_ptr;
if (m_expr2name.find(e, n_ptr)) {
TRACE("mk_definition_bug", tout << "name for expression is already cached..., returning false...\n";);
n = n_ptr;
if (m_manager.proofs_enabled()) {
proof * pr_ptr;
m_expr2proof.find(e, pr_ptr);
SASSERT(pr_ptr);
pr = pr_ptr;
}
return false;
}
else {
sort_ref_buffer var_sorts(m_manager);
buffer<symbol> var_names;
n = gen_name(e, var_sorts, var_names);
cache_new_name(e, n);
TRACE("mk_definition_bug", tout << "name: " << mk_ismt2_pp(n, m_manager) << "\n";);
// variables are in reverse order in quantifiers
std::reverse(var_sorts.c_ptr(), var_sorts.c_ptr() + var_sorts.size());
std::reverse(var_names.c_ptr(), var_names.c_ptr() + var_names.size());
mk_definition(e, n, var_sorts, var_names, new_def);
TRACE("mk_definition_bug", tout << "new_def:\n" << mk_ismt2_pp(new_def, m_manager) << "\n";);
if (m_manager.proofs_enabled()) {
new_def_pr = m_manager.mk_def_intro(new_def);
pr = m_manager.mk_apply_def(e, n, new_def_pr);
cache_new_name_intro_proof(e, pr);
}
return true;
}
}
void defined_names::impl::push_scope() {
SASSERT(m_exprs.size() == m_names.size());
m_lims.push_back(m_exprs.size());
}
void defined_names::impl::pop_scope(unsigned num_scopes) {
unsigned lvl = m_lims.size();
SASSERT(num_scopes <= lvl);
unsigned new_lvl = lvl - num_scopes;
unsigned old_sz = m_lims[new_lvl];
unsigned sz = m_exprs.size();
SASSERT(old_sz <= sz);
SASSERT(sz == m_names.size());
while (old_sz != sz) {
--sz;
if (m_manager.proofs_enabled()) {
m_expr2proof.erase(m_exprs.back());
m_apply_proofs.pop_back();
}
m_expr2name.erase(m_exprs.back());
m_exprs.pop_back();
m_names.pop_back();
}
SASSERT(m_exprs.size() == old_sz);
m_lims.shrink(new_lvl);
}
void defined_names::impl::reset() {
m_expr2name.reset();
m_expr2proof.reset();
m_exprs.reset();
m_names.reset();
m_apply_proofs.reset();
m_lims.reset();
}

View file

@ -1,151 +0,0 @@
/*++
Copyright (c) 2006 Microsoft Corporation
Module Name:
defined_names.h
Abstract:
In some transformations, we need to name expressions.
These expressions are stored in a table.
Author:
Leonardo de Moura (leonardo) 2008-01-14.
Revision History:
--*/
#ifndef _DEFINED_NAMES_H_
#define _DEFINED_NAMES_H_
#include"ast.h"
#include"obj_hashtable.h"
/**
\brief Mapping from expressions to skolem functions that are used to name them.
The mapping supports backtracking using the methods #push_scope and #pop_scope.
*/
class defined_names {
struct impl {
typedef obj_map<expr, app *> expr2name;
typedef obj_map<expr, proof *> expr2proof;
ast_manager & m_manager;
symbol m_z3name;
/**
\brief Mapping from expressions to their names. A name is an application.
If the expression does not have free variables, then the name is just a constant.
*/
expr2name m_expr2name;
/**
\brief Mapping from expressions to the apply-def proof.
That is, for each expression e, m_expr2proof[e] is the
proof e and m_expr2name[2] are observ. equivalent.
This mapping is not used if proof production is disabled.
*/
expr2proof m_expr2proof;
/**
\brief Domain of m_expr2name. It is used to keep the expressions
alive and for backtracking
*/
expr_ref_vector m_exprs;
expr_ref_vector m_names; //!< Range of m_expr2name. It is used to keep the names alive.
proof_ref_vector m_apply_proofs; //!< Range of m_expr2proof. It is used to keep the def-intro proofs alive.
unsigned_vector m_lims; //!< Backtracking support.
impl(ast_manager & m, char const * prefix);
virtual ~impl();
app * gen_name(expr * e, sort_ref_buffer & var_sorts, buffer<symbol> & var_names);
void cache_new_name(expr * e, app * name);
void cache_new_name_intro_proof(expr * e, proof * pr);
void bound_vars(sort_ref_buffer const & sorts, buffer<symbol> const & names, expr * def_conjunct, app * name, expr_ref & result);
void bound_vars(sort_ref_buffer const & sorts, buffer<symbol> const & names, expr * def_conjunct, app * name, expr_ref_buffer & result);
virtual void mk_definition(expr * e, app * n, sort_ref_buffer & var_sorts, buffer<symbol> const & var_names, expr_ref & new_def);
bool mk_name(expr * e, expr_ref & new_def, proof_ref & new_def_pr, app_ref & n, proof_ref & pr);
void push_scope();
void pop_scope(unsigned num_scopes);
void reset();
};
struct pos_impl : public impl {
pos_impl(ast_manager & m, char const * fresh_prefix):impl(m, fresh_prefix) {}
virtual void mk_definition(expr * e, app * n, sort_ref_buffer & var_sorts, buffer<symbol> const & var_names, expr_ref & new_def);
};
impl m_impl;
pos_impl m_pos_impl;
public:
defined_names(ast_manager & m, char const * fresh_prefix = "z3name"):m_impl(m, fresh_prefix), m_pos_impl(m, fresh_prefix) {}
// -----------------------------------
//
// High-level API
//
// -----------------------------------
/**
\brief Create a name for expression \c e if it doesn't already exists.
Return true if a new name was created, and false if a name already exists for \c e.
The resultant new name is stored in n, and a [apply-def] proof
that (= e n) is stored into pr.
If true is returned, then the definition of the new name is
stored into new_def, and a [def-intro] proof into new_def_pr.
The proofs are not produced when proof generation is disabled.
The definition of an expression e with name n is:
- (and (or (not e) n) (or e (not n))) if e is an formula.
- (and (or (not c) (= n t1)) (or c (= n t2))) if e is an if-then-else term of the form (ite c t1 t2)
- (= n e) if e is a term.
Remark: the definitions are closed with an universal quantifier if e contains free variables.
*/
bool mk_name(expr * e, expr_ref & new_def, proof_ref & new_def_pr, app_ref & n, proof_ref & pr) {
return m_impl.mk_name(e, new_def, new_def_pr, n, pr);
}
/**
\brief Create a name for a positive occurrence of the expression \c e.
Return true if a new pos-name was created, and false if a pos-name already exists for \c e.
If true is returned, then the definition of the new name is stored into new_def.
It has the form: (or (not n) e)
Remark: the definitions are closed with an universal quantifier if e contains free variables.
*/
bool mk_pos_name(expr * e, expr_ref & new_def, proof_ref & new_def_pr, app_ref & n, proof_ref & pr) {
return m_pos_impl.mk_name(e, new_def, new_def_pr, n, pr);
}
void push_scope() {
m_impl.push_scope();
m_pos_impl.push_scope();
}
void pop_scope(unsigned num_scopes) {
m_impl.pop_scope(num_scopes);
m_pos_impl.pop_scope(num_scopes);
}
void reset() {
m_impl.reset();
m_pos_impl.reset();
}
};
#endif /* _DEFINED_NAMES_H_ */

View file

@ -1,639 +0,0 @@
/*++
Copyright (c) 2006 Microsoft Corporation
Module Name:
der.cpp
Abstract:
<abstract>
Author:
Leonardo de Moura (leonardo) 2008-01-27.
Revision History:
Christoph Wintersteiger, 2010-03-30: Added Destr. Multi-Equality Resolution
--*/
#include"der.h"
#include"occurs.h"
#include"for_each_expr.h"
#include"rewriter_def.h"
#include"ast_pp.h"
#include"ast_ll_pp.h"
#include"ast_smt2_pp.h"
#include"tactical.h"
static bool is_var(expr * e, unsigned num_decls) {
return is_var(e) && to_var(e)->get_idx() < num_decls;
}
static bool is_neg_var(ast_manager & m, expr * e, unsigned num_decls) {
return m.is_not(e) && is_var(to_app(e)->get_arg(0)) && to_var(to_app(e)->get_arg(0))->get_idx() < num_decls;
}
/**
\brief Return true if \c e is of the form (not (= VAR t)) or (not (iff VAR t)) or (iff VAR t) or (iff (not VAR) t) or (VAR IDX) or (not (VAR IDX)).
The last case can be viewed
*/
bool der::is_var_diseq(expr * e, unsigned num_decls, var * & v, expr_ref & t) {
// (not (= VAR t)) and (not (iff VAR t)) cases
if (m_manager.is_not(e) && (m_manager.is_eq(to_app(e)->get_arg(0)) || m_manager.is_iff(to_app(e)->get_arg(0)))) {
app * eq = to_app(to_app(e)->get_arg(0));
SASSERT(m_manager.is_eq(eq) || m_manager.is_iff(eq));
expr * lhs = eq->get_arg(0);
expr * rhs = eq->get_arg(1);
if (!is_var(lhs, num_decls) && !is_var(rhs, num_decls))
return false;
if (!is_var(lhs, num_decls))
std::swap(lhs, rhs);
SASSERT(is_var(lhs, num_decls));
// Remark: Occurs check is not necessary here... the top-sort procedure will check for cycles...
// if (occurs(lhs, rhs)) {
// return false;
// }
v = to_var(lhs);
t = rhs;
TRACE("der", tout << mk_pp(e, m_manager) << "\n";);
return true;
}
// (iff VAR t) and (iff (not VAR) t) cases
else if (m_manager.is_iff(e)) {
expr * lhs = to_app(e)->get_arg(0);
expr * rhs = to_app(e)->get_arg(1);
// (iff VAR t) case
if (is_var(lhs, num_decls) || is_var(rhs, num_decls)) {
if (!is_var(lhs, num_decls))
std::swap(lhs, rhs);
SASSERT(is_var(lhs, num_decls));
// Remark: Occurs check is not necessary here... the top-sort procedure will check for cycles...
// if (occurs(lhs, rhs)) {
// return false;
// }
v = to_var(lhs);
t = m_manager.mk_not(rhs);
m_new_exprs.push_back(t);
TRACE("der", tout << mk_pp(e, m_manager) << "\n";);
return true;
}
// (iff (not VAR) t) case
else if (is_neg_var(m_manager, lhs, num_decls) || is_neg_var(m_manager, rhs, num_decls)) {
if (!is_neg_var(m_manager, lhs, num_decls))
std::swap(lhs, rhs);
SASSERT(is_neg_var(m_manager, lhs, num_decls));
expr * lhs_var = to_app(lhs)->get_arg(0);
// Remark: Occurs check is not necessary here... the top-sort procedure will check for cycles...
// if (occurs(lhs_var, rhs)) {
// return false;
// }
v = to_var(lhs_var);
t = rhs;
TRACE("der", tout << mk_pp(e, m_manager) << "\n";);
return true;
}
else {
return false;
}
}
// VAR != false case
else if (is_var(e, num_decls)) {
t = m_manager.mk_false();
v = to_var(e);
TRACE("der", tout << mk_pp(e, m_manager) << "\n";);
return true;
}
// VAR != true case
else if (is_neg_var(m_manager, e, num_decls)) {
t = m_manager.mk_true();
v = to_var(to_app(e)->get_arg(0));
TRACE("der", tout << mk_pp(e, m_manager) << "\n";);
return true;
}
else {
return false;
}
}
void der::operator()(quantifier * q, expr_ref & r, proof_ref & pr) {
bool reduced = false;
pr = 0;
r = q;
TRACE("der", tout << mk_pp(q, m_manager) << "\n";);
// Keep applying it until r doesn't change anymore
do {
proof_ref curr_pr(m_manager);
q = to_quantifier(r);
reduce1(q, r, curr_pr);
if (q != r)
reduced = true;
if (m_manager.proofs_enabled()) {
pr = m_manager.mk_transitivity(pr, curr_pr);
}
} while (q != r && is_quantifier(r));
// Eliminate variables that have become unused
if (reduced && is_forall(r)) {
quantifier * q = to_quantifier(r);
elim_unused_vars(m_manager, q, r);
if (m_manager.proofs_enabled()) {
proof * p1 = m_manager.mk_elim_unused_vars(q, r);
pr = m_manager.mk_transitivity(pr, p1);
}
}
m_new_exprs.reset();
}
void der::reduce1(quantifier * q, expr_ref & r, proof_ref & pr) {
if (!is_forall(q)) {
pr = 0;
r = q;
return;
}
expr * e = q->get_expr();
unsigned num_decls = q->get_num_decls();
var * v = 0;
expr_ref t(m_manager);
if (m_manager.is_or(e)) {
unsigned num_args = to_app(e)->get_num_args();
unsigned i = 0;
unsigned diseq_count = 0;
unsigned largest_vinx = 0;
m_map.reset();
m_pos2var.reset();
m_inx2var.reset();
m_pos2var.reserve(num_args, -1);
// Find all disequalities
for (; i < num_args; i++) {
if (is_var_diseq(to_app(e)->get_arg(i), num_decls, v, t)) {
unsigned idx = v->get_idx();
if(m_map.get(idx, 0) == 0) {
m_map.reserve(idx + 1, 0);
m_inx2var.reserve(idx + 1, 0);
m_map[idx] = t;
m_inx2var[idx] = v;
m_pos2var[i] = idx;
diseq_count++;
largest_vinx = (idx>largest_vinx) ? idx : largest_vinx;
}
}
}
if (diseq_count > 0) {
get_elimination_order();
SASSERT(m_order.size() <= diseq_count); // some might be missing because of cycles
if (!m_order.empty()) {
create_substitution(largest_vinx + 1);
apply_substitution(q, r);
}
}
else {
TRACE("der_bug", tout << "Did not find any diseq\n" << mk_pp(q, m_manager) << "\n";);
r = q;
}
}
// Remark: get_elimination_order/top-sort checks for cycles, but it is not invoked for unit clauses.
// So, we must perform a occurs check here.
else if (is_var_diseq(e, num_decls, v, t) && !occurs(v, t)) {
r = m_manager.mk_false();
}
else
r = q;
if (m_manager.proofs_enabled()) {
pr = r == q ? 0 : m_manager.mk_der(q, r);
}
}
void der_sort_vars(ptr_vector<var> & vars, ptr_vector<expr> & definitions, unsigned_vector & order) {
order.reset();
// eliminate self loops, and definitions containing quantifiers.
bool found = false;
for (unsigned i = 0; i < definitions.size(); i++) {
var * v = vars[i];
expr * t = definitions[i];
if (t == 0 || has_quantifiers(t) || occurs(v, t))
definitions[i] = 0;
else
found = true; // found at least one candidate
}
if (!found)
return;
typedef std::pair<expr *, unsigned> frame;
svector<frame> todo;
expr_fast_mark1 visiting;
expr_fast_mark2 done;
unsigned vidx, num;
for (unsigned i = 0; i < definitions.size(); i++) {
if (definitions[i] == 0)
continue;
var * v = vars[i];
SASSERT(v->get_idx() == i);
SASSERT(todo.empty());
todo.push_back(frame(v, 0));
while (!todo.empty()) {
start:
frame & fr = todo.back();
expr * t = fr.first;
if (t->get_ref_count() > 1 && done.is_marked(t)) {
todo.pop_back();
continue;
}
switch (t->get_kind()) {
case AST_VAR:
vidx = to_var(t)->get_idx();
if (fr.second == 0) {
CTRACE("der_bug", vidx >= definitions.size(), tout << "vidx: " << vidx << "\n";);
// Remark: The size of definitions may be smaller than the number of variables occuring in the quantified formula.
if (definitions.get(vidx, 0) != 0) {
if (visiting.is_marked(t)) {
// cycle detected: remove t
visiting.reset_mark(t);
definitions[vidx] = 0;
}
else {
visiting.mark(t);
fr.second = 1;
todo.push_back(frame(definitions[vidx], 0));
goto start;
}
}
}
else {
SASSERT(fr.second == 1);
if (definitions.get(vidx, 0) != 0) {
visiting.reset_mark(t);
order.push_back(vidx);
}
else {
// var was removed from the list of candidate vars to elim cycle
// do nothing
}
}
if (t->get_ref_count() > 1)
done.mark(t);
todo.pop_back();
break;
case AST_QUANTIFIER:
UNREACHABLE();
todo.pop_back();
break;
case AST_APP:
num = to_app(t)->get_num_args();
while (fr.second < num) {
expr * arg = to_app(t)->get_arg(fr.second);
fr.second++;
if (arg->get_ref_count() > 1 && done.is_marked(arg))
continue;
todo.push_back(frame(arg, 0));
goto start;
}
if (t->get_ref_count() > 1)
done.mark(t);
todo.pop_back();
break;
default:
UNREACHABLE();
todo.pop_back();
break;
}
}
}
}
void der::get_elimination_order() {
m_order.reset();
TRACE("top_sort",
tout << "DEFINITIONS: " << std::endl;
for(unsigned i = 0; i < m_map.size(); i++)
if(m_map[i]) tout << "VAR " << i << " = " << mk_pp(m_map[i], m_manager) << std::endl;
);
// der::top_sort ts(m_manager);
der_sort_vars(m_inx2var, m_map, m_order);
TRACE("der",
tout << "Elimination m_order:" << std::endl;
for(unsigned i=0; i<m_order.size(); i++)
{
if (i != 0) tout << ",";
tout << m_order[i];
}
tout << std::endl;
);
}
void der::create_substitution(unsigned sz) {
m_subst_map.reset();
m_subst_map.resize(sz, 0);
for(unsigned i = 0; i < m_order.size(); i++) {
expr_ref cur(m_map[m_order[i]], m_manager);
// do all the previous substitutions before inserting
expr_ref r(m_manager);
m_subst(cur, m_subst_map.size(), m_subst_map.c_ptr(), r);
unsigned inx = sz - m_order[i]- 1;
SASSERT(m_subst_map[inx]==0);
m_subst_map[inx] = r;
}
}
void der::apply_substitution(quantifier * q, expr_ref & r) {
expr * e = q->get_expr();
unsigned num_args=to_app(e)->get_num_args();
// get a new expression
m_new_args.reset();
for(unsigned i = 0; i < num_args; i++) {
int x = m_pos2var[i];
if (x != -1 && m_map[x] != 0)
continue; // this is a disequality with definition (vanishes)
m_new_args.push_back(to_app(e)->get_arg(i));
}
unsigned sz = m_new_args.size();
expr_ref t(m_manager);
t = (sz == 1) ? m_new_args[0] : m_manager.mk_or(sz, m_new_args.c_ptr());
expr_ref new_e(m_manager);
m_subst(t, m_subst_map.size(), m_subst_map.c_ptr(), new_e);
// don't forget to update the quantifier patterns
expr_ref_buffer new_patterns(m_manager);
expr_ref_buffer new_no_patterns(m_manager);
for (unsigned j = 0; j < q->get_num_patterns(); j++) {
expr_ref new_pat(m_manager);
m_subst(q->get_pattern(j), m_subst_map.size(), m_subst_map.c_ptr(), new_pat);
new_patterns.push_back(new_pat);
}
for (unsigned j = 0; j < q->get_num_no_patterns(); j++) {
expr_ref new_nopat(m_manager);
m_subst(q->get_no_pattern(j), m_subst_map.size(), m_subst_map.c_ptr(), new_nopat);
new_no_patterns.push_back(new_nopat);
}
r = m_manager.update_quantifier(q, new_patterns.size(), new_patterns.c_ptr(),
new_no_patterns.size(), new_no_patterns.c_ptr(), new_e);
}
struct der_rewriter_cfg : public default_rewriter_cfg {
der m_der;
der_rewriter_cfg(ast_manager & m):m_der(m) {}
ast_manager & m() const { return m_der.m(); }
bool reduce_quantifier(quantifier * old_q,
expr * new_body,
expr * const * new_patterns,
expr * const * new_no_patterns,
expr_ref & result,
proof_ref & result_pr) {
quantifier_ref q1(m());
q1 = m().update_quantifier(old_q, old_q->get_num_patterns(), new_patterns, old_q->get_num_no_patterns(), new_no_patterns, new_body);
m_der(q1, result, result_pr);
return true;
}
};
template class rewriter_tpl<der_rewriter_cfg>;
struct der_rewriter::imp : public rewriter_tpl<der_rewriter_cfg> {
der_rewriter_cfg m_cfg;
imp(ast_manager & m):
rewriter_tpl<der_rewriter_cfg>(m, m.proofs_enabled(), m_cfg),
m_cfg(m) {
}
};
der_rewriter::der_rewriter(ast_manager & m) {
m_imp = alloc(imp, m);
}
der_rewriter::~der_rewriter() {
dealloc(m_imp);
}
ast_manager & der_rewriter::m() const {
return m_imp->m();
}
void der_rewriter::operator()(expr * t, expr_ref & result, proof_ref & result_pr) {
m_imp->operator()(t, result, result_pr);
}
void der_rewriter::set_cancel(bool f) {
#pragma omp critical (der_rewriter)
{
m_imp->set_cancel(f);
}
}
void der_rewriter::cleanup() {
ast_manager & m = m_imp->m();
#pragma omp critical (th_rewriter)
{
dealloc(m_imp);
m_imp = alloc(imp, m);
}
}
void der_rewriter::reset() {
m_imp->reset();
}
struct der_strategy::imp {
ast_manager & m_manager;
der_rewriter m_r;
imp(ast_manager & m):
m_manager(m),
m_r(m) {
}
ast_manager & m() const { return m_manager; }
void set_cancel(bool f) {
m_r.set_cancel(f);
}
void reset() {
m_r.reset();
}
void operator()(assertion_set & s) {
SASSERT(is_well_sorted(s));
as_st_report report("der", s);
TRACE("before_der", s.display(tout););
if (s.inconsistent())
return;
expr_ref new_curr(m());
proof_ref new_pr(m());
unsigned size = s.size();
for (unsigned idx = 0; idx < size; idx++) {
if (s.inconsistent())
break;
expr * curr = s.form(idx);
m_r(curr, new_curr, new_pr);
if (m().proofs_enabled()) {
proof * pr = s.pr(idx);
new_pr = m().mk_modus_ponens(pr, new_pr);
}
s.update(idx, new_curr, new_pr);
}
s.elim_redundancies();
TRACE("after_der", s.display(tout););
SASSERT(is_well_sorted(s));
}
};
der_strategy::der_strategy(ast_manager & m) {
m_imp = alloc(imp, m);
}
der_strategy::~der_strategy() {
dealloc(m_imp);
}
void der_strategy::operator()(assertion_set & s) {
m_imp->operator()(s);
}
void der_strategy::set_cancel(bool f) {
if (m_imp)
m_imp->set_cancel(f);
}
void der_strategy::cleanup() {
ast_manager & m = m_imp->m();
imp * d = m_imp;
#pragma omp critical (as_st_cancel)
{
m_imp = 0;
}
dealloc(d);
d = alloc(imp, m);
#pragma omp critical (as_st_cancel)
{
m_imp = d;
}
}
class der_tactic : public tactic {
struct imp {
ast_manager & m_manager;
der_rewriter m_r;
imp(ast_manager & m):
m_manager(m),
m_r(m) {
}
ast_manager & m() const { return m_manager; }
void set_cancel(bool f) {
m_r.set_cancel(f);
}
void reset() {
m_r.reset();
}
void operator()(goal & g) {
SASSERT(g.is_well_sorted());
bool proofs_enabled = g.proofs_enabled();
tactic_report report("der", g);
TRACE("before_der", g.display(tout););
expr_ref new_curr(m());
proof_ref new_pr(m());
unsigned size = g.size();
for (unsigned idx = 0; idx < size; idx++) {
if (g.inconsistent())
break;
expr * curr = g.form(idx);
m_r(curr, new_curr, new_pr);
if (proofs_enabled) {
proof * pr = g.pr(idx);
new_pr = m().mk_modus_ponens(pr, new_pr);
}
g.update(idx, new_curr, new_pr, g.dep(idx));
}
g.elim_redundancies();
TRACE("after_der", g.display(tout););
SASSERT(g.is_well_sorted());
}
};
imp * m_imp;
public:
der_tactic(ast_manager & m) {
m_imp = alloc(imp, m);
}
virtual tactic * translate(ast_manager & m) {
return alloc(der_tactic, m);
}
virtual ~der_tactic() {
dealloc(m_imp);
}
virtual void operator()(goal_ref const & in,
goal_ref_buffer & result,
model_converter_ref & mc,
proof_converter_ref & pc,
expr_dependency_ref & core) {
mc = 0; pc = 0; core = 0;
(*m_imp)(*(in.get()));
in->inc_depth();
result.push_back(in.get());
}
virtual void cleanup() {
ast_manager & m = m_imp->m();
imp * d = m_imp;
#pragma omp critical (tactic_cancel)
{
m_imp = 0;
}
dealloc(d);
d = alloc(imp, m);
#pragma omp critical (tactic_cancel)
{
m_imp = d;
}
}
virtual void set_cancel(bool f) {
if (m_imp)
m_imp->set_cancel(f);
}
};
tactic * mk_der_tactic(ast_manager & m) {
return alloc(der_tactic, m);
}

215
lib/der.h
View file

@ -1,215 +0,0 @@
/*++
Copyright (c) 2006 Microsoft Corporation
Module Name:
der.h
Abstract:
Destructive equality resolution.
Author:
Leonardo de Moura (leonardo) 2008-01-27.
Revision History:
Christoph Wintersteiger, 2010-03-30: Added Destr. Multi-Equality Resolution
--*/
#ifndef _DER_H_
#define _DER_H_
#include"ast.h"
#include"var_subst.h"
#include"assertion_set_strategy.h"
/*
New DER: the class DER (above) eliminates variables one by one.
This is inefficient, and we should implement a new version that
can handle efficiently examples with hundreds of variables.
Suppose the target of the simplification is the quantifier
(FORALL (x1 T1) (x2 T2) ... (xn Tn) (or ....))
So, the variables x1 ... xn are the candidates for elimination.
First, we build a mapping of candidate substitutions
Since variables x1 ... xn have ids 0 ... n-1, we can
use an array m_map to implement this mapping.
The idea is to traverse the children of the (or ...) looking
for diseqs. The method is_var_diseq can be used for doing that.
Given a child c, if is_var_diseq(c, num_decls, v, t) returns true,
and m_map[v] is null, then we store t at m_map[v].
For performance reasons, we also store a mapping from child position (in the OR) to variable ID.
Thus, m_pos2var[pos] contains the variable that is defined by the diseq at position pos.
m_pos2var[pos] = -1, if this position does not contain a diseq.
After doing that, m_map contains the variables that can
be potentially eliminated using DER.
We say m_map[v] is the definition of variable v.
The next step is to perform a topological sort on these
variables. The result is an array (m_order) of integers (variable ids)
such that i < j implies that m_map[m_order[i]] does not depend on variable m_order[j].
For example, consider the case where m_map contains the following values
m_map[0] = (+ (VAR 2) 0)
m_map[1] = null
m_map[2] = (+ (VAR 3) 0)
m_map[3] = (+ (VAR 1) 1)
m_map[4] = (* (VAR 5) 2)
m_map[5] = null
In this example, variable 0 depends on the definition of variable 2, which
depends on the definition of variable 3, which depends on the definition of variable 0 (cycle).
On the other hand, no cycle is found when starting at variable 4.
Cycles can be broken by erasing entries from m_map. For example, the cycle above
can be removed by setting m_map[0] = null.
m_map[0] = null
m_map[1] = null
m_map[2] = (+ (VAR 3) 0)
m_map[3] = (+ (VAR 1) 1)
m_map[4] = (* (VAR 5) 2)
m_map[5] = null
The file asserted_formulas.cpp has a class top_sort for performing topological sort.
This class cannot be used here, since it is meant for eliminating constants (instead of variables).
We need to implement a new top_sort here, we do not need a separate class for doing that.
Moreover, it is much simpler, since m_map is just an array.
In the example above (after setting m_map[0] to null), top_sort will produce the following order
m_order = [3, 2, 4]
The next step is to use var_subst to update the definitions in var_subst.
The idea is to process the variables in the order specified by m_order.
When processing m_map[m_order[i]] we use the definitions of all variables in m_order[0 ... i-1].
For example:
The first variable is 3, since it is at m_order[0], nothing needs to be done.
Next we have variable 2, we use m_map[3] since 3 is before 2 in m_order. So, the new
definition for 2 is (+ (+ (VAR 1) 1) 0). That is, we update m_map[2] with (+ (+ (VAR 1) 1) 0)
Next we have variable 4, we use m_map[3] and m_map[2] since 3 and 2 are before 4 in m_order.
In this case, var_subst will not do anything since m_map[4] does not contain variables 3 or 2.
So, the new m_map is:
m_map[0] = null
m_map[1] = null
m_map[2] = (+ (+ (VAR 1) 1) 0)
m_map[3] = (+ (VAR 1) 1)
m_map[4] = (* (VAR 5) 2)
m_map[5] = null
Now, we update the body of the quantifier using var_subst and the mapping above.
The idea is to create a new set of children for the OR.
For each child at position i, we do
if m_map[m_pos2var[i]] != -1
skip this child, it is a diseq used during DER
else
apply var_subst using m_map to this child, and store the result in a new children array
Create a new OR (new body of the quantifier) using the new children
Then, we create a new quantifier using this new body, and use the function elim_unused_vars to
eliminate the ununsed variables.
Remark: let us implement the new version inside the class der.
Use #if 0 ... #endif to comment the old version.
Remark: after you are done, we can eliminate the call to occurs in is_var_diseq, since
top_sort is already performing cycle detection.
*/
/**
\brief Functor for applying Destructive Multi-Equality Resolution.
(forall (X Y) (or X /= s C[X])) --> (forall (Y) C[Y])
*/
class der {
ast_manager & m_manager;
var_subst m_subst;
expr_ref_buffer m_new_exprs;
ptr_vector<expr> m_map;
int_vector m_pos2var;
ptr_vector<var> m_inx2var;
unsigned_vector m_order;
expr_ref_vector m_subst_map;
expr_ref_buffer m_new_args;
/**
\brief Return true if e can be viewed as a variable disequality.
Store the variable id in v and the definition in t.
For example:
if e is (not (= (VAR 1) T)), then v assigned to 1, and t to T.
if e is (iff (VAR 2) T), then v is assigned to 2, and t to (not T).
(not T) is used because this formula is equivalent to (not (iff (VAR 2) (not T))),
and can be viewed as a disequality.
*/
bool is_var_diseq(expr * e, unsigned num_decls, var *& v, expr_ref & t);
void get_elimination_order();
void create_substitution(unsigned sz);
void apply_substitution(quantifier * q, expr_ref & r);
void reduce1(quantifier * q, expr_ref & r, proof_ref & pr);
public:
der(ast_manager & m):m_manager(m),m_subst(m),m_new_exprs(m),m_subst_map(m),m_new_args(m) {}
ast_manager & m() const { return m_manager; }
void operator()(quantifier * q, expr_ref & r, proof_ref & pr);
};
/**
\brief Functor for applying Destructive Multi-Equality Resolution in all
universal quantifiers in an expression.
*/
class der_rewriter {
protected:
struct imp;
imp * m_imp;
public:
der_rewriter(ast_manager & m);
~der_rewriter();
ast_manager & m () const;
void operator()(expr * t, expr_ref & result, proof_ref & result_pr);
void cancel() { set_cancel(true); }
void reset_cancel() { set_cancel(false); }
void set_cancel(bool f);
void cleanup();
void reset();
};
typedef der_rewriter der_star;
// TODO: delete obsolete class
class der_strategy : public assertion_set_strategy {
struct imp;
imp * m_imp;
public:
der_strategy(ast_manager & m);
virtual ~der_strategy();
void operator()(assertion_set & s);
virtual void operator()(assertion_set & s, model_converter_ref & mc) {
operator()(s);
mc = 0;
}
virtual void cleanup();
virtual void set_cancel(bool f);
};
inline as_st * mk_der(ast_manager & m) {
return alloc(der_strategy, m);
}
class tactic;
tactic * mk_der_tactic(ast_manager & m);
#endif /* _DER_H_ */

View file

@ -1,120 +0,0 @@
/*++
Copyright (c) 2011 Microsoft Corporation
Module Name:
elim_var_model_converter.cpp
Abstract:
Model converter that introduces eliminated variables in a model.
Author:
Leonardo (leonardo) 2011-05-05
Notes:
--*/
#include"elim_var_model_converter.h"
#include"model_evaluator.h"
#include"ast_smt2_pp.h"
#include"model_v2_pp.h"
#include"ast_pp.h"
elim_var_model_converter::~elim_var_model_converter() {
}
struct elim_var_model_converter::set_eval {
elim_var_model_converter * m_owner;
model_evaluator * m_old;
set_eval(elim_var_model_converter * owner, model_evaluator * ev) {
m_owner = owner;
m_old = owner->m_eval;
#pragma omp critical (elim_var_model_converter)
{
owner->m_eval = ev;
}
}
~set_eval() {
#pragma omp critical (elim_var_model_converter)
{
m_owner->m_eval = m_old;
}
}
};
static void display_decls_info(std::ostream & out, model_ref & md) {
ast_manager & m = md->get_manager();
unsigned sz = md->get_num_decls();
for (unsigned i = 0; i < sz; i++) {
func_decl * d = md->get_decl(i);
out << d->get_name();
out << " (";
for (unsigned j = 0; j < d->get_arity(); j++)
out << mk_pp(d->get_domain(j), m);
out << mk_pp(d->get_range(), m);
out << ") ";
if (d->get_info())
out << *(d->get_info());
out << " :id " << d->get_id() << "\n";
}
}
void elim_var_model_converter::operator()(model_ref & md) {
TRACE("elim_var_mc", model_v2_pp(tout, *md); display_decls_info(tout, md););
model_evaluator ev(*(md.get()));
ev.set_model_completion(true);
expr_ref val(m());
{
set_eval setter(this, &ev);
unsigned i = m_vars.size();
while (i > 0) {
--i;
expr * def = m_defs.get(i);
ev(def, val);
TRACE("elim_var_mc", tout << m_vars.get(i)->get_name() << " ->\n" << mk_ismt2_pp(def, m()) << "\n==>\n" << mk_ismt2_pp(val, m()) << "\n";);
func_decl * f = m_vars.get(i);
unsigned arity = f->get_arity();
if (arity == 0) {
md->register_decl(f, val);
}
else {
func_interp * new_fi = alloc(func_interp, m(), arity);
new_fi->set_else(val);
md->register_decl(f, new_fi);
}
}
}
TRACE("elim_var_mc", model_v2_pp(tout, *md); display_decls_info(tout, md););
}
void elim_var_model_converter::cancel() {
#pragma omp critical (elim_var_model_converter)
{
if (m_eval)
m_eval->cancel();
}
}
void elim_var_model_converter::display(std::ostream & out) {
ast_manager & m = m_vars.get_manager();
out << "(elim-var-model-converter";
for (unsigned i = 0; i < m_vars.size(); i++) {
out << "\n (" << m_vars.get(i)->get_name() << " ";
unsigned indent = m_vars.get(i)->get_name().size() + 4;
out << mk_ismt2_pp(m_defs.get(i), m, indent) << ")";
}
out << ")" << std::endl;
}
model_converter * elim_var_model_converter::translate(ast_translation & translator) {
elim_var_model_converter * res = alloc(elim_var_model_converter, translator.to());
for (unsigned i = 0; i < m_vars.size(); i++)
res->m_vars.push_back(translator(m_vars[i].get()));
for (unsigned i = 0; i < m_defs.size(); i++)
res->m_defs.push_back(translator(m_defs[i].get()));
// m_eval is a transient object. So, it doesn't need to be translated.
return res;
}

View file

@ -1,56 +0,0 @@
/*++
Copyright (c) 2011 Microsoft Corporation
Module Name:
elim_var_model_converter.h
Abstract:
Model converter that introduces eliminated variables in a model.
Author:
Leonardo (leonardo) 2011-05-05
Notes:
--*/
#ifndef _ELIM_VAR_MODEL_CONVERTER_H_
#define _ELIM_VAR_MODEL_CONVERTER_H_
#include"ast.h"
#include"model_converter.h"
class model_evaluator;
class elim_var_model_converter : public model_converter {
func_decl_ref_vector m_vars;
expr_ref_vector m_defs;
model_evaluator * m_eval;
struct set_eval;
public:
elim_var_model_converter(ast_manager & m):m_vars(m), m_defs(m), m_eval(0) {
}
virtual ~elim_var_model_converter();
ast_manager & m() const { return m_vars.get_manager(); }
virtual void operator()(model_ref & md);
virtual void cancel();
virtual void display(std::ostream & out);
// register a variable that was eliminated
void insert(func_decl * v, expr * def) {
m_vars.push_back(v);
m_defs.push_back(def);
}
virtual model_converter * translate(ast_translation & translator);
};
#endif

View file

@ -1,53 +0,0 @@
/*++
Copyright (c) 2006 Microsoft Corporation
Module Name:
expr_offset.h
Abstract:
Expressions + Offsets.
In order to avoid creating variants of terms, we use a pair (expression, offset),
where offset is just a small integer.
Non ground terms with different offsets are always considered
disequal. For example, (f x):1 is different from (f x):2, and
(f x):1 is unifiable with x:2.
Author:
Leonardo de Moura (leonardo) 2008-01-28.
Revision History:
--*/
#ifndef _EXPR_OFFSET_H_
#define _EXPR_OFFSET_H_
#include"ast.h"
class expr_offset {
expr * m_expr;
unsigned m_offset;
public:
expr_offset():m_expr(0), m_offset(0) {}
expr_offset(expr * e, unsigned o):m_expr(e), m_offset(o) {}
expr * get_expr() const { return m_expr; }
unsigned get_offset() const { return m_offset; }
bool operator==(expr_offset const & other) const { return m_expr == other.m_expr && m_offset == other.m_offset; }
bool operator!=(expr_offset const & other) const { return !operator==(other); }
unsigned hash() const {
unsigned a = m_expr->get_id();
unsigned b = m_offset;
unsigned c = 17;
mix(a, b, c);
return c;
}
};
typedef std::pair<expr_offset, expr_offset> expr_offset_pair;
typedef pair_hash<obj_hash<expr_offset>, obj_hash<expr_offset> > expr_offset_pair_hash;
#endif /* _EXPR_OFFSET_H_ */

View file

@ -1,94 +0,0 @@
/*++
Copyright (c) 2006 Microsoft Corporation
Module Name:
expr_offset_map.h
Abstract:
A generic mapping from (expression, offset) to a value T.
Author:
Leonardo de Moura (leonardo) 2008-02-01.
Revision History:
--*/
#ifndef _EXPR_OFFSET_MAP_H_
#define _EXPR_OFFSET_MAP_H_
#include"expr_offset.h"
#include"vector.h"
/**
\brief A mapping from expr_offset to some value of type T.
*/
template<typename T>
class expr_offset_map {
struct data {
T m_data;
unsigned m_timestamp;
data():m_timestamp(0) {}
};
vector<svector<data> > m_map;
unsigned m_timestamp;
public:
expr_offset_map():
m_timestamp(1) {}
bool contains(expr_offset const & n) const {
unsigned off = n.get_offset();
if (off < m_map.size()) {
svector<data> const & v = m_map[off];
unsigned id = n.get_expr()->get_id();
if (id < v.size())
return v[id].m_timestamp == m_timestamp;
}
return false;
}
bool find(expr_offset const & n, T & r) const {
unsigned off = n.get_offset();
if (off < m_map.size()) {
svector<data> const & v = m_map[off];
unsigned id = n.get_expr()->get_id();
if (id < v.size() && v[id].m_timestamp == m_timestamp) {
r = v[id].m_data;
return true;
}
}
return false;
}
void insert(expr_offset const & n, T const & r) {
unsigned off = n.get_offset();
if (off >= m_map.size())
m_map.resize(off+1, svector<data>());
svector<data> & v = m_map[off];
unsigned id = n.get_expr()->get_id();
if (id >= v.size())
v.resize(id+1);
v[id].m_data = r;
v[id].m_timestamp = m_timestamp;
}
void reset() {
m_timestamp++;
if (m_timestamp == UINT_MAX) {
typename vector<svector<data> >::iterator it = m_map.begin();
typename vector<svector<data> >::iterator end = m_map.end();
for (; it != end; ++it) {
svector<data> & v = *it;
typename svector<data>::iterator it2 = v.begin();
typename svector<data>::iterator end2 = v.end();
for (; it2 != end2; ++it2)
it2->m_timestamp = 0;
}
m_timestamp = 1;
}
}
};
#endif /* _EXPR_OFFSET_MAP_H_ */

View file

@ -1,494 +0,0 @@
/*++
Copyright (c) 2007 Microsoft Corporation
Module Name:
ast_pattern_match.cpp
Abstract:
Search for opportune pattern matching utilities.
Author:
Nikolaj Bjorner (nbjorner) 2007-04-10
Leonardo (leonardo)
Notes:
instead of the brute force enumeration of permutations
we can add an instruction 'gate' which copies the ast
into a register and creates another register with the same
term. Matching against a 'gate' is a noop, apart from clearing
the ast in the register. Then on backtracking we know how many
terms were matched from the permutation. It does not make sense
to enumerate all combinations of terms that were not considered, so
skip these.
Also, compilation should re-order terms to fail fast.
--*/
#include"ast.h"
#include"expr_pattern_match.h"
#include"smtparser.h"
#include"for_each_ast.h"
#include"ast_ll_pp.h"
#include"ast_pp.h"
expr_pattern_match::expr_pattern_match(ast_manager & manager):
m_manager(manager), m_precompiled(manager) {
}
expr_pattern_match::~expr_pattern_match() {
}
bool
expr_pattern_match::match_quantifier(quantifier* qf, app_ref_vector& patterns, unsigned& weight) {
if (m_regs.empty()) {
// HACK: the code crashes if database is empty.
return false;
}
m_regs[0] = qf->get_expr();
for (unsigned i = 0; i < m_precompiled.size(); ++i) {
quantifier* qf2 = m_precompiled[i].get();
if (qf2->is_forall() != qf->is_forall()) {
continue;
}
if (qf2->get_num_decls() != qf->get_num_decls()) {
continue;
}
subst s;
if (match(qf->get_expr(), m_first_instrs[i], s)) {
for (unsigned j = 0; j < qf2->get_num_patterns(); ++j) {
app* p = static_cast<app*>(qf2->get_pattern(j));
expr_ref p_result(m_manager);
instantiate(p, qf->get_num_decls(), s, p_result);
patterns.push_back(to_app(p_result.get()));
}
weight = qf2->get_weight();
return true;
}
}
return false;
}
void
expr_pattern_match::instantiate(expr* a, unsigned num_bound, subst& s, expr_ref& result) {
bound b;
for (unsigned i = 0; i < num_bound; ++i) {
b.insert(m_bound_dom[i], m_bound_rng[i]);
}
inst_proc proc(m_manager, s, b, m_regs);
for_each_ast(proc, a);
expr* v = 0;
proc.m_memoize.find(a, v);
SASSERT(v);
result = v;
}
void
expr_pattern_match::compile(expr* q)
{
SASSERT(q->get_kind() == AST_QUANTIFIER);
quantifier* qf = to_quantifier(q);
unsigned ip = m_instrs.size();
m_first_instrs.push_back(ip);
m_precompiled.push_back(qf);
instr instr(BACKTRACK);
unsigned_vector regs;
ptr_vector<expr> pats;
unsigned max_reg = 1;
subst s;
pats.push_back(qf->get_expr());
regs.push_back(0);
unsigned num_bound = 0;
obj_map<var, unsigned> bound;
while (!pats.empty()) {
unsigned reg = regs.back();
expr* pat = pats.back();
regs.pop_back();
pats.pop_back();
instr.m_pat = pat;
instr.m_next = m_instrs.size()+1;
instr.m_reg = reg;
instr.m_offset = max_reg;
switch(pat->get_kind()) {
case AST_VAR: {
var* b = to_var(pat);
if (bound.find(b, instr.m_num_bound)) {
instr.m_kind = CHECK_BOUND;
}
else {
instr.m_kind = SET_BOUND;
instr.m_num_bound = num_bound;
bound.insert(b, num_bound);
++num_bound;
}
break;
}
case AST_APP: {
unsigned r = 0;
app* app = to_app(pat);
func_decl* d = app->get_decl();
for (unsigned i = 0; i < app->get_num_args(); ++i) {
regs.push_back(max_reg);
pats.push_back(app->get_arg(i));
++max_reg;
}
if (is_var(d)) {
if (s.find(d, r)) {
instr.m_kind = CHECK_VAR;
instr.m_other_reg = r;
}
else {
instr.m_kind = SET_VAR;
s.insert(d, reg);
}
}
else {
if (d->is_associative() && d->is_commutative()) {
instr.m_kind = BIND_AC;
}
else if (d->is_commutative()) {
SASSERT(app->get_num_args() == 2);
instr.m_kind = BIND_C;
}
else {
instr.m_kind = BIND;
}
}
break;
}
default:
instr.m_kind = CHECK_TERM;
break;
}
m_instrs.push_back(instr);
}
if (m_regs.size() <= max_reg) {
m_regs.resize(max_reg+1, 0);
}
if (m_bound_dom.size() <= num_bound) {
m_bound_dom.resize(num_bound+1, 0);
m_bound_rng.resize(num_bound+1, 0);
}
instr.m_kind = YIELD;
m_instrs.push_back(instr);
}
bool
expr_pattern_match::match(expr* a, unsigned init, subst& s)
{
svector<instr> bstack;
instr pc = m_instrs[init];
while (true) {
bool ok = false;
switch(pc.m_kind) {
case YIELD:
// substitution s contains registers with matching declarations.
return true;
case CHECK_TERM:
TRACE("expr_pattern_match", display(tout, pc);
ast_pp(tout, m_regs[pc.m_reg], m_manager) << "\n";);
ok = (pc.m_pat == m_regs[pc.m_reg]);
break;
case SET_VAR:
case CHECK_VAR: {
TRACE("expr_pattern_match", display(tout, pc);
ast_pp(tout, m_regs[pc.m_reg], m_manager) << "\n";);
app* app1 = to_app(pc.m_pat);
a = m_regs[pc.m_reg];
if (a->get_kind() != AST_APP) {
break;
}
app* app2 = to_app(a);
if (app1->get_num_args() != app2->get_num_args()) {
break;
}
if (pc.m_kind == CHECK_VAR &&
to_app(m_regs[pc.m_reg])->get_decl() !=
to_app(m_regs[pc.m_other_reg])->get_decl()) {
break;
}
for (unsigned i = 0; i < app2->get_num_args(); ++i) {
m_regs[pc.m_offset + i] = app2->get_arg(i);
}
if (pc.m_kind == SET_VAR) {
s.insert(app1->get_decl(), pc.m_reg);
}
ok = true;
break;
}
case SET_BOUND: {
TRACE("expr_pattern_match", display(tout, pc);
ast_pp(tout, m_regs[pc.m_reg], m_manager) << "\n";);
a = m_regs[pc.m_reg];
if (a->get_kind() != AST_VAR) {
break;
}
ok = true;
var* var_a = to_var(a);
var* var_p = to_var(pc.m_pat);
// check that the mapping of bound variables remains a bijection.
for (unsigned i = 0; ok && i < pc.m_num_bound; ++i) {
ok = (a != m_bound_rng[i]);
}
if (!ok) {
break;
}
m_bound_dom[pc.m_num_bound] = var_p;
m_bound_rng[pc.m_num_bound] = var_a;
break;
}
case CHECK_BOUND:
TRACE("expr_pattern_match",
tout
<< "check bound "
<< pc.m_num_bound << " " << pc.m_reg;
);
ok = m_bound_rng[pc.m_num_bound] == m_regs[pc.m_reg];
break;
case BIND:
case BIND_AC:
case BIND_C: {
TRACE("expr_pattern_match", display(tout, pc);
tout << mk_pp(m_regs[pc.m_reg],m_manager) << "\n";);
app* app1 = to_app(pc.m_pat);
a = m_regs[pc.m_reg];
if (a->get_kind() != AST_APP) {
break;
}
app* app2 = to_app(a);
if (app1->get_num_args() != app2->get_num_args()) {
break;
}
if (!match_decl(app1->get_decl(), app2->get_decl())) {
break;
}
switch(pc.m_kind) {
case BIND:
for (unsigned i = 0; i < app2->get_num_args(); ++i) {
m_regs[pc.m_offset + i] = app2->get_arg(i);
}
ok = true;
break; // process the next instruction.
case BIND_AC:
// push CHOOSE_AC on the backtracking stack.
bstack.push_back(instr(CHOOSE_AC, pc.m_offset, pc.m_next, app2, 1));
break;
case BIND_C:
// push CHOOSE_C on the backtracking stack.
ok = true;
m_regs[pc.m_offset] = app2->get_arg(0);
m_regs[pc.m_offset+1] = app2->get_arg(1);
bstack.push_back(instr(CHOOSE_C, pc.m_offset, pc.m_next, app2, 2));
break;
default:
break;
}
break;
}
case CHOOSE_C:
ok = true;
SASSERT (pc.m_count == 2);
m_regs[pc.m_offset+1] = pc.m_app->get_arg(0);
m_regs[pc.m_offset] = pc.m_app->get_arg(1);
break;
case CHOOSE_AC: {
ok = true;
app* app2 = pc.m_app;
for (unsigned i = 0; i < app2->get_num_args(); ++i) {
m_regs[pc.m_offset + i] = app2->get_arg(i);
}
// generate the k'th permutation.
unsigned k = pc.m_count;
unsigned fac = 1;
unsigned num_args = pc.m_app->get_num_args();
for (unsigned j = 2; j <= num_args; ++j) {
fac *= (j-1);
SASSERT(((k /fac) % j) + 1 <= j);
std::swap(m_regs[pc.m_offset + j - 1], m_regs[pc.m_offset + j - ((k / fac) % j) - 1]);
}
if (k < fac*num_args) {
bstack.push_back(instr(CHOOSE_AC, pc.m_offset, pc.m_next, app2, k+1));
}
TRACE("expr_pattern_match",
{
tout << "fac: " << fac << " num_args:" << num_args << " k:" << k << "\n";
for (unsigned i = 0; i < num_args; ++i) {
ast_pp(tout, m_regs[pc.m_offset + i], m_manager);
tout << " ";
}
tout << "\n";
});
break;
}
case BACKTRACK:
if (bstack.empty()) {
return false;
}
pc = bstack.back();
bstack.pop_back();
continue; // with the loop.
}
if (ok) {
pc = m_instrs[pc.m_next];
}
else {
TRACE("expr_pattern_match", tout << "backtrack\n";);
pc = m_instrs[0];
}
}
}
bool
expr_pattern_match::match_decl(func_decl const * pat, func_decl const * d) const {
if (pat == d) {
return true;
}
if (pat->get_arity() != d->get_arity()) {
return false;
}
// match families
if (pat->get_family_id() == null_family_id) {
return false;
}
if (d->get_family_id() != pat->get_family_id()) {
return false;
}
if (d->get_decl_kind() != pat->get_decl_kind()) {
return false;
}
if (d->get_num_parameters() != pat->get_num_parameters()) {
return false;
}
for (unsigned i = 0; i < d->get_num_parameters(); ++i) {
if (!(d->get_parameter(i) == pat->get_parameter(i))) {
return false;
}
}
return true;
}
bool
expr_pattern_match::is_var(func_decl* d) {
const char* s = d->get_name().bare_str();
return s && *s == '?';
}
void
expr_pattern_match::initialize(char const * spec_string) {
if (!m_instrs.empty()) {
return;
}
m_instrs.push_back(instr(BACKTRACK));
smtlib::parser* parser = smtlib::parser::create(m_manager);
parser->initialize_smtlib();
if (!parser->parse_string(spec_string)) {
UNREACHABLE();
}
smtlib::benchmark* bench = parser->get_benchmark();
smtlib::theory::expr_iterator it = bench->begin_formulas();
smtlib::theory::expr_iterator end = bench->end_formulas();
for (; it != end; ++it) {
compile(*it);
}
dealloc(parser);
TRACE("expr_pattern_match", display(tout); );
}
void
expr_pattern_match::display(std::ostream& out) const {
for (unsigned i = 0; i < m_instrs.size(); ++i) {
display(out, m_instrs[i]);
}
}
void
expr_pattern_match::display(std::ostream& out, instr const& pc) const {
switch(pc.m_kind) {
case BACKTRACK:
out << "backtrack\n";
break;
case BIND:
out << "bind ";
ast_pp(out, to_app(pc.m_pat)->get_decl(), m_manager) << " ";
ast_pp(out, pc.m_pat, m_manager) << "\n";
out << "next: " << pc.m_next << "\n";
out << "offset: " << pc.m_offset << "\n";
out << "reg: " << pc.m_reg << "\n";
break;
case BIND_AC:
out << "bind_ac ";
ast_pp(out, to_app(pc.m_pat)->get_decl(), m_manager) << " ";
ast_pp(out, pc.m_pat, m_manager) << "\n";
out << "next: " << pc.m_next << "\n";
out << "offset: " << pc.m_offset << "\n";
out << "reg: " << pc.m_reg << "\n";
break;
case BIND_C:
out << "bind_c ";
ast_pp(out, to_app(pc.m_pat)->get_decl(), m_manager) << " ";
ast_pp(out, pc.m_pat, m_manager) << "\n";
out << "next: " << pc.m_next << "\n";
out << "offset: " << pc.m_offset << "\n";
out << "reg: " << pc.m_reg << "\n";
break;
case CHOOSE_AC:
out << "choose_ac\n";
out << "next: " << pc.m_next << "\n";
out << "count: " << pc.m_count << "\n";
break;
case CHOOSE_C:
out << "choose_c\n";
out << "next: " << pc.m_next << "\n";
//out << "reg: " << pc.m_reg << "\n";
break;
case CHECK_VAR:
out << "check_var ";
ast_pp(out, pc.m_pat, m_manager) << "\n";
out << "next: " << pc.m_next << "\n";
out << "reg: " << pc.m_reg << "\n";
out << "other_reg: " << pc.m_other_reg << "\n";
break;
case CHECK_TERM:
out << "check ";
ast_pp(out, pc.m_pat, m_manager) << "\n";
out << "next: " << pc.m_next << "\n";
out << "reg: " << pc.m_reg << "\n";
break;
case YIELD:
out << "yield\n";
break;
case SET_VAR:
out << "set_var ";
ast_pp(out, pc.m_pat, m_manager) << "\n";
out << "next: " << pc.m_next << "\n";
break;
default:
break;
} }
// TBD: fix type overloading.
// TBD: bound number of permutations.
// TBD: forward pruning checks.

View file

@ -1,148 +0,0 @@
/*++
Copyright (c) 2007 Microsoft Corporation
Module Name:
expr_pattern_match.h
Abstract:
Search for opportune pattern matching utilities.
Author:
Nikolaj Bjorner (nbjorner) 2007-04-10
Leonardo (leonardo)
Notes:
--*/
#ifndef _EXPR_PATTERN_MATCH_H_
#define _EXPR_PATTERN_MATCH_H_
#include"ast.h"
#include"map.h"
#include"front_end_params.h"
class expr_pattern_match {
enum instr_kind {
BACKTRACK,
BIND,
BIND_AC,
BIND_C,
CHOOSE_AC,
CHOOSE_C,
SET_VAR,
CHECK_VAR,
CHECK_TERM,
SET_BOUND,
CHECK_BOUND,
YIELD,
};
struct instr {
instr(instr_kind k) : m_kind(k) {}
instr(instr_kind k, unsigned o, unsigned next, app* app, unsigned count):
m_kind(k), m_offset(o), m_next(next), m_app(app), m_count(count) {}
instr_kind m_kind;
unsigned m_offset;
unsigned m_next;
app* m_app;
expr* m_pat;
unsigned m_reg;
unsigned m_other_reg;
unsigned m_count;
unsigned m_num_bound;
};
typedef obj_map<func_decl, unsigned> subst;
typedef obj_map<var, var*> bound;
struct inst_proc {
ast_manager& m_manager;
expr_ref_vector m_pinned;
subst& m_subst;
bound& m_bound;
obj_map<expr, expr*> m_memoize;
ptr_vector<expr>& m_regs;
inst_proc(ast_manager& m, subst& s, bound& b, ptr_vector<expr>& regs) :
m_manager(m), m_pinned(m), m_subst(s), m_bound(b), m_regs(regs) {}
void operator()(ast* a) {
}
void operator()(expr* a) {
m_memoize.insert(a, a);
}
void operator()(var* v) {
var* b = 0;
if (m_bound.find(v, b)) {
m_memoize.insert(v, b);
}
else {
UNREACHABLE();
}
}
void operator()(app * n) {
unsigned r;
ptr_vector<expr> args;
unsigned num_args = n->get_num_args();
func_decl * decl = n->get_decl();
expr* result;
if (m_subst.find(decl, r)) {
decl = to_app(m_regs[r])->get_decl();
}
for (unsigned i = 0; i < num_args; ++i) {
expr* arg = 0;
if (m_memoize.find(n->get_arg(i), arg)) {
SASSERT(arg);
args.push_back(arg);
}
else {
UNREACHABLE();
}
}
if (m_manager.is_pattern(n)) {
result = m_manager.mk_pattern(num_args, reinterpret_cast<app**>(args.c_ptr()));
}
else {
result = m_manager.mk_app(decl, num_args, args.c_ptr());
}
m_pinned.push_back(result);
m_memoize.insert(n, result);
return;
}
};
ast_manager & m_manager;
quantifier_ref_vector m_precompiled;
unsigned_vector m_first_instrs;
svector<instr> m_instrs;
ptr_vector<expr> m_regs;
ptr_vector<var> m_bound_dom;
ptr_vector<var> m_bound_rng;
public:
expr_pattern_match(ast_manager & manager);
~expr_pattern_match();
bool match_quantifier(quantifier* qf, app_ref_vector& patterns, unsigned& weight);
void initialize(char const * database);
void display(std::ostream& out) const;
private:
void instantiate(expr* a, unsigned num_bound, subst& s, expr_ref& result);
void compile(expr* q);
bool match(expr* a, unsigned init, subst& s);
bool match_decl(func_decl const * pat, func_decl const * d) const;
bool is_var(func_decl* d);
void display(std::ostream& out, instr const& pc) const;
};
#endif

View file

@ -1,156 +0,0 @@
/*++
Copyright (c) 2011 Microsoft Corporation
Module Name:
expr_replacer.cpp
Abstract:
Abstract (functor) for replacing constants with expressions.
Author:
Leonardo (leonardo) 2011-04-29
Notes:
--*/
#include"expr_replacer.h"
#include"rewriter_def.h"
#include"th_rewriter.h"
#include"cooperate.h"
void expr_replacer::operator()(expr * t, expr_ref & result, proof_ref & result_pr) {
expr_dependency_ref result_dep(m());
operator()(t, result, result_pr, result_dep);
}
void expr_replacer::operator()(expr * t, expr_ref & result) {
proof_ref pr(m());
operator()(t, result, pr);
}
struct expr_replacer::scoped_set_subst {
expr_replacer & m_r;
scoped_set_subst(expr_replacer & r, expr_substitution & s):m_r(r) { m_r.set_substitution(&s); }
~scoped_set_subst() { m_r.set_substitution(0); }
};
void expr_replacer::apply_substitution(expr * s, expr * def, proof * def_pr, expr_ref & t) {
expr_substitution sub(m());
sub.insert(s, def, def_pr);
scoped_set_subst set(*this, sub);
(*this)(t);
}
void expr_replacer::apply_substitution(expr * s, expr * def, expr_ref & t) {
expr_substitution sub(m());
sub.insert(s, def);
scoped_set_subst set(*this, sub);
(*this)(t);
}
struct default_expr_replacer_cfg : public default_rewriter_cfg {
ast_manager & m;
expr_substitution * m_subst;
expr_dependency_ref m_used_dependencies;
default_expr_replacer_cfg(ast_manager & _m):
m(_m),
m_subst(0),
m_used_dependencies(_m) {
}
bool get_subst(expr * s, expr * & t, proof * & pr) {
if (m_subst == 0)
return false;
expr_dependency * d = 0;
if (m_subst->find(s, t, pr, d)) {
m_used_dependencies = m.mk_join(m_used_dependencies, d);
return true;
}
return false;
}
bool max_steps_exceeded(unsigned num_steps) const {
cooperate("simplifier");
return false;
}
};
template class rewriter_tpl<default_expr_replacer_cfg>;
class default_expr_replacer : public expr_replacer {
default_expr_replacer_cfg m_cfg;
rewriter_tpl<default_expr_replacer_cfg> m_replacer;
public:
default_expr_replacer(ast_manager & m):
m_cfg(m),
m_replacer(m, m.proofs_enabled(), m_cfg) {
}
virtual ast_manager & m() const { return m_replacer.m(); }
virtual void set_substitution(expr_substitution * s) {
m_replacer.cleanup();
m_replacer.cfg().m_subst = s;
}
virtual void operator()(expr * t, expr_ref & result, proof_ref & result_pr, expr_dependency_ref & result_dep) {
result_dep = 0;
m_replacer.operator()(t, result, result_pr);
if (m_cfg.m_used_dependencies != 0) {
result_dep = m_cfg.m_used_dependencies;
m_replacer.reset(); // reset cache
m_cfg.m_used_dependencies = 0;
}
}
virtual void set_cancel(bool f) {
m_replacer.set_cancel(f);
}
virtual unsigned get_num_steps() const {
return m_replacer.get_num_steps();
}
};
expr_replacer * mk_default_expr_replacer(ast_manager & m) {
return alloc(default_expr_replacer, m);
}
/**
\brief Adapter for using th_rewriter as an expr_replacer.
*/
class th_rewriter2expr_replacer : public expr_replacer {
th_rewriter m_r;
public:
th_rewriter2expr_replacer(ast_manager & m, params_ref const & p):
m_r(m, p) {
}
virtual ~th_rewriter2expr_replacer() {}
virtual ast_manager & m() const { return m_r.m(); }
virtual void set_substitution(expr_substitution * s) { m_r.set_substitution(s); }
virtual void operator()(expr * t, expr_ref & result, proof_ref & result_pr, expr_dependency_ref & result_dep) {
m_r(t, result, result_pr);
result_dep = m_r.get_used_dependencies();
m_r.reset_used_dependencies();
}
virtual void set_cancel(bool f) {
m_r.set_cancel(f);
}
virtual unsigned get_num_steps() const {
return m_r.get_num_steps();
}
};
expr_replacer * mk_expr_simp_replacer(ast_manager & m, params_ref const & p) {
return alloc(th_rewriter2expr_replacer, m, p);
}

View file

@ -1,62 +0,0 @@
/*++
Copyright (c) 2011 Microsoft Corporation
Module Name:
expr_replacer.h
Abstract:
Abstract (functor) for replacing expressions.
Author:
Leonardo (leonardo) 2011-04-29
Notes:
--*/
#ifndef _EXPR_REPLACER_H_
#define _EXPR_REPLACER_H_
#include"ast.h"
#include"expr_substitution.h"
#include"params.h"
/**
\brief Abstract interface for functors that replace constants with expressions.
*/
class expr_replacer {
struct scoped_set_subst;
public:
virtual ~expr_replacer() {}
virtual ast_manager & m() const = 0;
virtual void set_substitution(expr_substitution * s) = 0;
virtual void operator()(expr * t, expr_ref & result, proof_ref & result_pr, expr_dependency_ref & deps) = 0;
virtual void operator()(expr * t, expr_ref & result, proof_ref & result_pr);
virtual void operator()(expr * t, expr_ref & result);
virtual void operator()(expr_ref & t) { expr_ref s(t, m()); (*this)(s, t); }
void cancel() { set_cancel(true); }
void reset_cancel() { set_cancel(false); }
virtual void set_cancel(bool f) = 0;
virtual unsigned get_num_steps() const { return 0; }
void apply_substitution(expr * s, expr * def, proof * def_pr, expr_ref & t);
void apply_substitution(expr * s, expr * def, expr_ref & t);
};
/**
\brief Create a vanilla replacer. It just applies the substitution.
*/
expr_replacer * mk_default_expr_replacer(ast_manager & m);
/**
\brief Apply substitution and simplify.
*/
expr_replacer * mk_expr_simp_replacer(ast_manager & m, params_ref const & p = params_ref());
#endif

View file

@ -1,88 +0,0 @@
/*++
Copyright (c) 2006 Microsoft Corporation
Module Name:
expr_stat.cpp
Abstract:
Expression statistics (symbol count, var count, depth, ...)
All functions in these module assume expressions do not contain
nested quantifiers.
Author:
Leonardo de Moura (leonardo) 2008-02-05.
Revision History:
--*/
#include"for_each_expr.h"
#include"expr_stat.h"
void get_expr_stat(expr * n, expr_stat & r) {
typedef std::pair<expr *, unsigned> pair;
buffer<pair> todo;
todo.push_back(pair(n, 0));
while (!todo.empty()) {
pair & p = todo.back();
n = p.first;
unsigned depth = p.second;
unsigned j;
todo.pop_back();
r.m_sym_count++;
if (depth > r.m_depth)
r.m_depth = depth;
switch (n->get_kind()) {
case AST_APP:
j = to_app(n)->get_num_args();
if (j == 0)
r.m_const_count++;
while (j > 0) {
--j;
todo.push_back(pair(to_app(n)->get_arg(j), depth + 1));
}
break;
case AST_VAR:
if (to_var(n)->get_idx() > r.m_max_var_idx)
r.m_max_var_idx = to_var(n)->get_idx();
r.m_ground = false;
break;
case AST_QUANTIFIER:
todo.push_back(pair(to_quantifier(n)->get_expr(), depth+1));
break;
default:
UNREACHABLE();
}
}
}
unsigned get_symbol_count(expr * n) {
unsigned r = 0;
ptr_buffer<expr> todo;
todo.push_back(n);
while (!todo.empty()) {
n = todo.back();
unsigned j;
todo.pop_back();
r++;
switch (n->get_kind()) {
case AST_APP:
j = to_app(n)->get_num_args();
while (j > 0) {
--j;
todo.push_back(to_app(n)->get_arg(j));
}
break;
case AST_QUANTIFIER:
todo.push_back(to_quantifier(n)->get_expr());
break;
default:
break;
}
}
return r;
}

View file

@ -1,50 +0,0 @@
/*++
Copyright (c) 2006 Microsoft Corporation
Module Name:
expr_stat.h
Abstract:
Expression statistics (symbol count, var count, depth, ...)
All functions in these module assume expressions do not contain
nested quantifiers.
Author:
Leonardo de Moura (leonardo) 2008-02-05.
Revision History:
--*/
#ifndef _EXPR_STAT_H_
#define _EXPR_STAT_H_
class expr;
struct expr_stat {
unsigned m_sym_count; // symbol count
unsigned m_depth; // depth
unsigned m_const_count; // constant count
unsigned m_max_var_idx;
bool m_ground;
expr_stat():m_sym_count(0), m_depth(0), m_const_count(0), m_max_var_idx(0), m_ground(true) {}
};
/**
\brief Collect statistics regarding the given expression.
\warning This function traverses the dag as a tree.
*/
void get_expr_stat(expr * n, expr_stat & r);
/**
\brief Return the number of symbols in \c n.
\warning This function traverses the dag as a tree.
*/
unsigned get_symbol_count(expr * n);
#endif /* _EXPR_STAT_H_ */

View file

@ -1,775 +0,0 @@
/*++
Copyright (c) 2011 Microsoft Corporation
Module Name:
gaussian_elim.cpp
Abstract:
(extended) Gaussian elimination for assertion sets.
It also supports other theories besides arithmetic.
Author:
Leonardo (leonardo) 2011-04-29
Notes:
--*/
#include"gaussian_elim.h"
#include"ast.h"
#include"expr_replacer.h"
#include"model_converter.h"
#include"assertion_set.h"
#include"ast_smt2_pp.h"
#include"elim_var_model_converter.h"
#include"occurs.h"
#include"cooperate.h"
#include"assertion_set_util.h"
struct gaussian_elim::imp {
ast_manager & m_manager;
expr_replacer * m_r;
bool m_r_owner;
arith_util m_a_util;
obj_map<expr, unsigned> m_num_occs;
unsigned m_num_steps;
unsigned m_num_eliminated_vars;
bool m_produce_models;
bool m_theory_solver;
bool m_ite_solver;
unsigned m_max_occs;
void updt_params(params_ref const & p) {
m_produce_models = p.get_bool(":produce-models", false);
m_ite_solver = p.get_bool(":ite-solver", true);
m_theory_solver = p.get_bool(":theory-solver", true);
m_max_occs = p.get_uint(":gaussian-max-occs", UINT_MAX);
}
typedef elim_var_model_converter gmc;
expr_substitution m_subst;
expr_substitution m_norm_subst;
expr_sparse_mark m_candidate_vars;
expr_sparse_mark m_candidate_set;
ptr_vector<expr> m_candidates;
ptr_vector<app> m_vars;
ptr_vector<app> m_ordered_vars;
volatile bool m_cancel;
imp(ast_manager & m, params_ref const & p, expr_replacer * r, bool owner):
m_manager(m),
m_r(r),
m_r_owner(r == 0 || owner),
m_a_util(m),
m_num_steps(0),
m_num_eliminated_vars(0),
m_subst(m),
m_norm_subst(m),
m_cancel(false) {
updt_params(p);
if (m_r == 0)
m_r = mk_default_expr_replacer(m);
}
~imp() {
if (m_r_owner)
dealloc(m_r);
}
ast_manager & m() const { return m_manager; }
bool check_occs(expr * t) const {
if (m_max_occs == UINT_MAX)
return true;
unsigned num = 0;
m_num_occs.find(t, num);
TRACE("gaussian_check_occs", tout << mk_ismt2_pp(t, m_manager) << " num_occs: " << num << " max: " << m_max_occs << "\n";);
return num <= m_max_occs;
}
// Use: (= x def) and (= def x)
bool trivial_solve(expr * lhs, expr * rhs, app_ref & var, expr_ref & def, proof_ref & pr) {
if (is_uninterp_const(lhs) && !m_candidate_vars.is_marked(lhs) && !occurs(lhs, rhs) && check_occs(lhs)) {
var = to_app(lhs);
def = rhs;
pr = 0;
return true;
}
else if (is_uninterp_const(rhs) && !m_candidate_vars.is_marked(rhs) && !occurs(rhs, lhs) && check_occs(rhs)) {
var = to_app(rhs);
def = lhs;
if (m_manager.proofs_enabled())
pr = m().mk_commutativity(m().mk_eq(lhs, rhs));
return true;
}
return false;
}
// (ite c (= x t1) (= x t2)) --> (= x (ite c t1 t2))
bool solve_ite_core(app * ite, expr * lhs1, expr * rhs1, expr * lhs2, expr * rhs2, app_ref & var, expr_ref & def, proof_ref & pr) {
if (lhs1 != lhs2)
return false;
if (!is_uninterp_const(lhs1) || m_candidate_vars.is_marked(lhs1))
return false;
if (occurs(lhs1, ite->get_arg(0)) || occurs(lhs1, rhs1) || occurs(lhs1, rhs2))
return false;
if (!check_occs(lhs1))
return false;
var = to_app(lhs1);
def = m().mk_ite(ite->get_arg(0), rhs1, rhs2);
if (m().proofs_enabled())
pr = m().mk_rewrite(ite, m().mk_eq(var, def));
return true;
}
// (ite c (= x t1) (= x t2)) --> (= x (ite c t1 t2))
bool solve_ite(app * ite, app_ref & var, expr_ref & def, proof_ref & pr) {
expr * t = ite->get_arg(1);
expr * e = ite->get_arg(2);
if (!m().is_eq(t) || !m().is_eq(e))
return false;
expr * lhs1 = to_app(t)->get_arg(0);
expr * rhs1 = to_app(t)->get_arg(1);
expr * lhs2 = to_app(e)->get_arg(0);
expr * rhs2 = to_app(e)->get_arg(1);
return
solve_ite_core(ite, lhs1, rhs1, lhs2, rhs2, var, def, pr) ||
solve_ite_core(ite, rhs1, lhs1, lhs2, rhs2, var, def, pr) ||
solve_ite_core(ite, lhs1, rhs1, rhs2, lhs2, var, def, pr) ||
solve_ite_core(ite, rhs1, lhs1, rhs2, lhs2, var, def, pr);
}
bool is_pos_literal(expr * n) {
return is_app(n) && to_app(n)->get_num_args() == 0 && to_app(n)->get_family_id() == null_family_id;
}
bool is_neg_literal(expr * n) {
if (m_manager.is_not(n))
return is_pos_literal(to_app(n)->get_arg(0));
return false;
}
#if 0
bool not_bool_eq(expr * f, app_ref & var, expr_ref & def, proof_ref & pr) {
if (!m().is_not(f))
return false;
expr * eq = to_app(f)->get_arg(0);
if (!m().is_eq(f))
return false;
}
#endif
/**
\brief Given t of the form (f s_0 ... s_n),
return true if x occurs in some s_j for j != i
*/
bool occurs_except(expr * x, app * t, unsigned i) {
unsigned num = t->get_num_args();
for (unsigned j = 0; j < num; j++) {
if (i != j && occurs(x, t->get_arg(j)))
return true;
}
return false;
}
bool solve_arith_core(app * lhs, expr * rhs, expr * eq, app_ref & var, expr_ref & def, proof_ref & pr) {
SASSERT(m_a_util.is_add(lhs));
bool is_int = m_a_util.is_int(lhs);
expr * a;
expr * v;
rational a_val;
unsigned num = lhs->get_num_args();
unsigned i;
for (i = 0; i < num; i++) {
expr * arg = lhs->get_arg(i);
if (is_uninterp_const(arg) && !m_candidate_vars.is_marked(arg) && check_occs(arg) && !occurs(arg, rhs) && !occurs_except(arg, lhs, i)) {
a_val = rational(1);
v = arg;
break;
}
else if (m_a_util.is_mul(arg, a, v) &&
is_uninterp_const(v) && !m_candidate_vars.is_marked(v) &&
m_a_util.is_numeral(a, a_val) &&
!a_val.is_zero() &&
(!is_int || a_val.is_minus_one()) &&
check_occs(v) &&
!occurs(v, rhs) &&
!occurs_except(v, lhs, i)) {
break;
}
}
if (i == num)
return false;
var = to_app(v);
expr_ref inv_a(m());
if (!a_val.is_one()) {
inv_a = m_a_util.mk_numeral(rational(1)/a_val, is_int);
rhs = m_a_util.mk_mul(inv_a, rhs);
}
ptr_buffer<expr> other_args;
for (unsigned j = 0; j < num; j++) {
if (i != j) {
if (inv_a)
other_args.push_back(m_a_util.mk_mul(inv_a, lhs->get_arg(j)));
else
other_args.push_back(lhs->get_arg(j));
}
}
switch (other_args.size()) {
case 0:
def = rhs;
break;
case 1:
def = m_a_util.mk_sub(rhs, other_args[0]);
break;
default:
def = m_a_util.mk_sub(rhs, m_a_util.mk_add(other_args.size(), other_args.c_ptr()));
break;
}
if (m().proofs_enabled()) {
pr = m().mk_rewrite(eq, m().mk_eq(var, def));
}
return true;
}
bool solve_arith(expr * lhs, expr * rhs, expr * eq, app_ref & var, expr_ref & def, proof_ref & pr) {
return
(m_a_util.is_add(lhs) && solve_arith_core(to_app(lhs), rhs, eq, var, def, pr)) ||
(m_a_util.is_add(rhs) && solve_arith_core(to_app(rhs), lhs, eq, var, def, pr));
}
bool solve(expr * f, app_ref & var, expr_ref & def, proof_ref & pr) {
if (m().is_eq(f)) {
if (trivial_solve(to_app(f)->get_arg(0), to_app(f)->get_arg(1), var, def, pr))
return true;
if (m_theory_solver) {
expr * lhs = to_app(f)->get_arg(0);
expr * rhs = to_app(f)->get_arg(1);
if (solve_arith(lhs, rhs, f, var, def, pr))
return true;
}
return false;
}
if (m().is_iff(f))
return trivial_solve(to_app(f)->get_arg(0), to_app(f)->get_arg(1), var, def, pr);
#if 0
if (not_bool_eq(f, var, def, pr))
return true;
#endif
if (m_ite_solver && m().is_ite(f))
return solve_ite(to_app(f), var, def, pr);
if (is_pos_literal(f)) {
if (m_candidate_vars.is_marked(f))
return false;
var = to_app(f);
def = m().mk_true();
if (m().proofs_enabled()) {
// [rewrite]: (iff (iff l true) l)
// [symmetry T1]: (iff l (iff l true))
pr = m().mk_rewrite(m().mk_eq(var, def), var);
pr = m().mk_symmetry(pr);
}
TRACE("gaussian_elim_bug2", tout << "eliminating: " << mk_ismt2_pp(f, m()) << "\n";);
return true;
}
if (is_neg_literal(f)) {
var = to_app(to_app(f)->get_arg(0));
if (m_candidate_vars.is_marked(var))
return false;
def = m().mk_false();
if (m().proofs_enabled()) {
// [rewrite]: (iff (iff l false) ~l)
// [symmetry T1]: (iff ~l (iff l false))
pr = m().mk_rewrite(m().mk_eq(var, def), f);
pr = m().mk_symmetry(pr);
}
return true;
}
return false;
}
void checkpoint() {
if (m_cancel)
throw gaussian_elim_exception(STE_CANCELED_MSG);
cooperate("gaussian elimination");
}
/**
\brief Start collecting candidates
*/
void collect(assertion_set & set) {
m_subst.reset();
m_norm_subst.reset();
m_r->set_substitution(0);
m_candidate_vars.reset();
m_candidate_set.reset();
m_candidates.reset();
m_vars.reset();
app_ref var(m());
expr_ref def(m());
proof_ref pr(m());
unsigned size = set.size();
for (unsigned idx = 0; idx < size; idx++) {
checkpoint();
expr * f = set.form(idx);
if (solve(f, var, def, pr)) {
m_vars.push_back(var);
m_candidates.push_back(f);
m_candidate_set.mark(f);
m_candidate_vars.mark(var);
if (m().proofs_enabled()) {
if (pr == 0)
pr = set.pr(idx);
else
pr = m().mk_modus_ponens(set.pr(idx), pr);
}
m_subst.insert(var, def, pr);
}
m_num_steps++;
}
TRACE("gaussian_elim",
tout << "candidate vars:\n";
ptr_vector<app>::iterator it = m_vars.begin();
ptr_vector<app>::iterator end = m_vars.end();
for (; it != end; ++it) {
tout << mk_ismt2_pp(*it, m()) << " ";
}
tout << "\n";);
}
void sort_vars() {
SASSERT(m_candidates.size() == m_vars.size());
TRACE("gaussian_elim_bug", tout << "sorting vars...\n";);
m_ordered_vars.reset();
// The variables (and its definitions) in m_subst must remain alive until the end of this procedure.
// Reason: they are scheduled for unmarking in visiting/done.
// They should remain alive while they are on the stack.
// To make sure this is the case, whenever a variable (and its definition) is removed from m_subst,
// I add them to the saved vector.
expr_ref_vector saved(m());
expr_fast_mark1 visiting;
expr_fast_mark2 done;
typedef std::pair<expr *, unsigned> frame;
svector<frame> todo;
ptr_vector<app>::const_iterator it = m_vars.begin();
ptr_vector<app>::const_iterator end = m_vars.end();
unsigned num;
for (; it != end; ++it) {
checkpoint();
app * v = *it;
if (!m_candidate_vars.is_marked(v))
continue;
todo.push_back(frame(v, 0));
while (!todo.empty()) {
start:
frame & fr = todo.back();
expr * t = fr.first;
m_num_steps++;
TRACE("gaussian_elim_bug", tout << "processing:\n" << mk_ismt2_pp(t, m()) << "\n";);
if (t->get_ref_count() > 1 && done.is_marked(t)) {
todo.pop_back();
continue;
}
switch (t->get_kind()) {
case AST_VAR:
todo.pop_back();
break;
case AST_QUANTIFIER:
num = to_quantifier(t)->get_num_children();
while (fr.second < num) {
expr * c = to_quantifier(t)->get_child(fr.second);
fr.second++;
if (c->get_ref_count() > 1 && done.is_marked(c))
continue;
todo.push_back(frame(c, 0));
goto start;
}
if (t->get_ref_count() > 1)
done.mark(t);
todo.pop_back();
break;
case AST_APP:
num = to_app(t)->get_num_args();
if (num == 0) {
if (fr.second == 0) {
if (m_candidate_vars.is_marked(t)) {
if (visiting.is_marked(t)) {
// cycle detected: remove t
visiting.reset_mark(t);
m_candidate_vars.mark(t, false);
SASSERT(!m_candidate_vars.is_marked(t));
// Must save t and its definition.
// See comment in the beginning of the function
expr * def = 0;
proof * pr;
m_subst.find(to_app(t), def, pr);
SASSERT(def != 0);
saved.push_back(t);
saved.push_back(def);
//
m_subst.erase(t);
}
else {
visiting.mark(t);
fr.second = 1;
expr * def = 0;
proof * pr;
m_subst.find(to_app(t), def, pr);
SASSERT(def != 0);
todo.push_back(frame(def, 0));
goto start;
}
}
}
else {
SASSERT(fr.second == 1);
if (m_candidate_vars.is_marked(t)) {
visiting.reset_mark(t);
m_ordered_vars.push_back(to_app(t));
}
else {
// var was removed from the list of candidate vars to elim cycle
// do nothing
}
}
}
else {
while (fr.second < num) {
expr * arg = to_app(t)->get_arg(fr.second);
fr.second++;
if (arg->get_ref_count() > 1 && done.is_marked(arg))
continue;
todo.push_back(frame(arg, 0));
goto start;
}
}
if (t->get_ref_count() > 1)
done.mark(t);
todo.pop_back();
break;
default:
UNREACHABLE();
todo.pop_back();
break;
}
}
}
// cleanup
it = m_vars.begin();
for (unsigned idx = 0; it != end; ++it, ++idx) {
if (!m_candidate_vars.is_marked(*it)) {
m_candidate_set.mark(m_candidates[idx], false);
}
}
TRACE("gaussian_elim",
tout << "ordered vars:\n";
ptr_vector<app>::iterator it = m_ordered_vars.begin();
ptr_vector<app>::iterator end = m_ordered_vars.end();
for (; it != end; ++it) {
SASSERT(m_candidate_vars.is_marked(*it));
tout << mk_ismt2_pp(*it, m()) << " ";
}
tout << "\n";);
m_candidate_vars.reset();
}
void normalize() {
m_norm_subst.reset();
m_r->set_substitution(&m_norm_subst);
expr_ref new_def(m());
proof_ref new_pr(m());
unsigned size = m_ordered_vars.size();
for (unsigned idx = 0; idx < size; idx++) {
checkpoint();
expr * v = m_ordered_vars[idx];
expr * def = 0;
proof * pr = 0;
m_subst.find(v, def, pr);
SASSERT(def != 0);
m_r->operator()(def, new_def, new_pr);
m_num_steps += m_r->get_num_steps() + 1;
if (m().proofs_enabled())
new_pr = m().mk_transitivity(pr, new_pr);
m_norm_subst.insert(v, new_def, new_pr);
// we updated the substituting, but we don't need to reset m_r
// because all cached values there do not depend on v.
}
m_subst.reset();
TRACE("gaussian_elim",
tout << "after normalizing variables\n";
for (unsigned i = 0; i < m_ordered_vars.size(); i++) {
expr * v = m_ordered_vars[i];
expr * def = 0;
proof * pr = 0;
m_norm_subst.find(v, def, pr);
tout << mk_ismt2_pp(v, m()) << "\n----->\n" << mk_ismt2_pp(def, m()) << "\n\n";
});
#if 0
DEBUG_CODE({
for (unsigned i = 0; i < m_ordered_vars.size(); i++) {
expr * v = m_ordered_vars[i];
expr * def = 0;
proof * pr = 0;
m_norm_subst.find(v, def, pr);
SASSERT(def != 0);
CASSERT("gaussian_elim_bug", !occurs(v, def));
}
});
#endif
}
void substitute(assertion_set & set) {
// force the cache of m_r to be reset.
m_r->set_substitution(&m_norm_subst);
expr_ref new_f(m());
proof_ref new_pr(m());
unsigned size = set.size();
for (unsigned idx = 0; idx < size; idx++) {
checkpoint();
expr * f = set.form(idx);
TRACE("gaussian_leak", tout << "processing:\n" << mk_ismt2_pp(f, m()) << "\n";);
if (m_candidate_set.is_marked(f)) {
// f may be deleted after the following update.
// so, we must remove remove the mark before doing the update
m_candidate_set.mark(f, false);
SASSERT(!m_candidate_set.is_marked(f));
set.update(idx, m().mk_true(), m().mk_true_proof());
m_num_steps ++;
continue;
}
else {
m_r->operator()(f, new_f, new_pr);
}
TRACE("gaussian_elim_subst", tout << mk_ismt2_pp(f, m()) << "\n--->\n" << mk_ismt2_pp(new_f, m()) << "\n";);
m_num_steps += m_r->get_num_steps() + 1;
if (m().proofs_enabled()) {
new_pr = m().mk_modus_ponens(set.pr(idx), new_pr);
}
set.update(idx, new_f, new_pr);
if (set.inconsistent())
return;
}
set.elim_true();
TRACE("gaussian_elim",
tout << "after applying substitution\n";
set.display(tout););
#if 0
DEBUG_CODE({
for (unsigned i = 0; i < m_ordered_vars.size(); i++) {
expr * v = m_ordered_vars[i];
for (unsigned j = 0; j < set.size(); j++) {
CASSERT("gaussian_elim_bug", !occurs(v, set.form(j)));
}
}});
#endif
}
void save_elim_vars(model_converter_ref & mc) {
IF_VERBOSE(100, if (!m_ordered_vars.empty()) verbose_stream() << "num. eliminated vars: " << m_ordered_vars.size() << "\n";);
m_num_eliminated_vars += m_ordered_vars.size();
if (m_produce_models) {
if (mc.get() == 0)
mc = alloc(gmc, m());
ptr_vector<app>::iterator it = m_ordered_vars.begin();
ptr_vector<app>::iterator end = m_ordered_vars.end();
for (; it != end; ++it) {
app * v = *it;
expr * def = 0;
proof * pr;
m_norm_subst.find(v, def, pr);
SASSERT(def != 0);
static_cast<gmc*>(mc.get())->insert(v->get_decl(), def);
}
}
}
void collect_num_occs(expr * t, expr_fast_mark1 & visited) {
ptr_buffer<expr, 128> stack;
#define VISIT(ARG) { \
if (is_uninterp_const(ARG)) { \
obj_map<expr, unsigned>::obj_map_entry * entry = m_num_occs.insert_if_not_there2(ARG, 0); \
entry->get_data().m_value++; \
} \
if (!visited.is_marked(ARG)) { \
visited.mark(ARG, true); \
stack.push_back(ARG); \
} \
}
VISIT(t);
while (!stack.empty()) {
expr * t = stack.back();
stack.pop_back();
if (!is_app(t))
continue;
unsigned j = to_app(t)->get_num_args();
while (j > 0) {
--j;
expr * arg = to_app(t)->get_arg(j);
VISIT(arg);
}
}
}
void collect_num_occs(assertion_set & s) {
if (m_max_occs == UINT_MAX)
return; // no need to compute num occs
m_num_occs.reset();
expr_fast_mark1 visited;
unsigned sz = s.size();
for (unsigned i = 0; i < sz; i++)
collect_num_occs(s.form(i), visited);
}
void operator()(assertion_set & s, model_converter_ref & mc) {
SASSERT(is_well_sorted(s));
as_st_report report("gaussian-elimination", s);
TRACE("gaussian_elim", tout << "starting guassian elimination\n"; s.display(tout); tout << "\n";);
m_num_steps = 0;
mc = 0;
if (s.inconsistent())
return;
while (true) {
collect_num_occs(s);
collect(s);
if (m_subst.empty())
break;
sort_vars();
if (m_ordered_vars.empty())
break;
normalize();
substitute(s);
if (s.inconsistent()) {
mc = 0;
break;
}
save_elim_vars(mc);
TRACE("gaussian_elim_round", s.display(tout); if (mc) mc->display(tout););
}
TRACE("gaussian_elim", s.display(tout););
SASSERT(is_well_sorted(s));
}
void set_cancel(bool f) {
m_cancel = f;
m_r->set_cancel(f);
}
unsigned get_num_steps() const {
return m_num_steps;
}
unsigned get_num_eliminated_vars() const {
return m_num_eliminated_vars;
}
};
gaussian_elim::gaussian_elim(ast_manager & m, params_ref const & p, expr_replacer * r, bool owner):
m_params(p) {
m_imp = alloc(imp, m, p, r, owner);
}
gaussian_elim::~gaussian_elim() {
dealloc(m_imp);
}
ast_manager & gaussian_elim::m() const {
return m_imp->m();
}
void gaussian_elim::updt_params(params_ref const & p) {
m_params = p;
m_imp->updt_params(p);
}
void gaussian_elim::get_param_descrs(param_descrs & r) {
insert_produce_models(r);
r.insert(":gaussian-max-occs", CPK_UINT, "(default: infty) maximum number of occurrences for considering a variable for gaussian eliminations.");
r.insert(":theory-solver", CPK_BOOL, "(default: true) use theory solvers.");
r.insert(":ite-solver", CPK_BOOL, "(default: true) use if-then-else solver.");
}
void gaussian_elim::operator()(assertion_set & s, model_converter_ref & mc) {
m_imp->operator()(s, mc);
report_st_progress(":num-elim-vars", get_num_eliminated_vars());
}
void gaussian_elim::set_cancel(bool f) {
if (m_imp)
m_imp->set_cancel(f);
}
void gaussian_elim::cleanup() {
unsigned num_elim_vars = m_imp->m_num_eliminated_vars;
ast_manager & m = m_imp->m();
imp * d = m_imp;
expr_replacer * r = m_imp->m_r_owner ? m_imp->m_r : 0;
if (r)
r->set_substitution(0);
bool owner = m_imp->m_r_owner;
m_imp->m_r_owner = false; // stole replacer
#pragma omp critical (as_st_cancel)
{
m_imp = 0;
}
dealloc(d);
d = alloc(imp, m, m_params, r, owner);
#pragma omp critical (as_st_cancel)
{
m_imp = d;
}
m_imp->m_num_eliminated_vars = num_elim_vars;
}
unsigned gaussian_elim::get_num_steps() const {
return m_imp->get_num_steps();
}
unsigned gaussian_elim::get_num_eliminated_vars() const {
return m_imp->get_num_eliminated_vars();
}
void gaussian_elim::collect_statistics(statistics & st) const {
st.update("eliminated vars", get_num_eliminated_vars());
}
void gaussian_elim::reset_statistics() {
m_imp->m_num_eliminated_vars = 0;
}
as_st * mk_gaussian(ast_manager & m, params_ref const & p) {
return clean(alloc(gaussian_elim, m, p, mk_expr_simp_replacer(m, p), true));
}

View file

@ -1,66 +0,0 @@
/*++
Copyright (c) 2011 Microsoft Corporation
Module Name:
gaussian_elim.h
Abstract:
(extended) Gaussian elimination for assertion sets.
It also supports other theories besides arithmetic.
Author:
Leonardo (leonardo) 2011-04-21
Notes:
--*/
#ifndef _GAUSSIAN_ELIM_H_
#define _GAUSSIAN_ELIM_H_
#include"assertion_set_strategy.h"
class expr_replacer;
MK_ST_EXCEPTION(gaussian_elim_exception);
class gaussian_elim : public assertion_set_strategy {
struct imp;
imp * m_imp;
params_ref m_params;
public:
gaussian_elim(ast_manager & m, params_ref const & p = params_ref(), expr_replacer * r = 0, bool owner = false);
virtual ~gaussian_elim();
ast_manager & m () const;
virtual void updt_params(params_ref const & p);
static void get_param_descrs(param_descrs & r);
virtual void collect_param_descrs(param_descrs & r) { get_param_descrs(r); }
/**
\brief Apply gaussian elimination on the assertion set \c s.
Return a model_converter that converts any model for the updated set into a model for the old set.
*/
virtual void operator()(assertion_set & s, model_converter_ref & mc);
virtual void cleanup();
unsigned get_num_steps() const;
unsigned get_num_eliminated_vars() const;
virtual void collect_statistics(statistics & st) const;
virtual void reset_statistics();
protected:
virtual void set_cancel(bool f);
};
as_st * mk_gaussian(ast_manager & m, params_ref const & p = params_ref());
inline as_st * mk_eq_solver(ast_manager & m, params_ref const & p = params_ref()) {
return mk_gaussian(m, p);
}
#endif

View file

@ -1,276 +0,0 @@
/*++
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;
}
}

View file

@ -1,70 +0,0 @@
/*++
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_ */

View file

@ -1,184 +0,0 @@
/*++
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;
}
}

View file

@ -1,49 +0,0 @@
/*++
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_ */

View file

@ -1,56 +0,0 @@
/*++
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

@ -1,81 +0,0 @@
/*++
Copyright (c) 2006 Microsoft Corporation
Module Name:
matcher.cpp
Abstract:
<abstract>
Author:
Leonardo de Moura (leonardo) 2008-02-02.
Revision History:
--*/
#include"matcher.h"
matcher::matcher(ast_manager & m):
m_manager(m) {
}
bool matcher::operator()(expr * e1, expr * e2, substitution & s) {
reset();
m_subst = &s;
m_todo.push_back(expr_pair(e1, e2));
while (!m_todo.empty()) {
expr_pair const & p = m_todo.back();
// if (m_cache.contains(p)) {
// m_todo.pop_back();
// continue;
// }
if (is_var(p.first)) {
expr_offset r;
if (m_subst->find(to_var(p.first), 0, r)) {
if (r.get_expr() != p.second)
return false;
}
else {
m_subst->insert(to_var(p.first), 0, expr_offset(p.second, 1));
}
m_todo.pop_back();
continue;
}
if (is_var(p.second))
return false;
app * n1 = to_app(p.first);
app * n2 = to_app(p.second);
if (n1->get_decl() != n2->get_decl())
return false;
unsigned num_args1 = n1->get_num_args();
if (num_args1 != n2->get_num_args())
return false;
m_todo.pop_back();
if (num_args1 == 0)
continue;
// m_cache.insert(p);
unsigned j = num_args1;
while (j > 0) {
--j;
m_todo.push_back(expr_pair(n1->get_arg(j), n2->get_arg(j)));
}
}
return true;
}
void matcher::reset() {
// m_cache.reset();
m_todo.reset();
}

View file

@ -1,64 +0,0 @@
/*++
Copyright (c) 2006 Microsoft Corporation
Module Name:
matcher.h
Abstract:
<abstract>
Author:
Leonardo de Moura (leonardo) 2008-02-02.
Revision History:
--*/
#ifndef _MATCHER_H_
#define _MATCHER_H_
#include"substitution.h"
#include"hashtable.h"
/**
\brief Functor for matching expressions.
*/
class matcher {
typedef std::pair<expr *, expr *> expr_pair;
typedef pair_hash<obj_ptr_hash<expr>, obj_ptr_hash<expr> > expr_pair_hash;
typedef hashtable<expr_pair, expr_pair_hash, default_eq<expr_pair> > cache;
ast_manager & m_manager;
substitution * m_subst;
cache m_cache;
svector<expr_pair> m_todo;
void reset();
public:
matcher(ast_manager & m);
/**
\brief Return true if e2 is an instance of e1.
In case of success (result is true), it will store the substitution that makes e1 equals to e2 into s.
For example:
1) e1 = f(g(x), x), e2 = f(g(h(a)), h(a))
The result is true, and s will contain x -> h(a)
2) e1 = f(a, x) e2 = f(x, a)
The result is false.
3) e1 = f(x, x) e2 = f(y, a)
The result is false
4) e1 = f(x, y) e2 = f(h(z), a)
The result is true, and s contains x->h(z) and y->a
*/
bool operator()(expr * e1, expr * e2, substitution & s);
};
#endif /* _MATCHER_H_ */

View file

@ -1,167 +0,0 @@
/*++
Copyright (c) 2011 Microsoft Corporation
Module Name:
name_exprs.h
Abstract:
Goodies for naming nested expressions.
Author:
Leonardo (leonardo) 2011-10-06
Notes:
--*/
#include"name_exprs.h"
#include"rewriter_def.h"
#include"ast_smt2_pp.h"
class name_exprs_core : public name_exprs {
struct cfg : public default_rewriter_cfg {
ast_manager & m_manager;
defined_names & m_defined_names;
expr_predicate & m_pred;
app_ref m_r;
proof_ref m_pr;
expr_ref_vector * m_def_exprs;
proof_ref_vector * m_def_proofs;
cfg(ast_manager & m, defined_names & n, expr_predicate & pred):
m_manager(m),
m_defined_names(n),
m_pred(pred),
m_r(m),
m_pr(m),
m_def_exprs(0),
m_def_proofs(0) {
}
void gen_name_for_expr(expr * n, expr * & t, proof * & t_pr) {
expr_ref new_def(m_manager);
proof_ref new_def_pr(m_manager);
if (m_defined_names.mk_name(n, new_def, new_def_pr, m_r, m_pr)) {
m_def_exprs->push_back(new_def);
if (m_manager.proofs_enabled())
m_def_proofs->push_back(new_def_pr);
}
t = m_r.get();
t_pr = m_pr.get();
}
bool get_subst(expr * s, expr * & t, proof * & t_pr) {
TRACE("name_exprs", tout << "get_subst:\n" << mk_ismt2_pp(s, m_manager) << "\n";);
if (m_pred(s)) {
gen_name_for_expr(s, t, t_pr);
return true;
}
return false;
}
};
typedef rewriter_tpl<cfg> rw;
cfg m_cfg;
rw m_rw;
public:
name_exprs_core(ast_manager & m, defined_names & n, expr_predicate & pred):
m_cfg(m, n, pred),
m_rw(m, m.proofs_enabled(), m_cfg) {
}
virtual ~name_exprs_core() {
}
virtual void operator()(expr * n, expr_ref_vector & new_defs, proof_ref_vector & new_def_proofs, expr_ref & r, proof_ref & p) {
m_cfg.m_def_exprs = &new_defs;
m_cfg.m_def_proofs = &new_def_proofs;
m_rw(n, r, p);
TRACE("name_exprs", tout << mk_ismt2_pp(n, m_rw.m()) << "\n---->\n" << mk_ismt2_pp(r, m_rw.m()) << "\n";);
}
virtual void set_cancel(bool f) {
m_rw.set_cancel(f);
}
virtual void reset() {
m_rw.reset();
}
};
name_exprs * mk_expr_namer(ast_manager & m, defined_names & n, expr_predicate & pred) {
return alloc(name_exprs_core, m, n, pred);
}
class name_quantifier_labels : public name_exprs_core {
class pred : public expr_predicate {
ast_manager & m_manager;
public:
pred(ast_manager & m):m_manager(m) {}
virtual bool operator()(expr * t) {
return is_quantifier(t) || m_manager.is_label(t);
}
};
pred m_pred;
public:
name_quantifier_labels(ast_manager & m, defined_names & n):
name_exprs_core(m, n, m_pred),
m_pred(m) {
}
virtual ~name_quantifier_labels() {
}
};
name_exprs * mk_quantifier_label_namer(ast_manager & m, defined_names & n) {
return alloc(name_quantifier_labels, m, n);
}
class name_nested_formulas : public name_exprs_core {
struct pred : public expr_predicate {
ast_manager & m_manager;
expr * m_root;
pred(ast_manager & m):m_manager(m), m_root(0) {}
virtual bool operator()(expr * t) {
TRACE("name_exprs", tout << "name_nested_formulas::pred:\n" << mk_ismt2_pp(t, m_manager) << "\n";);
if (is_app(t))
return to_app(t)->get_family_id() == m_manager.get_basic_family_id() && to_app(t)->get_num_args() > 0 && t != m_root;
return m_manager.is_label(t) || is_quantifier(t);
}
};
pred m_pred;
public:
name_nested_formulas(ast_manager & m, defined_names & n):
name_exprs_core(m, n, m_pred),
m_pred(m) {
}
virtual ~name_nested_formulas() {
}
virtual void operator()(expr * n, expr_ref_vector & new_defs, proof_ref_vector & new_def_proofs, expr_ref & r, proof_ref & p) {
m_pred.m_root = n;
TRACE("name_exprs", tout << "operator()\n";);
name_exprs_core::operator()(n, new_defs, new_def_proofs, r, p);
}
};
name_exprs * mk_nested_formula_namer(ast_manager & m, defined_names & n) {
return alloc(name_nested_formulas, m, n);
}
void del_name_exprs(name_exprs * functor) {
dealloc(functor);
}

View file

@ -1,65 +0,0 @@
/*++
Copyright (c) 2011 Microsoft Corporation
Module Name:
name_exprs.h
Abstract:
Goodies for naming nested expressions.
Author:
Leonardo (leonardo) 2011-10-06
Notes:
--*/
#ifndef _NAME_EXPRS_H_
#define _NAME_EXPRS_H_
#include"ast.h"
#include"defined_names.h"
class expr_predicate {
public:
virtual bool operator()(expr * t) = 0;
};
class name_exprs {
public:
virtual ~name_exprs() {}
virtual void operator()(expr * n, // [IN] expression that contain the sub-expressions to be named
expr_ref_vector & new_defs, // [OUT] new definitions
proof_ref_vector & new_def_proofs, // [OUT] proofs of the new definitions
expr_ref & r, // [OUT] resultant expression
proof_ref & p // [OUT] proof for (iff n p)
) = 0;
virtual void set_cancel(bool f) = 0;
void cancel() { set_cancel(true); }
void reset_cancel() { set_cancel(false); }
virtual void reset() = 0;
};
/**
\brief Create an expression "namer" that will create replace nested expressions that satisfy pred with new
fresh declarations.
*/
name_exprs * mk_expr_namer(ast_manager & m, defined_names & n, expr_predicate & pred);
/**
\brief Create an expression "namer" that will replace quantifiers and labels with new fresh declarations.
*/
name_exprs * mk_quantifier_label_namer(ast_manager & m, defined_names & n);
/**
\brief Create an expression "namer" that will replace all nested formulas and term if-then-elses with
fresh declarations.
*/
name_exprs * mk_nested_formula_namer(ast_manager & m, defined_names & n);
void del_name_exprs(name_exprs * functor);
#endif

File diff suppressed because it is too large Load diff

View file

@ -1,68 +0,0 @@
/*++
Copyright (c) 2007 Microsoft Corporation
Module Name:
nnf.h
Abstract:
Negation Normal Form & Skolemization
Author:
Leonardo (leonardo) 2008-01-11
Notes:
Major revision on 2011-10-06
--*/
#ifndef _NNF_H_
#define _NNF_H_
#include"ast.h"
#include"nnf_params.h"
#include"params.h"
#include"defined_names.h"
class nnf {
struct imp;
imp * m_imp;
public:
nnf(ast_manager & m, defined_names & n, params_ref const & p = params_ref());
nnf(ast_manager & m, defined_names & n, nnf_params & params); // for backward compatibility
~nnf();
void operator()(expr * n, // [IN] expression that should be put into NNF
expr_ref_vector & new_defs, // [OUT] new definitions
proof_ref_vector & new_def_proofs, // [OUT] proofs of the new definitions
expr_ref & r, // [OUT] resultant expression
proof_ref & p // [OUT] proof for (~ n r)
);
void updt_params(params_ref const & p);
static void get_param_descrs(param_descrs & r);
void cancel() { set_cancel(true); }
void reset_cancel() { set_cancel(false); }
void set_cancel(bool f);
void reset();
void reset_cache();
};
// Old strategy framework
class assertion_set_strategy;
// Skolem Normal Form
assertion_set_strategy * mk_snf(params_ref const & p = params_ref());
// Negation Normal Form
assertion_set_strategy * mk_nnf(params_ref const & p = params_ref());
// New strategy framework
class tactic;
// Skolem Normal Form
tactic * mk_snf_tactic(ast_manager & m, params_ref const & p = params_ref());
// Negation Normal Form
tactic * mk_nnf_tactic(ast_manager & m, params_ref const & p = params_ref());
#endif /* _NNF_H_ */

View file

@ -1,88 +0,0 @@
/*++
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

@ -1,47 +0,0 @@
/*++
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_ */

View file

@ -1,92 +0,0 @@
/*++
Copyright (c) 2006 Microsoft Corporation
Module Name:
num_occurs.cpp
Abstract:
<abstract>
Author:
Leonardo de Moura (leonardo) 2008-01-27.
Revision History:
--*/
#include"num_occurs.h"
#include"assertion_set.h"
#include"goal.h"
void num_occurs::process(expr * t, expr_fast_mark1 & visited) {
ptr_buffer<expr, 128> stack;
#define VISIT(ARG) { \
if (!m_ignore_ref_count1 || ARG->get_ref_count() > 1) { \
obj_map<expr, unsigned>::obj_map_entry * entry = m_num_occurs.insert_if_not_there2(ARG, 0); \
entry->get_data().m_value++; \
} \
if (!visited.is_marked(ARG)) { \
visited.mark(ARG, true); \
stack.push_back(ARG); \
} \
}
VISIT(t);
while (!stack.empty()) {
expr * t = stack.back();
stack.pop_back();
unsigned j;
switch (t->get_kind()) {
case AST_APP:
j = to_app(t)->get_num_args();
while (j > 0) {
--j;
expr * arg = to_app(t)->get_arg(j);
VISIT(arg);
}
break;
case AST_QUANTIFIER:
if (!m_ignore_quantifiers) {
expr * child = to_quantifier(t)->get_expr();
VISIT(child);
}
break;
default:
break;
}
}
}
void num_occurs::operator()(expr * t) {
expr_fast_mark1 visited;
process(t, visited);
}
void num_occurs::operator()(unsigned num, expr * const * ts) {
expr_fast_mark1 visited;
for (unsigned i = 0; i < num; i++) {
process(ts[i], visited);
}
}
// TODO delete
void num_occurs::operator()(assertion_set const & s) {
expr_fast_mark1 visited;
unsigned sz = s.size();
for (unsigned i = 0; i < sz; i++) {
process(s.form(i), visited);
}
}
void num_occurs::operator()(goal const & g) {
expr_fast_mark1 visited;
unsigned sz = g.size();
for (unsigned i = 0; i < sz; i++) {
process(g.form(i), visited);
}
}

View file

@ -1,59 +0,0 @@
/*++
Copyright (c) 2006 Microsoft Corporation
Module Name:
num_occurs.h
Abstract:
<abstract>
Author:
Leonardo de Moura (leonardo) 2008-01-27.
Revision History:
--*/
#ifndef _NUM_OCCURS_H_
#define _NUM_OCCURS_H_
#include"ast.h"
#include"obj_hashtable.h"
class assertion_set; // TODO delete
class goal;
/**
\brief Functor for computing the number of occurrences of each sub-expression in a expression F.
*/
class num_occurs {
bool m_ignore_ref_count1;
bool m_ignore_quantifiers;
obj_map<expr, unsigned> m_num_occurs;
void process(expr * t, expr_fast_mark1 & visited);
public:
num_occurs(bool ignore_ref_count1 = false, bool ignore_quantifiers = false):
m_ignore_ref_count1(ignore_ref_count1),
m_ignore_quantifiers(ignore_quantifiers) {
}
void reset() { m_num_occurs.reset(); }
void operator()(expr * t);
void operator()(unsigned num, expr * const * ts);
void operator()(assertion_set const & s); // TODO delete
void operator()(goal const & s);
unsigned get_num_occs(expr * n) const {
unsigned val;
if (m_num_occurs.find(n, val))
return val;
return 0;
}
};
#endif /* _NUM_OCCURS_H_ */

View file

@ -1,77 +0,0 @@
/*++
Copyright (c) 2006 Microsoft Corporation
Module Name:
occurs.cpp
Abstract:
<abstract>
Author:
Leonardo de Moura (leonardo) 2007-06-07.
Revision History:
--*/
#include"occurs.h"
#include"for_each_expr.h"
// -----------------------------------
//
// Occurs check
//
// -----------------------------------
namespace occurs_namespace {
struct found {};
struct proc {
expr * m_n;
#define CHECK() { if (n == m_n) throw found(); }
proc(expr * n):m_n(n) {}
void operator()(var const * n) { CHECK(); }
void operator()(app const * n) { CHECK(); }
void operator()(quantifier const * n) { CHECK(); }
};
struct decl_proc {
func_decl * m_d;
decl_proc(func_decl * d):m_d(d) {}
void operator()(var const * n) { }
void operator()(app const * n) { if (n->get_decl() == m_d) throw found(); }
void operator()(quantifier const * n) { }
};
};
// Return true if n1 occurs in n2
bool occurs(expr * n1, expr * n2) {
occurs_namespace::proc p(n1);
try {
quick_for_each_expr(p, n2);
}
catch (occurs_namespace::found) {
return true;
}
return false;
}
bool occurs(func_decl * d, expr * n) {
occurs_namespace::decl_proc p(d);
try {
quick_for_each_expr(p, n);
}
catch (occurs_namespace::found) {
return true;
}
return false;
}

View file

@ -1,36 +0,0 @@
/*++
Copyright (c) 2006 Microsoft Corporation
Module Name:
occurs.h
Abstract:
<abstract>
Author:
Leonardo de Moura (leonardo) 2007-06-07.
Revision History:
--*/
#ifndef _OCCURS_H_
#define _OCCURS_H_
class expr;
class func_decl;
/**
\brief Return true if n1 occurs in n2
*/
bool occurs(expr * n1, expr * n2);
/**
\brief Return true if d is used in n
*/
bool occurs(func_decl * d, expr * n);
#endif /* _OCCURS_H_ */

View file

@ -1,51 +0,0 @@
/*++
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;
}

View file

@ -1,87 +0,0 @@
/*++
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_ */

View file

@ -1,744 +0,0 @@
/*++
Copyright (c) 2006 Microsoft Corporation
Module Name:
pattern_inference.cpp
Abstract:
<abstract>
Author:
Leonardo de Moura (leonardo) 2006-12-08.
Revision History:
--*/
#include"pattern_inference.h"
#include"ast_ll_pp.h"
#include"ast_pp.h"
#include"ast_util.h"
#include"warning.h"
#include"arith_decl_plugin.h"
#include"pull_quant.h"
#include"well_sorted.h"
#include"for_each_expr.h"
void smaller_pattern::save(expr * p1, expr * p2) {
expr_pair e(p1, p2);
if (!m_cache.contains(e)) {
TRACE("smaller_pattern_proc", tout << "saving: " << p1->get_id() << " " << p2->get_id() << "\n";);
m_cache.insert(e);
m_todo.push_back(e);
}
}
bool smaller_pattern::process(expr * p1, expr * p2) {
m_todo.reset();
m_cache.reset();
save(p1, p2);
while (!m_todo.empty()) {
expr_pair & curr = m_todo.back();
p1 = curr.first;
p2 = curr.second;
m_todo.pop_back();
ast_kind k1 = p1->get_kind();
if (k1 != AST_VAR && k1 != p2->get_kind())
return false;
switch (k1) {
case AST_APP: {
app * app1 = to_app(p1);
app * app2 = to_app(p2);
unsigned num1 = app1->get_num_args();
if (num1 != app2->get_num_args() || app1->get_decl() != app2->get_decl())
return false;
for (unsigned i = 0; i < num1; i++)
save(app1->get_arg(i), app2->get_arg(i));
break;
}
case AST_VAR: {
unsigned idx = to_var(p1)->get_idx();
if (idx < m_bindings.size()) {
if (m_bindings[idx] == 0)
m_bindings[idx] = p2;
else if (m_bindings[idx] != p2)
return false;
}
// it is a variable bound by an external quantifier
else if (p1 != p2)
return false;
break;
}
default:
if (p1 != p2)
return false;
break;
}
}
return true;
}
bool smaller_pattern::operator()(unsigned num_bindings, expr * p1, expr * p2) {
m_bindings.resize(num_bindings);
for (unsigned i = 0; i < num_bindings; i++)
m_bindings[i] = 0;
return process(p1, p2);
}
pattern_inference::pattern_inference(ast_manager & m, pattern_inference_params & params):
simplifier(m),
m_params(params),
m_bfid(m.get_basic_family_id()),
m_afid(m.get_family_id("arith")),
m_le(m),
m_nested_arith_only(true),
m_block_loop_patterns(params.m_pi_block_loop_patterns),
m_candidates(m),
m_pattern_weight_lt(m_candidates_info),
m_collect(m, *this),
m_contains_subpattern(*this),
m_database(m) {
if (params.m_pi_arith == AP_NO)
register_forbidden_family(m_afid);
enable_ac_support(false);
}
void pattern_inference::collect::operator()(expr * n, unsigned num_bindings) {
SASSERT(m_info.empty());
SASSERT(m_todo.empty());
SASSERT(m_cache.empty());
m_num_bindings = num_bindings;
m_todo.push_back(entry(n, 0));
while (!m_todo.empty()) {
entry & e = m_todo.back();
n = e.m_node;
unsigned delta = e.m_delta;
TRACE("collect", tout << "processing: " << n->get_id() << " " << delta << " kind: " << n->get_kind() << "\n";);
TRACE("collect_info", tout << mk_pp(n, m_manager) << "\n";);
if (visit_children(n, delta)) {
m_todo.pop_back();
save_candidate(n, delta);
}
}
reset();
}
inline void pattern_inference::collect::visit(expr * n, unsigned delta, bool & visited) {
entry e(n, delta);
if (!m_cache.contains(e)) {
m_todo.push_back(e);
visited = false;
}
}
bool pattern_inference::collect::visit_children(expr * n, unsigned delta) {
bool visited = true;
unsigned i;
switch (n->get_kind()) {
case AST_APP:
i = to_app(n)->get_num_args();
while (i > 0) {
--i;
visit(to_app(n)->get_arg(i), delta, visited);
}
break;
case AST_QUANTIFIER:
visit(to_quantifier(n)->get_expr(), delta + to_quantifier(n)->get_num_decls(), visited);
break;
default:
break;
}
return visited;
}
inline void pattern_inference::collect::save(expr * n, unsigned delta, info * i) {
m_cache.insert(entry(n, delta), i);
if (i != 0)
m_info.push_back(i);
}
void pattern_inference::collect::save_candidate(expr * n, unsigned delta) {
switch (n->get_kind()) {
case AST_VAR: {
unsigned idx = to_var(n)->get_idx();
if (idx >= delta) {
idx = idx - delta;
uint_set free_vars;
if (idx < m_num_bindings)
free_vars.insert(idx);
info * i = 0;
if (delta == 0)
i = alloc(info, m_manager, n, free_vars, 1);
else
i = alloc(info, m_manager, m_manager.mk_var(idx, to_var(n)->get_sort()), free_vars, 1);
save(n, delta, i);
}
else {
save(n, delta, 0);
}
return;
}
case AST_APP: {
app * c = to_app(n);
func_decl * decl = c->get_decl();
if (m_owner.is_forbidden(c)) {
save(n, delta, 0);
return;
}
if (c->get_num_args() == 0) {
save(n, delta, alloc(info, m_manager, n, uint_set(), 1));
return;
}
ptr_buffer<expr> buffer;
bool changed = false; // false if none of the children is mapped to a node different from itself.
uint_set free_vars;
unsigned size = 1;
unsigned num = c->get_num_args();
for (unsigned i = 0; i < num; i++) {
expr * child = c->get_arg(i);
info * child_info = 0;
#ifdef Z3DEBUG
bool found =
#endif
m_cache.find(entry(child, delta), child_info);
SASSERT(found);
if (child_info == 0) {
save(n, delta, 0);
return;
}
buffer.push_back(child_info->m_node.get());
free_vars |= child_info->m_free_vars;
size += child_info->m_size;
if (child != child_info->m_node.get())
changed = true;
}
app * new_node = 0;
if (changed)
new_node = m_manager.mk_app(decl, buffer.size(), buffer.c_ptr());
else
new_node = to_app(n);
save(n, delta, alloc(info, m_manager, new_node, free_vars, size));
// Remark: arithmetic patterns are only used if they are nested inside other terms.
// That is, we never consider x + 1 as pattern. On the other hand, f(x+1) can be a pattern
// if arithmetic is not in the forbidden list.
//
// Remark: The rule above has an exception. The operators (div, idiv, mod) are allowed to be
// used as patterns even when they are not nested in other terms. The motivation is that
// Z3 currently doesn't implement them (i.e., they are uninterpreted). So, some users add axioms
// stating properties about these operators.
family_id fid = c->get_family_id();
decl_kind k = c->get_decl_kind();
if (!free_vars.empty() &&
(fid != m_afid || (fid == m_afid && !m_owner.m_nested_arith_only && (k == OP_DIV || k == OP_IDIV || k == OP_MOD || k == OP_REM || k == OP_MUL)))) {
TRACE("pattern_inference", tout << "potential candidate: \n" << mk_pp(new_node, m_manager) << "\n";);
m_owner.add_candidate(new_node, free_vars, size);
}
return;
}
default:
save(n, delta, 0);
return;
}
}
void pattern_inference::collect::reset() {
m_cache.reset();
std::for_each(m_info.begin(), m_info.end(), delete_proc<info>());
m_info.reset();
SASSERT(m_todo.empty());
}
void pattern_inference::add_candidate(app * n, uint_set const & free_vars, unsigned size) {
for (unsigned i = 0; i < m_num_no_patterns; i++) {
if (n == m_no_patterns[i])
return;
}
if (!m_candidates_info.contains(n)) {
m_candidates_info.insert(n, info(free_vars, size));
m_candidates.push_back(n);
}
}
/**
\brief Copy the non-looping patterns in m_candidates to result when m_params.m_pi_block_loop_patterns = true.
Otherwise, copy m_candidates to result.
*/
void pattern_inference::filter_looping_patterns(ptr_vector<app> & result) {
unsigned num = m_candidates.size();
for (unsigned i1 = 0; i1 < num; i1++) {
app * n1 = m_candidates.get(i1);
expr2info::obj_map_entry * e1 = m_candidates_info.find_core(n1);
SASSERT(e1);
uint_set const & s1 = e1->get_data().m_value.m_free_vars;
if (m_block_loop_patterns) {
bool smaller = false;
for (unsigned i2 = 0; i2 < num; i2++) {
if (i1 != i2) {
app * n2 = m_candidates.get(i2);
expr2info::obj_map_entry * e2 = m_candidates_info.find_core(n2);
if (e2) {
uint_set const & s2 = e2->get_data().m_value.m_free_vars;
// Remark: the comparison operator only makes sense if both AST nodes
// contain the same number of variables.
// Example:
// (f X Y) <: (f (g X Z W) Y)
if (s1 == s2 && m_le(m_num_bindings, n1, n2) && !m_le(m_num_bindings, n2, n1)) {
smaller = true;
break;
}
}
}
}
if (!smaller)
result.push_back(n1);
else
m_candidates_info.erase(n1);
}
else {
result.push_back(n1);
}
}
}
inline void pattern_inference::contains_subpattern::save(expr * n) {
unsigned id = n->get_id();
m_already_processed.assure_domain(id);
if (!m_already_processed.contains(id)) {
m_todo.push_back(n);
m_already_processed.insert(id);
}
}
bool pattern_inference::contains_subpattern::operator()(expr * n) {
m_already_processed.reset();
m_todo.reset();
expr2info::obj_map_entry * _e = m_owner.m_candidates_info.find_core(n);
SASSERT(_e);
uint_set const & s1 = _e->get_data().m_value.m_free_vars;
save(n);
unsigned num;
while (!m_todo.empty()) {
expr * curr = m_todo.back();
m_todo.pop_back();
switch (curr->get_kind()) {
case AST_APP:
if (curr != n) {
expr2info::obj_map_entry * e = m_owner.m_candidates_info.find_core(curr);
if (e) {
uint_set const & s2 = e->get_data().m_value.m_free_vars;
SASSERT(s2.subset_of(s1));
if (s1 == s2) {
TRACE("pattern_inference", tout << mk_pp(n, m_owner.m_manager) << "\nis bigger than\n" << mk_pp(to_app(curr), m_owner.m_manager) << "\n";);
return true;
}
}
}
num = to_app(curr)->get_num_args();
for (unsigned i = 0; i < num; i++)
save(to_app(curr)->get_arg(i));
break;
case AST_VAR:
break;
default:
UNREACHABLE();
}
}
return false;
}
/**
Return true if n contains a direct/indirect child that is also a
pattern, and contains the same number of free variables.
*/
inline bool pattern_inference::contains_subpattern(expr * n) {
return m_contains_subpattern(n);
}
/**
\brief Copy a pattern p in patterns to result, if there is no
direct/indirect child of p in patterns which contains the same set
of variables.
Remark: Every pattern p in patterns is also a member of
m_pattern_map.
*/
void pattern_inference::filter_bigger_patterns(ptr_vector<app> const & patterns, ptr_vector<app> & result) {
ptr_vector<app>::const_iterator it = patterns.begin();
ptr_vector<app>::const_iterator end = patterns.end();
for (; it != end; ++it) {
app * curr = *it;
if (!contains_subpattern(curr))
result.push_back(curr);
}
}
bool pattern_inference::pattern_weight_lt::operator()(expr * n1, expr * n2) const {
expr2info::obj_map_entry * e1 = m_candidates_info.find_core(n1);
expr2info::obj_map_entry * e2 = m_candidates_info.find_core(n2);
SASSERT(e1 != 0);
SASSERT(e2 != 0);
info const & i1 = e1->get_data().m_value;
info const & i2 = e2->get_data().m_value;
unsigned num_free_vars1 = i1.m_free_vars.num_elems();
unsigned num_free_vars2 = i2.m_free_vars.num_elems();
return num_free_vars1 > num_free_vars2 || (num_free_vars1 == num_free_vars2 && i1.m_size < i2.m_size);
}
/**
\brief Create unary patterns (single expressions that contain all
bound variables). If a candidate does not contain all bound
variables, then it is copied to remaining_candidate_patterns. The
new patterns are stored in result.
*/
void pattern_inference::candidates2unary_patterns(ptr_vector<app> const & candidate_patterns,
ptr_vector<app> & remaining_candidate_patterns,
app_ref_buffer & result) {
ptr_vector<app>::const_iterator it = candidate_patterns.begin();
ptr_vector<app>::const_iterator end = candidate_patterns.end();
for (; it != end; ++it) {
app * candidate = *it;
expr2info::obj_map_entry * e = m_candidates_info.find_core(candidate);
info const & i = e->get_data().m_value;
if (i.m_free_vars.num_elems() == m_num_bindings) {
app * new_pattern = m_manager.mk_pattern(candidate);
result.push_back(new_pattern);
}
else {
remaining_candidate_patterns.push_back(candidate);
}
}
}
// TODO: this code is too inefficient when the number of candidate
// patterns is too big.
// HACK: limit the number of case-splits:
#define MAX_SPLITS 32
void pattern_inference::candidates2multi_patterns(unsigned max_num_patterns,
ptr_vector<app> const & candidate_patterns,
app_ref_buffer & result) {
SASSERT(!candidate_patterns.empty());
m_pre_patterns.push_back(alloc(pre_pattern));
unsigned sz = candidate_patterns.size();
unsigned num_splits = 0;
for (unsigned j = 0; j < m_pre_patterns.size(); j++) {
pre_pattern * curr = m_pre_patterns[j];
if (curr->m_free_vars.num_elems() == m_num_bindings) {
app * new_pattern = m_manager.mk_pattern(curr->m_exprs.size(), curr->m_exprs.c_ptr());
result.push_back(new_pattern);
if (result.size() >= max_num_patterns)
return;
}
else if (curr->m_idx < sz) {
app * n = candidate_patterns[curr->m_idx];
expr2info::obj_map_entry * e = m_candidates_info.find_core(n);
uint_set const & s = e->get_data().m_value.m_free_vars;
if (!s.subset_of(curr->m_free_vars)) {
pre_pattern * new_p = alloc(pre_pattern,*curr);
new_p->m_exprs.push_back(n);
new_p->m_free_vars |= s;
new_p->m_idx++;
m_pre_patterns.push_back(new_p);
if (num_splits < MAX_SPLITS) {
m_pre_patterns[j] = 0;
curr->m_idx++;
m_pre_patterns.push_back(curr);
num_splits++;
}
}
else {
m_pre_patterns[j] = 0;
curr->m_idx++;
m_pre_patterns.push_back(curr);
}
}
TRACE("pattern_inference", tout << "m_pre_patterns.size(): " << m_pre_patterns.size() <<
"\nnum_splits: " << num_splits << "\n";);
}
}
void pattern_inference::reset_pre_patterns() {
std::for_each(m_pre_patterns.begin(), m_pre_patterns.end(), delete_proc<pre_pattern>());
m_pre_patterns.reset();
}
static void dump_app_vector(std::ostream & out, ptr_vector<app> const & v, ast_manager & m) {
ptr_vector<app>::const_iterator it = v.begin();
ptr_vector<app>::const_iterator end = v.end();
for (; it != end; ++it)
out << mk_pp(*it, m) << "\n";
}
bool pattern_inference::is_forbidden(app * n) const {
func_decl const * decl = n->get_decl();
if (is_ground(n))
return false;
// Remark: skolem constants should not be used in patterns, since they do not
// occur outside of the quantifier. That is, Z3 will never match this kind of
// pattern.
if (m_params.m_pi_avoid_skolems && decl->is_skolem()) {
CTRACE("pattern_inference_skolem", decl->is_skolem(), tout << "ignoring: " << mk_pp(n, m_manager) << "\n";);
return true;
}
if (is_forbidden(decl))
return true;
return false;
}
bool pattern_inference::has_preferred_patterns(ptr_vector<app> & candidate_patterns, app_ref_buffer & result) {
if (m_preferred.empty())
return false;
bool found = false;
ptr_vector<app>::const_iterator it = candidate_patterns.begin();
ptr_vector<app>::const_iterator end = candidate_patterns.end();
for (; it != end; ++it) {
app * candidate = *it;
if (m_preferred.contains(to_app(candidate)->get_decl())) {
expr2info::obj_map_entry * e = m_candidates_info.find_core(candidate);
info const & i = e->get_data().m_value;
if (i.m_free_vars.num_elems() == m_num_bindings) {
TRACE("pattern_inference", tout << "found preferred pattern:\n" << mk_pp(candidate, m_manager) << "\n";);
app * p = m_manager.mk_pattern(candidate);
result.push_back(p);
found = true;
}
}
}
return found;
}
void pattern_inference::mk_patterns(unsigned num_bindings,
expr * n,
unsigned num_no_patterns,
expr * const * no_patterns,
app_ref_buffer & result) {
m_num_bindings = num_bindings;
m_num_no_patterns = num_no_patterns;
m_no_patterns = no_patterns;
m_collect(n, num_bindings);
TRACE("pattern_inference",
tout << mk_pp(n, m_manager);
tout << "\ncandidates:\n";
unsigned num = m_candidates.size();
for (unsigned i = 0; i < num; i++) {
tout << mk_pp(m_candidates.get(i), m_manager) << "\n";
});
if (!m_candidates.empty()) {
m_tmp1.reset();
filter_looping_patterns(m_tmp1);
TRACE("pattern_inference",
tout << "candidates after removing looping-patterns:\n";
dump_app_vector(tout, m_tmp1, m_manager););
SASSERT(!m_tmp1.empty());
if (!has_preferred_patterns(m_tmp1, result)) {
// continue if there are no preferred patterns
m_tmp2.reset();
filter_bigger_patterns(m_tmp1, m_tmp2);
SASSERT(!m_tmp2.empty());
TRACE("pattern_inference",
tout << "candidates after removing bigger patterns:\n";
dump_app_vector(tout, m_tmp2, m_manager););
m_tmp1.reset();
candidates2unary_patterns(m_tmp2, m_tmp1, result);
unsigned num_extra_multi_patterns = m_params.m_pi_max_multi_patterns;
if (result.empty())
num_extra_multi_patterns++;
if (num_extra_multi_patterns > 0 && !m_tmp1.empty()) {
// m_pattern_weight_lt is not a total order
std::stable_sort(m_tmp1.begin(), m_tmp1.end(), m_pattern_weight_lt);
TRACE("pattern_inference",
tout << "candidates after sorting:\n";
dump_app_vector(tout, m_tmp1, m_manager););
candidates2multi_patterns(num_extra_multi_patterns, m_tmp1, result);
}
}
}
reset_pre_patterns();
m_candidates_info.reset();
m_candidates.reset();
}
#include"database.h" // defines g_pattern_database
void pattern_inference::reduce1_quantifier(quantifier * q) {
TRACE("pattern_inference", tout << "processing:\n" << mk_pp(q, m_manager) << "\n";);
if (!q->is_forall()) {
simplifier::reduce1_quantifier(q);
return;
}
int weight = q->get_weight();
if (m_params.m_pi_use_database) {
m_database.initialize(g_pattern_database);
app_ref_vector new_patterns(m_manager);
unsigned new_weight;
if (m_database.match_quantifier(q, new_patterns, new_weight)) {
#ifdef Z3DEBUG
for (unsigned i = 0; i < new_patterns.size(); i++) { SASSERT(is_well_sorted(m_manager, new_patterns.get(i))); }
#endif
quantifier_ref new_q(m_manager);
if (q->get_num_patterns() > 0) {
// just update the weight...
TRACE("pattern_inference", tout << "updating weight to: " << new_weight << "\n" << mk_pp(q, m_manager) << "\n";);
new_q = m_manager.update_quantifier_weight(q, new_weight);
}
else {
quantifier_ref tmp(m_manager);
tmp = m_manager.update_quantifier(q, new_patterns.size(), (expr**) new_patterns.c_ptr(), q->get_expr());
new_q = m_manager.update_quantifier_weight(tmp, new_weight);
TRACE("pattern_inference", tout << "found patterns in database, weight: " << new_weight << "\n" << mk_pp(new_q, m_manager) << "\n";);
}
proof * pr = 0;
if (m_manager.fine_grain_proofs())
pr = m_manager.mk_rewrite(q, new_q);
cache_result(q, new_q, pr);
return;
}
}
if (q->get_num_patterns() > 0) {
simplifier::reduce1_quantifier(q);
return;
}
if (m_params.m_pi_nopat_weight >= 0)
weight = m_params.m_pi_nopat_weight;
SASSERT(q->get_num_patterns() == 0);
expr * new_body;
proof * new_body_pr;
get_cached(q->get_expr(), new_body, new_body_pr);
ptr_buffer<expr> new_no_patterns;
unsigned num_no_patterns = q->get_num_no_patterns();
for (unsigned i = 0; i < num_no_patterns; i++) {
expr * new_pattern;
proof * new_pattern_pr;
get_cached(q->get_no_pattern(i), new_pattern, new_pattern_pr);
new_no_patterns.push_back(new_pattern);
}
app_ref_buffer new_patterns(m_manager);
if (m_params.m_pi_arith == AP_CONSERVATIVE)
m_forbidden.push_back(m_afid);
mk_patterns(q->get_num_decls(), new_body, new_no_patterns.size(), new_no_patterns.c_ptr(), new_patterns);
if (new_patterns.empty() && !new_no_patterns.empty()) {
if (new_patterns.empty()) {
mk_patterns(q->get_num_decls(), new_body, 0, 0, new_patterns);
if (m_params.m_pi_warnings && !new_patterns.empty()) {
warning_msg("ignoring nopats annotation because Z3 couldn't find any other pattern (quantifier id: %s)", q->get_qid().str().c_str());
}
}
}
if (m_params.m_pi_arith == AP_CONSERVATIVE) {
m_forbidden.pop_back();
if (new_patterns.empty()) {
flet<bool> l1(m_block_loop_patterns, false); // allow looping patterns
mk_patterns(q->get_num_decls(), new_body, new_no_patterns.size(), new_no_patterns.c_ptr(), new_patterns);
if (!new_patterns.empty()) {
weight = std::max(weight, static_cast<int>(m_params.m_pi_arith_weight));
if (m_params.m_pi_warnings) {
warning_msg("using arith. in pattern (quantifier id: %s), the weight was increased to %d (this value can be modified using PI_ARITH_WEIGHT=<val>).",
q->get_qid().str().c_str(), weight);
}
}
}
}
if (m_params.m_pi_arith != AP_NO && new_patterns.empty()) {
if (new_patterns.empty()) {
flet<bool> l1(m_nested_arith_only, false); // try to find a non-nested arith pattern
flet<bool> l2(m_block_loop_patterns, false); // allow looping patterns
mk_patterns(q->get_num_decls(), new_body, new_no_patterns.size(), new_no_patterns.c_ptr(), new_patterns);
if (!new_patterns.empty()) {
weight = std::max(weight, static_cast<int>(m_params.m_pi_non_nested_arith_weight));
if (m_params.m_pi_warnings) {
warning_msg("using non nested arith. pattern (quantifier id: %s), the weight was increased to %d (this value can be modified using PI_NON_NESTED_ARITH_WEIGHT=<val>).",
q->get_qid().str().c_str(), weight);
}
// verbose_stream() << mk_pp(q, m_manager) << "\n";
}
}
}
quantifier_ref new_q(m_manager);
new_q = m_manager.update_quantifier(q, new_patterns.size(), (expr**) new_patterns.c_ptr(), new_body);
if (weight != q->get_weight())
new_q = m_manager.update_quantifier_weight(new_q, weight);
proof_ref pr(m_manager);
if (m_manager.fine_grain_proofs()) {
if (new_body_pr == 0)
new_body_pr = m_manager.mk_reflexivity(new_body);
pr = m_manager.mk_quant_intro(q, new_q, new_body_pr);
}
if (new_patterns.empty() && m_params.m_pi_pull_quantifiers) {
pull_quant pull(m_manager);
expr_ref new_expr(m_manager);
proof_ref new_pr(m_manager);
pull(new_q, new_expr, new_pr);
quantifier * new_new_q = to_quantifier(new_expr);
if (new_new_q != new_q) {
mk_patterns(new_new_q->get_num_decls(), new_new_q->get_expr(), 0, 0, new_patterns);
if (!new_patterns.empty()) {
if (m_params.m_pi_warnings) {
warning_msg("pulled nested quantifier to be able to find an useable pattern (quantifier id: %s)", q->get_qid().str().c_str());
}
new_q = m_manager.update_quantifier(new_new_q, new_patterns.size(), (expr**) new_patterns.c_ptr(), new_new_q->get_expr());
if (m_manager.fine_grain_proofs()) {
pr = m_manager.mk_transitivity(pr, new_pr);
pr = m_manager.mk_transitivity(pr, m_manager.mk_quant_intro(new_new_q, new_q, m_manager.mk_reflexivity(new_q->get_expr())));
}
TRACE("pattern_inference", tout << "pulled quantifier:\n" << mk_pp(new_q, m_manager) << "\n";);
}
}
}
if (new_patterns.empty()) {
if (m_params.m_pi_warnings) {
warning_msg("failed to find a pattern for quantifier (quantifier id: %s)", q->get_qid().str().c_str());
}
TRACE("pi_failed", tout << mk_pp(q, m_manager) << "\n";);
}
if (new_patterns.empty() && new_body == q->get_expr()) {
cache_result(q, q, 0);
return;
}
cache_result(q, new_q, pr);
}
#if 0
// unused
static void dump_expr_vector(std::ostream & out, ptr_vector<expr> const & v, ast_manager & m) {
ptr_vector<expr>::const_iterator it = v.begin();
ptr_vector<expr>::const_iterator end = v.end();
for (; it != end; ++it)
out << mk_pp(*it, m) << "\n";
}
#endif

View file

@ -1,248 +0,0 @@
/*++
Copyright (c) 2006 Microsoft Corporation
Module Name:
pattern_inference.h
Abstract:
<abstract>
Author:
Leonardo de Moura (leonardo) 2006-12-08.
Revision History:
--*/
#ifndef _PATTERN_INFERENCE_H_
#define _PATTERN_INFERENCE_H_
#include"ast.h"
#include"simplifier.h"
#include"pattern_inference_params.h"
#include"vector.h"
#include"uint_set.h"
#include"nat_set.h"
#include"obj_hashtable.h"
#include"obj_pair_hashtable.h"
#include"map.h"
#include"expr_pattern_match.h"
/**
\brief A pattern p_1 is smaller than a pattern p_2 iff
every instance of p_2 is also an instance of p_1.
Example: f(X) is smaller than f(g(X)) because
every instance of f(g(X)) is also an instance of f(X).
*/
class smaller_pattern {
ast_manager & m_manager;
ptr_vector<expr> m_bindings;
typedef std::pair<expr *, expr *> expr_pair;
typedef obj_pair_hashtable<expr, expr> cache;
svector<expr_pair> m_todo;
cache m_cache;
void save(expr * p1, expr * p2);
bool process(expr * p1, expr * p2);
smaller_pattern & operator=(smaller_pattern const &);
public:
smaller_pattern(ast_manager & m):
m_manager(m) {
}
bool operator()(unsigned num_bindings, expr * p1, expr * p2);
};
class pattern_inference : public simplifier {
pattern_inference_params & m_params;
family_id m_bfid;
family_id m_afid;
svector<family_id> m_forbidden;
obj_hashtable<func_decl> m_preferred;
smaller_pattern m_le;
unsigned m_num_bindings;
unsigned m_num_no_patterns;
expr * const * m_no_patterns;
bool m_nested_arith_only;
bool m_block_loop_patterns;
struct info {
uint_set m_free_vars;
unsigned m_size;
info(uint_set const & vars, unsigned size):
m_free_vars(vars),
m_size(size) {
}
info():
m_free_vars(),
m_size(0) {
}
};
typedef obj_map<expr, info> expr2info;
expr2info m_candidates_info; // candidate -> set of free vars + size
app_ref_vector m_candidates;
ptr_vector<app> m_tmp1;
ptr_vector<app> m_tmp2;
ptr_vector<app> m_todo;
// Compare candidates patterns based on their usefulness
// p1 < p2 if
// - p1 has more free variables than p2
// - p1 and p2 has the same number of free variables,
// and p1 is smaller than p2.
struct pattern_weight_lt {
expr2info & m_candidates_info;
pattern_weight_lt(expr2info & i):
m_candidates_info(i) {
}
bool operator()(expr * n1, expr * n2) const;
};
pattern_weight_lt m_pattern_weight_lt;
//
// Functor for collecting candidates.
//
class collect {
struct entry {
expr * m_node;
unsigned m_delta;
entry():m_node(0), m_delta(0) {}
entry(expr * n, unsigned d):m_node(n), m_delta(d) {}
unsigned hash() const {
return hash_u_u(m_node->get_id(), m_delta);
}
bool operator==(entry const & e) const {
return m_node == e.m_node && m_delta == e.m_delta;
}
};
struct info {
expr_ref m_node;
uint_set m_free_vars;
unsigned m_size;
info(ast_manager & m, expr * n, uint_set const & vars, unsigned sz):
m_node(n, m), m_free_vars(vars), m_size(sz) {}
};
ast_manager & m_manager;
pattern_inference & m_owner;
family_id m_afid;
unsigned m_num_bindings;
typedef map<entry, info *, obj_hash<entry>, default_eq<entry> > cache;
cache m_cache;
ptr_vector<info> m_info;
svector<entry> m_todo;
void visit(expr * n, unsigned delta, bool & visited);
bool visit_children(expr * n, unsigned delta);
void save(expr * n, unsigned delta, info * i);
void save_candidate(expr * n, unsigned delta);
void reset();
public:
collect(ast_manager & m, pattern_inference & o):m_manager(m), m_owner(o), m_afid(m.get_family_id("arith")) {}
void operator()(expr * n, unsigned num_bindings);
};
collect m_collect;
void add_candidate(app * n, uint_set const & s, unsigned size);
void filter_looping_patterns(ptr_vector<app> & result);
bool has_preferred_patterns(ptr_vector<app> & candidate_patterns, app_ref_buffer & result);
void filter_bigger_patterns(ptr_vector<app> const & patterns, ptr_vector<app> & result);
class contains_subpattern {
pattern_inference & m_owner;
nat_set m_already_processed;
ptr_vector<expr> m_todo;
void save(expr * n);
public:
contains_subpattern(pattern_inference & owner):
m_owner(owner) {}
bool operator()(expr * n);
};
contains_subpattern m_contains_subpattern;
bool contains_subpattern(expr * n);
struct pre_pattern {
ptr_vector<app> m_exprs; // elements of the pattern.
uint_set m_free_vars; // set of free variables in m_exprs
unsigned m_idx; // idx of the next candidate to process.
pre_pattern():
m_idx(0) {
}
};
ptr_vector<pre_pattern> m_pre_patterns;
expr_pattern_match m_database;
void candidates2unary_patterns(ptr_vector<app> const & candidate_patterns,
ptr_vector<app> & remaining_candidate_patterns,
app_ref_buffer & result);
void candidates2multi_patterns(unsigned max_num_patterns,
ptr_vector<app> const & candidate_patterns,
app_ref_buffer & result);
void reset_pre_patterns();
/**
\brief All minimal unary patterns (i.e., expressions that
contain all bound variables) are copied to result. If there
are unary patterns, then at most num_extra_multi_patterns multi
patterns are created. If there are no unary pattern, then at
most 1 + num_extra_multi_patterns multi_patterns are created.
*/
void mk_patterns(unsigned num_bindings, // IN number of bindings.
expr * n, // IN node where the patterns are going to be extracted.
unsigned num_no_patterns, // IN num. patterns that should not be used.
expr * const * no_patterns, // IN patterns that should not be used.
app_ref_buffer & result); // OUT result
virtual void reduce1_quantifier(quantifier * q);
public:
pattern_inference(ast_manager & m, pattern_inference_params & params);
void register_forbidden_family(family_id fid) {
SASSERT(fid != m_bfid);
m_forbidden.push_back(fid);
}
/**
\brief Register f as a preferred function symbol. The inference algorithm
gives preference to patterns rooted by this kind of function symbol.
*/
void register_preferred(func_decl * f) {
m_preferred.insert(f);
}
void register_preferred(unsigned num, func_decl * const * fs) { for (unsigned i = 0; i < num; i++) register_preferred(fs[i]); }
bool is_forbidden(func_decl const * decl) const {
family_id fid = decl->get_family_id();
if (fid == m_bfid && decl->get_decl_kind() != OP_TRUE && decl->get_decl_kind() != OP_FALSE)
return true;
return std::find(m_forbidden.begin(), m_forbidden.end(), fid) != m_forbidden.end();
}
bool is_forbidden(app * n) const;
};
#endif /* _PATTERN_INFERENCE_H_ */

View file

@ -1,105 +0,0 @@
/*++
Copyright (c) 2006 Microsoft Corporation
Module Name:
pattern_validation.cpp
Abstract:
Code for checking whether a pattern is valid or not.
Author:
Leonardo de Moura (leonardo) 2006-12-08.
Revision History:
--*/
#include"pattern_validation.h"
#include"for_each_expr.h"
#include"warning.h"
#include"ast_pp.h"
struct pattern_validation_functor {
uint_set & m_found_vars;
unsigned m_num_bindings;
unsigned m_num_new_bindings;
bool m_result;
bool m_found_a_var;
family_id m_bfid;
family_id m_lfid;
pattern_validation_functor(uint_set & found_vars, unsigned num_bindings, unsigned num_new_bindings,
family_id bfid, family_id lfid):
m_found_vars(found_vars),
m_num_bindings(num_bindings),
m_num_new_bindings(num_new_bindings),
m_result(true),
m_found_a_var(false),
m_bfid(bfid),
m_lfid(lfid) {
}
bool is_forbidden(func_decl const * decl) {
family_id fid = decl->get_family_id();
if (fid == m_bfid && decl->get_decl_kind() != OP_TRUE && decl->get_decl_kind() != OP_FALSE)
return true;
if (fid == m_lfid)
return true;
return false;
}
void operator()(app * n) {
func_decl * decl = to_app(n)->get_decl();
if (is_forbidden(decl)) {
warning_msg("'%s' cannot be used in patterns.", decl->get_name().str().c_str());
m_result = false;
}
}
void operator()(var * v) {
unsigned idx = to_var(v)->get_idx();
if (idx >= m_num_bindings) {
warning_msg("free variables cannot be used in patterns.");
m_result = false;
return;
}
if (idx < m_num_new_bindings) {
m_found_a_var = true;
m_found_vars.insert(idx);
}
}
void operator()(quantifier * q) { m_result = false; }
};
bool pattern_validator::process(uint_set & found_vars, unsigned num_bindings, unsigned num_new_bindings, expr * n) {
// I'm traversing the DAG as a tree, this is not a problem since pattern are supposed to be small ASTs.
if (n->get_kind() == AST_VAR) {
warning_msg("invalid pattern: variable.");
return false;
}
pattern_validation_functor f(found_vars, num_bindings, num_new_bindings, m_bfid, m_lfid);
for_each_expr(f, n);
if (!f.m_result)
return false;
if (!f.m_found_a_var) {
warning_msg("pattern does contain any variable.");
return false;
}
return true;
}
bool pattern_validator::operator()(unsigned num_bindings, unsigned num_new_bindings, expr * n) {
uint_set found_vars;
if (!process(found_vars, num_bindings, num_new_bindings, n))
return false;
bool r = found_vars.num_elems() == num_new_bindings;
if (!r)
warning_msg("pattern does not contain all quantified variables.");
return r;
}

View file

@ -1,44 +0,0 @@
/*++
Copyright (c) 2006 Microsoft Corporation
Module Name:
pattern_validation.h
Abstract:
Code for checking whether a pattern is valid or not.
Author:
Leonardo de Moura (leonardo) 2006-12-08.
Revision History:
--*/
#ifndef _PATTERN_VALIDATION_H_
#define _PATTERN_VALIDATION_H_
#include"ast.h"
#include"uint_set.h"
#include"vector.h"
class pattern_validator {
family_id m_bfid;
family_id m_lfid;
bool process(uint_set & found_vars, unsigned num_bindings, unsigned num_new_bindings, expr * n);
public:
pattern_validator(ast_manager const & m):
m_bfid(m.get_basic_family_id()),
m_lfid(m.get_family_id("label")) {
}
bool operator()(unsigned num_bindings, unsigned num_new_bindings, expr * n);
bool operator()(unsigned num_new_bindings, expr * n) { return operator()(UINT_MAX, num_new_bindings, n); }
};
#endif /* _PATTERN_VALIDATION_H_ */

View file

@ -1,191 +0,0 @@
/*++
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);
}

View file

@ -1,142 +0,0 @@
/*++
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

@ -1,155 +0,0 @@
/*++
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

@ -1,51 +0,0 @@
/*++
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

@ -1,385 +0,0 @@
/*++
Copyright (c) 2007 Microsoft Corporation
Module Name:
pull_quant.cpp
Abstract:
Pull nested quantifiers.
Author:
Leonardo (leonardo) 2008-01-20
Notes:
--*/
#include"pull_quant.h"
#include"ast_pp.h"
#include"for_each_expr.h"
void pull_quant::pull_quant1(func_decl * d, unsigned num_children, expr * const * children, expr_ref & result) {
ptr_buffer<sort> var_sorts;
buffer<symbol> var_names;
symbol qid;
int w = INT_MAX;
// The input formula is in Skolem normal form...
// So all children are forall (positive context) or exists (negative context).
// Remark: (AND a1 ...) may be represented (NOT (OR (NOT a1) ...)))
// So, when pulling a quantifier over a NOT, it becomes an exists.
if (m_manager.is_not(d)) {
SASSERT(num_children == 1);
expr * child = children[0];
if (is_quantifier(child)) {
quantifier * q = to_quantifier(child);
expr * body = q->get_expr();
result = m_manager.update_quantifier(q, !q->is_forall(), m_manager.mk_not(body));
}
else {
result = m_manager.mk_not(child);
}
return;
}
bool found_quantifier = false;
bool forall_children;
for (unsigned i = 0; i < num_children; i++) {
expr * child = children[i];
if (is_quantifier(child)) {
if (!found_quantifier) {
found_quantifier = true;
forall_children = is_forall(child);
}
else {
// Since the initial formula was in SNF, all children must be EXISTS or FORALL.
SASSERT(forall_children == is_forall(child));
}
quantifier * nested_q = to_quantifier(child);
if (var_sorts.empty()) {
// use the qid of one of the nested quantifiers.
qid = nested_q->get_qid();
}
w = std::min(w, nested_q->get_weight());
unsigned j = nested_q->get_num_decls();
while (j > 0) {
--j;
var_sorts.push_back(nested_q->get_decl_sort(j));
symbol s = nested_q->get_decl_name(j);
if (std::find(var_names.begin(), var_names.end(), s) != var_names.end())
var_names.push_back(m_manager.mk_fresh_var_name(s.is_numerical() ? 0 : s.bare_str()));
else
var_names.push_back(s);
}
}
}
if (!var_sorts.empty()) {
SASSERT(found_quantifier);
// adjust the variable ids in formulas in new_children
expr_ref_buffer new_adjusted_children(m_manager);
expr_ref adjusted_child(m_manager);
unsigned num_decls = var_sorts.size();
unsigned shift_amount = 0;
TRACE("pull_quant", tout << "Result num decls:" << num_decls << "\n";);
for (unsigned i = 0; i < num_children; i++) {
expr * child = children[i];
if (!is_quantifier(child)) {
// increment the free variables in child by num_decls because
// child will be in the scope of num_decls bound variables.
m_shift(child, num_decls, adjusted_child);
TRACE("pull_quant", tout << "shifted by: " << num_decls << "\n" <<
mk_pp(child, m_manager) << "\n---->\n" << mk_pp(adjusted_child, m_manager) << "\n";);
}
else {
quantifier * nested_q = to_quantifier(child);
SASSERT(num_decls >= nested_q->get_num_decls());
// Assume nested_q is of the form
// forall xs. P(xs, ys)
// where xs (ys) represents the set of bound (free) variables.
//
// - the index of the variables xs must be increased by shift_amount.
// That is, the number of new bound variables that will precede the bound
// variables xs.
//
// - the index of the variables ys must be increased by num_decls - nested_q->get_num_decls.
// That is, the total number of new bound variables that will be in the scope
// of nested_q->get_expr().
m_shift(nested_q->get_expr(),
nested_q->get_num_decls(), // bound for shift1/shift2
num_decls - nested_q->get_num_decls(), // shift1 (shift by this ammount if var idx >= bound)
shift_amount, // shift2 (shift by this ammount if var idx < bound)
adjusted_child);
TRACE("pull_quant", tout << "shifted bound: " << nested_q->get_num_decls() << " shift1: " << shift_amount <<
" shift2: " << (num_decls - nested_q->get_num_decls()) << "\n" << mk_pp(nested_q->get_expr(), m_manager) <<
"\n---->\n" << mk_pp(adjusted_child, m_manager) << "\n";);
shift_amount += nested_q->get_num_decls();
}
new_adjusted_children.push_back(adjusted_child);
}
// Remark: patterns are ignored.
// This is ok, since this functor is used in one of the following cases:
//
// 1) Superposition calculus is being used, so the
// patterns are useless.
//
// 2) No patterns were provided, and the functor is used
// to increase the effectiveness of the pattern inference
// procedure.
//
// 3) MBQI
std::reverse(var_sorts.begin(), var_sorts.end());
std::reverse(var_names.begin(), var_names.end());
result = m_manager.mk_quantifier(forall_children,
var_sorts.size(),
var_sorts.c_ptr(),
var_names.c_ptr(),
m_manager.mk_app(d, new_adjusted_children.size(), new_adjusted_children.c_ptr()),
w,
qid);
}
else {
SASSERT(!found_quantifier);
result = m_manager.mk_app(d, num_children, children);
}
}
void pull_quant::pull_quant1(quantifier * q, expr * new_expr, expr_ref & result) {
// The original formula was in SNF, so the original quantifiers must be universal.
SASSERT(is_forall(q));
if (is_forall(new_expr)) {
quantifier * nested_q = to_quantifier(new_expr);
ptr_buffer<sort> var_sorts;
buffer<symbol> var_names;
var_sorts.append(q->get_num_decls(), const_cast<sort**>(q->get_decl_sorts()));
var_sorts.append(nested_q->get_num_decls(), const_cast<sort**>(nested_q->get_decl_sorts()));
var_names.append(q->get_num_decls(), const_cast<symbol*>(q->get_decl_names()));
var_names.append(nested_q->get_num_decls(), const_cast<symbol*>(nested_q->get_decl_names()));
// Remark: patterns are ignored.
// See comment in reduce1_app
result = m_manager.mk_forall(var_sorts.size(),
var_sorts.c_ptr(),
var_names.c_ptr(),
nested_q->get_expr(),
std::min(q->get_weight(), nested_q->get_weight()),
q->get_qid());
}
else {
SASSERT(!is_quantifier(new_expr));
result = m_manager.update_quantifier(q, new_expr);
}
}
void pull_quant::pull_quant1(expr * n, expr_ref & result) {
if (is_app(n))
pull_quant1(to_app(n)->get_decl(), to_app(n)->get_num_args(), to_app(n)->get_args(), result);
else if (is_quantifier(n))
pull_quant1(to_quantifier(n), to_quantifier(n)->get_expr(), result);
else
result = n;
}
// Code for proof generation...
void pull_quant::pull_quant2(expr * n, expr_ref & r, proof_ref & pr) {
pr = 0;
if (is_app(n)) {
expr_ref_buffer new_args(m_manager);
expr_ref new_arg(m_manager);
ptr_buffer<proof> proofs;
unsigned num = to_app(n)->get_num_args();
for (unsigned i = 0; i < num; i++) {
expr * arg = to_app(n)->get_arg(i);
pull_quant1(arg , new_arg);
new_args.push_back(new_arg);
if (new_arg != arg)
proofs.push_back(m_manager.mk_pull_quant(arg, to_quantifier(new_arg)));
}
pull_quant1(to_app(n)->get_decl(), new_args.size(), new_args.c_ptr(), r);
if (m_manager.fine_grain_proofs()) {
app * r1 = m_manager.mk_app(to_app(n)->get_decl(), new_args.size(), new_args.c_ptr());
proof * p1 = proofs.empty() ? 0 : m_manager.mk_congruence(to_app(n), r1, proofs.size(), proofs.c_ptr());
proof * p2 = r1 == r ? 0 : m_manager.mk_pull_quant(r1, to_quantifier(r));
pr = m_manager.mk_transitivity(p1, p2);
}
}
else if (is_quantifier(n)) {
expr_ref new_expr(m_manager);
pull_quant1(to_quantifier(n)->get_expr(), new_expr);
pull_quant1(to_quantifier(n), new_expr, r);
if (m_manager.fine_grain_proofs()) {
quantifier * q1 = m_manager.update_quantifier(to_quantifier(n), new_expr);
proof * p1 = 0;
if (n != q1) {
proof * p0 = m_manager.mk_pull_quant(to_quantifier(n)->get_expr(), to_quantifier(new_expr));
p1 = m_manager.mk_quant_intro(to_quantifier(n), q1, p0);
}
proof * p2 = q1 == r ? 0 : m_manager.mk_pull_quant(q1, to_quantifier(r));
pr = m_manager.mk_transitivity(p1, p2);
}
}
else {
r = n;
}
}
bool pull_quant::visit_children(expr * n) {
bool visited = true;
unsigned j;
switch(n->get_kind()) {
case AST_APP:
// This transformation is also applied after the formula
// has been converted into a SNF using only OR and NOT.
if (m_manager.is_or(n) || m_manager.is_and(n) || m_manager.is_not(n)) {
j = to_app(n)->get_num_args();
while (j > 0) {
--j;
visit(to_app(n)->get_arg(j), visited);
}
}
else {
// This class assumes the formula is in skolem normal form.
SASSERT(!has_quantifiers(n));
}
break;
case AST_QUANTIFIER:
if (to_quantifier(n)->is_forall())
visit(to_quantifier(n)->get_expr(), visited);
break;
default:
break;
}
return visited;
}
void pull_quant::reduce1(expr * n) {
switch(n->get_kind()) {
case AST_APP:
reduce1_app(to_app(n));
break;
case AST_VAR:
cache_result(n, n, 0);
break;
case AST_QUANTIFIER:
reduce1_quantifier(to_quantifier(n));
break;
default:
UNREACHABLE();
break;
}
}
void pull_quant::reduce1_app(app * n) {
if (m_manager.is_or(n) || m_manager.is_and(n) || m_manager.is_not(n)) {
ptr_buffer<expr> new_children;
ptr_buffer<proof> new_children_proofs;
unsigned num = n->get_num_args();
for (unsigned i = 0; i < num; i++) {
expr * new_child = 0;
proof * new_child_pr = 0;
get_cached(n->get_arg(i), new_child, new_child_pr);
new_children.push_back(new_child);
if (new_child_pr) {
new_children_proofs.push_back(new_child_pr);
}
}
expr_ref r(m_manager);
pull_quant1(n->get_decl(), new_children.size(), new_children.c_ptr(), r);
proof * pr = 0;
if (m_manager.fine_grain_proofs()) {
app * n_prime = m_manager.mk_app(n->get_decl(), new_children.size(), new_children.c_ptr());
TRACE("proof_bug", tout << mk_pp(n, m_manager) << "\n";
tout << mk_pp(n_prime, m_manager) << "\n";);
proof * p1 = n == n_prime ? 0 : m_manager.mk_congruence(n, n_prime,
new_children_proofs.size(), new_children_proofs.c_ptr());
proof * p2 = n_prime == r ? 0 : m_manager.mk_pull_quant(n_prime, to_quantifier(r));
pr = m_manager.mk_transitivity(p1, p2);
}
cache_result(n, r, pr);
return;
}
TRACE("proof_bug", tout << mk_pp(n, m_manager) << "\n";);
cache_result(n, n, 0);
}
void pull_quant::reduce1_quantifier(quantifier * q) {
if (q->is_forall()) {
expr * new_expr;
proof * new_expr_pr;
get_cached(q->get_expr(), new_expr, new_expr_pr);
expr_ref r(m_manager);
pull_quant1(q, new_expr, r);
proof * pr = 0;
if (m_manager.fine_grain_proofs()) {
quantifier * q_prime = m_manager.update_quantifier(q, new_expr);
proof * p1 = q == q_prime ? 0 : m_manager.mk_quant_intro(q, q_prime, new_expr_pr);
proof * p2 = q_prime == r ? 0 : m_manager.mk_pull_quant(q_prime, to_quantifier(r));
pr = m_manager.mk_transitivity(p1, p2);
}
cache_result(q, r, pr);
return;
}
// should be unreachable, right?
UNREACHABLE();
cache_result(q, q, 0);
}
pull_quant::pull_quant(ast_manager & m):
base_simplifier(m),
m_shift(m) {
}
void pull_quant::operator()(expr * n, expr_ref & r, proof_ref & p) {
flush_cache();
m_todo.push_back(n);
while (!m_todo.empty()) {
expr * n = m_todo.back();
if (is_cached(n))
m_todo.pop_back();
else if (visit_children(n)) {
m_todo.pop_back();
reduce1(n);
}
}
expr * result;
proof * result_proof;
get_cached(n, result, result_proof);
r = result;
switch (m_manager.proof_mode()) {
case PGM_DISABLED:
p = m_manager.mk_undef_proof();
break;
case PGM_COARSE:
if (result == n)
p = m_manager.mk_reflexivity(n);
else
p = m_manager.mk_pull_quant_star(n, to_quantifier(result));
break;
case PGM_FINE:
SASSERT(result_proof || result == n);
p = result_proof ? result_proof : m_manager.mk_reflexivity(n);
break;
}
}
bool pull_nested_quant::visit_quantifier(quantifier * q) {
// do not recurse.
return true;
}
void pull_nested_quant::reduce1_quantifier(quantifier * q) {
expr_ref r(m_manager);
proof_ref pr(m_manager);
m_pull(q, r, pr);
cache_result(q, r, pr);
}

View file

@ -1,67 +0,0 @@
/*++
Copyright (c) 2007 Microsoft Corporation
Module Name:
pull_quant.h
Abstract:
Pull nested quantifiers.
Author:
Leonardo (leonardo) 2008-01-20
Notes:
--*/
#ifndef _PULL_QUANT_H_
#define _PULL_QUANT_H_
#include"simplifier.h"
#include"var_subst.h"
/**
\brief Pull nested quantifiers in a formula.
\warning It assumes the input formula is in NNF.
\remark pull_quant(F) is a quantifier if F contains a quantifier.
\remark If pull_quant(F) is a quantifier then its weight is
Min{weight(Q') | Q' is a quantifier nested in F}
*/
class pull_quant : public base_simplifier {
protected:
shift_vars m_shift;
bool visit_children(expr * n);
void reduce1(expr *);
void reduce1_app(app * n);
void reduce1_quantifier(quantifier * q);
public:
pull_quant(ast_manager & m);
virtual ~pull_quant() {}
void operator()(expr * n, expr_ref & r, proof_ref & p);
void reset() { flush_cache(); }
void pull_quant1(func_decl * d, unsigned num_children, expr * const * children, expr_ref & result);
void pull_quant1(quantifier * q, expr * new_expr, expr_ref & result);
void pull_quant1(expr * n, expr_ref & result);
void pull_quant2(expr * n, expr_ref & r, proof_ref & pr);
};
/**
\brief After applying this transformation the formula will not
contain nested quantifiers.
*/
class pull_nested_quant : public simplifier {
pull_quant m_pull;
virtual bool visit_quantifier(quantifier * q);
virtual void reduce1_quantifier(quantifier * q);
public:
pull_nested_quant(ast_manager & m):simplifier(m), m_pull(m) { enable_ac_support(false); }
virtual ~pull_nested_quant() {}
};
#endif /* _PULL_QUANT_H_ */

View file

@ -1,220 +0,0 @@
/*++
Copyright (c) 2006 Microsoft Corporation
Module Name:
push_app_ite.cpp
Abstract:
TODO: Write a better ite lifter
Author:
Leonardo de Moura (leonardo) 2008-05-14.
Revision History:
--*/
#include"push_app_ite.h"
#include"ast_pp.h"
push_app_ite::push_app_ite(simplifier & s, bool conservative):
simplifier(s.get_manager()),
m_conservative(conservative) {
borrow_plugins(s);
}
push_app_ite::~push_app_ite() {
// the plugins were borrowed. So, release ownership.
m_plugins.release();
}
int push_app_ite::has_ite_arg(unsigned num_args, expr * const * args) {
for (unsigned i = 0; i < num_args; i++)
if (m_manager.is_ite(args[i]))
return i;
return -1;
}
void push_app_ite::apply(func_decl * decl, unsigned num_args, expr * const * args, expr_ref & r) {
TRACE("push_app_ite", tout << "pushing app...\n";);
int ite_arg_idx = has_ite_arg(num_args, args);
if (ite_arg_idx < 0) {
mk_app(decl, num_args, args, r);
return;
}
app * ite = to_app(args[ite_arg_idx]);
expr * c = ite->get_arg(0);
expr * t = ite->get_arg(1);
expr * e = ite->get_arg(2);
expr ** args_prime = const_cast<expr**>(args);
expr * old = args_prime[ite_arg_idx];
args_prime[ite_arg_idx] = t;
expr_ref t_new(m_manager);
apply(decl, num_args, args_prime, t_new);
args_prime[ite_arg_idx] = e;
expr_ref e_new(m_manager);
apply(decl, num_args, args_prime, e_new);
args_prime[ite_arg_idx] = old;
expr * new_args[3] = { c, t_new, e_new };
mk_app(ite->get_decl(), 3, new_args, r);
}
/**
\brief Default (conservative) implementation. Return true if there one and only one ite-term argument.
*/
bool push_app_ite::is_target(func_decl * decl, unsigned num_args, expr * const * args) {
if (m_manager.is_ite(decl))
return false;
bool found_ite = false;
for (unsigned i = 0; i < num_args; i++) {
if (m_manager.is_ite(args[i]) && !m_manager.is_bool(args[i])) {
if (found_ite) {
if (m_conservative)
return false;
}
else {
found_ite = true;
}
}
}
CTRACE("push_app_ite", found_ite, tout << "found target for push app ite:\n";
tout << decl->get_name();
for (unsigned i = 0; i < num_args; i++) tout << " " << mk_pp(args[i], m_manager);
tout << "\n";);
return found_ite;
}
void push_app_ite::operator()(expr * s, expr_ref & r, proof_ref & p) {
expr * result;
proof * result_proof;
reduce_core(s);
get_cached(s, result, result_proof);
r = result;
switch (m_manager.proof_mode()) {
case PGM_DISABLED:
p = m_manager.mk_undef_proof();
break;
case PGM_COARSE:
if (result == s)
p = m_manager.mk_reflexivity(s);
else
p = m_manager.mk_rewrite_star(s, result, 0, 0);
break;
case PGM_FINE:
if (result == s)
p = m_manager.mk_reflexivity(s);
else
p = result_proof;
break;
}
}
void push_app_ite::reduce_core(expr * n) {
if (!is_cached(n)) {
unsigned sz = m_todo.size();
m_todo.push_back(n);
while (m_todo.size() != sz) {
expr * n = m_todo.back();
if (is_cached(n))
m_todo.pop_back();
else if (visit_children(n)) {
m_todo.pop_back();
reduce1(n);
}
}
}
}
bool push_app_ite::visit_children(expr * n) {
bool visited = true;
unsigned j;
switch(n->get_kind()) {
case AST_VAR:
return true;
case AST_APP:
j = to_app(n)->get_num_args();
while (j > 0) {
--j;
visit(to_app(n)->get_arg(j), visited);
}
return visited;
case AST_QUANTIFIER:
visit(to_quantifier(n)->get_expr(), visited);
return visited;
default:
UNREACHABLE();
return true;
}
}
void push_app_ite::reduce1(expr * n) {
switch (n->get_kind()) {
case AST_VAR:
cache_result(n, n, 0);
break;
case AST_APP:
reduce1_app(to_app(n));
break;
case AST_QUANTIFIER:
reduce1_quantifier(to_quantifier(n));
break;
default:
UNREACHABLE();
}
}
void push_app_ite::reduce1_app(app * n) {
m_args.reset();
func_decl * decl = n->get_decl();
proof_ref p1(m_manager);
get_args(n, m_args, p1);
expr_ref r(m_manager);
if (is_target(decl, m_args.size(), m_args.c_ptr()))
apply(decl, m_args.size(), m_args.c_ptr(), r);
else
mk_app(decl, m_args.size(), m_args.c_ptr(), r);
if (!m_manager.fine_grain_proofs())
cache_result(n, r, 0);
else {
expr * s = m_manager.mk_app(decl, m_args.size(), m_args.c_ptr());
proof * p;
if (n == r)
p = 0;
else if (r != s)
p = m_manager.mk_transitivity(p1, m_manager.mk_rewrite(s, r));
else
p = p1;
cache_result(n, r, p);
}
}
void push_app_ite::reduce1_quantifier(quantifier * q) {
expr * new_body;
proof * new_body_pr;
get_cached(q->get_expr(), new_body, new_body_pr);
quantifier * new_q = m_manager.update_quantifier(q, new_body);
proof * p = q == new_q ? 0 : m_manager.mk_quant_intro(q, new_q, new_body_pr);
cache_result(q, new_q, p);
}
bool ng_push_app_ite::is_target(func_decl * decl, unsigned num_args, expr * const * args) {
bool r = push_app_ite::is_target(decl, num_args, args);
if (!r)
return false;
for (unsigned i = 0; i < num_args; i++)
if (!is_ground(args[i]))
return true;
return false;
}
ng_push_app_ite::ng_push_app_ite(simplifier & s, bool conservative):
push_app_ite(s, conservative) {
}

View file

@ -1,63 +0,0 @@
/*++
Copyright (c) 2006 Microsoft Corporation
Module Name:
push_app_ite.h
Abstract:
<abstract>
Author:
Leonardo de Moura (leonardo) 2008-05-14.
Revision History:
--*/
#ifndef _PUSH_APP_ITE_H_
#define _PUSH_APP_ITE_H_
#include"ast.h"
#include"simplifier.h"
/**
\brief Functor for applying the following transformation:
(f s (ite c t1 t2)) ==> (ite c (f s t1) (f s t2))
*/
class push_app_ite : public simplifier {
protected:
bool m_conservative;
int has_ite_arg(unsigned num_args, expr * const * args);
void apply(func_decl * decl, unsigned num_args, expr * const * args, expr_ref & result);
virtual bool is_target(func_decl * decl, unsigned num_args, expr * const * args);
void reduce_core(expr * n);
bool visit_children(expr * n);
void reduce1(expr * n);
void reduce1_app(app * n);
void reduce1_quantifier(quantifier * q);
public:
push_app_ite(simplifier & s, bool conservative = true);
virtual ~push_app_ite();
void operator()(expr * s, expr_ref & r, proof_ref & p);
};
/**
\brief Variation of push_app_ite that applies the transformation on nonground terms only.
\remark This functor uses the app::is_ground method. This method is not
completly precise, for instance, any term containing a quantifier is marked as non ground.
*/
class ng_push_app_ite : public push_app_ite {
protected:
virtual bool is_target(func_decl * decl, unsigned num_args, expr * const * args);
public:
ng_push_app_ite(simplifier & s, bool conservative = true);
virtual ~ng_push_app_ite() {}
};
#endif /* _PUSH_APP_ITE_H_ */

View file

@ -1,107 +0,0 @@
/*++
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

@ -1,170 +0,0 @@
/*++
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

@ -1,69 +0,0 @@
/*++
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_ */

View file

@ -1,287 +0,0 @@
/*++
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())]++;
}
}
};

View file

@ -1,152 +0,0 @@
/*++
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

@ -1,58 +0,0 @@
/*++
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

@ -1,121 +0,0 @@
/*++
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

@ -1,85 +0,0 @@
/*++
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

@ -1,504 +0,0 @@
/*++
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
*/
};

View file

@ -1,122 +0,0 @@
/*++
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

@ -1,135 +0,0 @@
/*++
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

@ -1,61 +0,0 @@
/*++
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_ */

View file

@ -1,80 +0,0 @@
/*++
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))
;
}
};

View file

@ -1,52 +0,0 @@
/*++
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

@ -1,44 +0,0 @@
/*++
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

@ -1,50 +0,0 @@
/*++
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

@ -1,156 +0,0 @@
/*++
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

@ -1,66 +0,0 @@
/*++
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

@ -1,184 +0,0 @@
/*++
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

@ -1,337 +0,0 @@
/*++
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

@ -1,432 +0,0 @@
/*++
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());
}
}
};

View file

@ -1,212 +0,0 @@
/*++
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

@ -1,107 +0,0 @@
/*++
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

@ -1,95 +0,0 @@
/*++
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_ */

View file

@ -1,132 +0,0 @@
/*++
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;
}
};

View file

@ -1,59 +0,0 @@
/*++
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

@ -1,269 +0,0 @@
/*++
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);
}
}
};

View file

@ -1,122 +0,0 @@
/*++
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

@ -1,234 +0,0 @@
/*++
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

@ -1,114 +0,0 @@
/*++
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

@ -1,54 +0,0 @@
/*++
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

@ -1,49 +0,0 @@
/*++
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

@ -1,698 +0,0 @@
/*++
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

@ -1,156 +0,0 @@
/*++
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

@ -1,531 +0,0 @@
/*++
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

@ -1,147 +0,0 @@
/*++
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

@ -1,52 +0,0 @@
/*++
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

@ -1,48 +0,0 @@
/*++
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_ */

View file

@ -1,180 +0,0 @@
/*++
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

@ -1,152 +0,0 @@
/*++
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

@ -1,114 +0,0 @@
/*++
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_ */

Some files were not shown because too many files have changed in this diff Show more