mirror of
https://github.com/Z3Prover/z3
synced 2025-04-15 21:38:44 +00:00
Merge branch 'unstable' of https://git01.codeplex.com/z3 into unstable
This commit is contained in:
commit
7053b7636b
|
@ -46,7 +46,7 @@ extern "C" {
|
||||||
Z3_TRY;
|
Z3_TRY;
|
||||||
LOG_Z3_mk_int_symbol(c, i);
|
LOG_Z3_mk_int_symbol(c, i);
|
||||||
RESET_ERROR_CODE();
|
RESET_ERROR_CODE();
|
||||||
if (i < 0 || (unsigned)i >= (SIZE_MAX >> PTR_ALIGNMENT)) {
|
if (i < 0 || (size_t)i >= (SIZE_MAX >> PTR_ALIGNMENT)) {
|
||||||
SET_ERROR_CODE(Z3_IOB);
|
SET_ERROR_CODE(Z3_IOB);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -268,6 +268,8 @@ public:
|
||||||
bool is_int_real(expr const * n) const { return is_int_real(get_sort(n)); }
|
bool is_int_real(expr const * n) const { return is_int_real(get_sort(n)); }
|
||||||
|
|
||||||
MATCH_UNARY(is_uminus);
|
MATCH_UNARY(is_uminus);
|
||||||
|
MATCH_UNARY(is_to_real);
|
||||||
|
MATCH_UNARY(is_to_int);
|
||||||
MATCH_BINARY(is_sub);
|
MATCH_BINARY(is_sub);
|
||||||
MATCH_BINARY(is_add);
|
MATCH_BINARY(is_add);
|
||||||
MATCH_BINARY(is_mul);
|
MATCH_BINARY(is_mul);
|
||||||
|
|
|
@ -260,6 +260,7 @@ class smt_printer {
|
||||||
else {
|
else {
|
||||||
m_out << sym << "[";
|
m_out << sym << "[";
|
||||||
}
|
}
|
||||||
|
|
||||||
for (unsigned i = 0; i < num_params; ++i) {
|
for (unsigned i = 0; i < num_params; ++i) {
|
||||||
parameter const& p = params[i];
|
parameter const& p = params[i];
|
||||||
if (p.is_ast()) {
|
if (p.is_ast()) {
|
||||||
|
@ -642,9 +643,7 @@ class smt_printer {
|
||||||
m_out << m_var_names[m_num_var_names - idx - 1];
|
m_out << m_var_names[m_num_var_names - idx - 1];
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (!m_is_smt2) {
|
m_out << "?" << idx;
|
||||||
m_out << "?" << idx;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,52 +20,50 @@ Notes:
|
||||||
#include "expr_abstract.h"
|
#include "expr_abstract.h"
|
||||||
#include "map.h"
|
#include "map.h"
|
||||||
|
|
||||||
void expr_abstract(ast_manager& m, unsigned base, unsigned num_bound, expr* const* bound, expr* n, expr_ref& result) {
|
void expr_abstractor::operator()(unsigned base, unsigned num_bound, expr* const* bound, expr* n, expr_ref& result) {
|
||||||
ast_ref_vector pinned(m);
|
|
||||||
ptr_vector<expr> stack;
|
|
||||||
obj_map<expr, expr*> map;
|
|
||||||
expr * curr = 0, *b = 0;
|
expr * curr = 0, *b = 0;
|
||||||
SASSERT(n->get_ref_count() > 0);
|
SASSERT(n->get_ref_count() > 0);
|
||||||
|
|
||||||
stack.push_back(n);
|
m_stack.push_back(n);
|
||||||
|
|
||||||
for (unsigned i = 0; i < num_bound; ++i) {
|
for (unsigned i = 0; i < num_bound; ++i) {
|
||||||
b = bound[i];
|
b = bound[i];
|
||||||
expr* v = m.mk_var(base + num_bound - i - 1, m.get_sort(b));
|
expr* v = m.mk_var(base + num_bound - i - 1, m.get_sort(b));
|
||||||
pinned.push_back(v);
|
m_pinned.push_back(v);
|
||||||
map.insert(b, v);
|
m_map.insert(b, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
while(!stack.empty()) {
|
while(!m_stack.empty()) {
|
||||||
curr = stack.back();
|
curr = m_stack.back();
|
||||||
if (map.contains(curr)) {
|
if (m_map.contains(curr)) {
|
||||||
stack.pop_back();
|
m_stack.pop_back();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
switch(curr->get_kind()) {
|
switch(curr->get_kind()) {
|
||||||
case AST_VAR: {
|
case AST_VAR: {
|
||||||
map.insert(curr, curr);
|
m_map.insert(curr, curr);
|
||||||
stack.pop_back();
|
m_stack.pop_back();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case AST_APP: {
|
case AST_APP: {
|
||||||
app* a = to_app(curr);
|
app* a = to_app(curr);
|
||||||
bool all_visited = true;
|
bool all_visited = true;
|
||||||
ptr_vector<expr> args;
|
m_args.reset();
|
||||||
for (unsigned i = 0; i < a->get_num_args(); ++i) {
|
for (unsigned i = 0; i < a->get_num_args(); ++i) {
|
||||||
if (!map.find(a->get_arg(i), b)) {
|
if (!m_map.find(a->get_arg(i), b)) {
|
||||||
stack.push_back(a->get_arg(i));
|
m_stack.push_back(a->get_arg(i));
|
||||||
all_visited = false;
|
all_visited = false;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
args.push_back(b);
|
m_args.push_back(b);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (all_visited) {
|
if (all_visited) {
|
||||||
b = m.mk_app(a->get_decl(), args.size(), args.c_ptr());
|
b = m.mk_app(a->get_decl(), m_args.size(), m_args.c_ptr());
|
||||||
pinned.push_back(b);
|
m_pinned.push_back(b);
|
||||||
map.insert(curr, b);
|
m_map.insert(curr, b);
|
||||||
stack.pop_back();
|
m_stack.pop_back();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -81,17 +79,24 @@ void expr_abstract(ast_manager& m, unsigned base, unsigned num_bound, expr* cons
|
||||||
}
|
}
|
||||||
expr_abstract(m, new_base, num_bound, bound, q->get_expr(), result1);
|
expr_abstract(m, new_base, num_bound, bound, q->get_expr(), result1);
|
||||||
b = m.update_quantifier(q, patterns.size(), patterns.c_ptr(), result1.get());
|
b = m.update_quantifier(q, patterns.size(), patterns.c_ptr(), result1.get());
|
||||||
pinned.push_back(b);
|
m_pinned.push_back(b);
|
||||||
map.insert(curr, b);
|
m_map.insert(curr, b);
|
||||||
stack.pop_back();
|
m_stack.pop_back();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!map.find(n, b)) {
|
VERIFY (m_map.find(n, b));
|
||||||
UNREACHABLE();
|
|
||||||
}
|
|
||||||
result = b;
|
result = b;
|
||||||
|
m_pinned.reset();
|
||||||
|
m_map.reset();
|
||||||
|
m_stack.reset();
|
||||||
|
m_args.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void expr_abstract(ast_manager& m, unsigned base, unsigned num_bound, expr* const* bound, expr* n, expr_ref& result) {
|
||||||
|
expr_abstractor abs(m);
|
||||||
|
abs(base, num_bound, bound, n, result);
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,17 @@ Notes:
|
||||||
|
|
||||||
#include"ast.h"
|
#include"ast.h"
|
||||||
|
|
||||||
|
class expr_abstractor {
|
||||||
|
ast_manager& m;
|
||||||
|
expr_ref_vector m_pinned;
|
||||||
|
ptr_vector<expr> m_stack, m_args;
|
||||||
|
obj_map<expr, expr*> m_map;
|
||||||
|
|
||||||
|
public:
|
||||||
|
expr_abstractor(ast_manager& m): m(m), m_pinned(m) {}
|
||||||
|
void operator()(unsigned base, unsigned num_bound, expr* const* bound, expr* n, expr_ref& result);
|
||||||
|
};
|
||||||
|
|
||||||
void expr_abstract(ast_manager& m, unsigned base, unsigned num_bound, expr* const* bound, expr* n, expr_ref& result);
|
void expr_abstract(ast_manager& m, unsigned base, unsigned num_bound, expr* const* bound, expr* n, expr_ref& result);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -93,7 +93,9 @@ void var_counter::count_vars(ast_manager & m, const app * pred, int coef) {
|
||||||
unsigned n = pred->get_num_args();
|
unsigned n = pred->get_num_args();
|
||||||
for (unsigned i = 0; i < n; i++) {
|
for (unsigned i = 0; i < n; i++) {
|
||||||
m_sorts.reset();
|
m_sorts.reset();
|
||||||
::get_free_vars(pred->get_arg(i), m_sorts);
|
m_todo.reset();
|
||||||
|
m_mark.reset();
|
||||||
|
::get_free_vars(m_mark, m_todo, pred->get_arg(i), m_sorts);
|
||||||
for (unsigned j = 0; j < m_sorts.size(); ++j) {
|
for (unsigned j = 0; j < m_sorts.size(); ++j) {
|
||||||
if (m_sorts[j]) {
|
if (m_sorts[j]) {
|
||||||
update(j, coef);
|
update(j, coef);
|
||||||
|
@ -108,24 +110,27 @@ unsigned var_counter::get_max_var(bool& has_var) {
|
||||||
unsigned max_var = 0;
|
unsigned max_var = 0;
|
||||||
while (!m_todo.empty()) {
|
while (!m_todo.empty()) {
|
||||||
expr* e = m_todo.back();
|
expr* e = m_todo.back();
|
||||||
unsigned scope = m_scopes.back();
|
|
||||||
m_todo.pop_back();
|
m_todo.pop_back();
|
||||||
m_scopes.pop_back();
|
|
||||||
if (m_visited.is_marked(e)) {
|
if (m_visited.is_marked(e)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
m_visited.mark(e, true);
|
m_visited.mark(e, true);
|
||||||
switch(e->get_kind()) {
|
switch(e->get_kind()) {
|
||||||
case AST_QUANTIFIER: {
|
case AST_QUANTIFIER: {
|
||||||
|
var_counter aux_counter;
|
||||||
quantifier* q = to_quantifier(e);
|
quantifier* q = to_quantifier(e);
|
||||||
m_todo.push_back(q->get_expr());
|
bool has_var1 = false;
|
||||||
m_scopes.push_back(scope + q->get_num_decls());
|
unsigned max_v = aux_counter.get_max_var(has_var1);
|
||||||
|
if (max_v > max_var + q->get_num_decls()) {
|
||||||
|
max_var = max_v - q->get_num_decls();
|
||||||
|
has_var = true;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case AST_VAR: {
|
case AST_VAR: {
|
||||||
if (to_var(e)->get_idx() >= scope + max_var) {
|
if (to_var(e)->get_idx() >= max_var) {
|
||||||
has_var = true;
|
has_var = true;
|
||||||
max_var = to_var(e)->get_idx() - scope;
|
max_var = to_var(e)->get_idx();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -133,7 +138,6 @@ unsigned var_counter::get_max_var(bool& has_var) {
|
||||||
app* a = to_app(e);
|
app* a = to_app(e);
|
||||||
for (unsigned i = 0; i < a->get_num_args(); ++i) {
|
for (unsigned i = 0; i < a->get_num_args(); ++i) {
|
||||||
m_todo.push_back(a->get_arg(i));
|
m_todo.push_back(a->get_arg(i));
|
||||||
m_scopes.push_back(scope);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -150,14 +154,12 @@ unsigned var_counter::get_max_var(bool& has_var) {
|
||||||
unsigned var_counter::get_max_var(expr* e) {
|
unsigned var_counter::get_max_var(expr* e) {
|
||||||
bool has_var = false;
|
bool has_var = false;
|
||||||
m_todo.push_back(e);
|
m_todo.push_back(e);
|
||||||
m_scopes.push_back(0);
|
|
||||||
return get_max_var(has_var);
|
return get_max_var(has_var);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned var_counter::get_next_var(expr* e) {
|
unsigned var_counter::get_next_var(expr* e) {
|
||||||
bool has_var = false;
|
bool has_var = false;
|
||||||
m_todo.push_back(e);
|
m_todo.push_back(e);
|
||||||
m_scopes.push_back(0);
|
|
||||||
unsigned mv = get_max_var(has_var);
|
unsigned mv = get_max_var(has_var);
|
||||||
if (has_var) mv++;
|
if (has_var) mv++;
|
||||||
return mv;
|
return mv;
|
||||||
|
|
|
@ -38,6 +38,7 @@ public:
|
||||||
|
|
||||||
counter(bool stay_non_negative = true) : m_stay_non_negative(stay_non_negative) {}
|
counter(bool stay_non_negative = true) : m_stay_non_negative(stay_non_negative) {}
|
||||||
|
|
||||||
|
void reset() { m_data.reset(); }
|
||||||
iterator begin() const { return m_data.begin(); }
|
iterator begin() const { return m_data.begin(); }
|
||||||
iterator end() const { return m_data.end(); }
|
iterator end() const { return m_data.end(); }
|
||||||
void update(unsigned el, int delta);
|
void update(unsigned el, int delta);
|
||||||
|
@ -71,6 +72,7 @@ protected:
|
||||||
ptr_vector<sort> m_sorts;
|
ptr_vector<sort> m_sorts;
|
||||||
expr_fast_mark1 m_visited;
|
expr_fast_mark1 m_visited;
|
||||||
ptr_vector<expr> m_todo;
|
ptr_vector<expr> m_todo;
|
||||||
|
ast_mark m_mark;
|
||||||
unsigned_vector m_scopes;
|
unsigned_vector m_scopes;
|
||||||
unsigned get_max_var(bool & has_var);
|
unsigned get_max_var(bool & has_var);
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -17,7 +17,6 @@ Notes:
|
||||||
|
|
||||||
--*/
|
--*/
|
||||||
#include"var_subst.h"
|
#include"var_subst.h"
|
||||||
#include"used_vars.h"
|
|
||||||
#include"ast_ll_pp.h"
|
#include"ast_ll_pp.h"
|
||||||
#include"ast_pp.h"
|
#include"ast_pp.h"
|
||||||
#include"ast_smt2_pp.h"
|
#include"ast_smt2_pp.h"
|
||||||
|
@ -40,7 +39,7 @@ void var_subst::operator()(expr * n, unsigned num_args, expr * const * args, exp
|
||||||
tout << mk_ismt2_pp(result, m_reducer.m()) << "\n";);
|
tout << mk_ismt2_pp(result, m_reducer.m()) << "\n";);
|
||||||
}
|
}
|
||||||
|
|
||||||
void elim_unused_vars(ast_manager & m, quantifier * q, expr_ref & result) {
|
void unused_vars_eliminator::operator()(quantifier* q, expr_ref & result) {
|
||||||
SASSERT(is_well_sorted(m, q));
|
SASSERT(is_well_sorted(m, q));
|
||||||
if (is_ground(q->get_expr())) {
|
if (is_ground(q->get_expr())) {
|
||||||
// ignore patterns if the body is a ground formula.
|
// ignore patterns if the body is a ground formula.
|
||||||
|
@ -51,17 +50,17 @@ void elim_unused_vars(ast_manager & m, quantifier * q, expr_ref & result) {
|
||||||
result = q;
|
result = q;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
used_vars used;
|
m_used.reset();
|
||||||
used.process(q->get_expr());
|
m_used.process(q->get_expr());
|
||||||
unsigned num_patterns = q->get_num_patterns();
|
unsigned num_patterns = q->get_num_patterns();
|
||||||
for (unsigned i = 0; i < num_patterns; i++)
|
for (unsigned i = 0; i < num_patterns; i++)
|
||||||
used.process(q->get_pattern(i));
|
m_used.process(q->get_pattern(i));
|
||||||
unsigned num_no_patterns = q->get_num_no_patterns();
|
unsigned num_no_patterns = q->get_num_no_patterns();
|
||||||
for (unsigned i = 0; i < num_no_patterns; i++)
|
for (unsigned i = 0; i < num_no_patterns; i++)
|
||||||
used.process(q->get_no_pattern(i));
|
m_used.process(q->get_no_pattern(i));
|
||||||
|
|
||||||
unsigned num_decls = q->get_num_decls();
|
unsigned num_decls = q->get_num_decls();
|
||||||
if (used.uses_all_vars(num_decls)) {
|
if (m_used.uses_all_vars(num_decls)) {
|
||||||
q->set_no_unused_vars();
|
q->set_no_unused_vars();
|
||||||
result = q;
|
result = q;
|
||||||
return;
|
return;
|
||||||
|
@ -70,7 +69,7 @@ void elim_unused_vars(ast_manager & m, quantifier * q, expr_ref & result) {
|
||||||
ptr_buffer<sort> used_decl_sorts;
|
ptr_buffer<sort> used_decl_sorts;
|
||||||
buffer<symbol> used_decl_names;
|
buffer<symbol> used_decl_names;
|
||||||
for (unsigned i = 0; i < num_decls; ++i) {
|
for (unsigned i = 0; i < num_decls; ++i) {
|
||||||
if (used.contains(num_decls - i - 1)) {
|
if (m_used.contains(num_decls - i - 1)) {
|
||||||
used_decl_sorts.push_back(q->get_decl_sort(i));
|
used_decl_sorts.push_back(q->get_decl_sort(i));
|
||||||
used_decl_names.push_back(q->get_decl_name(i));
|
used_decl_names.push_back(q->get_decl_name(i));
|
||||||
}
|
}
|
||||||
|
@ -79,10 +78,10 @@ void elim_unused_vars(ast_manager & m, quantifier * q, expr_ref & result) {
|
||||||
unsigned num_removed = 0;
|
unsigned num_removed = 0;
|
||||||
expr_ref_buffer var_mapping(m);
|
expr_ref_buffer var_mapping(m);
|
||||||
int next_idx = 0;
|
int next_idx = 0;
|
||||||
unsigned sz = used.get_max_found_var_idx_plus_1();
|
unsigned sz = m_used.get_max_found_var_idx_plus_1();
|
||||||
|
|
||||||
for (unsigned i = 0; i < num_decls; ++i) {
|
for (unsigned i = 0; i < num_decls; ++i) {
|
||||||
sort * s = used.contains(i);
|
sort * s = m_used.contains(i);
|
||||||
if (s) {
|
if (s) {
|
||||||
var_mapping.push_back(m.mk_var(next_idx, s));
|
var_mapping.push_back(m.mk_var(next_idx, s));
|
||||||
next_idx++;
|
next_idx++;
|
||||||
|
@ -95,7 +94,7 @@ void elim_unused_vars(ast_manager & m, quantifier * q, expr_ref & result) {
|
||||||
// (VAR 0) is in the first position of var_mapping.
|
// (VAR 0) is in the first position of var_mapping.
|
||||||
|
|
||||||
for (unsigned i = num_decls; i < sz; i++) {
|
for (unsigned i = num_decls; i < sz; i++) {
|
||||||
sort * s = used.contains(i);
|
sort * s = m_used.contains(i);
|
||||||
if (s)
|
if (s)
|
||||||
var_mapping.push_back(m.mk_var(i - num_removed, s));
|
var_mapping.push_back(m.mk_var(i - num_removed, s));
|
||||||
else
|
else
|
||||||
|
@ -110,9 +109,8 @@ void elim_unused_vars(ast_manager & m, quantifier * q, expr_ref & result) {
|
||||||
std::reverse(var_mapping.c_ptr(), var_mapping.c_ptr() + var_mapping.size());
|
std::reverse(var_mapping.c_ptr(), var_mapping.c_ptr() + var_mapping.size());
|
||||||
|
|
||||||
expr_ref new_expr(m);
|
expr_ref new_expr(m);
|
||||||
var_subst subst(m);
|
|
||||||
|
|
||||||
subst(q->get_expr(), var_mapping.size(), var_mapping.c_ptr(), new_expr);
|
m_subst(q->get_expr(), var_mapping.size(), var_mapping.c_ptr(), new_expr);
|
||||||
|
|
||||||
if (num_removed == num_decls) {
|
if (num_removed == num_decls) {
|
||||||
result = new_expr;
|
result = new_expr;
|
||||||
|
@ -124,11 +122,11 @@ void elim_unused_vars(ast_manager & m, quantifier * q, expr_ref & result) {
|
||||||
expr_ref_buffer new_no_patterns(m);
|
expr_ref_buffer new_no_patterns(m);
|
||||||
|
|
||||||
for (unsigned i = 0; i < num_patterns; i++) {
|
for (unsigned i = 0; i < num_patterns; i++) {
|
||||||
subst(q->get_pattern(i), var_mapping.size(), var_mapping.c_ptr(), tmp);
|
m_subst(q->get_pattern(i), var_mapping.size(), var_mapping.c_ptr(), tmp);
|
||||||
new_patterns.push_back(tmp);
|
new_patterns.push_back(tmp);
|
||||||
}
|
}
|
||||||
for (unsigned i = 0; i < num_no_patterns; i++) {
|
for (unsigned i = 0; i < num_no_patterns; i++) {
|
||||||
subst(q->get_no_pattern(i), var_mapping.size(), var_mapping.c_ptr(), tmp);
|
m_subst(q->get_no_pattern(i), var_mapping.size(), var_mapping.c_ptr(), tmp);
|
||||||
new_no_patterns.push_back(tmp);
|
new_no_patterns.push_back(tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -145,7 +143,12 @@ void elim_unused_vars(ast_manager & m, quantifier * q, expr_ref & result) {
|
||||||
num_no_patterns,
|
num_no_patterns,
|
||||||
new_no_patterns.c_ptr());
|
new_no_patterns.c_ptr());
|
||||||
to_quantifier(result)->set_no_unused_vars();
|
to_quantifier(result)->set_no_unused_vars();
|
||||||
SASSERT(is_well_sorted(m, result));
|
SASSERT(is_well_sorted(m, result));
|
||||||
|
}
|
||||||
|
|
||||||
|
void elim_unused_vars(ast_manager & m, quantifier * q, expr_ref & result) {
|
||||||
|
unused_vars_eliminator el(m);
|
||||||
|
el(q, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
void instantiate(ast_manager & m, quantifier * q, expr * const * exprs, expr_ref & result) {
|
void instantiate(ast_manager & m, quantifier * q, expr * const * exprs, expr_ref & result) {
|
||||||
|
@ -161,9 +164,7 @@ void instantiate(ast_manager & m, quantifier * q, expr * const * exprs, expr_ref
|
||||||
tout << "\n----->\n" << mk_ismt2_pp(result, m) << "\n";);
|
tout << "\n----->\n" << mk_ismt2_pp(result, m) << "\n";);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void get_free_vars_offset(expr* e, unsigned offset, ptr_vector<sort>& sorts) {
|
static void get_free_vars_offset(ast_mark& mark, ptr_vector<expr>& todo, unsigned offset, expr* e, ptr_vector<sort>& sorts) {
|
||||||
ast_mark mark;
|
|
||||||
ptr_vector<expr> todo;
|
|
||||||
todo.push_back(e);
|
todo.push_back(e);
|
||||||
while (!todo.empty()) {
|
while (!todo.empty()) {
|
||||||
e = todo.back();
|
e = todo.back();
|
||||||
|
@ -175,7 +176,9 @@ static void get_free_vars_offset(expr* e, unsigned offset, ptr_vector<sort>& sor
|
||||||
switch(e->get_kind()) {
|
switch(e->get_kind()) {
|
||||||
case AST_QUANTIFIER: {
|
case AST_QUANTIFIER: {
|
||||||
quantifier* q = to_quantifier(e);
|
quantifier* q = to_quantifier(e);
|
||||||
get_free_vars_offset(q->get_expr(), offset+q->get_num_decls(), sorts);
|
ast_mark mark1;
|
||||||
|
ptr_vector<expr> todo1;
|
||||||
|
get_free_vars_offset(mark1, todo1, offset+q->get_num_decls(), q->get_expr(), sorts);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case AST_VAR: {
|
case AST_VAR: {
|
||||||
|
@ -207,5 +210,11 @@ static void get_free_vars_offset(expr* e, unsigned offset, ptr_vector<sort>& sor
|
||||||
|
|
||||||
|
|
||||||
void get_free_vars(expr* e, ptr_vector<sort>& sorts) {
|
void get_free_vars(expr* e, ptr_vector<sort>& sorts) {
|
||||||
get_free_vars_offset(e, 0, sorts);
|
ast_mark mark;
|
||||||
|
ptr_vector<expr> todo;
|
||||||
|
get_free_vars_offset(mark, todo, 0, e, sorts);
|
||||||
|
}
|
||||||
|
|
||||||
|
void get_free_vars(ast_mark& mark, ptr_vector<expr>& todo, expr* e, ptr_vector<sort>& sorts) {
|
||||||
|
get_free_vars_offset(mark, todo, 0, e, sorts);
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@ Notes:
|
||||||
#define _VAR_SUBST_H_
|
#define _VAR_SUBST_H_
|
||||||
|
|
||||||
#include"rewriter.h"
|
#include"rewriter.h"
|
||||||
|
#include"used_vars.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\brief Alias for var_shifter class.
|
\brief Alias for var_shifter class.
|
||||||
|
@ -53,6 +54,15 @@ public:
|
||||||
/**
|
/**
|
||||||
\brief Eliminate the unused variables from \c q. Store the result in \c r.
|
\brief Eliminate the unused variables from \c q. Store the result in \c r.
|
||||||
*/
|
*/
|
||||||
|
class unused_vars_eliminator {
|
||||||
|
ast_manager& m;
|
||||||
|
var_subst m_subst;
|
||||||
|
used_vars m_used;
|
||||||
|
public:
|
||||||
|
unused_vars_eliminator(ast_manager& m): m(m), m_subst(m) {}
|
||||||
|
void operator()(quantifier* q, expr_ref& r);
|
||||||
|
};
|
||||||
|
|
||||||
void elim_unused_vars(ast_manager & m, quantifier * q, expr_ref & r);
|
void elim_unused_vars(ast_manager & m, quantifier * q, expr_ref & r);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -73,6 +83,8 @@ void instantiate(ast_manager & m, quantifier * q, expr * const * exprs, expr_ref
|
||||||
*/
|
*/
|
||||||
void get_free_vars(expr* e, ptr_vector<sort>& sorts);
|
void get_free_vars(expr* e, ptr_vector<sort>& sorts);
|
||||||
|
|
||||||
|
void get_free_vars(ast_mark& mark, ptr_vector<expr>& todo, expr* e, ptr_vector<sort>& sorts);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
226
src/muz_qe/clp_context.cpp
Normal file
226
src/muz_qe/clp_context.cpp
Normal file
|
@ -0,0 +1,226 @@
|
||||||
|
/*++
|
||||||
|
Copyright (c) 2013 Microsoft Corporation
|
||||||
|
|
||||||
|
Module Name:
|
||||||
|
|
||||||
|
clp_context.cpp
|
||||||
|
|
||||||
|
Abstract:
|
||||||
|
|
||||||
|
Bounded CLP (symbolic simulation using Z3) context.
|
||||||
|
|
||||||
|
Author:
|
||||||
|
|
||||||
|
Nikolaj Bjorner (nbjorner) 2013-04-26
|
||||||
|
|
||||||
|
Revision History:
|
||||||
|
|
||||||
|
--*/
|
||||||
|
|
||||||
|
#include "clp_context.h"
|
||||||
|
#include "dl_context.h"
|
||||||
|
#include "unifier.h"
|
||||||
|
#include "var_subst.h"
|
||||||
|
#include "substitution.h"
|
||||||
|
|
||||||
|
namespace datalog {
|
||||||
|
|
||||||
|
class clp::imp {
|
||||||
|
struct stats {
|
||||||
|
stats() { reset(); }
|
||||||
|
void reset() { memset(this, 0, sizeof(*this)); }
|
||||||
|
unsigned m_num_unfold;
|
||||||
|
unsigned m_num_no_unfold;
|
||||||
|
unsigned m_num_subsumed;
|
||||||
|
};
|
||||||
|
|
||||||
|
context& m_ctx;
|
||||||
|
ast_manager& m;
|
||||||
|
rule_manager& rm;
|
||||||
|
smt_params m_fparams;
|
||||||
|
smt::kernel m_solver;
|
||||||
|
var_subst m_var_subst;
|
||||||
|
expr_ref_vector m_ground;
|
||||||
|
app_ref_vector m_goals;
|
||||||
|
volatile bool m_cancel;
|
||||||
|
stats m_stats;
|
||||||
|
public:
|
||||||
|
imp(context& ctx):
|
||||||
|
m_ctx(ctx),
|
||||||
|
m(ctx.get_manager()),
|
||||||
|
rm(ctx.get_rule_manager()),
|
||||||
|
m_solver(m, m_fparams), // TBD: can be replaced by efficient BV solver.
|
||||||
|
m_var_subst(m, false),
|
||||||
|
m_ground(m),
|
||||||
|
m_goals(m),
|
||||||
|
m_cancel(false)
|
||||||
|
{
|
||||||
|
// m_fparams.m_relevancy_lvl = 0;
|
||||||
|
m_fparams.m_mbqi = false;
|
||||||
|
m_fparams.m_soft_timeout = 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
~imp() {}
|
||||||
|
|
||||||
|
lbool query(expr* query) {
|
||||||
|
m_ctx.ensure_opened();
|
||||||
|
m_solver.reset();
|
||||||
|
m_goals.reset();
|
||||||
|
rm.mk_query(query, m_ctx.get_rules());
|
||||||
|
expr_ref head(m);
|
||||||
|
head = m_ctx.get_rules().last()->get_head();
|
||||||
|
ground(head);
|
||||||
|
m_goals.push_back(to_app(head));
|
||||||
|
return search(20, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cancel() {
|
||||||
|
m_cancel = true;
|
||||||
|
m_solver.cancel();
|
||||||
|
}
|
||||||
|
|
||||||
|
void cleanup() {
|
||||||
|
m_cancel = false;
|
||||||
|
m_goals.reset();
|
||||||
|
m_solver.reset_cancel();
|
||||||
|
}
|
||||||
|
|
||||||
|
void reset_statistics() {
|
||||||
|
m_stats.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void collect_statistics(statistics& st) const {
|
||||||
|
//st.update("tab.num_unfold", m_stats.m_num_unfold);
|
||||||
|
//st.update("tab.num_unfold_fail", m_stats.m_num_no_unfold);
|
||||||
|
//st.update("tab.num_subsumed", m_stats.m_num_subsumed);
|
||||||
|
}
|
||||||
|
|
||||||
|
void display_certificate(std::ostream& out) const {
|
||||||
|
expr_ref ans = get_answer();
|
||||||
|
out << mk_pp(ans, m) << "\n";
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
expr_ref get_answer() const {
|
||||||
|
return expr_ref(m.mk_true(), m);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
void reset_ground() {
|
||||||
|
m_ground.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ground(expr_ref& e) {
|
||||||
|
ptr_vector<sort> sorts;
|
||||||
|
get_free_vars(e, sorts);
|
||||||
|
if (m_ground.size() < sorts.size()) {
|
||||||
|
m_ground.resize(sorts.size());
|
||||||
|
}
|
||||||
|
for (unsigned i = 0; i < sorts.size(); ++i) {
|
||||||
|
if (sorts[i] && !m_ground[i].get()) {
|
||||||
|
m_ground[i] = m.mk_fresh_const("c",sorts[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m_var_subst(e, m_ground.size(), m_ground.c_ptr(), e);
|
||||||
|
}
|
||||||
|
|
||||||
|
lbool search(unsigned depth, unsigned index) {
|
||||||
|
if (index == m_goals.size()) {
|
||||||
|
return l_true;
|
||||||
|
}
|
||||||
|
if (depth == 0) {
|
||||||
|
return l_undef;
|
||||||
|
}
|
||||||
|
IF_VERBOSE(1, verbose_stream() << "search " << depth << " " << index << "\n";);
|
||||||
|
unsigned num_goals = m_goals.size();
|
||||||
|
app* head = m_goals[index].get();
|
||||||
|
rule_vector const& rules = m_ctx.get_rules().get_predicate_rules(head->get_decl());
|
||||||
|
lbool status = l_false;
|
||||||
|
for (unsigned i = 0; i < rules.size(); ++i) {
|
||||||
|
rule* r = rules[i];
|
||||||
|
m_solver.push();
|
||||||
|
reset_ground();
|
||||||
|
expr_ref tmp(m);
|
||||||
|
tmp = r->get_head();
|
||||||
|
IF_VERBOSE(2, verbose_stream() << index << " " << mk_pp(tmp, m) << "\n";);
|
||||||
|
ground(tmp);
|
||||||
|
for (unsigned j = 0; j < head->get_num_args(); ++j) {
|
||||||
|
expr_ref eq(m);
|
||||||
|
eq = m.mk_eq(head->get_arg(j), to_app(tmp)->get_arg(j));
|
||||||
|
m_solver.assert_expr(eq);
|
||||||
|
}
|
||||||
|
for (unsigned j = r->get_uninterpreted_tail_size(); j < r->get_tail_size(); ++j) {
|
||||||
|
tmp = r->get_tail(j);
|
||||||
|
ground(tmp);
|
||||||
|
m_solver.assert_expr(tmp);
|
||||||
|
}
|
||||||
|
lbool is_sat = m_solver.check();
|
||||||
|
switch (is_sat) {
|
||||||
|
case l_false:
|
||||||
|
break;
|
||||||
|
case l_true:
|
||||||
|
if (depth == 1 && (index+1 > m_goals.size() || r->get_uninterpreted_tail_size() > 0)) {
|
||||||
|
status = l_undef;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
for (unsigned j = 0; j < r->get_uninterpreted_tail_size(); ++j) {
|
||||||
|
tmp = r->get_tail(j);
|
||||||
|
ground(tmp);
|
||||||
|
m_goals.push_back(to_app(tmp));
|
||||||
|
}
|
||||||
|
switch(search(depth-1, index+1)) {
|
||||||
|
case l_undef:
|
||||||
|
status = l_undef;
|
||||||
|
// fallthrough
|
||||||
|
case l_false:
|
||||||
|
m_goals.resize(num_goals);
|
||||||
|
break;
|
||||||
|
case l_true:
|
||||||
|
return l_true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case l_undef:
|
||||||
|
status = l_undef;
|
||||||
|
throw default_exception("undef");
|
||||||
|
}
|
||||||
|
m_solver.pop(1);
|
||||||
|
}
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
proof_ref get_proof() const {
|
||||||
|
return proof_ref(0, m);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
clp::clp(context& ctx):
|
||||||
|
m_imp(alloc(imp, ctx)) {
|
||||||
|
}
|
||||||
|
clp::~clp() {
|
||||||
|
dealloc(m_imp);
|
||||||
|
}
|
||||||
|
lbool clp::query(expr* query) {
|
||||||
|
return m_imp->query(query);
|
||||||
|
}
|
||||||
|
void clp::cancel() {
|
||||||
|
m_imp->cancel();
|
||||||
|
}
|
||||||
|
void clp::cleanup() {
|
||||||
|
m_imp->cleanup();
|
||||||
|
}
|
||||||
|
void clp::reset_statistics() {
|
||||||
|
m_imp->reset_statistics();
|
||||||
|
}
|
||||||
|
void clp::collect_statistics(statistics& st) const {
|
||||||
|
m_imp->collect_statistics(st);
|
||||||
|
}
|
||||||
|
void clp::display_certificate(std::ostream& out) const {
|
||||||
|
m_imp->display_certificate(out);
|
||||||
|
}
|
||||||
|
expr_ref clp::get_answer() {
|
||||||
|
return m_imp->get_answer();
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
45
src/muz_qe/clp_context.h
Normal file
45
src/muz_qe/clp_context.h
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
/*++
|
||||||
|
Copyright (c) 2013 Microsoft Corporation
|
||||||
|
|
||||||
|
Module Name:
|
||||||
|
|
||||||
|
clp_context.h
|
||||||
|
|
||||||
|
Abstract:
|
||||||
|
|
||||||
|
Bounded CLP (symbolic simulation using Z3) context.
|
||||||
|
|
||||||
|
Author:
|
||||||
|
|
||||||
|
Nikolaj Bjorner (nbjorner) 2013-04-26
|
||||||
|
|
||||||
|
Revision History:
|
||||||
|
|
||||||
|
--*/
|
||||||
|
#ifndef _CLP_CONTEXT_H_
|
||||||
|
#define _CLP_CONTEXT_H_
|
||||||
|
|
||||||
|
#include "ast.h"
|
||||||
|
#include "lbool.h"
|
||||||
|
#include "statistics.h"
|
||||||
|
|
||||||
|
namespace datalog {
|
||||||
|
class context;
|
||||||
|
|
||||||
|
class clp {
|
||||||
|
class imp;
|
||||||
|
imp* m_imp;
|
||||||
|
public:
|
||||||
|
clp(context& ctx);
|
||||||
|
~clp();
|
||||||
|
lbool query(expr* query);
|
||||||
|
void cancel();
|
||||||
|
void cleanup();
|
||||||
|
void reset_statistics();
|
||||||
|
void collect_statistics(statistics& st) const;
|
||||||
|
void display_certificate(std::ostream& out) const;
|
||||||
|
expr_ref get_answer();
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -656,6 +656,7 @@ namespace datalog {
|
||||||
|
|
||||||
typedef sort * relation_sort;
|
typedef sort * relation_sort;
|
||||||
typedef ptr_vector<sort> relation_signature_base0;
|
typedef ptr_vector<sort> relation_signature_base0;
|
||||||
|
typedef ptr_hash<sort> relation_sort_hash;
|
||||||
|
|
||||||
typedef app * relation_element;
|
typedef app * relation_element;
|
||||||
typedef app_ref relation_element_ref;
|
typedef app_ref relation_element_ref;
|
||||||
|
@ -739,8 +740,8 @@ namespace datalog {
|
||||||
|
|
||||||
struct hash {
|
struct hash {
|
||||||
unsigned operator()(relation_signature const& s) const {
|
unsigned operator()(relation_signature const& s) const {
|
||||||
relation_sort const* sorts = s.c_ptr();
|
return obj_vector_hash<relation_signature>(s);
|
||||||
return string_hash(reinterpret_cast<char const*>(sorts), sizeof(*sorts)*s.size(), 12); }
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct eq {
|
struct eq {
|
||||||
|
@ -816,9 +817,11 @@ namespace datalog {
|
||||||
|
|
||||||
typedef uint64 table_sort;
|
typedef uint64 table_sort;
|
||||||
typedef svector<table_sort> table_signature_base0;
|
typedef svector<table_sort> table_signature_base0;
|
||||||
|
typedef uint64_hash table_sort_hash;
|
||||||
|
|
||||||
typedef uint64 table_element;
|
typedef uint64 table_element;
|
||||||
typedef svector<table_element> table_fact;
|
typedef svector<table_element> table_fact;
|
||||||
|
typedef uint64_hash table_element_hash;
|
||||||
|
|
||||||
struct table_traits {
|
struct table_traits {
|
||||||
typedef table_plugin plugin;
|
typedef table_plugin plugin;
|
||||||
|
@ -881,8 +884,8 @@ namespace datalog {
|
||||||
public:
|
public:
|
||||||
struct hash {
|
struct hash {
|
||||||
unsigned operator()(table_signature const& s) const {
|
unsigned operator()(table_signature const& s) const {
|
||||||
table_sort const* sorts = s.c_ptr();
|
return svector_hash<table_sort_hash>()(s);
|
||||||
return string_hash(reinterpret_cast<char const*>(sorts), sizeof(*sorts)*s.size(), 12); }
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct eq {
|
struct eq {
|
||||||
|
|
|
@ -1004,7 +1004,6 @@ namespace datalog {
|
||||||
symbol is_name(_name.str().c_str());
|
symbol is_name(_name.str().c_str());
|
||||||
std::stringstream _name2;
|
std::stringstream _name2;
|
||||||
_name2 << "get_succ#" << i;
|
_name2 << "get_succ#" << i;
|
||||||
symbol acc_name(_name2.str().c_str());
|
|
||||||
ptr_vector<accessor_decl> accs;
|
ptr_vector<accessor_decl> accs;
|
||||||
type_ref tr(0);
|
type_ref tr(0);
|
||||||
accs.push_back(mk_accessor_decl(name, tr));
|
accs.push_back(mk_accessor_decl(name, tr));
|
||||||
|
|
|
@ -89,15 +89,6 @@ namespace datalog {
|
||||||
|
|
||||||
class check_table : public table_base {
|
class check_table : public table_base {
|
||||||
friend class check_table_plugin;
|
friend class check_table_plugin;
|
||||||
friend class check_table_plugin::join_fn;
|
|
||||||
friend class check_table_plugin::union_fn;
|
|
||||||
friend class check_table_plugin::transformer_fn;
|
|
||||||
friend class check_table_plugin::rename_fn;
|
|
||||||
friend class check_table_plugin::project_fn;
|
|
||||||
friend class check_table_plugin::filter_equal_fn;
|
|
||||||
friend class check_table_plugin::filter_identical_fn;
|
|
||||||
friend class check_table_plugin::filter_interpreted_fn;
|
|
||||||
friend class check_table_plugin::filter_by_negation_fn;
|
|
||||||
|
|
||||||
table_base* m_checker;
|
table_base* m_checker;
|
||||||
table_base* m_tocheck;
|
table_base* m_tocheck;
|
||||||
|
|
|
@ -36,7 +36,7 @@ namespace datalog {
|
||||||
}
|
}
|
||||||
|
|
||||||
void compiler::ensure_predicate_loaded(func_decl * pred, instruction_block & acc) {
|
void compiler::ensure_predicate_loaded(func_decl * pred, instruction_block & acc) {
|
||||||
pred2idx::entry * e = m_pred_regs.insert_if_not_there2(pred, UINT_MAX);
|
pred2idx::obj_map_entry * e = m_pred_regs.insert_if_not_there2(pred, UINT_MAX);
|
||||||
if(e->get_data().m_value!=UINT_MAX) {
|
if(e->get_data().m_value!=UINT_MAX) {
|
||||||
//predicate is already loaded
|
//predicate is already loaded
|
||||||
return;
|
return;
|
||||||
|
@ -421,6 +421,7 @@ namespace datalog {
|
||||||
void compiler::compile_rule_evaluation_run(rule * r, reg_idx head_reg, const reg_idx * tail_regs,
|
void compiler::compile_rule_evaluation_run(rule * r, reg_idx head_reg, const reg_idx * tail_regs,
|
||||||
reg_idx delta_reg, bool use_widening, instruction_block & acc) {
|
reg_idx delta_reg, bool use_widening, instruction_block & acc) {
|
||||||
|
|
||||||
|
ast_manager & m = m_context.get_manager();
|
||||||
m_instruction_observer.start_rule(r);
|
m_instruction_observer.start_rule(r);
|
||||||
|
|
||||||
const app * h = r->get_head();
|
const app * h = r->get_head();
|
||||||
|
@ -433,7 +434,7 @@ namespace datalog {
|
||||||
SASSERT(pt_len<=2); //we require rules to be processed by the mk_simple_joins rule transformer plugin
|
SASSERT(pt_len<=2); //we require rules to be processed by the mk_simple_joins rule transformer plugin
|
||||||
|
|
||||||
reg_idx single_res;
|
reg_idx single_res;
|
||||||
ptr_vector<expr> single_res_expr;
|
expr_ref_vector single_res_expr(m);
|
||||||
|
|
||||||
//used to save on filter_identical instructions where the check is already done
|
//used to save on filter_identical instructions where the check is already done
|
||||||
//by the join operation
|
//by the join operation
|
||||||
|
@ -536,7 +537,7 @@ namespace datalog {
|
||||||
unsigned srlen=single_res_expr.size();
|
unsigned srlen=single_res_expr.size();
|
||||||
SASSERT((single_res==execution_context::void_register) ? (srlen==0) : (srlen==m_reg_signatures[single_res].size()));
|
SASSERT((single_res==execution_context::void_register) ? (srlen==0) : (srlen==m_reg_signatures[single_res].size()));
|
||||||
for(unsigned i=0; i<srlen; i++) {
|
for(unsigned i=0; i<srlen; i++) {
|
||||||
expr * exp = single_res_expr[i];
|
expr * exp = single_res_expr[i].get();
|
||||||
if(is_app(exp)) {
|
if(is_app(exp)) {
|
||||||
SASSERT(m_context.get_decl_util().is_numeral_ext(exp));
|
SASSERT(m_context.get_decl_util().is_numeral_ext(exp));
|
||||||
relation_element value = to_app(exp);
|
relation_element value = to_app(exp);
|
||||||
|
@ -618,14 +619,13 @@ namespace datalog {
|
||||||
dealloc = true;
|
dealloc = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
//enforce interpreted tail predicates
|
// enforce interpreted tail predicates
|
||||||
unsigned ft_len=r->get_tail_size(); //full tail
|
unsigned ft_len=r->get_tail_size(); //full tail
|
||||||
for(unsigned tail_index=ut_len; tail_index<ft_len; tail_index++) {
|
for(unsigned tail_index=ut_len; tail_index<ft_len; tail_index++) {
|
||||||
app * t = r->get_tail(tail_index);
|
app * t = r->get_tail(tail_index);
|
||||||
var_idx_set t_vars;
|
ptr_vector<sort> t_vars;
|
||||||
ast_manager & m = m_context.get_manager();
|
::get_free_vars(t, t_vars);
|
||||||
collect_vars(m, t, t_vars);
|
|
||||||
|
|
||||||
if(t_vars.empty()) {
|
if(t_vars.empty()) {
|
||||||
expr_ref simplified(m);
|
expr_ref simplified(m);
|
||||||
m_context.get_rewriter()(t, simplified);
|
m_context.get_rewriter()(t, simplified);
|
||||||
|
@ -639,40 +639,23 @@ namespace datalog {
|
||||||
}
|
}
|
||||||
|
|
||||||
//determine binding size
|
//determine binding size
|
||||||
unsigned max_var=0;
|
while (!t_vars.back()) {
|
||||||
var_idx_set::iterator vit = t_vars.begin();
|
t_vars.pop_back();
|
||||||
var_idx_set::iterator vend = t_vars.end();
|
|
||||||
for(; vit!=vend; ++vit) {
|
|
||||||
unsigned v = *vit;
|
|
||||||
if(v>max_var) { max_var = v; }
|
|
||||||
}
|
}
|
||||||
|
unsigned max_var = t_vars.size();
|
||||||
|
|
||||||
//create binding
|
//create binding
|
||||||
expr_ref_vector binding(m);
|
expr_ref_vector binding(m);
|
||||||
binding.resize(max_var+1);
|
binding.resize(max_var+1);
|
||||||
vit = t_vars.begin();
|
|
||||||
for(; vit!=vend; ++vit) {
|
for(unsigned v = 0; v < t_vars.size(); ++v) {
|
||||||
unsigned v = *vit;
|
if (!t_vars[v]) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
int2ints::entry * e = var_indexes.find_core(v);
|
int2ints::entry * e = var_indexes.find_core(v);
|
||||||
if(!e) {
|
if(!e) {
|
||||||
//we have an unbound variable, so we add an unbound column for it
|
//we have an unbound variable, so we add an unbound column for it
|
||||||
relation_sort unbound_sort = 0;
|
relation_sort unbound_sort = t_vars[v];
|
||||||
|
|
||||||
for(unsigned hindex = 0; hindex<head_len; hindex++) {
|
|
||||||
expr * harg = h->get_arg(hindex);
|
|
||||||
if(!is_var(harg) || to_var(harg)->get_idx()!=v) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
unbound_sort = to_var(harg)->get_sort();
|
|
||||||
}
|
|
||||||
if(!unbound_sort) {
|
|
||||||
// the variable in the interpreted tail is neither bound in the
|
|
||||||
// uninterpreted tail nor present in the head
|
|
||||||
std::stringstream sstm;
|
|
||||||
sstm << "rule with unbound variable #" << v << " in interpreted tail: ";
|
|
||||||
r->display(m_context, sstm);
|
|
||||||
throw default_exception(sstm.str());
|
|
||||||
}
|
|
||||||
|
|
||||||
reg_idx new_reg;
|
reg_idx new_reg;
|
||||||
TRACE("dl", tout << mk_pp(head_pred, m_context.get_manager()) << "\n";);
|
TRACE("dl", tout << mk_pp(head_pred, m_context.get_manager()) << "\n";);
|
||||||
|
@ -759,7 +742,7 @@ namespace datalog {
|
||||||
m_instruction_observer.finish_rule();
|
m_instruction_observer.finish_rule();
|
||||||
}
|
}
|
||||||
|
|
||||||
void compiler::add_unbound_columns_for_negation(rule* r, func_decl* pred, reg_idx& single_res, ptr_vector<expr>& single_res_expr,
|
void compiler::add_unbound_columns_for_negation(rule* r, func_decl* pred, reg_idx& single_res, expr_ref_vector& single_res_expr,
|
||||||
bool & dealloc, instruction_block & acc) {
|
bool & dealloc, instruction_block & acc) {
|
||||||
uint_set pos_vars;
|
uint_set pos_vars;
|
||||||
u_map<expr*> neg_vars;
|
u_map<expr*> neg_vars;
|
||||||
|
@ -782,7 +765,7 @@ namespace datalog {
|
||||||
}
|
}
|
||||||
// populate positive variables:
|
// populate positive variables:
|
||||||
for (unsigned i = 0; i < single_res_expr.size(); ++i) {
|
for (unsigned i = 0; i < single_res_expr.size(); ++i) {
|
||||||
expr* e = single_res_expr[i];
|
expr* e = single_res_expr[i].get();
|
||||||
if (is_var(e)) {
|
if (is_var(e)) {
|
||||||
pos_vars.insert(to_var(e)->get_idx());
|
pos_vars.insert(to_var(e)->get_idx());
|
||||||
}
|
}
|
||||||
|
@ -849,19 +832,19 @@ namespace datalog {
|
||||||
typedef rule_dependencies::item_set item_set; //set of T
|
typedef rule_dependencies::item_set item_set; //set of T
|
||||||
|
|
||||||
rule_dependencies & m_deps;
|
rule_dependencies & m_deps;
|
||||||
rule_set const& m_rules;
|
|
||||||
context& m_context;
|
|
||||||
item_set & m_removed;
|
item_set & m_removed;
|
||||||
svector<T> m_stack;
|
svector<T> m_stack;
|
||||||
|
ast_mark m_stack_content;
|
||||||
ast_mark m_visited;
|
ast_mark m_visited;
|
||||||
|
|
||||||
void traverse(T v) {
|
void traverse(T v) {
|
||||||
SASSERT(!m_visited.is_marked(v));
|
SASSERT(!m_stack_content.is_marked(v));
|
||||||
if (m_removed.contains(v)) {
|
if(m_visited.is_marked(v) || m_removed.contains(v)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_stack.push_back(v);
|
m_stack.push_back(v);
|
||||||
|
m_stack_content.mark(v, true);
|
||||||
m_visited.mark(v, true);
|
m_visited.mark(v, true);
|
||||||
|
|
||||||
const item_set & deps = m_deps.get_deps(v);
|
const item_set & deps = m_deps.get_deps(v);
|
||||||
|
@ -869,49 +852,22 @@ namespace datalog {
|
||||||
item_set::iterator end = deps.end();
|
item_set::iterator end = deps.end();
|
||||||
for(; it!=end; ++it) {
|
for(; it!=end; ++it) {
|
||||||
T d = *it;
|
T d = *it;
|
||||||
if (m_visited.is_marked(d)) {
|
if(m_stack_content.is_marked(d)) {
|
||||||
//TODO: find the best vertex to remove in the cycle
|
//TODO: find the best vertex to remove in the cycle
|
||||||
remove_from_stack();
|
m_removed.insert(v);
|
||||||
continue;
|
break;
|
||||||
}
|
}
|
||||||
traverse(d);
|
traverse(d);
|
||||||
}
|
}
|
||||||
SASSERT(m_stack.back()==v);
|
SASSERT(m_stack.back()==v);
|
||||||
|
|
||||||
m_stack.pop_back();
|
m_stack.pop_back();
|
||||||
m_visited.mark(v, false);
|
m_stack_content.mark(v, false);
|
||||||
}
|
|
||||||
|
|
||||||
void remove_from_stack() {
|
|
||||||
for (unsigned i = 0; i < m_stack.size(); ++i) {
|
|
||||||
func_decl* p = m_stack[i];
|
|
||||||
if (m_context.has_facts(p)) {
|
|
||||||
m_removed.insert(p);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
rule_vector const& rules = m_rules.get_predicate_rules(p);
|
|
||||||
unsigned stratum = m_rules.get_predicate_strat(p);
|
|
||||||
for (unsigned j = 0; j < rules.size(); ++j) {
|
|
||||||
rule const& r = *rules[j];
|
|
||||||
bool ok = true;
|
|
||||||
for (unsigned k = 0; ok && k < r.get_uninterpreted_tail_size(); ++k) {
|
|
||||||
ok = m_rules.get_predicate_strat(r.get_decl(k)) < stratum;
|
|
||||||
}
|
|
||||||
if (ok) {
|
|
||||||
m_removed.insert(p);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// nothing was found.
|
|
||||||
m_removed.insert(m_stack.back());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
cycle_breaker(rule_dependencies & deps, rule_set const& rules, context& ctx, item_set & removed)
|
cycle_breaker(rule_dependencies & deps, item_set & removed)
|
||||||
: m_deps(deps), m_rules(rules), m_context(ctx), m_removed(removed) { SASSERT(removed.empty()); }
|
: m_deps(deps), m_removed(removed) { SASSERT(removed.empty()); }
|
||||||
|
|
||||||
void operator()() {
|
void operator()() {
|
||||||
rule_dependencies::iterator it = m_deps.begin();
|
rule_dependencies::iterator it = m_deps.begin();
|
||||||
|
@ -933,7 +889,7 @@ namespace datalog {
|
||||||
|
|
||||||
rule_dependencies deps(m_rule_set.get_dependencies());
|
rule_dependencies deps(m_rule_set.get_dependencies());
|
||||||
deps.restrict(preds);
|
deps.restrict(preds);
|
||||||
cycle_breaker(deps, m_rule_set, m_context, global_deltas)();
|
cycle_breaker(deps, global_deltas)();
|
||||||
VERIFY( deps.sort_deps(ordered_preds) );
|
VERIFY( deps.sort_deps(ordered_preds) );
|
||||||
|
|
||||||
//the predicates that were removed to get acyclic induced subgraph are put last
|
//the predicates that were removed to get acyclic induced subgraph are put last
|
||||||
|
@ -1069,12 +1025,17 @@ namespace datalog {
|
||||||
}
|
}
|
||||||
|
|
||||||
func_decl_vector preds_vector;
|
func_decl_vector preds_vector;
|
||||||
func_decl_set global_deltas;
|
func_decl_set global_deltas_dummy;
|
||||||
|
|
||||||
detect_chains(head_preds, preds_vector, global_deltas);
|
detect_chains(head_preds, preds_vector, global_deltas_dummy);
|
||||||
|
|
||||||
|
/*
|
||||||
|
FIXME: right now we use all preds as global deltas for correctness purposes
|
||||||
func_decl_set local_deltas(head_preds);
|
func_decl_set local_deltas(head_preds);
|
||||||
set_difference(local_deltas, global_deltas);
|
set_difference(local_deltas, global_deltas);
|
||||||
|
*/
|
||||||
|
func_decl_set local_deltas;
|
||||||
|
func_decl_set global_deltas(head_preds);
|
||||||
|
|
||||||
pred2idx d_global_src; //these deltas serve as sources of tuples for rule evaluation inside the loop
|
pred2idx d_global_src; //these deltas serve as sources of tuples for rule evaluation inside the loop
|
||||||
get_fresh_registers(global_deltas, d_global_src);
|
get_fresh_registers(global_deltas, d_global_src);
|
||||||
|
|
|
@ -41,7 +41,7 @@ namespace datalog {
|
||||||
typedef hashtable<unsigned, u_hash, u_eq> int_set;
|
typedef hashtable<unsigned, u_hash, u_eq> int_set;
|
||||||
typedef u_map<unsigned> int2int;
|
typedef u_map<unsigned> int2int;
|
||||||
typedef u_map<unsigned_vector> int2ints;
|
typedef u_map<unsigned_vector> int2ints;
|
||||||
typedef map<func_decl *, reg_idx, ptr_hash<func_decl>,ptr_eq<func_decl> > pred2idx;
|
typedef obj_map<func_decl, reg_idx> pred2idx;
|
||||||
typedef unsigned_vector var_vector;
|
typedef unsigned_vector var_vector;
|
||||||
typedef ptr_vector<func_decl> func_decl_vector;
|
typedef ptr_vector<func_decl> func_decl_vector;
|
||||||
|
|
||||||
|
@ -177,7 +177,7 @@ namespace datalog {
|
||||||
void make_full_relation(func_decl* pred, const relation_signature & sig, reg_idx & result,
|
void make_full_relation(func_decl* pred, const relation_signature & sig, reg_idx & result,
|
||||||
instruction_block & acc);
|
instruction_block & acc);
|
||||||
|
|
||||||
void add_unbound_columns_for_negation(rule* compiled_rule, func_decl* pred, reg_idx& single_res, ptr_vector<expr>& single_res_expr,
|
void add_unbound_columns_for_negation(rule* compiled_rule, func_decl* pred, reg_idx& single_res, expr_ref_vector& single_res_expr,
|
||||||
bool & dealloc, instruction_block& acc);
|
bool & dealloc, instruction_block& acc);
|
||||||
|
|
||||||
void make_duplicate_column(reg_idx src, unsigned col, reg_idx & result, instruction_block & acc);
|
void make_duplicate_column(reg_idx src, unsigned col, reg_idx & result, instruction_block & acc);
|
||||||
|
|
|
@ -41,7 +41,6 @@ Revision History:
|
||||||
#include"for_each_expr.h"
|
#include"for_each_expr.h"
|
||||||
#include"ast_smt_pp.h"
|
#include"ast_smt_pp.h"
|
||||||
#include"ast_smt2_pp.h"
|
#include"ast_smt2_pp.h"
|
||||||
#include"expr_functors.h"
|
|
||||||
#include"dl_mk_partial_equiv.h"
|
#include"dl_mk_partial_equiv.h"
|
||||||
#include"dl_mk_bit_blast.h"
|
#include"dl_mk_bit_blast.h"
|
||||||
#include"dl_mk_array_blast.h"
|
#include"dl_mk_array_blast.h"
|
||||||
|
@ -49,7 +48,6 @@ Revision History:
|
||||||
#include"dl_mk_quantifier_abstraction.h"
|
#include"dl_mk_quantifier_abstraction.h"
|
||||||
#include"dl_mk_quantifier_instantiation.h"
|
#include"dl_mk_quantifier_instantiation.h"
|
||||||
#include"datatype_decl_plugin.h"
|
#include"datatype_decl_plugin.h"
|
||||||
#include"expr_abstract.h"
|
|
||||||
|
|
||||||
|
|
||||||
namespace datalog {
|
namespace datalog {
|
||||||
|
@ -226,6 +224,10 @@ namespace datalog {
|
||||||
m_rewriter(m),
|
m_rewriter(m),
|
||||||
m_var_subst(m),
|
m_var_subst(m),
|
||||||
m_rule_manager(*this),
|
m_rule_manager(*this),
|
||||||
|
m_elim_unused_vars(m),
|
||||||
|
m_abstractor(m),
|
||||||
|
m_contains_p(*this),
|
||||||
|
m_check_pred(m_contains_p, m),
|
||||||
m_transf(*this),
|
m_transf(*this),
|
||||||
m_trail(*this),
|
m_trail(*this),
|
||||||
m_pinned(m),
|
m_pinned(m),
|
||||||
|
@ -301,18 +303,19 @@ namespace datalog {
|
||||||
expr_ref context::bind_variables(expr* fml, bool is_forall) {
|
expr_ref context::bind_variables(expr* fml, bool is_forall) {
|
||||||
expr_ref result(m);
|
expr_ref result(m);
|
||||||
app_ref_vector const & vars = m_vars;
|
app_ref_vector const & vars = m_vars;
|
||||||
|
rule_manager& rm = get_rule_manager();
|
||||||
if (vars.empty()) {
|
if (vars.empty()) {
|
||||||
result = fml;
|
result = fml;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ptr_vector<sort> sorts;
|
m_names.reset();
|
||||||
expr_abstract(m, 0, vars.size(), reinterpret_cast<expr*const*>(vars.c_ptr()), fml, result);
|
m_abstractor(0, vars.size(), reinterpret_cast<expr*const*>(vars.c_ptr()), fml, result);
|
||||||
get_free_vars(result, sorts);
|
rm.collect_vars(result);
|
||||||
|
ptr_vector<sort>& sorts = rm.get_var_sorts();
|
||||||
if (sorts.empty()) {
|
if (sorts.empty()) {
|
||||||
result = fml;
|
result = fml;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
svector<symbol> names;
|
|
||||||
for (unsigned i = 0; i < sorts.size(); ++i) {
|
for (unsigned i = 0; i < sorts.size(); ++i) {
|
||||||
if (!sorts[i]) {
|
if (!sorts[i]) {
|
||||||
if (i < vars.size()) {
|
if (i < vars.size()) {
|
||||||
|
@ -323,16 +326,16 @@ namespace datalog {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (i < vars.size()) {
|
if (i < vars.size()) {
|
||||||
names.push_back(vars[i]->get_decl()->get_name());
|
m_names.push_back(vars[i]->get_decl()->get_name());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
names.push_back(symbol(i));
|
m_names.push_back(symbol(i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
quantifier_ref q(m);
|
quantifier_ref q(m);
|
||||||
sorts.reverse();
|
sorts.reverse();
|
||||||
q = m.mk_quantifier(is_forall, sorts.size(), sorts.c_ptr(), names.c_ptr(), result);
|
q = m.mk_quantifier(is_forall, sorts.size(), sorts.c_ptr(), m_names.c_ptr(), result);
|
||||||
elim_unused_vars(m, q, result);
|
m_elim_unused_vars(q, result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
|
@ -544,6 +547,8 @@ namespace datalog {
|
||||||
throw default_exception("get_num_levels is not supported for bmc");
|
throw default_exception("get_num_levels is not supported for bmc");
|
||||||
case TAB_ENGINE:
|
case TAB_ENGINE:
|
||||||
throw default_exception("get_num_levels is not supported for tab");
|
throw default_exception("get_num_levels is not supported for tab");
|
||||||
|
case CLP_ENGINE:
|
||||||
|
throw default_exception("get_num_levels is not supported for clp");
|
||||||
default:
|
default:
|
||||||
throw default_exception("unknown engine");
|
throw default_exception("unknown engine");
|
||||||
}
|
}
|
||||||
|
@ -562,6 +567,8 @@ namespace datalog {
|
||||||
throw default_exception("operation is not supported for BMC engine");
|
throw default_exception("operation is not supported for BMC engine");
|
||||||
case TAB_ENGINE:
|
case TAB_ENGINE:
|
||||||
throw default_exception("operation is not supported for TAB engine");
|
throw default_exception("operation is not supported for TAB engine");
|
||||||
|
case CLP_ENGINE:
|
||||||
|
throw default_exception("operation is not supported for CLP engine");
|
||||||
default:
|
default:
|
||||||
throw default_exception("unknown engine");
|
throw default_exception("unknown engine");
|
||||||
}
|
}
|
||||||
|
@ -581,6 +588,8 @@ namespace datalog {
|
||||||
throw default_exception("operation is not supported for BMC engine");
|
throw default_exception("operation is not supported for BMC engine");
|
||||||
case TAB_ENGINE:
|
case TAB_ENGINE:
|
||||||
throw default_exception("operation is not supported for TAB engine");
|
throw default_exception("operation is not supported for TAB engine");
|
||||||
|
case CLP_ENGINE:
|
||||||
|
throw default_exception("operation is not supported for CLP engine");
|
||||||
default:
|
default:
|
||||||
throw default_exception("unknown engine");
|
throw default_exception("unknown engine");
|
||||||
}
|
}
|
||||||
|
@ -607,28 +616,16 @@ namespace datalog {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class context::contains_pred : public i_expr_pred {
|
|
||||||
context const& ctx;
|
|
||||||
public:
|
|
||||||
contains_pred(context& ctx): ctx(ctx) {}
|
|
||||||
virtual ~contains_pred() {}
|
|
||||||
|
|
||||||
virtual bool operator()(expr* e) {
|
|
||||||
return ctx.is_predicate(e);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
void context::check_existential_tail(rule_ref& r) {
|
void context::check_existential_tail(rule_ref& r) {
|
||||||
unsigned ut_size = r->get_uninterpreted_tail_size();
|
unsigned ut_size = r->get_uninterpreted_tail_size();
|
||||||
unsigned t_size = r->get_tail_size();
|
unsigned t_size = r->get_tail_size();
|
||||||
contains_pred contains_p(*this);
|
|
||||||
check_pred check_pred(contains_p, get_manager());
|
|
||||||
|
|
||||||
TRACE("dl", r->display_smt2(get_manager(), tout); tout << "\n";);
|
TRACE("dl", r->display_smt2(get_manager(), tout); tout << "\n";);
|
||||||
for (unsigned i = ut_size; i < t_size; ++i) {
|
for (unsigned i = ut_size; i < t_size; ++i) {
|
||||||
app* t = r->get_tail(i);
|
app* t = r->get_tail(i);
|
||||||
TRACE("dl", tout << "checking: " << mk_ismt2_pp(t, get_manager()) << "\n";);
|
TRACE("dl", tout << "checking: " << mk_ismt2_pp(t, get_manager()) << "\n";);
|
||||||
if (check_pred(t)) {
|
if (m_check_pred(t)) {
|
||||||
std::ostringstream out;
|
std::ostringstream out;
|
||||||
out << "interpreted body " << mk_ismt2_pp(t, get_manager()) << " contains recursive predicate";
|
out << "interpreted body " << mk_ismt2_pp(t, get_manager()) << " contains recursive predicate";
|
||||||
throw default_exception(out.str());
|
throw default_exception(out.str());
|
||||||
|
@ -720,6 +717,10 @@ namespace datalog {
|
||||||
check_existential_tail(r);
|
check_existential_tail(r);
|
||||||
check_positive_predicates(r);
|
check_positive_predicates(r);
|
||||||
break;
|
break;
|
||||||
|
case CLP_ENGINE:
|
||||||
|
check_existential_tail(r);
|
||||||
|
check_positive_predicates(r);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
break;
|
break;
|
||||||
|
@ -813,9 +814,8 @@ namespace datalog {
|
||||||
|
|
||||||
void context::transform_rules() {
|
void context::transform_rules() {
|
||||||
m_transf.reset();
|
m_transf.reset();
|
||||||
if (get_params().filter_rules()) {
|
m_transf.register_plugin(alloc(mk_coi_filter, *this));
|
||||||
m_transf.register_plugin(alloc(mk_filter_rules, *this));
|
m_transf.register_plugin(alloc(mk_filter_rules, *this));
|
||||||
}
|
|
||||||
m_transf.register_plugin(alloc(mk_simple_joins, *this));
|
m_transf.register_plugin(alloc(mk_simple_joins, *this));
|
||||||
if (unbound_compressor()) {
|
if (unbound_compressor()) {
|
||||||
m_transf.register_plugin(alloc(mk_unbound_compressor, *this));
|
m_transf.register_plugin(alloc(mk_unbound_compressor, *this));
|
||||||
|
@ -823,7 +823,14 @@ namespace datalog {
|
||||||
if (similarity_compressor()) {
|
if (similarity_compressor()) {
|
||||||
m_transf.register_plugin(alloc(mk_similarity_compressor, *this));
|
m_transf.register_plugin(alloc(mk_similarity_compressor, *this));
|
||||||
}
|
}
|
||||||
m_transf.register_plugin(alloc(datalog::mk_partial_equivalence_transformer, *this));
|
m_transf.register_plugin(alloc(mk_partial_equivalence_transformer, *this));
|
||||||
|
m_transf.register_plugin(alloc(mk_rule_inliner, *this));
|
||||||
|
m_transf.register_plugin(alloc(mk_interp_tail_simplifier, *this));
|
||||||
|
|
||||||
|
if (get_params().bit_blast()) {
|
||||||
|
m_transf.register_plugin(alloc(mk_bit_blast, *this, 22000));
|
||||||
|
m_transf.register_plugin(alloc(mk_interp_tail_simplifier, *this, 21000));
|
||||||
|
}
|
||||||
|
|
||||||
transform_rules(m_transf);
|
transform_rules(m_transf);
|
||||||
}
|
}
|
||||||
|
@ -988,6 +995,9 @@ namespace datalog {
|
||||||
else if (e == symbol("tab")) {
|
else if (e == symbol("tab")) {
|
||||||
m_engine = TAB_ENGINE;
|
m_engine = TAB_ENGINE;
|
||||||
}
|
}
|
||||||
|
else if (e == symbol("clp")) {
|
||||||
|
m_engine = CLP_ENGINE;
|
||||||
|
}
|
||||||
|
|
||||||
if (m_engine == LAST_ENGINE) {
|
if (m_engine == LAST_ENGINE) {
|
||||||
expr_fast_mark1 mark;
|
expr_fast_mark1 mark;
|
||||||
|
@ -1023,6 +1033,8 @@ namespace datalog {
|
||||||
return bmc_query(query);
|
return bmc_query(query);
|
||||||
case TAB_ENGINE:
|
case TAB_ENGINE:
|
||||||
return tab_query(query);
|
return tab_query(query);
|
||||||
|
case CLP_ENGINE:
|
||||||
|
return clp_query(query);
|
||||||
default:
|
default:
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
return rel_query(query);
|
return rel_query(query);
|
||||||
|
@ -1087,11 +1099,22 @@ namespace datalog {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void context::ensure_clp() {
|
||||||
|
if (!m_clp.get()) {
|
||||||
|
m_clp = alloc(clp, *this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
lbool context::tab_query(expr* query) {
|
lbool context::tab_query(expr* query) {
|
||||||
ensure_tab();
|
ensure_tab();
|
||||||
return m_tab->query(query);
|
return m_tab->query(query);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lbool context::clp_query(expr* query) {
|
||||||
|
ensure_clp();
|
||||||
|
return m_clp->query(query);
|
||||||
|
}
|
||||||
|
|
||||||
void context::ensure_rel() {
|
void context::ensure_rel() {
|
||||||
if (!m_rel.get()) {
|
if (!m_rel.get()) {
|
||||||
m_rel = alloc(rel_context, *this);
|
m_rel = alloc(rel_context, *this);
|
||||||
|
@ -1132,6 +1155,10 @@ namespace datalog {
|
||||||
ensure_tab();
|
ensure_tab();
|
||||||
m_last_answer = m_tab->get_answer();
|
m_last_answer = m_tab->get_answer();
|
||||||
return m_last_answer.get();
|
return m_last_answer.get();
|
||||||
|
case CLP_ENGINE:
|
||||||
|
ensure_clp();
|
||||||
|
m_last_answer = m_clp->get_answer();
|
||||||
|
return m_last_answer.get();
|
||||||
default:
|
default:
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
}
|
}
|
||||||
|
@ -1157,6 +1184,10 @@ namespace datalog {
|
||||||
ensure_tab();
|
ensure_tab();
|
||||||
m_tab->display_certificate(out);
|
m_tab->display_certificate(out);
|
||||||
return true;
|
return true;
|
||||||
|
case CLP_ENGINE:
|
||||||
|
ensure_clp();
|
||||||
|
m_clp->display_certificate(out);
|
||||||
|
return true;
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,6 +45,9 @@ Revision History:
|
||||||
#include"model2expr.h"
|
#include"model2expr.h"
|
||||||
#include"smt_params.h"
|
#include"smt_params.h"
|
||||||
#include"dl_rule_transformer.h"
|
#include"dl_rule_transformer.h"
|
||||||
|
#include"expr_abstract.h"
|
||||||
|
#include"expr_functors.h"
|
||||||
|
#include"clp_context.h"
|
||||||
|
|
||||||
namespace datalog {
|
namespace datalog {
|
||||||
|
|
||||||
|
@ -76,6 +79,18 @@ namespace datalog {
|
||||||
typedef obj_map<const func_decl, svector<symbol> > pred2syms;
|
typedef obj_map<const func_decl, svector<symbol> > pred2syms;
|
||||||
typedef obj_map<const sort, sort_domain*> sort_domain_map;
|
typedef obj_map<const sort, sort_domain*> sort_domain_map;
|
||||||
|
|
||||||
|
class contains_pred : public i_expr_pred {
|
||||||
|
context const& ctx;
|
||||||
|
public:
|
||||||
|
contains_pred(context& ctx): ctx(ctx) {}
|
||||||
|
virtual ~contains_pred() {}
|
||||||
|
|
||||||
|
virtual bool operator()(expr* e) {
|
||||||
|
return ctx.is_predicate(e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
ast_manager & m;
|
ast_manager & m;
|
||||||
smt_params & m_fparams;
|
smt_params & m_fparams;
|
||||||
params_ref m_params_ref;
|
params_ref m_params_ref;
|
||||||
|
@ -84,10 +99,15 @@ namespace datalog {
|
||||||
th_rewriter m_rewriter;
|
th_rewriter m_rewriter;
|
||||||
var_subst m_var_subst;
|
var_subst m_var_subst;
|
||||||
rule_manager m_rule_manager;
|
rule_manager m_rule_manager;
|
||||||
|
unused_vars_eliminator m_elim_unused_vars;
|
||||||
|
expr_abstractor m_abstractor;
|
||||||
|
contains_pred m_contains_p;
|
||||||
|
check_pred m_check_pred;
|
||||||
rule_transformer m_transf;
|
rule_transformer m_transf;
|
||||||
trail_stack<context> m_trail;
|
trail_stack<context> m_trail;
|
||||||
ast_ref_vector m_pinned;
|
ast_ref_vector m_pinned;
|
||||||
app_ref_vector m_vars;
|
app_ref_vector m_vars;
|
||||||
|
svector<symbol> m_names;
|
||||||
sort_domain_map m_sorts;
|
sort_domain_map m_sorts;
|
||||||
func_decl_set m_preds;
|
func_decl_set m_preds;
|
||||||
sym2decl m_preds_by_name;
|
sym2decl m_preds_by_name;
|
||||||
|
@ -104,6 +124,7 @@ namespace datalog {
|
||||||
scoped_ptr<bmc> m_bmc;
|
scoped_ptr<bmc> m_bmc;
|
||||||
scoped_ptr<rel_context> m_rel;
|
scoped_ptr<rel_context> m_rel;
|
||||||
scoped_ptr<tab> m_tab;
|
scoped_ptr<tab> m_tab;
|
||||||
|
scoped_ptr<clp> m_clp;
|
||||||
|
|
||||||
bool m_closed;
|
bool m_closed;
|
||||||
bool m_saturation_was_run;
|
bool m_saturation_was_run;
|
||||||
|
@ -457,6 +478,8 @@ namespace datalog {
|
||||||
|
|
||||||
void ensure_tab();
|
void ensure_tab();
|
||||||
|
|
||||||
|
void ensure_clp();
|
||||||
|
|
||||||
void ensure_rel();
|
void ensure_rel();
|
||||||
|
|
||||||
void new_query();
|
void new_query();
|
||||||
|
@ -469,6 +492,8 @@ namespace datalog {
|
||||||
|
|
||||||
lbool tab_query(expr* query);
|
lbool tab_query(expr* query);
|
||||||
|
|
||||||
|
lbool clp_query(expr* query);
|
||||||
|
|
||||||
void check_quantifier_free(rule_ref& r);
|
void check_quantifier_free(rule_ref& r);
|
||||||
void check_uninterpreted_free(rule_ref& r);
|
void check_uninterpreted_free(rule_ref& r);
|
||||||
void check_existential_tail(rule_ref& r);
|
void check_existential_tail(rule_ref& r);
|
||||||
|
|
|
@ -1291,8 +1291,8 @@ namespace datalog {
|
||||||
m_renaming_for_inner_rel(m_manager) {
|
m_renaming_for_inner_rel(m_manager) {
|
||||||
relation_manager & rmgr = r.get_manager();
|
relation_manager & rmgr = r.get_manager();
|
||||||
|
|
||||||
idx_set cond_columns;
|
rule_manager& rm = r.get_context().get_rule_manager();
|
||||||
collect_vars(m_manager, m_cond, cond_columns);
|
idx_set& cond_columns = rm.collect_vars(m_cond);
|
||||||
|
|
||||||
unsigned sig_sz = r.get_signature().size();
|
unsigned sig_sz = r.get_signature().size();
|
||||||
for(unsigned i=0; i<sig_sz; i++) {
|
for(unsigned i=0; i<sig_sz; i++) {
|
||||||
|
|
|
@ -47,7 +47,7 @@ namespace datalog {
|
||||||
}
|
}
|
||||||
struct hash {
|
struct hash {
|
||||||
unsigned operator()(const rel_spec & o) const {
|
unsigned operator()(const rel_spec & o) const {
|
||||||
return o.m_inner_kind^int_vector_hash(o.m_table_cols);
|
return o.m_inner_kind^svector_hash<bool_hash>()(o.m_table_cols);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -359,21 +359,7 @@ namespace datalog {
|
||||||
r2.get_signature().output(ctx.get_rel_context().get_manager(), tout);
|
r2.get_signature().output(ctx.get_rel_context().get_manager(), tout);
|
||||||
tout<<":"<<r2.get_size_estimate_rows()<<" ->\n";);
|
tout<<":"<<r2.get_size_estimate_rows()<<" ->\n";);
|
||||||
|
|
||||||
try {
|
ctx.set_reg(m_res, (*fn)(r1, r2));
|
||||||
ctx.set_reg(m_res, (*fn)(r1, r2));
|
|
||||||
}
|
|
||||||
catch(...)
|
|
||||||
{
|
|
||||||
std::string annotation;
|
|
||||||
unsigned sz;
|
|
||||||
ctx.get_register_annotation(m_rel1, annotation);
|
|
||||||
sz = ctx.reg(m_rel1)?ctx.reg(m_rel1)->get_size_estimate_rows():0;
|
|
||||||
std::cout << m_rel1 << "\t" << sz << "\t" << annotation << "\n";
|
|
||||||
ctx.get_register_annotation(m_rel2, annotation);
|
|
||||||
sz = ctx.reg(m_rel2)?ctx.reg(m_rel2)->get_size_estimate_rows():0;
|
|
||||||
std::cout << m_rel2 << "\t" << sz << "\t" << annotation << "\n";
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
|
|
||||||
TRACE("dl",
|
TRACE("dl",
|
||||||
ctx.reg(m_res)->get_signature().output(ctx.get_rel_context().get_manager(), tout);
|
ctx.reg(m_res)->get_signature().output(ctx.get_rel_context().get_manager(), tout);
|
||||||
|
|
|
@ -145,7 +145,6 @@ namespace datalog {
|
||||||
expr_ref_vector conjs(m), new_conjs(m);
|
expr_ref_vector conjs(m), new_conjs(m);
|
||||||
expr_ref tmp(m);
|
expr_ref tmp(m);
|
||||||
expr_safe_replace sub(m);
|
expr_safe_replace sub(m);
|
||||||
uint_set lhs_vars, rhs_vars;
|
|
||||||
bool change = false;
|
bool change = false;
|
||||||
bool inserted = false;
|
bool inserted = false;
|
||||||
|
|
||||||
|
@ -161,10 +160,8 @@ namespace datalog {
|
||||||
|
|
||||||
if (is_store_def(e, x, y)) {
|
if (is_store_def(e, x, y)) {
|
||||||
// enforce topological order consistency:
|
// enforce topological order consistency:
|
||||||
uint_set lhs;
|
uint_set lhs = rm.collect_vars(x);
|
||||||
collect_vars(m, x, lhs_vars);
|
uint_set rhs_vars = rm.collect_vars(y);
|
||||||
collect_vars(m, y, rhs_vars);
|
|
||||||
lhs = lhs_vars;
|
|
||||||
lhs &= rhs_vars;
|
lhs &= rhs_vars;
|
||||||
if (!lhs.empty()) {
|
if (!lhs.empty()) {
|
||||||
TRACE("dl", tout << "unusable equality " << mk_pp(e, m) << "\n";);
|
TRACE("dl", tout << "unusable equality " << mk_pp(e, m) << "\n";);
|
||||||
|
|
78
src/muz_qe/dl_mk_backwards.cpp
Normal file
78
src/muz_qe/dl_mk_backwards.cpp
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
/*++
|
||||||
|
Copyright (c) 2013 Microsoft Corporation
|
||||||
|
|
||||||
|
Module Name:
|
||||||
|
|
||||||
|
dl_mk_backwards.cpp
|
||||||
|
|
||||||
|
Abstract:
|
||||||
|
|
||||||
|
Create Horn clauses for backwards flow.
|
||||||
|
|
||||||
|
Author:
|
||||||
|
|
||||||
|
Nikolaj Bjorner (nbjorner) 2013-04-17
|
||||||
|
|
||||||
|
Revision History:
|
||||||
|
|
||||||
|
--*/
|
||||||
|
|
||||||
|
#include"dl_mk_backwards.h"
|
||||||
|
#include"dl_context.h"
|
||||||
|
|
||||||
|
namespace datalog {
|
||||||
|
|
||||||
|
mk_backwards::mk_backwards(context & ctx, unsigned priority):
|
||||||
|
plugin(priority),
|
||||||
|
m(ctx.get_manager()),
|
||||||
|
m_ctx(ctx) {
|
||||||
|
}
|
||||||
|
|
||||||
|
mk_backwards::~mk_backwards() { }
|
||||||
|
|
||||||
|
rule_set * mk_backwards::operator()(rule_set const & source) {
|
||||||
|
context& ctx = source.get_context();
|
||||||
|
rule_manager& rm = source.get_rule_manager();
|
||||||
|
rule_set * result = alloc(rule_set, ctx);
|
||||||
|
unsigned sz = source.get_num_rules();
|
||||||
|
rule_ref new_rule(rm);
|
||||||
|
app_ref_vector tail(m);
|
||||||
|
app_ref head(m);
|
||||||
|
svector<bool> neg;
|
||||||
|
app_ref query(m);
|
||||||
|
query = m.mk_fresh_const("Q", m.mk_bool_sort());
|
||||||
|
result->set_output_predicate(query->get_decl());
|
||||||
|
m_ctx.register_predicate(query->get_decl(), false);
|
||||||
|
for (unsigned i = 0; i < sz; ++i) {
|
||||||
|
tail.reset();
|
||||||
|
neg.reset();
|
||||||
|
rule & r = *source.get_rule(i);
|
||||||
|
unsigned utsz = r.get_uninterpreted_tail_size();
|
||||||
|
unsigned tsz = r.get_tail_size();
|
||||||
|
if (!source.is_output_predicate(r.get_decl())) {
|
||||||
|
tail.push_back(r.get_head());
|
||||||
|
neg.push_back(false);
|
||||||
|
}
|
||||||
|
for (unsigned j = utsz; j < tsz; ++j) {
|
||||||
|
tail.push_back(r.get_tail(j));
|
||||||
|
neg.push_back(false);
|
||||||
|
}
|
||||||
|
for (unsigned j = 0; j <= utsz; ++j) {
|
||||||
|
if (j == utsz && j > 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (j == utsz) {
|
||||||
|
head = query;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
head = r.get_tail(j);
|
||||||
|
}
|
||||||
|
new_rule = rm.mk(head, tail.size(), tail.c_ptr(), neg.c_ptr(), r.name(), true);
|
||||||
|
result->add_rule(new_rule);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TRACE("dl", result->display(tout););
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
38
src/muz_qe/dl_mk_backwards.h
Normal file
38
src/muz_qe/dl_mk_backwards.h
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
/*++
|
||||||
|
Copyright (c) 2013 Microsoft Corporation
|
||||||
|
|
||||||
|
Module Name:
|
||||||
|
|
||||||
|
dl_mk_backwards.h
|
||||||
|
|
||||||
|
Abstract:
|
||||||
|
|
||||||
|
Create Horn clauses for backwards flow.
|
||||||
|
|
||||||
|
Author:
|
||||||
|
|
||||||
|
Nikolaj Bjorner (nbjorner) 2013-04-17
|
||||||
|
|
||||||
|
Revision History:
|
||||||
|
|
||||||
|
--*/
|
||||||
|
#ifndef _DL_MK_BACKWARDS_H_
|
||||||
|
#define _DL_MK_BACKWARDS_H_
|
||||||
|
|
||||||
|
#include"dl_rule_transformer.h"
|
||||||
|
|
||||||
|
namespace datalog {
|
||||||
|
|
||||||
|
class mk_backwards : public rule_transformer::plugin {
|
||||||
|
ast_manager& m;
|
||||||
|
context& m_ctx;
|
||||||
|
public:
|
||||||
|
mk_backwards(context & ctx, unsigned priority = 33000);
|
||||||
|
~mk_backwards();
|
||||||
|
rule_set * operator()(rule_set const & source);
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* _DL_MK_BACKWARDS_H_ */
|
||||||
|
|
|
@ -27,9 +27,10 @@ namespace datalog {
|
||||||
mk_filter_rules::mk_filter_rules(context & ctx):
|
mk_filter_rules::mk_filter_rules(context & ctx):
|
||||||
plugin(2000),
|
plugin(2000),
|
||||||
m_context(ctx),
|
m_context(ctx),
|
||||||
m_manager(ctx.get_manager()),
|
m(ctx.get_manager()),
|
||||||
|
rm(ctx.get_rule_manager()),
|
||||||
m_result(0),
|
m_result(0),
|
||||||
m_pinned(m_manager) {
|
m_pinned(m) {
|
||||||
}
|
}
|
||||||
|
|
||||||
mk_filter_rules::~mk_filter_rules() {
|
mk_filter_rules::~mk_filter_rules() {
|
||||||
|
@ -52,14 +53,14 @@ namespace datalog {
|
||||||
*/
|
*/
|
||||||
bool mk_filter_rules::is_candidate(app * pred) {
|
bool mk_filter_rules::is_candidate(app * pred) {
|
||||||
if (!m_context.is_predicate(pred)) {
|
if (!m_context.is_predicate(pred)) {
|
||||||
TRACE("mk_filter_rules", tout << mk_pp(pred, m_manager) << "\nis not a candidate because it is interpreted.\n";);
|
TRACE("mk_filter_rules", tout << mk_pp(pred, m) << "\nis not a candidate because it is interpreted.\n";);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
var_idx_set used_vars;
|
var_idx_set used_vars;
|
||||||
unsigned n = pred->get_num_args();
|
unsigned n = pred->get_num_args();
|
||||||
for (unsigned i = 0; i < n; i++) {
|
for (unsigned i = 0; i < n; i++) {
|
||||||
expr * arg = pred->get_arg(i);
|
expr * arg = pred->get_arg(i);
|
||||||
if (m_manager.is_value(arg))
|
if (m.is_value(arg))
|
||||||
return true;
|
return true;
|
||||||
SASSERT(is_var(arg));
|
SASSERT(is_var(arg));
|
||||||
unsigned vidx = to_var(arg)->get_idx();
|
unsigned vidx = to_var(arg)->get_idx();
|
||||||
|
@ -74,10 +75,10 @@ namespace datalog {
|
||||||
\brief Create a "filter" (if it doesn't exist already) for the given predicate.
|
\brief Create a "filter" (if it doesn't exist already) for the given predicate.
|
||||||
*/
|
*/
|
||||||
func_decl * mk_filter_rules::mk_filter_decl(app * pred, var_idx_set const & non_local_vars) {
|
func_decl * mk_filter_rules::mk_filter_decl(app * pred, var_idx_set const & non_local_vars) {
|
||||||
sort_ref_buffer filter_domain(m_manager);
|
sort_ref_buffer filter_domain(m);
|
||||||
|
|
||||||
filter_key * key = alloc(filter_key, m_manager);
|
filter_key * key = alloc(filter_key, m);
|
||||||
mk_new_rule_tail(m_manager, pred, non_local_vars, filter_domain, key->filter_args, key->new_pred);
|
mk_new_rule_tail(m, pred, non_local_vars, filter_domain, key->filter_args, key->new_pred);
|
||||||
func_decl * filter_decl = 0;
|
func_decl * filter_decl = 0;
|
||||||
if (!m_tail2filter.find(key, filter_decl)) {
|
if (!m_tail2filter.find(key, filter_decl)) {
|
||||||
filter_decl = m_context.mk_fresh_head_predicate(pred->get_decl()->get_name(), symbol("filter"),
|
filter_decl = m_context.mk_fresh_head_predicate(pred->get_decl()->get_name(), symbol("filter"),
|
||||||
|
@ -85,8 +86,8 @@ namespace datalog {
|
||||||
|
|
||||||
m_pinned.push_back(filter_decl);
|
m_pinned.push_back(filter_decl);
|
||||||
m_tail2filter.insert(key, filter_decl);
|
m_tail2filter.insert(key, filter_decl);
|
||||||
app_ref filter_head(m_manager);
|
app_ref filter_head(m);
|
||||||
filter_head = m_manager.mk_app(filter_decl, key->filter_args.size(), key->filter_args.c_ptr());
|
filter_head = m.mk_app(filter_decl, key->filter_args.size(), key->filter_args.c_ptr());
|
||||||
app * filter_tail = key->new_pred;
|
app * filter_tail = key->new_pred;
|
||||||
rule * filter_rule = m_context.get_rule_manager().mk(filter_head, 1, &filter_tail, (const bool *)0);
|
rule * filter_rule = m_context.get_rule_manager().mk(filter_head, 1, &filter_tail, (const bool *)0);
|
||||||
filter_rule->set_accounting_parent_object(m_context, m_current);
|
filter_rule->set_accounting_parent_object(m_context, m_current);
|
||||||
|
@ -104,16 +105,15 @@ namespace datalog {
|
||||||
void mk_filter_rules::process(rule * r) {
|
void mk_filter_rules::process(rule * r) {
|
||||||
m_current = r;
|
m_current = r;
|
||||||
app * new_head = r->get_head();
|
app * new_head = r->get_head();
|
||||||
app_ref_vector new_tail(m_manager);
|
app_ref_vector new_tail(m);
|
||||||
svector<bool> new_is_negated;
|
svector<bool> new_is_negated;
|
||||||
unsigned sz = r->get_tail_size();
|
unsigned sz = r->get_tail_size();
|
||||||
bool rule_modified = false;
|
bool rule_modified = false;
|
||||||
for (unsigned i = 0; i < sz; i++) {
|
for (unsigned i = 0; i < sz; i++) {
|
||||||
app * tail = r->get_tail(i);
|
app * tail = r->get_tail(i);
|
||||||
if (is_candidate(tail)) {
|
if (is_candidate(tail)) {
|
||||||
TRACE("mk_filter_rules", tout << "is_candidate: " << mk_pp(tail, m_manager) << "\n";);
|
TRACE("mk_filter_rules", tout << "is_candidate: " << mk_pp(tail, m) << "\n";);
|
||||||
var_idx_set non_local_vars;
|
var_idx_set non_local_vars = rm.collect_rule_vars_ex(r, tail);
|
||||||
collect_non_local_vars(m_manager, r, tail, non_local_vars);
|
|
||||||
func_decl * filter_decl = mk_filter_decl(tail, non_local_vars);
|
func_decl * filter_decl = mk_filter_decl(tail, non_local_vars);
|
||||||
ptr_buffer<expr> new_args;
|
ptr_buffer<expr> new_args;
|
||||||
var_idx_set used_vars;
|
var_idx_set used_vars;
|
||||||
|
@ -129,7 +129,7 @@ namespace datalog {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SASSERT(new_args.size() == filter_decl->get_arity());
|
SASSERT(new_args.size() == filter_decl->get_arity());
|
||||||
new_tail.push_back(m_manager.mk_app(filter_decl, new_args.size(), new_args.c_ptr()));
|
new_tail.push_back(m.mk_app(filter_decl, new_args.size(), new_args.c_ptr()));
|
||||||
rule_modified = true;
|
rule_modified = true;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -152,9 +152,6 @@ namespace datalog {
|
||||||
}
|
}
|
||||||
|
|
||||||
rule_set * mk_filter_rules::operator()(rule_set const & source) {
|
rule_set * mk_filter_rules::operator()(rule_set const & source) {
|
||||||
if (!m_context.get_params().filter_rules()) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
m_tail2filter.reset();
|
m_tail2filter.reset();
|
||||||
m_result = alloc(rule_set, m_context);
|
m_result = alloc(rule_set, m_context);
|
||||||
m_modified = false;
|
m_modified = false;
|
||||||
|
|
|
@ -45,17 +45,22 @@ namespace datalog {
|
||||||
filter_key(ast_manager & m) : new_pred(m), filter_args(m) {}
|
filter_key(ast_manager & m) : new_pred(m), filter_args(m) {}
|
||||||
|
|
||||||
unsigned hash() const {
|
unsigned hash() const {
|
||||||
return new_pred->hash() ^ int_vector_hash(filter_args);
|
unsigned r = new_pred->hash();
|
||||||
|
for (unsigned i = 0; i < filter_args.size(); ++i) {
|
||||||
|
r ^= filter_args[i]->hash();
|
||||||
|
}
|
||||||
|
return r;
|
||||||
}
|
}
|
||||||
bool operator==(const filter_key & o) const {
|
bool operator==(const filter_key & o) const {
|
||||||
return o.new_pred==new_pred && vectors_equal(o.filter_args, filter_args);
|
return o.new_pred==new_pred && vectors_equal(o.filter_args, filter_args);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef map<filter_key*, func_decl*, obj_ptr_hash<filter_key>, deref_eq<filter_key> > filter_cache;
|
typedef obj_map<filter_key, func_decl*> filter_cache;
|
||||||
|
|
||||||
context & m_context;
|
context & m_context;
|
||||||
ast_manager & m_manager;
|
ast_manager & m;
|
||||||
|
rule_manager & rm;
|
||||||
filter_cache m_tail2filter;
|
filter_cache m_tail2filter;
|
||||||
rule_set * m_result;
|
rule_set * m_result;
|
||||||
rule * m_current;
|
rule * m_current;
|
||||||
|
|
|
@ -67,24 +67,23 @@ namespace datalog {
|
||||||
void mk_interp_tail_simplifier::rule_substitution::get_result(rule_ref & res) {
|
void mk_interp_tail_simplifier::rule_substitution::get_result(rule_ref & res) {
|
||||||
SASSERT(m_rule);
|
SASSERT(m_rule);
|
||||||
|
|
||||||
app_ref new_head(m);
|
apply(m_rule->get_head(), m_head);
|
||||||
apply(m_rule->get_head(), new_head);
|
|
||||||
|
|
||||||
app_ref_vector tail(m);
|
m_tail.reset();
|
||||||
svector<bool> tail_neg;
|
m_neg.reset();
|
||||||
|
|
||||||
unsigned tail_len = m_rule->get_tail_size();
|
unsigned tail_len = m_rule->get_tail_size();
|
||||||
for (unsigned i=0; i<tail_len; i++) {
|
for (unsigned i=0; i<tail_len; i++) {
|
||||||
app_ref new_tail_el(m);
|
app_ref new_tail_el(m);
|
||||||
apply(m_rule->get_tail(i), new_tail_el);
|
apply(m_rule->get_tail(i), new_tail_el);
|
||||||
tail.push_back(new_tail_el);
|
m_tail.push_back(new_tail_el);
|
||||||
tail_neg.push_back(m_rule->is_neg_tail(i));
|
m_neg.push_back(m_rule->is_neg_tail(i));
|
||||||
}
|
}
|
||||||
|
|
||||||
mk_rule_inliner::remove_duplicate_tails(tail, tail_neg);
|
mk_rule_inliner::remove_duplicate_tails(m_tail, m_neg);
|
||||||
|
|
||||||
SASSERT(tail.size() == tail_neg.size());
|
SASSERT(m_tail.size() == m_neg.size());
|
||||||
res = m_context.get_rule_manager().mk(new_head, tail.size(), tail.c_ptr(), tail_neg.c_ptr());
|
res = m_context.get_rule_manager().mk(m_head, m_tail.size(), m_tail.c_ptr(), m_neg.c_ptr());
|
||||||
res->set_accounting_parent_object(m_context, m_rule);
|
res->set_accounting_parent_object(m_context, m_rule);
|
||||||
res->norm_vars(res.get_manager());
|
res->norm_vars(res.get_manager());
|
||||||
}
|
}
|
||||||
|
@ -362,14 +361,37 @@ namespace datalog {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class mk_interp_tail_simplifier::normalizer_rw : public rewriter_tpl<normalizer_cfg> {
|
||||||
|
public:
|
||||||
|
normalizer_rw(ast_manager& m, normalizer_cfg& cfg): rewriter_tpl<normalizer_cfg>(m, false, cfg) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
mk_interp_tail_simplifier::mk_interp_tail_simplifier(context & ctx, unsigned priority)
|
||||||
|
: plugin(priority),
|
||||||
|
m(ctx.get_manager()),
|
||||||
|
m_context(ctx),
|
||||||
|
m_simp(ctx.get_rewriter()),
|
||||||
|
a(m),
|
||||||
|
m_rule_subst(ctx),
|
||||||
|
m_tail(m),
|
||||||
|
m_itail_members(m),
|
||||||
|
m_conj(m) {
|
||||||
|
m_cfg = alloc(normalizer_cfg, m);
|
||||||
|
m_rw = alloc(normalizer_rw, m, *m_cfg);
|
||||||
|
}
|
||||||
|
|
||||||
|
mk_interp_tail_simplifier::~mk_interp_tail_simplifier() {
|
||||||
|
dealloc(m_rw);
|
||||||
|
dealloc(m_cfg);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void mk_interp_tail_simplifier::simplify_expr(app * a, expr_ref& res)
|
void mk_interp_tail_simplifier::simplify_expr(app * a, expr_ref& res)
|
||||||
{
|
{
|
||||||
expr_ref simp1_res(m);
|
expr_ref simp1_res(m);
|
||||||
m_simp(a, simp1_res);
|
m_simp(a, simp1_res);
|
||||||
normalizer_cfg r_cfg(m);
|
(*m_rw)(simp1_res.get(), res);
|
||||||
rewriter_tpl<normalizer_cfg> rwr(m, false, r_cfg);
|
|
||||||
expr_ref dl_form_e(m);
|
|
||||||
rwr(simp1_res.get(), res);
|
|
||||||
|
|
||||||
/*if (simp1_res.get()!=res.get()) {
|
/*if (simp1_res.get()!=res.get()) {
|
||||||
std::cout<<"pre norm:\n"<<mk_pp(simp1_res.get(),m)<<"post norm:\n"<<mk_pp(res.get(),m)<<"\n";
|
std::cout<<"pre norm:\n"<<mk_pp(simp1_res.get(),m)<<"post norm:\n"<<mk_pp(res.get(),m)<<"\n";
|
||||||
|
@ -385,15 +407,15 @@ namespace datalog {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ptr_vector<expr> todo;
|
m_todo.reset();
|
||||||
|
m_leqs.reset();
|
||||||
for (unsigned i = u_len; i < len; i++) {
|
for (unsigned i = u_len; i < len; i++) {
|
||||||
todo.push_back(r->get_tail(i));
|
m_todo.push_back(r->get_tail(i));
|
||||||
SASSERT(!r->is_neg_tail(i));
|
SASSERT(!r->is_neg_tail(i));
|
||||||
}
|
}
|
||||||
|
|
||||||
m_rule_subst.reset(r);
|
m_rule_subst.reset(r);
|
||||||
|
|
||||||
obj_hashtable<expr> leqs;
|
|
||||||
expr_ref_vector trail(m);
|
expr_ref_vector trail(m);
|
||||||
expr_ref tmp1(m), tmp2(m);
|
expr_ref tmp1(m), tmp2(m);
|
||||||
bool found_something = false;
|
bool found_something = false;
|
||||||
|
@ -401,10 +423,10 @@ namespace datalog {
|
||||||
#define TRY_UNIFY(_x,_y) if (m_rule_subst.unify(_x,_y)) { found_something = true; }
|
#define TRY_UNIFY(_x,_y) if (m_rule_subst.unify(_x,_y)) { found_something = true; }
|
||||||
#define IS_FLEX(_x) (is_var(_x) || m.is_value(_x))
|
#define IS_FLEX(_x) (is_var(_x) || m.is_value(_x))
|
||||||
|
|
||||||
while (!todo.empty()) {
|
while (!m_todo.empty()) {
|
||||||
expr * arg1, *arg2;
|
expr * arg1, *arg2;
|
||||||
expr * t0 = todo.back();
|
expr * t0 = m_todo.back();
|
||||||
todo.pop_back();
|
m_todo.pop_back();
|
||||||
expr* t = t0;
|
expr* t = t0;
|
||||||
bool neg = m.is_not(t, t);
|
bool neg = m.is_not(t, t);
|
||||||
if (is_var(t)) {
|
if (is_var(t)) {
|
||||||
|
@ -412,7 +434,7 @@ namespace datalog {
|
||||||
}
|
}
|
||||||
else if (!neg && m.is_and(t)) {
|
else if (!neg && m.is_and(t)) {
|
||||||
app* a = to_app(t);
|
app* a = to_app(t);
|
||||||
todo.append(a->get_num_args(), a->get_args());
|
m_todo.append(a->get_num_args(), a->get_args());
|
||||||
}
|
}
|
||||||
else if (!neg && m.is_eq(t, arg1, arg2) && IS_FLEX(arg1) && IS_FLEX(arg2)) {
|
else if (!neg && m.is_eq(t, arg1, arg2) && IS_FLEX(arg1) && IS_FLEX(arg2)) {
|
||||||
TRY_UNIFY(arg1, arg2);
|
TRY_UNIFY(arg1, arg2);
|
||||||
|
@ -440,12 +462,12 @@ namespace datalog {
|
||||||
else if (!neg && (a.is_le(t, arg1, arg2) || a.is_ge(t, arg2, arg1))) {
|
else if (!neg && (a.is_le(t, arg1, arg2) || a.is_ge(t, arg2, arg1))) {
|
||||||
tmp1 = a.mk_sub(arg1, arg2);
|
tmp1 = a.mk_sub(arg1, arg2);
|
||||||
tmp2 = a.mk_sub(arg2, arg1);
|
tmp2 = a.mk_sub(arg2, arg1);
|
||||||
if (false && leqs.contains(tmp2) && IS_FLEX(arg1) && IS_FLEX(arg2)) {
|
if (false && m_leqs.contains(tmp2) && IS_FLEX(arg1) && IS_FLEX(arg2)) {
|
||||||
TRY_UNIFY(arg1, arg2);
|
TRY_UNIFY(arg1, arg2);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
trail.push_back(tmp1);
|
trail.push_back(tmp1);
|
||||||
leqs.insert(tmp1);
|
m_leqs.insert(tmp1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -485,12 +507,12 @@ namespace datalog {
|
||||||
}
|
}
|
||||||
app_ref head(r->get_head(), m);
|
app_ref head(r->get_head(), m);
|
||||||
|
|
||||||
app_ref_vector tail(m);
|
m_tail.reset();
|
||||||
svector<bool> tail_neg;
|
m_tail_neg.reset();
|
||||||
|
|
||||||
for (unsigned i=0; i<u_len; i++) {
|
for (unsigned i=0; i<u_len; i++) {
|
||||||
tail.push_back(r->get_tail(i));
|
m_tail.push_back(r->get_tail(i));
|
||||||
tail_neg.push_back(r->is_neg_tail(i));
|
m_tail_neg.push_back(r->is_neg_tail(i));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool modified = false;
|
bool modified = false;
|
||||||
|
@ -502,12 +524,12 @@ namespace datalog {
|
||||||
SASSERT(!r->is_neg_tail(u_len));
|
SASSERT(!r->is_neg_tail(u_len));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
expr_ref_vector itail_members(m);
|
m_itail_members.reset();
|
||||||
for (unsigned i=u_len; i<len; i++) {
|
for (unsigned i=u_len; i<len; i++) {
|
||||||
itail_members.push_back(r->get_tail(i));
|
m_itail_members.push_back(r->get_tail(i));
|
||||||
SASSERT(!r->is_neg_tail(i));
|
SASSERT(!r->is_neg_tail(i));
|
||||||
}
|
}
|
||||||
itail = m.mk_and(itail_members.size(), itail_members.c_ptr());
|
itail = m.mk_and(m_itail_members.size(), m_itail_members.c_ptr());
|
||||||
modified = true;
|
modified = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -523,21 +545,21 @@ namespace datalog {
|
||||||
SASSERT(m.is_bool(simp_res));
|
SASSERT(m.is_bool(simp_res));
|
||||||
|
|
||||||
if (modified) {
|
if (modified) {
|
||||||
expr_ref_vector conjs(m);
|
m_conj.reset();
|
||||||
flatten_and(simp_res, conjs);
|
flatten_and(simp_res, m_conj);
|
||||||
for (unsigned i = 0; i < conjs.size(); ++i) {
|
for (unsigned i = 0; i < m_conj.size(); ++i) {
|
||||||
expr* e = conjs[i].get();
|
expr* e = m_conj[i].get();
|
||||||
if (is_app(e)) {
|
if (is_app(e)) {
|
||||||
tail.push_back(to_app(e));
|
m_tail.push_back(to_app(e));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
tail.push_back(m.mk_eq(e, m.mk_true()));
|
m_tail.push_back(m.mk_eq(e, m.mk_true()));
|
||||||
}
|
}
|
||||||
tail_neg.push_back(false);
|
m_tail_neg.push_back(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
SASSERT(tail.size() == tail_neg.size());
|
SASSERT(m_tail.size() == m_tail_neg.size());
|
||||||
res = m_context.get_rule_manager().mk(head, tail.size(), tail.c_ptr(), tail_neg.c_ptr());
|
res = m_context.get_rule_manager().mk(head, m_tail.size(), m_tail.c_ptr(), m_tail_neg.c_ptr());
|
||||||
res->set_accounting_parent_object(m_context, r);
|
res->set_accounting_parent_object(m_context, r);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
|
@ -34,15 +34,17 @@ namespace datalog {
|
||||||
{
|
{
|
||||||
ast_manager& m;
|
ast_manager& m;
|
||||||
context& m_context;
|
context& m_context;
|
||||||
substitution m_subst;
|
substitution m_subst;
|
||||||
unifier m_unif;
|
unifier m_unif;
|
||||||
|
app_ref m_head;
|
||||||
rule * m_rule;
|
app_ref_vector m_tail;
|
||||||
|
svector<bool> m_neg;
|
||||||
|
rule * m_rule;
|
||||||
|
|
||||||
void apply(app * a, app_ref& res);
|
void apply(app * a, app_ref& res);
|
||||||
public:
|
public:
|
||||||
rule_substitution(context & ctx)
|
rule_substitution(context & ctx)
|
||||||
: m(ctx.get_manager()), m_context(ctx), m_subst(m), m_unif(m), m_rule(0) {}
|
: m(ctx.get_manager()), m_context(ctx), m_subst(m), m_unif(m), m_head(m), m_tail(m), m_rule(0) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Reset substitution and get it ready for working with rule r.
|
Reset substitution and get it ready for working with rule r.
|
||||||
|
@ -61,13 +63,23 @@ namespace datalog {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class normalizer_cfg;
|
||||||
|
class normalizer_rw;
|
||||||
|
|
||||||
ast_manager & m;
|
ast_manager & m;
|
||||||
context & m_context;
|
context & m_context;
|
||||||
th_rewriter & m_simp;
|
th_rewriter & m_simp;
|
||||||
arith_util a;
|
arith_util a;
|
||||||
rule_substitution m_rule_subst;
|
rule_substitution m_rule_subst;
|
||||||
|
ptr_vector<expr> m_todo;
|
||||||
|
obj_hashtable<expr> m_leqs;
|
||||||
|
app_ref_vector m_tail;
|
||||||
|
expr_ref_vector m_itail_members;
|
||||||
|
expr_ref_vector m_conj;
|
||||||
|
svector<bool> m_tail_neg;
|
||||||
|
normalizer_cfg* m_cfg;
|
||||||
|
normalizer_rw* m_rw;
|
||||||
|
|
||||||
class normalizer_cfg;
|
|
||||||
|
|
||||||
void simplify_expr(app * a, expr_ref& res);
|
void simplify_expr(app * a, expr_ref& res);
|
||||||
|
|
||||||
|
@ -77,13 +89,8 @@ namespace datalog {
|
||||||
/** Return true if something was modified */
|
/** Return true if something was modified */
|
||||||
bool transform_rules(const rule_set & orig, rule_set & tgt);
|
bool transform_rules(const rule_set & orig, rule_set & tgt);
|
||||||
public:
|
public:
|
||||||
mk_interp_tail_simplifier(context & ctx, unsigned priority=40000)
|
mk_interp_tail_simplifier(context & ctx, unsigned priority=40000);
|
||||||
: plugin(priority),
|
virtual ~mk_interp_tail_simplifier();
|
||||||
m(ctx.get_manager()),
|
|
||||||
m_context(ctx),
|
|
||||||
m_simp(ctx.get_rewriter()),
|
|
||||||
a(m),
|
|
||||||
m_rule_subst(ctx) {}
|
|
||||||
|
|
||||||
/**If rule should be retained, assign transformed version to res and return true;
|
/**If rule should be retained, assign transformed version to res and return true;
|
||||||
if rule can be deleted, return false.
|
if rule can be deleted, return false.
|
||||||
|
|
|
@ -35,6 +35,8 @@ Revision History:
|
||||||
#include"dl_mk_karr_invariants.h"
|
#include"dl_mk_karr_invariants.h"
|
||||||
#include"expr_safe_replace.h"
|
#include"expr_safe_replace.h"
|
||||||
#include"bool_rewriter.h"
|
#include"bool_rewriter.h"
|
||||||
|
#include"dl_mk_backwards.h"
|
||||||
|
#include"dl_mk_loop_counter.h"
|
||||||
|
|
||||||
namespace datalog {
|
namespace datalog {
|
||||||
|
|
||||||
|
@ -199,6 +201,29 @@ namespace datalog {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mk_loop_counter lc(m_ctx);
|
||||||
|
mk_backwards bwd(m_ctx);
|
||||||
|
|
||||||
|
scoped_ptr<rule_set> src_loop = lc(source);
|
||||||
|
TRACE("dl", src_loop->display(tout << "source loop\n"););
|
||||||
|
|
||||||
|
// run propagation forwards, then backwards
|
||||||
|
scoped_ptr<rule_set> src_annot = update_using_propagation(*src_loop, *src_loop);
|
||||||
|
TRACE("dl", src_annot->display(tout << "updated using propagation\n"););
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
// figure out whether to update same rules as used for saturation.
|
||||||
|
scoped_ptr<rule_set> rev_source = bwd(*src_annot);
|
||||||
|
src_annot = update_using_propagation(*src_annot, *rev_source);
|
||||||
|
#endif
|
||||||
|
rule_set* rules = lc.revert(*src_annot);
|
||||||
|
rules->inherit_predicates(source);
|
||||||
|
TRACE("dl", rules->display(tout););
|
||||||
|
return rules;
|
||||||
|
}
|
||||||
|
|
||||||
|
rule_set* mk_karr_invariants::update_using_propagation(rule_set const& src, rule_set const& srcref) {
|
||||||
m_inner_ctx.reset();
|
m_inner_ctx.reset();
|
||||||
rel_context& rctx = m_inner_ctx.get_rel_context();
|
rel_context& rctx = m_inner_ctx.get_rel_context();
|
||||||
ptr_vector<func_decl> heads;
|
ptr_vector<func_decl> heads;
|
||||||
|
@ -207,24 +232,24 @@ namespace datalog {
|
||||||
m_inner_ctx.register_predicate(*fit, false);
|
m_inner_ctx.register_predicate(*fit, false);
|
||||||
}
|
}
|
||||||
m_inner_ctx.ensure_opened();
|
m_inner_ctx.ensure_opened();
|
||||||
m_inner_ctx.replace_rules(source);
|
m_inner_ctx.replace_rules(srcref);
|
||||||
m_inner_ctx.close();
|
m_inner_ctx.close();
|
||||||
rule_set::decl2rules::iterator dit = source.begin_grouped_rules();
|
rule_set::decl2rules::iterator dit = srcref.begin_grouped_rules();
|
||||||
rule_set::decl2rules::iterator dend = source.end_grouped_rules();
|
rule_set::decl2rules::iterator dend = srcref.end_grouped_rules();
|
||||||
for (; dit != dend; ++dit) {
|
for (; dit != dend; ++dit) {
|
||||||
heads.push_back(dit->m_key);
|
heads.push_back(dit->m_key);
|
||||||
}
|
}
|
||||||
m_inner_ctx.rel_query(heads.size(), heads.c_ptr());
|
m_inner_ctx.rel_query(heads.size(), heads.c_ptr());
|
||||||
|
|
||||||
rule_set* rules = alloc(rule_set, m_ctx);
|
rule_set* dst = alloc(rule_set, m_ctx);
|
||||||
it = source.begin();
|
rule_set::iterator it = src.begin(), end = src.end();
|
||||||
for (; it != end; ++it) {
|
for (; it != end; ++it) {
|
||||||
update_body(rctx, *rules, **it);
|
update_body(rctx, *dst, **it);
|
||||||
}
|
}
|
||||||
if (m_ctx.get_model_converter()) {
|
if (m_ctx.get_model_converter()) {
|
||||||
add_invariant_model_converter* kmc = alloc(add_invariant_model_converter, m);
|
add_invariant_model_converter* kmc = alloc(add_invariant_model_converter, m);
|
||||||
rule_set::decl2rules::iterator git = source.begin_grouped_rules();
|
rule_set::decl2rules::iterator git = src.begin_grouped_rules();
|
||||||
rule_set::decl2rules::iterator gend = source.end_grouped_rules();
|
rule_set::decl2rules::iterator gend = src.end_grouped_rules();
|
||||||
for (; git != gend; ++git) {
|
for (; git != gend; ++git) {
|
||||||
func_decl* p = git->m_key;
|
func_decl* p = git->m_key;
|
||||||
expr_ref fml(m);
|
expr_ref fml(m);
|
||||||
|
@ -236,9 +261,9 @@ namespace datalog {
|
||||||
}
|
}
|
||||||
m_ctx.add_model_converter(kmc);
|
m_ctx.add_model_converter(kmc);
|
||||||
}
|
}
|
||||||
TRACE("dl", rules->display(tout););
|
|
||||||
rules->inherit_predicates(source);
|
dst->inherit_predicates(src);
|
||||||
return rules;
|
return dst;
|
||||||
}
|
}
|
||||||
|
|
||||||
void mk_karr_invariants::update_body(rel_context& rctx, rule_set& rules, rule& r) {
|
void mk_karr_invariants::update_body(rel_context& rctx, rule_set& rules, rule& r) {
|
||||||
|
|
|
@ -56,7 +56,7 @@ namespace datalog {
|
||||||
context m_inner_ctx;
|
context m_inner_ctx;
|
||||||
arith_util a;
|
arith_util a;
|
||||||
void update_body(rel_context& rctx, rule_set& result, rule& r);
|
void update_body(rel_context& rctx, rule_set& result, rule& r);
|
||||||
|
rule_set* update_using_propagation(rule_set const& src, rule_set const& srcref);
|
||||||
public:
|
public:
|
||||||
mk_karr_invariants(context & ctx, unsigned priority);
|
mk_karr_invariants(context & ctx, unsigned priority);
|
||||||
|
|
||||||
|
|
|
@ -32,7 +32,7 @@ namespace datalog {
|
||||||
|
|
||||||
mk_loop_counter::~mk_loop_counter() { }
|
mk_loop_counter::~mk_loop_counter() { }
|
||||||
|
|
||||||
app_ref mk_loop_counter::add_arg(app* fn, unsigned idx) {
|
app_ref mk_loop_counter::add_arg(rule_set const& src, rule_set& dst, app* fn, unsigned idx) {
|
||||||
expr_ref_vector args(m);
|
expr_ref_vector args(m);
|
||||||
func_decl* new_fn, *old_fn = fn->get_decl();
|
func_decl* new_fn, *old_fn = fn->get_decl();
|
||||||
args.append(fn->get_num_args(), fn->get_args());
|
args.append(fn->get_num_args(), fn->get_args());
|
||||||
|
@ -46,17 +46,29 @@ namespace datalog {
|
||||||
m_old2new.insert(old_fn, new_fn);
|
m_old2new.insert(old_fn, new_fn);
|
||||||
m_new2old.insert(new_fn, old_fn);
|
m_new2old.insert(new_fn, old_fn);
|
||||||
m_refs.push_back(new_fn);
|
m_refs.push_back(new_fn);
|
||||||
|
m_ctx.register_predicate(new_fn, false);
|
||||||
|
if (src.is_output_predicate(old_fn)) {
|
||||||
|
dst.set_output_predicate(new_fn);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return app_ref(m.mk_app(new_fn, args.size(), args.c_ptr()), m);
|
return app_ref(m.mk_app(new_fn, args.size(), args.c_ptr()), m);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
app_ref mk_loop_counter::del_arg(app* fn) {
|
||||||
|
expr_ref_vector args(m);
|
||||||
|
func_decl* old_fn, *new_fn = fn->get_decl();
|
||||||
|
SASSERT(fn->get_num_args() > 0);
|
||||||
|
args.append(fn->get_num_args()-1, fn->get_args());
|
||||||
|
VERIFY (m_new2old.find(new_fn, old_fn));
|
||||||
|
return app_ref(m.mk_app(old_fn, args.size(), args.c_ptr()), m);
|
||||||
|
}
|
||||||
|
|
||||||
rule_set * mk_loop_counter::operator()(rule_set const & source) {
|
rule_set * mk_loop_counter::operator()(rule_set const & source) {
|
||||||
m_refs.reset();
|
m_refs.reset();
|
||||||
m_old2new.reset();
|
m_old2new.reset();
|
||||||
m_new2old.reset();
|
m_new2old.reset();
|
||||||
context& ctx = source.get_context();
|
|
||||||
rule_manager& rm = source.get_rule_manager();
|
rule_manager& rm = source.get_rule_manager();
|
||||||
rule_set * result = alloc(rule_set, ctx);
|
rule_set * result = alloc(rule_set, m_ctx);
|
||||||
unsigned sz = source.get_num_rules();
|
unsigned sz = source.get_num_rules();
|
||||||
rule_ref new_rule(rm);
|
rule_ref new_rule(rm);
|
||||||
app_ref_vector tail(m);
|
app_ref_vector tail(m);
|
||||||
|
@ -71,16 +83,14 @@ namespace datalog {
|
||||||
unsigned utsz = r.get_uninterpreted_tail_size();
|
unsigned utsz = r.get_uninterpreted_tail_size();
|
||||||
unsigned tsz = r.get_tail_size();
|
unsigned tsz = r.get_tail_size();
|
||||||
for (unsigned j = 0; j < utsz; ++j, ++cnt) {
|
for (unsigned j = 0; j < utsz; ++j, ++cnt) {
|
||||||
tail.push_back(add_arg(r.get_tail(j), cnt));
|
tail.push_back(add_arg(source, *result, r.get_tail(j), cnt));
|
||||||
neg.push_back(r.is_neg_tail(j));
|
neg.push_back(r.is_neg_tail(j));
|
||||||
m_ctx.register_predicate(tail.back()->get_decl(), false);
|
|
||||||
}
|
}
|
||||||
for (unsigned j = utsz; j < tsz; ++j) {
|
for (unsigned j = utsz; j < tsz; ++j) {
|
||||||
tail.push_back(r.get_tail(j));
|
tail.push_back(r.get_tail(j));
|
||||||
neg.push_back(false);
|
neg.push_back(false);
|
||||||
}
|
}
|
||||||
head = add_arg(r.get_head(), cnt);
|
head = add_arg(source, *result, r.get_head(), cnt);
|
||||||
m_ctx.register_predicate(head->get_decl(), false);
|
|
||||||
// set the loop counter to be an increment of the previous
|
// set the loop counter to be an increment of the previous
|
||||||
bool found = false;
|
bool found = false;
|
||||||
unsigned last = head->get_num_args()-1;
|
unsigned last = head->get_num_args()-1;
|
||||||
|
@ -108,9 +118,41 @@ namespace datalog {
|
||||||
// model converter: remove references to extra argument.
|
// model converter: remove references to extra argument.
|
||||||
// proof converter: remove references to extra argument as well.
|
// proof converter: remove references to extra argument as well.
|
||||||
|
|
||||||
result->inherit_predicates(source);
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rule_set * mk_loop_counter::revert(rule_set const & source) {
|
||||||
|
context& ctx = source.get_context();
|
||||||
|
rule_manager& rm = source.get_rule_manager();
|
||||||
|
rule_set * result = alloc(rule_set, ctx);
|
||||||
|
unsigned sz = source.get_num_rules();
|
||||||
|
rule_ref new_rule(rm);
|
||||||
|
app_ref_vector tail(m);
|
||||||
|
app_ref head(m);
|
||||||
|
svector<bool> neg;
|
||||||
|
for (unsigned i = 0; i < sz; ++i) {
|
||||||
|
tail.reset();
|
||||||
|
neg.reset();
|
||||||
|
rule & r = *source.get_rule(i);
|
||||||
|
unsigned utsz = r.get_uninterpreted_tail_size();
|
||||||
|
unsigned tsz = r.get_tail_size();
|
||||||
|
for (unsigned j = 0; j < utsz; ++j) {
|
||||||
|
tail.push_back(del_arg(r.get_tail(j)));
|
||||||
|
neg.push_back(r.is_neg_tail(j));
|
||||||
|
}
|
||||||
|
for (unsigned j = utsz; j < tsz; ++j) {
|
||||||
|
tail.push_back(r.get_tail(j));
|
||||||
|
neg.push_back(false);
|
||||||
|
}
|
||||||
|
head = del_arg(r.get_head());
|
||||||
|
new_rule = rm.mk(head, tail.size(), tail.c_ptr(), neg.c_ptr(), r.name(), true);
|
||||||
|
result->add_rule(new_rule);
|
||||||
|
}
|
||||||
|
|
||||||
|
// model converter: ...
|
||||||
|
// proof converter: ...
|
||||||
|
|
||||||
|
return result;
|
||||||
|
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -32,7 +32,8 @@ namespace datalog {
|
||||||
obj_map<func_decl, func_decl*> m_new2old;
|
obj_map<func_decl, func_decl*> m_new2old;
|
||||||
obj_map<func_decl, func_decl*> m_old2new;
|
obj_map<func_decl, func_decl*> m_old2new;
|
||||||
|
|
||||||
app_ref add_arg(app* fn, unsigned idx);
|
app_ref add_arg(rule_set const& src, rule_set& dst, app* fn, unsigned idx);
|
||||||
|
app_ref del_arg(app* fn);
|
||||||
public:
|
public:
|
||||||
mk_loop_counter(context & ctx, unsigned priority = 33000);
|
mk_loop_counter(context & ctx, unsigned priority = 33000);
|
||||||
~mk_loop_counter();
|
~mk_loop_counter();
|
||||||
|
@ -40,6 +41,8 @@ namespace datalog {
|
||||||
rule_set * operator()(rule_set const & source);
|
rule_set * operator()(rule_set const & source);
|
||||||
|
|
||||||
func_decl* get_old(func_decl* f) const { return m_new2old.find(f); }
|
func_decl* get_old(func_decl* f) const { return m_new2old.find(f); }
|
||||||
|
|
||||||
|
rule_set * revert(rule_set const& source);
|
||||||
};
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -28,6 +28,7 @@ namespace datalog {
|
||||||
plugin(10000, true),
|
plugin(10000, true),
|
||||||
m_context(ctx),
|
m_context(ctx),
|
||||||
m(ctx.get_manager()),
|
m(ctx.get_manager()),
|
||||||
|
rm(ctx.get_rule_manager()),
|
||||||
m_pinned(m),
|
m_pinned(m),
|
||||||
m_goal(goal, m) {
|
m_goal(goal, m) {
|
||||||
}
|
}
|
||||||
|
@ -259,7 +260,7 @@ namespace datalog {
|
||||||
}
|
}
|
||||||
new_tail.push_back(curr);
|
new_tail.push_back(curr);
|
||||||
negations.push_back(r->is_neg_tail(curr_index));
|
negations.push_back(r->is_neg_tail(curr_index));
|
||||||
collect_vars(m, curr, bound_vars);
|
bound_vars |= rm.collect_vars(curr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -47,6 +47,11 @@ namespace datalog {
|
||||||
AD_BOUND
|
AD_BOUND
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct a_flag_hash {
|
||||||
|
typedef a_flag data;
|
||||||
|
unsigned operator()(a_flag x) const { return x; }
|
||||||
|
};
|
||||||
|
|
||||||
struct adornment : public svector<a_flag> {
|
struct adornment : public svector<a_flag> {
|
||||||
|
|
||||||
void populate(app * lit, const var_idx_set & bound_vars);
|
void populate(app * lit, const var_idx_set & bound_vars);
|
||||||
|
@ -71,7 +76,7 @@ namespace datalog {
|
||||||
return m_pred==o.m_pred && m_adornment==o.m_adornment;
|
return m_pred==o.m_pred && m_adornment==o.m_adornment;
|
||||||
}
|
}
|
||||||
unsigned hash() const {
|
unsigned hash() const {
|
||||||
return m_pred->hash()^int_vector_hash(m_adornment);
|
return m_pred->hash()^svector_hash<a_flag_hash>()(m_adornment);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -90,6 +95,7 @@ namespace datalog {
|
||||||
|
|
||||||
context & m_context;
|
context & m_context;
|
||||||
ast_manager & m;
|
ast_manager & m;
|
||||||
|
rule_manager& rm;
|
||||||
ast_ref_vector m_pinned;
|
ast_ref_vector m_pinned;
|
||||||
/**
|
/**
|
||||||
\brief Predicates from the original set that appear in a head of a rule
|
\brief Predicates from the original set that appear in a head of a rule
|
||||||
|
|
|
@ -505,9 +505,6 @@ namespace datalog {
|
||||||
|
|
||||||
unsigned head_arity = head_pred->get_arity();
|
unsigned head_arity = head_pred->get_arity();
|
||||||
|
|
||||||
//var_idx_set head_vars;
|
|
||||||
//var_idx_set same_strat_vars;
|
|
||||||
//collect_vars(m, r->get_head(), head_vars);
|
|
||||||
|
|
||||||
unsigned pt_len = r->get_positive_tail_size();
|
unsigned pt_len = r->get_positive_tail_size();
|
||||||
for (unsigned ti=0; ti<pt_len; ++ti) {
|
for (unsigned ti=0; ti<pt_len; ++ti) {
|
||||||
|
@ -518,7 +515,6 @@ namespace datalog {
|
||||||
SASSERT(pred_strat<=head_strat);
|
SASSERT(pred_strat<=head_strat);
|
||||||
|
|
||||||
if (pred_strat==head_strat) {
|
if (pred_strat==head_strat) {
|
||||||
//collect_vars(m, r->get_head(), same_strat_vars);
|
|
||||||
if (pred->get_arity()>head_arity
|
if (pred->get_arity()>head_arity
|
||||||
|| (pred->get_arity()==head_arity && pred->get_id()>=head_pred->get_id()) ) {
|
|| (pred->get_arity()==head_arity && pred->get_id()>=head_pred->get_id()) ) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -709,8 +705,7 @@ namespace datalog {
|
||||||
|
|
||||||
#define PRT(_x_) ((_x_)?"T":"F")
|
#define PRT(_x_) ((_x_)?"T":"F")
|
||||||
|
|
||||||
bool mk_rule_inliner::inline_linear(rule_set const& source, scoped_ptr<rule_set>& rules) {
|
bool mk_rule_inliner::inline_linear(scoped_ptr<rule_set>& rules) {
|
||||||
scoped_ptr<rule_set> res = alloc(rule_set, m_context);
|
|
||||||
bool done_something = false;
|
bool done_something = false;
|
||||||
unsigned sz = rules->get_num_rules();
|
unsigned sz = rules->get_num_rules();
|
||||||
|
|
||||||
|
@ -731,7 +726,7 @@ namespace datalog {
|
||||||
svector<bool>& can_expand = m_head_visitor.can_expand();
|
svector<bool>& can_expand = m_head_visitor.can_expand();
|
||||||
|
|
||||||
for (unsigned i = 0; i < sz; ++i) {
|
for (unsigned i = 0; i < sz; ++i) {
|
||||||
add_rule(source, acc[i].get(), i);
|
add_rule(*rules, acc[i].get(), i);
|
||||||
}
|
}
|
||||||
|
|
||||||
// initialize substitution.
|
// initialize substitution.
|
||||||
|
@ -808,7 +803,7 @@ namespace datalog {
|
||||||
TRACE("dl", r->display(m_context, tout); r2->display(m_context, tout); rl_res->display(m_context, tout); );
|
TRACE("dl", r->display(m_context, tout); r2->display(m_context, tout); rl_res->display(m_context, tout); );
|
||||||
|
|
||||||
del_rule(r, i);
|
del_rule(r, i);
|
||||||
add_rule(source, rl_res.get(), i);
|
add_rule(*rules, rl_res.get(), i);
|
||||||
|
|
||||||
|
|
||||||
r = rl_res;
|
r = rl_res;
|
||||||
|
@ -828,13 +823,15 @@ namespace datalog {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (done_something) {
|
if (done_something) {
|
||||||
rules = alloc(rule_set, m_context);
|
scoped_ptr<rule_set> res = alloc(rule_set, m_context);
|
||||||
for (unsigned i = 0; i < sz; ++i) {
|
for (unsigned i = 0; i < sz; ++i) {
|
||||||
if (valid.get(i)) {
|
if (valid.get(i)) {
|
||||||
rules->add_rule(acc[i].get());
|
res->add_rule(acc[i].get());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TRACE("dl", rules->display(tout););
|
res->inherit_predicates(*rules);
|
||||||
|
TRACE("dl", res->display(tout););
|
||||||
|
rules = res.detach();
|
||||||
}
|
}
|
||||||
return done_something;
|
return done_something;
|
||||||
}
|
}
|
||||||
|
@ -871,11 +868,17 @@ namespace datalog {
|
||||||
// try eager inlining
|
// try eager inlining
|
||||||
if (do_eager_inlining(res)) {
|
if (do_eager_inlining(res)) {
|
||||||
something_done = true;
|
something_done = true;
|
||||||
}
|
}
|
||||||
TRACE("dl", res->display(tout << "after eager inlining\n"););
|
TRACE("dl", res->display(tout << "after eager inlining\n"););
|
||||||
|
}
|
||||||
|
if (something_done) {
|
||||||
|
res->inherit_predicates(source);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
res = alloc(rule_set, source);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_context.get_params().inline_linear() && inline_linear(source, res)) {
|
if (m_context.get_params().inline_linear() && inline_linear(res)) {
|
||||||
something_done = true;
|
something_done = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -883,7 +886,6 @@ namespace datalog {
|
||||||
res = 0;
|
res = 0;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
res->inherit_predicates(source);
|
|
||||||
m_context.add_model_converter(hsmc.get());
|
m_context.add_model_converter(hsmc.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -172,7 +172,7 @@ namespace datalog {
|
||||||
/**
|
/**
|
||||||
Inline predicates that are known to not be join-points.
|
Inline predicates that are known to not be join-points.
|
||||||
*/
|
*/
|
||||||
bool inline_linear(rule_set const& source, scoped_ptr<rule_set>& rules);
|
bool inline_linear(scoped_ptr<rule_set>& rules);
|
||||||
|
|
||||||
void add_rule(rule_set const& rule_set, rule* r, unsigned i);
|
void add_rule(rule_set const& rule_set, rule* r, unsigned i);
|
||||||
void del_rule(rule* r, unsigned i);
|
void del_rule(rule* r, unsigned i);
|
||||||
|
|
|
@ -29,6 +29,7 @@ namespace datalog {
|
||||||
m_manager(ctx.get_manager()),
|
m_manager(ctx.get_manager()),
|
||||||
m_threshold_count(ctx.similarity_compressor_threshold()),
|
m_threshold_count(ctx.similarity_compressor_threshold()),
|
||||||
m_result_rules(ctx.get_rule_manager()),
|
m_result_rules(ctx.get_rule_manager()),
|
||||||
|
m_modified(false),
|
||||||
m_pinned(m_manager) {
|
m_pinned(m_manager) {
|
||||||
SASSERT(m_threshold_count>1);
|
SASSERT(m_threshold_count>1);
|
||||||
}
|
}
|
||||||
|
@ -55,6 +56,9 @@ namespace datalog {
|
||||||
return (a>b) ? 1 : ( (a==b) ? 0 : -1);
|
return (a>b) ? 1 : ( (a==b) ? 0 : -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
static int aux_compare(T* a, T* b);
|
||||||
|
|
||||||
static int compare_var_args(app* t1, app* t2) {
|
static int compare_var_args(app* t1, app* t2) {
|
||||||
SASSERT(t1->get_num_args()==t2->get_num_args());
|
SASSERT(t1->get_num_args()==t2->get_num_args());
|
||||||
int res;
|
int res;
|
||||||
|
@ -88,7 +92,7 @@ namespace datalog {
|
||||||
if ((skip_countdown--) == 0) {
|
if ((skip_countdown--) == 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
res = aux_compare(t1->get_arg(i), t2->get_arg(i));
|
res = aux_compare(t1->get_arg(i)->get_id(), t2->get_arg(i)->get_id());
|
||||||
if (res!=0) { return res; }
|
if (res!=0) { return res; }
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -113,7 +117,7 @@ namespace datalog {
|
||||||
for (int i=-1; i<pos_tail_sz; i++) {
|
for (int i=-1; i<pos_tail_sz; i++) {
|
||||||
app * t1 = get_by_tail_index(r1, i);
|
app * t1 = get_by_tail_index(r1, i);
|
||||||
app * t2 = get_by_tail_index(r2, i);
|
app * t2 = get_by_tail_index(r2, i);
|
||||||
res = aux_compare(t1->get_decl(), t2->get_decl());
|
res = aux_compare(t1->get_decl()->get_id(), t2->get_decl()->get_id());
|
||||||
if (res!=0) { return res; }
|
if (res!=0) { return res; }
|
||||||
res = compare_var_args(t1, t2);
|
res = compare_var_args(t1, t2);
|
||||||
if (res!=0) { return res; }
|
if (res!=0) { return res; }
|
||||||
|
@ -121,7 +125,7 @@ namespace datalog {
|
||||||
|
|
||||||
unsigned tail_sz = r1->get_tail_size();
|
unsigned tail_sz = r1->get_tail_size();
|
||||||
for (unsigned i=pos_tail_sz; i<tail_sz; i++) {
|
for (unsigned i=pos_tail_sz; i<tail_sz; i++) {
|
||||||
res = aux_compare(r1->get_tail(i), r2->get_tail(i));
|
res = aux_compare(r1->get_tail(i)->get_id(), r2->get_tail(i)->get_id());
|
||||||
if (res!=0) { return res; }
|
if (res!=0) { return res; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,8 @@ namespace datalog {
|
||||||
|
|
||||||
mk_simple_joins::mk_simple_joins(context & ctx):
|
mk_simple_joins::mk_simple_joins(context & ctx):
|
||||||
plugin(1000),
|
plugin(1000),
|
||||||
m_context(ctx) {
|
m_context(ctx),
|
||||||
|
rm(ctx.get_rule_manager()) {
|
||||||
}
|
}
|
||||||
|
|
||||||
class join_planner {
|
class join_planner {
|
||||||
|
@ -120,6 +121,7 @@ namespace datalog {
|
||||||
|
|
||||||
context & m_context;
|
context & m_context;
|
||||||
ast_manager & m;
|
ast_manager & m;
|
||||||
|
rule_manager & rm;
|
||||||
var_subst & m_var_subst;
|
var_subst & m_var_subst;
|
||||||
rule_set & m_rs_aux_copy; //reference to a rule_set that will allow to ask for stratum levels
|
rule_set & m_rs_aux_copy; //reference to a rule_set that will allow to ask for stratum levels
|
||||||
|
|
||||||
|
@ -130,10 +132,13 @@ namespace datalog {
|
||||||
ptr_hashtable<rule, ptr_hash<rule>, ptr_eq<rule> > m_modified_rules;
|
ptr_hashtable<rule, ptr_hash<rule>, ptr_eq<rule> > m_modified_rules;
|
||||||
|
|
||||||
ast_ref_vector m_pinned;
|
ast_ref_vector m_pinned;
|
||||||
|
mutable ptr_vector<sort> m_vars;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
join_planner(context & ctx, rule_set & rs_aux_copy)
|
join_planner(context & ctx, rule_set & rs_aux_copy)
|
||||||
: m_context(ctx), m(ctx.get_manager()), m_var_subst(ctx.get_var_subst()),
|
: m_context(ctx), m(ctx.get_manager()),
|
||||||
|
rm(ctx.get_rule_manager()),
|
||||||
|
m_var_subst(ctx.get_var_subst()),
|
||||||
m_rs_aux_copy(rs_aux_copy),
|
m_rs_aux_copy(rs_aux_copy),
|
||||||
m_introduced_rules(ctx.get_rule_manager()),
|
m_introduced_rules(ctx.get_rule_manager()),
|
||||||
m_pinned(ctx.get_manager())
|
m_pinned(ctx.get_manager())
|
||||||
|
@ -175,9 +180,7 @@ namespace datalog {
|
||||||
|
|
||||||
unsigned max_var_idx = 0;
|
unsigned max_var_idx = 0;
|
||||||
{
|
{
|
||||||
var_idx_set orig_var_set;
|
var_idx_set& orig_var_set = rm.collect_vars(t1, t2);
|
||||||
collect_vars(m, t1, orig_var_set);
|
|
||||||
collect_vars(m, t2, orig_var_set);
|
|
||||||
var_idx_set::iterator ovit = orig_var_set.begin();
|
var_idx_set::iterator ovit = orig_var_set.begin();
|
||||||
var_idx_set::iterator ovend = orig_var_set.end();
|
var_idx_set::iterator ovend = orig_var_set.end();
|
||||||
for(; ovit!=ovend; ++ovit) {
|
for(; ovit!=ovend; ++ovit) {
|
||||||
|
@ -323,14 +326,13 @@ namespace datalog {
|
||||||
}
|
}
|
||||||
for(unsigned i=0; i<pos_tail_size; i++) {
|
for(unsigned i=0; i<pos_tail_size; i++) {
|
||||||
app * t1 = r->get_tail(i);
|
app * t1 = r->get_tail(i);
|
||||||
var_idx_set t1_vars;
|
var_idx_set t1_vars = rm.collect_vars(t1);
|
||||||
collect_vars(m, t1, t1_vars);
|
|
||||||
counter.count_vars(m, t1, -1); //temporarily remove t1 variables from counter
|
counter.count_vars(m, t1, -1); //temporarily remove t1 variables from counter
|
||||||
for(unsigned j=i+1; j<pos_tail_size; j++) {
|
for(unsigned j=i+1; j<pos_tail_size; j++) {
|
||||||
app * t2 = r->get_tail(j);
|
app * t2 = r->get_tail(j);
|
||||||
counter.count_vars(m, t2, -1); //temporarily remove t2 variables from counter
|
counter.count_vars(m, t2, -1); //temporarily remove t2 variables from counter
|
||||||
var_idx_set scope_vars(t1_vars);
|
var_idx_set scope_vars = rm.collect_vars(t2);
|
||||||
collect_vars(m, t2, scope_vars);
|
scope_vars |= t1_vars;
|
||||||
var_idx_set non_local_vars;
|
var_idx_set non_local_vars;
|
||||||
counter.collect_positive(non_local_vars);
|
counter.collect_positive(non_local_vars);
|
||||||
counter.count_vars(m, t2, 1); //restore t2 variables in counter
|
counter.count_vars(m, t2, 1); //restore t2 variables in counter
|
||||||
|
@ -472,8 +474,7 @@ namespace datalog {
|
||||||
while(!added_tails.empty()) {
|
while(!added_tails.empty()) {
|
||||||
app * a_tail = added_tails.back(); //added tail
|
app * a_tail = added_tails.back(); //added tail
|
||||||
|
|
||||||
var_idx_set a_tail_vars;
|
var_idx_set a_tail_vars = rm.collect_vars(a_tail);
|
||||||
collect_vars(m, a_tail, a_tail_vars);
|
|
||||||
counter.count_vars(m, a_tail, -1); //temporarily remove a_tail variables from counter
|
counter.count_vars(m, a_tail, -1); //temporarily remove a_tail variables from counter
|
||||||
|
|
||||||
for(unsigned i=0; i<len; i++) {
|
for(unsigned i=0; i<len; i++) {
|
||||||
|
@ -484,8 +485,8 @@ namespace datalog {
|
||||||
}
|
}
|
||||||
|
|
||||||
counter.count_vars(m, o_tail, -1); //temporarily remove o_tail variables from counter
|
counter.count_vars(m, o_tail, -1); //temporarily remove o_tail variables from counter
|
||||||
var_idx_set scope_vars(a_tail_vars);
|
var_idx_set scope_vars = rm.collect_vars(o_tail);
|
||||||
collect_vars(m, o_tail, scope_vars);
|
scope_vars |= a_tail_vars;
|
||||||
var_idx_set non_local_vars;
|
var_idx_set non_local_vars;
|
||||||
counter.collect_positive(non_local_vars);
|
counter.collect_positive(non_local_vars);
|
||||||
counter.count_vars(m, o_tail, 1); //restore o_tail variables in counter
|
counter.count_vars(m, o_tail, 1); //restore o_tail variables in counter
|
||||||
|
|
|
@ -49,7 +49,8 @@ namespace datalog {
|
||||||
We say that a rule containing C_i's is a rule with a "big tail".
|
We say that a rule containing C_i's is a rule with a "big tail".
|
||||||
*/
|
*/
|
||||||
class mk_simple_joins : public rule_transformer::plugin {
|
class mk_simple_joins : public rule_transformer::plugin {
|
||||||
context & m_context;
|
context & m_context;
|
||||||
|
rule_manager & rm;
|
||||||
public:
|
public:
|
||||||
mk_simple_joins(context & ctx);
|
mk_simple_joins(context & ctx);
|
||||||
|
|
||||||
|
|
|
@ -725,6 +725,9 @@ namespace datalog {
|
||||||
m_mc->add_predicate(p, f);
|
m_mc->add_predicate(p, f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (src.is_output_predicate(p)) {
|
||||||
|
dst.set_output_predicate(p);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -241,6 +241,7 @@ namespace datalog {
|
||||||
tgt.add_rule(new_rule);
|
tgt.add_rule(new_rule);
|
||||||
subs_index.add(new_rule);
|
subs_index.add(new_rule);
|
||||||
}
|
}
|
||||||
|
tgt.inherit_predicates(orig);
|
||||||
TRACE("dl",
|
TRACE("dl",
|
||||||
tout << "original set size: "<<orig.get_num_rules()<<"\n"
|
tout << "original set size: "<<orig.get_num_rules()<<"\n"
|
||||||
<< "reduced set size: "<<tgt.get_num_rules()<<"\n"; );
|
<< "reduced set size: "<<tgt.get_num_rules()<<"\n"; );
|
||||||
|
@ -338,7 +339,7 @@ namespace datalog {
|
||||||
rule_set * res = alloc(rule_set, m_context);
|
rule_set * res = alloc(rule_set, m_context);
|
||||||
bool modified = transform_rules(source, *res);
|
bool modified = transform_rules(source, *res);
|
||||||
|
|
||||||
if(!m_have_new_total_rule && !modified) {
|
if (!m_have_new_total_rule && !modified) {
|
||||||
dealloc(res);
|
dealloc(res);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -347,7 +348,7 @@ namespace datalog {
|
||||||
//During the construction of the new set we may discover new total relations
|
//During the construction of the new set we may discover new total relations
|
||||||
//(by quantifier elimination on the uninterpreted tails).
|
//(by quantifier elimination on the uninterpreted tails).
|
||||||
SASSERT(m_new_total_relation_discovery_during_transformation || !m_have_new_total_rule);
|
SASSERT(m_new_total_relation_discovery_during_transformation || !m_have_new_total_rule);
|
||||||
while(m_have_new_total_rule) {
|
while (m_have_new_total_rule) {
|
||||||
m_have_new_total_rule = false;
|
m_have_new_total_rule = false;
|
||||||
|
|
||||||
rule_set * old = res;
|
rule_set * old = res;
|
||||||
|
@ -355,7 +356,6 @@ namespace datalog {
|
||||||
transform_rules(*old, *res);
|
transform_rules(*old, *res);
|
||||||
dealloc(old);
|
dealloc(old);
|
||||||
}
|
}
|
||||||
res->inherit_predicates(source);
|
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,8 @@ namespace datalog {
|
||||||
plugin(500),
|
plugin(500),
|
||||||
m_context(ctx),
|
m_context(ctx),
|
||||||
m(ctx.get_manager()),
|
m(ctx.get_manager()),
|
||||||
m_rules(ctx.get_rule_manager()),
|
rm(ctx.get_rule_manager()),
|
||||||
|
m_rules(rm),
|
||||||
m_pinned(m) {
|
m_pinned(m) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,10 +48,7 @@ namespace datalog {
|
||||||
}
|
}
|
||||||
unsigned var_idx = to_var(head_arg)->get_idx();
|
unsigned var_idx = to_var(head_arg)->get_idx();
|
||||||
|
|
||||||
var_idx_set tail_vars;
|
return rm.collect_tail_vars(r).contains(var_idx);
|
||||||
collect_tail_vars(m, r, tail_vars);
|
|
||||||
|
|
||||||
return tail_vars.contains(var_idx);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void mk_unbound_compressor::add_task(func_decl * pred, unsigned arg_index) {
|
void mk_unbound_compressor::add_task(func_decl * pred, unsigned arg_index) {
|
||||||
|
@ -83,8 +81,7 @@ namespace datalog {
|
||||||
|
|
||||||
void mk_unbound_compressor::detect_tasks(rule_set const& source, unsigned rule_index) {
|
void mk_unbound_compressor::detect_tasks(rule_set const& source, unsigned rule_index) {
|
||||||
rule * r = m_rules.get(rule_index);
|
rule * r = m_rules.get(rule_index);
|
||||||
var_idx_set tail_vars;
|
var_idx_set& tail_vars = rm.collect_tail_vars(r);
|
||||||
collect_tail_vars(m, r, tail_vars);
|
|
||||||
|
|
||||||
app * head = r->get_head();
|
app * head = r->get_head();
|
||||||
func_decl * head_pred = head->get_decl();
|
func_decl * head_pred = head->get_decl();
|
||||||
|
@ -94,9 +91,9 @@ namespace datalog {
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned n = head_pred->get_arity();
|
unsigned n = head_pred->get_arity();
|
||||||
|
|
||||||
var_counter head_var_counter;
|
rm.get_counter().reset();
|
||||||
head_var_counter.count_vars(m, head, 1);
|
rm.get_counter().count_vars(m, head, 1);
|
||||||
|
|
||||||
for (unsigned i=0; i<n; i++) {
|
for (unsigned i=0; i<n; i++) {
|
||||||
expr * arg = head->get_arg(i);
|
expr * arg = head->get_arg(i);
|
||||||
|
@ -107,7 +104,7 @@ namespace datalog {
|
||||||
if (!tail_vars.contains(var_idx)) {
|
if (!tail_vars.contains(var_idx)) {
|
||||||
//unbound
|
//unbound
|
||||||
|
|
||||||
unsigned occurence_cnt = head_var_counter.get(var_idx);
|
unsigned occurence_cnt = rm.get_counter().get(var_idx);
|
||||||
SASSERT(occurence_cnt>0);
|
SASSERT(occurence_cnt>0);
|
||||||
if (occurence_cnt == 1) {
|
if (occurence_cnt == 1) {
|
||||||
TRACE("dl", r->display(m_context, tout << "Compress: "););
|
TRACE("dl", r->display(m_context, tout << "Compress: "););
|
||||||
|
@ -121,15 +118,14 @@ namespace datalog {
|
||||||
void mk_unbound_compressor::try_compress(rule_set const& source, unsigned rule_index) {
|
void mk_unbound_compressor::try_compress(rule_set const& source, unsigned rule_index) {
|
||||||
start:
|
start:
|
||||||
rule * r = m_rules.get(rule_index);
|
rule * r = m_rules.get(rule_index);
|
||||||
var_idx_set tail_vars;
|
var_idx_set& tail_vars = rm.collect_tail_vars(r);
|
||||||
collect_tail_vars(m, r, tail_vars);
|
|
||||||
|
|
||||||
app * head = r->get_head();
|
app * head = r->get_head();
|
||||||
func_decl * head_pred = head->get_decl();
|
func_decl * head_pred = head->get_decl();
|
||||||
unsigned head_arity = head_pred->get_arity();
|
unsigned head_arity = head_pred->get_arity();
|
||||||
|
|
||||||
var_counter head_var_counter;
|
rm.get_counter().reset();
|
||||||
head_var_counter.count_vars(m, head);
|
rm.get_counter().count_vars(m, head);
|
||||||
|
|
||||||
unsigned arg_index;
|
unsigned arg_index;
|
||||||
for (arg_index = 0; arg_index < head_arity; arg_index++) {
|
for (arg_index = 0; arg_index < head_arity; arg_index++) {
|
||||||
|
@ -140,7 +136,7 @@ namespace datalog {
|
||||||
unsigned var_idx = to_var(arg)->get_idx();
|
unsigned var_idx = to_var(arg)->get_idx();
|
||||||
if (!tail_vars.contains(var_idx)) {
|
if (!tail_vars.contains(var_idx)) {
|
||||||
//unbound
|
//unbound
|
||||||
unsigned occurence_cnt = head_var_counter.get(var_idx);
|
unsigned occurence_cnt = rm.get_counter().get(var_idx);
|
||||||
SASSERT(occurence_cnt>0);
|
SASSERT(occurence_cnt>0);
|
||||||
if ( occurence_cnt==1 && m_in_progress.contains(c_info(head_pred, arg_index)) ) {
|
if ( occurence_cnt==1 && m_in_progress.contains(c_info(head_pred, arg_index)) ) {
|
||||||
//we have found what to compress
|
//we have found what to compress
|
||||||
|
|
|
@ -52,6 +52,7 @@ namespace datalog {
|
||||||
|
|
||||||
context & m_context;
|
context & m_context;
|
||||||
ast_manager & m;
|
ast_manager & m;
|
||||||
|
rule_manager & rm;
|
||||||
rule_ref_vector m_rules;
|
rule_ref_vector m_rules;
|
||||||
bool m_modified;
|
bool m_modified;
|
||||||
todo_stack m_todo;
|
todo_stack m_todo;
|
||||||
|
|
|
@ -40,8 +40,12 @@ namespace datalog {
|
||||||
class filter_equal_fn;
|
class filter_equal_fn;
|
||||||
class filter_identical_fn;
|
class filter_identical_fn;
|
||||||
class filter_interpreted_fn;
|
class filter_interpreted_fn;
|
||||||
|
struct fid_hash {
|
||||||
|
typedef family_id data;
|
||||||
|
unsigned operator()(data x) const { return static_cast<unsigned>(x); }
|
||||||
|
};
|
||||||
|
|
||||||
rel_spec_store<rel_spec> m_spec_store;
|
rel_spec_store<rel_spec, svector_hash<fid_hash> > m_spec_store;
|
||||||
|
|
||||||
family_id get_relation_kind(const product_relation & r);
|
family_id get_relation_kind(const product_relation & r);
|
||||||
|
|
||||||
|
|
|
@ -740,7 +740,6 @@ namespace datalog {
|
||||||
relation_transformer_fn * relation_manager::mk_select_equal_and_project_fn(const relation_base & t,
|
relation_transformer_fn * relation_manager::mk_select_equal_and_project_fn(const relation_base & t,
|
||||||
const relation_element & value, unsigned col) {
|
const relation_element & value, unsigned col) {
|
||||||
relation_transformer_fn * res = t.get_plugin().mk_select_equal_and_project_fn(t, value, col);
|
relation_transformer_fn * res = t.get_plugin().mk_select_equal_and_project_fn(t, value, col);
|
||||||
TRACE("dl", tout << t.get_plugin().get_name() << " " << value << " " << col << "\n";);
|
|
||||||
if(!res) {
|
if(!res) {
|
||||||
relation_mutator_fn * selector = mk_filter_equal_fn(t, value, col);
|
relation_mutator_fn * selector = mk_filter_equal_fn(t, value, col);
|
||||||
if(selector) {
|
if(selector) {
|
||||||
|
|
|
@ -605,7 +605,7 @@ namespace datalog {
|
||||||
/**
|
/**
|
||||||
This is a helper class for relation_plugins whose relations can be of various kinds.
|
This is a helper class for relation_plugins whose relations can be of various kinds.
|
||||||
*/
|
*/
|
||||||
template<class Spec, class Hash=int_vector_hash_proc<Spec>, class Eq=vector_eq_proc<Spec> >
|
template<class Spec, class Hash, class Eq=vector_eq_proc<Spec> >
|
||||||
class rel_spec_store {
|
class rel_spec_store {
|
||||||
typedef relation_signature::hash r_hash;
|
typedef relation_signature::hash r_hash;
|
||||||
typedef relation_signature::eq r_eq;
|
typedef relation_signature::eq r_eq;
|
||||||
|
|
|
@ -40,15 +40,20 @@ Revision History:
|
||||||
#include"quant_hoist.h"
|
#include"quant_hoist.h"
|
||||||
#include"expr_replacer.h"
|
#include"expr_replacer.h"
|
||||||
#include"bool_rewriter.h"
|
#include"bool_rewriter.h"
|
||||||
#include"qe_lite.h"
|
|
||||||
#include"expr_safe_replace.h"
|
#include"expr_safe_replace.h"
|
||||||
#include"hnf.h"
|
|
||||||
|
|
||||||
namespace datalog {
|
namespace datalog {
|
||||||
|
|
||||||
rule_manager::rule_manager(context& ctx)
|
rule_manager::rule_manager(context& ctx)
|
||||||
: m(ctx.get_manager()),
|
: m(ctx.get_manager()),
|
||||||
m_ctx(ctx) {}
|
m_ctx(ctx),
|
||||||
|
m_body(m),
|
||||||
|
m_head(m),
|
||||||
|
m_args(m),
|
||||||
|
m_hnf(m),
|
||||||
|
m_qe(m),
|
||||||
|
m_cfg(m),
|
||||||
|
m_rwr(m, false, m_cfg) {}
|
||||||
|
|
||||||
void rule_manager::inc_ref(rule * r) {
|
void rule_manager::inc_ref(rule * r) {
|
||||||
if (r) {
|
if (r) {
|
||||||
|
@ -67,29 +72,23 @@ namespace datalog {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class remove_label_cfg : public default_rewriter_cfg {
|
rule_manager::remove_label_cfg::~remove_label_cfg() {}
|
||||||
family_id m_label_fid;
|
|
||||||
public:
|
|
||||||
remove_label_cfg(ast_manager& m): m_label_fid(m.get_label_family_id()) {}
|
|
||||||
virtual ~remove_label_cfg() {}
|
|
||||||
|
|
||||||
br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result,
|
br_status rule_manager::remove_label_cfg::reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result,
|
||||||
proof_ref & result_pr)
|
proof_ref & result_pr)
|
||||||
{
|
{
|
||||||
if (is_decl_of(f, m_label_fid, OP_LABEL)) {
|
if (is_decl_of(f, m_label_fid, OP_LABEL)) {
|
||||||
SASSERT(num == 1);
|
SASSERT(num == 1);
|
||||||
result = args[0];
|
result = args[0];
|
||||||
return BR_DONE;
|
return BR_DONE;
|
||||||
}
|
|
||||||
return BR_FAILED;
|
|
||||||
}
|
}
|
||||||
};
|
return BR_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void rule_manager::remove_labels(expr_ref& fml, proof_ref& pr) {
|
void rule_manager::remove_labels(expr_ref& fml, proof_ref& pr) {
|
||||||
expr_ref tmp(m);
|
expr_ref tmp(m);
|
||||||
remove_label_cfg r_cfg(m);
|
m_rwr(fml, tmp);
|
||||||
rewriter_tpl<remove_label_cfg> rwr(m, false, r_cfg);
|
|
||||||
rwr(fml, tmp);
|
|
||||||
if (pr && fml != tmp) {
|
if (pr && fml != tmp) {
|
||||||
|
|
||||||
pr = m.mk_modus_ponens(pr, m.mk_rewrite(fml, tmp));
|
pr = m.mk_modus_ponens(pr, m.mk_rewrite(fml, tmp));
|
||||||
|
@ -97,6 +96,67 @@ namespace datalog {
|
||||||
fml = tmp;
|
fml = tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var_idx_set& rule_manager::collect_vars(expr* e) {
|
||||||
|
return collect_vars(e, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
var_idx_set& rule_manager::collect_vars(expr* e1, expr* e2) {
|
||||||
|
reset_collect_vars();
|
||||||
|
if (e1) accumulate_vars(e1);
|
||||||
|
if (e2) accumulate_vars(e2);
|
||||||
|
return finalize_collect_vars();
|
||||||
|
}
|
||||||
|
|
||||||
|
void rule_manager::reset_collect_vars() {
|
||||||
|
m_vars.reset();
|
||||||
|
m_var_idx.reset();
|
||||||
|
m_todo.reset();
|
||||||
|
m_mark.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
var_idx_set& rule_manager::finalize_collect_vars() {
|
||||||
|
unsigned sz = m_vars.size();
|
||||||
|
for (unsigned i=0; i<sz; ++i) {
|
||||||
|
if (m_vars[i]) m_var_idx.insert(i);
|
||||||
|
}
|
||||||
|
return m_var_idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
var_idx_set& rule_manager::collect_tail_vars(rule * r) {
|
||||||
|
reset_collect_vars();
|
||||||
|
unsigned n = r->get_tail_size();
|
||||||
|
for (unsigned i=0;i<n;i++) {
|
||||||
|
accumulate_vars(r->get_tail(i));
|
||||||
|
}
|
||||||
|
return finalize_collect_vars();
|
||||||
|
}
|
||||||
|
|
||||||
|
var_idx_set& rule_manager::collect_rule_vars_ex(rule * r, app* t) {
|
||||||
|
reset_collect_vars();
|
||||||
|
unsigned n = r->get_tail_size();
|
||||||
|
accumulate_vars(r->get_head());
|
||||||
|
for (unsigned i=0;i<n;i++) {
|
||||||
|
if (r->get_tail(i) != t) {
|
||||||
|
accumulate_vars(r->get_tail(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return finalize_collect_vars();
|
||||||
|
}
|
||||||
|
|
||||||
|
var_idx_set& rule_manager::collect_rule_vars(rule * r) {
|
||||||
|
reset_collect_vars();
|
||||||
|
unsigned n = r->get_tail_size();
|
||||||
|
accumulate_vars(r->get_head());
|
||||||
|
for (unsigned i=0;i<n;i++) {
|
||||||
|
accumulate_vars(r->get_tail(i));
|
||||||
|
}
|
||||||
|
return finalize_collect_vars();
|
||||||
|
}
|
||||||
|
|
||||||
|
void rule_manager::accumulate_vars(expr* e) {
|
||||||
|
::get_free_vars(m_mark, m_todo, e, m_vars);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void rule_manager::mk_rule(expr* fml, proof* p, rule_set& rules, symbol const& name) {
|
void rule_manager::mk_rule(expr* fml, proof* p, rule_set& rules, symbol const& name) {
|
||||||
scoped_proof_mode _sc(m, m_ctx.generate_proof_trace()?PGM_FINE:PGM_DISABLED);
|
scoped_proof_mode _sc(m, m_ctx.generate_proof_trace()?PGM_FINE:PGM_DISABLED);
|
||||||
|
@ -125,13 +185,13 @@ namespace datalog {
|
||||||
}
|
}
|
||||||
|
|
||||||
void rule_manager::mk_rule_core(expr* fml, proof* p, rule_set& rules, symbol const& name) {
|
void rule_manager::mk_rule_core(expr* fml, proof* p, rule_set& rules, symbol const& name) {
|
||||||
hnf h(m);
|
|
||||||
expr_ref_vector fmls(m);
|
expr_ref_vector fmls(m);
|
||||||
proof_ref_vector prs(m);
|
proof_ref_vector prs(m);
|
||||||
h.set_name(name);
|
m_hnf.reset();
|
||||||
h(fml, p, fmls, prs);
|
m_hnf.set_name(name);
|
||||||
for (unsigned i = 0; i < h.get_fresh_predicates().size(); ++i) {
|
m_hnf(fml, p, fmls, prs);
|
||||||
m_ctx.register_predicate(h.get_fresh_predicates()[i], false);
|
for (unsigned i = 0; i < m_hnf.get_fresh_predicates().size(); ++i) {
|
||||||
|
m_ctx.register_predicate(m_hnf.get_fresh_predicates()[i], false);
|
||||||
}
|
}
|
||||||
for (unsigned i = 0; i < fmls.size(); ++i) {
|
for (unsigned i = 0; i < fmls.size(); ++i) {
|
||||||
mk_horn_rule(fmls[i].get(), prs[i].get(), rules, name);
|
mk_horn_rule(fmls[i].get(), prs[i].get(), rules, name);
|
||||||
|
@ -140,24 +200,23 @@ namespace datalog {
|
||||||
|
|
||||||
void rule_manager::mk_horn_rule(expr* fml, proof* p, rule_set& rules, symbol const& name) {
|
void rule_manager::mk_horn_rule(expr* fml, proof* p, rule_set& rules, symbol const& name) {
|
||||||
|
|
||||||
app_ref_vector body(m);
|
m_body.reset();
|
||||||
app_ref head(m);
|
m_neg.reset();
|
||||||
svector<bool> is_negated;
|
unsigned index = extract_horn(fml, m_body, m_head);
|
||||||
unsigned index = extract_horn(fml, body, head);
|
hoist_compound_predicates(index, m_head, m_body);
|
||||||
hoist_compound_predicates(index, head, body);
|
|
||||||
TRACE("dl_rule",
|
TRACE("dl_rule",
|
||||||
tout << mk_pp(head, m) << " :- ";
|
tout << mk_pp(m_head, m) << " :- ";
|
||||||
for (unsigned i = 0; i < body.size(); ++i) {
|
for (unsigned i = 0; i < m_body.size(); ++i) {
|
||||||
tout << mk_pp(body[i].get(), m) << " ";
|
tout << mk_pp(m_body[i].get(), m) << " ";
|
||||||
}
|
}
|
||||||
tout << "\n";);
|
tout << "\n";);
|
||||||
|
|
||||||
|
|
||||||
mk_negations(body, is_negated);
|
mk_negations(m_body, m_neg);
|
||||||
check_valid_rule(head, body.size(), body.c_ptr());
|
check_valid_rule(m_head, m_body.size(), m_body.c_ptr());
|
||||||
|
|
||||||
rule_ref r(*this);
|
rule_ref r(*this);
|
||||||
r = mk(head.get(), body.size(), body.c_ptr(), is_negated.c_ptr(), name);
|
r = mk(m_head.get(), m_body.size(), m_body.c_ptr(), m_neg.c_ptr(), name);
|
||||||
|
|
||||||
expr_ref fml1(m);
|
expr_ref fml1(m);
|
||||||
if (p) {
|
if (p) {
|
||||||
|
@ -326,28 +385,28 @@ namespace datalog {
|
||||||
fml = m.mk_not(fml);
|
fml = m.mk_not(fml);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
expr_ref_vector args(m);
|
|
||||||
if (!m_ctx.is_predicate(fml)) {
|
if (!m_ctx.is_predicate(fml)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
m_args.reset();
|
||||||
for (unsigned i = 0; i < fml->get_num_args(); ++i) {
|
for (unsigned i = 0; i < fml->get_num_args(); ++i) {
|
||||||
e = fml->get_arg(i);
|
e = fml->get_arg(i);
|
||||||
if (!is_app(e)) {
|
if (!is_app(e)) {
|
||||||
args.push_back(e);
|
m_args.push_back(e);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
app* b = to_app(e);
|
app* b = to_app(e);
|
||||||
|
|
||||||
if (m.is_value(b)) {
|
if (m.is_value(b)) {
|
||||||
args.push_back(e);
|
m_args.push_back(e);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
var* v = m.mk_var(num_bound++, m.get_sort(b));
|
var* v = m.mk_var(num_bound++, m.get_sort(b));
|
||||||
args.push_back(v);
|
m_args.push_back(v);
|
||||||
body.push_back(m.mk_eq(v, b));
|
body.push_back(m.mk_eq(v, b));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fml = m.mk_app(fml->get_decl(), args.size(), args.c_ptr());
|
fml = m.mk_app(fml->get_decl(), m_args.size(), m_args.c_ptr());
|
||||||
TRACE("dl_rule", tout << mk_pp(fml.get(), m) << "\n";);
|
TRACE("dl_rule", tout << mk_pp(fml.get(), m) << "\n";);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -511,29 +570,22 @@ namespace datalog {
|
||||||
void rule_manager::reduce_unbound_vars(rule_ref& r) {
|
void rule_manager::reduce_unbound_vars(rule_ref& r) {
|
||||||
unsigned ut_len = r->get_uninterpreted_tail_size();
|
unsigned ut_len = r->get_uninterpreted_tail_size();
|
||||||
unsigned t_len = r->get_tail_size();
|
unsigned t_len = r->get_tail_size();
|
||||||
ptr_vector<sort> vars;
|
|
||||||
uint_set index_set;
|
|
||||||
qe_lite qe(m);
|
|
||||||
expr_ref_vector conjs(m);
|
expr_ref_vector conjs(m);
|
||||||
|
|
||||||
if (ut_len == t_len) {
|
if (ut_len == t_len) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
get_free_vars(r->get_head(), vars);
|
reset_collect_vars();
|
||||||
|
accumulate_vars(r->get_head());
|
||||||
for (unsigned i = 0; i < ut_len; ++i) {
|
for (unsigned i = 0; i < ut_len; ++i) {
|
||||||
get_free_vars(r->get_tail(i), vars);
|
accumulate_vars(r->get_tail(i));
|
||||||
}
|
}
|
||||||
|
var_idx_set& index_set = finalize_collect_vars();
|
||||||
for (unsigned i = ut_len; i < t_len; ++i) {
|
for (unsigned i = ut_len; i < t_len; ++i) {
|
||||||
conjs.push_back(r->get_tail(i));
|
conjs.push_back(r->get_tail(i));
|
||||||
}
|
}
|
||||||
|
m_qe(index_set, false, conjs);
|
||||||
for (unsigned i = 0; i < vars.size(); ++i) {
|
|
||||||
if (vars[i]) {
|
|
||||||
index_set.insert(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
qe(index_set, false, conjs);
|
|
||||||
bool change = conjs.size() != t_len - ut_len;
|
bool change = conjs.size() != t_len - ut_len;
|
||||||
for (unsigned i = 0; !change && i < conjs.size(); ++i) {
|
for (unsigned i = 0; !change && i < conjs.size(); ++i) {
|
||||||
change = r->get_tail(ut_len+i) != conjs[i].get();
|
change = r->get_tail(ut_len+i) != conjs[i].get();
|
||||||
|
@ -570,15 +622,14 @@ namespace datalog {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ptr_vector<sort> free_rule_vars;
|
|
||||||
var_counter vctr;
|
var_counter vctr;
|
||||||
app_ref_vector tail(m);
|
app_ref_vector tail(m);
|
||||||
svector<bool> tail_neg;
|
svector<bool> tail_neg;
|
||||||
app_ref head(r->get_head(), m);
|
app_ref head(r->get_head(), m);
|
||||||
|
|
||||||
get_free_vars(r, free_rule_vars);
|
collect_rule_vars(r);
|
||||||
vctr.count_vars(m, head);
|
vctr.count_vars(m, head);
|
||||||
|
ptr_vector<sort>& free_rule_vars = m_vars;
|
||||||
|
|
||||||
for (unsigned i = 0; i < ut_len; i++) {
|
for (unsigned i = 0; i < ut_len; i++) {
|
||||||
app * t = r->get_tail(i);
|
app * t = r->get_tail(i);
|
||||||
|
@ -906,7 +957,7 @@ namespace datalog {
|
||||||
}
|
}
|
||||||
|
|
||||||
void rule::norm_vars(rule_manager & rm) {
|
void rule::norm_vars(rule_manager & rm) {
|
||||||
used_vars used;
|
used_vars& used = rm.reset_used();
|
||||||
get_used_vars(used);
|
get_used_vars(used);
|
||||||
|
|
||||||
unsigned first_unsused = used.get_max_found_var_idx_plus_1();
|
unsigned first_unsused = used.get_max_found_var_idx_plus_1();
|
||||||
|
@ -1004,16 +1055,14 @@ namespace datalog {
|
||||||
}
|
}
|
||||||
svector<symbol> names;
|
svector<symbol> names;
|
||||||
used_symbols<> us;
|
used_symbols<> us;
|
||||||
|
|
||||||
us(fml);
|
|
||||||
sorts.reverse();
|
|
||||||
|
|
||||||
for (unsigned i = 0; i < sorts.size(); ++i) {
|
for (unsigned i = 0; i < sorts.size(); ++i) {
|
||||||
if (!sorts[i]) {
|
if (!sorts[i]) {
|
||||||
sorts[i] = m.mk_bool_sort();
|
sorts[i] = m.mk_bool_sort();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
us(fml);
|
||||||
|
sorts.reverse();
|
||||||
for (unsigned j = 0, i = 0; i < sorts.size(); ++j) {
|
for (unsigned j = 0, i = 0; i < sorts.size(); ++j) {
|
||||||
for (char c = 'A'; i < sorts.size() && c <= 'Z'; ++c) {
|
for (char c = 'A'; i < sorts.size() && c <= 'Z'; ++c) {
|
||||||
func_decl_ref f(m);
|
func_decl_ref f(m);
|
||||||
|
@ -1067,6 +1116,8 @@ namespace datalog {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template class rewriter_tpl<datalog::rule_manager::remove_label_cfg>;
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,9 @@ Revision History:
|
||||||
#include"proof_converter.h"
|
#include"proof_converter.h"
|
||||||
#include"model_converter.h"
|
#include"model_converter.h"
|
||||||
#include"ast_counter.h"
|
#include"ast_counter.h"
|
||||||
|
#include"rewriter.h"
|
||||||
|
#include"hnf.h"
|
||||||
|
#include"qe_lite.h"
|
||||||
|
|
||||||
namespace datalog {
|
namespace datalog {
|
||||||
|
|
||||||
|
@ -47,9 +50,33 @@ namespace datalog {
|
||||||
*/
|
*/
|
||||||
class rule_manager
|
class rule_manager
|
||||||
{
|
{
|
||||||
|
class remove_label_cfg : public default_rewriter_cfg {
|
||||||
|
family_id m_label_fid;
|
||||||
|
public:
|
||||||
|
remove_label_cfg(ast_manager& m): m_label_fid(m.get_label_family_id()) {}
|
||||||
|
virtual ~remove_label_cfg();
|
||||||
|
|
||||||
|
br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result,
|
||||||
|
proof_ref & result_pr);
|
||||||
|
};
|
||||||
|
|
||||||
ast_manager& m;
|
ast_manager& m;
|
||||||
context& m_ctx;
|
context& m_ctx;
|
||||||
rule_counter m_counter;
|
rule_counter m_counter;
|
||||||
|
used_vars m_used;
|
||||||
|
ptr_vector<sort> m_vars;
|
||||||
|
var_idx_set m_var_idx;
|
||||||
|
ptr_vector<expr> m_todo;
|
||||||
|
ast_mark m_mark;
|
||||||
|
app_ref_vector m_body;
|
||||||
|
app_ref m_head;
|
||||||
|
expr_ref_vector m_args;
|
||||||
|
svector<bool> m_neg;
|
||||||
|
hnf m_hnf;
|
||||||
|
qe_lite m_qe;
|
||||||
|
remove_label_cfg m_cfg;
|
||||||
|
rewriter_tpl<remove_label_cfg> m_rwr;
|
||||||
|
|
||||||
|
|
||||||
// only the context can create a rule_manager
|
// only the context can create a rule_manager
|
||||||
friend class context;
|
friend class context;
|
||||||
|
@ -90,6 +117,10 @@ namespace datalog {
|
||||||
*/
|
*/
|
||||||
void reduce_unbound_vars(rule_ref& r);
|
void reduce_unbound_vars(rule_ref& r);
|
||||||
|
|
||||||
|
void reset_collect_vars();
|
||||||
|
|
||||||
|
var_idx_set& finalize_collect_vars();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
ast_manager& get_manager() const { return m; }
|
ast_manager& get_manager() const { return m; }
|
||||||
|
@ -98,6 +129,24 @@ namespace datalog {
|
||||||
|
|
||||||
void dec_ref(rule * r);
|
void dec_ref(rule * r);
|
||||||
|
|
||||||
|
used_vars& reset_used() { m_used.reset(); return m_used; }
|
||||||
|
|
||||||
|
var_idx_set& collect_vars(expr * pred);
|
||||||
|
|
||||||
|
var_idx_set& collect_vars(expr * e1, expr* e2);
|
||||||
|
|
||||||
|
var_idx_set& collect_rule_vars(rule * r);
|
||||||
|
|
||||||
|
var_idx_set& collect_rule_vars_ex(rule * r, app* t);
|
||||||
|
|
||||||
|
var_idx_set& collect_tail_vars(rule * r);
|
||||||
|
|
||||||
|
void accumulate_vars(expr* pred);
|
||||||
|
|
||||||
|
ptr_vector<sort>& get_var_sorts() { return m_vars; }
|
||||||
|
|
||||||
|
var_idx_set& get_var_idx() { return m_var_idx; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\brief Create a Datalog rule from a Horn formula.
|
\brief Create a Datalog rule from a Horn formula.
|
||||||
The formula is of the form (forall (...) (forall (...) (=> (and ...) head)))
|
The formula is of the form (forall (...) (forall (...) (=> (and ...) head)))
|
||||||
|
|
|
@ -409,9 +409,10 @@ namespace datalog {
|
||||||
}
|
}
|
||||||
|
|
||||||
void rule_set::reopen() {
|
void rule_set::reopen() {
|
||||||
SASSERT(is_closed());
|
if (is_closed()) {
|
||||||
m_stratifier = 0;
|
m_stratifier = 0;
|
||||||
m_deps.reset();
|
m_deps.reset();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -567,8 +567,7 @@ namespace datalog {
|
||||||
const relation_signature sig = r.get_signature();
|
const relation_signature sig = r.get_signature();
|
||||||
unsigned sz = sig.size();
|
unsigned sz = sig.size();
|
||||||
|
|
||||||
var_idx_set cond_vars;
|
var_idx_set& cond_vars = get_context().get_rule_manager().collect_vars(condition);
|
||||||
collect_vars(m, condition, cond_vars);
|
|
||||||
expr_ref_vector subst_vect(m);
|
expr_ref_vector subst_vect(m);
|
||||||
subst_vect.resize(sz);
|
subst_vect.resize(sz);
|
||||||
unsigned subst_ofs = sz-1;
|
unsigned subst_ofs = sz-1;
|
||||||
|
|
|
@ -52,7 +52,7 @@ namespace datalog {
|
||||||
|
|
||||||
struct hash {
|
struct hash {
|
||||||
unsigned operator()(const rel_spec & s) const {
|
unsigned operator()(const rel_spec & s) const {
|
||||||
return int_vector_hash(s.m_inner_cols)^s.m_inner_kind;
|
return svector_hash<bool_hash>()(s.m_inner_cols)^s.m_inner_kind;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -359,7 +359,7 @@ namespace datalog {
|
||||||
|
|
||||||
typedef svector<unsigned> key_spec; //sequence of columns in a key
|
typedef svector<unsigned> key_spec; //sequence of columns in a key
|
||||||
typedef svector<table_element> key_value; //values of key columns
|
typedef svector<table_element> key_value; //values of key columns
|
||||||
typedef map<key_spec, key_indexer*, int_vector_hash_proc<key_spec>,
|
typedef map<key_spec, key_indexer*, svector_hash_proc<unsigned_hash>,
|
||||||
vector_eq_proc<key_spec> > key_index_map;
|
vector_eq_proc<key_spec> > key_index_map;
|
||||||
|
|
||||||
static const store_offset NO_RESERVE = UINT_MAX;
|
static const store_offset NO_RESERVE = UINT_MAX;
|
||||||
|
|
|
@ -73,7 +73,7 @@ namespace datalog {
|
||||||
|
|
||||||
class our_iterator_core;
|
class our_iterator_core;
|
||||||
|
|
||||||
typedef hashtable<table_fact, int_vector_hash_proc<table_fact>,
|
typedef hashtable<table_fact, svector_hash_proc<table_element_hash>,
|
||||||
vector_eq_proc<table_fact> > storage;
|
vector_eq_proc<table_fact> > storage;
|
||||||
|
|
||||||
storage m_data;
|
storage m_data;
|
||||||
|
|
|
@ -158,36 +158,7 @@ namespace datalog {
|
||||||
::get_free_vars(trm, vars);
|
::get_free_vars(trm, vars);
|
||||||
return var_idx < vars.size() && vars[var_idx] != 0;
|
return var_idx < vars.size() && vars[var_idx] != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void collect_vars(ast_manager & m, expr * e, var_idx_set & result) {
|
|
||||||
ptr_vector<sort> vars;
|
|
||||||
::get_free_vars(e, vars);
|
|
||||||
unsigned sz = vars.size();
|
|
||||||
for(unsigned i=0; i<sz; ++i) {
|
|
||||||
if(vars[i]) { result.insert(i); }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void collect_tail_vars(ast_manager & m, rule * r, var_idx_set & result) {
|
|
||||||
unsigned n = r->get_tail_size();
|
|
||||||
for(unsigned i=0;i<n;i++) {
|
|
||||||
collect_vars(m, r->get_tail(i), result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void get_free_tail_vars(rule * r, ptr_vector<sort>& sorts) {
|
|
||||||
unsigned n = r->get_tail_size();
|
|
||||||
for(unsigned i=0;i<n;i++) {
|
|
||||||
get_free_vars(r->get_tail(i), sorts);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void get_free_vars(rule * r, ptr_vector<sort>& sorts) {
|
|
||||||
get_free_vars(r->get_head(), sorts);
|
|
||||||
get_free_tail_vars(r, sorts);
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned count_variable_arguments(app * pred)
|
unsigned count_variable_arguments(app * pred)
|
||||||
{
|
{
|
||||||
SASSERT(is_uninterp(pred));
|
SASSERT(is_uninterp(pred));
|
||||||
|
@ -202,26 +173,6 @@ namespace datalog {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
void collect_non_local_vars(ast_manager & m, rule const * r, app * t, var_idx_set & result) {
|
|
||||||
collect_vars(m, r->get_head(), result);
|
|
||||||
unsigned sz = r->get_tail_size();
|
|
||||||
for (unsigned i = 0; i < sz; i++) {
|
|
||||||
app * curr = r->get_tail(i);
|
|
||||||
if (curr != t)
|
|
||||||
collect_vars(m, curr, result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void collect_non_local_vars(ast_manager & m, rule const * r, app * t_1, app * t_2, var_idx_set & result) {
|
|
||||||
collect_vars(m, r->get_head(), result);
|
|
||||||
unsigned sz = r->get_tail_size();
|
|
||||||
for (unsigned i = 0; i < sz; i++) {
|
|
||||||
app * curr = r->get_tail(i);
|
|
||||||
if (curr != t_1 && curr != t_2)
|
|
||||||
collect_vars(m, curr, result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void mk_new_rule_tail(ast_manager & m, app * pred, var_idx_set const & non_local_vars, unsigned & next_idx, varidx2var_map & varidx2var,
|
void mk_new_rule_tail(ast_manager & m, app * pred, var_idx_set const & non_local_vars, unsigned & next_idx, varidx2var_map & varidx2var,
|
||||||
sort_ref_buffer & new_rule_domain, expr_ref_buffer & new_rule_args, app_ref & new_pred) {
|
sort_ref_buffer & new_rule_domain, expr_ref_buffer & new_rule_args, app_ref & new_pred) {
|
||||||
expr_ref_buffer new_args(m);
|
expr_ref_buffer new_args(m);
|
||||||
|
@ -404,6 +355,7 @@ namespace datalog {
|
||||||
|
|
||||||
|
|
||||||
void rule_counter::count_rule_vars(ast_manager & m, const rule * r, int coef) {
|
void rule_counter::count_rule_vars(ast_manager & m, const rule * r, int coef) {
|
||||||
|
reset();
|
||||||
count_vars(m, r->get_head(), 1);
|
count_vars(m, r->get_head(), 1);
|
||||||
unsigned n = r->get_tail_size();
|
unsigned n = r->get_tail_size();
|
||||||
for (unsigned i = 0; i < n; i++) {
|
for (unsigned i = 0; i < n; i++) {
|
||||||
|
|
|
@ -54,6 +54,7 @@ namespace datalog {
|
||||||
BMC_ENGINE,
|
BMC_ENGINE,
|
||||||
QBMC_ENGINE,
|
QBMC_ENGINE,
|
||||||
TAB_ENGINE,
|
TAB_ENGINE,
|
||||||
|
CLP_ENGINE,
|
||||||
LAST_ENGINE
|
LAST_ENGINE
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -81,33 +82,13 @@ namespace datalog {
|
||||||
|
|
||||||
void flatten_or(expr* fml, expr_ref_vector& result);
|
void flatten_or(expr* fml, expr_ref_vector& result);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool contains_var(expr * trm, unsigned var_idx);
|
bool contains_var(expr * trm, unsigned var_idx);
|
||||||
|
|
||||||
/**
|
|
||||||
\brief Collect the variables in \c pred.
|
|
||||||
\pre \c pred must be a valid head or tail.
|
|
||||||
*/
|
|
||||||
void collect_vars(ast_manager & m, expr * pred, var_idx_set & result);
|
|
||||||
void collect_tail_vars(ast_manager & m, rule * r, var_idx_set & result);
|
|
||||||
|
|
||||||
void get_free_vars(rule * r, ptr_vector<sort>& sorts);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\brief Return number of arguments of \c pred that are variables
|
\brief Return number of arguments of \c pred that are variables
|
||||||
*/
|
*/
|
||||||
unsigned count_variable_arguments(app * pred);
|
unsigned count_variable_arguments(app * pred);
|
||||||
|
|
||||||
/**
|
|
||||||
\brief Store in \c result the set of variables used by \c r when ignoring the tail \c t.
|
|
||||||
*/
|
|
||||||
void collect_non_local_vars(ast_manager & m, rule const * r, app * t, var_idx_set & result);
|
|
||||||
|
|
||||||
/**
|
|
||||||
\brief Store in \c result the set of variables used by \c r when ignoring the tail elements \c t_1 and \c t_2.
|
|
||||||
*/
|
|
||||||
void collect_non_local_vars(ast_manager & m, rule const * r, app * t_1, app * t_2, var_idx_set & result);
|
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void copy_nonvariables(app * src, T& tgt)
|
void copy_nonvariables(app * src, T& tgt)
|
||||||
|
@ -207,7 +188,9 @@ namespace datalog {
|
||||||
static unsigned expr_cont_get_size(app * a) { return a->get_num_args(); }
|
static unsigned expr_cont_get_size(app * a) { return a->get_num_args(); }
|
||||||
static expr * expr_cont_get(app * a, unsigned i) { return a->get_arg(i); }
|
static expr * expr_cont_get(app * a, unsigned i) { return a->get_arg(i); }
|
||||||
static unsigned expr_cont_get_size(const ptr_vector<expr> & v) { return v.size(); }
|
static unsigned expr_cont_get_size(const ptr_vector<expr> & v) { return v.size(); }
|
||||||
|
static unsigned expr_cont_get_size(const expr_ref_vector & v) { return v.size(); }
|
||||||
static expr * expr_cont_get(const ptr_vector<expr> & v, unsigned i) { return v[i]; }
|
static expr * expr_cont_get(const ptr_vector<expr> & v, unsigned i) { return v[i]; }
|
||||||
|
static expr * expr_cont_get(const expr_ref_vector & v, unsigned i) { return v[i]; }
|
||||||
public:
|
public:
|
||||||
variable_intersection(ast_manager & m) : m_consts(m) {}
|
variable_intersection(ast_manager & m) : m_consts(m) {}
|
||||||
|
|
||||||
|
@ -585,17 +568,31 @@ namespace datalog {
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
unsigned int_vector_hash(const T & cont) {
|
struct default_obj_chash {
|
||||||
return string_hash(reinterpret_cast<const char *>(cont.c_ptr()),
|
unsigned operator()(T const& cont, unsigned i) const {
|
||||||
cont.size()*sizeof(typename T::data), 0);
|
return cont[i]->hash();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
template<class T>
|
||||||
|
unsigned obj_vector_hash(const T & cont) {
|
||||||
|
return get_composite_hash(cont, cont.size(),default_kind_hash_proc<T>(), default_obj_chash<T>());
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
struct int_vector_hash_proc {
|
struct obj_vector_hash_proc {
|
||||||
unsigned operator()(const T & cont) const {
|
unsigned operator()(const T & cont) const {
|
||||||
return int_vector_hash(cont);
|
return obj_vector_hash(cont);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
struct svector_hash_proc {
|
||||||
|
unsigned operator()(const svector<typename T::data> & cont) const {
|
||||||
|
return svector_hash<T>()(cont);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
struct vector_eq_proc {
|
struct vector_eq_proc {
|
||||||
bool operator()(const T & c1, const T & c2) const { return vectors_equal(c1, c2); }
|
bool operator()(const T & c1, const T & c2) const { return vectors_equal(c1, c2); }
|
||||||
|
@ -763,11 +760,6 @@ namespace datalog {
|
||||||
//
|
//
|
||||||
// -----------------------------------
|
// -----------------------------------
|
||||||
|
|
||||||
struct uint64_hash {
|
|
||||||
typedef uint64 data;
|
|
||||||
unsigned operator()(uint64 x) const { return hash_ull(x); }
|
|
||||||
};
|
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
void universal_delete(T* ptr) {
|
void universal_delete(T* ptr) {
|
||||||
dealloc(ptr);
|
dealloc(ptr);
|
||||||
|
|
|
@ -13,7 +13,6 @@ def_module_params('fixedpoint',
|
||||||
('unbound_compressor', BOOL, True, "auxiliary relations will be introduced to avoid unbound variables in rule heads"),
|
('unbound_compressor', BOOL, True, "auxiliary relations will be introduced to avoid unbound variables in rule heads"),
|
||||||
('similarity_compressor', BOOL, True, "(DATALOG) rules that differ only in values of constants will be merged into a single rule"),
|
('similarity_compressor', BOOL, True, "(DATALOG) rules that differ only in values of constants will be merged into a single rule"),
|
||||||
('similarity_compressor_threshold', UINT, 11, "(DATALOG) if similarity_compressor is on, this value determines how many similar rules there must be in order for them to be merged"),
|
('similarity_compressor_threshold', UINT, 11, "(DATALOG) if similarity_compressor is on, this value determines how many similar rules there must be in order for them to be merged"),
|
||||||
('filter_rules', BOOL, True, "(DATALOG) apply filter compression on rules"),
|
|
||||||
('all_or_nothing_deltas', BOOL, False, "(DATALOG) compile rules so that it is enough for the delta relation in union and widening operations to determine only whether the updated relation was modified or not"),
|
('all_or_nothing_deltas', BOOL, False, "(DATALOG) compile rules so that it is enough for the delta relation in union and widening operations to determine only whether the updated relation was modified or not"),
|
||||||
('compile_with_widening', BOOL, False, "(DATALOG) widening will be used to compile recursive rules"),
|
('compile_with_widening', BOOL, False, "(DATALOG) widening will be used to compile recursive rules"),
|
||||||
('eager_emptiness_checking', BOOL, True, "(DATALOG) emptiness of affected relations will be checked after each instruction, so that we may ommit unnecessary instructions"),
|
('eager_emptiness_checking', BOOL, True, "(DATALOG) emptiness of affected relations will be checked after each instruction, so that we may ommit unnecessary instructions"),
|
||||||
|
@ -61,6 +60,7 @@ def_module_params('fixedpoint',
|
||||||
('print_answer', BOOL, False, 'print answer instance(s) to query'),
|
('print_answer', BOOL, False, 'print answer instance(s) to query'),
|
||||||
('print_certificate', BOOL, False, 'print certificate for reachability or non-reachability'),
|
('print_certificate', BOOL, False, 'print certificate for reachability or non-reachability'),
|
||||||
('print_statistics', BOOL, False, 'print statistics'),
|
('print_statistics', BOOL, False, 'print statistics'),
|
||||||
|
('use_utvpi', BOOL, False, 'experimental use UTVPI strategy'),
|
||||||
('tab_selection', SYMBOL, 'weight', 'selection method for tabular strategy: weight (default), first, var-use'),
|
('tab_selection', SYMBOL, 'weight', 'selection method for tabular strategy: weight (default), first, var-use'),
|
||||||
))
|
))
|
||||||
|
|
||||||
|
|
|
@ -71,6 +71,9 @@ class hnf::imp {
|
||||||
obj_map<expr, app*> m_memoize_disj;
|
obj_map<expr, app*> m_memoize_disj;
|
||||||
obj_map<expr, proof*> m_memoize_proof;
|
obj_map<expr, proof*> m_memoize_proof;
|
||||||
func_decl_ref_vector m_fresh_predicates;
|
func_decl_ref_vector m_fresh_predicates;
|
||||||
|
expr_ref_vector m_body;
|
||||||
|
proof_ref_vector m_defs;
|
||||||
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
imp(ast_manager & m):
|
imp(ast_manager & m):
|
||||||
|
@ -82,7 +85,9 @@ public:
|
||||||
m_refs(m),
|
m_refs(m),
|
||||||
m_name("P"),
|
m_name("P"),
|
||||||
m_qh(m),
|
m_qh(m),
|
||||||
m_fresh_predicates(m) {
|
m_fresh_predicates(m),
|
||||||
|
m_body(m),
|
||||||
|
m_defs(m) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void operator()(expr * n,
|
void operator()(expr * n,
|
||||||
|
@ -181,14 +186,15 @@ private:
|
||||||
|
|
||||||
|
|
||||||
void mk_horn(expr_ref& fml, proof_ref& premise) {
|
void mk_horn(expr_ref& fml, proof_ref& premise) {
|
||||||
|
SASSERT(!premise || fml == m.get_fact(premise));
|
||||||
expr* e1, *e2;
|
expr* e1, *e2;
|
||||||
expr_ref_vector body(m);
|
|
||||||
proof_ref_vector defs(m);
|
|
||||||
expr_ref fml0(m), fml1(m), fml2(m), head(m);
|
expr_ref fml0(m), fml1(m), fml2(m), head(m);
|
||||||
proof_ref p(m);
|
proof_ref p(m);
|
||||||
fml0 = fml;
|
fml0 = fml;
|
||||||
m_names.reset();
|
m_names.reset();
|
||||||
m_sorts.reset();
|
m_sorts.reset();
|
||||||
|
m_body.reset();
|
||||||
|
m_defs.reset();
|
||||||
m_qh.pull_quantifier(true, fml0, &m_sorts, &m_names);
|
m_qh.pull_quantifier(true, fml0, &m_sorts, &m_names);
|
||||||
if (premise){
|
if (premise){
|
||||||
fml1 = bind_variables(fml0);
|
fml1 = bind_variables(fml0);
|
||||||
|
@ -199,12 +205,12 @@ private:
|
||||||
}
|
}
|
||||||
head = fml0;
|
head = fml0;
|
||||||
while (m.is_implies(head, e1, e2)) {
|
while (m.is_implies(head, e1, e2)) {
|
||||||
body.push_back(e1);
|
m_body.push_back(e1);
|
||||||
head = e2;
|
head = e2;
|
||||||
}
|
}
|
||||||
datalog::flatten_and(body);
|
datalog::flatten_and(m_body);
|
||||||
if (premise) {
|
if (premise) {
|
||||||
p = m.mk_rewrite(fml0, mk_implies(body, head));
|
p = m.mk_rewrite(fml0, mk_implies(m_body, head));
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -214,8 +220,8 @@ private:
|
||||||
// A -> C
|
// A -> C
|
||||||
// B -> C
|
// B -> C
|
||||||
//
|
//
|
||||||
if (body.size() == 1 && m.is_or(body[0].get()) && contains_predicate(body[0].get())) {
|
if (m_body.size() == 1 && m.is_or(m_body[0].get()) && contains_predicate(m_body[0].get())) {
|
||||||
app* _or = to_app(body[0].get());
|
app* _or = to_app(m_body[0].get());
|
||||||
unsigned sz = _or->get_num_args();
|
unsigned sz = _or->get_num_args();
|
||||||
expr* const* args = _or->get_args();
|
expr* const* args = _or->get_args();
|
||||||
for (unsigned i = 0; i < sz; ++i) {
|
for (unsigned i = 0; i < sz; ++i) {
|
||||||
|
@ -224,7 +230,7 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
if (premise) {
|
if (premise) {
|
||||||
expr_ref f1 = bind_variables(mk_implies(body, head));
|
expr_ref f1 = bind_variables(mk_implies(m_body, head));
|
||||||
expr* f2 = m.mk_and(sz, m_todo.c_ptr()+m_todo.size()-sz);
|
expr* f2 = m.mk_and(sz, m_todo.c_ptr()+m_todo.size()-sz);
|
||||||
proof_ref p2(m), p3(m);
|
proof_ref p2(m), p3(m);
|
||||||
p2 = m.mk_def_axiom(m.mk_iff(f1, f2));
|
p2 = m.mk_def_axiom(m.mk_iff(f1, f2));
|
||||||
|
@ -240,13 +246,13 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
eliminate_disjunctions(body, defs);
|
eliminate_disjunctions(m_body, m_defs);
|
||||||
p = mk_congruence(p, body, head, defs);
|
p = mk_congruence(p, m_body, head, m_defs);
|
||||||
|
|
||||||
eliminate_quantifier_body(body, defs);
|
eliminate_quantifier_body(m_body, m_defs);
|
||||||
p = mk_congruence(p, body, head, defs);
|
p = mk_congruence(p, m_body, head, m_defs);
|
||||||
|
|
||||||
fml2 = mk_implies(body, head);
|
fml2 = mk_implies(m_body, head);
|
||||||
|
|
||||||
fml = bind_variables(fml2);
|
fml = bind_variables(fml2);
|
||||||
|
|
||||||
|
|
|
@ -28,10 +28,8 @@ Revision History:
|
||||||
#include "well_sorted.h"
|
#include "well_sorted.h"
|
||||||
|
|
||||||
void horn_subsume_model_converter::insert(app* head, expr* body) {
|
void horn_subsume_model_converter::insert(app* head, expr* body) {
|
||||||
func_decl_ref pred(m);
|
m_delay_head.push_back(head);
|
||||||
expr_ref body_res(m);
|
m_delay_body.push_back(body);
|
||||||
VERIFY(mk_horn(head, body, pred, body_res));
|
|
||||||
insert(pred.get(), body_res.get());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void horn_subsume_model_converter::insert(app* head, unsigned sz, expr* const* body) {
|
void horn_subsume_model_converter::insert(app* head, unsigned sz, expr* const* body) {
|
||||||
|
@ -148,6 +146,7 @@ bool horn_subsume_model_converter::mk_horn(
|
||||||
}
|
}
|
||||||
|
|
||||||
void horn_subsume_model_converter::add_default_proc::operator()(app* n) {
|
void horn_subsume_model_converter::add_default_proc::operator()(app* n) {
|
||||||
|
|
||||||
//
|
//
|
||||||
// predicates that have not been assigned values
|
// predicates that have not been assigned values
|
||||||
// in the Horn model are assumed false.
|
// in the Horn model are assumed false.
|
||||||
|
@ -174,6 +173,16 @@ void horn_subsume_model_converter::add_default_false_interpretation(expr* e, mod
|
||||||
|
|
||||||
|
|
||||||
void horn_subsume_model_converter::operator()(model_ref& mr) {
|
void horn_subsume_model_converter::operator()(model_ref& mr) {
|
||||||
|
|
||||||
|
func_decl_ref pred(m);
|
||||||
|
expr_ref body_res(m);
|
||||||
|
for (unsigned i = 0; i < m_delay_head.size(); ++i) {
|
||||||
|
VERIFY(mk_horn(m_delay_head[i].get(), m_delay_body[i].get(), pred, body_res));
|
||||||
|
insert(pred.get(), body_res.get());
|
||||||
|
}
|
||||||
|
m_delay_head.reset();
|
||||||
|
m_delay_body.reset();
|
||||||
|
|
||||||
TRACE("mc", tout << m_funcs.size() << "\n"; model_smt2_pp(tout, m, *mr, 0););
|
TRACE("mc", tout << m_funcs.size() << "\n"; model_smt2_pp(tout, m, *mr, 0););
|
||||||
for (unsigned i = m_funcs.size(); i > 0; ) {
|
for (unsigned i = m_funcs.size(); i > 0; ) {
|
||||||
--i;
|
--i;
|
||||||
|
|
|
@ -43,6 +43,8 @@ class horn_subsume_model_converter : public model_converter {
|
||||||
func_decl_ref_vector m_funcs;
|
func_decl_ref_vector m_funcs;
|
||||||
expr_ref_vector m_bodies;
|
expr_ref_vector m_bodies;
|
||||||
th_rewriter m_rewrite;
|
th_rewriter m_rewrite;
|
||||||
|
app_ref_vector m_delay_head;
|
||||||
|
expr_ref_vector m_delay_body;
|
||||||
|
|
||||||
void add_default_false_interpretation(expr* e, model_ref& md);
|
void add_default_false_interpretation(expr* e, model_ref& md);
|
||||||
|
|
||||||
|
@ -56,7 +58,9 @@ class horn_subsume_model_converter : public model_converter {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
horn_subsume_model_converter(ast_manager& m): m(m), m_funcs(m), m_bodies(m), m_rewrite(m) {}
|
horn_subsume_model_converter(ast_manager& m):
|
||||||
|
m(m), m_funcs(m), m_bodies(m), m_rewrite(m),
|
||||||
|
m_delay_head(m), m_delay_body(m) {}
|
||||||
|
|
||||||
bool mk_horn(expr* clause, func_decl_ref& pred, expr_ref& body);
|
bool mk_horn(expr* clause, func_decl_ref& pred, expr_ref& body);
|
||||||
|
|
||||||
|
|
|
@ -125,12 +125,13 @@ class horn_tactic : public tactic {
|
||||||
enum formula_kind { IS_RULE, IS_QUERY, IS_NONE };
|
enum formula_kind { IS_RULE, IS_QUERY, IS_NONE };
|
||||||
|
|
||||||
formula_kind get_formula_kind(expr_ref& f) {
|
formula_kind get_formula_kind(expr_ref& f) {
|
||||||
normalize(f);
|
expr_ref tmp(f);
|
||||||
|
normalize(tmp);
|
||||||
ast_mark mark;
|
ast_mark mark;
|
||||||
expr_ref_vector args(m), body(m);
|
expr_ref_vector args(m), body(m);
|
||||||
expr_ref head(m);
|
expr_ref head(m);
|
||||||
expr* a = 0, *a1 = 0;
|
expr* a = 0, *a1 = 0;
|
||||||
datalog::flatten_or(f, args);
|
datalog::flatten_or(tmp, args);
|
||||||
for (unsigned i = 0; i < args.size(); ++i) {
|
for (unsigned i = 0; i < args.size(); ++i) {
|
||||||
a = args[i].get();
|
a = args[i].get();
|
||||||
check_predicate(mark, a);
|
check_predicate(mark, a);
|
||||||
|
@ -147,12 +148,12 @@ class horn_tactic : public tactic {
|
||||||
body.push_back(m.mk_not(a));
|
body.push_back(m.mk_not(a));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
f = m.mk_and(body.size(), body.c_ptr());
|
|
||||||
if (head) {
|
if (head) {
|
||||||
f = m.mk_implies(f, head);
|
// f = m.mk_implies(f, head);
|
||||||
return IS_RULE;
|
return IS_RULE;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
f = m.mk_and(body.size(), body.c_ptr());
|
||||||
return IS_QUERY;
|
return IS_QUERY;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -171,7 +172,7 @@ class horn_tactic : public tactic {
|
||||||
tactic_report report("horn", *g);
|
tactic_report report("horn", *g);
|
||||||
bool produce_proofs = g->proofs_enabled();
|
bool produce_proofs = g->proofs_enabled();
|
||||||
|
|
||||||
if (produce_proofs) {
|
if (produce_proofs) {
|
||||||
if (!m_ctx.get_params().generate_proof_trace()) {
|
if (!m_ctx.get_params().generate_proof_trace()) {
|
||||||
params_ref params = m_ctx.get_params().p;
|
params_ref params = m_ctx.get_params().p;
|
||||||
params.set_bool("generate_proof_trace", true);
|
params.set_bool("generate_proof_trace", true);
|
||||||
|
@ -239,10 +240,13 @@ class horn_tactic : public tactic {
|
||||||
switch (is_reachable) {
|
switch (is_reachable) {
|
||||||
case l_true: {
|
case l_true: {
|
||||||
// goal is unsat
|
// goal is unsat
|
||||||
g->assert_expr(m.mk_false());
|
|
||||||
if (produce_proofs) {
|
if (produce_proofs) {
|
||||||
proof_ref proof = m_ctx.get_proof();
|
proof_ref proof = m_ctx.get_proof();
|
||||||
pc = proof2proof_converter(m, proof);
|
pc = proof2proof_converter(m, proof);
|
||||||
|
g->assert_expr(m.mk_false(), proof, 0);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
g->assert_expr(m.mk_false());
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,6 +43,7 @@ Notes:
|
||||||
#include "ast_ll_pp.h"
|
#include "ast_ll_pp.h"
|
||||||
#include "proof_checker.h"
|
#include "proof_checker.h"
|
||||||
#include "smt_value_sort.h"
|
#include "smt_value_sort.h"
|
||||||
|
#include "proof_utils.h"
|
||||||
|
|
||||||
namespace pdr {
|
namespace pdr {
|
||||||
|
|
||||||
|
@ -275,7 +276,7 @@ namespace pdr {
|
||||||
src.pop_back();
|
src.pop_back();
|
||||||
}
|
}
|
||||||
else if (is_invariant(tgt_level, curr, false, assumes_level)) {
|
else if (is_invariant(tgt_level, curr, false, assumes_level)) {
|
||||||
|
|
||||||
add_property(curr, assumes_level?tgt_level:infty_level);
|
add_property(curr, assumes_level?tgt_level:infty_level);
|
||||||
TRACE("pdr", tout << "is invariant: "<< pp_level(tgt_level) << " " << mk_pp(curr, m) << "\n";);
|
TRACE("pdr", tout << "is invariant: "<< pp_level(tgt_level) << " " << mk_pp(curr, m) << "\n";);
|
||||||
src[i] = src.back();
|
src[i] = src.back();
|
||||||
|
@ -596,7 +597,7 @@ namespace pdr {
|
||||||
expr_ref fml = pm.mk_and(conj);
|
expr_ref fml = pm.mk_and(conj);
|
||||||
th_rewriter rw(m);
|
th_rewriter rw(m);
|
||||||
rw(fml);
|
rw(fml);
|
||||||
if (ctx.is_dl()) {
|
if (ctx.is_dl() || ctx.is_utvpi()) {
|
||||||
hoist_non_bool_if(fml);
|
hoist_non_bool_if(fml);
|
||||||
}
|
}
|
||||||
TRACE("pdr", tout << mk_pp(fml, m) << "\n";);
|
TRACE("pdr", tout << mk_pp(fml, m) << "\n";);
|
||||||
|
@ -1225,6 +1226,7 @@ namespace pdr {
|
||||||
m_search(m_params.bfs_model_search()),
|
m_search(m_params.bfs_model_search()),
|
||||||
m_last_result(l_undef),
|
m_last_result(l_undef),
|
||||||
m_inductive_lvl(0),
|
m_inductive_lvl(0),
|
||||||
|
m_expanded_lvl(0),
|
||||||
m_cancel(false)
|
m_cancel(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -1357,9 +1359,10 @@ namespace pdr {
|
||||||
bool m_is_bool_arith;
|
bool m_is_bool_arith;
|
||||||
bool m_has_arith;
|
bool m_has_arith;
|
||||||
bool m_is_dl;
|
bool m_is_dl;
|
||||||
|
bool m_is_utvpi;
|
||||||
public:
|
public:
|
||||||
classifier_proc(ast_manager& m, datalog::rule_set& rules):
|
classifier_proc(ast_manager& m, datalog::rule_set& rules):
|
||||||
m(m), a(m), m_is_bool(true), m_is_bool_arith(true), m_has_arith(false), m_is_dl(false) {
|
m(m), a(m), m_is_bool(true), m_is_bool_arith(true), m_has_arith(false), m_is_dl(false), m_is_utvpi(false) {
|
||||||
classify(rules);
|
classify(rules);
|
||||||
}
|
}
|
||||||
void operator()(expr* e) {
|
void operator()(expr* e) {
|
||||||
|
@ -1405,6 +1408,7 @@ namespace pdr {
|
||||||
|
|
||||||
bool is_dl() const { return m_is_dl; }
|
bool is_dl() const { return m_is_dl; }
|
||||||
|
|
||||||
|
bool is_utvpi() const { return m_is_utvpi; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
@ -1425,6 +1429,7 @@ namespace pdr {
|
||||||
mark.reset();
|
mark.reset();
|
||||||
|
|
||||||
m_is_dl = false;
|
m_is_dl = false;
|
||||||
|
m_is_utvpi = false;
|
||||||
if (m_has_arith) {
|
if (m_has_arith) {
|
||||||
ptr_vector<expr> forms;
|
ptr_vector<expr> forms;
|
||||||
for (it = rules.begin(); it != end; ++it) {
|
for (it = rules.begin(); it != end; ++it) {
|
||||||
|
@ -1436,6 +1441,7 @@ namespace pdr {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
m_is_dl = is_difference_logic(m, forms.size(), forms.c_ptr());
|
m_is_dl = is_difference_logic(m, forms.size(), forms.c_ptr());
|
||||||
|
m_is_utvpi = m_is_dl || is_utvpi_logic(m, forms.size(), forms.c_ptr());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1555,7 +1561,12 @@ namespace pdr {
|
||||||
m_fparams.m_arith_auto_config_simplex = true;
|
m_fparams.m_arith_auto_config_simplex = true;
|
||||||
m_fparams.m_arith_propagate_eqs = false;
|
m_fparams.m_arith_propagate_eqs = false;
|
||||||
m_fparams.m_arith_eager_eq_axioms = false;
|
m_fparams.m_arith_eager_eq_axioms = false;
|
||||||
if (classify.is_dl()) {
|
if (classify.is_utvpi() && m_params.use_utvpi()) {
|
||||||
|
IF_VERBOSE(1, verbose_stream() << "UTVPI\n";);
|
||||||
|
m_fparams.m_arith_mode = AS_UTVPI;
|
||||||
|
m_fparams.m_arith_expand_eqs = true;
|
||||||
|
}
|
||||||
|
else if (classify.is_dl()) {
|
||||||
m_fparams.m_arith_mode = AS_DIFF_LOGIC;
|
m_fparams.m_arith_mode = AS_DIFF_LOGIC;
|
||||||
m_fparams.m_arith_expand_eqs = true;
|
m_fparams.m_arith_expand_eqs = true;
|
||||||
}
|
}
|
||||||
|
@ -1680,6 +1691,9 @@ namespace pdr {
|
||||||
proof = m_search.get_proof_trace(*this);
|
proof = m_search.get_proof_trace(*this);
|
||||||
TRACE("pdr", tout << "PDR trace: " << mk_pp(proof, m) << "\n";);
|
TRACE("pdr", tout << "PDR trace: " << mk_pp(proof, m) << "\n";);
|
||||||
apply(m, m_pc.get(), proof);
|
apply(m, m_pc.get(), proof);
|
||||||
|
TRACE("pdr", tout << "PDR trace: " << mk_pp(proof, m) << "\n";);
|
||||||
|
// proof_utils::push_instantiations_up(proof);
|
||||||
|
// TRACE("pdr", tout << "PDR up: " << mk_pp(proof, m) << "\n";);
|
||||||
return proof;
|
return proof;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1711,6 +1725,7 @@ namespace pdr {
|
||||||
bool reachable;
|
bool reachable;
|
||||||
while (true) {
|
while (true) {
|
||||||
checkpoint();
|
checkpoint();
|
||||||
|
m_expanded_lvl = lvl;
|
||||||
reachable = check_reachability(lvl);
|
reachable = check_reachability(lvl);
|
||||||
if (reachable) {
|
if (reachable) {
|
||||||
throw model_exception();
|
throw model_exception();
|
||||||
|
@ -1769,6 +1784,10 @@ namespace pdr {
|
||||||
void context::expand_node(model_node& n) {
|
void context::expand_node(model_node& n) {
|
||||||
SASSERT(n.is_open());
|
SASSERT(n.is_open());
|
||||||
expr_ref_vector cube(m);
|
expr_ref_vector cube(m);
|
||||||
|
|
||||||
|
if (n.level() < m_expanded_lvl) {
|
||||||
|
m_expanded_lvl = n.level();
|
||||||
|
}
|
||||||
|
|
||||||
if (n.pt().is_reachable(n.state())) {
|
if (n.pt().is_reachable(n.state())) {
|
||||||
TRACE("pdr", tout << "reachable\n";);
|
TRACE("pdr", tout << "reachable\n";);
|
||||||
|
@ -1835,7 +1854,7 @@ namespace pdr {
|
||||||
if (m_params.simplify_formulas_pre()) {
|
if (m_params.simplify_formulas_pre()) {
|
||||||
simplify_formulas();
|
simplify_formulas();
|
||||||
}
|
}
|
||||||
for (unsigned lvl = 0; lvl <= max_prop_lvl; lvl++) {
|
for (unsigned lvl = m_expanded_lvl; lvl <= max_prop_lvl; lvl++) {
|
||||||
checkpoint();
|
checkpoint();
|
||||||
bool all_propagated = true;
|
bool all_propagated = true;
|
||||||
decl2rel::iterator it = m_rels.begin(), end = m_rels.end();
|
decl2rel::iterator it = m_rels.begin(), end = m_rels.end();
|
||||||
|
|
|
@ -303,6 +303,7 @@ namespace pdr {
|
||||||
mutable model_search m_search;
|
mutable model_search m_search;
|
||||||
lbool m_last_result;
|
lbool m_last_result;
|
||||||
unsigned m_inductive_lvl;
|
unsigned m_inductive_lvl;
|
||||||
|
unsigned m_expanded_lvl;
|
||||||
ptr_vector<core_generalizer> m_core_generalizers;
|
ptr_vector<core_generalizer> m_core_generalizers;
|
||||||
stats m_stats;
|
stats m_stats;
|
||||||
volatile bool m_cancel;
|
volatile bool m_cancel;
|
||||||
|
@ -366,7 +367,7 @@ namespace pdr {
|
||||||
expr_ref get_answer();
|
expr_ref get_answer();
|
||||||
|
|
||||||
bool is_dl() const { return m_fparams.m_arith_mode == AS_DIFF_LOGIC; }
|
bool is_dl() const { return m_fparams.m_arith_mode == AS_DIFF_LOGIC; }
|
||||||
|
bool is_utvpi() const { return m_fparams.m_arith_mode == AS_UTVPI; }
|
||||||
|
|
||||||
void collect_statistics(statistics& st) const;
|
void collect_statistics(statistics& st) const;
|
||||||
void reset_statistics();
|
void reset_statistics();
|
||||||
|
|
|
@ -216,6 +216,9 @@ namespace pdr {
|
||||||
}
|
}
|
||||||
res = m.mk_not(res);
|
res = m.mk_not(res);
|
||||||
th_rewriter rw(m);
|
th_rewriter rw(m);
|
||||||
|
params_ref params;
|
||||||
|
params.set_bool("gcd_rounding", true);
|
||||||
|
rw.updt_params(params);
|
||||||
proof_ref pr(m);
|
proof_ref pr(m);
|
||||||
expr_ref tmp(m);
|
expr_ref tmp(m);
|
||||||
rw(res, tmp, pr);
|
rw(res, tmp, pr);
|
||||||
|
|
|
@ -383,26 +383,32 @@ namespace pdr {
|
||||||
fl.get_lemmas(pr, bs, lemmas);
|
fl.get_lemmas(pr, bs, lemmas);
|
||||||
safe.elim_proxies(lemmas);
|
safe.elim_proxies(lemmas);
|
||||||
fl.simplify_lemmas(lemmas); // redundant?
|
fl.simplify_lemmas(lemmas); // redundant?
|
||||||
if (m_fparams.m_arith_mode == AS_DIFF_LOGIC &&
|
|
||||||
!is_difference_logic(m, lemmas.size(), lemmas.c_ptr())) {
|
bool outside_of_logic =
|
||||||
IF_VERBOSE(1,
|
(m_fparams.m_arith_mode == AS_DIFF_LOGIC &&
|
||||||
verbose_stream() << "not diff\n";
|
!is_difference_logic(m, lemmas.size(), lemmas.c_ptr())) ||
|
||||||
for (unsigned i = 0; i < lemmas.size(); ++i) {
|
(m_fparams.m_arith_mode == AS_UTVPI &&
|
||||||
verbose_stream() << mk_pp(lemmas[i].get(), m) << "\n";
|
!is_utvpi_logic(m, lemmas.size(), lemmas.c_ptr()));
|
||||||
});
|
|
||||||
extract_subset_core(safe);
|
if (outside_of_logic) {
|
||||||
return;
|
IF_VERBOSE(2,
|
||||||
|
verbose_stream() << "not diff\n";
|
||||||
|
for (unsigned i = 0; i < lemmas.size(); ++i) {
|
||||||
|
verbose_stream() << mk_pp(lemmas[i].get(), m) << "\n";
|
||||||
|
});
|
||||||
|
extract_subset_core(safe);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
|
IF_VERBOSE(2,
|
||||||
|
verbose_stream() << "Lemmas\n";
|
||||||
|
for (unsigned i = 0; i < lemmas.size(); ++i) {
|
||||||
|
verbose_stream() << mk_pp(lemmas[i].get(), m) << "\n";
|
||||||
|
});
|
||||||
|
|
||||||
|
m_core->reset();
|
||||||
|
m_core->append(lemmas);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
IF_VERBOSE(2,
|
|
||||||
verbose_stream() << "Lemmas\n";
|
|
||||||
for (unsigned i = 0; i < lemmas.size(); ++i) {
|
|
||||||
verbose_stream() << mk_pp(lemmas[i].get(), m) << "\n";
|
|
||||||
});
|
|
||||||
|
|
||||||
m_core->reset();
|
|
||||||
m_core->append(lemmas);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
lbool prop_solver::check_assumptions(const expr_ref_vector & atoms) {
|
lbool prop_solver::check_assumptions(const expr_ref_vector & atoms) {
|
||||||
|
|
|
@ -1081,6 +1081,7 @@ namespace pdr {
|
||||||
arith_util a;
|
arith_util a;
|
||||||
bv_util bv;
|
bv_util bv;
|
||||||
bool m_is_dl;
|
bool m_is_dl;
|
||||||
|
bool m_test_for_utvpi;
|
||||||
|
|
||||||
bool is_numeric(expr* e) const {
|
bool is_numeric(expr* e) const {
|
||||||
if (a.is_numeral(e)) {
|
if (a.is_numeral(e)) {
|
||||||
|
@ -1115,6 +1116,16 @@ namespace pdr {
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (m_test_for_utvpi) {
|
||||||
|
if (a.is_mul(e, e1, e2)) {
|
||||||
|
if (is_minus_one(e1)) {
|
||||||
|
return is_offset(e2);
|
||||||
|
}
|
||||||
|
if (is_minus_one(e2)) {
|
||||||
|
return is_offset(e1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return !is_arith_expr(e);
|
return !is_arith_expr(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1140,6 +1151,9 @@ namespace pdr {
|
||||||
if (!a.is_add(lhs, arg1, arg2))
|
if (!a.is_add(lhs, arg1, arg2))
|
||||||
return false;
|
return false;
|
||||||
// x
|
// x
|
||||||
|
if (m_test_for_utvpi) {
|
||||||
|
return is_offset(arg1) && is_offset(arg2);
|
||||||
|
}
|
||||||
if (is_arith_expr(arg1))
|
if (is_arith_expr(arg1))
|
||||||
std::swap(arg1, arg2);
|
std::swap(arg1, arg2);
|
||||||
if (is_arith_expr(arg1))
|
if (is_arith_expr(arg1))
|
||||||
|
@ -1209,8 +1223,10 @@ namespace pdr {
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
test_diff_logic(ast_manager& m): m(m), a(m), bv(m), m_is_dl(true) {}
|
test_diff_logic(ast_manager& m): m(m), a(m), bv(m), m_is_dl(true), m_test_for_utvpi(false) {}
|
||||||
|
|
||||||
|
void test_for_utvpi() { m_test_for_utvpi = true; }
|
||||||
|
|
||||||
void operator()(expr* e) {
|
void operator()(expr* e) {
|
||||||
if (!m_is_dl) {
|
if (!m_is_dl) {
|
||||||
return;
|
return;
|
||||||
|
@ -1232,7 +1248,11 @@ namespace pdr {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!m_is_dl) {
|
if (!m_is_dl) {
|
||||||
IF_VERBOSE(1, verbose_stream() << "non-diff: " << mk_pp(e, m) << "\n";);
|
char const* msg = "non-diff: ";
|
||||||
|
if (m_test_for_utvpi) {
|
||||||
|
msg = "non-utvpi: ";
|
||||||
|
}
|
||||||
|
IF_VERBOSE(1, verbose_stream() << msg << mk_pp(e, m) << "\n";);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1248,6 +1268,16 @@ namespace pdr {
|
||||||
return test.is_dl();
|
return test.is_dl();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool is_utvpi_logic(ast_manager& m, unsigned num_fmls, expr* const* fmls) {
|
||||||
|
test_diff_logic test(m);
|
||||||
|
test.test_for_utvpi();
|
||||||
|
expr_fast_mark1 mark;
|
||||||
|
for (unsigned i = 0; i < num_fmls; ++i) {
|
||||||
|
quick_for_each_expr(test, mark, fmls[i]);
|
||||||
|
}
|
||||||
|
return test.is_dl();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template class rewriter_tpl<pdr::ite_hoister_cfg>;
|
template class rewriter_tpl<pdr::ite_hoister_cfg>;
|
||||||
|
|
|
@ -151,6 +151,8 @@ namespace pdr {
|
||||||
|
|
||||||
bool is_difference_logic(ast_manager& m, unsigned num_fmls, expr* const* fmls);
|
bool is_difference_logic(ast_manager& m, unsigned num_fmls, expr* const* fmls);
|
||||||
|
|
||||||
|
bool is_utvpi_logic(ast_manager& m, unsigned num_fmls, expr* const* fmls);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include "dl_util.h"
|
#include "dl_util.h"
|
||||||
#include "proof_utils.h"
|
#include "proof_utils.h"
|
||||||
#include "ast_smt2_pp.h"
|
#include "ast_smt2_pp.h"
|
||||||
|
#include "var_subst.h"
|
||||||
|
|
||||||
class reduce_hypotheses {
|
class reduce_hypotheses {
|
||||||
typedef obj_hashtable<expr> expr_set;
|
typedef obj_hashtable<expr> expr_set;
|
||||||
|
@ -517,3 +518,93 @@ void proof_utils::permute_unit_resolution(proof_ref& pr) {
|
||||||
obj_map<proof,proof*> cache;
|
obj_map<proof,proof*> cache;
|
||||||
::permute_unit_resolution(refs, cache, pr);
|
::permute_unit_resolution(refs, cache, pr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class push_instantiations_up_cl {
|
||||||
|
ast_manager& m;
|
||||||
|
public:
|
||||||
|
push_instantiations_up_cl(ast_manager& m): m(m) {}
|
||||||
|
|
||||||
|
void operator()(proof_ref& p) {
|
||||||
|
expr_ref_vector s0(m);
|
||||||
|
p = push(p, s0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
proof* push(proof* p, expr_ref_vector const& sub) {
|
||||||
|
proof_ref_vector premises(m);
|
||||||
|
expr_ref conclusion(m);
|
||||||
|
svector<std::pair<unsigned, unsigned> > positions;
|
||||||
|
vector<expr_ref_vector> substs;
|
||||||
|
|
||||||
|
if (m.is_hyper_resolve(p, premises, conclusion, positions, substs)) {
|
||||||
|
for (unsigned i = 0; i < premises.size(); ++i) {
|
||||||
|
compose(substs[i], sub);
|
||||||
|
premises[i] = push(premises[i].get(), substs[i]);
|
||||||
|
substs[i].reset();
|
||||||
|
}
|
||||||
|
instantiate(sub, conclusion);
|
||||||
|
return
|
||||||
|
m.mk_hyper_resolve(premises.size(), premises.c_ptr(), conclusion,
|
||||||
|
positions,
|
||||||
|
substs);
|
||||||
|
}
|
||||||
|
if (sub.empty()) {
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
if (m.is_modus_ponens(p)) {
|
||||||
|
SASSERT(m.get_num_parents(p) == 2);
|
||||||
|
proof* p0 = m.get_parent(p, 0);
|
||||||
|
proof* p1 = m.get_parent(p, 1);
|
||||||
|
if (m.get_fact(p0) == m.get_fact(p)) {
|
||||||
|
return push(p0, sub);
|
||||||
|
}
|
||||||
|
expr* e1, *e2;
|
||||||
|
if (m.is_rewrite(p1, e1, e2) &&
|
||||||
|
is_quantifier(e1) && is_quantifier(e2) &&
|
||||||
|
to_quantifier(e1)->get_num_decls() == to_quantifier(e2)->get_num_decls()) {
|
||||||
|
expr_ref r1(e1,m), r2(e2,m);
|
||||||
|
instantiate(sub, r1);
|
||||||
|
instantiate(sub, r2);
|
||||||
|
p1 = m.mk_rewrite(r1, r2);
|
||||||
|
return m.mk_modus_ponens(push(p0, sub), p1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
premises.push_back(p);
|
||||||
|
substs.push_back(sub);
|
||||||
|
conclusion = m.get_fact(p);
|
||||||
|
instantiate(sub, conclusion);
|
||||||
|
return m.mk_hyper_resolve(premises.size(), premises.c_ptr(), conclusion, positions, substs);
|
||||||
|
}
|
||||||
|
|
||||||
|
void compose(expr_ref_vector& sub, expr_ref_vector const& s0) {
|
||||||
|
for (unsigned i = 0; i < sub.size(); ++i) {
|
||||||
|
expr_ref e(m);
|
||||||
|
var_subst(m, false)(sub[i].get(), s0.size(), s0.c_ptr(), e);
|
||||||
|
sub[i] = e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void instantiate(expr_ref_vector const& sub, expr_ref& fml) {
|
||||||
|
if (sub.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!is_forall(fml)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
quantifier* q = to_quantifier(fml);
|
||||||
|
if (q->get_num_decls() != sub.size()) {
|
||||||
|
TRACE("proof_utils", tout << "quantifier has different number of variables than substitution";
|
||||||
|
tout << mk_pp(q, m) << "\n";
|
||||||
|
tout << sub.size() << "\n";);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var_subst(m, false)(q->get_expr(), sub.size(), sub.c_ptr(), fml);
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
void proof_utils::push_instantiations_up(proof_ref& pr) {
|
||||||
|
push_instantiations_up_cl push(pr.get_manager());
|
||||||
|
push(pr);
|
||||||
|
}
|
||||||
|
|
|
@ -36,6 +36,12 @@ public:
|
||||||
*/
|
*/
|
||||||
static void permute_unit_resolution(proof_ref& pr);
|
static void permute_unit_resolution(proof_ref& pr);
|
||||||
|
|
||||||
|
/**
|
||||||
|
\brief Push instantiations created in hyper-resolutions up to leaves.
|
||||||
|
This produces a "ground" proof where leaves are annotated by instantiations.
|
||||||
|
*/
|
||||||
|
static void push_instantiations_up(proof_ref& pr);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -2525,15 +2525,15 @@ public:
|
||||||
m_params(p) {
|
m_params(p) {
|
||||||
m_imp = alloc(imp, m, p);
|
m_imp = alloc(imp, m, p);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual tactic * translate(ast_manager & m) {
|
|
||||||
return alloc(qe_lite_tactic, m, m_params);
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual ~qe_lite_tactic() {
|
virtual ~qe_lite_tactic() {
|
||||||
dealloc(m_imp);
|
dealloc(m_imp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual tactic * translate(ast_manager & m) {
|
||||||
|
return alloc(qe_lite_tactic, m, m_params);
|
||||||
|
}
|
||||||
|
|
||||||
virtual void updt_params(params_ref const & p) {
|
virtual void updt_params(params_ref const & p) {
|
||||||
m_params = p;
|
m_params = p;
|
||||||
// m_imp->updt_params(p);
|
// m_imp->updt_params(p);
|
||||||
|
|
|
@ -40,7 +40,9 @@ namespace datalog {
|
||||||
rule_set m_rules;
|
rule_set m_rules;
|
||||||
decl_set m_preds;
|
decl_set m_preds;
|
||||||
bool m_was_closed;
|
bool m_was_closed;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
scoped_query(context& ctx):
|
scoped_query(context& ctx):
|
||||||
m_ctx(ctx),
|
m_ctx(ctx),
|
||||||
m_rules(ctx.get_rules()),
|
m_rules(ctx.get_rules()),
|
||||||
|
@ -51,6 +53,7 @@ namespace datalog {
|
||||||
ctx.reopen();
|
ctx.reopen();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
~scoped_query() {
|
~scoped_query() {
|
||||||
m_ctx.reopen();
|
m_ctx.reopen();
|
||||||
m_ctx.restrict_predicates(m_preds);
|
m_ctx.restrict_predicates(m_preds);
|
||||||
|
@ -179,9 +182,7 @@ namespace datalog {
|
||||||
scoped_query.reset();
|
scoped_query.reset();
|
||||||
}
|
}
|
||||||
m_context.record_transformed_rules();
|
m_context.record_transformed_rules();
|
||||||
TRACE("dl", m_ectx.report_big_relations(100, tout););
|
TRACE("dl", display_profile(tout););
|
||||||
m_code.process_all_costs();
|
|
||||||
m_code.make_annotations(m_ectx);
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -236,7 +237,6 @@ namespace datalog {
|
||||||
query_pred = rm.mk_query(query, m_context.get_rules());
|
query_pred = rm.mk_query(query, m_context.get_rules());
|
||||||
}
|
}
|
||||||
catch (default_exception& exn) {
|
catch (default_exception& exn) {
|
||||||
m_context.close();
|
|
||||||
m_context.set_status(INPUT_ERROR);
|
m_context.set_status(INPUT_ERROR);
|
||||||
throw exn;
|
throw exn;
|
||||||
}
|
}
|
||||||
|
@ -480,7 +480,10 @@ namespace datalog {
|
||||||
get_rmanager().display(out);
|
get_rmanager().display(out);
|
||||||
}
|
}
|
||||||
|
|
||||||
void rel_context::display_profile(std::ostream& out) const {
|
void rel_context::display_profile(std::ostream& out) {
|
||||||
|
m_code.make_annotations(m_ectx);
|
||||||
|
m_code.process_all_costs();
|
||||||
|
|
||||||
out << "\n--------------\n";
|
out << "\n--------------\n";
|
||||||
out << "Instructions\n";
|
out << "Instructions\n";
|
||||||
m_code.display(*this, out);
|
m_code.display(*this, out);
|
||||||
|
|
|
@ -105,7 +105,7 @@ namespace datalog {
|
||||||
void display_output_facts(rule_set const& rules, std::ostream & out) const;
|
void display_output_facts(rule_set const& rules, std::ostream & out) const;
|
||||||
void display_facts(std::ostream & out) const;
|
void display_facts(std::ostream & out) const;
|
||||||
|
|
||||||
void display_profile(std::ostream& out) const;
|
void display_profile(std::ostream& out);
|
||||||
|
|
||||||
lbool saturate();
|
lbool saturate();
|
||||||
|
|
||||||
|
|
|
@ -1159,7 +1159,7 @@ namespace smt2 {
|
||||||
m_num_expr_frames++;
|
m_num_expr_frames++;
|
||||||
unsigned num_vars = parse_sorted_vars();
|
unsigned num_vars = parse_sorted_vars();
|
||||||
if (num_vars == 0)
|
if (num_vars == 0)
|
||||||
throw parser_exception("invalied quantifier, list of sorted variables is empty");
|
throw parser_exception("invalid quantifier, list of sorted variables is empty");
|
||||||
}
|
}
|
||||||
|
|
||||||
symbol parse_indexed_identifier_core() {
|
symbol parse_indexed_identifier_core() {
|
||||||
|
|
|
@ -118,7 +118,7 @@ const edge_id null_edge_id = -1;
|
||||||
|
|
||||||
template<typename Ext>
|
template<typename Ext>
|
||||||
class dl_graph {
|
class dl_graph {
|
||||||
struct statistics {
|
struct stats {
|
||||||
unsigned m_propagation_cost;
|
unsigned m_propagation_cost;
|
||||||
unsigned m_implied_literal_cost;
|
unsigned m_implied_literal_cost;
|
||||||
unsigned m_num_implied_literals;
|
unsigned m_num_implied_literals;
|
||||||
|
@ -131,16 +131,16 @@ class dl_graph {
|
||||||
m_num_helpful_implied_literals = 0;
|
m_num_helpful_implied_literals = 0;
|
||||||
m_num_relax = 0;
|
m_num_relax = 0;
|
||||||
}
|
}
|
||||||
statistics() { reset(); }
|
stats() { reset(); }
|
||||||
void display(std::ostream& out) const {
|
void collect_statistics(::statistics& st) const {
|
||||||
out << "num. prop. steps. " << m_propagation_cost << "\n";
|
st.update("dl prop steps", m_propagation_cost);
|
||||||
out << "num. impl. steps. " << m_implied_literal_cost << "\n";
|
st.update("dl impl steps", m_implied_literal_cost);
|
||||||
out << "num. impl. lits. " << m_num_implied_literals << "\n";
|
st.update("dl impl lits", m_num_implied_literals);
|
||||||
out << "num. impl. conf lits. " << m_num_helpful_implied_literals << "\n";
|
st.update("dl impl conf lits", m_num_helpful_implied_literals);
|
||||||
out << "num. bound relax. " << m_num_relax << "\n";
|
st.update("dl bound relax", m_num_relax);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
statistics m_stats;
|
stats m_stats;
|
||||||
typedef typename Ext::numeral numeral;
|
typedef typename Ext::numeral numeral;
|
||||||
typedef typename Ext::explanation explanation;
|
typedef typename Ext::explanation explanation;
|
||||||
typedef vector<numeral> assignment;
|
typedef vector<numeral> assignment;
|
||||||
|
@ -264,7 +264,6 @@ class dl_graph {
|
||||||
m_assignment[e.get_target()] - m_assignment[e.get_source()] <= e.get_weight();
|
m_assignment[e.get_target()] - m_assignment[e.get_source()] <= e.get_weight();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// An assignment is feasible if all edges are feasible.
|
// An assignment is feasible if all edges are feasible.
|
||||||
bool is_feasible() const {
|
bool is_feasible() const {
|
||||||
|
@ -472,8 +471,9 @@ public:
|
||||||
m_bw(m_mark) {
|
m_bw(m_mark) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void display_statistics(std::ostream& out) const {
|
|
||||||
m_stats.display(out);
|
void collect_statistics(::statistics& st) const {
|
||||||
|
m_stats.collect_statistics(st);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create/Initialize a variable with the given id.
|
// Create/Initialize a variable with the given id.
|
||||||
|
@ -655,10 +655,8 @@ public:
|
||||||
throw default_exception("edges are not inconsistent");
|
throw default_exception("edges are not inconsistent");
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 1
|
// allow theory to introduce shortcut lemmas.
|
||||||
// experimental feature:
|
|
||||||
prune_edges(edges, f);
|
prune_edges(edges, f);
|
||||||
#endif
|
|
||||||
|
|
||||||
for (unsigned i = 0; i < edges.size(); ++i) {
|
for (unsigned i = 0; i < edges.size(); ++i) {
|
||||||
edge const& e = m_edges[edges[i]];
|
edge const& e = m_edges[edges[i]];
|
||||||
|
@ -752,7 +750,6 @@ public:
|
||||||
f.new_edge(src, dst, idx2-idx1+1, edges.begin()+idx1);
|
f.new_edge(src, dst, idx2-idx1+1, edges.begin()+idx1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Create a new scope.
|
// Create a new scope.
|
||||||
// That is, save the number of edges in the graph.
|
// That is, save the number of edges in the graph.
|
||||||
void push() {
|
void push() {
|
||||||
|
@ -1643,7 +1640,3 @@ public:
|
||||||
|
|
||||||
#endif /* _DIFF_LOGIC_H_ */
|
#endif /* _DIFF_LOGIC_H_ */
|
||||||
|
|
||||||
#if 0
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
|
@ -26,7 +26,9 @@ enum arith_solver_id {
|
||||||
AS_NO_ARITH,
|
AS_NO_ARITH,
|
||||||
AS_DIFF_LOGIC,
|
AS_DIFF_LOGIC,
|
||||||
AS_ARITH,
|
AS_ARITH,
|
||||||
AS_DENSE_DIFF_LOGIC
|
AS_DENSE_DIFF_LOGIC,
|
||||||
|
AS_UTVPI,
|
||||||
|
AS_HORN
|
||||||
};
|
};
|
||||||
|
|
||||||
enum bound_prop_mode {
|
enum bound_prop_mode {
|
||||||
|
|
|
@ -22,6 +22,8 @@ Revision History:
|
||||||
#include"theory_arith.h"
|
#include"theory_arith.h"
|
||||||
#include"theory_dense_diff_logic.h"
|
#include"theory_dense_diff_logic.h"
|
||||||
#include"theory_diff_logic.h"
|
#include"theory_diff_logic.h"
|
||||||
|
#include"theory_horn_ineq.h"
|
||||||
|
#include"theory_utvpi.h"
|
||||||
#include"theory_array.h"
|
#include"theory_array.h"
|
||||||
#include"theory_array_full.h"
|
#include"theory_array_full.h"
|
||||||
#include"theory_bv.h"
|
#include"theory_bv.h"
|
||||||
|
@ -723,6 +725,18 @@ namespace smt {
|
||||||
m_context.register_plugin(alloc(smt::theory_dense_mi, m_manager, m_params));
|
m_context.register_plugin(alloc(smt::theory_dense_mi, m_manager, m_params));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case AS_HORN:
|
||||||
|
if (m_params.m_arith_int_only)
|
||||||
|
m_context.register_plugin(alloc(smt::theory_ihi, m_manager));
|
||||||
|
else
|
||||||
|
m_context.register_plugin(alloc(smt::theory_rhi, m_manager));
|
||||||
|
break;
|
||||||
|
case AS_UTVPI:
|
||||||
|
if (m_params.m_arith_int_only)
|
||||||
|
m_context.register_plugin(alloc(smt::theory_iutvpi, m_manager));
|
||||||
|
else
|
||||||
|
m_context.register_plugin(alloc(smt::theory_rutvpi, m_manager));
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
if (m_params.m_arith_int_only)
|
if (m_params.m_arith_int_only)
|
||||||
m_context.register_plugin(alloc(smt::theory_i_arith, m_manager, m_params));
|
m_context.register_plugin(alloc(smt::theory_i_arith, m_manager, m_params));
|
||||||
|
|
|
@ -46,7 +46,6 @@ namespace smt {
|
||||||
unsigned m_num_conflicts;
|
unsigned m_num_conflicts;
|
||||||
unsigned m_num_assertions;
|
unsigned m_num_assertions;
|
||||||
unsigned m_num_th2core_eqs;
|
unsigned m_num_th2core_eqs;
|
||||||
unsigned m_num_th2core_prop;
|
|
||||||
|
|
||||||
unsigned m_num_core2th_eqs;
|
unsigned m_num_core2th_eqs;
|
||||||
unsigned m_num_core2th_diseqs;
|
unsigned m_num_core2th_diseqs;
|
||||||
|
@ -59,109 +58,30 @@ namespace smt {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class dl_conflict : public simple_justification {
|
|
||||||
public:
|
|
||||||
dl_conflict(region & r, unsigned nls, literal const * lits): simple_justification(r, nls, lits) { }
|
|
||||||
|
|
||||||
virtual proof * mk_proof(conflict_resolution & cr) {
|
|
||||||
NOT_IMPLEMENTED_YET();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
template<typename Ext>
|
template<typename Ext>
|
||||||
class theory_diff_logic : public theory, private Ext {
|
class theory_diff_logic : public theory, private Ext {
|
||||||
|
|
||||||
typedef typename Ext::numeral numeral;
|
typedef typename Ext::numeral numeral;
|
||||||
|
|
||||||
class implied_eq_justification : public justification {
|
|
||||||
theory_diff_logic & m_theory;
|
|
||||||
theory_var m_v1;
|
|
||||||
theory_var m_v2;
|
|
||||||
unsigned m_timestamp;
|
|
||||||
public:
|
|
||||||
implied_eq_justification(theory_diff_logic & theory, theory_var v1, theory_var v2, unsigned ts):
|
|
||||||
m_theory(theory),
|
|
||||||
m_v1(v1),
|
|
||||||
m_v2(v2),
|
|
||||||
m_timestamp(ts) {
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void get_antecedents(conflict_resolution & cr) {
|
|
||||||
m_theory.get_eq_antecedents(m_v1, m_v2, m_timestamp, cr);
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual proof * mk_proof(conflict_resolution & cr) { NOT_IMPLEMENTED_YET(); return 0; }
|
|
||||||
};
|
|
||||||
|
|
||||||
class implied_bound_justification : public justification {
|
|
||||||
theory_diff_logic& m_theory;
|
|
||||||
edge_id m_subsumed_edge;
|
|
||||||
edge_id m_bridge_edge;
|
|
||||||
public:
|
|
||||||
implied_bound_justification(theory_diff_logic & theory, edge_id se, edge_id be):
|
|
||||||
m_theory(theory),
|
|
||||||
m_subsumed_edge(se),
|
|
||||||
m_bridge_edge(be) {
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void get_antecedents(conflict_resolution & cr) {
|
|
||||||
m_theory.get_implied_bound_antecedents(m_bridge_edge, m_subsumed_edge, cr);
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual proof * mk_proof(conflict_resolution & cr) { NOT_IMPLEMENTED_YET(); return 0; }
|
|
||||||
};
|
|
||||||
|
|
||||||
enum atom_kind {
|
|
||||||
LE_ATOM,
|
|
||||||
EQ_ATOM
|
|
||||||
};
|
|
||||||
|
|
||||||
class atom {
|
class atom {
|
||||||
protected:
|
|
||||||
atom_kind m_kind;
|
|
||||||
bool_var m_bvar;
|
bool_var m_bvar;
|
||||||
bool m_true;
|
bool m_true;
|
||||||
|
int m_pos;
|
||||||
|
int m_neg;
|
||||||
public:
|
public:
|
||||||
atom(atom_kind k, bool_var bv) : m_kind(k), m_bvar(bv), m_true(false) {}
|
atom(bool_var bv, int pos, int neg):
|
||||||
virtual ~atom() {}
|
m_bvar(bv), m_true(false),
|
||||||
atom_kind kind() const { return m_kind; }
|
|
||||||
bool_var get_bool_var() const { return m_bvar; }
|
|
||||||
bool is_true() const { return m_true; }
|
|
||||||
void assign_eh(bool is_true) { m_true = is_true; }
|
|
||||||
virtual std::ostream& display(theory_diff_logic const& th, std::ostream& out) const;
|
|
||||||
};
|
|
||||||
|
|
||||||
class le_atom : public atom {
|
|
||||||
int m_pos;
|
|
||||||
int m_neg;
|
|
||||||
public:
|
|
||||||
le_atom(bool_var bv, int pos, int neg):
|
|
||||||
atom(LE_ATOM, bv),
|
|
||||||
m_pos(pos),
|
m_pos(pos),
|
||||||
m_neg(neg) {
|
m_neg(neg) {
|
||||||
}
|
}
|
||||||
virtual ~le_atom() {}
|
~atom() {}
|
||||||
|
bool_var get_bool_var() const { return m_bvar; }
|
||||||
|
bool is_true() const { return m_true; }
|
||||||
|
void assign_eh(bool is_true) { m_true = is_true; }
|
||||||
int get_asserted_edge() const { return this->m_true?m_pos:m_neg; }
|
int get_asserted_edge() const { return this->m_true?m_pos:m_neg; }
|
||||||
int get_pos() const { return m_pos; }
|
int get_pos() const { return m_pos; }
|
||||||
int get_neg() const { return m_neg; }
|
int get_neg() const { return m_neg; }
|
||||||
virtual std::ostream& display(theory_diff_logic const& th, std::ostream& out) const;
|
std::ostream& display(theory_diff_logic const& th, std::ostream& out) const;
|
||||||
};
|
|
||||||
|
|
||||||
class eq_atom : public atom {
|
|
||||||
app_ref m_le;
|
|
||||||
app_ref m_ge;
|
|
||||||
public:
|
|
||||||
eq_atom(bool_var bv, app_ref& le, app_ref& ge):
|
|
||||||
atom(EQ_ATOM, bv),
|
|
||||||
m_le(le),
|
|
||||||
m_ge(ge)
|
|
||||||
{}
|
|
||||||
virtual ~eq_atom() {}
|
|
||||||
virtual std::ostream& display(theory_diff_logic const& th, std::ostream& out) const;
|
|
||||||
app* get_le() const { return m_le.get(); }
|
|
||||||
app* get_ge() const { return m_ge.get(); }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef ptr_vector<atom> atoms;
|
typedef ptr_vector<atom> atoms;
|
||||||
|
@ -239,19 +159,7 @@ namespace smt {
|
||||||
unsigned m_asserted_qhead_old;
|
unsigned m_asserted_qhead_old;
|
||||||
};
|
};
|
||||||
|
|
||||||
class theory_diff_logic_del_eh : public clause_del_eh {
|
smt_params & m_params;
|
||||||
theory_diff_logic& m_super;
|
|
||||||
public:
|
|
||||||
theory_diff_logic_del_eh(theory_diff_logic& s) : m_super(s) {}
|
|
||||||
virtual ~theory_diff_logic_del_eh() {}
|
|
||||||
virtual void operator()(ast_manager&, clause* cls) {
|
|
||||||
TRACE("dl_activity", tout << "deleting " << cls << "\n";);
|
|
||||||
m_super.del_clause_eh(cls);
|
|
||||||
dealloc(this);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
smt_params & m_params;
|
|
||||||
arith_util m_util;
|
arith_util m_util;
|
||||||
arith_eq_adapter m_arith_eq_adapter;
|
arith_eq_adapter m_arith_eq_adapter;
|
||||||
theory_diff_logic_statistics m_stats;
|
theory_diff_logic_statistics m_stats;
|
||||||
|
@ -259,8 +167,6 @@ namespace smt {
|
||||||
theory_var m_zero_int; // cache the variable representing the zero variable.
|
theory_var m_zero_int; // cache the variable representing the zero variable.
|
||||||
theory_var m_zero_real; // cache the variable representing the zero variable.
|
theory_var m_zero_real; // cache the variable representing the zero variable.
|
||||||
int_vector m_scc_id; // Cheap equality propagation
|
int_vector m_scc_id; // Cheap equality propagation
|
||||||
bool m_modified_since_eq_prop; // true if new constraints were asserted
|
|
||||||
// since last eq propagation.
|
|
||||||
eq_prop_info_set m_eq_prop_info_set; // set of existing equality prop infos
|
eq_prop_info_set m_eq_prop_info_set; // set of existing equality prop infos
|
||||||
ptr_vector<eq_prop_info> m_eq_prop_infos;
|
ptr_vector<eq_prop_info> m_eq_prop_infos;
|
||||||
|
|
||||||
|
@ -289,20 +195,14 @@ namespace smt {
|
||||||
virtual theory_var mk_var(enode* n);
|
virtual theory_var mk_var(enode* n);
|
||||||
|
|
||||||
virtual theory_var mk_var(app* n);
|
virtual theory_var mk_var(app* n);
|
||||||
|
|
||||||
void mark_as_modified_since_eq_prop();
|
|
||||||
|
|
||||||
void unmark_as_modified_since_eq_prop();
|
|
||||||
|
|
||||||
bool propagate_cheap_equalities();
|
|
||||||
|
|
||||||
void compute_delta();
|
void compute_delta();
|
||||||
|
|
||||||
void found_non_diff_logic_expr(expr * n);
|
void found_non_diff_logic_expr(expr * n);
|
||||||
|
|
||||||
bool is_interpreted(app* n) const;
|
bool is_interpreted(app* n) const {
|
||||||
|
return get_family_id() == n->get_family_id();
|
||||||
void del_clause_eh(clause* cls);
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
theory_diff_logic(ast_manager& m, smt_params & params):
|
theory_diff_logic(ast_manager& m, smt_params & params):
|
||||||
|
@ -312,7 +212,6 @@ namespace smt {
|
||||||
m_arith_eq_adapter(*this, params, m_util),
|
m_arith_eq_adapter(*this, params, m_util),
|
||||||
m_zero_int(null_theory_var),
|
m_zero_int(null_theory_var),
|
||||||
m_zero_real(null_theory_var),
|
m_zero_real(null_theory_var),
|
||||||
m_modified_since_eq_prop(false),
|
|
||||||
m_asserted_qhead(0),
|
m_asserted_qhead(0),
|
||||||
m_num_core_conflicts(0),
|
m_num_core_conflicts(0),
|
||||||
m_num_propagation_calls(0),
|
m_num_propagation_calls(0),
|
||||||
|
@ -323,7 +222,7 @@ namespace smt {
|
||||||
m_nc_functor(*this) {
|
m_nc_functor(*this) {
|
||||||
}
|
}
|
||||||
|
|
||||||
~theory_diff_logic() {
|
virtual ~theory_diff_logic() {
|
||||||
reset_eh();
|
reset_eh();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -360,7 +259,7 @@ namespace smt {
|
||||||
m_arith_eq_adapter.restart_eh();
|
m_arith_eq_adapter.restart_eh();
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void relevant_eh(app* e);
|
virtual void relevant_eh(app* e) {}
|
||||||
|
|
||||||
virtual void init_search_eh() {
|
virtual void init_search_eh() {
|
||||||
m_arith_eq_adapter.init_search_eh();
|
m_arith_eq_adapter.init_search_eh();
|
||||||
|
|
|
@ -31,34 +31,15 @@ Revision History:
|
||||||
|
|
||||||
using namespace smt;
|
using namespace smt;
|
||||||
|
|
||||||
|
|
||||||
template<typename Ext>
|
template<typename Ext>
|
||||||
std::ostream& theory_diff_logic<Ext>::atom::display(theory_diff_logic const& th, std::ostream& out) const {
|
std::ostream& theory_diff_logic<Ext>::atom::display(theory_diff_logic const& th, std::ostream& out) const {
|
||||||
context& ctx = th.get_context();
|
context& ctx = th.get_context();
|
||||||
lbool asgn = ctx.get_assignment(m_bvar);
|
lbool asgn = ctx.get_assignment(m_bvar);
|
||||||
//SASSERT(asgn == l_undef || ((asgn == l_true) == m_true));
|
//SASSERT(asgn == l_undef || ((asgn == l_true) == m_true));
|
||||||
bool sign = (l_undef == asgn) || m_true;
|
bool sign = (l_undef == asgn) || m_true;
|
||||||
return out << literal(m_bvar, sign)
|
return out << literal(m_bvar, sign)
|
||||||
<< " " << mk_pp(ctx.bool_var2expr(m_bvar), th.get_manager()) << " ";
|
<< " " << mk_pp(ctx.bool_var2expr(m_bvar), th.get_manager()) << " ";
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Ext>
|
|
||||||
std::ostream& theory_diff_logic<Ext>::eq_atom::display(theory_diff_logic const& th, std::ostream& out) const {
|
|
||||||
atom::display(th, out);
|
|
||||||
lbool asgn = th.get_context().get_assignment(this->m_bvar);
|
|
||||||
if (l_undef == asgn) {
|
|
||||||
out << "unassigned\n";
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
out << mk_pp(m_le.get(), m_le.get_manager()) << " "
|
|
||||||
<< mk_pp(m_ge.get(), m_ge.get_manager()) << "\n";
|
|
||||||
}
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Ext>
|
|
||||||
std::ostream& theory_diff_logic<Ext>::le_atom::display(theory_diff_logic const& th, std::ostream& out) const {
|
|
||||||
atom::display(th, out);
|
|
||||||
lbool asgn = th.get_context().get_assignment(this->m_bvar);
|
|
||||||
if (l_undef == asgn) {
|
if (l_undef == asgn) {
|
||||||
out << "unassigned\n";
|
out << "unassigned\n";
|
||||||
}
|
}
|
||||||
|
@ -94,7 +75,6 @@ void theory_diff_logic<Ext>::init(context * ctx) {
|
||||||
e = ctx->mk_enode(zero, false, false, true);
|
e = ctx->mk_enode(zero, false, false, true);
|
||||||
SASSERT(!is_attached_to_var(e));
|
SASSERT(!is_attached_to_var(e));
|
||||||
m_zero_real = mk_var(e);
|
m_zero_real = mk_var(e);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -277,7 +257,7 @@ bool theory_diff_logic<Ext>::internalize_atom(app * n, bool gate_ctx) {
|
||||||
k -= this->m_epsilon;
|
k -= this->m_epsilon;
|
||||||
}
|
}
|
||||||
edge_id neg = m_graph.add_edge(target, source, k, ~l);
|
edge_id neg = m_graph.add_edge(target, source, k, ~l);
|
||||||
le_atom * a = alloc(le_atom, bv, pos, neg);
|
atom * a = alloc(atom, bv, pos, neg);
|
||||||
m_atoms.push_back(a);
|
m_atoms.push_back(a);
|
||||||
m_bool_var2atom.insert(bv, a);
|
m_bool_var2atom.insert(bv, a);
|
||||||
|
|
||||||
|
@ -318,7 +298,7 @@ template<typename Ext>
|
||||||
void theory_diff_logic<Ext>::assign_eh(bool_var v, bool is_true) {
|
void theory_diff_logic<Ext>::assign_eh(bool_var v, bool is_true) {
|
||||||
m_stats.m_num_assertions++;
|
m_stats.m_num_assertions++;
|
||||||
atom * a = 0;
|
atom * a = 0;
|
||||||
m_bool_var2atom.find(v, a);
|
VERIFY (m_bool_var2atom.find(v, a));
|
||||||
SASSERT(a);
|
SASSERT(a);
|
||||||
SASSERT(get_context().get_assignment(v) != l_undef);
|
SASSERT(get_context().get_assignment(v) != l_undef);
|
||||||
SASSERT((get_context().get_assignment(v) == l_true) == is_true);
|
SASSERT((get_context().get_assignment(v) == l_true) == is_true);
|
||||||
|
@ -330,10 +310,11 @@ void theory_diff_logic<Ext>::assign_eh(bool_var v, bool is_true) {
|
||||||
template<typename Ext>
|
template<typename Ext>
|
||||||
void theory_diff_logic<Ext>::collect_statistics(::statistics & st) const {
|
void theory_diff_logic<Ext>::collect_statistics(::statistics & st) const {
|
||||||
st.update("dl conflicts", m_stats.m_num_conflicts);
|
st.update("dl conflicts", m_stats.m_num_conflicts);
|
||||||
st.update("dl propagations", m_stats.m_num_th2core_prop);
|
|
||||||
st.update("dl asserts", m_stats.m_num_assertions);
|
st.update("dl asserts", m_stats.m_num_assertions);
|
||||||
st.update("core->dl eqs", m_stats.m_num_core2th_eqs);
|
st.update("core->dl eqs", m_stats.m_num_core2th_eqs);
|
||||||
|
st.update("core->dl diseqs", m_stats.m_num_core2th_diseqs);
|
||||||
m_arith_eq_adapter.collect_statistics(st);
|
m_arith_eq_adapter.collect_statistics(st);
|
||||||
|
m_graph.collect_statistics(st);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Ext>
|
template<typename Ext>
|
||||||
|
@ -374,15 +355,6 @@ final_check_status theory_diff_logic<Ext>::final_check_eh() {
|
||||||
// either will already be zero (as we don't do mixed constraints).
|
// either will already be zero (as we don't do mixed constraints).
|
||||||
m_graph.set_to_zero(m_zero_int, m_zero_real);
|
m_graph.set_to_zero(m_zero_int, m_zero_real);
|
||||||
SASSERT(is_consistent());
|
SASSERT(is_consistent());
|
||||||
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
TBD:
|
|
||||||
if (propagate_cheap_equalities()) {
|
|
||||||
return FC_CONTINUE;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (m_non_diff_logic_exprs) {
|
if (m_non_diff_logic_exprs) {
|
||||||
return FC_GIVEUP;
|
return FC_GIVEUP;
|
||||||
}
|
}
|
||||||
|
@ -506,61 +478,14 @@ bool theory_diff_logic<Ext>::propagate_atom(atom* a) {
|
||||||
if (ctx.inconsistent()) {
|
if (ctx.inconsistent()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
switch(a->kind()) {
|
int edge_id = a->get_asserted_edge();
|
||||||
case LE_ATOM: {
|
if (!m_graph.enable_edge(edge_id)) {
|
||||||
int edge_id = dynamic_cast<le_atom*>(a)->get_asserted_edge();
|
set_neg_cycle_conflict();
|
||||||
if (!m_graph.enable_edge(edge_id)) {
|
return false;
|
||||||
set_neg_cycle_conflict();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
#if 0
|
|
||||||
if (m_params.m_arith_bound_prop != BP_NONE) {
|
|
||||||
svector<int> subsumed;
|
|
||||||
m_graph.find_subsumed1(edge_id, subsumed);
|
|
||||||
for (unsigned i = 0; i < subsumed.size(); ++i) {
|
|
||||||
int subsumed_edge_id = subsumed[i];
|
|
||||||
literal l = m_graph.get_explanation(subsumed_edge_id);
|
|
||||||
context & ctx = get_context();
|
|
||||||
region& r = ctx.get_region();
|
|
||||||
++m_stats.m_num_th2core_prop;
|
|
||||||
ctx.assign(l, new (r) implied_bound_justification(*this, subsumed_edge_id, edge_id));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case EQ_ATOM:
|
|
||||||
if (!a->is_true()) {
|
|
||||||
SASSERT(ctx.get_assignment(a->get_bool_var()) == l_false);
|
|
||||||
// eq_atom * ea = dynamic_cast<eq_atom*>(a);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
template<typename Ext>
|
|
||||||
void theory_diff_logic<Ext>::mark_as_modified_since_eq_prop() {
|
|
||||||
if (!m_modified_since_eq_prop) {
|
|
||||||
get_context().push_trail(value_trail<context, bool>(m_modified_since_eq_prop));
|
|
||||||
m_modified_since_eq_prop = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Ext>
|
|
||||||
void theory_diff_logic<Ext>::unmark_as_modified_since_eq_prop() {
|
|
||||||
get_context().push_trail(value_trail<context, bool>(m_modified_since_eq_prop));
|
|
||||||
m_modified_since_eq_prop = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Ext>
|
|
||||||
void theory_diff_logic<Ext>::del_clause_eh(clause* cls) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Ext>
|
template<typename Ext>
|
||||||
void theory_diff_logic<Ext>::new_edge(dl_var src, dl_var dst, unsigned num_edges, edge_id const* edges) {
|
void theory_diff_logic<Ext>::new_edge(dl_var src, dl_var dst, unsigned num_edges, edge_id const* edges) {
|
||||||
|
|
||||||
|
@ -609,7 +534,7 @@ void theory_diff_logic<Ext>::new_edge(dl_var src, dl_var dst, unsigned num_edges
|
||||||
atom* a = 0;
|
atom* a = 0;
|
||||||
m_bool_var2atom.find(bv, a);
|
m_bool_var2atom.find(bv, a);
|
||||||
SASSERT(a);
|
SASSERT(a);
|
||||||
edge_id e_id = static_cast<le_atom*>(a)->get_pos();
|
edge_id e_id = a->get_pos();
|
||||||
|
|
||||||
literal_vector lits;
|
literal_vector lits;
|
||||||
for (unsigned i = 0; i < num_edges; ++i) {
|
for (unsigned i = 0; i < num_edges; ++i) {
|
||||||
|
@ -633,11 +558,7 @@ void theory_diff_logic<Ext>::new_edge(dl_var src, dl_var dst, unsigned num_edges
|
||||||
lits.size(), lits.c_ptr(),
|
lits.size(), lits.c_ptr(),
|
||||||
params.size(), params.c_ptr());
|
params.size(), params.c_ptr());
|
||||||
}
|
}
|
||||||
clause_del_eh* del_eh = alloc(theory_diff_logic_del_eh, *this);
|
clause* cls = ctx.mk_clause(lits.size(), lits.c_ptr(), js, CLS_AUX_LEMMA, 0);
|
||||||
clause* cls = ctx.mk_clause(lits.size(), lits.c_ptr(), js, CLS_AUX_LEMMA, del_eh);
|
|
||||||
if (!cls) {
|
|
||||||
dealloc(del_eh);
|
|
||||||
}
|
|
||||||
if (dump_lemmas()) {
|
if (dump_lemmas()) {
|
||||||
char const * logic = m_is_lia ? "QF_LIA" : "QF_LRA";
|
char const * logic = m_is_lia ? "QF_LIA" : "QF_LRA";
|
||||||
ctx.display_lemma_as_smt_problem(lits.size(), lits.c_ptr(), false_literal, logic);
|
ctx.display_lemma_as_smt_problem(lits.size(), lits.c_ptr(), false_literal, logic);
|
||||||
|
@ -677,7 +598,6 @@ void theory_diff_logic<Ext>::set_neg_cycle_conflict() {
|
||||||
literal_vector const& lits = m_nc_functor.get_lits();
|
literal_vector const& lits = m_nc_functor.get_lits();
|
||||||
context & ctx = get_context();
|
context & ctx = get_context();
|
||||||
TRACE("arith_conflict",
|
TRACE("arith_conflict",
|
||||||
//display(tout);
|
|
||||||
tout << "conflict: ";
|
tout << "conflict: ";
|
||||||
for (unsigned i = 0; i < lits.size(); ++i) {
|
for (unsigned i = 0; i < lits.size(); ++i) {
|
||||||
ctx.display_literal_info(tout, lits[i]);
|
ctx.display_literal_info(tout, lits[i]);
|
||||||
|
@ -802,7 +722,6 @@ theory_var theory_diff_logic<Ext>::mk_num(app* n, rational const& r) {
|
||||||
|
|
||||||
template<typename Ext>
|
template<typename Ext>
|
||||||
theory_var theory_diff_logic<Ext>::mk_var(enode* n) {
|
theory_var theory_diff_logic<Ext>::mk_var(enode* n) {
|
||||||
mark_as_modified_since_eq_prop();
|
|
||||||
theory_var v = theory::mk_var(n);
|
theory_var v = theory::mk_var(n);
|
||||||
TRACE("diff_logic_vars", tout << "mk_var: " << v << "\n";);
|
TRACE("diff_logic_vars", tout << "mk_var: " << v << "\n";);
|
||||||
m_graph.init_var(v);
|
m_graph.init_var(v);
|
||||||
|
@ -810,10 +729,6 @@ theory_var theory_diff_logic<Ext>::mk_var(enode* n) {
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Ext>
|
|
||||||
bool theory_diff_logic<Ext>::is_interpreted(app* n) const {
|
|
||||||
return n->get_family_id() == get_family_id();
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Ext>
|
template<typename Ext>
|
||||||
theory_var theory_diff_logic<Ext>::mk_var(app* n) {
|
theory_var theory_diff_logic<Ext>::mk_var(app* n) {
|
||||||
|
@ -854,7 +769,6 @@ void theory_diff_logic<Ext>::reset_eh() {
|
||||||
m_asserted_atoms .reset();
|
m_asserted_atoms .reset();
|
||||||
m_stats .reset();
|
m_stats .reset();
|
||||||
m_scopes .reset();
|
m_scopes .reset();
|
||||||
m_modified_since_eq_prop = false;
|
|
||||||
m_asserted_qhead = 0;
|
m_asserted_qhead = 0;
|
||||||
m_num_core_conflicts = 0;
|
m_num_core_conflicts = 0;
|
||||||
m_num_propagation_calls = 0;
|
m_num_propagation_calls = 0;
|
||||||
|
@ -865,70 +779,6 @@ void theory_diff_logic<Ext>::reset_eh() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template<typename Ext>
|
|
||||||
bool theory_diff_logic<Ext>::propagate_cheap_equalities() {
|
|
||||||
bool result = false;
|
|
||||||
TRACE("dl_new_eq", get_context().display(tout););
|
|
||||||
context& ctx = get_context();
|
|
||||||
region& reg = ctx.get_region();
|
|
||||||
SASSERT(m_eq_prop_info_set.empty());
|
|
||||||
SASSERT(m_eq_prop_infos.empty());
|
|
||||||
if (m_modified_since_eq_prop) {
|
|
||||||
m_graph.compute_zero_edge_scc(m_scc_id);
|
|
||||||
int n = get_num_vars();
|
|
||||||
for (theory_var v = 0; v < n; v++) {
|
|
||||||
rational delta_r;
|
|
||||||
theory_var x_v = expand(true, v, delta_r);
|
|
||||||
numeral delta(delta_r);
|
|
||||||
int scc_id = m_scc_id[x_v];
|
|
||||||
if (scc_id != -1) {
|
|
||||||
delta += m_graph.get_assignment(x_v);
|
|
||||||
TRACE("eq_scc", tout << v << " " << x_v << " " << scc_id << " " << delta << "\n";);
|
|
||||||
eq_prop_info info(scc_id, delta);
|
|
||||||
typename eq_prop_info_set::entry * entry = m_eq_prop_info_set.find_core(&info);
|
|
||||||
if (entry == 0) {
|
|
||||||
eq_prop_info * new_info = alloc(eq_prop_info, scc_id, delta, v);
|
|
||||||
m_eq_prop_info_set.insert(new_info);
|
|
||||||
m_eq_prop_infos.push_back(new_info);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// new equality found
|
|
||||||
theory_var r = entry->get_data()->get_root();
|
|
||||||
|
|
||||||
enode * n1 = get_enode(v);
|
|
||||||
enode * n2 = get_enode(r);
|
|
||||||
if (n1->get_root() != n2->get_root()) {
|
|
||||||
// r may be an alias (i.e., it is not realy in the graph). So, I should expand it.
|
|
||||||
// nsb: ??
|
|
||||||
rational r_delta;
|
|
||||||
theory_var x_r = expand(true, r, r_delta);
|
|
||||||
|
|
||||||
justification* j = new (reg) implied_eq_justification(*this, x_v, x_r, m_graph.get_timestamp());
|
|
||||||
(void)j;
|
|
||||||
|
|
||||||
m_stats.m_num_th2core_eqs++;
|
|
||||||
// TBD: get equality into core.
|
|
||||||
|
|
||||||
NOT_IMPLEMENTED_YET();
|
|
||||||
// new_eq_eh(x_v, x_r, *j);
|
|
||||||
result = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
m_eq_prop_info_set.reset();
|
|
||||||
std::for_each(m_eq_prop_infos.begin(), m_eq_prop_infos.end(), delete_proc<eq_prop_info>());
|
|
||||||
m_eq_prop_infos.reset();
|
|
||||||
unmark_as_modified_since_eq_prop();
|
|
||||||
}
|
|
||||||
|
|
||||||
TRACE("dl_new_eq", get_context().display(tout););
|
|
||||||
SASSERT(!m_modified_since_eq_prop);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
template<typename Ext>
|
template<typename Ext>
|
||||||
void theory_diff_logic<Ext>::compute_delta() {
|
void theory_diff_logic<Ext>::compute_delta() {
|
||||||
m_delta = rational(1);
|
m_delta = rational(1);
|
||||||
|
@ -1001,30 +851,9 @@ bool theory_diff_logic<Ext>::is_consistent() const {
|
||||||
lbool asgn = ctx.get_assignment(bv);
|
lbool asgn = ctx.get_assignment(bv);
|
||||||
if (ctx.is_relevant(ctx.bool_var2expr(bv)) && asgn != l_undef) {
|
if (ctx.is_relevant(ctx.bool_var2expr(bv)) && asgn != l_undef) {
|
||||||
SASSERT((asgn == l_true) == a->is_true());
|
SASSERT((asgn == l_true) == a->is_true());
|
||||||
switch(a->kind()) {
|
int edge_id = a->get_asserted_edge();
|
||||||
case LE_ATOM: {
|
SASSERT(m_graph.is_enabled(edge_id));
|
||||||
le_atom* le = dynamic_cast<le_atom*>(a);
|
SASSERT(m_graph.is_feasible(edge_id));
|
||||||
int edge_id = le->get_asserted_edge();
|
|
||||||
SASSERT(m_graph.is_enabled(edge_id));
|
|
||||||
SASSERT(m_graph.is_feasible(edge_id));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case EQ_ATOM: {
|
|
||||||
eq_atom* ea = dynamic_cast<eq_atom*>(a);
|
|
||||||
bool_var bv1 = ctx.get_bool_var(ea->get_le());
|
|
||||||
bool_var bv2 = ctx.get_bool_var(ea->get_ge());
|
|
||||||
lbool val1 = ctx.get_assignment(bv1);
|
|
||||||
lbool val2 = ctx.get_assignment(bv2);
|
|
||||||
if (asgn == l_true) {
|
|
||||||
SASSERT(val1 == l_true);
|
|
||||||
SASSERT(val2 == l_true);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
SASSERT(val1 == l_false || val2 == l_false);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return m_graph.is_feasible();
|
return m_graph.is_feasible();
|
||||||
|
@ -1087,7 +916,6 @@ void theory_diff_logic<Ext>::new_eq_or_diseq(bool is_eq, theory_var v1, theory_v
|
||||||
// assign the corresponding equality literal.
|
// assign the corresponding equality literal.
|
||||||
//
|
//
|
||||||
|
|
||||||
mark_as_modified_since_eq_prop();
|
|
||||||
|
|
||||||
app_ref eq(m), s2(m), t2(m);
|
app_ref eq(m), s2(m), t2(m);
|
||||||
app* s1 = get_enode(s)->get_owner();
|
app* s1 = get_enode(s)->get_owner();
|
||||||
|
@ -1142,10 +970,6 @@ void theory_diff_logic<Ext>::new_diseq_eh(theory_var v1, theory_var v2) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template<typename Ext>
|
|
||||||
void theory_diff_logic<Ext>::relevant_eh(app* e) {
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
struct imp_functor {
|
struct imp_functor {
|
||||||
conflict_resolution & m_cr;
|
conflict_resolution & m_cr;
|
||||||
|
|
236
src/smt/theory_horn_ineq.cpp
Normal file
236
src/smt/theory_horn_ineq.cpp
Normal file
|
@ -0,0 +1,236 @@
|
||||||
|
/*++
|
||||||
|
Copyright (c) 2013 Microsoft Corporation
|
||||||
|
|
||||||
|
Module Name:
|
||||||
|
|
||||||
|
theory_horn_ineq.h
|
||||||
|
|
||||||
|
Author:
|
||||||
|
|
||||||
|
Nikolaj Bjorner (nbjorner) 2013-04-18
|
||||||
|
|
||||||
|
Revision History:
|
||||||
|
|
||||||
|
The implementaton is derived from theory_diff_logic.
|
||||||
|
|
||||||
|
--*/
|
||||||
|
#include "theory_horn_ineq.h"
|
||||||
|
#include "theory_horn_ineq_def.h"
|
||||||
|
|
||||||
|
namespace smt {
|
||||||
|
|
||||||
|
template class theory_horn_ineq<ihi_ext>;
|
||||||
|
template class theory_horn_ineq<rhi_ext>;
|
||||||
|
|
||||||
|
// similar to test_diff_logic:
|
||||||
|
|
||||||
|
horn_ineq_tester::horn_ineq_tester(ast_manager& m): m(m), a(m) {}
|
||||||
|
|
||||||
|
bool horn_ineq_tester::operator()(expr* e) {
|
||||||
|
m_todo.reset();
|
||||||
|
m_pols.reset();
|
||||||
|
pos_mark.reset();
|
||||||
|
neg_mark.reset();
|
||||||
|
m_todo.push_back(e);
|
||||||
|
m_pols.push_back(l_true);
|
||||||
|
while (!m_todo.empty()) {
|
||||||
|
expr* e = m_todo.back();
|
||||||
|
lbool p = m_pols.back();
|
||||||
|
m_todo.pop_back();
|
||||||
|
m_pols.pop_back();
|
||||||
|
switch (p) {
|
||||||
|
case l_true:
|
||||||
|
if (pos_mark.is_marked(e)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
pos_mark.mark(e, true);
|
||||||
|
break;
|
||||||
|
case l_false:
|
||||||
|
if (neg_mark.is_marked(e)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
neg_mark.mark(e, true);
|
||||||
|
break;
|
||||||
|
case l_undef:
|
||||||
|
if (pos_mark.is_marked(e) && neg_mark.is_marked(e)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
pos_mark.mark(e, true);
|
||||||
|
neg_mark.mark(e, true);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!test_expr(p, e)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
vector<std::pair<expr*,rational> > const& horn_ineq_tester::get_linearization() const {
|
||||||
|
return m_terms;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool horn_ineq_tester::test_expr(lbool p, expr* e) {
|
||||||
|
expr* e1, *e2, *e3;
|
||||||
|
if (is_var(e)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (!is_app(e)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
app* ap = to_app(e);
|
||||||
|
if (m.is_and(ap) || m.is_or(ap)) {
|
||||||
|
for (unsigned i = 0; i < ap->get_num_args(); ++i) {
|
||||||
|
m_todo.push_back(ap->get_arg(i));
|
||||||
|
m_pols.push_back(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (m.is_not(e, e1)) {
|
||||||
|
m_todo.push_back(e);
|
||||||
|
m_pols.push_back(~p);
|
||||||
|
}
|
||||||
|
else if (m.is_ite(e, e1, e2, e3)) {
|
||||||
|
m_todo.push_back(e1);
|
||||||
|
m_pols.push_back(l_undef);
|
||||||
|
m_todo.push_back(e2);
|
||||||
|
m_pols.push_back(p);
|
||||||
|
m_todo.push_back(e3);
|
||||||
|
m_pols.push_back(p);
|
||||||
|
}
|
||||||
|
else if (m.is_iff(e, e1, e2)) {
|
||||||
|
m_todo.push_back(e1);
|
||||||
|
m_pols.push_back(l_undef);
|
||||||
|
m_todo.push_back(e2);
|
||||||
|
m_pols.push_back(l_undef);
|
||||||
|
m_todo.push_back(e2);
|
||||||
|
}
|
||||||
|
else if (m.is_implies(e, e1, e2)) {
|
||||||
|
m_todo.push_back(e1);
|
||||||
|
m_pols.push_back(~p);
|
||||||
|
m_todo.push_back(e2);
|
||||||
|
m_pols.push_back(p);
|
||||||
|
}
|
||||||
|
else if (m.is_eq(e, e1, e2)) {
|
||||||
|
return linearize(e1, e2) == diff;
|
||||||
|
}
|
||||||
|
else if (m.is_true(e) || m.is_false(e)) {
|
||||||
|
// no-op
|
||||||
|
}
|
||||||
|
else if (a.is_le(e, e1, e2) || a.is_ge(e, e2, e1) ||
|
||||||
|
a.is_lt(e, e1, e2) || a.is_gt(e, e2, e1)) {
|
||||||
|
if (p == l_false) {
|
||||||
|
std::swap(e2, e1);
|
||||||
|
}
|
||||||
|
classify_t cl = linearize(e1, e2);
|
||||||
|
switch(p) {
|
||||||
|
case l_undef:
|
||||||
|
return cl == diff;
|
||||||
|
case l_true:
|
||||||
|
case l_false:
|
||||||
|
return cl == horn || cl == diff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (!is_uninterp_const(e)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool horn_ineq_tester::operator()(unsigned num_fmls, expr* const* fmls) {
|
||||||
|
for (unsigned i = 0; i < num_fmls; ++i) {
|
||||||
|
if (!(*this)(fmls[i])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
horn_ineq_tester::classify_t horn_ineq_tester::linearize(expr* e) {
|
||||||
|
m_terms.reset();
|
||||||
|
m_terms.push_back(std::make_pair(e, rational(1)));
|
||||||
|
return linearize();
|
||||||
|
}
|
||||||
|
|
||||||
|
horn_ineq_tester::classify_t horn_ineq_tester::linearize(expr* e1, expr* e2) {
|
||||||
|
m_terms.reset();
|
||||||
|
m_terms.push_back(std::make_pair(e1, rational(1)));
|
||||||
|
m_terms.push_back(std::make_pair(e2, rational(-1)));
|
||||||
|
return linearize();
|
||||||
|
}
|
||||||
|
|
||||||
|
horn_ineq_tester::classify_t horn_ineq_tester::linearize() {
|
||||||
|
|
||||||
|
m_weight.reset();
|
||||||
|
m_coeff_map.reset();
|
||||||
|
|
||||||
|
while (!m_terms.empty()) {
|
||||||
|
expr* e1, *e2;
|
||||||
|
rational num;
|
||||||
|
rational mul = m_terms.back().second;
|
||||||
|
expr* e = m_terms.back().first;
|
||||||
|
m_terms.pop_back();
|
||||||
|
if (a.is_add(e)) {
|
||||||
|
for (unsigned i = 0; i < to_app(e)->get_num_args(); ++i) {
|
||||||
|
m_terms.push_back(std::make_pair(to_app(e)->get_arg(i), mul));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (a.is_mul(e, e1, e2) && a.is_numeral(e1, num)) {
|
||||||
|
m_terms.push_back(std::make_pair(e2, mul*num));
|
||||||
|
}
|
||||||
|
else if (a.is_mul(e, e2, e1) && a.is_numeral(e1, num)) {
|
||||||
|
m_terms.push_back(std::make_pair(e2, mul*num));
|
||||||
|
}
|
||||||
|
else if (a.is_sub(e, e1, e2)) {
|
||||||
|
m_terms.push_back(std::make_pair(e1, mul));
|
||||||
|
m_terms.push_back(std::make_pair(e2, -mul));
|
||||||
|
}
|
||||||
|
else if (a.is_uminus(e, e1)) {
|
||||||
|
m_terms.push_back(std::make_pair(e1, -mul));
|
||||||
|
}
|
||||||
|
else if (a.is_numeral(e, num)) {
|
||||||
|
m_weight += num*mul;
|
||||||
|
}
|
||||||
|
else if (a.is_to_real(e, e1)) {
|
||||||
|
m_terms.push_back(std::make_pair(e1, mul));
|
||||||
|
}
|
||||||
|
else if (!is_uninterp_const(e)) {
|
||||||
|
return non_horn;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
m_coeff_map.insert_if_not_there2(e, rational(0))->get_data().m_value += mul;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
unsigned num_negative = 0;
|
||||||
|
unsigned num_positive = 0;
|
||||||
|
bool is_unit_pos = true, is_unit_neg = true;
|
||||||
|
obj_map<expr, rational>::iterator it = m_coeff_map.begin();
|
||||||
|
obj_map<expr, rational>::iterator end = m_coeff_map.end();
|
||||||
|
for (; it != end; ++it) {
|
||||||
|
rational r = it->m_value;
|
||||||
|
if (r.is_zero()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
m_terms.push_back(std::make_pair(it->m_key, r));
|
||||||
|
if (r.is_pos()) {
|
||||||
|
is_unit_pos = is_unit_pos && r.is_one();
|
||||||
|
num_positive++;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
is_unit_neg = is_unit_neg && r.is_minus_one();
|
||||||
|
num_negative++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (num_negative <= 1 && is_unit_pos && is_unit_neg && num_positive <= 1) {
|
||||||
|
return diff;
|
||||||
|
}
|
||||||
|
if (num_positive <= 1 && is_unit_pos) {
|
||||||
|
return horn;
|
||||||
|
}
|
||||||
|
if (num_negative <= 1 && is_unit_neg) {
|
||||||
|
return co_horn;
|
||||||
|
}
|
||||||
|
return non_horn;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
329
src/smt/theory_horn_ineq.h
Normal file
329
src/smt/theory_horn_ineq.h
Normal file
|
@ -0,0 +1,329 @@
|
||||||
|
/*++
|
||||||
|
Copyright (c) 2013 Microsoft Corporation
|
||||||
|
|
||||||
|
Module Name:
|
||||||
|
|
||||||
|
theory_horn_ineq.h
|
||||||
|
|
||||||
|
Abstract:
|
||||||
|
|
||||||
|
A*x <= weight + D*x, coefficients to A and D are non-negative,
|
||||||
|
D is a diagonal matrix.
|
||||||
|
Coefficients to weight may have both signs.
|
||||||
|
|
||||||
|
Label variables by weight.
|
||||||
|
Select inequality that is not satisfied.
|
||||||
|
Set delta(LHS) := 0
|
||||||
|
Set delta(RHS(x)) := weight(x) - b
|
||||||
|
Propagate weight increment through inequalities.
|
||||||
|
|
||||||
|
Author:
|
||||||
|
|
||||||
|
Nikolaj Bjorner (nbjorner) 2013-04-18
|
||||||
|
|
||||||
|
Revision History:
|
||||||
|
|
||||||
|
The implementaton is derived from theory_diff_logic.
|
||||||
|
|
||||||
|
--*/
|
||||||
|
|
||||||
|
#ifndef _THEORY_HORN_INEQ_H_
|
||||||
|
#define _THEORY_HORN_INEQ_H_
|
||||||
|
|
||||||
|
#include"rational.h"
|
||||||
|
#include"inf_rational.h"
|
||||||
|
#include"inf_int_rational.h"
|
||||||
|
#include"inf_eps_rational.h"
|
||||||
|
#include"smt_theory.h"
|
||||||
|
#include"arith_decl_plugin.h"
|
||||||
|
#include"smt_justification.h"
|
||||||
|
#include"map.h"
|
||||||
|
#include"smt_params.h"
|
||||||
|
#include"arith_eq_adapter.h"
|
||||||
|
#include"smt_model_generator.h"
|
||||||
|
#include"numeral_factory.h"
|
||||||
|
#include"smt_clause.h"
|
||||||
|
|
||||||
|
namespace smt {
|
||||||
|
|
||||||
|
class horn_ineq_tester {
|
||||||
|
ast_manager& m;
|
||||||
|
arith_util a;
|
||||||
|
ptr_vector<expr> m_todo;
|
||||||
|
svector<lbool> m_pols;
|
||||||
|
ast_mark pos_mark, neg_mark;
|
||||||
|
obj_map<expr, rational> m_coeff_map;
|
||||||
|
rational m_weight;
|
||||||
|
vector<std::pair<expr*, rational> > m_terms;
|
||||||
|
|
||||||
|
public:
|
||||||
|
enum classify_t {
|
||||||
|
co_horn,
|
||||||
|
horn,
|
||||||
|
diff,
|
||||||
|
non_horn
|
||||||
|
};
|
||||||
|
horn_ineq_tester(ast_manager& m);
|
||||||
|
|
||||||
|
// test if formula is in the Horn inequality fragment:
|
||||||
|
bool operator()(expr* fml);
|
||||||
|
bool operator()(unsigned num_fmls, expr* const* fmls);
|
||||||
|
|
||||||
|
// linearize inequality/equality
|
||||||
|
classify_t linearize(expr* e);
|
||||||
|
classify_t linearize(expr* e1, expr* e2);
|
||||||
|
|
||||||
|
// retrieve linearization
|
||||||
|
vector<std::pair<expr*,rational> > const& get_linearization() const;
|
||||||
|
rational const& get_weight() const { return m_weight; }
|
||||||
|
private:
|
||||||
|
bool test_expr(lbool p, expr* e);
|
||||||
|
classify_t linearize();
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename Ext>
|
||||||
|
class theory_horn_ineq : public theory, private Ext {
|
||||||
|
|
||||||
|
typedef typename Ext::numeral numeral;
|
||||||
|
typedef typename Ext::inf_numeral inf_numeral;
|
||||||
|
typedef literal explanation;
|
||||||
|
typedef theory_var th_var;
|
||||||
|
typedef svector<th_var> th_var_vector;
|
||||||
|
typedef unsigned clause_id;
|
||||||
|
typedef vector<std::pair<th_var, rational> > coeffs;
|
||||||
|
static const clause_id null_clause_id = UINT_MAX;
|
||||||
|
|
||||||
|
class clause;
|
||||||
|
class graph;
|
||||||
|
class assignment_trail;
|
||||||
|
class parent_trail;
|
||||||
|
|
||||||
|
class atom {
|
||||||
|
protected:
|
||||||
|
bool_var m_bvar;
|
||||||
|
bool m_true;
|
||||||
|
int m_pos;
|
||||||
|
int m_neg;
|
||||||
|
public:
|
||||||
|
atom(bool_var bv, int pos, int neg) :
|
||||||
|
m_bvar(bv), m_true(false),
|
||||||
|
m_pos(pos), m_neg(neg) {}
|
||||||
|
virtual ~atom() {}
|
||||||
|
bool_var get_bool_var() const { return m_bvar; }
|
||||||
|
bool is_true() const { return m_true; }
|
||||||
|
void assign_eh(bool is_true) { m_true = is_true; }
|
||||||
|
int get_asserted_edge() const { return this->m_true?m_pos:m_neg; }
|
||||||
|
int get_pos() const { return m_pos; }
|
||||||
|
int get_neg() const { return m_neg; }
|
||||||
|
std::ostream& display(theory_horn_ineq const& th, std::ostream& out) const;
|
||||||
|
};
|
||||||
|
typedef svector<atom> atoms;
|
||||||
|
|
||||||
|
struct scope {
|
||||||
|
unsigned m_atoms_lim;
|
||||||
|
unsigned m_asserted_atoms_lim;
|
||||||
|
unsigned m_asserted_qhead_old;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct stats {
|
||||||
|
unsigned m_num_conflicts;
|
||||||
|
unsigned m_num_assertions;
|
||||||
|
unsigned m_num_core2th_eqs;
|
||||||
|
unsigned m_num_core2th_diseqs;
|
||||||
|
|
||||||
|
void reset() {
|
||||||
|
memset(this, 0, sizeof(*this));
|
||||||
|
}
|
||||||
|
|
||||||
|
stats() {
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
stats m_stats;
|
||||||
|
smt_params m_params;
|
||||||
|
arith_util a;
|
||||||
|
arith_eq_adapter m_arith_eq_adapter;
|
||||||
|
th_var m_zero_int; // cache the variable representing the zero variable.
|
||||||
|
th_var m_zero_real; // cache the variable representing the zero variable.
|
||||||
|
|
||||||
|
graph* m_graph;
|
||||||
|
atoms m_atoms;
|
||||||
|
unsigned_vector m_asserted_atoms; // set of asserted atoms
|
||||||
|
unsigned m_asserted_qhead;
|
||||||
|
u_map<unsigned> m_bool_var2atom;
|
||||||
|
svector<scope> m_scopes;
|
||||||
|
|
||||||
|
double m_agility;
|
||||||
|
bool m_lia;
|
||||||
|
bool m_lra;
|
||||||
|
bool m_non_horn_ineq_exprs;
|
||||||
|
|
||||||
|
horn_ineq_tester m_test;
|
||||||
|
|
||||||
|
|
||||||
|
arith_factory * m_factory;
|
||||||
|
rational m_delta;
|
||||||
|
rational m_lambda;
|
||||||
|
|
||||||
|
|
||||||
|
// Set a conflict due to a negative cycle.
|
||||||
|
void set_neg_cycle_conflict();
|
||||||
|
|
||||||
|
// Create a new theory variable.
|
||||||
|
virtual th_var mk_var(enode* n);
|
||||||
|
|
||||||
|
virtual th_var mk_var(expr* n);
|
||||||
|
|
||||||
|
void compute_delta();
|
||||||
|
|
||||||
|
void found_non_horn_ineq_expr(expr * n);
|
||||||
|
|
||||||
|
bool is_interpreted(app* n) const {
|
||||||
|
return n->get_family_id() == get_family_id();
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
theory_horn_ineq(ast_manager& m);
|
||||||
|
|
||||||
|
virtual ~theory_horn_ineq();
|
||||||
|
|
||||||
|
virtual theory * mk_fresh(context * new_ctx) { return alloc(theory_horn_ineq, get_manager()); }
|
||||||
|
|
||||||
|
virtual char const * get_name() const { return "horn-inequality-logic"; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
\brief See comment in theory::mk_eq_atom
|
||||||
|
*/
|
||||||
|
virtual app * mk_eq_atom(expr * lhs, expr * rhs) { return a.mk_eq(lhs, rhs); }
|
||||||
|
|
||||||
|
virtual void init(context * ctx);
|
||||||
|
|
||||||
|
virtual bool internalize_atom(app * atom, bool gate_ctx);
|
||||||
|
|
||||||
|
virtual bool internalize_term(app * term);
|
||||||
|
|
||||||
|
virtual void internalize_eq_eh(app * atom, bool_var v);
|
||||||
|
|
||||||
|
virtual void assign_eh(bool_var v, bool is_true);
|
||||||
|
|
||||||
|
virtual void new_eq_eh(th_var v1, th_var v2) {
|
||||||
|
m_arith_eq_adapter.new_eq_eh(v1, v2);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool use_diseqs() const { return true; }
|
||||||
|
|
||||||
|
virtual void new_diseq_eh(th_var v1, th_var v2) {
|
||||||
|
m_arith_eq_adapter.new_diseq_eh(v1, v2);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void push_scope_eh();
|
||||||
|
|
||||||
|
virtual void pop_scope_eh(unsigned num_scopes);
|
||||||
|
|
||||||
|
virtual void restart_eh() {
|
||||||
|
m_arith_eq_adapter.restart_eh();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void relevant_eh(app* e) {}
|
||||||
|
|
||||||
|
virtual void init_search_eh() {
|
||||||
|
m_arith_eq_adapter.init_search_eh();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual final_check_status final_check_eh();
|
||||||
|
|
||||||
|
virtual bool is_shared(th_var v) const {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool can_propagate() {
|
||||||
|
SASSERT(m_asserted_qhead <= m_asserted_atoms.size());
|
||||||
|
return m_asserted_qhead != m_asserted_atoms.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void propagate();
|
||||||
|
|
||||||
|
virtual justification * why_is_diseq(th_var v1, th_var v2) {
|
||||||
|
UNREACHABLE();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void reset_eh();
|
||||||
|
|
||||||
|
virtual void init_model(model_generator & m);
|
||||||
|
|
||||||
|
virtual model_value_proc * mk_value(enode * n, model_generator & mg);
|
||||||
|
|
||||||
|
virtual bool validate_eq_in_model(th_var v1, th_var v2, bool is_true) const {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void display(std::ostream & out) const;
|
||||||
|
|
||||||
|
virtual void collect_statistics(::statistics & st) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
virtual void new_eq_eh(th_var v1, th_var v2, justification& j) {
|
||||||
|
m_stats.m_num_core2th_eqs++;
|
||||||
|
new_eq_or_diseq(true, v1, v2, j);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void new_diseq_eh(th_var v1, th_var v2, justification& j) {
|
||||||
|
m_stats.m_num_core2th_diseqs++;
|
||||||
|
new_eq_or_diseq(false, v1, v2, j);
|
||||||
|
}
|
||||||
|
|
||||||
|
void negate(coeffs& coeffs, rational& weight);
|
||||||
|
numeral mk_weight(bool is_real, bool is_strict, rational const& w) const;
|
||||||
|
void mk_coeffs(vector<std::pair<expr*,rational> >const& terms, coeffs& coeffs, rational& w);
|
||||||
|
|
||||||
|
void del_atoms(unsigned old_size);
|
||||||
|
|
||||||
|
void propagate_core();
|
||||||
|
|
||||||
|
bool propagate_atom(atom const& a);
|
||||||
|
|
||||||
|
th_var mk_term(app* n);
|
||||||
|
|
||||||
|
th_var mk_num(app* n, rational const& r);
|
||||||
|
|
||||||
|
bool is_consistent() const;
|
||||||
|
|
||||||
|
th_var expand(bool pos, th_var v, rational & k);
|
||||||
|
|
||||||
|
void new_eq_or_diseq(bool is_eq, th_var v1, th_var v2, justification& eq_just);
|
||||||
|
|
||||||
|
th_var get_zero(sort* s) const { return a.is_int(s)?m_zero_int:m_zero_real; }
|
||||||
|
|
||||||
|
th_var get_zero(expr* e) const { return get_zero(get_manager().get_sort(e)); }
|
||||||
|
|
||||||
|
void inc_conflicts();
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
struct rhi_ext {
|
||||||
|
typedef inf_rational inf_numeral;
|
||||||
|
typedef inf_eps_rational<inf_rational> numeral;
|
||||||
|
numeral m_epsilon;
|
||||||
|
numeral m_minus_infty;
|
||||||
|
rhi_ext() : m_epsilon(inf_rational(rational(), true)), m_minus_infty(rational(-1),inf_rational()) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ihi_ext {
|
||||||
|
typedef rational inf_numeral;
|
||||||
|
typedef inf_eps_rational<rational> numeral;
|
||||||
|
numeral m_epsilon;
|
||||||
|
numeral m_minus_infty;
|
||||||
|
ihi_ext() : m_epsilon(rational(1)), m_minus_infty(rational(-1),rational(0)) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef theory_horn_ineq<rhi_ext> theory_rhi;
|
||||||
|
typedef theory_horn_ineq<ihi_ext> theory_ihi;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* _THEORY_HORN_INEQ_H_ */
|
1164
src/smt/theory_horn_ineq_def.h
Normal file
1164
src/smt/theory_horn_ineq_def.h
Normal file
File diff suppressed because it is too large
Load diff
160
src/smt/theory_utvpi.cpp
Normal file
160
src/smt/theory_utvpi.cpp
Normal file
|
@ -0,0 +1,160 @@
|
||||||
|
/*++
|
||||||
|
Copyright (c) 2013 Microsoft Corporation
|
||||||
|
|
||||||
|
Module Name:
|
||||||
|
|
||||||
|
theory_utvpi.h
|
||||||
|
|
||||||
|
Author:
|
||||||
|
|
||||||
|
Nikolaj Bjorner (nbjorner) 2013-04-26
|
||||||
|
|
||||||
|
Revision History:
|
||||||
|
|
||||||
|
The implementaton is derived from theory_diff_logic.
|
||||||
|
|
||||||
|
--*/
|
||||||
|
#include "theory_utvpi.h"
|
||||||
|
#include "theory_utvpi_def.h"
|
||||||
|
|
||||||
|
namespace smt {
|
||||||
|
|
||||||
|
template class theory_utvpi<idl_ext>;
|
||||||
|
template class theory_utvpi<rdl_ext>;
|
||||||
|
|
||||||
|
// similar to test_diff_logic:
|
||||||
|
|
||||||
|
utvpi_tester::utvpi_tester(ast_manager& m): m(m), a(m) {}
|
||||||
|
|
||||||
|
bool utvpi_tester::operator()(expr* e) {
|
||||||
|
m_todo.reset();
|
||||||
|
m_mark.reset();
|
||||||
|
m_todo.push_back(e);
|
||||||
|
expr* e1, *e2;
|
||||||
|
|
||||||
|
while (!m_todo.empty()) {
|
||||||
|
expr* e = m_todo.back();
|
||||||
|
m_todo.pop_back();
|
||||||
|
if (!m_mark.is_marked(e)) {
|
||||||
|
m_mark.mark(e, true);
|
||||||
|
if (is_var(e)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!is_app(e)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
app* ap = to_app(e);
|
||||||
|
if (m.is_eq(ap, e1, e2)) {
|
||||||
|
if (!linearize(e1, e2)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (ap->get_family_id() == m.get_basic_family_id()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if (a.is_le(e, e1, e2) || a.is_ge(e, e2, e1) ||
|
||||||
|
a.is_lt(e, e1, e2) || a.is_gt(e, e2, e1)) {
|
||||||
|
if (!linearize(e1, e2)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (is_uninterp_const(e)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
vector<std::pair<expr*, rational> > const& utvpi_tester::get_linearization() const {
|
||||||
|
SASSERT(m_terms.size() <= 2);
|
||||||
|
return m_terms;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool utvpi_tester::operator()(unsigned num_fmls, expr* const* fmls) {
|
||||||
|
for (unsigned i = 0; i < num_fmls; ++i) {
|
||||||
|
if (!(*this)(fmls[i])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool utvpi_tester::linearize(expr* e) {
|
||||||
|
m_terms.reset();
|
||||||
|
m_terms.push_back(std::make_pair(e, rational(1)));
|
||||||
|
return linearize();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool utvpi_tester::linearize(expr* e1, expr* e2) {
|
||||||
|
m_terms.reset();
|
||||||
|
m_terms.push_back(std::make_pair(e1, rational(1)));
|
||||||
|
m_terms.push_back(std::make_pair(e2, rational(-1)));
|
||||||
|
return linearize();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool utvpi_tester::linearize() {
|
||||||
|
|
||||||
|
m_weight.reset();
|
||||||
|
m_coeff_map.reset();
|
||||||
|
|
||||||
|
while (!m_terms.empty()) {
|
||||||
|
expr* e1, *e2;
|
||||||
|
rational num;
|
||||||
|
rational mul = m_terms.back().second;
|
||||||
|
expr* e = m_terms.back().first;
|
||||||
|
m_terms.pop_back();
|
||||||
|
if (a.is_add(e)) {
|
||||||
|
for (unsigned i = 0; i < to_app(e)->get_num_args(); ++i) {
|
||||||
|
m_terms.push_back(std::make_pair(to_app(e)->get_arg(i), mul));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (a.is_mul(e, e1, e2) && a.is_numeral(e1, num)) {
|
||||||
|
m_terms.push_back(std::make_pair(e2, mul*num));
|
||||||
|
}
|
||||||
|
else if (a.is_mul(e, e2, e1) && a.is_numeral(e1, num)) {
|
||||||
|
m_terms.push_back(std::make_pair(e2, mul*num));
|
||||||
|
}
|
||||||
|
else if (a.is_sub(e, e1, e2)) {
|
||||||
|
m_terms.push_back(std::make_pair(e1, mul));
|
||||||
|
m_terms.push_back(std::make_pair(e2, -mul));
|
||||||
|
}
|
||||||
|
else if (a.is_uminus(e, e1)) {
|
||||||
|
m_terms.push_back(std::make_pair(e1, -mul));
|
||||||
|
}
|
||||||
|
else if (a.is_numeral(e, num)) {
|
||||||
|
m_weight += num*mul;
|
||||||
|
}
|
||||||
|
else if (a.is_to_real(e, e1)) {
|
||||||
|
m_terms.push_back(std::make_pair(e1, mul));
|
||||||
|
}
|
||||||
|
else if (!is_uninterp_const(e)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
m_coeff_map.insert_if_not_there2(e, rational(0))->get_data().m_value += mul;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
obj_map<expr, rational>::iterator it = m_coeff_map.begin();
|
||||||
|
obj_map<expr, rational>::iterator end = m_coeff_map.end();
|
||||||
|
for (; it != end; ++it) {
|
||||||
|
rational r = it->m_value;
|
||||||
|
if (r.is_zero()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
m_terms.push_back(std::make_pair(it->m_key, r));
|
||||||
|
if (m_terms.size() > 2) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!r.is_one() && !r.is_minus_one()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
336
src/smt/theory_utvpi.h
Normal file
336
src/smt/theory_utvpi.h
Normal file
|
@ -0,0 +1,336 @@
|
||||||
|
/*++
|
||||||
|
Copyright (c) 2013 Microsoft Corporation
|
||||||
|
|
||||||
|
Module Name:
|
||||||
|
|
||||||
|
theory_utvpi.h
|
||||||
|
|
||||||
|
Abstract:
|
||||||
|
|
||||||
|
use Bellman Ford traversal algorithm for UTVPI.
|
||||||
|
|
||||||
|
Author:
|
||||||
|
|
||||||
|
Nikolaj Bjorner (nbjorner) 2013-04-26
|
||||||
|
|
||||||
|
Revision History:
|
||||||
|
|
||||||
|
The implementaton is derived from theory_diff_logic.
|
||||||
|
|
||||||
|
--*/
|
||||||
|
|
||||||
|
#ifndef _THEORY_UTVPI_H_
|
||||||
|
#define _THEORY_UTVPI_H_
|
||||||
|
|
||||||
|
#include"theory_diff_logic.h"
|
||||||
|
|
||||||
|
namespace smt {
|
||||||
|
|
||||||
|
class utvpi_tester {
|
||||||
|
ast_manager& m;
|
||||||
|
arith_util a;
|
||||||
|
ptr_vector<expr> m_todo;
|
||||||
|
ast_mark m_mark;
|
||||||
|
obj_map<expr, rational> m_coeff_map;
|
||||||
|
rational m_weight;
|
||||||
|
vector<std::pair<expr*, rational> > m_terms;
|
||||||
|
|
||||||
|
public:
|
||||||
|
utvpi_tester(ast_manager& m);
|
||||||
|
|
||||||
|
// test if formula is in the Horn inequality fragment:
|
||||||
|
bool operator()(expr* fml);
|
||||||
|
bool operator()(unsigned num_fmls, expr* const* fmls);
|
||||||
|
|
||||||
|
// linearize inequality/equality
|
||||||
|
bool linearize(expr* e);
|
||||||
|
bool linearize(expr* e1, expr* e2);
|
||||||
|
|
||||||
|
// retrieve linearization
|
||||||
|
vector<std::pair<expr*, rational> > const& get_linearization() const;
|
||||||
|
rational const& get_weight() const { return m_weight; }
|
||||||
|
private:
|
||||||
|
bool linearize();
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename Ext>
|
||||||
|
class theory_utvpi : public theory, private Ext {
|
||||||
|
|
||||||
|
typedef typename Ext::numeral numeral;
|
||||||
|
typedef theory_var th_var;
|
||||||
|
typedef svector<th_var> th_var_vector;
|
||||||
|
typedef vector<std::pair<th_var, rational> > coeffs;
|
||||||
|
|
||||||
|
class assignment_trail;
|
||||||
|
class parent_trail;
|
||||||
|
|
||||||
|
struct GExt : public Ext {
|
||||||
|
typedef literal explanation;
|
||||||
|
};
|
||||||
|
|
||||||
|
class atom {
|
||||||
|
protected:
|
||||||
|
bool_var m_bvar;
|
||||||
|
bool m_true;
|
||||||
|
int m_pos;
|
||||||
|
int m_neg;
|
||||||
|
public:
|
||||||
|
atom(bool_var bv, int pos, int neg) :
|
||||||
|
m_bvar(bv), m_true(false),
|
||||||
|
m_pos(pos), m_neg(neg) {}
|
||||||
|
virtual ~atom() {}
|
||||||
|
bool_var get_bool_var() const { return m_bvar; }
|
||||||
|
void assign_eh(bool is_true) { m_true = is_true; }
|
||||||
|
int get_asserted_edge() const { return this->m_true?m_pos:m_neg; }
|
||||||
|
int get_pos() const { return m_pos; }
|
||||||
|
int get_neg() const { return m_neg; }
|
||||||
|
std::ostream& display(theory_utvpi const& th, std::ostream& out) const;
|
||||||
|
};
|
||||||
|
typedef svector<atom> atoms;
|
||||||
|
|
||||||
|
struct scope {
|
||||||
|
unsigned m_atoms_lim;
|
||||||
|
unsigned m_asserted_atoms_lim;
|
||||||
|
unsigned m_asserted_qhead_old;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct stats {
|
||||||
|
unsigned m_num_conflicts;
|
||||||
|
unsigned m_num_assertions;
|
||||||
|
unsigned m_num_core2th_eqs;
|
||||||
|
unsigned m_num_core2th_diseqs;
|
||||||
|
|
||||||
|
void reset() {
|
||||||
|
memset(this, 0, sizeof(*this));
|
||||||
|
}
|
||||||
|
|
||||||
|
stats() {
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Functor used to collect the proofs for a conflict due to
|
||||||
|
// a negative cycle.
|
||||||
|
class nc_functor {
|
||||||
|
literal_vector m_antecedents;
|
||||||
|
theory_utvpi& m_super;
|
||||||
|
public:
|
||||||
|
nc_functor(theory_utvpi& s) : m_super(s) {}
|
||||||
|
void reset() { m_antecedents.reset(); }
|
||||||
|
literal_vector const& get_lits() const { return m_antecedents; }
|
||||||
|
|
||||||
|
void operator()(literal const & ex) {
|
||||||
|
if (ex != null_literal) {
|
||||||
|
m_antecedents.push_back(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void new_edge(dl_var src, dl_var dst, unsigned num_edges, edge_id const* edges) {
|
||||||
|
m_super.new_edge(src, dst, num_edges, edges);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
stats m_stats;
|
||||||
|
smt_params m_params;
|
||||||
|
arith_util a;
|
||||||
|
arith_eq_adapter m_arith_eq_adapter;
|
||||||
|
th_var m_zero_int; // cache the variable representing the zero variable.
|
||||||
|
th_var m_zero_real; // cache the variable representing the zero variable.
|
||||||
|
|
||||||
|
dl_graph<GExt> m_graph;
|
||||||
|
nc_functor m_nc_functor;
|
||||||
|
atoms m_atoms;
|
||||||
|
unsigned_vector m_asserted_atoms; // set of asserted atoms
|
||||||
|
unsigned m_asserted_qhead;
|
||||||
|
u_map<unsigned> m_bool_var2atom;
|
||||||
|
svector<scope> m_scopes;
|
||||||
|
|
||||||
|
double m_agility;
|
||||||
|
bool m_lia;
|
||||||
|
bool m_lra;
|
||||||
|
bool m_non_utvpi_exprs;
|
||||||
|
|
||||||
|
utvpi_tester m_test;
|
||||||
|
|
||||||
|
|
||||||
|
arith_factory * m_factory;
|
||||||
|
rational m_delta;
|
||||||
|
|
||||||
|
|
||||||
|
// Set a conflict due to a negative cycle.
|
||||||
|
void set_conflict();
|
||||||
|
|
||||||
|
void new_edge(dl_var src, dl_var dst, unsigned num_edges, edge_id const* edges) {}
|
||||||
|
|
||||||
|
// Create a new theory variable.
|
||||||
|
virtual th_var mk_var(enode* n);
|
||||||
|
|
||||||
|
virtual th_var mk_var(expr* n);
|
||||||
|
|
||||||
|
void compute_delta();
|
||||||
|
|
||||||
|
void found_non_utvpi_expr(expr * n);
|
||||||
|
|
||||||
|
bool is_interpreted(app* n) const {
|
||||||
|
return n->get_family_id() == get_family_id();
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
theory_utvpi(ast_manager& m);
|
||||||
|
|
||||||
|
virtual ~theory_utvpi();
|
||||||
|
|
||||||
|
virtual theory * mk_fresh(context * new_ctx) { return alloc(theory_utvpi, get_manager()); }
|
||||||
|
|
||||||
|
virtual char const * get_name() const { return "utvpi-logic"; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
\brief See comment in theory::mk_eq_atom
|
||||||
|
*/
|
||||||
|
virtual app * mk_eq_atom(expr * lhs, expr * rhs) { return a.mk_eq(lhs, rhs); }
|
||||||
|
|
||||||
|
virtual void init(context * ctx);
|
||||||
|
|
||||||
|
virtual bool internalize_atom(app * atom, bool gate_ctx);
|
||||||
|
|
||||||
|
virtual bool internalize_term(app * term);
|
||||||
|
|
||||||
|
virtual void internalize_eq_eh(app * atom, bool_var v);
|
||||||
|
|
||||||
|
virtual void assign_eh(bool_var v, bool is_true);
|
||||||
|
|
||||||
|
virtual void new_eq_eh(th_var v1, th_var v2) {
|
||||||
|
m_stats.m_num_core2th_eqs++;
|
||||||
|
m_arith_eq_adapter.new_eq_eh(v1, v2);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool use_diseqs() const { return true; }
|
||||||
|
|
||||||
|
virtual void new_diseq_eh(th_var v1, th_var v2) {
|
||||||
|
m_arith_eq_adapter.new_diseq_eh(v1, v2);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void push_scope_eh();
|
||||||
|
|
||||||
|
virtual void pop_scope_eh(unsigned num_scopes);
|
||||||
|
|
||||||
|
virtual void restart_eh() {
|
||||||
|
m_arith_eq_adapter.restart_eh();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void relevant_eh(app* e) {}
|
||||||
|
|
||||||
|
virtual void init_search_eh() {
|
||||||
|
m_arith_eq_adapter.init_search_eh();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual final_check_status final_check_eh();
|
||||||
|
|
||||||
|
virtual bool is_shared(th_var v) const {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool can_propagate() {
|
||||||
|
SASSERT(m_asserted_qhead <= m_asserted_atoms.size());
|
||||||
|
return m_asserted_qhead != m_asserted_atoms.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void propagate();
|
||||||
|
|
||||||
|
virtual justification * why_is_diseq(th_var v1, th_var v2) {
|
||||||
|
UNREACHABLE();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void reset_eh();
|
||||||
|
|
||||||
|
virtual void init_model(model_generator & m);
|
||||||
|
|
||||||
|
virtual model_value_proc * mk_value(enode * n, model_generator & mg);
|
||||||
|
|
||||||
|
virtual bool validate_eq_in_model(th_var v1, th_var v2, bool is_true) const {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void display(std::ostream & out) const;
|
||||||
|
|
||||||
|
virtual void collect_statistics(::statistics & st) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
rational mk_value(theory_var v);
|
||||||
|
|
||||||
|
void validate_model();
|
||||||
|
|
||||||
|
bool eval(expr* e);
|
||||||
|
|
||||||
|
rational eval_num(expr* e);
|
||||||
|
|
||||||
|
bool check_z_consistency();
|
||||||
|
|
||||||
|
virtual void new_eq_eh(th_var v1, th_var v2, justification& j) {
|
||||||
|
m_stats.m_num_core2th_eqs++;
|
||||||
|
new_eq_or_diseq(true, v1, v2, j);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void new_diseq_eh(th_var v1, th_var v2, justification& j) {
|
||||||
|
m_stats.m_num_core2th_diseqs++;
|
||||||
|
new_eq_or_diseq(false, v1, v2, j);
|
||||||
|
}
|
||||||
|
|
||||||
|
void negate(coeffs& coeffs, rational& weight);
|
||||||
|
numeral mk_weight(bool is_real, bool is_strict, rational const& w) const;
|
||||||
|
void mk_coeffs(vector<std::pair<expr*,rational> >const& terms, coeffs& coeffs, rational& w);
|
||||||
|
|
||||||
|
void del_atoms(unsigned old_size);
|
||||||
|
|
||||||
|
bool propagate_atom(atom const& a);
|
||||||
|
|
||||||
|
th_var mk_term(app* n);
|
||||||
|
|
||||||
|
th_var mk_num(app* n, rational const& r);
|
||||||
|
|
||||||
|
bool is_consistent() const;
|
||||||
|
|
||||||
|
th_var expand(bool pos, th_var v, rational & k);
|
||||||
|
|
||||||
|
void new_eq_or_diseq(bool is_eq, th_var v1, th_var v2, justification& eq_just);
|
||||||
|
|
||||||
|
th_var get_zero(sort* s) const { return a.is_int(s)?m_zero_int:m_zero_real; }
|
||||||
|
|
||||||
|
th_var get_zero(expr* e) const { return get_zero(get_manager().get_sort(e)); }
|
||||||
|
|
||||||
|
void inc_conflicts();
|
||||||
|
|
||||||
|
edge_id add_ineq(vector<std::pair<th_var, rational> > const& terms, numeral const& weight, literal l);
|
||||||
|
|
||||||
|
bool enable_edge(edge_id id);
|
||||||
|
|
||||||
|
th_var to_var(th_var v) const {
|
||||||
|
return 2*v;
|
||||||
|
}
|
||||||
|
|
||||||
|
th_var from_var(th_var v) const {
|
||||||
|
return v/2;
|
||||||
|
}
|
||||||
|
|
||||||
|
th_var pos(th_var v) const {
|
||||||
|
return v & 0xFFFFFFFE;
|
||||||
|
}
|
||||||
|
|
||||||
|
th_var neg(th_var v) const {
|
||||||
|
return v | 0x1;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
typedef theory_utvpi<rdl_ext> theory_rutvpi;
|
||||||
|
typedef theory_utvpi<idl_ext> theory_iutvpi;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* _THEORY_UTVPI_H_ */
|
814
src/smt/theory_utvpi_def.h
Normal file
814
src/smt/theory_utvpi_def.h
Normal file
|
@ -0,0 +1,814 @@
|
||||||
|
/*++
|
||||||
|
Copyright (c) 2013 Microsoft Corporation
|
||||||
|
|
||||||
|
Module Name:
|
||||||
|
|
||||||
|
theory_utvpi_def.h
|
||||||
|
|
||||||
|
Abstract:
|
||||||
|
|
||||||
|
Implementation of UTVPI solver.
|
||||||
|
|
||||||
|
Author:
|
||||||
|
|
||||||
|
Nikolaj Bjorner (nbjorner) 2013-04-26
|
||||||
|
|
||||||
|
Revision History:
|
||||||
|
|
||||||
|
1. introduce x^+ and x^-, such that 2*x := x^+ - x^-
|
||||||
|
2. rewrite constraints as follows:
|
||||||
|
|
||||||
|
x - y <= k => x^+ - y^+ <= k
|
||||||
|
y^- - x^- <= k
|
||||||
|
|
||||||
|
x <= k => x^+ - x^- <= 2k
|
||||||
|
|
||||||
|
|
||||||
|
x + y <= k => x^+ - y^- <= k
|
||||||
|
y^+ - x^- <= k
|
||||||
|
|
||||||
|
|
||||||
|
- x - y <= k => x^- - y^+ <= k
|
||||||
|
y^- - x^+ <= k
|
||||||
|
|
||||||
|
3. Solve for x^+ and x^-
|
||||||
|
4. Check parity condition for integers (see Lahiri and Musuvathi 05)
|
||||||
|
5. extract model for M(x) := (M(x^+)- M(x^-))/2
|
||||||
|
|
||||||
|
--*/
|
||||||
|
|
||||||
|
#ifndef _THEORY_UTVPI_DEF_H_
|
||||||
|
#define _THEORY_UTVPI_DEF_H_
|
||||||
|
#include "theory_utvpi.h"
|
||||||
|
#include "heap.h"
|
||||||
|
#include "ast_pp.h"
|
||||||
|
#include "smt_context.h"
|
||||||
|
|
||||||
|
namespace smt {
|
||||||
|
|
||||||
|
|
||||||
|
template<typename Ext>
|
||||||
|
theory_utvpi<Ext>::theory_utvpi(ast_manager& m):
|
||||||
|
theory(m.mk_family_id("arith")),
|
||||||
|
a(m),
|
||||||
|
m_arith_eq_adapter(*this, m_params, a),
|
||||||
|
m_zero_int(null_theory_var),
|
||||||
|
m_zero_real(null_theory_var),
|
||||||
|
m_asserted_qhead(0),
|
||||||
|
m_nc_functor(*this),
|
||||||
|
m_agility(0.5),
|
||||||
|
m_lia(false),
|
||||||
|
m_lra(false),
|
||||||
|
m_non_utvpi_exprs(false),
|
||||||
|
m_test(m),
|
||||||
|
m_factory(0) {
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Ext>
|
||||||
|
theory_utvpi<Ext>::~theory_utvpi() {
|
||||||
|
reset_eh();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Ext>
|
||||||
|
std::ostream& theory_utvpi<Ext>::atom::display(theory_utvpi const& th, std::ostream& out) const {
|
||||||
|
context& ctx = th.get_context();
|
||||||
|
lbool asgn = ctx.get_assignment(m_bvar);
|
||||||
|
bool sign = (l_undef == l_false);
|
||||||
|
return out << literal(m_bvar, sign) << " " << mk_pp(ctx.bool_var2expr(m_bvar), th.get_manager()) << " ";
|
||||||
|
if (l_undef == asgn) {
|
||||||
|
out << "unassigned\n";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
th.m_graph.display_edge(out, get_asserted_edge());
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Ext>
|
||||||
|
theory_var theory_utvpi<Ext>::mk_var(enode* n) {
|
||||||
|
th_var v = theory::mk_var(n);
|
||||||
|
TRACE("utvpi", tout << v << " " << mk_pp(n->get_owner(), get_manager()) << "\n";);
|
||||||
|
m_graph.init_var(to_var(v));
|
||||||
|
m_graph.init_var(neg(to_var(v)));
|
||||||
|
get_context().attach_th_var(n, this, v);
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Ext>
|
||||||
|
theory_var theory_utvpi<Ext>::mk_var(expr* n) {
|
||||||
|
context & ctx = get_context();
|
||||||
|
enode* e = 0;
|
||||||
|
th_var v = null_theory_var;
|
||||||
|
m_lia |= a.is_int(n);
|
||||||
|
m_lra |= a.is_real(n);
|
||||||
|
if (!is_app(n)) {
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
if (ctx.e_internalized(n)) {
|
||||||
|
e = ctx.get_enode(n);
|
||||||
|
v = e->get_th_var(get_id());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ctx.internalize(n, false);
|
||||||
|
e = ctx.get_enode(n);
|
||||||
|
}
|
||||||
|
if (v == null_theory_var) {
|
||||||
|
v = mk_var(e);
|
||||||
|
}
|
||||||
|
if (is_interpreted(to_app(n))) {
|
||||||
|
found_non_utvpi_expr(n);
|
||||||
|
}
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Ext>
|
||||||
|
void theory_utvpi<Ext>::reset_eh() {
|
||||||
|
m_graph .reset();
|
||||||
|
m_zero_int = null_theory_var;
|
||||||
|
m_zero_real = null_theory_var;
|
||||||
|
m_atoms .reset();
|
||||||
|
m_asserted_atoms .reset();
|
||||||
|
m_stats .reset();
|
||||||
|
m_scopes .reset();
|
||||||
|
m_asserted_qhead = 0;
|
||||||
|
m_agility = 0.5;
|
||||||
|
m_lia = false;
|
||||||
|
m_lra = false;
|
||||||
|
m_non_utvpi_exprs = false;
|
||||||
|
theory::reset_eh();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Ext>
|
||||||
|
void theory_utvpi<Ext>::new_eq_or_diseq(bool is_eq, th_var v1, th_var v2, justification& eq_just) {
|
||||||
|
rational k;
|
||||||
|
th_var s = expand(true, v1, k);
|
||||||
|
th_var t = expand(false, v2, k);
|
||||||
|
context& ctx = get_context();
|
||||||
|
ast_manager& m = get_manager();
|
||||||
|
|
||||||
|
if (s == t) {
|
||||||
|
if (is_eq != k.is_zero()) {
|
||||||
|
// conflict 0 /= k;
|
||||||
|
inc_conflicts();
|
||||||
|
ctx.set_conflict(&eq_just);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
//
|
||||||
|
// Create equality ast, internalize_atom
|
||||||
|
// assign the corresponding equality literal.
|
||||||
|
//
|
||||||
|
|
||||||
|
app_ref eq(m), s2(m), t2(m);
|
||||||
|
app* s1 = get_enode(s)->get_owner();
|
||||||
|
app* t1 = get_enode(t)->get_owner();
|
||||||
|
s2 = a.mk_sub(t1, s1);
|
||||||
|
t2 = a.mk_numeral(k, m.get_sort(s2.get()));
|
||||||
|
// t1 - s1 = k
|
||||||
|
eq = m.mk_eq(s2.get(), t2.get());
|
||||||
|
|
||||||
|
TRACE("utvpi",
|
||||||
|
tout << v1 << " .. " << v2 << "\n";
|
||||||
|
tout << mk_pp(eq.get(), m) <<"\n";);
|
||||||
|
|
||||||
|
if (!internalize_atom(eq.get(), false)) {
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
|
|
||||||
|
literal l(ctx.get_literal(eq.get()));
|
||||||
|
if (!is_eq) {
|
||||||
|
l = ~l;
|
||||||
|
}
|
||||||
|
ctx.assign(l, b_justification(&eq_just), false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Ext>
|
||||||
|
void theory_utvpi<Ext>::inc_conflicts() {
|
||||||
|
m_stats.m_num_conflicts++;
|
||||||
|
if (m_params.m_arith_adaptive) {
|
||||||
|
double g = m_params.m_arith_adaptive_propagation_threshold;
|
||||||
|
m_agility = m_agility*g + 1 - g;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Ext>
|
||||||
|
void theory_utvpi<Ext>::set_conflict() {
|
||||||
|
inc_conflicts();
|
||||||
|
literal_vector const& lits = m_nc_functor.get_lits();
|
||||||
|
context & ctx = get_context();
|
||||||
|
TRACE("utvpi",
|
||||||
|
tout << "conflict: ";
|
||||||
|
for (unsigned i = 0; i < lits.size(); ++i) {
|
||||||
|
ctx.display_literal_info(tout, lits[i]);
|
||||||
|
}
|
||||||
|
tout << "\n";
|
||||||
|
);
|
||||||
|
|
||||||
|
if (m_params.m_arith_dump_lemmas) {
|
||||||
|
char const * logic = m_lra ? (m_lia?"QF_LIRA":"QF_LRA") : "QF_LIA";
|
||||||
|
ctx.display_lemma_as_smt_problem(lits.size(), lits.c_ptr(), false_literal, logic);
|
||||||
|
}
|
||||||
|
|
||||||
|
vector<parameter> params;
|
||||||
|
if (get_manager().proofs_enabled()) {
|
||||||
|
params.push_back(parameter(symbol("farkas")));
|
||||||
|
params.resize(lits.size()+1, parameter(rational(1)));
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.set_conflict(
|
||||||
|
ctx.mk_justification(
|
||||||
|
ext_theory_conflict_justification(
|
||||||
|
get_id(), ctx.get_region(),
|
||||||
|
lits.size(), lits.c_ptr(), 0, 0, params.size(), params.c_ptr())));
|
||||||
|
|
||||||
|
m_nc_functor.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Ext>
|
||||||
|
void theory_utvpi<Ext>::found_non_utvpi_expr(expr* n) {
|
||||||
|
if (!m_non_utvpi_exprs) {
|
||||||
|
std::stringstream msg;
|
||||||
|
msg << "found non utvpi logic expression:\n" << mk_pp(n, get_manager()) << "\n";
|
||||||
|
TRACE("utvpi", tout << msg.str(););
|
||||||
|
warning_msg(msg.str().c_str());
|
||||||
|
get_context().push_trail(value_trail<context, bool>(m_non_utvpi_exprs));
|
||||||
|
m_non_utvpi_exprs = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Ext>
|
||||||
|
void theory_utvpi<Ext>::init(context* ctx) {
|
||||||
|
theory::init(ctx);
|
||||||
|
m_zero_int = mk_var(ctx->mk_enode(a.mk_numeral(rational(0), true), false, false, true));
|
||||||
|
m_zero_real = mk_var(ctx->mk_enode(a.mk_numeral(rational(0), false), false, false, true));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
\brief Create negated literal.
|
||||||
|
|
||||||
|
The negation of: E <= 0
|
||||||
|
|
||||||
|
-E + epsilon <= 0
|
||||||
|
or
|
||||||
|
-E + 1 <= 0
|
||||||
|
*/
|
||||||
|
template<typename Ext>
|
||||||
|
void theory_utvpi<Ext>::negate(coeffs& coeffs, rational& weight) {
|
||||||
|
for (unsigned i = 0; i < coeffs.size(); ++i) {
|
||||||
|
coeffs[i].second.neg();
|
||||||
|
}
|
||||||
|
weight.neg();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Ext>
|
||||||
|
typename theory_utvpi<Ext>::numeral theory_utvpi<Ext>::mk_weight(bool is_real, bool is_strict, rational const& w) const {
|
||||||
|
if (is_strict) {
|
||||||
|
return numeral(w) + (is_real?Ext::m_epsilon:numeral(1));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return numeral(w);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Ext>
|
||||||
|
void theory_utvpi<Ext>::mk_coeffs(vector<std::pair<expr*,rational> > const& terms, coeffs& coeffs, rational& w) {
|
||||||
|
coeffs.reset();
|
||||||
|
w = m_test.get_weight();
|
||||||
|
for (unsigned i = 0; i < terms.size(); ++i) {
|
||||||
|
coeffs.push_back(std::make_pair(mk_var(terms[i].first), terms[i].second));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Ext>
|
||||||
|
void theory_utvpi<Ext>::internalize_eq_eh(app * atom, bool_var v) {
|
||||||
|
context & ctx = get_context();
|
||||||
|
app * lhs = to_app(atom->get_arg(0));
|
||||||
|
app * rhs = to_app(atom->get_arg(1));
|
||||||
|
if (a.is_numeral(rhs)) {
|
||||||
|
std::swap(rhs, lhs);
|
||||||
|
}
|
||||||
|
if (!a.is_numeral(rhs)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (a.is_add(lhs) || a.is_sub(lhs)) {
|
||||||
|
// force axioms for (= (+ x y) k)
|
||||||
|
// this is necessary because (+ x y) is not expressible as a utvpi term.
|
||||||
|
m_arith_eq_adapter.mk_axioms(ctx.get_enode(lhs), ctx.get_enode(rhs));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Ext>
|
||||||
|
bool theory_utvpi<Ext>::internalize_atom(app * n, bool) {
|
||||||
|
context & ctx = get_context();
|
||||||
|
if (!a.is_le(n) && !a.is_ge(n) && !a.is_lt(n) && !a.is_gt(n)) {
|
||||||
|
found_non_utvpi_expr(n);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
SASSERT(!ctx.b_internalized(n));
|
||||||
|
expr* e1 = n->get_arg(0), *e2 = n->get_arg(1);
|
||||||
|
if (a.is_ge(n) || a.is_gt(n)) {
|
||||||
|
std::swap(e1, e2);
|
||||||
|
}
|
||||||
|
bool is_strict = a.is_gt(n) || a.is_lt(n);
|
||||||
|
|
||||||
|
bool cl = m_test.linearize(e1, e2);
|
||||||
|
if (!cl) {
|
||||||
|
found_non_utvpi_expr(n);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
rational w;
|
||||||
|
coeffs coeffs;
|
||||||
|
mk_coeffs(m_test.get_linearization(), coeffs, w);
|
||||||
|
bool_var bv = ctx.mk_bool_var(n);
|
||||||
|
ctx.set_var_theory(bv, get_id());
|
||||||
|
literal l(bv);
|
||||||
|
numeral w1 = mk_weight(a.is_real(e1), is_strict, w);
|
||||||
|
edge_id pos = add_ineq(coeffs, w1, l);
|
||||||
|
negate(coeffs, w);
|
||||||
|
numeral w2 = mk_weight(a.is_real(e1), !is_strict, w);
|
||||||
|
edge_id neg = add_ineq(coeffs, w2, ~l);
|
||||||
|
m_bool_var2atom.insert(bv, m_atoms.size());
|
||||||
|
m_atoms.push_back(atom(bv, pos, neg));
|
||||||
|
|
||||||
|
TRACE("utvpi",
|
||||||
|
tout << mk_pp(n, get_manager()) << "\n";
|
||||||
|
m_graph.display_edge(tout << "pos: ", pos);
|
||||||
|
m_graph.display_edge(tout << "neg: ", neg);
|
||||||
|
);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Ext>
|
||||||
|
bool theory_utvpi<Ext>::internalize_term(app * term) {
|
||||||
|
bool result = null_theory_var != mk_term(term);
|
||||||
|
CTRACE("utvpi", !result, tout << "Did not internalize " << mk_pp(term, get_manager()) << "\n";);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Ext>
|
||||||
|
void theory_utvpi<Ext>::assign_eh(bool_var v, bool is_true) {
|
||||||
|
m_stats.m_num_assertions++;
|
||||||
|
unsigned idx = m_bool_var2atom.find(v);
|
||||||
|
SASSERT(get_context().get_assignment(v) != l_undef);
|
||||||
|
SASSERT((get_context().get_assignment(v) == l_true) == is_true);
|
||||||
|
m_atoms[idx].assign_eh(is_true);
|
||||||
|
m_asserted_atoms.push_back(idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Ext>
|
||||||
|
void theory_utvpi<Ext>::push_scope_eh() {
|
||||||
|
theory::push_scope_eh();
|
||||||
|
m_graph.push();
|
||||||
|
m_scopes.push_back(scope());
|
||||||
|
scope & s = m_scopes.back();
|
||||||
|
s.m_atoms_lim = m_atoms.size();
|
||||||
|
s.m_asserted_atoms_lim = m_asserted_atoms.size();
|
||||||
|
s.m_asserted_qhead_old = m_asserted_qhead;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Ext>
|
||||||
|
void theory_utvpi<Ext>::pop_scope_eh(unsigned num_scopes) {
|
||||||
|
unsigned lvl = m_scopes.size();
|
||||||
|
SASSERT(num_scopes <= lvl);
|
||||||
|
unsigned new_lvl = lvl - num_scopes;
|
||||||
|
scope & s = m_scopes[new_lvl];
|
||||||
|
del_atoms(s.m_atoms_lim);
|
||||||
|
m_asserted_atoms.shrink(s.m_asserted_atoms_lim);
|
||||||
|
m_asserted_qhead = s.m_asserted_qhead_old;
|
||||||
|
m_scopes.shrink(new_lvl);
|
||||||
|
m_graph.pop(num_scopes);
|
||||||
|
theory::pop_scope_eh(num_scopes);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Ext>
|
||||||
|
final_check_status theory_utvpi<Ext>::final_check_eh() {
|
||||||
|
SASSERT(is_consistent());
|
||||||
|
TRACE("utvpi", display(tout););
|
||||||
|
if (can_propagate()) {
|
||||||
|
propagate();
|
||||||
|
return FC_CONTINUE;
|
||||||
|
}
|
||||||
|
else if (!check_z_consistency()) {
|
||||||
|
return FC_CONTINUE;
|
||||||
|
}
|
||||||
|
else if (m_non_utvpi_exprs) {
|
||||||
|
return FC_GIVEUP;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
m_graph.set_to_zero(to_var(m_zero_int), to_var(m_zero_real));
|
||||||
|
m_graph.set_to_zero(neg(to_var(m_zero_int)), neg(to_var(m_zero_real)));
|
||||||
|
m_graph.set_to_zero(to_var(m_zero_int), neg(to_var(m_zero_int)));
|
||||||
|
return FC_DONE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Ext>
|
||||||
|
bool theory_utvpi<Ext>::check_z_consistency() {
|
||||||
|
int_vector scc_id;
|
||||||
|
m_graph.compute_zero_edge_scc(scc_id);
|
||||||
|
|
||||||
|
unsigned sz = get_num_vars();
|
||||||
|
for (unsigned i = 0; i < sz; ++i) {
|
||||||
|
enode* e = get_enode(i);
|
||||||
|
if (a.is_int(e->get_owner())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
th_var v1 = to_var(i);
|
||||||
|
th_var v2 = neg(v1);
|
||||||
|
rational r1 = m_graph.get_assignment(v1).get_rational();
|
||||||
|
rational r2 = m_graph.get_assignment(v2).get_rational();
|
||||||
|
SASSERT(r1.is_int());
|
||||||
|
SASSERT(r2.is_int());
|
||||||
|
if (r1.is_even() == r2.is_even()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (scc_id[v1] != scc_id[v2]) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (scc_id[v1] == -1) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// they are in the same SCC and have different parities => contradiction.
|
||||||
|
m_nc_functor.reset();
|
||||||
|
VERIFY(m_graph.find_shortest_zero_edge_path(v1, v2, UINT_MAX, m_nc_functor));
|
||||||
|
VERIFY(m_graph.find_shortest_zero_edge_path(v2, v1, UINT_MAX, m_nc_functor));
|
||||||
|
IF_VERBOSE(1, verbose_stream() << "parity conflict " << mk_pp(e->get_owner(), get_manager()) << "\n";);
|
||||||
|
set_conflict();
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Ext>
|
||||||
|
void theory_utvpi<Ext>::display(std::ostream& out) const {
|
||||||
|
for (unsigned i = 0; i < m_atoms.size(); ++i) {
|
||||||
|
m_atoms[i].display(*this, out); out << "\n";
|
||||||
|
}
|
||||||
|
m_graph.display(out);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Ext>
|
||||||
|
void theory_utvpi<Ext>::collect_statistics(::statistics& st) const {
|
||||||
|
st.update("utvpi conflicts", m_stats.m_num_conflicts);
|
||||||
|
st.update("utvpi asserts", m_stats.m_num_assertions);
|
||||||
|
st.update("core->utvpi eqs", m_stats.m_num_core2th_eqs);
|
||||||
|
st.update("core->utvpi diseqs", m_stats.m_num_core2th_diseqs);
|
||||||
|
m_arith_eq_adapter.collect_statistics(st);
|
||||||
|
m_graph.collect_statistics(st);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Ext>
|
||||||
|
void theory_utvpi<Ext>::del_atoms(unsigned old_size) {
|
||||||
|
typename atoms::iterator begin = m_atoms.begin() + old_size;
|
||||||
|
typename atoms::iterator it = m_atoms.end();
|
||||||
|
while (it != begin) {
|
||||||
|
--it;
|
||||||
|
m_bool_var2atom.erase(it->get_bool_var());
|
||||||
|
}
|
||||||
|
m_atoms.shrink(old_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Ext>
|
||||||
|
void theory_utvpi<Ext>::propagate() {
|
||||||
|
bool consistent = true;
|
||||||
|
while (consistent && can_propagate()) {
|
||||||
|
unsigned idx = m_asserted_atoms[m_asserted_qhead];
|
||||||
|
m_asserted_qhead++;
|
||||||
|
consistent = propagate_atom(m_atoms[idx]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Ext>
|
||||||
|
bool theory_utvpi<Ext>::propagate_atom(atom const& a) {
|
||||||
|
context& ctx = get_context();
|
||||||
|
TRACE("utvpi", a.display(*this, tout); tout << "\n";);
|
||||||
|
if (ctx.inconsistent()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
int edge_id = a.get_asserted_edge();
|
||||||
|
if (!enable_edge(edge_id)) {
|
||||||
|
m_graph.traverse_neg_cycle2(m_params.m_arith_stronger_lemmas, m_nc_functor);
|
||||||
|
set_conflict();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Ext>
|
||||||
|
theory_var theory_utvpi<Ext>::mk_term(app* n) {
|
||||||
|
TRACE("utvpi", tout << mk_pp(n, get_manager()) << "\n";);
|
||||||
|
context& ctx = get_context();
|
||||||
|
|
||||||
|
bool cl = m_test.linearize(n);
|
||||||
|
if (!cl) {
|
||||||
|
found_non_utvpi_expr(n);
|
||||||
|
return null_theory_var;
|
||||||
|
}
|
||||||
|
|
||||||
|
coeffs coeffs;
|
||||||
|
rational w;
|
||||||
|
mk_coeffs(m_test.get_linearization(), coeffs, w);
|
||||||
|
if (coeffs.empty()) {
|
||||||
|
return mk_num(n, w);
|
||||||
|
}
|
||||||
|
if (coeffs.size() == 1 && coeffs[0].second.is_one()) {
|
||||||
|
return coeffs[0].first;
|
||||||
|
}
|
||||||
|
if (coeffs.size() == 2) {
|
||||||
|
// do not create an alias.
|
||||||
|
return null_theory_var;
|
||||||
|
}
|
||||||
|
for (unsigned i = 0; i < n->get_num_args(); ++i) {
|
||||||
|
mk_term(to_app(n->get_arg(i)));
|
||||||
|
}
|
||||||
|
th_var target = mk_var(ctx.mk_enode(n, false, false, true));
|
||||||
|
coeffs.push_back(std::make_pair(target, rational(-1)));
|
||||||
|
|
||||||
|
VERIFY(enable_edge(add_ineq(coeffs, numeral(w), null_literal)));
|
||||||
|
negate(coeffs, w);
|
||||||
|
VERIFY(enable_edge(add_ineq(coeffs, numeral(w), null_literal)));
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Ext>
|
||||||
|
theory_var theory_utvpi<Ext>::mk_num(app* n, rational const& r) {
|
||||||
|
theory_var v = null_theory_var;
|
||||||
|
context& ctx = get_context();
|
||||||
|
if (r.is_zero()) {
|
||||||
|
v = a.is_int(n)?m_zero_int:m_zero_real;
|
||||||
|
}
|
||||||
|
else if (ctx.e_internalized(n)) {
|
||||||
|
enode* e = ctx.get_enode(n);
|
||||||
|
v = e->get_th_var(get_id());
|
||||||
|
SASSERT(v != null_theory_var);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
v = mk_var(ctx.mk_enode(n, false, false, true));
|
||||||
|
// v = k: v <= k k <= v
|
||||||
|
coeffs coeffs;
|
||||||
|
coeffs.push_back(std::make_pair(v, rational(-1)));
|
||||||
|
VERIFY(enable_edge(add_ineq(coeffs, numeral(r), null_literal)));
|
||||||
|
coeffs.back().second.neg();
|
||||||
|
VERIFY(enable_edge(add_ineq(coeffs, numeral(-r), null_literal)));
|
||||||
|
}
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Ext>
|
||||||
|
theory_var theory_utvpi<Ext>::expand(bool pos, th_var v, rational & k) {
|
||||||
|
context& ctx = get_context();
|
||||||
|
enode* e = get_enode(v);
|
||||||
|
expr* x, *y;
|
||||||
|
rational r;
|
||||||
|
for (;;) {
|
||||||
|
app* n = e->get_owner();
|
||||||
|
if (a.is_add(n, x, y)) {
|
||||||
|
if (a.is_numeral(x, r)) {
|
||||||
|
e = ctx.get_enode(y);
|
||||||
|
}
|
||||||
|
else if (a.is_numeral(y, r)) {
|
||||||
|
e = ctx.get_enode(x);
|
||||||
|
}
|
||||||
|
v = e->get_th_var(get_id());
|
||||||
|
SASSERT(v != null_theory_var);
|
||||||
|
if (v == null_theory_var) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (pos) {
|
||||||
|
k += r;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
k -= r;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
// m_graph(source, target, weight, ex);
|
||||||
|
// target - source <= weight
|
||||||
|
|
||||||
|
template<typename Ext>
|
||||||
|
edge_id theory_utvpi<Ext>::add_ineq(vector<std::pair<th_var, rational> > const& terms, numeral const& weight, literal l) {
|
||||||
|
|
||||||
|
SASSERT(terms.size() <= 2);
|
||||||
|
SASSERT(terms.size() < 1 || terms[0].second.is_one() || terms[0].second.is_minus_one());
|
||||||
|
SASSERT(terms.size() < 2 || terms[1].second.is_one() || terms[1].second.is_minus_one());
|
||||||
|
|
||||||
|
th_var v1 = null_theory_var, v2 = null_theory_var;
|
||||||
|
bool pos1 = true, pos2 = true;
|
||||||
|
if (terms.size() >= 1) {
|
||||||
|
v1 = terms[0].first;
|
||||||
|
pos1 = terms[0].second.is_one();
|
||||||
|
SASSERT(v1 != null_theory_var);
|
||||||
|
SASSERT(pos1 || terms[0].second.is_minus_one());
|
||||||
|
}
|
||||||
|
if (terms.size() >= 2) {
|
||||||
|
v2 = terms[1].first;
|
||||||
|
pos2 = terms[1].second.is_one();
|
||||||
|
SASSERT(v1 != null_theory_var);
|
||||||
|
SASSERT(pos2 || terms[1].second.is_minus_one());
|
||||||
|
}
|
||||||
|
// TRACE("utvpi", tout << (pos1?"$":"-$") << v1 << (pos2?" + $":" - $") << v2 << " + " << weight << " <= 0\n";);
|
||||||
|
edge_id id = m_graph.get_num_edges();
|
||||||
|
th_var w1 = to_var(v1), w2 = to_var(v2);
|
||||||
|
if (terms.size() == 1 && pos1) {
|
||||||
|
m_graph.add_edge(neg(w1), pos(w1), -weight-weight, l);
|
||||||
|
m_graph.add_edge(neg(w1), pos(w1), -weight-weight, l);
|
||||||
|
}
|
||||||
|
else if (terms.size() == 1 && !pos1) {
|
||||||
|
m_graph.add_edge(pos(w1), neg(w1), -weight-weight, l);
|
||||||
|
m_graph.add_edge(pos(w1), neg(w1), -weight-weight, l);
|
||||||
|
}
|
||||||
|
else if (pos1 && pos2) {
|
||||||
|
m_graph.add_edge(neg(w2), pos(w1), -weight, l);
|
||||||
|
m_graph.add_edge(neg(w1), pos(w2), -weight, l);
|
||||||
|
}
|
||||||
|
else if (pos1 && !pos2) {
|
||||||
|
m_graph.add_edge(pos(w2), pos(w1), -weight, l);
|
||||||
|
m_graph.add_edge(neg(w1), neg(w2), -weight, l);
|
||||||
|
}
|
||||||
|
else if (!pos1 && pos2) {
|
||||||
|
m_graph.add_edge(neg(w2), neg(w1), -weight, l);
|
||||||
|
m_graph.add_edge(pos(w1), pos(w2), -weight, l);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
m_graph.add_edge(pos(w1), neg(w2), -weight, l);
|
||||||
|
m_graph.add_edge(pos(w2), neg(w1), -weight, l);
|
||||||
|
}
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Ext>
|
||||||
|
bool theory_utvpi<Ext>::enable_edge(edge_id id) {
|
||||||
|
return (id == null_edge_id) || (m_graph.enable_edge(id) && m_graph.enable_edge(id+1));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Ext>
|
||||||
|
bool theory_utvpi<Ext>::is_consistent() const {
|
||||||
|
return m_graph.is_feasible();
|
||||||
|
}
|
||||||
|
|
||||||
|
// models:
|
||||||
|
template<typename Ext>
|
||||||
|
void theory_utvpi<Ext>::init_model(model_generator & m) {
|
||||||
|
m_factory = alloc(arith_factory, get_manager());
|
||||||
|
m.register_factory(m_factory);
|
||||||
|
// TBD: enforce strong or tight coherence?
|
||||||
|
compute_delta();
|
||||||
|
DEBUG_CODE(validate_model(););
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Ext>
|
||||||
|
void theory_utvpi<Ext>::validate_model() {
|
||||||
|
context& ctx = get_context();
|
||||||
|
unsigned sz = m_atoms.size();
|
||||||
|
for (unsigned i = 0; i < sz; ++i) {
|
||||||
|
bool_var b = m_atoms[i].get_bool_var();
|
||||||
|
if (!ctx.is_relevant(b)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
bool ok = true;
|
||||||
|
expr* e = ctx.bool_var2expr(b);
|
||||||
|
switch(ctx.get_assignment(b)) {
|
||||||
|
case l_true:
|
||||||
|
ok = eval(e);
|
||||||
|
break;
|
||||||
|
case l_false:
|
||||||
|
ok = !eval(e);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
CTRACE("utvpi", !ok, tout << "validation failed: " << mk_pp(e, get_manager()) << "\n";);
|
||||||
|
// CTRACE("utvpi", ok, tout << "validation success: " << mk_pp(e, get_manager()) << "\n";);
|
||||||
|
SASSERT(ok);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Ext>
|
||||||
|
bool theory_utvpi<Ext>::eval(expr* e) {
|
||||||
|
expr* e1, *e2;
|
||||||
|
if (a.is_le(e, e1, e2) || a.is_ge(e, e2, e1)) {
|
||||||
|
return eval_num(e1) <= eval_num(e2);
|
||||||
|
}
|
||||||
|
if (a.is_lt(e, e1, e2) || a.is_gt(e, e2, e1)) {
|
||||||
|
return eval_num(e1) < eval_num(e2);
|
||||||
|
}
|
||||||
|
if (get_manager().is_eq(e, e1, e2)) {
|
||||||
|
return eval_num(e1) == eval_num(e2);
|
||||||
|
}
|
||||||
|
TRACE("utvpi", tout << "expression not handled: " << mk_pp(e, get_manager()) << "\n";);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Ext>
|
||||||
|
rational theory_utvpi<Ext>::eval_num(expr* e) {
|
||||||
|
rational r;
|
||||||
|
expr* e1, *e2;
|
||||||
|
if (a.is_numeral(e, r)) {
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
if (a.is_sub(e, e1, e2)) {
|
||||||
|
return eval_num(e1) - eval_num(e2);
|
||||||
|
}
|
||||||
|
if (a.is_add(e)) {
|
||||||
|
r.reset();
|
||||||
|
for (unsigned i = 0; i < to_app(e)->get_num_args(); ++i) {
|
||||||
|
r += eval_num(to_app(e)->get_arg(i));
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
if (a.is_mul(e)) {
|
||||||
|
r = rational(1);
|
||||||
|
for (unsigned i = 0; i < to_app(e)->get_num_args(); ++i) {
|
||||||
|
r *= eval_num(to_app(e)->get_arg(i));
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
if (a.is_uminus(e, e1)) {
|
||||||
|
return -eval_num(e1);
|
||||||
|
}
|
||||||
|
if (a.is_to_real(e, e1)) {
|
||||||
|
return eval_num(e1);
|
||||||
|
}
|
||||||
|
if (is_uninterp_const(e)) {
|
||||||
|
return mk_value(mk_var(e));
|
||||||
|
}
|
||||||
|
TRACE("utvpi", tout << "expression not handled: " << mk_pp(e, get_manager()) << "\n";);
|
||||||
|
UNREACHABLE();
|
||||||
|
return rational(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<typename Ext>
|
||||||
|
rational theory_utvpi<Ext>::mk_value(th_var v) {
|
||||||
|
SASSERT(v != null_theory_var);
|
||||||
|
numeral val1 = m_graph.get_assignment(to_var(v));
|
||||||
|
numeral val2 = m_graph.get_assignment(neg(to_var(v)));
|
||||||
|
numeral val = val1 - val2;
|
||||||
|
rational num = val.get_rational() + (m_delta * val.get_infinitesimal().to_rational());
|
||||||
|
num = num/rational(2);
|
||||||
|
num = floor(num);
|
||||||
|
return num;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Ext>
|
||||||
|
model_value_proc * theory_utvpi<Ext>::mk_value(enode * n, model_generator & mg) {
|
||||||
|
theory_var v = n->get_th_var(get_id());
|
||||||
|
rational num = mk_value(v);
|
||||||
|
TRACE("utvpi", tout << mk_pp(n->get_owner(), get_manager()) << " |-> " << num << "\n";);
|
||||||
|
return alloc(expr_wrapper_proc, m_factory->mk_value(num, a.is_int(n->get_owner())));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
\brief Compute numeral values for the infinitesimals to satisfy the inequalities.
|
||||||
|
*/
|
||||||
|
|
||||||
|
template<typename Ext>
|
||||||
|
void theory_utvpi<Ext>::compute_delta() {
|
||||||
|
m_delta = rational(1);
|
||||||
|
unsigned sz = m_graph.get_num_edges();
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < sz; ++i) {
|
||||||
|
if (!m_graph.is_enabled(i)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
numeral w = m_graph.get_weight(i);
|
||||||
|
numeral tgt = m_graph.get_assignment(m_graph.get_target(i));
|
||||||
|
numeral src = m_graph.get_assignment(m_graph.get_source(i));
|
||||||
|
numeral b = tgt - src - w;
|
||||||
|
SASSERT(b.is_nonpos());
|
||||||
|
rational eps_r = b.get_infinitesimal();
|
||||||
|
|
||||||
|
// Given: b <= 0
|
||||||
|
// suppose that 0 < b.eps
|
||||||
|
// then we have 0 > b.num
|
||||||
|
// then delta must ensure:
|
||||||
|
// 0 >= b.num + delta*b.eps
|
||||||
|
// <=>
|
||||||
|
// -b.num/b.eps >= delta
|
||||||
|
if (eps_r.is_pos()) {
|
||||||
|
rational num_r = -b.get_rational();
|
||||||
|
SASSERT(num_r.is_pos());
|
||||||
|
rational new_delta = num_r/eps_r;
|
||||||
|
if (new_delta < m_delta) {
|
||||||
|
m_delta = new_delta;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -371,6 +371,12 @@ struct ctx_simplify_tactic::imp {
|
||||||
if (!modified) {
|
if (!modified) {
|
||||||
r = t;
|
r = t;
|
||||||
}
|
}
|
||||||
|
else if (new_new_args.empty()) {
|
||||||
|
r = OR?m.mk_false():m.mk_true();
|
||||||
|
}
|
||||||
|
else if (new_new_args.size() == 1) {
|
||||||
|
r = new_new_args[0];
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
std::reverse(new_new_args.c_ptr(), new_new_args.c_ptr() + new_new_args.size());
|
std::reverse(new_new_args.c_ptr(), new_new_args.c_ptr() + new_new_args.size());
|
||||||
m_mk_app(t->get_decl(), new_new_args.size(), new_new_args.c_ptr(), r);
|
m_mk_app(t->get_decl(), new_new_args.size(), new_new_args.c_ptr(), r);
|
||||||
|
|
|
@ -94,7 +94,6 @@ public:
|
||||||
smt_strategic_solver_factory(symbol const & logic):m_logic(logic) {}
|
smt_strategic_solver_factory(symbol const & logic):m_logic(logic) {}
|
||||||
|
|
||||||
virtual ~smt_strategic_solver_factory() {}
|
virtual ~smt_strategic_solver_factory() {}
|
||||||
|
|
||||||
virtual solver * operator()(ast_manager & m, params_ref const & p, bool proofs_enabled, bool models_enabled, bool unsat_core_enabled, symbol const & logic) {
|
virtual solver * operator()(ast_manager & m, params_ref const & p, bool proofs_enabled, bool models_enabled, bool unsat_core_enabled, symbol const & logic) {
|
||||||
symbol l;
|
symbol l;
|
||||||
if (m_logic != symbol::null)
|
if (m_logic != symbol::null)
|
||||||
|
|
|
@ -20,6 +20,7 @@ Revision History:
|
||||||
#define _HASH_H_
|
#define _HASH_H_
|
||||||
|
|
||||||
#include<algorithm>
|
#include<algorithm>
|
||||||
|
#include"util.h"
|
||||||
|
|
||||||
#ifndef __fallthrough
|
#ifndef __fallthrough
|
||||||
#define __fallthrough
|
#define __fallthrough
|
||||||
|
@ -142,6 +143,11 @@ struct size_t_hash {
|
||||||
unsigned operator()(size_t x) const { return static_cast<unsigned>(x); }
|
unsigned operator()(size_t x) const { return static_cast<unsigned>(x); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct uint64_hash {
|
||||||
|
typedef uint64 data;
|
||||||
|
unsigned operator()(uint64 x) const { return static_cast<unsigned>(x); }
|
||||||
|
};
|
||||||
|
|
||||||
struct bool_hash {
|
struct bool_hash {
|
||||||
typedef bool data;
|
typedef bool data;
|
||||||
unsigned operator()(bool x) const { return static_cast<unsigned>(x); }
|
unsigned operator()(bool x) const { return static_cast<unsigned>(x); }
|
||||||
|
|
409
src/util/inf_eps_rational.h
Normal file
409
src/util/inf_eps_rational.h
Normal file
|
@ -0,0 +1,409 @@
|
||||||
|
/*++
|
||||||
|
Copyright (c) 2013 Microsoft Corporation
|
||||||
|
|
||||||
|
Module Name:
|
||||||
|
|
||||||
|
inf_eps_rational.h
|
||||||
|
|
||||||
|
Abstract:
|
||||||
|
|
||||||
|
Rational numbers with infinity and epsilon.
|
||||||
|
|
||||||
|
Author:
|
||||||
|
|
||||||
|
Nikolaj Bjorner (nbjorner) 2013-4-23.
|
||||||
|
|
||||||
|
Revision History:
|
||||||
|
|
||||||
|
--*/
|
||||||
|
#ifndef _INF_EPS_RATIONAL_H_
|
||||||
|
#define _INF_EPS_RATIONAL_H_
|
||||||
|
#include<stdlib.h>
|
||||||
|
#include<string>
|
||||||
|
#include"debug.h"
|
||||||
|
#include"vector.h"
|
||||||
|
#include"rational.h"
|
||||||
|
|
||||||
|
template<typename Numeral>
|
||||||
|
class inf_eps_rational {
|
||||||
|
rational m_infty;
|
||||||
|
Numeral m_r;
|
||||||
|
public:
|
||||||
|
|
||||||
|
unsigned hash() const {
|
||||||
|
return m_infty.hash() ^ m_r.hash();
|
||||||
|
}
|
||||||
|
|
||||||
|
struct hash_proc { unsigned operator()(inf_eps_rational const& r) const { return r.hash(); } };
|
||||||
|
|
||||||
|
struct eq_proc { bool operator()(inf_eps_rational const& r1, inf_eps_rational const& r2) const { return r1 == r2; } };
|
||||||
|
|
||||||
|
void swap(inf_eps_rational & n) {
|
||||||
|
m_infty.swap(n.m_infty);
|
||||||
|
m_r.swap(n.m_r);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string to_string() const {
|
||||||
|
if (m_infty.is_zero()) {
|
||||||
|
return m_r.to_string();
|
||||||
|
}
|
||||||
|
std::string si;
|
||||||
|
if (m_infty.is_one()) {
|
||||||
|
si = "oo";
|
||||||
|
}
|
||||||
|
else if (m_infty.is_minus_one()) {
|
||||||
|
si = "-oo";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
si = m_infty.to_string() += "*oo";
|
||||||
|
}
|
||||||
|
if (m_r.is_zero()) {
|
||||||
|
return si;
|
||||||
|
}
|
||||||
|
std::string s = "(";
|
||||||
|
s += si;
|
||||||
|
s += " + ";
|
||||||
|
s += m_r.to_string();
|
||||||
|
s += ")";
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
inf_eps_rational():
|
||||||
|
m_infty(),
|
||||||
|
m_r()
|
||||||
|
{}
|
||||||
|
|
||||||
|
inf_eps_rational(const inf_eps_rational & r):
|
||||||
|
m_infty(r.m_infty),
|
||||||
|
m_r(r.m_r)
|
||||||
|
{}
|
||||||
|
|
||||||
|
explicit inf_eps_rational(int n):
|
||||||
|
m_infty(),
|
||||||
|
m_r(n)
|
||||||
|
{}
|
||||||
|
|
||||||
|
explicit inf_eps_rational(Numeral const& r):
|
||||||
|
m_infty(),
|
||||||
|
m_r(r)
|
||||||
|
{}
|
||||||
|
|
||||||
|
explicit inf_eps_rational(rational const& i, Numeral const& r):
|
||||||
|
m_infty(i),
|
||||||
|
m_r(r) {
|
||||||
|
}
|
||||||
|
|
||||||
|
~inf_eps_rational() {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
\brief Set inf_eps_rational to 0.
|
||||||
|
*/
|
||||||
|
void reset() {
|
||||||
|
m_infty.reset();
|
||||||
|
m_r.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_int() const {
|
||||||
|
return m_infty.is_zero() && m_r.is_int();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_int64() const {
|
||||||
|
return m_infty.is_zero() && m_r.is_int64();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_uint64() const {
|
||||||
|
return m_infty.is_zero() && m_r.is_uint64();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_rational() const { return m_infty.is_zero() && m_r.is_rational(); }
|
||||||
|
|
||||||
|
int64 get_int64() const {
|
||||||
|
SASSERT(is_int64());
|
||||||
|
return m_r.get_int64();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64 get_uint64() const {
|
||||||
|
SASSERT(is_uint64());
|
||||||
|
return m_r.get_uint64();
|
||||||
|
}
|
||||||
|
|
||||||
|
rational const& get_rational() const {
|
||||||
|
return m_r.get_rational();
|
||||||
|
}
|
||||||
|
|
||||||
|
rational const& get_infinitesimal() const {
|
||||||
|
return m_r.get_infinitesimal();
|
||||||
|
}
|
||||||
|
|
||||||
|
rational const& get_infinity() const {
|
||||||
|
return m_infty;
|
||||||
|
}
|
||||||
|
|
||||||
|
inf_eps_rational & operator=(const inf_eps_rational & r) {
|
||||||
|
m_infty = r.m_infty;
|
||||||
|
m_r = r.m_r;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
inf_eps_rational & operator=(const rational & r) {
|
||||||
|
m_infty.reset();
|
||||||
|
m_r = r;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
inf_eps_rational & operator+=(const inf_eps_rational & r) {
|
||||||
|
m_infty += r.m_infty;
|
||||||
|
m_r += r.m_r;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
inf_eps_rational & operator-=(const inf_eps_rational & r) {
|
||||||
|
m_infty -= r.m_infty;
|
||||||
|
m_r -= r.m_r;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
inf_eps_rational & operator+=(const rational & r) {
|
||||||
|
m_r += r;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
inf_eps_rational & operator-=(const rational & r) {
|
||||||
|
m_r -= r;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
inf_eps_rational & operator*=(const rational & r1) {
|
||||||
|
m_infty *= r1;
|
||||||
|
m_r *= r1;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
inf_eps_rational & operator/=(const rational & r) {
|
||||||
|
m_infty /= r;
|
||||||
|
m_r /= r;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inf_eps_rational & operator++() {
|
||||||
|
++m_r;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
const inf_eps_rational operator++(int) { inf_eps_rational tmp(*this); ++(*this); return tmp; }
|
||||||
|
|
||||||
|
inf_eps_rational & operator--() {
|
||||||
|
--m_r;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
const inf_eps_rational operator--(int) { inf_eps_rational tmp(*this); --(*this); return tmp; }
|
||||||
|
|
||||||
|
friend inline bool operator==(const inf_eps_rational & r1, const inf_eps_rational & r2) {
|
||||||
|
return r1.m_infty == r2.m_infty && r1.m_r == r2.m_r;
|
||||||
|
}
|
||||||
|
|
||||||
|
friend inline bool operator==(const rational & r1, const inf_eps_rational & r2) {
|
||||||
|
return r1 == r2.m_infty && r2.m_r.is_zero();
|
||||||
|
}
|
||||||
|
|
||||||
|
friend inline bool operator==(const inf_eps_rational & r1, const rational & r2) {
|
||||||
|
return r1.m_infty == r2 && r1.m_r.is_zero();
|
||||||
|
}
|
||||||
|
|
||||||
|
friend inline bool operator<(const inf_eps_rational & r1, const inf_eps_rational & r2) {
|
||||||
|
return
|
||||||
|
(r1.m_infty < r2.m_infty) ||
|
||||||
|
(r1.m_infty == r2.m_infty && r1.m_r < r2.m_r);
|
||||||
|
}
|
||||||
|
|
||||||
|
friend inline bool operator<(const rational & r1, const inf_eps_rational & r2) {
|
||||||
|
return
|
||||||
|
r2.m_infty.is_pos() ||
|
||||||
|
(r2.m_infty.is_zero() && r1 < r2.m_r);
|
||||||
|
}
|
||||||
|
|
||||||
|
friend inline bool operator<(const inf_eps_rational & r1, const rational & r2) {
|
||||||
|
return
|
||||||
|
r1.m_infty.is_neg() ||
|
||||||
|
(r1.m_infty.is_zero() && r1.m_r < r2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void neg() {
|
||||||
|
m_infty.neg();
|
||||||
|
m_r.neg();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_zero() const {
|
||||||
|
return m_infty.is_zero() && m_r.is_zero();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_one() const {
|
||||||
|
return m_infty.is_zero() && m_r.is_one();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_minus_one() const {
|
||||||
|
return m_infty.is_zero() && m_r.is_minus_one();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_neg() const {
|
||||||
|
return
|
||||||
|
m_infty.is_neg() ||
|
||||||
|
(m_infty.is_zero() && m_r.is_neg());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_pos() const {
|
||||||
|
return
|
||||||
|
m_infty.is_pos() ||
|
||||||
|
(m_infty.is_zero() && m_r.is_pos());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_nonneg() const {
|
||||||
|
return
|
||||||
|
m_infty.is_pos() ||
|
||||||
|
(m_infty.is_zero() && m_r.is_nonneg());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_nonpos() const {
|
||||||
|
return
|
||||||
|
m_infty.is_neg() ||
|
||||||
|
(m_infty.is_zero() && m_r.is_nonpos());
|
||||||
|
}
|
||||||
|
|
||||||
|
friend inline rational floor(const inf_eps_rational & r) {
|
||||||
|
SASSERT(r.m_infty.is_zero());
|
||||||
|
return floor(r.m_r);
|
||||||
|
}
|
||||||
|
|
||||||
|
friend inline rational ceil(const inf_eps_rational & r) {
|
||||||
|
SASSERT(r.m_infty.is_zero());
|
||||||
|
return ceil(r.m_r);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Perform: this += c * k
|
||||||
|
void addmul(const rational & c, const inf_eps_rational & k) {
|
||||||
|
m_infty.addmul(c, k.m_infty);
|
||||||
|
m_r.addmul(c, k.m_r);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Perform: this += c * k
|
||||||
|
void submul(const rational & c, const inf_eps_rational & k) {
|
||||||
|
m_infty.submul(c, k.m_infty);
|
||||||
|
m_r.submul(c, k.m_r);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename N>
|
||||||
|
inline bool operator!=(const inf_eps_rational<N> & r1, const inf_eps_rational<N> & r2) {
|
||||||
|
return !operator==(r1, r2);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename N>
|
||||||
|
inline bool operator!=(const rational & r1, const inf_eps_rational<N> & r2) {
|
||||||
|
return !operator==(r1, r2);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename N>
|
||||||
|
inline bool operator!=(const inf_eps_rational<N> & r1, const rational & r2) {
|
||||||
|
return !operator==(r1, r2);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename N>
|
||||||
|
inline bool operator>(const inf_eps_rational<N> & r1, const inf_eps_rational<N> & r2) {
|
||||||
|
return operator<(r2, r1);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename N>
|
||||||
|
inline bool operator>(const inf_eps_rational<N> & r1, const rational & r2) {
|
||||||
|
return operator<(r2, r1);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename N>
|
||||||
|
inline bool operator>(const rational & r1, const inf_eps_rational<N> & r2) {
|
||||||
|
return operator<(r2, r1);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename N>
|
||||||
|
inline bool operator<=(const inf_eps_rational<N> & r1, const inf_eps_rational<N> & r2) {
|
||||||
|
return !operator>(r1, r2);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename N>
|
||||||
|
inline bool operator<=(const rational & r1, const inf_eps_rational<N> & r2) {
|
||||||
|
return !operator>(r1, r2);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename N>
|
||||||
|
inline bool operator<=(const inf_eps_rational<N> & r1, const rational & r2) {
|
||||||
|
return !operator>(r1, r2);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename N>
|
||||||
|
inline bool operator>=(const inf_eps_rational<N> & r1, const inf_eps_rational<N> & r2) {
|
||||||
|
return !operator<(r1, r2);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename N>
|
||||||
|
inline bool operator>=(const rational & r1, const inf_eps_rational<N> & r2) {
|
||||||
|
return !operator<(r1, r2);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename N>
|
||||||
|
inline bool operator>=(const inf_eps_rational<N> & r1, const rational & r2) {
|
||||||
|
return !operator<(r1, r2);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename N>
|
||||||
|
inline inf_eps_rational<N> operator+(const inf_eps_rational<N> & r1, const inf_eps_rational<N> & r2) {
|
||||||
|
return inf_eps_rational<N>(r1) += r2;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename N>
|
||||||
|
inline inf_eps_rational<N> operator-(const inf_eps_rational<N> & r1, const inf_eps_rational<N> & r2) {
|
||||||
|
return inf_eps_rational<N>(r1) -= r2;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename N>
|
||||||
|
inline inf_eps_rational<N> operator-(const inf_eps_rational<N> & r) {
|
||||||
|
inf_eps_rational<N> result(r);
|
||||||
|
result.neg();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename N>
|
||||||
|
inline inf_eps_rational<N> operator*(const rational & r1, const inf_eps_rational<N> & r2) {
|
||||||
|
inf_eps_rational<N> result(r2);
|
||||||
|
result *= r1;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename N>
|
||||||
|
inline inf_eps_rational<N> operator*(const inf_eps_rational<N> & r1, const rational & r2) {
|
||||||
|
return r2 * r1;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename N>
|
||||||
|
inline inf_eps_rational<N> operator/(const inf_eps_rational<N> & r1, const rational & r2) {
|
||||||
|
inf_eps_rational<N> result(r1);
|
||||||
|
result /= r2;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename N>
|
||||||
|
inline std::ostream & operator<<(std::ostream & target, const inf_eps_rational<N> & r) {
|
||||||
|
target << r.to_string();
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename N>
|
||||||
|
inline inf_eps_rational<N> abs(const inf_eps_rational<N> & r) {
|
||||||
|
inf_eps_rational<N> result(r);
|
||||||
|
if (result.is_neg()) {
|
||||||
|
result.neg();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* _INF_EPS_RATIONAL_H_ */
|
|
@ -223,6 +223,7 @@ class inf_rational {
|
||||||
}
|
}
|
||||||
|
|
||||||
friend inline inf_rational operator*(const rational & r1, const inf_rational & r2);
|
friend inline inf_rational operator*(const rational & r1, const inf_rational & r2);
|
||||||
|
friend inline inf_rational operator*(const inf_rational & r1, const rational & r2);
|
||||||
friend inline inf_rational operator/(const inf_rational & r1, const rational & r2);
|
friend inline inf_rational operator/(const inf_rational & r1, const rational & r2);
|
||||||
|
|
||||||
inf_rational & operator++() {
|
inf_rational & operator++() {
|
||||||
|
@ -426,6 +427,10 @@ inline inf_rational operator*(const rational & r1, const inf_rational & r2) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline inf_rational operator*(const inf_rational & r1, const rational & r2) {
|
||||||
|
return r2 * r1;
|
||||||
|
}
|
||||||
|
|
||||||
inline inf_rational operator/(const inf_rational & r1, const rational & r2) {
|
inline inf_rational operator/(const inf_rational & r1, const rational & r2) {
|
||||||
inf_rational result(r1);
|
inf_rational result(r1);
|
||||||
result.m_first /= r2;
|
result.m_first /= r2;
|
||||||
|
|
|
@ -231,9 +231,8 @@ void * memory::allocate(size_t s) {
|
||||||
return 0;
|
return 0;
|
||||||
s = s + sizeof(size_t); // we allocate an extra field!
|
s = s + sizeof(size_t); // we allocate an extra field!
|
||||||
void * r = malloc(s);
|
void * r = malloc(s);
|
||||||
if (r == 0) {
|
if (r == 0)
|
||||||
throw_out_of_memory();
|
throw_out_of_memory();
|
||||||
}
|
|
||||||
*(static_cast<size_t*>(r)) = s;
|
*(static_cast<size_t*>(r)) = s;
|
||||||
g_memory_thread_alloc_size += s;
|
g_memory_thread_alloc_size += s;
|
||||||
if (g_memory_thread_alloc_size > SYNCH_THRESHOLD) {
|
if (g_memory_thread_alloc_size > SYNCH_THRESHOLD) {
|
||||||
|
|
|
@ -432,24 +432,29 @@ typedef svector<unsigned> unsigned_vector;
|
||||||
typedef svector<char> char_vector;
|
typedef svector<char> char_vector;
|
||||||
typedef svector<double> double_vector;
|
typedef svector<double> double_vector;
|
||||||
|
|
||||||
template<typename Hash>
|
template<typename Hash, typename Vec>
|
||||||
struct vector_hash {
|
struct vector_hash_tpl {
|
||||||
Hash m_hash;
|
Hash m_hash;
|
||||||
typedef vector<typename Hash::data> data;
|
typedef Vec data;
|
||||||
|
|
||||||
unsigned operator()(data const& v, unsigned idx) const { return m_hash(v[idx]); }
|
unsigned operator()(data const& v, unsigned idx) const { return m_hash(v[idx]); }
|
||||||
|
|
||||||
vector_hash(Hash const& h = Hash()):m_hash(h) {}
|
vector_hash_tpl(Hash const& h = Hash()):m_hash(h) {}
|
||||||
|
|
||||||
unsigned operator()(data const& v) const {
|
unsigned operator()(data const& v) const {
|
||||||
if (v.empty()) {
|
if (v.empty()) {
|
||||||
return 778;
|
return 778;
|
||||||
}
|
}
|
||||||
return get_composite_hash<data, default_kind_hash_proc<data>, vector_hash>(v, v.size());
|
return get_composite_hash<data, default_kind_hash_proc<data>, vector_hash_tpl>(v, v.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<typename Hash>
|
||||||
|
struct vector_hash : public vector_hash_tpl<Hash, vector<typename Hash::data> > {};
|
||||||
|
|
||||||
|
template<typename Hash>
|
||||||
|
struct svector_hash : public vector_hash_tpl<Hash, svector<typename Hash::data> > {};
|
||||||
|
|
||||||
|
|
||||||
#endif /* _VECTOR_H_ */
|
#endif /* _VECTOR_H_ */
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue