fix(library/expr_lt): make sure the builtin order is AC-compatible

Signed-off-by: Leonardo de Moura <leonardo@microsoft.com>
This commit is contained in:
Leonardo de Moura 2014-08-04 15:48:24 -07:00
parent b2cb49fa1f
commit 0d5e346143
7 changed files with 51 additions and 31 deletions

View file

@ -26,6 +26,20 @@ Author: Leonardo de Moura
#endif #endif
namespace lean { namespace lean {
unsigned add_weight(unsigned w1, unsigned w2) {
unsigned r = w1 + w2;
if (r < w1)
r = std::numeric_limits<unsigned>::max(); // overflow
return r;
}
unsigned inc_weight(unsigned w) {
if (w < std::numeric_limits<unsigned>::max())
return w+1;
else
return w;
}
static expr g_dummy(mk_var(0)); static expr g_dummy(mk_var(0));
expr::expr():expr(g_dummy) {} expr::expr():expr(g_dummy) {}
@ -150,9 +164,9 @@ void expr_local::dealloc(buffer<expr_cell*> & todelete) {
// Composite expressions // Composite expressions
expr_composite::expr_composite(expr_kind k, unsigned h, bool has_expr_mv, bool has_univ_mv, expr_composite::expr_composite(expr_kind k, unsigned h, bool has_expr_mv, bool has_univ_mv,
bool has_local, bool has_param_univ, unsigned d, unsigned fv_range): bool has_local, bool has_param_univ, unsigned w, unsigned fv_range):
expr_cell(k, h, has_expr_mv, has_univ_mv, has_local, has_param_univ), expr_cell(k, h, has_expr_mv, has_univ_mv, has_local, has_param_univ),
m_depth(d), m_weight(w),
m_free_var_range(fv_range) {} m_free_var_range(fv_range) {}
// Expr applications // Expr applications
@ -164,10 +178,10 @@ expr_app::expr_app(expr const & fn, expr const & arg):
fn.has_univ_metavar() || arg.has_univ_metavar(), fn.has_univ_metavar() || arg.has_univ_metavar(),
fn.has_local() || arg.has_local(), fn.has_local() || arg.has_local(),
fn.has_param_univ() || arg.has_param_univ(), fn.has_param_univ() || arg.has_param_univ(),
std::max(get_depth(fn), get_depth(arg)) + 1, inc_weight(add_weight(get_weight(fn), get_weight(arg))),
std::max(get_free_var_range(fn), get_free_var_range(arg))), std::max(get_free_var_range(fn), get_free_var_range(arg))),
m_fn(fn), m_arg(arg) { m_fn(fn), m_arg(arg) {
m_hash = ::lean::hash(m_hash, m_depth); m_hash = ::lean::hash(m_hash, m_weight);
} }
void expr_app::dealloc(buffer<expr_cell*> & todelete) { void expr_app::dealloc(buffer<expr_cell*> & todelete) {
dec_ref(m_fn, todelete); dec_ref(m_fn, todelete);
@ -195,11 +209,11 @@ expr_binding::expr_binding(expr_kind k, name const & n, expr const & t, expr con
t.has_univ_metavar() || b.has_univ_metavar(), t.has_univ_metavar() || b.has_univ_metavar(),
t.has_local() || b.has_local(), t.has_local() || b.has_local(),
t.has_param_univ() || b.has_param_univ(), t.has_param_univ() || b.has_param_univ(),
std::max(get_depth(t), get_depth(b)) + 1, inc_weight(add_weight(get_weight(t), get_weight(b))),
std::max(get_free_var_range(t), dec(get_free_var_range(b)))), std::max(get_free_var_range(t), dec(get_free_var_range(b)))),
m_binder(n, t, i), m_binder(n, t, i),
m_body(b) { m_body(b) {
m_hash = ::lean::hash(m_hash, m_depth); m_hash = ::lean::hash(m_hash, m_weight);
lean_assert(k == expr_kind::Lambda || k == expr_kind::Pi); lean_assert(k == expr_kind::Lambda || k == expr_kind::Pi);
} }
void expr_binding::dealloc(buffer<expr_cell*> & todelete) { void expr_binding::dealloc(buffer<expr_cell*> & todelete) {
@ -245,13 +259,10 @@ bool macro_definition::operator<(macro_definition const & other) const {
return get_name() < other.get_name(); return get_name() < other.get_name();
} }
static unsigned max_depth(unsigned num, expr const * args) { static unsigned add_weight(unsigned num, expr const * args) {
unsigned r = 0; unsigned r = 0;
for (unsigned i = 0; i < num; i++) { for (unsigned i = 0; i < num; i++)
unsigned d = get_depth(args[i]); r = add_weight(r, get_weight(args[i]));
if (d > r)
r = d;
}
return r; return r;
} }
@ -272,7 +283,7 @@ expr_macro::expr_macro(macro_definition const & m, unsigned num, expr const * ar
std::any_of(args, args+num, [](expr const & e) { return e.has_univ_metavar(); }), std::any_of(args, args+num, [](expr const & e) { return e.has_univ_metavar(); }),
std::any_of(args, args+num, [](expr const & e) { return e.has_local(); }), std::any_of(args, args+num, [](expr const & e) { return e.has_local(); }),
std::any_of(args, args+num, [](expr const & e) { return e.has_param_univ(); }), std::any_of(args, args+num, [](expr const & e) { return e.has_param_univ(); }),
max_depth(num, args) + 1, inc_weight(add_weight(num, args)),
get_free_var_range(num, args)), get_free_var_range(num, args)),
m_definition(m), m_definition(m),
m_num_args(num) { m_num_args(num) {
@ -471,14 +482,14 @@ expr mk_Type() {
expr Prop = mk_Prop(); expr Prop = mk_Prop();
expr Type = mk_Type(); expr Type = mk_Type();
unsigned get_depth(expr const & e) { unsigned get_weight(expr const & e) {
switch (e.kind()) { switch (e.kind()) {
case expr_kind::Var: case expr_kind::Constant: case expr_kind::Sort: case expr_kind::Var: case expr_kind::Constant: case expr_kind::Sort:
case expr_kind::Meta: case expr_kind::Local: case expr_kind::Meta: case expr_kind::Local:
return 1; return 1;
case expr_kind::Lambda: case expr_kind::Pi: case expr_kind::Macro: case expr_kind::Lambda: case expr_kind::Pi: case expr_kind::Macro:
case expr_kind::App: case expr_kind::App:
return static_cast<expr_composite*>(e.raw())->m_depth; return static_cast<expr_composite*>(e.raw())->m_weight;
} }
lean_unreachable(); // LCOV_EXCL_LINE lean_unreachable(); // LCOV_EXCL_LINE
} }

View file

@ -200,13 +200,13 @@ public:
/** \brief Composite expressions */ /** \brief Composite expressions */
class expr_composite : public expr_cell { class expr_composite : public expr_cell {
protected: protected:
unsigned m_depth; unsigned m_weight;
unsigned m_free_var_range; unsigned m_free_var_range;
friend unsigned get_depth(expr const & e); friend unsigned get_weight(expr const & e);
friend unsigned get_free_var_range(expr const & e); friend unsigned get_free_var_range(expr const & e);
public: public:
expr_composite(expr_kind k, unsigned h, bool has_expr_mv, bool has_univ_mv, bool has_local, expr_composite(expr_kind k, unsigned h, bool has_expr_mv, bool has_univ_mv, bool has_local,
bool has_param_univ, unsigned d, unsigned fv_range); bool has_param_univ, unsigned w, unsigned fv_range);
}; };
/** \brief Metavariables and local constants */ /** \brief Metavariables and local constants */
@ -589,7 +589,7 @@ inline bool has_univ_metavar(expr const & e) { return e.has_univ_metavar(); }
bool has_expr_metavar_strict(expr const & e); bool has_expr_metavar_strict(expr const & e);
inline bool has_local(expr const & e) { return e.has_local(); } inline bool has_local(expr const & e) { return e.has_local(); }
inline bool has_param_univ(expr const & e) { return e.has_param_univ(); } inline bool has_param_univ(expr const & e) { return e.has_param_univ(); }
unsigned get_depth(expr const & e); unsigned get_weight(expr const & e);
/** /**
\brief Return \c R s.t. the de Bruijn index of all free variables \brief Return \c R s.t. the de Bruijn index of all free variables
occurring in \c e is in the interval <tt>[0, R)</tt>. occurring in \c e is in the interval <tt>[0, R)</tt>.

View file

@ -10,10 +10,10 @@ Author: Leonardo de Moura
namespace lean { namespace lean {
bool is_lt(expr const & a, expr const & b, bool use_hash) { bool is_lt(expr const & a, expr const & b, bool use_hash) {
if (is_eqp(a, b)) return false; if (is_eqp(a, b)) return false;
unsigned da = get_depth(a); unsigned wa = get_weight(a);
unsigned db = get_depth(b); unsigned wb = get_weight(b);
if (da < db) return true; if (wa < wb) return true;
if (da > db) return false; if (wa > wb) return false;
if (a.kind() != b.kind()) return a.kind() < b.kind(); if (a.kind() != b.kind()) return a.kind() < b.kind();
if (use_hash) { if (use_hash) {
if (a.hash() < b.hash()) return true; if (a.hash() < b.hash()) return true;

View file

@ -581,8 +581,8 @@ static int binding_info(lua_State * L) { return push_binder_info(L, binding_info
static int expr_occurs(lua_State * L) { return push_boolean(L, occurs(to_expr(L, 1), to_expr(L, 2))); } static int expr_occurs(lua_State * L) { return push_boolean(L, occurs(to_expr(L, 1), to_expr(L, 2))); }
static int expr_is_eqp(lua_State * L) { return push_boolean(L, is_eqp(to_expr(L, 1), to_expr(L, 2))); } static int expr_is_eqp(lua_State * L) { return push_boolean(L, is_eqp(to_expr(L, 1), to_expr(L, 2))); }
static int expr_hash(lua_State * L) { return push_integer(L, to_expr(L, 1).hash()); } static int expr_hash(lua_State * L) { return push_integer(L, to_expr(L, 1).hash()); }
static int expr_depth(lua_State * L) { return push_integer(L, get_depth(to_expr(L, 1))); } static int expr_weight(lua_State * L) { return push_integer(L, get_weight(to_expr(L, 1))); }
static int expr_is_lt(lua_State * L) { static int expr_is_lt(lua_State * L) {
int nargs = lua_gettop(L); int nargs = lua_gettop(L);
return push_boolean(L, is_lt(to_expr(L, 1), to_expr(L, 2), nargs == 3 && lua_toboolean(L, 3))); return push_boolean(L, is_lt(to_expr(L, 1), to_expr(L, 2), nargs == 3 && lua_toboolean(L, 3)));
@ -630,7 +630,7 @@ static const struct luaL_Reg expr_m[] = {
{"fn", safe_function<expr_fn>}, {"fn", safe_function<expr_fn>},
{"fields", safe_function<expr_fields>}, {"fields", safe_function<expr_fields>},
{"data", safe_function<expr_fields>}, {"data", safe_function<expr_fields>},
{"depth", safe_function<expr_depth>}, {"weight", safe_function<expr_weight>},
{"binding_name", safe_function<binding_name>}, {"binding_name", safe_function<binding_name>},
{"binding_domain", safe_function<binding_domain>}, {"binding_domain", safe_function<binding_domain>},
{"binding_body", safe_function<binding_body>}, {"binding_body", safe_function<binding_body>},

View file

@ -8,6 +8,7 @@ Author: Leonardo de Moura
#include <algorithm> #include <algorithm>
#include <utility> #include <utility>
#include <vector> #include <vector>
#include <limits>
#include "util/test.h" #include "util/test.h"
#include "kernel/expr.h" #include "kernel/expr.h"
#include "kernel/expr_sets.h" #include "kernel/expr_sets.h"
@ -68,11 +69,11 @@ static expr mk_dag(unsigned depth, bool _closed = false) {
} }
static void tst2() { static void tst2() {
expr r1 = mk_dag(20); expr r1 = mk_dag(40);
expr r2 = mk_dag(20); expr r2 = mk_dag(40);
lean_assert(r1 == r2); lean_assert(r1 == r2);
std::cout << get_depth(r1) << "\n"; std::cout << get_weight(r1) << "\n";
lean_assert_eq(get_depth(r1), 41); lean_assert(get_weight(r1) == std::numeric_limits<unsigned>::max());
} }
static expr mk_big(expr f, unsigned depth, unsigned val) { static expr mk_big(expr f, unsigned depth, unsigned val) {

View file

@ -95,5 +95,5 @@ assert(a:occurs(f(a)))
enable_expr_caching(false) enable_expr_caching(false)
assert(not f(a):is_eqp(f(a))) assert(not f(a):is_eqp(f(a)))
assert(f(a):arg():is_eqp(a)) assert(f(a):arg():is_eqp(a))
assert(f(a):depth() == 2) assert(f(a):weight() == 3)
print(f(a):hash()) print(f(a):hash())

8
tests/lua/order.lua Normal file
View file

@ -0,0 +1,8 @@
local mul = Const("mul")
local div = Const("div")
local z = Const("z")
local x = Const("x")
local y = Const("y")
local t1 = mul(z, mul(div(x, y), y))
local t2 = mul(div(x, y), mul(z, y))
assert(t1 < t2)