feat(kernel/level): is_trivial predicate for level constraints

Signed-off-by: Leonardo de Moura <leonardo@microsoft.com>
This commit is contained in:
Leonardo de Moura 2014-02-23 10:35:49 -08:00
parent 0b3599851d
commit aa4a7acccf
3 changed files with 67 additions and 109 deletions

View file

@ -13,6 +13,7 @@ Author: Leonardo de Moura
#include "util/debug.h" #include "util/debug.h"
#include "util/hash.h" #include "util/hash.h"
#include "util/object_serializer.h" #include "util/object_serializer.h"
#include "util/interrupt.h"
#include "kernel/level.h" #include "kernel/level.h"
namespace lean { namespace lean {
@ -499,6 +500,33 @@ format pp(level l, bool unicode, unsigned indent) {
format pp(level const & l, options const & opts) { format pp(level const & l, options const & opts) {
return pp(l, get_pp_unicode(opts), get_pp_indent(opts)); return pp(l, get_pp_unicode(opts), get_pp_indent(opts));
} }
}
bool is_trivial(level const & lhs, level const & rhs) {
check_system("level constraints");
if (is_zero(lhs) || lhs == rhs) {
// 0 <= l
// l <= l
return true;
} else if (is_succ(lhs) && is_succ(rhs)) {
// is_trivial(l <= r) implies is_trivial(succ l <= succ r)
return is_trivial(succ_of(lhs), succ_of(rhs));
} else if (is_succ(rhs)) {
// is_trivial(l <= r) implies is_trivial(l <= succ^k r)
lean_assert(!is_succ(lhs));
level it = succ_of(rhs);
while (is_succ(it))
it = succ_of(it);
return is_trivial(lhs, it);
} else if (is_max(rhs)) {
// is_trivial(l <= l1) implies is_trivial(l <= max(l1, l2))
// is_trivial(l <= l2) implies is_trivial(l <= max(l1, l2))
return is_trivial(lhs, max_lhs(rhs)) || is_trivial(lhs, max_rhs(rhs));
} else if (is_imax(rhs)) {
// is_trivial(l <= l2) implies is_trivial(l <= imax(l1, l2))
return is_trivial(lhs, imax_rhs(rhs));
} else {
return false;
}
}
}
void print(lean::level const & l) { std::cout << l << std::endl; } void print(lean::level const & l) { std::cout << l << std::endl; }

View file

@ -110,6 +110,16 @@ bool is_explicit(level const & l);
*/ */
inline bool has_meta(level const & l) { return get_meta_range(l) > 0; } inline bool has_meta(level const & l) { return get_meta_range(l) > 0; }
/**
\brief Return true if lhs <= rhs is a trivial constraint.
That is, it is a constraint that is always valid, and can be discarded.
This is not a complete procedure. It only "catches" the easy cases.
\remark The type checker produces many trivial constraints.
*/
bool is_trivial(level const & lhs, level const & rhs);
/** /**
\brief Printer for debugging purposes \brief Printer for debugging purposes
*/ */

View file

@ -43,120 +43,40 @@ static void tst1() {
std::cout << pp(mk_max(p, mk_max(mk_succ(mk_param_univ(1)), one))) << "\n"; std::cout << pp(mk_max(p, mk_max(mk_succ(mk_param_univ(1)), one))) << "\n";
} }
#if 0
static void tst0() {
environment env;
lean_assert(env->begin_objects() == env->end_objects());
std::for_each(env->begin_objects(), env->end_objects(), [&](object const & obj) {
std::cout << obj.keyword() << "\n";
});
level l1 = env->add_uvar_cnstr(name(name("l1"), "suffix"), level());
lean_assert(env->begin_objects() != env->end_objects());
std::for_each(env->begin_objects(), env->end_objects(), [&](object const & obj) {
std::cout << obj.keyword() << "\n";
});
std::cout << env;
}
static void tst1() {
environment env;
level l1 = env->add_uvar_cnstr(name(name("l1"), "suffix"), level());
level l2 = env->add_uvar_cnstr("l2", l1 + 10);
level l3 = env->add_uvar_cnstr("l3", max(l2, l1 + 3));
level l4 = env->add_uvar_cnstr("l4", max(l1 + 8, max(l2 + 2, l3 + 20)));
check_serializer(l1);
check_serializer(l2);
check_serializer(l3);
check_serializer(l4);
std::cout << pp(max(l1 + 8, max(l2 + 2, l3 + 20))) << "\n";
std::cout << pp(level()) << "\n";
std::cout << pp(level()+1) << "\n";
std::cout << env;
lean_assert(env->is_ge(l4 + 10, l3 + 30));
lean_assert(!env->is_ge(l4 + 9, l3 + 30));
}
static void tst2() { static void tst2() {
environment env; level zero;
level l1 = env->add_uvar_cnstr("l1", level()); level one = mk_succ(zero);
level l2 = env->add_uvar_cnstr("l1", level()); level two = mk_succ(one);
level p1 = mk_param_univ(0);
level p2 = mk_param_univ(1);
level m1 = mk_meta_univ(0);
lean_assert(is_trivial(zero, mk_succ(mk_max(p1, p2))));
lean_assert(is_trivial(mk_succ(mk_max(p1, p2)), mk_succ(mk_max(p1, p2))));
lean_assert(is_trivial(p1, mk_succ(mk_max(p1, p2))));
lean_assert(!is_trivial(p1, mk_succ(mk_imax(p1, p2))));
lean_assert(is_trivial(p2, mk_succ(mk_max(p1, p2))));
lean_assert(is_trivial(mk_succ(p2), mk_succ(mk_max(p1, p2))));
lean_assert(is_trivial(p2, mk_succ(mk_imax(p1, p2))));
lean_assert(is_trivial(mk_succ(p2), mk_succ(mk_imax(p1, p2))));
lean_assert(!is_trivial(mk_succ(mk_succ(p2)), mk_succ(mk_max(p1, p2))));
lean_assert(!is_trivial(mk_succ(mk_max(p1, p2)), zero));
lean_assert(is_trivial(mk_succ(mk_succ(p1)), mk_succ(mk_succ(mk_succ(p1)))));
lean_assert(!is_trivial(mk_succ(mk_succ(p1)), mk_succ(mk_succ(mk_succ(p2)))));
lean_assert(!is_trivial(mk_succ(mk_succ(mk_succ(p1))), mk_succ(mk_succ(p1))));
lean_assert(is_trivial(p1, mk_max(m1, mk_max(p1, p2))));
lean_assert(!is_trivial(p1, mk_imax(m1, mk_imax(p1, p2))));
lean_assert(is_trivial(p2, mk_imax(m1, mk_imax(p1, p2))));
lean_assert(is_trivial(zero, one));
lean_assert(is_trivial(one, two));
lean_assert(!is_trivial(one, zero));
lean_assert(!is_trivial(two, one));
lean_assert(!is_trivial(m1, p1));
lean_assert(!is_trivial(p1, m1));
} }
static void tst3() {
environment env;
level l1 = env->add_uvar_cnstr("l1", level());
level l2 = env->add_uvar_cnstr("l2", l1 + ((1<<30) + 1024));
check_serializer(l2);
try {
level l3 = env->add_uvar_cnstr("l3", l2 + (1<<30));
lean_unreachable();
}
catch (exception & ex) {
std::cout << "ok\n";
}
}
static void tst4() {
environment env;
level l1 = env->add_uvar_cnstr("l1", level() + 1);
level l2 = env->add_uvar_cnstr("l2", level() + 1);
level l3 = env->add_uvar_cnstr("l3", max(l1, l2) + 1);
level l4 = env->add_uvar_cnstr("l4", l3 + 1);
level l5 = env->add_uvar_cnstr("l5", l3 + 1);
level l6 = env->add_uvar_cnstr("l6", max(l4, l5) + 1);
check_serializer(l1);
check_serializer(l2);
check_serializer(l3);
check_serializer(l4);
check_serializer(l5);
check_serializer(l6);
lean_assert(!env->is_ge(l5 + 1, l6));
lean_assert(env->is_ge(l6, l5));
lean_assert(env->is_ge(l6, max({l1, l2, l3, l4, l5})));
lean_assert(env->is_ge(l6, l6));
lean_assert(!env->is_ge(l5, l4));
lean_assert(env->is_ge(max({l1, l2, l4, l5}), max({l1, l2, l3, l4, l5})));
lean_assert(env->is_ge(max({l4, l5}), max({l1, l2, l3})));
lean_assert(!env->is_ge(max({l1, l2, l5}), max({l1, l2, l3, l4, l5})));
lean_assert(!env->is_ge(max({l2, l4}), max({l1, l2, l3, l4, l5})));
lean_assert(env->is_ge(max(l2, l3) + 1, max(l1, l1+1)));
lean_assert(env->is_ge(max(l2, l3) + 1, max(l1+2, l1+1)));
lean_assert(env->is_ge(max(l2, l3) + 1, max(l2+2, l1+1)));
lean_assert(!env->is_ge(max(l4, l5) + 1, max(l2+4, l1+1)));
lean_assert(!env->is_ge(max(l6, l5), max(l2+4, l1+1)));
lean_assert(env->is_ge(max(l6, l5), max(l2+3, l1+1)));
lean_assert(!env->is_ge(max(l6, l5), max(l2, l1+1)+3));
lean_assert(env->is_ge(max(l6+1, l5), max(l2, l1+1)+3));
std::cout << env;
}
static void tst5() {
environment env;
level l1 = env->add_uvar_cnstr("l1", level() + 1);
level l2 = env->add_uvar_cnstr("l2", level() + 1);
std::cout << max(l1, l1) << "\n";
lean_assert(max(l1, l1) == l1);
lean_assert(max(l1+1, l1+1) == l1+1);
std::cout << max(l1, l1+1) << "\n";
std::cout << max(l2, max(l1, l1+1)) << "\n";
lean_assert(max(l1, l1+1) == l1+1);
lean_assert(max(l2, max(l1, l1+1)) == max(l2, l1+1));
std::cout << max(l1, max(l2, l1+1)) << "\n";
lean_assert(max(l1, max(l2, l1+1)) == max(l1+1, l2));
}
#endif
int main() { int main() {
save_stack_info(); save_stack_info();
tst1(); tst1();
#if 0
tst0();
tst1();
tst2(); tst2();
tst3();
tst4();
tst5();
#endif
return has_violations() ? 1 : 0; return has_violations() ? 1 : 0;
} }