Normalize level expressions

Signed-off-by: Leonardo de Moura <leonardo@microsoft.com>
This commit is contained in:
Leonardo de Moura 2013-08-01 18:52:28 -07:00
parent e220d7c525
commit 7b00561a94
6 changed files with 159 additions and 45 deletions

View file

@ -53,10 +53,10 @@ struct environment::imp {
return d != uninit && (k < 0 || (k >= 0 && d >= static_cast<unsigned>(k)));
}
case level_kind::Lift: return is_ge(lift_of(l1), l2, sub(k, lift_offset(l1)));
case level_kind::Max: return is_ge(max_level1(l1), l2, k) || is_ge(max_level2(l1), l2, k);
case level_kind::Max: return std::any_of(max_begin_levels(l1), max_end_levels(l1), [&](level const & l) { return is_ge(l, l2, k); });
}
case level_kind::Lift: return is_ge(l1, lift_of(l2), add(k, lift_offset(l2)));
case level_kind::Max: return is_ge(l1, max_level1(l2), k) && is_ge(l1, max_level2(l2), k);
case level_kind::Max: return std::all_of(max_begin_levels(l2), max_end_levels(l2), [&](level const & l) { return is_ge(l1, l, k); });
}
lean_unreachable();
return false;
@ -103,9 +103,9 @@ struct environment::imp {
void add_constraints(uvar v1, level const & l, unsigned k) {
switch (kind(l)) {
case level_kind::UVar: add_constraint(v1, uvar_idx(l), k); return;
case level_kind::Lift: add_constraints(v1, lift_of(l), add(k, lift_offset(l))); return;
case level_kind::Max: add_constraints(v1, max_level1(l), k); add_constraints(v1, max_level2(l), k); return;
case level_kind::UVar: add_constraint(v1, uvar_idx(l), k); return;
case level_kind::Lift: add_constraints(v1, lift_of(l), add(k, lift_offset(l))); return;
case level_kind::Max: std::for_each(max_begin_levels(l), max_end_levels(l), [&](level const & l1) { add_constraints(v1, l1, k); }); return;
}
lean_unreachable();
}

View file

@ -4,7 +4,9 @@ Released under Apache 2.0 license as described in the file LICENSE.
Author: Leonardo de Moura
*/
#include <algorithm>
#include "level.h"
#include "buffer.h"
#include "rc.h"
#include "debug.h"
#include "hash.h"
@ -27,9 +29,18 @@ struct level_lift : public level_cell {
level_lift(level const & l, unsigned k):level_cell(level_kind::Lift), m_l(l), m_k(k) {}
};
struct level_max : public level_cell {
level m_l1;
level m_l2;
level_max(level const & l1, level const & l2):level_cell(level_kind::Max), m_l1(l1), m_l2(l2) {}
unsigned m_size;
level m_levels[0];
level_max(unsigned sz, level const * ls):level_cell(level_kind::Max), m_size(sz) {
for (unsigned i = 0; i < m_size; i++)
new (m_levels + i) level(ls[i]);
}
~level_max() {
for (unsigned i = 0; i < m_size; i++)
(m_levels+i)->~level();
}
level const * begin_levels() const { return m_levels; }
level const * end_levels() const { return m_levels + m_size; }
};
level_uvar * to_uvar(level_cell * c) { return static_cast<level_uvar*>(c); }
level_lift * to_lift(level_cell * c) { return static_cast<level_lift*>(c); }
@ -38,13 +49,13 @@ void level_cell::dealloc() {
switch (m_kind) {
case level_kind::UVar: delete to_uvar(this); break;
case level_kind::Lift: delete to_lift(this); break;
case level_kind::Max: delete to_max(this); break;
case level_kind::Max: static_cast<level_max*>(this)->~level_max(); delete[] reinterpret_cast<char*>(this); break;
}
}
level::level(): m_ptr(new level_uvar(name("bot"), 0)) { lean_assert(uvar_name(*this) == name("bot")); }
level::level(name const & n, uvar u): m_ptr(new level_uvar(n, u)) {}
level::level(level const & l, unsigned k): m_ptr(new level_lift(l, k)) {}
level::level(level const & l1, level const & l2):m_ptr(new level_max(l1, l2)) {}
level::level(): m_ptr(new level_uvar(name("bot"), 0)) { lean_assert(uvar_name(*this) == name("bot")); }
level::level(name const & n, uvar u): m_ptr(new level_uvar(n, u)) {}
level::level(level const & l, unsigned k):m_ptr(new level_lift(l, k)) { lean_assert(is_uvar(l)); }
level::level(level_cell * ptr): m_ptr(ptr) { lean_assert(m_ptr->get_rc() == 1); }
level::level(level const & s):
m_ptr(s.m_ptr) {
if (m_ptr)
@ -58,22 +69,89 @@ level::~level() {
if (m_ptr)
m_ptr->dec_ref();
}
level to_level(level_cell * c) { return level(c); }
level_cell * to_cell(level const & l) { return l.m_ptr; }
level_max * to_max(level const & l) { return to_max(to_cell(l)); }
unsigned level::hash() const {
switch (m_ptr->m_kind) {
case level_kind::UVar: return to_uvar(m_ptr)->m_name.hash();
case level_kind::Lift: return ::lean::hash(to_lift(m_ptr)->m_l.hash(), to_lift(m_ptr)->m_k);
case level_kind::Max: return ::lean::hash(to_max(m_ptr)->m_l1.hash(), to_max(m_ptr)->m_l2.hash());
case level_kind::Max: return ::lean::hash(to_max(m_ptr)->m_size, [&](unsigned i) { return to_max(m_ptr)->m_levels[i].hash(); });
}
return 0;
}
level max_core(unsigned sz, level const * ls) {
char * mem = new char[sizeof(level_max) + sz*sizeof(level)];
return to_level(new (mem) level_max(sz, ls));
}
level const & _lift_of(level const & l) { return is_lift(l) ? lift_of(l) : l; }
unsigned _lift_offset(level const & l) { return is_lift(l) ? lift_offset(l) : 0; }
void push_back(buffer<level> & ls, level const & l) {
for (unsigned i = 0; i < ls.size(); i++) {
if (_lift_of(ls[i]) == _lift_of(l)) {
if (_lift_offset(ls[i]) < _lift_offset(l))
ls[i] = l;
return;
}
}
ls.push_back(l);
}
level max_core(unsigned sz1, level const * ls1, unsigned sz2, level const * ls2) {
buffer<level> new_lvls;
std::for_each(ls1, ls1 + sz1, [&](level const & l) { push_back(new_lvls, l); });
std::for_each(ls2, ls2 + sz2, [&](level const & l) { push_back(new_lvls, l); });
if (new_lvls.size() == 1)
return new_lvls[0];
else
return max_core(new_lvls.size(), new_lvls.data());
}
level max_core(level const & l1, level const & l2) { return max_core(1, &l1, 1, &l2); }
level max_core(level const & l1, level_max * l2) { return max_core(1, &l1, l2->m_size, l2->m_levels); }
level max_core(level_max * l1, level const & l2) { return max_core(l1->m_size, l1->m_levels, 1, &l2); }
level max_core(level_max * l1, level_max * l2) { return max_core(l1->m_size, l1->m_levels, l2->m_size, l2->m_levels); }
level max(level const & l1, level const & l2) {
if (is_max(l1)) {
if (is_max(l2))
return max_core(to_max(l1), to_max(l1));
else
return max_core(to_max(l1), l2);
}
else {
if (is_max(l2))
return max_core(l1, to_max(l2));
else
return max_core(l1, l2);
}
}
level operator+(level const & l, unsigned k) {
switch (kind(l)) {
case level_kind::UVar: return level(l, k);
case level_kind::Lift: return level(lift_of(l), lift_offset(l) + k);
case level_kind::Max: {
std::cout << l << "\n";
buffer<level> new_lvls;
for (unsigned i = 0; i < max_size(l); i++)
new_lvls.push_back(max_level(l, i) + k);
return max_core(new_lvls.size(), new_lvls.data());
}}
lean_unreachable();
return level();
}
level_kind kind (level const & l) { lean_assert(l.m_ptr); return l.m_ptr->m_kind; }
name const & uvar_name (level const & l) { lean_assert(is_uvar(l)); return static_cast<level_uvar*>(l.m_ptr)->m_name; }
uvar uvar_idx (level const & l) { lean_assert(is_uvar(l)); return static_cast<level_uvar*>(l.m_ptr)->m_uvar; }
level const & lift_of (level const & l) { lean_assert(is_lift(l)); return static_cast<level_lift*>(l.m_ptr)->m_l; }
unsigned lift_offset(level const & l) { lean_assert(is_lift(l)); return static_cast<level_lift*>(l.m_ptr)->m_k; }
level const & max_level1 (level const & l) { lean_assert(is_max(l)); return static_cast<level_max*>(l.m_ptr)->m_l1; }
level const & max_level2 (level const & l) { lean_assert(is_max(l)); return static_cast<level_max*>(l.m_ptr)->m_l2; }
unsigned max_size (level const & l) { lean_assert(is_max(l)); return static_cast<level_max*>(l.m_ptr)->m_size; }
level const & max_level (level const & l, unsigned i) { lean_assert(is_max(l)); return static_cast<level_max*>(l.m_ptr)->m_levels[i]; }
level & level::operator=(level const & l) { LEAN_COPY_REF(level, l); }
level & level::operator=(level&& l) { LEAN_MOVE_REF(level, l); }
@ -81,9 +159,17 @@ level & level::operator=(level&& l) { LEAN_MOVE_REF(level, l); }
bool operator==(level const & l1, level const & l2) {
if (kind(l1) != kind(l2)) return false;
switch (kind(l1)) {
case level_kind::UVar: return uvar_idx(l1) == uvar_idx(l2);
case level_kind::Lift: return lift_of(l1) == lift_of(l2) && lift_offset(l1) == lift_offset(l2);
case level_kind::Max: return max_level1(l1) == max_level1(l2) && max_level2(l1) == max_level2(l2);
case level_kind::UVar: return uvar_idx(l1) == uvar_idx(l2);
case level_kind::Lift: return lift_of(l1) == lift_of(l2) && lift_offset(l1) == lift_offset(l2);
case level_kind::Max:
if (max_size(l1) == max_size(l2)) {
for (unsigned i = 0; i < max_size(l1); i++)
if (max_level(l1, i) != max_level(l2, i))
return false;
return true;
} else {
return false;
}
}
lean_unreachable();
return false;
@ -91,20 +177,21 @@ bool operator==(level const & l1, level const & l2) {
std::ostream & operator<<(std::ostream & out, level const & l) {
switch (kind(l)) {
case level_kind::UVar: out << uvar_name(l); return out;
case level_kind::Lift: out << lift_of(l) << "+" << lift_offset(l); return out;
case level_kind::Max: out << "(max " << max_level1(l) << " " << max_level2(l) << ")"; return out;
case level_kind::UVar: out << uvar_name(l); return out;
case level_kind::Lift: out << lift_of(l) << "+" << lift_offset(l); return out;
case level_kind::Max:
out << "(max";
for (unsigned i = 0; i < max_size(l); i++)
out << " " << max_level(l, i);
out << ")";
return out;
}
return out;
}
level max(std::initializer_list<level> const & l) {
lean_assert(l.size() >= 1);
auto it = l.begin();
level r = *it;
++it;
for (; it != l.end(); ++it)
r = max(r, *it);
return r;
if (l.size() == 1)
return *(l.begin());
return max_core(l.size(), l.begin());
}
}

View file

@ -21,13 +21,14 @@ class level {
level_cell * m_ptr;
/** \brief Private constructor used by the environment to create a new universe variable named \c n with internal id \c u. */
level(name const & n, uvar u);
level(level const & l, unsigned k);
level(level_cell * ptr);
friend level to_level(level_cell * c);
friend level_cell * to_cell(level const & l);
friend level operator+(level const & l, unsigned k);
public:
/** \brief Universe 0 */
level();
/** \brief Lift universe l by k (l + k) */
level(level const & l, unsigned k);
/** \brief New level that is >= max(l1,l2) */
level(level const & l1, level const & l2);
level(level const & l);
level(level&& s);
~level();
@ -39,8 +40,8 @@ public:
friend uvar uvar_idx (level const & l);
friend level const & lift_of (level const & l);
friend unsigned lift_offset(level const & l);
friend level const & max_level1 (level const & l);
friend level const & max_level2 (level const & l);
friend unsigned max_size (level const & l);
friend level const & max_level (level const & l, unsigned i);
level & operator=(level const & l);
level & operator=(level&& l);
@ -51,10 +52,15 @@ public:
friend std::ostream & operator<<(std::ostream & out, level const & l);
};
inline level max(level const & l1, level const & l2) { return level(l1, l2); }
level max(std::initializer_list<level> const & l);
inline level operator+(level const & l, unsigned k) { return level(l, k); }
level max(level const & l1, level const & l2);
level max(std::initializer_list<level> const & l);
level operator+(level const & l, unsigned k);
inline bool is_uvar(level const & l) { return kind(l) == level_kind::UVar; }
inline bool is_lift(level const & l) { return kind(l) == level_kind::Lift; }
inline bool is_max (level const & l) { return kind(l) == level_kind::Max; }
inline level const * max_begin_levels(level const & l) { return &max_level(l, 0); }
inline level const * max_end_levels(level const & l) { return max_begin_levels(l) + max_size(l); }
}

View file

@ -41,10 +41,10 @@ public:
unsigned get_var_idx() const { lean_assert(is_bounded_var()); return m_bvar; }
};
value_kind kind(value const & v) { return v.kind(); }
expr const & to_expr(value const & v) { return v.get_expr(); }
stack const & stack_of(value const & v) { return v.get_ctx(); }
unsigned to_bvar(value const & v) { return v.get_var_idx(); }
value_kind kind(value const & v) { return v.kind(); }
expr const & to_expr(value const & v) { return v.get_expr(); }
stack const & stack_of(value const & v) { return v.get_ctx(); }
unsigned to_bvar(value const & v) { return v.get_var_idx(); }
stack extend(stack const & s, value const & v) { return cons(v, s); }

View file

@ -36,9 +36,9 @@ static void tst2() {
static void tst3() {
environment env;
level l1 = env.define_uvar("l1", level());
level l2 = env.define_uvar("l2", level(l1, (1<<30) + 1024));
level l2 = env.define_uvar("l2", l1 + ((1<<30) + 1024));
try {
level l3 = env.define_uvar("l3", level(l2, 1<<30));
level l3 = env.define_uvar("l3", l2 + (1<<30));
lean_unreachable();
}
catch (exception ex) {
@ -74,11 +74,27 @@ static void tst4() {
env.display_uvars(std::cout);
}
static void tst5() {
environment env;
level l1 = env.define_uvar("l1", level() + 1);
level l2 = env.define_uvar("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));
}
int main() {
continue_on_violation(true);
// continue_on_violation(true);
tst1();
tst2();
tst3();
tst4();
tst5();
return has_violations() ? 1 : 0;
}

View file

@ -94,6 +94,11 @@ public:
m_pos--;
}
void append(unsigned sz, T const * elems) {
for (unsigned i = 0; i < sz; i++)
push_back(elems[i]);
}
void resize(unsigned nsz, T const & elem=T()) {
unsigned sz = size();
if (nsz > sz) {