/*++ Copyright (c) 2006 Microsoft Corporation Module Name: smt_for_each_relevant_expr.cpp Abstract: Author: Leonardo de Moura (leonardo) 2009-01-05. Revision History: --*/ #include"smt_context.h" #include"smt_for_each_relevant_expr.h" #include"ast_pp.h" #include"ast_ll_pp.h" namespace smt { bool check_at_labels::check(expr* n) { m_first = true; return count_at_labels_pos(n) <= 1; } unsigned check_at_labels::count_at_labels_lit(expr* n, bool polarity) { unsigned count = 0; buffer lbls; bool pos; if (m_manager.is_label_lit(n, lbls) || (m_manager.is_label(n, pos, lbls) && pos == polarity)) { buffer::const_iterator it = lbls.begin(); buffer::const_iterator end = lbls.end(); for (; it != end; ++it) { symbol const & s = *it; if (s.contains('@')) { TRACE("for_each_relevant_expr", tout << "@ label: " << mk_pp(n, m_manager) << "\n";); count += 1; } } } return count; } unsigned check_at_labels::count_at_labels_neg(expr* n) { if (!is_app(n)) { return 0; } app* a = to_app(n); unsigned sz = a->get_num_args(); unsigned count = count_at_labels_lit(n, false); if (m_manager.is_or(n)) { for (unsigned i = 0; i < sz; ++i) { count += count_at_labels_neg(a->get_arg(i)); } } else if (m_manager.is_not(n)) { count = count_at_labels_pos(a->get_arg(0)); } else if (m_manager.is_implies(n)) { count += count_at_labels_pos(a->get_arg(0)); count += count_at_labels_neg(a->get_arg(1)); } else if (m_manager.is_and(n)) { for (unsigned i = 0; i < sz; ++i) { count = std::max(count, count_at_labels_neg(a->get_arg(i))); } } if (count > 1 && m_first) { TRACE("for_each_relevant_expr", tout << mk_pp(n, m_manager) << "\n";); m_first = false; } return count; } unsigned check_at_labels::count_at_labels_pos(expr* n) { if (!is_app(n)) { return 0; } app* a = to_app(n); unsigned sz = a->get_num_args(); unsigned count = count_at_labels_lit(n, true); if (m_manager.is_and(n)) { for (unsigned i = 0; i < sz; ++i) { count += count_at_labels_pos(a->get_arg(i)); } } else if (m_manager.is_not(n)) { count = count_at_labels_neg(a->get_arg(0)); } else if (m_manager.is_implies(n)) { count = std::max(count, count_at_labels_neg(a->get_arg(0))); count = std::max(count, count_at_labels_pos(a->get_arg(1))); } else if (m_manager.is_or(n)) { for (unsigned i = 0; i < sz; ++i) { count = std::max(count, count_at_labels_pos(a->get_arg(i))); } } if (count > 1 && m_first) { TRACE("for_each_relevant_expr", tout << mk_pp(n, m_manager) << "\n";); m_first = false; } return count; } for_each_relevant_expr::for_each_relevant_expr(context & ctx): m_manager(ctx.get_manager()), m_context(ctx) { } void for_each_relevant_expr::operator()(expr * n) { TRACE("for_each_relevant_expr", tout << "#" << n->get_id() << "\n";); } void for_each_relevant_expr::reset() { m_todo.reset(); m_cache.reset(); } inline bool for_each_relevant_expr::is_relevant(expr * n) { return m_context.is_relevant(n); } inline lbool for_each_relevant_expr::get_assignment(expr * n) { if (!m_context.lit_internalized(n)) return l_true; // assume it is a top-level label return m_context.get_assignment(n); } void for_each_relevant_expr::process(expr * n) { TRACE("for_each_relevant_expr", tout << "processing:\n" << mk_bounded_pp(n, m_manager) << "\n";); TRACE("for_each_relevant_expr", tout << "processing:\n" << mk_pp(n, m_manager) << "\n";); if (m_cache.contains(n)) return; m_todo.reset(); m_todo.push_back(n); while (!m_todo.empty()) { expr * curr = m_todo.back(); m_todo.pop_back(); SASSERT(is_relevant(curr)); if (m_cache.contains(curr)) continue; operator()(curr); m_cache.insert(curr); if (!is_app(curr)) continue; if (to_app(curr)->get_family_id() == m_manager.get_basic_family_id()) { switch (to_app(curr)->get_decl_kind()) { case OP_OR: process_or(to_app(curr)); break; case OP_AND: process_and(to_app(curr)); break; case OP_ITE: process_ite(to_app(curr)); break; default: process_app(to_app(curr)); } } else { process_app(to_app(curr)); } } } void for_each_relevant_expr::process_app(app * n) { unsigned sz = n->get_num_args(); for (unsigned i = 0; i < sz; i++) { expr * arg = n->get_arg(i); if (m_cache.contains(arg)) continue; SASSERT(is_relevant(arg)); m_todo.push_back(arg); } } /** \brief Add a relevant child of n (that is assigned to val) to m_todo. \remark Give preference to a child that is already in the cache. */ void for_each_relevant_expr::process_relevant_child(app * n, lbool val) { unsigned sz = n->get_num_args(); TRACE("for_each_relevant_expr", tout << val << " " << mk_bounded_pp(n, m_manager) << "\n";); for (unsigned i = 0; i < sz; i++) { expr * arg = n->get_arg(i); if (!is_relevant(arg)) continue; if (get_assignment(arg) != val) continue; if (m_cache.contains(arg)) { TRACE("for_each_relevant_expr", tout << "justified by: " << mk_bounded_pp(arg, m_manager) << "\n";); return; // the current child justifies n. } } for (unsigned i = 0; i < sz; i++) { expr * arg = n->get_arg(i); if (!is_relevant(arg)) continue; if (get_assignment(arg) != val) continue; TRACE("for_each_relevant_expr", tout << "to_process: " << mk_bounded_pp(arg, m_manager) << "\n";); m_todo.push_back(arg); return; } UNREACHABLE(); } void for_each_relevant_expr::process_and(app * n) { switch (get_assignment(n)) { case l_undef: UNREACHABLE(); break; case l_false: process_relevant_child(n, l_false); break; case l_true: process_app(n); break; } } void for_each_relevant_expr::process_or(app * n) { switch (get_assignment(n)) { case l_undef: UNREACHABLE(); break; case l_false: process_app(n); break; case l_true: process_relevant_child(n, l_true); break; } } void for_each_relevant_expr::process_ite(app * n) { if (!m_cache.contains(n->get_arg(0))) m_todo.push_back(n->get_arg(0)); switch (get_assignment(n->get_arg(0))) { case l_false: if (!m_cache.contains(n->get_arg(2))) m_todo.push_back(n->get_arg(2)); break; case l_undef: UNREACHABLE(); break; case l_true: if (!m_cache.contains(n->get_arg(1))) m_todo.push_back(n->get_arg(1)); break; } } void collect_relevant_label_lits::operator()(expr * n) { TRACE("for_each_relevant_expr", tout << "label: " << m_manager.is_label_lit(n) << " " << " " << get_assignment(n) << " " << mk_bounded_pp(n, m_manager) << "\n";); if (!m_manager.is_label_lit(n)) return; if (get_assignment(n) != l_true) return; m_manager.is_label_lit(n, m_buffer); // copy symbols to buffer } void collect_relevant_labels::operator()(expr * n) { bool pos; TRACE("for_each_relevant_expr", tout << "label: " << m_manager.is_label(n) << " " << get_assignment(n) << " " << mk_bounded_pp(n, m_manager) << "\n";); if (!m_manager.is_label(n, pos)) return; if (pos && (get_assignment(n) != l_true)) return; if (!pos && (get_assignment(n) != l_false)) return; m_manager.is_label(n, pos, m_buffer); // copy symbols to buffer } };