From 0d96b6b4cb1e76d0129ae1a889dc4d32e34d7646 Mon Sep 17 00:00:00 2001 From: Leonardo de Moura Date: Tue, 10 Feb 2015 18:20:10 -0800 Subject: [PATCH] feat(library/expr_lt): add expression comparison operator that ignores treat level parameters as wildcards --- src/library/expr_lt.cpp | 110 ++++++++++++++++++++++++++++++++++++++++ src/library/expr_lt.h | 6 ++- 2 files changed, 114 insertions(+), 2 deletions(-) diff --git a/src/library/expr_lt.cpp b/src/library/expr_lt.cpp index 9c0f534e8..19ede78f9 100644 --- a/src/library/expr_lt.cpp +++ b/src/library/expr_lt.cpp @@ -58,4 +58,114 @@ bool is_lt(expr const & a, expr const & b, bool use_hash) { } lean_unreachable(); // LCOV_EXCL_LINE } + +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(); +} + +bool is_lt_no_level_params(levels const & as, levels const & bs) { + if (is_nil(as)) + return !is_nil(bs); + else if (is_nil(bs)) + return false; + else if (is_lt_no_level_params(car(as), car(bs))) + return true; + else if (is_lt_no_level_params(car(bs), car(as))) + return false; + else + return is_lt_no_level_params(cdr(as), cdr(bs)); +} + +bool is_lt_no_level_params(expr const & a, expr const & b) { + if (is_eqp(a, b)) return false; + unsigned wa = get_weight(a); + unsigned wb = get_weight(b); + if (wa < wb) return true; + if (wa > wb) return false; + if (a.kind() != b.kind()) return a.kind() < b.kind(); + switch (a.kind()) { + case expr_kind::Var: + return var_idx(a) < var_idx(b); + case expr_kind::Constant: + if (const_name(a) != const_name(b)) + return const_name(a) < const_name(b); + else + return is_lt_no_level_params(const_levels(a), const_levels(b)); + case expr_kind::App: + if (is_lt_no_level_params(app_fn(a), app_fn(b))) + return true; + else if (is_lt_no_level_params(app_fn(b), app_fn(a))) + return false; + else + return is_lt_no_level_params(app_arg(a), app_arg(b)); + case expr_kind::Lambda: case expr_kind::Pi: + if (is_lt_no_level_params(binding_domain(a), binding_domain(b))) + return true; + else if (is_lt_no_level_params(binding_domain(b), binding_domain(a))) + return false; + else + return is_lt_no_level_params(binding_body(a), binding_body(b)); + case expr_kind::Sort: + return is_lt_no_level_params(sort_level(a), sort_level(b)); + case expr_kind::Local: case expr_kind::Meta: + if (mlocal_name(a) != mlocal_name(b)) + return mlocal_name(a) < mlocal_name(b); + else + return is_lt_no_level_params(mlocal_type(a), mlocal_type(b)); + case expr_kind::Macro: + if (macro_def(a) != macro_def(b)) + return macro_def(a) < macro_def(b); + if (macro_num_args(a) != macro_num_args(b)) + return macro_num_args(a) < macro_num_args(b); + for (unsigned i = 0; i < macro_num_args(a); i++) { + if (is_lt_no_level_params(macro_arg(a, i), macro_arg(b, i))) + return true; + else if (is_lt_no_level_params(macro_arg(b, i), macro_arg(a, i))) + return false; + } + return false; + } + lean_unreachable(); +} + +int expr_cmp_no_level_params::operator()(expr const & e1, expr const & e2) const { + if (is_lt_no_level_params(e1, e2)) + return -1; + else if (is_lt_no_level_params(e2, e1)) + return 1; + else + return 0; +} } diff --git a/src/library/expr_lt.h b/src/library/expr_lt.h index cc40af234..538ca54d2 100644 --- a/src/library/expr_lt.h +++ b/src/library/expr_lt.h @@ -7,17 +7,19 @@ Author: Leonardo de Moura #pragma once #include "kernel/expr.h" namespace lean { -/** - \brief Total order on expressions. +/** \brief Total order on expressions. \remark If \c use_hash is true, then we use the hash_code to partially order expressions. Setting use_hash to false is useful for testing the code. */ bool is_lt(expr const & a, expr const & b, bool use_hash); +/** \brief Similar to is_lt, but universe level parameter names are ignored. */ +bool is_lt_no_level_params(expr const & a, expr const & b); inline bool operator<(expr const & a, expr const & b) { return is_lt(a, b, true); } inline bool operator>(expr const & a, expr const & b) { return is_lt(b, a, true); } inline bool operator<=(expr const & a, expr const & b) { return !is_lt(b, a, true); } inline bool operator>=(expr const & a, expr const & b) { return !is_lt(a, b, true); } struct expr_quick_cmp { int operator()(expr const & e1, expr const & e2) const { return is_lt(e1, e2, true) ? -1 : (e1 == e2 ? 0 : 1); } }; +struct expr_cmp_no_level_params { int operator()(expr const & e1, expr const & e2) const; }; }