inline order::result lpo::compare_core(expr_offset s, expr_offset t, unsigned depth) { s = find(s); t = find(t); if (max_depth(depth)) return UNKNOWN; if (is_var(s.get_expr())) return s == t ? EQUAL : UNCOMPARABLE; else if (is_var(t.get_expr())) return occurs(t, s) ? GREATER : UNCOMPARABLE; else { func_decl * f = to_app(s.get_expr())->get_decl(); func_decl * g = to_app(t.get_expr())->get_decl(); if (f_greater(f, g)) return dominates_args(s, t, depth) ? GREATER : NOT_GTEQ; else if (f != g) return arg_dominates_expr(s, t, depth) ? GREATER : NOT_GTEQ; else { result r = lex_compare(s, t, depth); if (r == GREATER) { if (dominates_args(s, t, depth)) return GREATER; } else if (r == EQUAL) return EQUAL; return to_app(s.get_expr())->get_num_args() > 1 && arg_dominates_expr(s, t, depth) ? GREATER : NOT_GTEQ; } } }
/** \brief Check whether the variable in t1 occurs in t2. */ bool lpo::occurs(expr_offset const & t1, expr_offset const & t2) { SASSERT(is_var(t1.get_expr())); if (is_ground(t2.get_expr())) return false; m_todo.reset(); m_todo.push_back(t2); while (!m_todo.empty()) { expr_offset t = m_todo.back(); m_todo.pop_back(); t = find(t); expr * n = t.get_expr(); if (is_ground(n)) continue; unsigned offset = t.get_offset(); unsigned j; switch (n->get_kind()) { case AST_VAR: if (t == t1) return true; break; case AST_APP: j = to_app(n)->get_num_args(); while (j > 0) { --j; expr * arg = to_app(n)->get_arg(j); if (!is_ground(arg)) m_todo.push_back(expr_offset(arg, offset)); } break; default: UNREACHABLE(); } } return false; }
/** \brief Return true if s >_{lpo} t_i forall children t_i of t. */ bool lpo::dominates_args(expr_offset s, expr_offset t, unsigned depth) { SASSERT(is_app(t.get_expr())); unsigned num_args = to_app(t.get_expr())->get_num_args(); unsigned off = t.get_offset(); for (unsigned i = 0; i < num_args; i++) { expr * t_i = to_app(t.get_expr())->get_arg(i); if (!greater(s, expr_offset(t_i, off), depth+1)) return false; } return true; }
/** \brief Return true if s_i >=_{lpo} t for some arg s_i of s. */ bool lpo::arg_dominates_expr(expr_offset s, expr_offset t, unsigned depth) { SASSERT(is_app(s.get_expr())); unsigned num_args = to_app(s.get_expr())->get_num_args(); unsigned off = s.get_offset(); for (unsigned i = 0; i < num_args; i++) { expr * s_i = to_app(s.get_expr())->get_arg(i); result r = compare(expr_offset(s_i, off), t, depth+1); if (r == EQUAL || r == GREATER) return true; } return false; }
inline void kbo::VWB(expr_offset t, unsigned idx) { expr_offset null(0, 0); app * n = to_app(t.get_expr()); unsigned num = n->get_num_args(); for (; idx < num; idx++) VWBc<pos>(expr_offset(n->get_arg(idx), t.get_offset()), null); }
void unifier::save_var(expr_offset const & p, expr_offset const & t) { expr * n = p.get_expr(); if (is_var(n)) { unsigned off = p.get_offset(); m_subst->insert(to_var(n)->get_idx(), off, t); } }
bool kbo::VWBc(expr_offset t, expr_offset target_var) { SASSERT(target_var.get_expr() == 0 || is_var(target_var.get_expr())); svector<expr_offset> & todo = m_vwbc_todo; expr_offset s; bool found = false; unsigned j; SASSERT(todo.empty()); todo.push_back(t); while (!todo.empty()) { t = todo.back(); if (t == target_var) found = true; expr * n = t.get_expr(); unsigned offset = t.get_offset(); todo.pop_back(); switch (n->get_kind()) { case AST_VAR: if (m_subst && m_subst->find(to_var(n), offset, s)) todo.push_back(s); else if (pos) { inc(t); m_weight_balance += var_weight(); } else { dec(t); m_weight_balance -= var_weight(); } break; case AST_APP: if (pos) m_weight_balance += f_weight(to_app(n)->get_decl()); else m_weight_balance -= f_weight(to_app(n)->get_decl()); j = to_app(n)->get_num_args(); while (j > 0) { --j; todo.push_back(expr_offset(to_app(n)->get_arg(j), offset)); } break; default: UNREACHABLE(); break; } } return found; }
/** \brief Increase the balance of the given variable. */ inline void kbo::inc(expr_offset v) { SASSERT(is_var(v.get_expr())); int val; unsigned v_idx = to_var(v.get_expr())->get_idx(); unsigned offset = v.get_offset(); if (m_deltas.find(v_idx, offset, val)) { if (val == -1) m_num_neg--; else if (val == 0) m_num_pos++; m_deltas.insert(v_idx, offset, val + 1); } else { m_deltas.insert(v_idx, offset, 1); m_num_pos ++; } }
order::result lpo::lex_compare(expr_offset s, expr_offset t, unsigned depth) { SASSERT(is_app(s.get_expr())); SASSERT(is_app(t.get_expr())); app * _s = to_app(s.get_expr()); app * _t = to_app(t.get_expr()); unsigned num_args1 = _s->get_num_args(); unsigned num_args2 = _t->get_num_args(); unsigned num_args = std::min(num_args1, num_args2); unsigned off1 = s.get_offset(); unsigned off2 = t.get_offset(); result r = EQUAL; for (unsigned i = 0; i < num_args; i++) { r = compare(expr_offset(_s->get_arg(i), off1), expr_offset(_t->get_arg(i), off2), depth+1); if (r != EQUAL) break; } if (r == EQUAL) { if (num_args1 > num_args2) return GREATER; if (num_args1 < num_args2) return NOT_GTEQ; } return r; }
/** \brief Decreate the balance of the given variable. */ inline void kbo::dec(expr_offset v) { int val; unsigned v_idx = to_var(v.get_expr())->get_idx(); unsigned offset = v.get_offset(); if (m_deltas.find(v_idx, offset, val)) { if (val == 0) m_num_neg++; else if (val == 1) m_num_pos--; m_deltas.insert(v_idx, offset, val - 1); } else { m_deltas.insert(v_idx, offset, -1); m_num_neg ++; } }
return arg_dominates_expr(s, t, depth) ? GREATER : NOT_GTEQ; else { result r = lex_compare(s, t, depth); if (r == GREATER) { if (dominates_args(s, t, depth)) return GREATER; } else if (r == EQUAL) return EQUAL; return to_app(s.get_expr())->get_num_args() > 1 && arg_dominates_expr(s, t, depth) ? GREATER : NOT_GTEQ; } } } order::result lpo::compare(expr_offset s, expr_offset t, unsigned depth) { TRACE("lpo", tout << "comparing:\n" << mk_pp(s.get_expr(), m_manager) << "\n" << mk_pp(t.get_expr(), m_manager) << "\n";); result r = compare_core(s, t, depth); TRACE("lpo", tout << "result of comparing:\n" << mk_pp(s.get_expr(), m_manager) << "\n" << mk_pp(t.get_expr(), m_manager) << "\nresult: " << r << "\n";); return r; } bool lpo::greater(expr_offset const & t1, expr_offset const & t2, substitution * s) { m_subst = s; return greater(t1, t2, static_cast<unsigned>(0)); } order::result lpo::compare(expr_offset const & t1, expr_offset const & t2, substitution * s) { m_subst = s; result r = compare(t1, t2, static_cast<unsigned>(0)); if (r != NOT_GTEQ) return r;
order::result kbo::compare(expr_offset const & t1, expr_offset const & t2, substitution * s) { reset(); m_subst = s; if (t1 == t2) return EQUAL; expr * n1 = t1.get_expr(); expr * n2 = t2.get_expr(); // f(s) >_{kbo} f(t) iff s >_{kbo} t while (is_unary_app(n1) && is_unary_app(n2) && to_app(n1)->get_decl() == to_app(n2)->get_decl()) { n1 = to_app(n1)->get_arg(0); n2 = to_app(n2)->get_arg(0); } svector<entry> & todo = m_compare_todo; SASSERT(todo.empty()); todo.push_back(entry(find(expr_offset(n1, t1.get_offset())), find(expr_offset(n2, t2.get_offset())), 0)); result res = UNKNOWN; while (!todo.empty()) { entry & e = todo.back(); expr_offset t1 = e.m_t1; expr_offset t2 = e.m_t2; expr * n1 = t1.get_expr(); expr * n2 = t2.get_expr(); TRACE("kbo", tout << "processing with idx: " << e.m_idx << "\n" << mk_pp(n1, m_manager) << "\n" << mk_pp(n2, m_manager) << "\n"; tout << "wb : " << m_weight_balance << "\n";); SASSERT(!is_quantifier(n1) && !is_quantifier(n2)); bool v1 = is_var(n1); bool v2 = is_var(n2); if (v1 && v2) { todo.pop_back(); inc(t1); dec(t2); res = t1 == t2 ? EQUAL : UNCOMPARABLE; } else if (v1) { todo.pop_back(); res = VWBc<false>(t2, t1) ? LESSER : UNCOMPARABLE; inc(t1); m_weight_balance += var_weight(); } else if (v2) { todo.pop_back(); res = VWBc<true>(t1, t2) ? GREATER : UNCOMPARABLE; dec(t2); m_weight_balance -= var_weight(); } else { func_decl * f = to_app(n1)->get_decl(); func_decl * g = to_app(n2)->get_decl(); result lex; if (f != g || to_app(n1)->get_num_args() != to_app(n2)->get_num_args()) { VWB<true>(t1, 0); VWB<false>(t2, 0); lex = UNCOMPARABLE; } else { unsigned & idx = e.m_idx; // when idx > 0, res contains the result for child (idx - 1) if (idx > 0 && res != EQUAL) { VWB<true>(t1, idx); VWB<false>(t2, idx); lex = res; } else if (idx == to_app(n1)->get_num_args()) { // all children were visited lex = EQUAL; } else if (idx < to_app(n1)->get_num_args()) { expr_offset c1 = find(expr_offset(to_app(n1)->get_arg(idx), t1.get_offset())); expr_offset c2 = find(expr_offset(to_app(n2)->get_arg(idx), t2.get_offset())); idx++; // move curr entry child idx entry new_entry(c1, c2, 0); todo.push_back(new_entry); continue; // process child before continuing } } todo.pop_back(); m_weight_balance += f_weight(f); m_weight_balance -= f_weight(g); if (m_weight_balance > 0) res = no_neg(); else if (m_weight_balance < 0) res = no_pos(); else if (f_greater(f, g)) res = no_neg(); else if (f_greater(g, f)) res = no_pos(); else if (f != g) res = UNCOMPARABLE; else if (lex == EQUAL) res = EQUAL; else if (lex == GREATER) res = no_neg(); else if (lex == LESSER) res = no_pos(); else res = UNCOMPARABLE; } TRACE("kbo", tout << "result: " << res << "\n";);