3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-04-10 03:07:07 +00:00
z3/lib/spc_rewriter.cpp
Leonardo de Moura e9eab22e5c Z3 sources
Signed-off-by: Leonardo de Moura <leonardo@microsoft.com>
2012-10-02 11:35:25 -07:00

270 lines
8.8 KiB
C++

/*++
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);
}
}
};