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:
parent
2b8fb6c718
commit
492484c5aa
125 changed files with 632 additions and 390 deletions
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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();
|
||||
}
|
||||
|
|
@ -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
|
@ -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
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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
|
526
lib/cnf.cpp
526
lib/cnf.cpp
|
@ -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
121
lib/cnf.h
|
@ -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_ */
|
||||
|
316
lib/database.h
316
lib/database.h
|
@ -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"
|
||||
;
|
314
lib/database.smt
314
lib/database.smt
|
@ -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) })
|
||||
)
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -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_ */
|
||||
|
639
lib/der.cpp
639
lib/der.cpp
|
@ -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
215
lib/der.h
|
@ -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_ */
|
||||
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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_ */
|
|
@ -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_ */
|
|
@ -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.
|
|
@ -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
|
|
@ -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);
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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_ */
|
|
@ -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));
|
||||
}
|
|
@ -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
|
276
lib/kbo.cpp
276
lib/kbo.cpp
|
@ -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;
|
||||
}
|
||||
}
|
70
lib/kbo.h
70
lib/kbo.h
|
@ -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_ */
|
184
lib/lpo.cpp
184
lib/lpo.cpp
|
@ -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;
|
||||
}
|
||||
}
|
49
lib/lpo.h
49
lib/lpo.h
|
@ -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_ */
|
56
lib/marker.h
56
lib/marker.h
|
@ -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_ */
|
|
@ -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();
|
||||
}
|
|
@ -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_ */
|
||||
|
|
@ -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);
|
||||
}
|
|
@ -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
|
1030
lib/nnf.cpp
1030
lib/nnf.cpp
File diff suppressed because it is too large
Load diff
68
lib/nnf.h
68
lib/nnf.h
|
@ -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_ */
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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_ */
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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_ */
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
36
lib/occurs.h
36
lib/occurs.h
|
@ -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_ */
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
87
lib/order.h
87
lib/order.h
|
@ -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_ */
|
|
@ -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
|
||||
|
|
@ -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_ */
|
||||
|
|
@ -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;
|
||||
}
|
|
@ -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_ */
|
||||
|
|
@ -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);
|
||||
}
|
142
lib/precedence.h
142
lib/precedence.h
|
@ -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_ */
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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_ */
|
|
@ -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);
|
||||
}
|
|
@ -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_ */
|
|
@ -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) {
|
||||
}
|
|
@ -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_ */
|
||||
|
|
@ -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_ */
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
};
|
|
@ -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_ */
|
||||
|
|
@ -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())]++;
|
||||
}
|
||||
}
|
||||
|
||||
};
|
152
lib/spc_clause.h
152
lib/spc_clause.h
|
@ -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_ */
|
||||
|
|
@ -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_ */
|
||||
|
|
@ -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;
|
||||
}
|
||||
};
|
|
@ -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_ */
|
||||
|
|
@ -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
|
||||
|
||||
*/
|
||||
|
||||
};
|
|
@ -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_ */
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -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_ */
|
||||
|
|
@ -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))
|
||||
;
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
|
@ -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_ */
|
||||
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
|
@ -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_ */
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
|
@ -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_ */
|
||||
|
|
@ -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);
|
||||
}
|
||||
};
|
|
@ -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_ */
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
};
|
|
@ -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_ */
|
|
@ -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);
|
||||
}
|
||||
|
||||
};
|
|
@ -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_ */
|
|
@ -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;
|
||||
}
|
||||
};
|
||||
|
|
@ -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_ */
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
|
@ -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_ */
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
};
|
|
@ -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_ */
|
||||
|
|
@ -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";
|
||||
}
|
||||
|
||||
};
|
||||
|
|
@ -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_ */
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
};
|
|
@ -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_ */
|
||||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
|
@ -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_ */
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
};
|
|
@ -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_ */
|
||||
|
180
lib/splay_tree.h
180
lib/splay_tree.h
|
@ -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
|
|
@ -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_ */
|
|
@ -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
Loading…
Add table
Add a link
Reference in a new issue