mirror of
https://github.com/Z3Prover/z3
synced 2025-04-11 03:33:35 +00:00
832 lines
29 KiB
C++
832 lines
29 KiB
C++
/*++
|
|
Copyright (c) 2010 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
dl_decl_plugin.h
|
|
|
|
Abstract:
|
|
|
|
<abstract>
|
|
|
|
Author:
|
|
|
|
Nikolaj Bjorner (nbjorner) 2010-04-10
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
#include<sstream>
|
|
|
|
#include "ast_pp.h"
|
|
#include "array_decl_plugin.h"
|
|
#include "datatype_decl_plugin.h"
|
|
#include "dl_decl_plugin.h"
|
|
#include "warning.h"
|
|
|
|
namespace datalog {
|
|
|
|
dl_decl_plugin::dl_decl_plugin() :
|
|
m_store_sym("store"),
|
|
m_empty_sym("empty"),
|
|
m_is_empty_sym("is_empty"),
|
|
m_join_sym("join"),
|
|
m_union_sym("union"),
|
|
m_widen_sym("widen"),
|
|
m_project_sym("project"),
|
|
m_filter_sym("filter"),
|
|
m_negation_filter_sym("negation_filter"),
|
|
m_rename_sym("rename"),
|
|
m_complement_sym("complement"),
|
|
m_select_sym("select"),
|
|
m_clone_sym("clone"),
|
|
m_num_sym("N"),
|
|
m_lt_sym("<"),
|
|
m_le_sym("<="),
|
|
m_rule_sym("R"),
|
|
m_hyper_resolve_sym("hyper-res")
|
|
{
|
|
}
|
|
|
|
bool dl_decl_plugin::check_bounds(char const* msg, unsigned low, unsigned up, unsigned val) const {
|
|
if (low <= val && val <= up) {
|
|
return true;
|
|
}
|
|
std::ostringstream buffer;
|
|
buffer << msg << ", value is not within bound " << low << " <= " << val << " <= " << up;
|
|
m_manager->raise_exception(buffer.str().c_str());
|
|
return false;
|
|
}
|
|
|
|
bool dl_decl_plugin::check_domain(unsigned low, unsigned up, unsigned val) const {
|
|
return check_bounds("unexpected number of arguments", low, up, val);
|
|
}
|
|
|
|
bool dl_decl_plugin::check_params(unsigned low, unsigned up, unsigned val) const {
|
|
return check_bounds("unexpected number of parameters", low, up, val);
|
|
}
|
|
|
|
sort * dl_decl_plugin::mk_relation_sort( unsigned num_parameters, parameter const * parameters) {
|
|
bool is_finite = true;
|
|
rational r(1);
|
|
for (unsigned i = 0; is_finite && i < num_parameters; ++i) {
|
|
if (!parameters[i].is_ast() || !is_sort(parameters[i].get_ast())) {
|
|
m_manager->raise_exception("expecting sort parameters");
|
|
return 0;
|
|
}
|
|
sort* s = to_sort(parameters[i].get_ast());
|
|
sort_size sz1 = s->get_num_elements();
|
|
if (sz1.is_finite()) {
|
|
r *= rational(sz1.size(),rational::ui64());
|
|
}
|
|
else {
|
|
is_finite = false;
|
|
}
|
|
}
|
|
sort_size sz;
|
|
if (is_finite && r.is_uint64()) {
|
|
sz = sort_size::mk_finite(r.get_uint64());
|
|
}
|
|
else {
|
|
sz = sort_size::mk_very_big();
|
|
}
|
|
sort_info info(m_family_id, DL_RELATION_SORT, sz, num_parameters, parameters);
|
|
return m_manager->mk_sort(symbol("Table"),info);
|
|
}
|
|
|
|
sort * dl_decl_plugin::mk_finite_sort(unsigned num_params, parameter const* params) {
|
|
if (num_params != 2) {
|
|
m_manager->raise_exception("expecting two parameters");
|
|
return 0;
|
|
}
|
|
if (!params[0].is_symbol()) {
|
|
m_manager->raise_exception("expecting symbol");
|
|
return 0;
|
|
}
|
|
|
|
if (!params[1].is_rational() || !params[1].get_rational().is_uint64()) {
|
|
m_manager->raise_exception("expecting rational");
|
|
return 0;
|
|
}
|
|
sort_size sz = sort_size::mk_finite(params[1].get_rational().get_uint64());
|
|
sort_info info(m_family_id, DL_FINITE_SORT, sz, num_params, params);
|
|
return m_manager->mk_sort(params[0].get_symbol(),info);
|
|
}
|
|
|
|
sort* dl_decl_plugin::mk_rule_sort() {
|
|
sort_size sz(sort_size::mk_infinite());
|
|
sort_info info(m_family_id, DL_RULE_SORT, sz, 0, 0);
|
|
return m_manager->mk_sort(m_rule_sym, info);
|
|
}
|
|
|
|
sort * dl_decl_plugin::mk_sort(decl_kind k, unsigned num_parameters, parameter const * parameters) {
|
|
switch(k) {
|
|
case DL_RELATION_SORT:
|
|
return mk_relation_sort(num_parameters, parameters);
|
|
case DL_FINITE_SORT:
|
|
return mk_finite_sort(num_parameters, parameters);
|
|
case DL_RULE_SORT:
|
|
return mk_rule_sort();
|
|
default:
|
|
UNREACHABLE();
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
bool dl_decl_plugin::is_rel_sort(sort* r) {
|
|
ptr_vector<sort> sorts;
|
|
return is_rel_sort(r, sorts);
|
|
}
|
|
|
|
bool dl_decl_plugin::is_rel_sort(sort* r, ptr_vector<sort>& sorts) {
|
|
if (!is_sort_of(r, m_family_id, DL_RELATION_SORT)) {
|
|
m_manager->raise_exception("expected relation sort");
|
|
return false;
|
|
}
|
|
unsigned n = r->get_num_parameters();
|
|
for (unsigned i = 0; i < n; ++i) {
|
|
parameter const& p = r->get_parameter(i);
|
|
if (!p.is_ast() || !is_sort(p.get_ast())) {
|
|
m_manager->raise_exception("exptected sort parameter");
|
|
return false;
|
|
}
|
|
sorts.push_back(to_sort(p.get_ast()));
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool dl_decl_plugin::is_fin_sort(sort* r) {
|
|
if (!is_sort_of(r, m_family_id, DL_FINITE_SORT)) {
|
|
m_manager->raise_exception("expected finite sort");
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
func_decl* dl_decl_plugin::mk_store_select(decl_kind k, unsigned arity, sort* const* domain) {
|
|
bool is_store = (k == OP_RA_STORE);
|
|
ast_manager& m = *m_manager;
|
|
symbol sym = is_store?m_store_sym:m_select_sym;
|
|
sort * r = domain[0];
|
|
if (!is_store) {
|
|
r = m.mk_bool_sort();
|
|
}
|
|
ptr_vector<sort> sorts;
|
|
if (!is_rel_sort(r, sorts)) {
|
|
return 0;
|
|
}
|
|
if (sorts.size() + 1 != arity) {
|
|
m_manager->raise_exception("wrong arity supplied to relational access");
|
|
return 0;
|
|
}
|
|
for (unsigned i = 0; i < sorts.size(); ++i) {
|
|
if (sorts[i] != domain[i+1]) {
|
|
IF_VERBOSE(0,
|
|
verbose_stream() << "Domain: " << mk_pp(domain[0], m) << "\n" <<
|
|
mk_pp(sorts[i], m) << "\n" <<
|
|
mk_pp(domain[i+1], m) << "\n";);
|
|
m_manager->raise_exception("sort miss-match for relational access");
|
|
return 0;
|
|
}
|
|
}
|
|
func_decl_info info(m_family_id, k, 0, 0);
|
|
return m.mk_func_decl(sym, arity, domain, r, info);
|
|
}
|
|
|
|
func_decl * dl_decl_plugin::mk_empty(parameter const& p) {
|
|
ast_manager& m = *m_manager;
|
|
if (!p.is_ast() || !is_sort(p.get_ast())) {
|
|
m_manager->raise_exception("expected sort parameter");
|
|
return 0;
|
|
}
|
|
sort* r = to_sort(p.get_ast());
|
|
if (!is_rel_sort(r)) {
|
|
return 0;
|
|
}
|
|
func_decl_info info(m_family_id, OP_RA_EMPTY, 1, &p);
|
|
return m.mk_func_decl(m_empty_sym, 0, (sort*const*)0, r, info);
|
|
}
|
|
|
|
func_decl* dl_decl_plugin::mk_project(unsigned num_params, parameter const* params, sort* r) {
|
|
ast_manager& m = *m_manager;
|
|
ptr_vector<sort> sorts;
|
|
vector<parameter> ps;
|
|
TRACE("dl_decl_plugin",
|
|
tout << mk_pp(r, m) << " ";
|
|
for (unsigned i = 0; i < num_params; ++i) {
|
|
tout << params[i] << " ";
|
|
}
|
|
tout << "\n";
|
|
);
|
|
if (!is_rel_sort(r, sorts)) {
|
|
return 0;
|
|
}
|
|
SASSERT(sorts.size() >= num_params);
|
|
// populate ps
|
|
unsigned j = 0, i = 0;
|
|
for (; i < num_params; ++i) {
|
|
if (!params[i].is_int()) {
|
|
m_manager->raise_exception("expecting integer parameter");
|
|
return 0;
|
|
}
|
|
unsigned k = params[i].get_int();
|
|
if (j > k) {
|
|
m_manager->raise_exception("arguments to projection should be increasing");
|
|
return 0;
|
|
}
|
|
while (j < k) {
|
|
ps.push_back(parameter(sorts[j]));
|
|
++j;
|
|
}
|
|
++j;
|
|
}
|
|
for (; j < sorts.size(); ++j) {
|
|
ps.push_back(parameter(sorts[j]));
|
|
}
|
|
SASSERT(ps.size() + num_params == sorts.size());
|
|
sort* r2 = m.mk_sort(m_family_id, DL_RELATION_SORT, ps.size(), ps.c_ptr());
|
|
func_decl_info info(m_family_id, OP_RA_PROJECT, num_params, params);
|
|
return m.mk_func_decl(m_project_sym, 1, &r, r2, info);
|
|
}
|
|
|
|
func_decl * dl_decl_plugin::mk_unionw(decl_kind k, sort* s1, sort* s2) {
|
|
ast_manager& m = *m_manager;
|
|
if (s1 != s2) {
|
|
m_manager->raise_exception("sort miss-match for arguments to union");
|
|
return 0;
|
|
}
|
|
if (!is_rel_sort(s1)) {
|
|
return 0;
|
|
}
|
|
sort* domain[2] = { s1, s2 };
|
|
func_decl_info info(m_family_id, k, 0, 0);
|
|
return m.mk_func_decl(m_union_sym, 2, domain, s1, info);
|
|
}
|
|
|
|
func_decl * dl_decl_plugin::mk_filter(parameter const& p, sort* r) {
|
|
ast_manager& m = *m_manager;
|
|
ptr_vector<sort> sorts;
|
|
if (!is_rel_sort(r, sorts)) {
|
|
return 0;
|
|
}
|
|
if (!p.is_ast() || !is_expr(p.get_ast())) {
|
|
m_manager->raise_exception("ast expression expected to filter");
|
|
}
|
|
expr* f = to_expr(p.get_ast());
|
|
// 1. f is of Boolean type.
|
|
// 2. the free variables in f correspond to column types of r.
|
|
if (!m.is_bool(f)) {
|
|
m_manager->raise_exception("filter predicate should be of Boolean type");
|
|
return 0;
|
|
}
|
|
ptr_vector<expr> todo;
|
|
todo.push_back(f);
|
|
ast_mark mark;
|
|
while (!todo.empty()) {
|
|
expr* e = todo.back();
|
|
todo.pop_back();
|
|
if (mark.is_marked(e)) {
|
|
continue;
|
|
}
|
|
mark.mark(e, true);
|
|
unsigned idx;
|
|
switch(e->get_kind()) {
|
|
case AST_VAR:
|
|
idx = to_var(e)->get_idx();
|
|
if (idx >= sorts.size()) {
|
|
m_manager->raise_exception("illegal index");
|
|
return 0;
|
|
}
|
|
if (sorts[idx] != m.get_sort(e)) {
|
|
m_manager->raise_exception("sort miss-match in filter");
|
|
return 0;
|
|
}
|
|
break;
|
|
case AST_APP:
|
|
for (unsigned i = 0; i < to_app(e)->get_num_args(); ++i) {
|
|
todo.push_back(to_app(e)->get_arg(i));
|
|
}
|
|
break;
|
|
case AST_QUANTIFIER:
|
|
m_manager->raise_exception("quantifiers are not allowed in filter expressions");
|
|
return 0;
|
|
default:
|
|
m_manager->raise_exception("unexpected filter expression kind");
|
|
return 0;
|
|
}
|
|
}
|
|
func_decl_info info(m_family_id, OP_RA_FILTER, 1, &p);
|
|
return m.mk_func_decl(m_filter_sym, 1, &r, r, info);
|
|
}
|
|
|
|
func_decl * dl_decl_plugin::mk_rename(unsigned num_params, parameter const* params, sort* r) {
|
|
ptr_vector<sort> sorts;
|
|
if (!is_rel_sort(r, sorts)) {
|
|
return 0;
|
|
}
|
|
unsigned index0;
|
|
sort* last_sort = 0;
|
|
for (unsigned i = 0; i < num_params; ++i) {
|
|
parameter const& p = params[i];
|
|
if (!p.is_int()) {
|
|
m_manager->raise_exception("expected integer parameter");
|
|
return 0;
|
|
}
|
|
unsigned j = p.get_int();
|
|
if (j >= sorts.size()) {
|
|
// We should not use ast_pp anymore on error messages.
|
|
// m_manager->raise_exception("index %d out of bound %s : %d", j, ast_pp(r, *m_manager).c_str(), sorts.size());
|
|
m_manager->raise_exception("index out of bound");
|
|
return 0;
|
|
}
|
|
if (i == 0) {
|
|
index0 = j;
|
|
last_sort = sorts[j];
|
|
}
|
|
else {
|
|
std::swap(last_sort, sorts[j]);
|
|
}
|
|
}
|
|
sorts[index0] = last_sort;
|
|
vector<parameter> params2;
|
|
for (unsigned i = 0; i < sorts.size(); ++i) {
|
|
params2.push_back(parameter(sorts[i]));
|
|
}
|
|
sort* rng = m_manager->mk_sort(m_family_id, DL_RELATION_SORT, params2.size(), params2.c_ptr());
|
|
func_decl_info info(m_family_id, OP_RA_RENAME, num_params, params);
|
|
return m_manager->mk_func_decl(m_rename_sym, 1, &r, rng, info);
|
|
}
|
|
|
|
func_decl * dl_decl_plugin::mk_join(unsigned num_params, parameter const* params, sort* r1, sort* r2) {
|
|
vector<parameter> params2;
|
|
ptr_vector<sort> sorts1, sorts2;
|
|
if (!is_rel_sort(r1, sorts1)) {
|
|
return 0;
|
|
}
|
|
if (!is_rel_sort(r2, sorts2)) {
|
|
return 0;
|
|
}
|
|
for (unsigned i = 0; i < sorts1.size(); ++i) {
|
|
params2.push_back(parameter(sorts1[i]));
|
|
}
|
|
for (unsigned i = 0; i < sorts2.size(); ++i) {
|
|
params2.push_back(parameter(sorts2[i]));
|
|
}
|
|
if (0 != num_params % 2) {
|
|
m_manager->raise_exception("expecting an even number of parameters to join");
|
|
return 0;
|
|
}
|
|
for (unsigned i = 0; i + 1 < num_params; i += 2) {
|
|
parameter const& p1 = params[i];
|
|
parameter const& p2 = params[i+1];
|
|
if (!p1.is_int() || !p2.is_int()) {
|
|
m_manager->raise_exception("encountered non-integer parameter");
|
|
return 0;
|
|
}
|
|
unsigned i1 = p1.get_int();
|
|
unsigned i2 = p2.get_int();
|
|
if (i1 >= sorts1.size() || i2 >= sorts2.size()) {
|
|
m_manager->raise_exception("index out of bounds");
|
|
return 0;
|
|
}
|
|
if (sorts1[i1] != sorts2[i2]) {
|
|
m_manager->raise_exception("sort miss-match in join");
|
|
return 0;
|
|
}
|
|
}
|
|
sort* args[2] = { r1, r2 };
|
|
sort* rng = m_manager->mk_sort(m_family_id, DL_RELATION_SORT, params2.size(), params2.c_ptr());
|
|
func_decl_info info(m_family_id, OP_RA_JOIN, num_params, params);
|
|
return m_manager->mk_func_decl(m_join_sym, 2, args, rng, info);
|
|
}
|
|
|
|
func_decl* dl_decl_plugin::mk_complement(sort* s) {
|
|
if (!is_rel_sort(s)) {
|
|
return 0;
|
|
}
|
|
func_decl_info info(m_family_id, OP_RA_COMPLEMENT, 0, 0);
|
|
return m_manager->mk_func_decl(m_complement_sym, 1, &s, s, info);
|
|
}
|
|
|
|
func_decl * dl_decl_plugin::mk_negation_filter(unsigned num_params, parameter const* params, sort* r1, sort* r2) {
|
|
ptr_vector<sort> sorts1, sorts2;
|
|
if (!is_rel_sort(r1, sorts1)) {
|
|
return 0;
|
|
}
|
|
if (!is_rel_sort(r2, sorts2)) {
|
|
return 0;
|
|
}
|
|
if (0 != num_params % 2) {
|
|
m_manager->raise_exception("expecting an even number of parameters to negation filter");
|
|
return 0;
|
|
}
|
|
for (unsigned i = 0; i + 1 < num_params; i += 2) {
|
|
parameter const& p1 = params[i];
|
|
parameter const& p2 = params[i+1];
|
|
if (!p1.is_int() || !p2.is_int()) {
|
|
m_manager->raise_exception("encountered non-integer parameter");
|
|
return 0;
|
|
}
|
|
unsigned i1 = p1.get_int();
|
|
unsigned i2 = p2.get_int();
|
|
if (i1 >= sorts1.size() || i2 >= sorts2.size()) {
|
|
m_manager->raise_exception("index out of bounds");
|
|
return 0;
|
|
}
|
|
if (sorts1[i1] != sorts2[i2]) {
|
|
m_manager->raise_exception("sort miss-match in join");
|
|
return 0;
|
|
}
|
|
}
|
|
sort* args[2] = { r1, r2 };
|
|
func_decl_info info(m_family_id, OP_RA_NEGATION_FILTER, num_params, params);
|
|
return m_manager->mk_func_decl(m_negation_filter_sym, 2, args, r1, info);
|
|
}
|
|
|
|
func_decl * dl_decl_plugin::mk_is_empty(sort* s) {
|
|
if (!is_rel_sort(s)) {
|
|
return 0;
|
|
}
|
|
func_decl_info info(m_family_id, OP_RA_IS_EMPTY, 0, 0);
|
|
sort* rng = m_manager->mk_bool_sort();
|
|
return m_manager->mk_func_decl(m_is_empty_sym, 1, &s, rng, info);
|
|
}
|
|
|
|
func_decl * dl_decl_plugin::mk_constant(parameter const* params) {
|
|
parameter const& p = params[0];
|
|
parameter const& ps = params[1];
|
|
if (!p.is_rational() || !p.get_rational().is_uint64()) {
|
|
m_manager->raise_exception("first parameter should be a rational");
|
|
return 0;
|
|
}
|
|
if (!ps.is_ast() || !is_sort(ps.get_ast()) || !is_fin_sort(to_sort(ps.get_ast()))) {
|
|
m_manager->raise_exception("second paramter should be a finite domain sort");
|
|
return 0;
|
|
}
|
|
sort* s = to_sort(ps.get_ast());
|
|
func_decl_info info(m_family_id, OP_DL_CONSTANT, 2, params);
|
|
return m_manager->mk_func_decl(m_num_sym, 0, (sort*const*)0, s, info);
|
|
}
|
|
|
|
func_decl * dl_decl_plugin::mk_compare(decl_kind k, symbol const& sym, sort *const* domain) {
|
|
if (!is_sort_of(domain[0], m_family_id, DL_FINITE_SORT)) {
|
|
m_manager->raise_exception("expecting finite domain sort");
|
|
return 0;
|
|
}
|
|
if (domain[0] != domain[1]) {
|
|
m_manager->raise_exception("expecting two identical finite domain sorts");
|
|
return 0;
|
|
}
|
|
func_decl_info info(m_family_id, k, 0, 0);
|
|
return m_manager->mk_func_decl(sym, 2, domain, m_manager->mk_bool_sort(), info);
|
|
}
|
|
|
|
func_decl * dl_decl_plugin::mk_clone(sort* s) {
|
|
if (!is_rel_sort(s)) {
|
|
return 0;
|
|
}
|
|
func_decl_info info(m_family_id, OP_RA_CLONE, 0, 0);
|
|
return m_manager->mk_func_decl(m_clone_sym, 1, &s, s, info);
|
|
}
|
|
|
|
func_decl * dl_decl_plugin::mk_hyper_res(unsigned num_params, parameter const* params, unsigned arity, sort *const* domain) {
|
|
ast_manager& m = *m_manager;
|
|
func_decl_info info(m_family_id, OP_DL_HYPER_RESOLVE, num_params, params);
|
|
return m_manager->mk_func_decl(m_hyper_resolve_sym, arity, domain, m_manager->mk_proof_sort(), info);
|
|
}
|
|
|
|
func_decl * dl_decl_plugin::mk_func_decl(
|
|
decl_kind k, unsigned num_parameters, parameter const * parameters,
|
|
unsigned arity, sort * const * domain, sort * range) {
|
|
func_decl* result = 0;
|
|
switch(k) {
|
|
|
|
case OP_RA_STORE:
|
|
case OP_RA_SELECT:
|
|
if (!check_params(0, 0, num_parameters) ||
|
|
!check_domain(1, UINT_MAX, arity)) {
|
|
return 0;
|
|
}
|
|
result = mk_store_select(k, arity, domain);
|
|
break;
|
|
|
|
case OP_RA_EMPTY:
|
|
if (!check_params( 1, 1, num_parameters) ||
|
|
!check_domain(0, 0, arity)) {
|
|
return 0;
|
|
}
|
|
result = mk_empty(parameters[0]);
|
|
break;
|
|
|
|
case OP_RA_JOIN:
|
|
if (!check_params(0, UINT_MAX, num_parameters) ||
|
|
!check_domain(2, 2, arity)) {
|
|
return 0;
|
|
}
|
|
result = mk_join(num_parameters, parameters, domain[0], domain[1]);
|
|
break;
|
|
|
|
case OP_RA_UNION:
|
|
case OP_RA_WIDEN:
|
|
if (!check_params( 0, 0, num_parameters) ||
|
|
!check_domain(2, 2, arity)) {
|
|
return 0;
|
|
}
|
|
result = mk_unionw(k, domain[0], domain[1]);
|
|
break;
|
|
|
|
case OP_RA_PROJECT:
|
|
if (!check_params( 1, UINT_MAX, num_parameters) ||
|
|
!check_domain(1, 1, arity)) {
|
|
return 0;
|
|
}
|
|
result = mk_project(num_parameters, parameters, domain[0]);
|
|
break;
|
|
|
|
case OP_RA_FILTER:
|
|
if (!check_params( 1, 1, num_parameters) ||
|
|
!check_domain(1, 1, arity)) {
|
|
return 0;
|
|
}
|
|
result = mk_filter(parameters[0], domain[0]);
|
|
break;
|
|
|
|
case OP_RA_IS_EMPTY:
|
|
if (!check_params( 0, 0, num_parameters) ||
|
|
!check_domain(1, 1, arity)) {
|
|
return 0;
|
|
}
|
|
result = mk_is_empty(domain[0]);
|
|
break;
|
|
|
|
case OP_RA_RENAME:
|
|
if (!check_params( 2, UINT_MAX, num_parameters) ||
|
|
!check_domain(1, 1, arity)) {
|
|
return 0;
|
|
}
|
|
result = mk_rename(num_parameters, parameters, domain[0]);
|
|
break;
|
|
|
|
case OP_RA_COMPLEMENT:
|
|
if (!check_params( 0, 0, num_parameters) ||
|
|
!check_domain(1, 1, arity)) {
|
|
return 0;
|
|
}
|
|
result = mk_complement(domain[0]);
|
|
break;
|
|
|
|
case OP_RA_NEGATION_FILTER:
|
|
if (!check_params(1, UINT_MAX, num_parameters) ||
|
|
!check_domain(2, 2, arity)) {
|
|
return 0;
|
|
}
|
|
result = mk_negation_filter(num_parameters, parameters, domain[0], domain[1]);
|
|
break;
|
|
|
|
case OP_RA_CLONE:
|
|
if (!check_params(0, 0, num_parameters) || !check_domain(1, 1, arity)) {
|
|
return 0;
|
|
}
|
|
result = mk_clone(domain[0]);
|
|
break;
|
|
|
|
case OP_DL_CONSTANT:
|
|
if (!check_params( 2, 2, num_parameters) ||
|
|
!check_domain(0, 0, arity)) {
|
|
return 0;
|
|
}
|
|
result = mk_constant(parameters);
|
|
break;
|
|
|
|
case OP_DL_LT:
|
|
if (!check_params( 0, 0, num_parameters) ||
|
|
!check_domain(2, 2, arity)) {
|
|
return 0;
|
|
}
|
|
result = mk_compare(OP_DL_LT, m_lt_sym, domain);
|
|
break;
|
|
|
|
case OP_DL_HYPER_RESOLVE:
|
|
result = mk_hyper_res(num_parameters, parameters, arity, domain);
|
|
break;
|
|
|
|
default:
|
|
m_manager->raise_exception("operator not recognized");
|
|
return 0;
|
|
}
|
|
|
|
TRACE("dl_decl_plugin", tout << mk_pp(result, *m_manager) << "\n";);
|
|
return result;
|
|
}
|
|
|
|
void dl_decl_plugin::get_op_names(svector<builtin_name> & op_names, symbol const & logic) {
|
|
|
|
}
|
|
|
|
void dl_decl_plugin::get_sort_names(svector<builtin_name> & sort_names, symbol const & logic) {
|
|
|
|
}
|
|
|
|
|
|
dl_decl_util::ast_plugin_registrator::ast_plugin_registrator(ast_manager& m)
|
|
{
|
|
// ensure required plugins are installed into the ast_manager
|
|
m.register_decl_plugins();
|
|
}
|
|
|
|
dl_decl_util::dl_decl_util(ast_manager& m):
|
|
m_plugin_registrator(m),
|
|
m(m),
|
|
m_arith(m),
|
|
m_bv(m),
|
|
m_fid(m.get_family_id(symbol("datalog_relation")))
|
|
{}
|
|
|
|
// create a constant belonging to a given finite domain.
|
|
|
|
app* dl_decl_util::mk_numeral(uint64 value, sort* s) {
|
|
if (is_finite_sort(s)) {
|
|
parameter params[2] = { parameter(rational(value, rational::ui64())), parameter(s) };
|
|
return m.mk_const(m.mk_func_decl(m_fid, OP_DL_CONSTANT, 2, params, 0, (sort*const*)0));
|
|
}
|
|
if (m_arith.is_int(s) || m_arith.is_real(s)) {
|
|
return m_arith.mk_numeral(rational(value, rational::ui64()), s);
|
|
}
|
|
if (m_bv.is_bv_sort(s)) {
|
|
return m_bv.mk_numeral(rational(value, rational::ui64()), s);
|
|
}
|
|
if (m.is_bool(s)) {
|
|
if (value == 0) {
|
|
return m.mk_false();
|
|
}
|
|
SASSERT(value == 1);
|
|
return m.mk_true();
|
|
}
|
|
m.raise_exception("unrecognized sort");
|
|
return 0;
|
|
}
|
|
|
|
bool dl_decl_util::is_numeral(expr* e, uint64& v) const {
|
|
if (is_numeral(e)) {
|
|
app* c = to_app(e);
|
|
SASSERT(c->get_decl()->get_num_parameters() == 2);
|
|
parameter const& p = c->get_decl()->get_parameter(0);
|
|
SASSERT(p.is_rational());
|
|
SASSERT(p.get_rational().is_uint64());
|
|
v = p.get_rational().get_uint64();
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool dl_decl_util::is_numeral_ext(expr* e, uint64& v) const {
|
|
if (is_numeral(e, v)) {
|
|
return true;
|
|
}
|
|
rational val;
|
|
unsigned bv_size = 0;
|
|
if (m_bv.is_numeral(e, val, bv_size) && bv_size < 64) {
|
|
SASSERT(val.is_uint64());
|
|
v = val.get_uint64();
|
|
return true;
|
|
}
|
|
if (m.is_true(e)) {
|
|
v = 1;
|
|
return true;
|
|
}
|
|
if (m.is_false(e)) {
|
|
v = 0;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool dl_decl_util::is_numeral_ext(expr* c) const {
|
|
if (is_numeral(c)) return true;
|
|
rational val;
|
|
unsigned bv_size = 0;
|
|
if (m_arith.is_numeral(c, val) && val.is_uint64()) return true;
|
|
if (m_bv.is_numeral(c, val, bv_size) && bv_size < 64) return true;
|
|
return m.is_true(c) || m.is_false(c);
|
|
}
|
|
|
|
sort* dl_decl_util::mk_sort(const symbol& name, uint64 domain_size) {
|
|
if (domain_size == 0) {
|
|
std::stringstream sstm;
|
|
sstm << "Domain size of sort '" << name << "' may not be 0";
|
|
throw default_exception(sstm.str());
|
|
}
|
|
parameter params[2] = { parameter(name), parameter(rational(domain_size, rational::ui64())) };
|
|
return m.mk_sort(m_fid, DL_FINITE_SORT, 2, params);
|
|
}
|
|
|
|
bool dl_decl_util::try_get_size(const sort * s, uint64& size) const {
|
|
sort_size sz = s->get_info()->get_num_elements();
|
|
if (sz.is_finite()) {
|
|
size = sz.size();
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
app* dl_decl_util::mk_lt(expr* a, expr* b) {
|
|
expr* args[2] = { a, b };
|
|
return m.mk_app(m_fid, OP_DL_LT, 0, 0, 2, args);
|
|
}
|
|
|
|
app* dl_decl_util::mk_le(expr* a, expr* b) {
|
|
expr* args[2] = { b, a };
|
|
return m.mk_not(m.mk_app(m_fid, OP_DL_LT, 0, 0, 2, args));
|
|
}
|
|
|
|
sort* dl_decl_util::mk_rule_sort() {
|
|
return m.mk_sort(m_fid, DL_RULE_SORT);
|
|
}
|
|
|
|
app* dl_decl_util::mk_rule(symbol const& name, unsigned num_args, expr* const* args) {
|
|
ptr_buffer<sort> sorts;
|
|
for (unsigned i = 0; i < num_args; ++i) {
|
|
sorts.push_back(m.get_sort(args[i]));
|
|
}
|
|
func_decl* f = m.mk_func_decl(name, num_args, sorts.c_ptr(), mk_rule_sort());
|
|
return m.mk_app(f, num_args, args);
|
|
}
|
|
|
|
proof* dl_decl_util::mk_hyper_resolve(unsigned num_premises, proof* const* premises, expr* concl,
|
|
svector<std::pair<unsigned, unsigned> > const& positions,
|
|
vector<expr_ref_vector> const& substs) {
|
|
ptr_vector<expr> fmls;
|
|
SASSERT(positions.size() + 1 == substs.size());
|
|
for (unsigned i = 0; i < num_premises; ++i) {
|
|
TRACE("dl", tout << mk_pp(premises[i], m) << "\n";);
|
|
fmls.push_back(m.get_fact(premises[i]));
|
|
}
|
|
SASSERT(m.is_bool(concl));
|
|
vector<parameter> params;
|
|
for (unsigned i = 0; i < substs.size(); ++i) {
|
|
expr_ref_vector const& vec = substs[i];
|
|
for (unsigned j = 0; j < vec.size(); ++j) {
|
|
params.push_back(parameter(vec[j]));
|
|
}
|
|
if (i + 1 < substs.size()) {
|
|
params.push_back(parameter(positions[i].first));
|
|
params.push_back(parameter(positions[i].second));
|
|
}
|
|
}
|
|
ptr_vector<sort> sorts;
|
|
ptr_vector<expr> args;
|
|
for (unsigned i = 0; i < num_premises; ++i) {
|
|
sorts.push_back(m.mk_proof_sort());
|
|
args.push_back(premises[i]);
|
|
}
|
|
sorts.push_back(m.mk_bool_sort());
|
|
args.push_back(concl);
|
|
app* result = m.mk_app(m_fid, OP_DL_HYPER_RESOLVE, params.size(), params.c_ptr(), args.size(), args.c_ptr());
|
|
SASSERT(result->get_family_id() == m_fid);
|
|
SASSERT(result->get_decl_kind() == OP_DL_HYPER_RESOLVE);
|
|
return result;
|
|
}
|
|
|
|
bool dl_decl_util::is_hyper_resolve(
|
|
proof* p,
|
|
proof_ref_vector& premises,
|
|
expr_ref& conclusion,
|
|
svector<std::pair<unsigned, unsigned> > & positions,
|
|
vector<expr_ref_vector> & substs) const {
|
|
if (!is_hyper_resolve(p)) {
|
|
return false;
|
|
}
|
|
unsigned sz = p->get_num_args();
|
|
SASSERT(sz > 0);
|
|
for (unsigned i = 0; i + 1 < sz; ++i) {
|
|
premises.push_back(to_app(p->get_arg(i)));
|
|
}
|
|
conclusion = p->get_arg(sz-1);
|
|
func_decl* d = p->get_decl();
|
|
unsigned num_p = d->get_num_parameters();
|
|
parameter const* params = d->get_parameters();
|
|
|
|
substs.push_back(expr_ref_vector(m));
|
|
for (unsigned i = 0; i < num_p; ++i) {
|
|
if (params[i].is_int()) {
|
|
SASSERT(i + 1 < num_p);
|
|
SASSERT(params[i+1].is_int());
|
|
unsigned x = static_cast<unsigned>(params[i].get_int());
|
|
unsigned y = static_cast<unsigned>(params[i+1].get_int());
|
|
positions.push_back(std::make_pair(x, y));
|
|
substs.push_back(expr_ref_vector(m));
|
|
++i;
|
|
}
|
|
else {
|
|
SASSERT(params[i].is_ast());
|
|
ast* a = params[i].get_ast();
|
|
SASSERT(is_expr(a));
|
|
substs.back().push_back(to_expr(a));
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
};
|