3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-04-29 20:05:51 +00:00

fix regression for simplifying tails with quantifiers, add some more handling for quantified tails

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
Nikolaj Bjorner 2012-11-30 15:58:06 -08:00
parent 692593baaa
commit 2d1a6bf270
10 changed files with 888 additions and 627 deletions

View file

@ -74,462 +74,489 @@ public:
};
class der2 {
ast_manager & m;
is_variable_proc* m_is_variable;
var_subst m_subst;
expr_ref_buffer m_new_exprs;
ptr_vector<expr> m_map;
int_vector m_pos2var;
ptr_vector<var> m_inx2var;
unsigned_vector m_order;
expr_ref_vector m_subst_map;
expr_ref_buffer m_new_args;
th_rewriter m_rewriter;
void der_sort_vars(ptr_vector<var> & vars, ptr_vector<expr> & definitions, unsigned_vector & order) {
order.reset();
namespace eq {
class der {
ast_manager & m;
is_variable_proc* m_is_variable;
var_subst m_subst;
expr_ref_buffer m_new_exprs;
// eliminate self loops, and definitions containing quantifiers.
bool found = false;
for (unsigned i = 0; i < definitions.size(); i++) {
var * v = vars[i];
expr * t = definitions[i];
if (t == 0 || has_quantifiers(t) || occurs(v, t))
definitions[i] = 0;
else
found = true; // found at least one candidate
}
ptr_vector<expr> m_map;
int_vector m_pos2var;
ptr_vector<var> m_inx2var;
unsigned_vector m_order;
expr_ref_vector m_subst_map;
expr_ref_buffer m_new_args;
th_rewriter m_rewriter;
if (!found)
return;
typedef std::pair<expr *, unsigned> frame;
svector<frame> todo;
expr_fast_mark1 visiting;
expr_fast_mark2 done;
unsigned vidx, num;
for (unsigned i = 0; i < definitions.size(); i++) {
if (definitions[i] == 0)
continue;
var * v = vars[i];
SASSERT(v->get_idx() == i);
SASSERT(todo.empty());
todo.push_back(frame(v, 0));
while (!todo.empty()) {
start:
frame & fr = todo.back();
expr * t = fr.first;
if (t->get_ref_count() > 1 && done.is_marked(t)) {
todo.pop_back();
void der_sort_vars(ptr_vector<var> & vars, ptr_vector<expr> & definitions, unsigned_vector & order) {
order.reset();
// eliminate self loops, and definitions containing quantifiers.
bool found = false;
for (unsigned i = 0; i < definitions.size(); i++) {
var * v = vars[i];
expr * t = definitions[i];
if (t == 0 || has_quantifiers(t) || occurs(v, t))
definitions[i] = 0;
else
found = true; // found at least one candidate
}
if (!found)
return;
typedef std::pair<expr *, unsigned> frame;
svector<frame> todo;
expr_fast_mark1 visiting;
expr_fast_mark2 done;
unsigned vidx, num;
for (unsigned i = 0; i < definitions.size(); i++) {
if (definitions[i] == 0)
continue;
}
switch (t->get_kind()) {
case AST_VAR:
vidx = to_var(t)->get_idx();
if (fr.second == 0) {
CTRACE("der_bug", vidx >= definitions.size(), tout << "vidx: " << vidx << "\n";);
// Remark: The size of definitions may be smaller than the number of variables occuring in the quantified formula.
if (definitions.get(vidx, 0) != 0) {
if (visiting.is_marked(t)) {
// cycle detected: remove t
visiting.reset_mark(t);
definitions[vidx] = 0;
}
else {
visiting.mark(t);
fr.second = 1;
todo.push_back(frame(definitions[vidx], 0));
goto start;
}
}
var * v = vars[i];
SASSERT(v->get_idx() == i);
SASSERT(todo.empty());
todo.push_back(frame(v, 0));
while (!todo.empty()) {
start:
frame & fr = todo.back();
expr * t = fr.first;
if (t->get_ref_count() > 1 && done.is_marked(t)) {
todo.pop_back();
continue;
}
else {
SASSERT(fr.second == 1);
if (definitions.get(vidx, 0) != 0) {
visiting.reset_mark(t);
order.push_back(vidx);
switch (t->get_kind()) {
case AST_VAR:
vidx = to_var(t)->get_idx();
if (fr.second == 0) {
CTRACE("der_bug", vidx >= definitions.size(), tout << "vidx: " << vidx << "\n";);
// Remark: The size of definitions may be smaller than the number of variables occuring in the quantified formula.
if (definitions.get(vidx, 0) != 0) {
if (visiting.is_marked(t)) {
// cycle detected: remove t
visiting.reset_mark(t);
definitions[vidx] = 0;
}
else {
visiting.mark(t);
fr.second = 1;
todo.push_back(frame(definitions[vidx], 0));
goto start;
}
}
}
else {
// var was removed from the list of candidate vars to elim cycle
// do nothing
SASSERT(fr.second == 1);
if (definitions.get(vidx, 0) != 0) {
visiting.reset_mark(t);
order.push_back(vidx);
}
else {
// var was removed from the list of candidate vars to elim cycle
// do nothing
}
}
if (t->get_ref_count() > 1)
done.mark(t);
todo.pop_back();
break;
case AST_QUANTIFIER:
UNREACHABLE();
todo.pop_back();
break;
case AST_APP:
num = to_app(t)->get_num_args();
while (fr.second < num) {
expr * arg = to_app(t)->get_arg(fr.second);
fr.second++;
if (arg->get_ref_count() > 1 && done.is_marked(arg))
continue;
todo.push_back(frame(arg, 0));
goto start;
}
if (t->get_ref_count() > 1)
done.mark(t);
todo.pop_back();
break;
default:
UNREACHABLE();
todo.pop_back();
break;
}
if (t->get_ref_count() > 1)
done.mark(t);
todo.pop_back();
break;
case AST_QUANTIFIER:
UNREACHABLE();
todo.pop_back();
break;
case AST_APP:
num = to_app(t)->get_num_args();
while (fr.second < num) {
expr * arg = to_app(t)->get_arg(fr.second);
fr.second++;
if (arg->get_ref_count() > 1 && done.is_marked(arg))
continue;
todo.push_back(frame(arg, 0));
goto start;
}
if (t->get_ref_count() > 1)
done.mark(t);
todo.pop_back();
break;
default:
UNREACHABLE();
todo.pop_back();
break;
}
}
}
}
bool is_variable(expr * e) const {
return (*m_is_variable)(e);
}
bool is_neg_var(ast_manager & m, expr * e) {
expr* e1;
return m.is_not(e, e1) && is_variable(e1);
}
/**
\brief Return true if e can be viewed as a variable disequality.
Store the variable id in v and the definition in t.
For example:
if e is (not (= (VAR 1) T)), then v assigned to 1, and t to T.
if e is (iff (VAR 2) T), then v is assigned to 2, and t to (not T).
(not T) is used because this formula is equivalent to (not (iff (VAR 2) (not T))),
and can be viewed as a disequality.
*/
bool is_var_diseq(expr * e, var * & v, expr_ref & t) {
expr* e1;
if (m.is_not(e, e1)) {
return is_var_eq(e, v, t);
}
else if (is_var_eq(e, v, t) && m.is_bool(v)) {
bool_rewriter(m).mk_not(t, t);
m_new_exprs.push_back(t);
return true;
}
else {
return false;
}
}
/**
\brief Return true if e can be viewed as a variable equality.
*/
bool is_var_eq(expr * e, var * & v, expr_ref & t) {
expr* lhs, *rhs;
// (= VAR t), (iff VAR t), (iff (not VAR) t), (iff t (not VAR)) cases
if (m.is_eq(e, lhs, rhs) || m.is_iff(e, lhs, rhs)) {
// (iff (not VAR) t) (iff t (not VAR)) cases
if (!is_variable(lhs) && !is_variable(rhs) && m.is_bool(lhs)) {
if (!is_neg_var(m, lhs)) {
std::swap(lhs, rhs);
}
if (!is_neg_var(m, lhs)) {
return false;
}
v = to_var(lhs);
t = m.mk_not(rhs);
bool is_variable(expr * e) const {
return (*m_is_variable)(e);
}
bool is_neg_var(ast_manager & m, expr * e) {
expr* e1;
return m.is_not(e, e1) && is_variable(e1);
}
/**
\brief Return true if e can be viewed as a variable disequality.
Store the variable id in v and the definition in t.
For example:
if e is (not (= (VAR 1) T)), then v assigned to 1, and t to T.
if e is (iff (VAR 2) T), then v is assigned to 2, and t to (not T).
(not T) is used because this formula is equivalent to (not (iff (VAR 2) (not T))),
and can be viewed as a disequality.
*/
bool is_var_diseq(expr * e, var * & v, expr_ref & t) {
expr* e1;
if (m.is_not(e, e1)) {
return is_var_eq(e, v, t);
}
else if (is_var_eq(e, v, t) && m.is_bool(v)) {
bool_rewriter(m).mk_not(t, t);
m_new_exprs.push_back(t);
return true;
}
else {
return false;
}
}
/**
\brief Return true if e can be viewed as a variable equality.
*/
bool is_var_eq(expr * e, var * & v, expr_ref & t) {
expr* lhs, *rhs;
// (= VAR t), (iff VAR t), (iff (not VAR) t), (iff t (not VAR)) cases
if (m.is_eq(e, lhs, rhs) || m.is_iff(e, lhs, rhs)) {
// (iff (not VAR) t) (iff t (not VAR)) cases
if (!is_variable(lhs) && !is_variable(rhs) && m.is_bool(lhs)) {
if (!is_neg_var(m, lhs)) {
std::swap(lhs, rhs);
}
if (!is_neg_var(m, lhs)) {
return false;
}
v = to_var(lhs);
t = m.mk_not(rhs);
m_new_exprs.push_back(t);
TRACE("der", tout << mk_pp(e, m) << "\n";);
return true;
}
if (!is_variable(lhs))
std::swap(lhs, rhs);
if (!is_variable(lhs))
return false;
v = to_var(lhs);
t = rhs;
TRACE("der", tout << mk_pp(e, m) << "\n";);
return true;
}
if (!is_variable(lhs))
std::swap(lhs, rhs);
if (!is_variable(lhs))
// (ite cond (= VAR t) (= VAR t2)) case
expr* cond, *e2, *e3;
if (m.is_ite(e, cond, e2, e3)) {
if (is_var_eq(e2, v, t)) {
expr_ref t2(m);
var* v2;
if (is_var_eq(e3, v2, t2) && v2 == v) {
t = m.mk_ite(cond, t, t2);
m_new_exprs.push_back(t);
return true;
}
}
return false;
v = to_var(lhs);
t = rhs;
TRACE("der", tout << mk_pp(e, m) << "\n";);
return true;
}
// VAR = true case
if (is_variable(e)) {
t = m.mk_true();
v = to_var(e);
TRACE("der", tout << mk_pp(e, m) << "\n";);
return true;
}
// VAR = false case
if (is_neg_var(m, e)) {
t = m.mk_false();
v = to_var(to_app(e)->get_arg(0));
TRACE("der", tout << mk_pp(e, m) << "\n";);
return true;
}
return false;
}
// (ite cond (= VAR t) (= VAR t2)) case
expr* cond, *e2, *e3;
if (m.is_ite(e, cond, e2, e3)) {
if (is_var_eq(e2, v, t)) {
expr_ref t2(m);
var* v2;
if (is_var_eq(e3, v2, t2) && v2 == v) {
t = m.mk_ite(cond, t, t2);
m_new_exprs.push_back(t);
bool is_var_def(bool check_eq, expr* e, var*& v, expr_ref& t) {
if (check_eq) {
return is_var_eq(e, v, t);
}
else {
return is_var_diseq(e, v, t);
}
}
void get_elimination_order() {
m_order.reset();
TRACE("top_sort",
tout << "DEFINITIONS: " << std::endl;
for(unsigned i = 0; i < m_map.size(); i++)
if(m_map[i]) tout << "VAR " << i << " = " << mk_pp(m_map[i], m) << std::endl;
);
der_sort_vars(m_inx2var, m_map, m_order);
TRACE("der",
tout << "Elimination m_order:" << std::endl;
for(unsigned i=0; i<m_order.size(); i++)
{
if (i != 0) tout << ",";
tout << m_order[i];
}
tout << std::endl;
);
}
void create_substitution(unsigned sz) {
m_subst_map.reset();
m_subst_map.resize(sz, 0);
for (unsigned i = 0; i < m_order.size(); i++) {
expr_ref cur(m_map[m_order[i]], m);
// do all the previous substitutions before inserting
expr_ref r(m);
m_subst(cur, m_subst_map.size(), m_subst_map.c_ptr(), r);
unsigned inx = sz - m_order[i]- 1;
SASSERT(m_subst_map[inx]==0);
m_subst_map[inx] = r;
}
}
void flatten_args(quantifier* q, unsigned& num_args, expr*const*& args) {
expr * e = q->get_expr();
if ((q->is_forall() && m.is_or(e)) ||
(q->is_exists() && m.is_and(e))) {
num_args = to_app(e)->get_num_args();
args = to_app(e)->get_args();
}
}
void apply_substitution(quantifier * q, expr_ref & r) {
expr * e = q->get_expr();
unsigned num_args = 1;
expr* const* args = &e;
flatten_args(q, num_args, args);
bool_rewriter rw(m);
// get a new expression
m_new_args.reset();
for(unsigned i = 0; i < num_args; i++) {
int x = m_pos2var[i];
if (x == -1 || m_map[x] == 0) {
m_new_args.push_back(args[i]);
}
}
expr_ref t(m);
if (q->is_forall()) {
rw.mk_or(m_new_args.size(), m_new_args.c_ptr(), t);
}
else {
rw.mk_and(m_new_args.size(), m_new_args.c_ptr(), t);
}
expr_ref new_e(m);
m_subst(t, m_subst_map.size(), m_subst_map.c_ptr(), new_e);
// don't forget to update the quantifier patterns
expr_ref_buffer new_patterns(m);
expr_ref_buffer new_no_patterns(m);
for (unsigned j = 0; j < q->get_num_patterns(); j++) {
expr_ref new_pat(m);
m_subst(q->get_pattern(j), m_subst_map.size(), m_subst_map.c_ptr(), new_pat);
new_patterns.push_back(new_pat);
}
for (unsigned j = 0; j < q->get_num_no_patterns(); j++) {
expr_ref new_nopat(m);
m_subst(q->get_no_pattern(j), m_subst_map.size(), m_subst_map.c_ptr(), new_nopat);
new_no_patterns.push_back(new_nopat);
}
r = m.update_quantifier(q, new_patterns.size(), new_patterns.c_ptr(),
new_no_patterns.size(), new_no_patterns.c_ptr(), new_e);
}
void reduce_quantifier1(quantifier * q, expr_ref & r, proof_ref & pr) {
expr * e = q->get_expr();
is_variable_test is_v(q->get_num_decls());
set_is_variable_proc(is_v);
unsigned num_args = 1;
expr* const* args = &e;
flatten_args(q, num_args, args);
unsigned def_count = 0;
unsigned largest_vinx = 0;
find_definitions(num_args, args, q->is_exists(), def_count, largest_vinx);
if (def_count > 0) {
get_elimination_order();
SASSERT(m_order.size() <= def_count); // some might be missing because of cycles
if (!m_order.empty()) {
create_substitution(largest_vinx + 1);
apply_substitution(q, r);
}
else {
r = q;
}
}
else {
TRACE("der_bug", tout << "Did not find any diseq\n" << mk_pp(q, m) << "\n";);
r = q;
}
if (m.proofs_enabled()) {
pr = r == q ? 0 : m.mk_der(q, r);
}
}
void elim_unused_vars(expr_ref& r, proof_ref &pr) {
if (is_quantifier(r)) {
quantifier * q = to_quantifier(r);
::elim_unused_vars(m, q, r);
if (m.proofs_enabled()) {
proof * p1 = m.mk_elim_unused_vars(q, r);
pr = m.mk_transitivity(pr, p1);
}
}
}
void find_definitions(unsigned num_args, expr* const* args, bool is_exists, unsigned& def_count, unsigned& largest_vinx) {
var * v = 0;
expr_ref t(m);
def_count = 0;
largest_vinx = 0;
m_map.reset();
m_pos2var.reset();
m_inx2var.reset();
m_pos2var.reserve(num_args, -1);
// Find all definitions
for (unsigned i = 0; i < num_args; i++) {
if (is_var_def(is_exists, args[i], v, t)) {
unsigned idx = v->get_idx();
if(m_map.get(idx, 0) == 0) {
m_map.reserve(idx + 1, 0);
m_inx2var.reserve(idx + 1, 0);
m_map[idx] = t;
m_inx2var[idx] = v;
m_pos2var[i] = idx;
def_count++;
largest_vinx = std::max(idx, largest_vinx);
}
}
}
}
bool reduce_var_set(expr_ref_vector& conjs) {
unsigned def_count = 0;
unsigned largest_vinx = 0;
find_definitions(conjs.size(), conjs.c_ptr(), true, def_count, largest_vinx);
if (def_count > 0) {
get_elimination_order();
SASSERT(m_order.size() <= def_count); // some might be missing because of cycles
if (!m_order.empty()) {
expr_ref r(m), new_r(m);
r = m.mk_and(conjs.size(), conjs.c_ptr());
create_substitution(largest_vinx + 1);
m_subst(r, m_subst_map.size(), m_subst_map.c_ptr(), new_r);
m_rewriter(new_r);
conjs.reset();
datalog::flatten_and(new_r, conjs);
return true;
}
}
return false;
}
// VAR = true case
if (is_variable(e)) {
t = m.mk_true();
v = to_var(e);
TRACE("der", tout << mk_pp(e, m) << "\n";);
return true;
}
// VAR = false case
if (is_neg_var(m, e)) {
t = m.mk_false();
v = to_var(to_app(e)->get_arg(0));
TRACE("der", tout << mk_pp(e, m) << "\n";);
return true;
}
return false;
}
bool is_var_def(bool check_eq, expr* e, var*& v, expr_ref& t) {
if (check_eq) {
return is_var_eq(e, v, t);
}
else {
return is_var_diseq(e, v, t);
}
}
void get_elimination_order() {
m_order.reset();
TRACE("top_sort",
tout << "DEFINITIONS: " << std::endl;
for(unsigned i = 0; i < m_map.size(); i++)
if(m_map[i]) tout << "VAR " << i << " = " << mk_pp(m_map[i], m) << std::endl;
);
public:
der(ast_manager & m): m(m), m_is_variable(0), m_subst(m), m_new_exprs(m), m_subst_map(m), m_new_args(m), m_rewriter(m) {}
der_sort_vars(m_inx2var, m_map, m_order);
void set_is_variable_proc(is_variable_proc& proc) { m_is_variable = &proc;}
TRACE("der",
tout << "Elimination m_order:" << std::endl;
for(unsigned i=0; i<m_order.size(); i++)
{
if (i != 0) tout << ",";
tout << m_order[i];
}
tout << std::endl;
);
}
void create_substitution(unsigned sz) {
m_subst_map.reset();
m_subst_map.resize(sz, 0);
for (unsigned i = 0; i < m_order.size(); i++) {
expr_ref cur(m_map[m_order[i]], m);
// do all the previous substitutions before inserting
expr_ref r(m);
m_subst(cur, m_subst_map.size(), m_subst_map.c_ptr(), r);
unsigned inx = sz - m_order[i]- 1;
SASSERT(m_subst_map[inx]==0);
m_subst_map[inx] = r;
}
}
void flatten_args(quantifier* q, unsigned& num_args, expr*const*& args) {
expr * e = q->get_expr();
if ((q->is_forall() && m.is_or(e)) ||
(q->is_exists() && m.is_and(e))) {
num_args = to_app(e)->get_num_args();
args = to_app(e)->get_args();
}
}
void apply_substitution(quantifier * q, expr_ref & r) {
expr * e = q->get_expr();
unsigned num_args = 1;
expr* const* args = &e;
flatten_args(q, num_args, args);
bool_rewriter rw(m);
// get a new expression
m_new_args.reset();
for(unsigned i = 0; i < num_args; i++) {
int x = m_pos2var[i];
if (x == -1 || m_map[x] == 0) {
m_new_args.push_back(args[i]);
void operator()(quantifier * q, expr_ref & r, proof_ref & pr) {
TRACE("der", tout << mk_pp(q, m) << "\n";);
pr = 0;
r = q;
reduce_quantifier(q, r, pr);
if (r != q) {
elim_unused_vars(r, pr);
}
}
expr_ref t(m);
if (q->is_forall()) {
rw.mk_or(m_new_args.size(), m_new_args.c_ptr(), t);
}
else {
rw.mk_and(m_new_args.size(), m_new_args.c_ptr(), t);
}
expr_ref new_e(m);
m_subst(t, m_subst_map.size(), m_subst_map.c_ptr(), new_e);
// don't forget to update the quantifier patterns
expr_ref_buffer new_patterns(m);
expr_ref_buffer new_no_patterns(m);
for (unsigned j = 0; j < q->get_num_patterns(); j++) {
expr_ref new_pat(m);
m_subst(q->get_pattern(j), m_subst_map.size(), m_subst_map.c_ptr(), new_pat);
new_patterns.push_back(new_pat);
}
for (unsigned j = 0; j < q->get_num_no_patterns(); j++) {
expr_ref new_nopat(m);
m_subst(q->get_no_pattern(j), m_subst_map.size(), m_subst_map.c_ptr(), new_nopat);
new_no_patterns.push_back(new_nopat);
}
r = m.update_quantifier(q, new_patterns.size(), new_patterns.c_ptr(),
new_no_patterns.size(), new_no_patterns.c_ptr(), new_e);
}
void reduce_quantifier1(quantifier * q, expr_ref & r, proof_ref & pr) {
expr * e = q->get_expr();
is_variable_test is_v(q->get_num_decls());
set_is_variable_proc(is_v);
unsigned num_args = 1;
expr* const* args = &e;
flatten_args(q, num_args, args);
unsigned def_count = 0;
unsigned largest_vinx = 0;
find_definitions(num_args, args, q->is_exists(), def_count, largest_vinx);
if (def_count > 0) {
get_elimination_order();
SASSERT(m_order.size() <= def_count); // some might be missing because of cycles
if (!m_order.empty()) {
create_substitution(largest_vinx + 1);
apply_substitution(q, r);
}
else {
r = q;
}
}
else {
TRACE("der_bug", tout << "Did not find any diseq\n" << mk_pp(q, m) << "\n";);
void reduce_quantifier(quantifier * q, expr_ref & r, proof_ref & pr) {
r = q;
}
if (m.proofs_enabled()) {
pr = r == q ? 0 : m.mk_der(q, r);
}
}
void elim_unused_vars(expr_ref& r, proof_ref &pr) {
if (is_quantifier(r)) {
quantifier * q = to_quantifier(r);
::elim_unused_vars(m, q, r);
if (m.proofs_enabled()) {
proof * p1 = m.mk_elim_unused_vars(q, r);
pr = m.mk_transitivity(pr, p1);
}
}
}
void find_definitions(unsigned num_args, expr* const* args, bool is_exists, unsigned& def_count, unsigned& largest_vinx) {
var * v = 0;
expr_ref t(m);
def_count = 0;
largest_vinx = 0;
m_map.reset();
m_pos2var.reset();
m_inx2var.reset();
m_pos2var.reserve(num_args, -1);
// Find all definitions
for (unsigned i = 0; i < num_args; i++) {
if (is_var_def(is_exists, args[i], v, t)) {
unsigned idx = v->get_idx();
if(m_map.get(idx, 0) == 0) {
m_map.reserve(idx + 1, 0);
m_inx2var.reserve(idx + 1, 0);
m_map[idx] = t;
m_inx2var[idx] = v;
m_pos2var[i] = idx;
def_count++;
largest_vinx = std::max(idx, largest_vinx);
// Keep applying reduce_quantifier1 until r doesn't change anymore
do {
proof_ref curr_pr(m);
q = to_quantifier(r);
reduce_quantifier1(q, r, curr_pr);
if (m.proofs_enabled()) {
pr = m.mk_transitivity(pr, curr_pr);
}
}
}
}
bool reduce_var_set(expr_ref_vector& conjs) {
unsigned def_count = 0;
unsigned largest_vinx = 0;
find_definitions(conjs.size(), conjs.c_ptr(), true, def_count, largest_vinx);
if (def_count > 0) {
get_elimination_order();
SASSERT(m_order.size() <= def_count); // some might be missing because of cycles
} while (q != r && is_quantifier(r));
if (!m_order.empty()) {
expr_ref r(m), new_r(m);
r = m.mk_and(conjs.size(), conjs.c_ptr());
create_substitution(largest_vinx + 1);
m_subst(r, m_subst_map.size(), m_subst_map.c_ptr(), new_r);
m_rewriter(new_r);
conjs.reset();
datalog::flatten_and(new_r, conjs);
return true;
}
m_new_exprs.reset();
}
return false;
}
public:
der2(ast_manager & m): m(m), m_is_variable(0), m_subst(m), m_new_exprs(m), m_subst_map(m), m_new_args(m), m_rewriter(m) {}
void set_is_variable_proc(is_variable_proc& proc) { m_is_variable = &proc;}
void operator()(quantifier * q, expr_ref & r, proof_ref & pr) {
TRACE("der", tout << mk_pp(q, m) << "\n";);
pr = 0;
r = q;
reduce_quantifier(q, r, pr);
if (r != q) {
elim_unused_vars(r, pr);
}
}
void reduce_quantifier(quantifier * q, expr_ref & r, proof_ref & pr) {
r = q;
// Keep applying reduce_quantifier1 until r doesn't change anymore
do {
proof_ref curr_pr(m);
q = to_quantifier(r);
reduce_quantifier1(q, r, curr_pr);
if (m.proofs_enabled()) {
pr = m.mk_transitivity(pr, curr_pr);
}
} while (q != r && is_quantifier(r));
m_new_exprs.reset();
}
void operator()(expr_ref_vector& r) {
while (reduce_var_set(r)) ;
m_new_exprs.reset();
}
ast_manager& get_manager() const { return m; }
};
}; // namespace eq
void operator()(expr_ref_vector& r) {
while (reduce_var_set(r)) ;
m_new_exprs.reset();
}
// ------------------------------------------------------------
// basic destructive equality (and disequality) resolution for arrays.
namespace ar {
class der {
ast_manager& m;
is_variable_proc* m_is_variable;
bool is_variable(expr * e) const {
return (*m_is_variable)(e);
}
public:
der(ast_manager& m): m(m), m_is_variable(0) {}
void operator()(expr_ref_vector& fmls) {
IF_VERBOSE(1, verbose_stream() << "Todo: eliminate arrays\n";);
}
void set_is_variable_proc(is_variable_proc& proc) { m_is_variable = &proc;}
};
}; // namespace ar
ast_manager& get_manager() const { return m; }
};
// ------------------------------------------------------------
// fm_tactic adapted to eliminate designated de-Brujin indices.
@ -1808,7 +1835,6 @@ namespace fm {
void set_is_variable_proc(is_variable_proc& proc) { m_is_variable = &proc;}
void operator()(expr_ref_vector& fmls) {
init(fmls);
init_use_list(fmls);
@ -1873,12 +1899,13 @@ namespace fm {
class qe_lite::impl {
ast_manager& m;
der2 m_der;
params_ref m_params;
eq::der m_der;
fm::fm m_fm;
ar::der m_array_der;
public:
impl(ast_manager& m): m(m), m_der(m), m_fm(m, m_params) {}
impl(ast_manager& m): m(m), m_der(m), m_fm(m, m_params), m_array_der(m) {}
void operator()(app_ref_vector& vars, expr_ref& fml) {
if (vars.empty()) {
@ -1928,10 +1955,16 @@ public:
}
void operator()(uint_set const& index_set, bool index_of_bound, expr_ref& fml) {
expr_ref_vector conjs(m);
conjs.push_back(fml);
(*this)(index_set, index_of_bound, conjs);
bool_rewriter(m).mk_and(conjs.size(), conjs.c_ptr(), fml);
expr_ref_vector disjs(m);
datalog::flatten_or(fml, disjs);
for (unsigned i = 0; i < disjs.size(); ++i) {
expr_ref_vector conjs(m);
conjs.push_back(disjs[i].get());
(*this)(index_set, index_of_bound, conjs);
bool_rewriter(m).mk_and(conjs.size(), conjs.c_ptr(), fml);
disjs[i] = fml;
}
bool_rewriter(m).mk_or(disjs.size(), disjs.c_ptr(), fml);
}
@ -1941,9 +1974,11 @@ public:
TRACE("qe_lite", for (unsigned i = 0; i < fmls.size(); ++i) tout << mk_pp(fmls[i].get(), m) << "\n";);
IF_VERBOSE(3, for (unsigned i = 0; i < fmls.size(); ++i) verbose_stream() << mk_pp(fmls[i].get(), m) << "\n";);
m_der.set_is_variable_proc(is_var);
m_der(fmls);
m_fm.set_is_variable_proc(is_var);
m_array_der.set_is_variable_proc(is_var);
m_der(fmls);
m_fm(fmls);
m_array_der(fmls);
TRACE("qe_lite", for (unsigned i = 0; i < fmls.size(); ++i) tout << mk_pp(fmls[i].get(), m) << "\n";);
}