bool is_lt_no_level_params(level const & a, level const & b) { if (is_eqp(a, b)) return false; if (kind(a) != kind(b)) { if (kind(a) == level_kind::Param || kind(b) == level_kind::Param) return false; return kind(a) < kind(b); } switch (kind(a)) { case level_kind::Zero: lean_unreachable(); // LCOV_EXCL_LINE case level_kind::Param: return false; case level_kind::Global: return global_id(a) < global_id(b); case level_kind::Meta: return meta_id(a) < meta_id(b); case level_kind::Max: if (is_lt_no_level_params(max_lhs(a), max_lhs(b))) return true; else if (is_lt_no_level_params(max_lhs(b), max_lhs(a))) return false; else return is_lt_no_level_params(max_rhs(a), max_rhs(b)); case level_kind::IMax: if (is_lt_no_level_params(imax_lhs(a), imax_lhs(b))) return true; else if (is_lt_no_level_params(imax_lhs(b), imax_lhs(a))) return false; else return is_lt_no_level_params(imax_rhs(a), imax_rhs(b)); case level_kind::Succ: return is_lt_no_level_params(succ_of(a), succ_of(b)); } lean_unreachable(); }
unsigned level_cases_on(vm_obj const & o, buffer<vm_obj> & data) { level const & l = to_level(o); switch (l.kind()) { case level_kind::Zero: break; case level_kind::Succ: data.push_back(to_obj(succ_of(l))); break; case level_kind::Max: data.push_back(to_obj(max_lhs(l))); data.push_back(to_obj(max_rhs(l))); break; case level_kind::IMax: data.push_back(to_obj(imax_lhs(l))); data.push_back(to_obj(imax_rhs(l))); break; case level_kind::Param: data.push_back(to_obj(param_id(l))); break; case level_kind::Global: data.push_back(to_obj(global_id(l))); break; case level_kind::Meta: data.push_back(to_obj(meta_id(l))); break; } return static_cast<unsigned>(l.kind()); }
bool is_geq_core(level l1, level l2) { if (l1 == l2 || is_zero(l2)) return true; if (is_max(l2)) return is_geq(l1, max_lhs(l2)) && is_geq(l1, max_rhs(l2)); if (is_max(l1) && (is_geq(max_lhs(l1), l2) || is_geq(max_rhs(l1), l2))) return true; if (is_imax(l2)) return is_geq(l1, imax_lhs(l2)) && is_geq(l1, imax_rhs(l2)); if (is_imax(l1)) return is_geq(imax_rhs(l1), l2); auto p1 = to_offset(l1); auto p2 = to_offset(l2); if (p1.first == p2.first || is_zero(p2.first)) return p1.second >= p2.second; if (p1.second == p2.second && p1.second > 0) return is_geq(p1.first, p2.first); return false; }
level apply(level const & l) { auto r = m_lvl_cache.find(l); if (r != m_lvl_cache.end()) return *r; level res; switch (l.kind()) { case level_kind::Zero: case level_kind::Param: case level_kind::Global: case level_kind::Meta: res = l; break; case level_kind::Succ: res = update_succ(l, apply(succ_of(l))); break; case level_kind::Max: res = update_max(l, apply(max_lhs(l)), apply(max_rhs(l))); break; case level_kind::IMax: res = update_max(l, apply(imax_lhs(l)), apply(imax_rhs(l))); break; } m_lvl_cache.insert(res); return res; }
level normalize(level const & l) { auto p = to_offset(l); level const & r = p.first; switch (kind(r)) { case level_kind::Succ: lean_unreachable(); // LCOV_EXCL_LINE case level_kind::Zero: case level_kind::Param: case level_kind::Global: case level_kind::Meta: return l; case level_kind::IMax: { auto l1 = normalize(imax_lhs(r)); auto l2 = normalize(imax_rhs(r)); if (!is_eqp(l1, imax_lhs(r)) || !is_eqp(l2, imax_rhs(r))) return mk_succ(mk_imax(l1, l2), p.second); else return l; } case level_kind::Max: { buffer<level> todo; buffer<level> args; push_max_args(r, todo); for (level const & a : todo) push_max_args(normalize(a), args); std::sort(args.begin(), args.end(), is_norm_lt); buffer<level> & rargs = todo; rargs.clear(); unsigned i = 0; if (is_explicit(args[i])) { // find max explicit univierse while (i+1 < args.size() && is_explicit(args[i+1])) i++; lean_assert(is_explicit(args[i])); unsigned k = to_offset(args[i]).second; // an explicit universe k is subsumed by succ^k(l) unsigned j = i+1; for (; j < args.size(); j++) { if (to_offset(args[j]).second >= k) break; } if (j < args.size()) { // explicit universe was subsumed by succ^k'(l) where k' >= k i++; } } rargs.push_back(args[i]); auto p_prev = to_offset(args[i]); i++; for (; i < args.size(); i++) { auto p_curr = to_offset(args[i]); if (p_prev.first == p_curr.first) { if (p_prev.second < p_curr.second) { p_prev = p_curr; rargs.pop_back(); rargs.push_back(args[i]); } } else { p_prev = p_curr; rargs.push_back(args[i]); } } for (level & a : rargs) a = mk_succ(a, p.second); return mk_max(rargs); }} lean_unreachable(); // LCOV_EXCL_LINE }