/*++ Copyright (c) 2006 Microsoft Corporation Module Name: demodulator.cpp Abstract: Author: Leonardo de Moura (leonardo) 2010-04-12. Revision History: Christoph Wintersteiger 2010-04-21: Implementation --*/ #include"ast_pp.h" #include"demodulator.h" #include"for_each_expr.h" #include"var_subst.h" #include"uint_set.h" demodulator::demodulator(ast_manager & m, basic_simplifier_plugin & p): m_manager(m), m_match_subst(m), m_bsimp(p), m_todo(m), m_rewrite_todo(m), m_rewrite_cache(m), m_new_exprs(m) { } demodulator::~demodulator() { reset_dealloc_values(m_fwd_idx); reset_dealloc_values(m_back_idx); for (demodulator2lhs_rhs::iterator it = m_demodulator2lhs_rhs.begin(); it != m_demodulator2lhs_rhs.end(); it++) { m_manager.dec_ref(it->m_key); m_manager.dec_ref(it->m_value.first); m_manager.dec_ref(it->m_value.second); } } bool demodulator::is_demodulator(expr * e, expr_ref & large, expr_ref & small) const { if (e->get_kind() == AST_QUANTIFIER) { quantifier * q = to_quantifier(e); if (q->is_forall()) { expr * qe = q->get_expr(); if ((m_manager.is_eq(qe) || m_manager.is_iff(qe))) { app * eq = to_app(q->get_expr()); expr * lhs = eq->get_arg(0); expr * rhs = eq->get_arg(1); int subset = is_subset(lhs, rhs); int smaller = is_smaller(lhs, rhs); TRACE("demodulator", tout << "testing is_demodulator:\n" << mk_pp(lhs, m_manager) << "\n" << mk_pp(rhs, m_manager) << "\n" << "subset: " << subset << ", smaller: " << smaller << "\n";); // We only track uninterpreted functions, everything else is likely too expensive. if ((subset == +1 || subset == +2) && smaller == +1) { if (is_uninterp(rhs)) { large = rhs; small = lhs; return true; } #if 1 // lhs = (not rhs) --> (not lhs) = rhs expr * not_rhs; if (m_manager.is_not(rhs, not_rhs) && is_uninterp(not_rhs)) { large = not_rhs; small = m_manager.mk_not(lhs); return true; } #endif } if ((subset == -1 || subset == +2) && smaller == -1) { if (is_uninterp(lhs)) { large = lhs; small = rhs; return true; } #if 1 // (not lhs) = rhs --> lhs = (not rhs) expr * not_lhs; if (m_manager.is_not(lhs, not_lhs) && is_uninterp(not_lhs)) { large = not_lhs; small = m_manager.mk_not(rhs); return true; } #endif } } else if (m_manager.is_not(qe) && is_uninterp(to_app(qe)->get_arg(0))) { // this is like (not (f ... )) --> (= (f ...) false) large = to_app(qe)->get_arg(0); small = m_manager.mk_false(); return true; } else if (is_uninterp(qe)) { // this is like (f ... ) --> (= (f ...) true) large = to_app(qe); small = m_manager.mk_true(); return true; } } } return false; } class var_set_proc { uint_set & m_set; public: var_set_proc(uint_set &s):m_set(s) {} void operator()(var * n) { m_set.insert(n->get_idx()); } void operator()(quantifier * n) {} void operator()(app * n) {} }; int demodulator::is_subset(expr * e1, expr * e2) const { uint_set ev1, ev2; if (m_manager.is_value(e1)) return 1; // values are always a subset! var_set_proc proc1(ev1); for_each_expr(proc1, e1); var_set_proc proc2(ev2); for_each_expr(proc2, e2); return (ev1==ev2 ) ? +2 : // We return +2 if the sets are equal. (ev1.subset_of(ev2)) ? +1 : (ev2.subset_of(ev1)) ? -1 : 0 ; } int demodulator::is_smaller(expr * e1, expr * e2) const { unsigned sz1 = 0, sz2 = 0; // values are always smaller! if (m_manager.is_value(e1)) return +1; else if (m_manager.is_value(e2)) return -1; // interpreted stuff is always better than uninterpreted. if (!is_uninterp(e1) && is_uninterp(e2)) return +1; else if (is_uninterp(e1) && !is_uninterp(e2)) return -1; // two uninterpreted functions are ordered first by the number of // arguments, then by their id. if (is_uninterp(e1) && is_uninterp(e2)) { if (to_app(e1)->get_num_args() < to_app(e2)->get_num_args()) return +1; else if (to_app(e1)->get_num_args() > to_app(e2)->get_num_args()) return -1; else { unsigned a = to_app(e1)->get_decl()->get_id(); unsigned b = to_app(e2)->get_decl()->get_id(); if (a < b) return +1; else if (a > b) return -1; } } switch (e1->get_kind()) { case AST_VAR: sz1 = 1; break; case AST_QUANTIFIER: sz1 = to_quantifier(e1)->get_depth(); break; case AST_APP: sz1 = to_app(e1)->get_depth(); break; default: UNREACHABLE(); } switch (e2->get_kind()) { case AST_VAR: sz2 = 1; break; case AST_QUANTIFIER: sz2 = to_quantifier(e2)->get_depth(); break; case AST_APP: sz2 = to_app(e2)->get_depth(); break; default: UNREACHABLE(); } return (sz1 == sz2) ? 0 : (sz1 < sz2) ? +1 : -1 ; } class max_var_id_proc { unsigned m_max_var_id; public: max_var_id_proc(void):m_max_var_id(0) {} void operator()(var * n) { if(n->get_idx() > m_max_var_id) m_max_var_id = n->get_idx(); } void operator()(quantifier * n) {} void operator()(app * n) {} unsigned get_max(void) { return m_max_var_id; } }; unsigned demodulator::max_var_id(expr * e) { max_var_id_proc proc; for_each_expr(proc, e); return proc.get_max(); } void demodulator::insert_fwd_idx(expr * large, expr * small, quantifier * demodulator) { SASSERT(large->get_kind() == AST_APP); SASSERT(demodulator); SASSERT(large && small); TRACE("demodulator_fwd", tout << "INSERT: " << mk_pp(demodulator, m_manager) << std::endl; ); func_decl * fd = to_app(large)->get_decl(); fwd_idx_map::iterator it = m_fwd_idx.find_iterator(fd); if (it == m_fwd_idx.end()) { quantifier_set * qs = alloc(quantifier_set, 1); m_fwd_idx.insert(fd, qs); it = m_fwd_idx.find_iterator(fd); } SASSERT(it->m_value); it->m_value->insert(demodulator); m_manager.inc_ref(demodulator); m_manager.inc_ref(large); m_manager.inc_ref(small); m_demodulator2lhs_rhs.insert(demodulator, expr_pair(large, small)); } void demodulator::remove_fwd_idx(func_decl * f, quantifier * demodulator) { TRACE("demodulator_fwd", tout << "REMOVE: " << std::hex << (size_t)demodulator << std::endl; ); fwd_idx_map::iterator it = m_fwd_idx.find_iterator(f); if (it != m_fwd_idx.end()) { demodulator2lhs_rhs::iterator fit = m_demodulator2lhs_rhs.find_iterator(demodulator); m_manager.dec_ref(fit->m_value.first); m_manager.dec_ref(fit->m_value.second); m_manager.dec_ref(demodulator); m_demodulator2lhs_rhs.erase(demodulator); it->m_value->erase(demodulator); } else { SASSERT(m_demodulator2lhs_rhs.contains(demodulator)); } } bool demodulator::check_fwd_idx_consistency(void) { for (fwd_idx_map::iterator it = m_fwd_idx.begin(); it != m_fwd_idx.end() ; it++ ) { quantifier_set * set = it->m_value; SASSERT(set); for (quantifier_set::iterator sit = set->begin(); sit != set->end(); sit++) { if (!m_demodulator2lhs_rhs.contains(*sit)) return false; } } return true; } void demodulator::show_fwd_idx(std::ostream & out) { for (fwd_idx_map::iterator it = m_fwd_idx.begin(); it != m_fwd_idx.end() ; it++ ) { quantifier_set * set = it->m_value; SASSERT(!set); out << it->m_key->get_name() << ": " << std::endl; for (quantifier_set::iterator sit = set->begin(); sit != set->end(); sit++) { out << std::hex << (size_t)*sit << std::endl; } } out << "D2LR: " << std::endl; for (demodulator2lhs_rhs::iterator it = m_demodulator2lhs_rhs.begin(); it != m_demodulator2lhs_rhs.end() ; it++) { out << (size_t) it->m_key << std::endl; } } bool demodulator::rewrite1(func_decl * f, ptr_vector & m_new_args, expr_ref & np) { fwd_idx_map::iterator it = m_fwd_idx.find_iterator(f); if (it != m_fwd_idx.end()) { TRACE("demodulator_bug", tout << "trying to rewrite: " << f->get_name() << " args:\n"; for (unsigned i = 0; i < m_new_args.size(); i++) { tout << mk_pp(m_new_args[i], m_manager) << "\n"; }); quantifier_set::iterator dit = it->m_value->begin(); quantifier_set::iterator dend = it->m_value->end(); for ( ; dit != dend ; dit++ ) { quantifier * d = *dit; SASSERT(m_demodulator2lhs_rhs.contains(d)); expr_pair l_s; m_demodulator2lhs_rhs.find(d, l_s); app * large = to_app(l_s.first); if (large->get_num_args() != m_new_args.size()) continue; TRACE("demodulator_bug", tout << "Matching with demodulator: " << mk_pp(d, m_manager) << std::endl; ); SASSERT(large->get_decl() == f); if (m_match_subst(large, l_s.second, m_new_args.c_ptr(), np)) { TRACE("demodulator_bug", tout << "succeeded...\n" << mk_pp(l_s.second, m_manager) << "\n===>\n" << mk_pp(np, m_manager) << "\n";); return true; } } } return false; } bool demodulator::rewrite_visit_children(app * a) { bool res=true; unsigned j = a->get_num_args(); while (j > 0) { expr * e = a->get_arg(--j); if (!m_rewrite_cache.contains(e) || !m_rewrite_cache.get(e).second) { m_rewrite_todo.push_back(e); res = false; } } return res; } void demodulator::rewrite_cache(expr * e, expr * new_e, bool done) { m_rewrite_cache.insert(e, expr_bool_pair(new_e, done)); } expr * demodulator::rewrite(expr * n) { if (m_fwd_idx.empty()) return n; TRACE("demodulator", tout << "rewrite: " << mk_pp(n, m_manager) << std::endl; ); app * a; SASSERT(m_rewrite_todo.empty()); m_rewrite_cache.reset(); m_rewrite_todo.push_back(n); while (!m_rewrite_todo.empty()) { TRACE("demodulator_stack", tout << "STACK: " << std::endl; for ( unsigned i = 0; iget_kind()) { case AST_VAR: rewrite_cache(e, actual, true); m_rewrite_todo.pop_back(); break; case AST_APP: a = to_app(actual); if (rewrite_visit_children(a)) { func_decl * f = a->get_decl(); m_new_args.reset(); unsigned num_args = a->get_num_args(); bool all_untouched=true; for (unsigned i = 0 ; i < num_args ; i++ ) { expr * o_child = a->get_arg(i); expr * n_child; SASSERT(m_rewrite_cache.contains(o_child) && m_rewrite_cache.get(o_child).second); expr_bool_pair const & ebp = m_rewrite_cache.get(o_child); n_child = ebp.first; if (n_child != o_child) all_untouched = false; m_new_args.push_back(n_child); } expr_ref np(m_manager); if (rewrite1(f, m_new_args, np)) { rewrite_cache(e, np, false); // No pop. } else { if(all_untouched) { rewrite_cache(e, actual, true); } else { expr_ref na(m_manager); if (f->get_family_id() != m_manager.get_basic_family_id()) na = m_manager.mk_app(f, m_new_args.size(), m_new_args.c_ptr()); else m_bsimp.reduce(f, m_new_args.size(), m_new_args.c_ptr(), na); TRACE("demodulator_bug", tout << "e:\n" << mk_pp(e, m_manager) << "\nnew_args: \n"; for (unsigned i = 0; i < m_new_args.size(); i++) { tout << mk_pp(m_new_args[i], m_manager) << "\n"; } tout << "=====>\n"; tout << "na:\n " << mk_pp(na, m_manager) << "\n";); rewrite_cache(e, na, true); } m_rewrite_todo.pop_back(); } } break; case AST_QUANTIFIER: { expr * body = to_quantifier(actual)->get_expr(); if (m_rewrite_cache.contains(body)) { const expr_bool_pair ebp = m_rewrite_cache.get(body); SASSERT(ebp.second); expr * new_body = ebp.first; quantifier_ref q(m_manager); q = m_manager.update_quantifier(to_quantifier(actual), new_body); m_new_exprs.push_back(q); expr_ref new_q(m_manager); elim_unused_vars(m_manager, q, new_q); m_new_exprs.push_back(new_q); rewrite_cache(e, new_q, true); m_rewrite_todo.pop_back(); } else { m_rewrite_todo.push_back(body); } break; } default: UNREACHABLE(); } } SASSERT(m_rewrite_cache.contains(n)); const expr_bool_pair & ebp = m_rewrite_cache.get(n); SASSERT(ebp.second); expr * r = ebp.first; TRACE("demodulator", tout << "rewrite result: " << mk_pp(r, m_manager) << std::endl; ); return r; } class demodulator::add_back_idx_proc { ast_manager & m_manager; back_idx_map & m_back_idx; expr * m_expr; public: add_back_idx_proc(ast_manager & m, back_idx_map & bi, expr * e):m_manager(m),m_back_idx(bi),m_expr(e) {} void operator()(var * n) {} void operator()(quantifier * n) {} void operator()(app * n) { // We track only uninterpreted and constant functions. if (n->get_num_args()==0) return; SASSERT(m_expr && m_expr != (expr*) 0x00000003); func_decl * d=n->get_decl(); if (d->get_family_id() == null_family_id) { back_idx_map::iterator it = m_back_idx.find_iterator(d); if (it != m_back_idx.end()) { SASSERT(it->m_value); it->m_value->insert(m_expr); } else { expr_set * e = alloc(expr_set); e->insert(m_expr); m_back_idx.insert(d, e); } } } }; class demodulator::remove_back_idx_proc { ast_manager & m_manager; back_idx_map & m_back_idx; expr * m_expr; public: remove_back_idx_proc(ast_manager & m, back_idx_map & bi, expr * e):m_manager(m),m_back_idx(bi),m_expr(e) {} void operator()(var * n) {} void operator()(quantifier * n) {} void operator()(app * n) { // We track only uninterpreted and constant functions. if (n->get_num_args()==0) return; func_decl * d=n->get_decl(); if (d->get_family_id() == null_family_id) { back_idx_map::iterator it = m_back_idx.find_iterator(d); if (it != m_back_idx.end()) { SASSERT(it->m_value); it->m_value->remove(m_expr); } } } }; void demodulator::reschedule_processed(func_decl * f) { //use m_back_idx to find all formulas p in m_processed that contains f { back_idx_map::iterator it = m_back_idx.find_iterator(f); if (it != m_back_idx.end()) { SASSERT(it->m_value); expr_set temp; expr_set::iterator sit = it->m_value->begin(); expr_set::iterator send = it->m_value->end(); for ( ; sit != send ; sit++ ) { expr * p = *sit; if (m_processed.contains(p)) temp.insert(p); } sit = temp.begin(); send = temp.end(); for ( ; sit != send; sit++) { expr * p = *sit; // remove p from m_processed and m_back_idx m_processed.remove(p); remove_back_idx_proc proc(m_manager, m_back_idx, p); // this could change it->m_value, thus we need the `temp' set. for_each_expr(proc, p); // insert p into m_todo m_todo.push_back(p); } } } bool demodulator::can_rewrite(expr * n, expr * lhs) { // this is a quick check, we just traverse d and check if there is an expression in d that is an instance of lhs of n'. // we cannot use the trick used for m_processed, since the main loop would not terminate. ptr_vector stack; expr * curr; expr_mark visited; stack.push_back(n); while (!stack.empty()) { curr = stack.back(); if (visited.is_marked(curr)) { stack.pop_back(); continue; } switch(curr->get_kind()) { case AST_VAR: visited.mark(curr, true); stack.pop_back(); break; case AST_APP: if (for_each_expr_args(stack, visited, to_app(curr)->get_num_args(), to_app(curr)->get_args())) { if (m_match_subst(lhs, curr)) return true; visited.mark(curr, true); stack.pop_back(); } break; case AST_QUANTIFIER: if (!for_each_expr_args(stack, visited, to_quantifier(curr)->get_num_patterns(), to_quantifier(curr)->get_patterns())) { break; } if (!for_each_expr_args(stack, visited, to_quantifier(curr)->get_num_no_patterns(), to_quantifier(curr)->get_no_patterns())) { break; } if (!visited.is_marked(to_quantifier(curr)->get_expr())) { stack.push_back(to_quantifier(curr)->get_expr()); break; } stack.pop_back(); break; default: UNREACHABLE(); } } return false; } void demodulator::reschedule_demodulators(func_decl * f, expr * lhs) { // use m_back_idx to find all demodulators d in m_fwd_idx that contains f { //ptr_vector to_remove; back_idx_map::iterator it = m_back_idx.find_iterator(f); if (it != m_back_idx.end()) { SASSERT(it->m_value); expr_set all_occurrences; expr_ref l(m_manager); expr_set::iterator esit = it->m_value->begin(); expr_set::iterator esend = it->m_value->end(); for ( ; esit != esend ; esit++) all_occurrences.insert(*esit); // Run over all f-demodulators esit = all_occurrences.begin(); esend = all_occurrences.end(); for ( ; esit != esend ; esit++ ) { expr * occ = *esit; if (!is_quantifier(occ)) continue; // Use the fwd idx to find out whether this is a demodulator. demodulator2lhs_rhs::iterator d2lr_it = m_demodulator2lhs_rhs.find_iterator(to_quantifier(occ)); if (d2lr_it != m_demodulator2lhs_rhs.end()) { l = d2lr_it->m_value.first; quantifier_ref d(m_manager); func_decl_ref df(m_manager); d = to_quantifier(occ); df = to_app(l)->get_decl(); // Now we know there is an occurrence of f in d // if n' can rewrite d { if (can_rewrite(d, lhs)) { TRACE("demodulator", tout << "Rescheduling: " << std::endl << mk_pp(d, m_manager) << std::endl; ); // remove d from m_fwd_idx remove_fwd_idx(df, d); // remove d from m_back_idx // just remember it here, because otherwise it and/or esit might become invalid? // to_remove.insert(d); remove_back_idx_proc proc(m_manager, m_back_idx, d); for_each_expr(proc, d); // insert d into m_todo m_todo.push_back(d); } } } } //for (ptr_vector::iterator it = to_remove.begin(); it != to_remove.end(); it++) { // expr * d = *it; // remove_back_idx_proc proc(m_manager, m_back_idx, d); // for_each_expr(proc, d); //} } void demodulator::operator()(unsigned n, expr * const * exprs, proof * const * prs, expr_ref_vector & new_exprs, proof_ref_vector & new_prs) { if (m_manager.proofs_enabled()) { // Let us not waste time with proof production warning_msg("PRE_DEMODULATOR=true is not supported when proofs are enabled."); new_exprs.append(n, exprs); new_prs.append(n, prs); return; } TRACE("demodulator", tout << "before demodulator:\n"; for ( unsigned i = 0 ; i < n ; i++ ) tout << mk_pp(exprs[i], m_manager) << std::endl; ); // Initially, m_todo contains all formulas. That is, it contains the argument exprs. m_fwd_idx, m_processed, m_back_idx are empty. unsigned max_vid = 0; for ( unsigned i = 0 ; i < n ; i++ ) { m_todo.push_back(exprs[i]); max_vid = std::max(max_vid, max_var_id(exprs[i])); } m_match_subst.reserve(max_vid); while (!m_todo.empty()) { // let n be the next formula in m_todo. expr_ref cur(m_manager); cur = m_todo.back(); m_todo.pop_back(); // rewrite cur using m_fwd_idx, and let n' be the result. expr * np = rewrite(cur); // at this point, it should be the case that there is no demodulator in m_fwd_idx that can rewrite n'. SASSERT(rewrite(np)==np); // if (n' is not a demodulator) { expr_ref large(m_manager), small(m_manager); if (!is_demodulator(np, large, small)) { // insert n' into m_processed m_processed.insert(np); // update m_back_idx (traverse n' and for each uninterpreted function declaration f in n' add the entry f->n' to m_back_idx) add_back_idx_proc proc(m_manager, m_back_idx, np); for_each_expr(proc, np); } else { // np is a demodulator that allows us to replace 'large' with 'small'. TRACE("demodulator", tout << "Found demodulator: " << std::endl; tout << mk_pp(large.get(), m_manager) << std::endl << " ---> " << std::endl << mk_pp(small.get(), m_manager) << std::endl; ); TRACE("demodulator_s", tout << "Found demodulator: " << std::endl; tout << to_app(large)->get_decl()->get_name() << "[" << to_app(large)->get_depth() << "]" << " ---> "; if (is_app(small)) tout << to_app(small)->get_decl()->get_name() << "[" << to_app(small)->get_depth() << "]" << std::endl; else tout << mk_pp(small.get(), m_manager) << std::endl; ); // let f be the top symbol of n' SASSERT(is_app(large)); func_decl * f = to_app(large)->get_decl(); reschedule_processed(f); reschedule_demodulators(f, large); // insert n' into m_fwd_idx insert_fwd_idx(large, small, to_quantifier(np)); // update m_back_idx add_back_idx_proc proc(m_manager, m_back_idx, np); for_each_expr(proc, np); } } // the result is the contents of m_processed + all demodulators in m_fwd_idx. obj_hashtable::iterator pit = m_processed.begin(); obj_hashtable::iterator pend = m_processed.end(); for ( ; pit != pend ; pit++ ) { new_exprs.push_back(*pit); TRACE("demodulator", tout << mk_pp(*pit, m_manager) << std::endl; ); } fwd_idx_map::iterator fit = m_fwd_idx.begin(); fwd_idx_map::iterator fend = m_fwd_idx.end(); for ( ; fit != fend ; fit++ ) { if (fit->m_value) { quantifier_set::iterator dit = fit->m_value->begin(); quantifier_set::iterator dend = fit->m_value->end(); for ( ; dit != dend ; dit++ ) { expr * e = *dit; new_exprs.push_back(e); TRACE("demodulator", tout << mk_pp(*dit, m_manager) << std::endl; ); } } } TRACE("demodulator", tout << "after demodulator:\n"; for ( unsigned i = 0 ; i < new_exprs.size() ; i++ ) tout << mk_pp(new_exprs[i].get(), m_manager) << std::endl; ); } demodulator::match_subst::match_subst(ast_manager & m): m_manager(m), m_subst(m) { } /** \brief Auxiliary functor used to implement optimization in match_args. See comment there. */ struct match_args_aux_proc { substitution & m_subst; struct no_match {}; match_args_aux_proc(substitution & s):m_subst(s) {} void operator()(var * n) { expr_offset r; if (m_subst.find(n, 0, r)) { if (r.get_expr() != n) { SASSERT(r.get_offset() == 1); throw no_match(); } else { m_subst.insert(n, 0, expr_offset(n, 1)); } } } void operator()(quantifier * n) { throw no_match(); } void operator()(app * n) {} }; bool demodulator::match_subst::match_args(app * lhs, expr * const * args) { m_cache.reset(); m_todo.reset(); // fill todo-list, and perform quick success/failure tests m_all_args_eq = true; unsigned num_args = lhs->get_num_args(); for (unsigned i = 0; i < num_args; i++) { expr * t_arg = lhs->get_arg(i); expr * i_arg = args[i]; if (t_arg != i_arg) m_all_args_eq = false; if (is_app(t_arg) && is_app(i_arg) && to_app(t_arg)->get_decl() != to_app(i_arg)->get_decl()) { // quick failure... return false; } m_todo.push_back(expr_pair(t_arg, i_arg)); } if (m_all_args_eq) { // quick success worked... return true; } m_subst.reset(); while (!m_todo.empty()) { expr_pair const & p = m_todo.back(); if (is_var(p.first)) { expr_offset r; if (m_subst.find(to_var(p.first), 0, r)) { if (r.get_expr() != p.second) return false; } else { m_subst.insert(to_var(p.first), 0, expr_offset(p.second, 1)); } m_todo.pop_back(); continue; } if (is_var(p.second)) return false; // we may have nested quantifiers. if (is_quantifier(p.first) || is_quantifier(p.second)) return false; SASSERT(is_app(p.first) && is_app(p.second)); if (to_app(p.first)->is_ground() && !to_app(p.second)->is_ground()) return false; if (p.first == p.second && to_app(p.first)->is_ground()) { SASSERT(to_app(p.second)->is_ground()); m_todo.pop_back(); continue; } if (m_cache.contains(p)) { m_todo.pop_back(); continue; } if (p.first == p.second) { // p.first and p.second is not ground... // Traverse p.first and check whether every variable X:0 in p.first // 1) is unbounded (then we bind X:0 -> X:1) // 2) or, is already bounded to X:1 // If that is, the case, we execute: // m_todo.pop_back(); // m_cache.insert(p); // continue; // Otherwise // return false; match_args_aux_proc proc(m_subst); try { for_each_expr(proc, p.first); // succeeded m_todo.pop_back(); m_cache.insert(p); continue; } catch (match_args_aux_proc::no_match) { return false; } } app * n1 = to_app(p.first); app * n2 = to_app(p.second); if (n1->get_decl() != n2->get_decl()) return false; unsigned num_args1 = n1->get_num_args(); if (num_args1 != n2->get_num_args()) return false; m_todo.pop_back(); if (num_args1 == 0) continue; m_cache.insert(p); unsigned j = num_args1; while (j > 0) { --j; m_todo.push_back(expr_pair(n1->get_arg(j), n2->get_arg(j))); } } return true; } bool demodulator::match_subst::operator()(app * lhs, expr * rhs, expr * const * args, expr_ref & new_rhs) { if (match_args(lhs, args)) { if (m_all_args_eq) { // quick success... new_rhs = rhs; return true; } unsigned deltas[2] = { 0, 0 }; m_subst.apply(2, deltas, expr_offset(rhs, 0), new_rhs); return true; } return false; } bool demodulator::match_subst::operator()(expr * t, expr * i) { m_cache.reset(); m_todo.reset(); if (is_var(t)) return true; if (is_app(t) && is_app(i) && to_app(t)->get_decl() == to_app(i)->get_decl() && to_app(t)->get_num_args() == to_app(i)->get_num_args()) { return match_args(to_app(t), to_app(i)->get_args()); } return false; }