z3-z3-4.13.0.src.smt.theory_dl.cpp Maven / Gradle / Ivy
The newest version!
/*++
Copyright (c) 2011 Microsoft Corporation
Module Name:
theory_dl.h
Abstract:
Theory for DL constants.
DL constants are discrete and ordered by the linear order LT.
Constants have a parameter which indicates the numeric value that ranges
from 0 up to the size of the domain.
The procedure works by a simple reduction to bit-vectors. We enforce an injection into bit-vectors.
Author:
Nikolaj Bjorner (nbjorner) 2011-1-10
Revision History:
--*/
#include "ast/dl_decl_plugin.h"
#include "ast/bv_decl_plugin.h"
#include "ast/ast_pp.h"
#include "model/value_factory.h"
#include "smt/smt_theory.h"
#include "smt/smt_model_generator.h"
#include "smt/theory_bv.h"
#include "smt/smt_context.h"
// Basic approach: reduce theory to bit-vectors:
//
// rep(c(n)) = n
// LT(x,y) <=> rep(x) < rep(y)
// val(rep(x)) = x
// 0 <= rep(x) <= max_value
//
namespace smt {
class dl_factory : public simple_factory {
datalog::dl_decl_util& m_util;
public:
dl_factory(datalog::dl_decl_util& u, proto_model& m):
simple_factory(u.get_manager(), u.get_family_id()),
m_util(u)
{}
app * mk_value_core(unsigned const & val, sort * s) override {
return m_util.mk_numeral(val, s);
}
};
class theory_dl : public theory {
datalog::dl_decl_util m_util;
bv_util m_bv;
ast_ref_vector m_trail;
obj_map m_reps;
obj_map m_vals;
ast_manager& m() { return get_manager(); }
datalog::dl_decl_util& u() { return m_util; }
bv_util& b() { return m_bv; }
class dl_value_proc : public smt::model_value_proc {
theory_dl& m_th;
smt::enode* m_node;
public:
dl_value_proc(theory_dl& th, smt::enode* n) : m_th(th), m_node(n) {}
void get_dependencies(buffer & result) override {}
app * mk_value(smt::model_generator & mg, expr_ref_vector const & ) override {
smt::context& ctx = m_th.get_context();
app* result = nullptr;
expr* n = m_node->get_expr();
sort* s = n->get_sort();
func_decl* r, *v;
m_th.get_rep(s, r, v);
app_ref rep_of(m_th.m());
rep_of = m_th.m().mk_app(r, m_node->get_expr());
theory_id bv_id = m_th.m().mk_family_id("bv");
theory_bv* th_bv = dynamic_cast(ctx.get_theory(bv_id));
SASSERT(th_bv);
rational val;
if (ctx.e_internalized(rep_of) && th_bv &&
th_bv->get_fixed_value(rep_of.get(), val)) {
result = m_th.u().mk_numeral(val.get_int64(), s);
}
else {
result = m_th.u().mk_numeral(0, s);
}
TRACE("theory_dl", tout << mk_pp(result, m_th.m()) << "\n";);
return result;
}
};
public:
theory_dl(context& ctx):
theory(ctx, ctx.get_manager().mk_family_id("datalog_relation")),
m_util(ctx.get_manager()),
m_bv(ctx.get_manager()),
m_trail(ctx.get_manager())
{
}
char const * get_name() const override { return "datalog"; }
bool internalize_atom(app * atom, bool gate_ctx) override {
TRACE("theory_dl", tout << mk_pp(atom, m()) << "\n";);
if (ctx.b_internalized(atom)) {
return true;
}
switch(atom->get_decl_kind()) {
case datalog::OP_DL_LT: {
app* a = to_app(atom->get_arg(0));
app* b = to_app(atom->get_arg(1));
ctx.internalize(a, false);
ctx.internalize(b, false);
literal l(ctx.mk_bool_var(atom));
ctx.set_var_theory(l.var(), get_id());
mk_lt(a,b);
return true;
}
default:
break;
}
return false;
}
bool internalize_term(app * term) override {
TRACE("theory_dl", tout << mk_pp(term, m()) << "\n";);
if (u().is_finite_sort(term)) {
return mk_rep(term);
}
else {
return false;
}
}
void new_eq_eh(theory_var v1, theory_var v2) override {
}
void new_diseq_eh(theory_var v1, theory_var v2) override {
}
theory * mk_fresh(context * new_ctx) override {
return alloc(theory_dl, *new_ctx);
}
void init_model(smt::model_generator & m) override {
m.register_factory(alloc(dl_factory, m_util, m.get_model()));
}
smt::model_value_proc * mk_value(smt::enode * n, smt::model_generator&) override {
return alloc(dl_value_proc, *this, n);
}
void apply_sort_cnstr(enode * n, sort * s) override {
app* term = n->get_expr();
if (u().is_finite_sort(term)) {
mk_rep(term);
}
}
void relevant_eh(app * n) override {
if (u().is_finite_sort(n)) {
sort* s = n->get_sort();
func_decl* r, *v;
get_rep(s, r, v);
if (n->get_decl() != v) {
expr* rep = m().mk_app(r, n);
uint64_t vl;
if (u().is_numeral_ext(n, vl)) {
assert_cnstr(m().mk_eq(rep, mk_bv_constant(vl, s)));
}
else {
assert_cnstr(m().mk_eq(m().mk_app(v,rep), n));
assert_cnstr(b().mk_ule(rep, max_value(s)));
}
}
}
}
void display(std::ostream & out) const override {
}
private:
void get_rep(sort* s, func_decl*& r, func_decl*& v) {
if(!m_reps.find(s, r) || !m_vals.find(s,v)) {
SASSERT(!m_reps.contains(s));
sort* bv = b().mk_sort(64);
r = m().mk_func_decl(m_util.get_family_id(), datalog::OP_DL_REP, 0, nullptr, 1, &s, bv);
v = m().mk_func_decl(m_util.get_family_id(), datalog::OP_DL_ABS, 0, nullptr, 1, &bv, s);
m_reps.insert(s, r);
m_vals.insert(s, v);
add_trail(r);
add_trail(v);
ctx.push_trail(insert_obj_map(m_reps, s));
ctx.push_trail(insert_obj_map(m_vals, s));
}
}
bool mk_rep(app* n) {
unsigned num_args = n->get_num_args();
enode * e = nullptr;
for (unsigned i = 0; i < num_args; i++) {
ctx.internalize(n->get_arg(i), false);
}
if (ctx.e_internalized(n)) {
e = ctx.get_enode(n);
}
else {
e = ctx.mk_enode(n, false, false, true);
}
if (is_attached_to_var(e)) {
return false;
}
TRACE("theory_dl", tout << mk_pp(n, m()) << "\n";);
theory_var var = mk_var(e);
ctx.attach_th_var(e, this, var);
return true;
}
app* mk_bv_constant(uint64_t val, sort* s) {
return b().mk_numeral(rational(val, rational::ui64()), 64);
}
app* max_value(sort* s) {
uint64_t sz;
VERIFY(u().try_get_size(s, sz));
SASSERT(sz > 0);
return mk_bv_constant(sz-1, s);
}
void mk_lt(app* x, app* y) {
sort* s = x->get_sort();
func_decl* r, *v;
get_rep(s, r, v);
app_ref lt(m()), le(m());
lt = u().mk_lt(x,y);
le = b().mk_ule(m().mk_app(r,y),m().mk_app(r,x));
if (m().has_trace_stream()) {
app_ref body(m());
body = m().mk_eq(lt, le);
log_axiom_instantiation(body);
}
ctx.internalize(lt, false);
ctx.internalize(le, false);
literal lit1(ctx.get_literal(lt));
literal lit2(ctx.get_literal(le));
ctx.mark_as_relevant(lit1);
ctx.mark_as_relevant(lit2);
literal lits1[2] = { lit1, lit2 };
literal lits2[2] = { ~lit1, ~lit2 };
ctx.mk_th_axiom(get_id(), 2, lits1);
ctx.mk_th_axiom(get_id(), 2, lits2);
if (m().has_trace_stream()) m().trace_stream() << "[end-of-instance]\n";
}
void assert_cnstr(expr* e) {
TRACE("theory_dl", tout << mk_pp(e, m()) << "\n";);
if (m().has_trace_stream()) log_axiom_instantiation(e);
ctx.internalize(e, false);
if (m().has_trace_stream()) m().trace_stream() << "[end-of-instance]\n";
literal lit(ctx.get_literal(e));
ctx.mark_as_relevant(lit);
ctx.mk_th_axiom(get_id(), 1, &lit);
}
void add_trail(ast* a) {
m_trail.push_back(a);
ctx.push_trail(push_back_vector(m_trail));
}
};
theory* mk_theory_dl(context& ctx) { return alloc(theory_dl, ctx); }
};