z3-z3-4.13.0.src.sat.smt.sat_th.cpp Maven / Gradle / Ivy
The newest version!
/*++
Copyright (c) 2020 Microsoft Corporation
Module Name:
sat_th.cpp
Abstract:
Theory plugin base classes
Author:
Nikolaj Bjorner (nbjorner) 2020-08-25
--*/
#include "sat/smt/sat_th.h"
#include "sat/smt/euf_solver.h"
#include "tactic/tactic_exception.h"
namespace euf {
bool th_internalizer::visit_rec(ast_manager& m, expr* a, bool sign, bool root) {
IF_VERBOSE(110, verbose_stream() << "internalize: " << mk_pp(a, m) << "\n");
svector::scoped_stack _sc(m_stack);
unsigned sz = m_stack.size();
visit(a);
while (m_stack.size() > sz) {
loop:
if (!m.inc())
throw tactic_exception(m.limit().get_cancel_msg());
unsigned fsz = m_stack.size();
expr* e = m_stack[fsz-1].m_e;
if (visited(e)) {
m_stack.pop_back();
continue;
}
unsigned num = is_app(e) ? to_app(e)->get_num_args() : 0;
while (m_stack[fsz - 1].m_idx < num) {
expr* arg = to_app(e)->get_arg(m_stack[fsz - 1].m_idx);
m_stack[fsz - 1].m_idx++;
if (!visit(arg))
goto loop;
}
if (!visited(e) && !post_visit(e, sign, root && a == e))
return false;
m_stack.pop_back();
}
return true;
}
th_euf_solver::th_euf_solver(euf::solver& ctx, symbol const& name, euf::theory_id id):
th_solver(ctx.get_manager(), name, id),
ctx(ctx)
{}
smt_params const& th_euf_solver::get_config() const {
return ctx.get_config();
}
region& th_euf_solver::get_region() {
return ctx.get_region();
}
trail_stack& th_euf_solver::get_trail_stack() {
return ctx.get_trail_stack();
}
enode* th_euf_solver::expr2enode(expr* e) const {
return ctx.get_enode(e);
}
sat::literal th_euf_solver::expr2literal(expr* e) const {
return ctx.expr2literal(e);
}
expr* th_euf_solver::bool_var2expr(sat::bool_var v) const {
return ctx.bool_var2expr(v);
}
expr_ref th_euf_solver::literal2expr(sat::literal lit) const {
return ctx.literal2expr(lit);
}
theory_var th_euf_solver::mk_var(enode * n) {
force_push();
SASSERT(!is_attached_to_var(n));
euf::theory_var v = m_var2enode.size();
m_var2enode.push_back(n);
return v;
}
bool th_euf_solver::is_attached_to_var(enode* n) const {
theory_var v = n->get_th_var(get_id());
return v != null_theory_var && var2enode(v) == n;
}
theory_var th_euf_solver::get_th_var(expr* e) const {
return get_th_var(ctx.get_enode(e));
}
theory_var th_euf_solver::get_representative(theory_var v) const {
euf::enode* r = var2enode(v)->get_root();
return get_th_var(r);
}
void th_euf_solver::push_core() {
m_var2enode_lim.push_back(m_var2enode.size());
}
void th_euf_solver::pop_core(unsigned num_scopes) {
unsigned new_lvl = m_var2enode_lim.size() - num_scopes;
m_var2enode.shrink(m_var2enode_lim[new_lvl]);
m_var2enode_lim.shrink(new_lvl);
}
void th_euf_solver::pop(unsigned n) {
unsigned k = std::min(m_num_scopes, n);
m_num_scopes -= k;
n -= k;
if (n > 0)
pop_core(n);
}
bool th_euf_solver::add_unit(sat::literal lit, th_proof_hint const* ps) {
if (ctx.use_drat() && !ps)
ps = ctx.mk_smt_clause(name(), 1, &lit);
bool was_true = is_true(lit);
ctx.s().add_clause(1, &lit, sat::status::th(false, get_id(), ps));
ctx.add_root(lit);
return !was_true;
}
bool th_euf_solver::add_units(sat::literal_vector const& lits) {
bool is_new = false;
for (auto lit : lits)
if (add_unit(lit))
is_new = true;
return is_new;
}
bool th_euf_solver::add_clause(sat::literal a, sat::literal b, th_proof_hint const* ph) {
sat::literal lits[2] = { a, b };
return add_clause(2, lits, ph);
}
bool th_euf_solver::add_clause(sat::literal a, sat::literal b, sat::literal c, th_proof_hint const* ps) {
sat::literal lits[3] = { a, b, c };
return add_clause(3, lits, ps);
}
bool th_euf_solver::add_clause(sat::literal a, sat::literal b, sat::literal c, sat::literal d, th_proof_hint const* ps) {
sat::literal lits[4] = { a, b, c, d };
return add_clause(4, lits, ps);
}
bool th_euf_solver::add_clause(unsigned n, sat::literal* lits, th_proof_hint const* ps, bool is_redundant) {
if (ctx.use_drat() && !ps)
ps = ctx.mk_smt_clause(name(), n, lits);
bool was_true = false;
for (unsigned i = 0; i < n; ++i)
was_true |= is_true(lits[i]);
ctx.add_root(n, lits);
s().add_clause(n, lits, sat::status::th(is_redundant, get_id(), ps));
return !was_true;
}
void th_euf_solver::add_equiv(sat::literal a, sat::literal b) {
add_clause(~a, b);
add_clause(a, ~b);
}
void th_euf_solver::add_equiv_and(sat::literal a, sat::literal_vector const& bs) {
for (auto b : bs)
add_clause(~a, b);
sat::literal_vector _bs;
for (auto b : bs)
_bs.push_back(~b);
_bs.push_back(a);
add_clause(_bs);
}
bool th_euf_solver::is_true(sat::literal lit) {
return ctx.s().value(lit) == l_true;
}
euf::enode* th_euf_solver::mk_enode(expr* e, bool suppress_args) {
m_args.reset();
if (!suppress_args)
for (expr* arg : *to_app(e))
m_args.push_back(expr2enode(arg));
euf::enode* n = ctx.mk_enode(e, m_args.size(), m_args.data());
ctx.attach_node(n);
return n;
}
void th_euf_solver::rewrite(expr_ref& a) {
ctx.get_rewriter()(a);
}
expr_ref th_euf_solver::mk_eq(expr* e1, expr* e2) {
return ctx.mk_eq(e1, e2);
}
sat::literal th_euf_solver::mk_literal(expr* e) const {
return ctx.mk_literal(e);
}
sat::literal th_euf_solver::eq_internalize(expr* a, expr* b) {
return mk_literal(ctx.mk_eq(a, b));
}
euf::enode* th_euf_solver::e_internalize(expr* e) {
return ctx.e_internalize(e);
}
unsigned th_euf_solver::random() {
return ctx.s().rand()();
}
size_t th_explain::get_obj_size(unsigned num_lits, unsigned num_eqs) {
return sat::constraint_base::obj_size(sizeof(th_explain) + sizeof(sat::literal) * num_lits + sizeof(enode_pair) * num_eqs);
}
th_explain::th_explain(unsigned n_lits, sat::literal const* lits, unsigned n_eqs, enode_pair const* eqs, sat::literal c, enode_pair const& p, th_proof_hint const* pma) {
m_consequent = c;
m_eq = p;
if (m_eq.first && m_eq.first->get_id() > m_eq.second->get_id())
std::swap(m_eq.first, m_eq.second);
m_proof_hint = pma;
m_num_literals = n_lits;
m_num_eqs = n_eqs;
char * base_ptr = reinterpret_cast(this) + sizeof(th_explain);
m_literals = reinterpret_cast(base_ptr);
unsigned i;
for (i = 0; i < n_lits; ++i)
m_literals[i] = lits[i];
base_ptr += sizeof(literal) * n_lits;
m_eqs = reinterpret_cast(base_ptr);
for (i = 0; i < n_eqs; ++i) {
m_eqs[i] = eqs[i];
if (m_eqs[i].first->get_id() > m_eqs[i].second->get_id())
std::swap(m_eqs[i].first, m_eqs[i].second);
}
}
th_explain* th_explain::mk(th_euf_solver& th, unsigned n_lits, sat::literal const* lits, unsigned n_eqs, enode_pair const* eqs, sat::literal c, enode* x, enode* y, th_proof_hint const* pma) {
region& r = th.ctx.get_region();
void* mem = r.allocate(get_obj_size(n_lits, n_eqs));
sat::constraint_base::initialize(mem, &th);
return new (sat::constraint_base::ptr2mem(mem)) th_explain(n_lits, lits, n_eqs, eqs, c, enode_pair(x, y), pma);
}
th_explain* th_explain::propagate(th_euf_solver& th, sat::literal_vector const& lits, enode_pair_vector const& eqs, sat::literal consequent, th_proof_hint const* ph) {
return mk(th, lits.size(), lits.data(), eqs.size(), eqs.data(), consequent, nullptr, nullptr, ph);
}
th_explain* th_explain::propagate(th_euf_solver& th, sat::literal_vector const& lits, enode_pair_vector const& eqs, euf::enode* x, euf::enode* y, th_proof_hint const* ph) {
return mk(th, lits.size(), lits.data(), eqs.size(), eqs.data(), sat::null_literal, x, y, ph);
}
th_explain* th_explain::propagate(th_euf_solver& th, enode_pair_vector const& eqs, euf::enode* x, euf::enode* y, th_proof_hint const* ph) {
return mk(th, 0, nullptr, eqs.size(), eqs.data(), sat::null_literal, x, y, ph);
}
th_explain* th_explain::propagate(th_euf_solver& th, sat::literal lit, euf::enode* x, euf::enode* y, th_proof_hint const* ph) {
return mk(th, 1, &lit, 0, nullptr, sat::null_literal, x, y, ph);
}
th_explain* th_explain::conflict(th_euf_solver& th, sat::literal_vector const& lits, enode_pair_vector const& eqs, th_proof_hint const* ph) {
return conflict(th, lits.size(), lits.data(), eqs.size(), eqs.data(), ph);
}
th_explain* th_explain::conflict(th_euf_solver& th, unsigned n_lits, sat::literal const* lits, unsigned n_eqs, enode_pair const* eqs, th_proof_hint const* ph) {
return mk(th, n_lits, lits, n_eqs, eqs, sat::null_literal, nullptr, nullptr, ph);
}
th_explain* th_explain::conflict(th_euf_solver& th, enode_pair_vector const& eqs, th_proof_hint const* ph) {
return conflict(th, 0, nullptr, eqs.size(), eqs.data(), ph);
}
th_explain* th_explain::conflict(th_euf_solver& th, sat::literal lit, th_proof_hint const* ph) {
return conflict(th, 1, &lit, 0, nullptr, ph);
}
th_explain* th_explain::conflict(th_euf_solver& th, sat::literal lit, euf::enode* x, euf::enode* y, th_proof_hint const* ph) {
enode_pair eq(x, y);
return conflict(th, 1, &lit, 1, &eq, ph);
}
th_explain* th_explain::conflict(th_euf_solver& th, euf::enode* x, euf::enode* y, th_proof_hint const* ph) {
enode_pair eq(x, y);
return conflict(th, 0, nullptr, 1, &eq, ph);
}
std::ostream& th_explain::display(std::ostream& out) const {
for (auto lit : euf::th_explain::lits(*this))
out << lit << " ";
for (auto eq : euf::th_explain::eqs(*this))
out << eq.first->get_expr_id() << " == " << eq.second->get_expr_id() << " ";
if (m_consequent != sat::null_literal)
out << "--> " << m_consequent;
if (m_eq.first != nullptr)
out << "--> " << m_eq.first->get_expr_id() << " == " << m_eq.second->get_expr_id();
if (m_proof_hint != nullptr)
out << " p ";
return out;
}
}