2013-07-25 02:36:54 +00:00
|
|
|
/*
|
|
|
|
Copyright (c) 2013 Microsoft Corporation. All rights reserved.
|
|
|
|
Released under Apache 2.0 license as described in the file LICENSE.
|
|
|
|
|
|
|
|
Author: Leonardo de Moura
|
|
|
|
*/
|
2013-07-26 02:13:45 +00:00
|
|
|
#include <algorithm>
|
2013-07-25 02:36:54 +00:00
|
|
|
#include "normalize.h"
|
2013-08-04 16:37:52 +00:00
|
|
|
#include "builtin.h"
|
2013-07-25 02:36:54 +00:00
|
|
|
#include "trace.h"
|
|
|
|
#include "test.h"
|
2013-07-26 02:13:45 +00:00
|
|
|
#include "sets.h"
|
2013-07-25 02:36:54 +00:00
|
|
|
using namespace lean;
|
|
|
|
|
2013-07-30 07:25:19 +00:00
|
|
|
expr normalize(expr const & e) {
|
|
|
|
environment env;
|
|
|
|
return normalize(e, env);
|
|
|
|
}
|
|
|
|
|
2013-08-05 03:52:14 +00:00
|
|
|
static void eval(expr const & e, environment & env) { std::cout << e << " --> " << normalize(e, env) << "\n"; }
|
2013-07-26 02:13:45 +00:00
|
|
|
static expr t() { return constant("t"); }
|
|
|
|
static expr lam(expr const & e) { return lambda("_", t(), e); }
|
|
|
|
static expr lam(expr const & t, expr const & e) { return lambda("_", t, e); }
|
|
|
|
static expr v(unsigned i) { return var(i); }
|
|
|
|
static expr zero() {
|
|
|
|
// fun (t : T) (s : t -> t) (z : t) z
|
|
|
|
return lam(t(), lam(arrow(v(0), v(0)), lam(v(1), v(0))));
|
|
|
|
}
|
|
|
|
static expr one() {
|
|
|
|
// fun (t : T) (s : t -> t) s
|
|
|
|
return lam(t(), lam(arrow(v(0), v(0)), v(0)));
|
|
|
|
}
|
|
|
|
static expr num() { return constant("num"); }
|
|
|
|
static expr plus() {
|
|
|
|
// fun (m n : numeral) (A : Type 0) (f : A -> A) (x : A) => m A f (n A f x).
|
|
|
|
expr x = v(0), f = v(1), A = v(2), n = v(3), m = v(4);
|
|
|
|
expr body = m(A, f, n(A, f, x));
|
|
|
|
return lam(num(), lam(num(), lam(t(), lam(arrow(v(0), v(0)), lam(v(1), body)))));
|
|
|
|
}
|
|
|
|
static expr two() { return app(plus(), one(), one()); }
|
2013-07-26 05:05:09 +00:00
|
|
|
static expr three() { return app(plus(), two(), one()); }
|
2013-07-26 02:13:45 +00:00
|
|
|
static expr four() { return app(plus(), two(), two()); }
|
|
|
|
static expr times() {
|
|
|
|
// fun (m n : numeral) (A : Type 0) (f : A -> A) (x : A) => m A (n A f) x.
|
|
|
|
expr x = v(0), f = v(1), A = v(2), n = v(3), m = v(4);
|
|
|
|
expr body = m(A, n(A, f), x);
|
|
|
|
return lam(num(), lam(num(), lam(t(), lam(arrow(v(0), v(0)), lam(v(1), body)))));
|
|
|
|
}
|
|
|
|
static expr power() {
|
|
|
|
// fun (m n : numeral) (A : Type 0) => m (A -> A) (n A).
|
|
|
|
expr A = v(0), n = v(1), m = v(2);
|
|
|
|
expr body = n(arrow(A, A), m(A));
|
|
|
|
return lam(num(), lam(num(), lam(arrow(v(0), v(0)), body)));
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned count_core(expr const & a, expr_set & s) {
|
|
|
|
if (s.find(a) != s.end())
|
|
|
|
return 0;
|
|
|
|
s.insert(a);
|
|
|
|
switch (a.kind()) {
|
2013-08-03 23:09:21 +00:00
|
|
|
case expr_kind::Var: case expr_kind::Constant: case expr_kind::Type: case expr_kind::Value:
|
2013-07-26 02:13:45 +00:00
|
|
|
return 1;
|
|
|
|
case expr_kind::App:
|
|
|
|
return std::accumulate(begin_args(a), end_args(a), 1,
|
2013-07-26 21:16:29 +00:00
|
|
|
[&](unsigned sum, expr const & arg){ return sum + count_core(arg, s); });
|
2013-08-04 16:37:52 +00:00
|
|
|
case expr_kind::Eq:
|
|
|
|
return count_core(eq_lhs(a), s) + count_core(eq_rhs(a), s) + 1;
|
2013-07-26 02:13:45 +00:00
|
|
|
case expr_kind::Lambda: case expr_kind::Pi:
|
2013-08-03 18:31:42 +00:00
|
|
|
return count_core(abst_domain(a), s) + count_core(abst_body(a), s) + 1;
|
2013-08-04 16:37:52 +00:00
|
|
|
case expr_kind::Let:
|
|
|
|
return count_core(let_value(a), s) + count_core(let_body(a), s) + 1;
|
2013-07-26 02:13:45 +00:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned count(expr const & a) {
|
|
|
|
expr_set s;
|
|
|
|
return count_core(a, s);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void tst_church_numbers() {
|
2013-08-05 03:52:14 +00:00
|
|
|
environment env;
|
|
|
|
env.add_fact("t", type(level()));
|
|
|
|
env.add_fact("N", type(level()));
|
|
|
|
env.add_fact("z", constant("N"));
|
|
|
|
env.add_fact("s", constant("N"));
|
2013-07-26 02:13:45 +00:00
|
|
|
expr N = constant("N");
|
|
|
|
expr z = constant("z");
|
|
|
|
expr s = constant("s");
|
2013-08-05 03:52:14 +00:00
|
|
|
std::cout << normalize(app(zero(), N, s, z), env) << "\n";
|
|
|
|
std::cout << normalize(app(one(), N, s, z), env) << "\n";
|
|
|
|
std::cout << normalize(app(two(), N, s, z), env) << "\n";
|
|
|
|
std::cout << normalize(app(four(), N, s, z), env) << "\n";
|
|
|
|
std::cout << count(normalize(app(four(), N, s, z), env)) << "\n";
|
|
|
|
lean_assert(count(normalize(app(four(), N, s, z), env)) == 4 + 2);
|
|
|
|
std::cout << normalize(app(app(times(), four(), four()), N, s, z), env) << "\n";
|
|
|
|
std::cout << normalize(app(app(power(), two(), four()), N, s, z), env) << "\n";
|
|
|
|
lean_assert(count(normalize(app(app(power(), two(), four()), N, s, z), env)) == 16 + 2);
|
|
|
|
std::cout << normalize(app(app(times(), two(), app(power(), two(), four())), N, s, z), env) << "\n";
|
|
|
|
std::cout << count(normalize(app(app(times(), two(), app(power(), two(), four())), N, s, z), env)) << "\n";
|
|
|
|
std::cout << count(normalize(app(app(times(), four(), app(power(), two(), four())), N, s, z), env)) << "\n";
|
|
|
|
lean_assert(count(normalize(app(app(times(), four(), app(power(), two(), four())), N, s, z), env)) == 64 + 2);
|
|
|
|
expr big = normalize(app(app(power(), two(), app(power(), two(), three())), N, s, z), env);
|
2013-07-26 05:05:09 +00:00
|
|
|
std::cout << count(big) << "\n";
|
|
|
|
lean_assert(count(big) == 256 + 2);
|
2013-07-30 08:39:29 +00:00
|
|
|
expr three = app(plus(), two(), one());
|
2013-08-05 03:52:14 +00:00
|
|
|
lean_assert(count(normalize(app(app(power(), three, three), N, s, z), env)) == 27 + 2);
|
|
|
|
// expr big2 = normalize(app(app(power(), two(), app(times(), app(plus(), four(), one()), four())), N, s, z), env);
|
2013-07-30 08:39:29 +00:00
|
|
|
// std::cout << count(big2) << "\n";
|
2013-08-05 03:52:14 +00:00
|
|
|
std::cout << normalize(lam(lam(app(app(times(), four(), four()), N, var(0), z))), env) << "\n";
|
2013-07-26 02:13:45 +00:00
|
|
|
}
|
|
|
|
|
2013-07-25 02:36:54 +00:00
|
|
|
static void tst1() {
|
2013-08-05 03:52:14 +00:00
|
|
|
environment env;
|
|
|
|
env.add_fact("t", type(level()));
|
|
|
|
expr t = type(level());
|
|
|
|
env.add_fact("f", arrow(t, t));
|
2013-07-25 02:36:54 +00:00
|
|
|
expr f = constant("f");
|
2013-08-05 03:52:14 +00:00
|
|
|
env.add_fact("a", t);
|
2013-07-25 02:36:54 +00:00
|
|
|
expr a = constant("a");
|
2013-08-05 03:52:14 +00:00
|
|
|
env.add_fact("b", t);
|
2013-07-25 02:36:54 +00:00
|
|
|
expr b = constant("b");
|
|
|
|
expr x = var(0);
|
|
|
|
expr y = var(1);
|
2013-08-05 03:52:14 +00:00
|
|
|
eval(app(lambda("x", t, x), a), env);
|
|
|
|
eval(app(lambda("x", t, x), a, b), env);
|
|
|
|
eval(lambda("x", t, f(x)), env);
|
|
|
|
eval(lambda("y", t, lambda("x", t, f(y, x))), env);
|
2013-07-25 02:36:54 +00:00
|
|
|
eval(app(lambda("x", t,
|
|
|
|
app(lambda("f", t,
|
|
|
|
app(var(0), b)),
|
|
|
|
lambda("g", t, f(var(1))))),
|
2013-08-05 03:52:14 +00:00
|
|
|
a), env);
|
2013-07-26 02:13:45 +00:00
|
|
|
expr l01 = lam(v(0)(v(1)));
|
|
|
|
expr l12 = lam(lam(v(1)(v(2))));
|
2013-08-05 03:52:14 +00:00
|
|
|
eval(lam(l12(l01)), env);
|
|
|
|
lean_assert(normalize(lam(l12(l01)), env) == lam(lam(v(1)(v(1)))));
|
2013-07-25 02:36:54 +00:00
|
|
|
}
|
|
|
|
|
2013-07-30 07:25:19 +00:00
|
|
|
static void tst2() {
|
|
|
|
environment env;
|
2013-08-05 03:52:14 +00:00
|
|
|
expr t = type(level());
|
|
|
|
env.add_fact("f", arrow(t, t));
|
2013-07-30 07:25:19 +00:00
|
|
|
expr f = constant("f");
|
2013-08-05 03:52:14 +00:00
|
|
|
env.add_fact("a", t);
|
2013-07-30 07:25:19 +00:00
|
|
|
expr a = constant("a");
|
2013-08-05 03:52:14 +00:00
|
|
|
env.add_fact("b", t);
|
2013-07-30 07:25:19 +00:00
|
|
|
expr b = constant("b");
|
2013-08-05 03:52:14 +00:00
|
|
|
env.add_fact("h", arrow(t, t));
|
|
|
|
expr h = constant("h");
|
2013-07-30 07:25:19 +00:00
|
|
|
expr x = var(0);
|
|
|
|
expr y = var(1);
|
2013-07-30 08:39:29 +00:00
|
|
|
lean_assert(normalize(f(x,x), env, extend(context(), name("f"), t, f(a))) == f(f(a), f(a)));
|
|
|
|
context c1 = extend(extend(context(), name("f"), t, f(a)), name("h"), t, h(x));
|
|
|
|
expr F1 = normalize(f(x,f(x)), env, c1);
|
|
|
|
lean_assert(F1 == f(h(f(a)), f(h(f(a)))));
|
|
|
|
std::cout << F1 << "\n";
|
|
|
|
expr F2 = normalize(lambda("x", t, f(x, f(y))), env, c1);
|
|
|
|
std::cout << F2 << "\n";
|
|
|
|
lean_assert(F2 == lambda("x", t, f(x, f(h(f(a))))));
|
|
|
|
expr F3 = normalize(lambda("y", t, lambda("x", t, f(x, f(y)))), env, c1);
|
|
|
|
std::cout << F3 << "\n";
|
|
|
|
lean_assert(F3 == lambda("y", t, lambda("x", t, f(x, f(y)))));
|
|
|
|
context c2 = extend(extend(context(), name("foo"), t, lambda("x", t, f(x, a))), name("bla"), t, lambda("z", t, h(x,y)));
|
|
|
|
expr F4 = normalize(lambda("x", t, f(x, f(y))), env, c2);
|
|
|
|
std::cout << F4 << "\n";
|
|
|
|
lean_assert(F4 == lambda("x", t, f(x, f(lambda("z", t, h(x,lambda("x", t, f(x, a))))))));
|
|
|
|
context c3 = extend(context(), name("x"), t);
|
|
|
|
expr f5 = app(lambda("f", t, lambda("z", t, var(1))), lambda("y", t, var(1)));
|
|
|
|
expr F5 = normalize(f5, env, c3);
|
|
|
|
std::cout << f5 << "\n---->\n";
|
|
|
|
std::cout << F5 << "\n";
|
|
|
|
lean_assert(F5 == lambda("z", t, lambda("y", t, var(2))));
|
|
|
|
context c4 = extend(extend(context(), name("x"), t), name("x2"), t);
|
|
|
|
expr F6 = normalize(app(lambda("f", t, lambda("z1", t, lambda("z2", t, app(var(2), constant("a"))))),
|
|
|
|
lambda("y", t, app(var(1), var(2), var(0)))), env, c4);
|
|
|
|
std::cout << F6 << "\n";
|
|
|
|
lean_assert(F6 == lambda("z1", t, lambda("z2", t, app(var(2), var(3), constant("a")))));
|
2013-07-30 07:25:19 +00:00
|
|
|
}
|
|
|
|
|
2013-08-04 16:37:52 +00:00
|
|
|
static void tst3() {
|
|
|
|
environment env;
|
2013-08-05 03:52:14 +00:00
|
|
|
env.add_fact("a", bool_type());
|
2013-08-04 16:37:52 +00:00
|
|
|
expr t1 = constant("a");
|
|
|
|
expr t2 = constant("a");
|
|
|
|
expr e = eq(t1, t2);
|
|
|
|
std::cout << e << " --> " << normalize(e, env) << "\n";
|
|
|
|
lean_assert(normalize(e, env) == bool_value(true));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void tst4() {
|
|
|
|
environment env;
|
2013-08-05 03:52:14 +00:00
|
|
|
env.add_fact("b", type(level()));
|
2013-08-04 16:37:52 +00:00
|
|
|
expr t1 = let("a", constant("b"), lambda("c", type(), var(1)(var(0))));
|
|
|
|
std::cout << t1 << " --> " << normalize(t1, env) << "\n";
|
|
|
|
lean_assert(normalize(t1, env) == lambda("c", type(), constant("b")(var(0))));
|
|
|
|
}
|
|
|
|
|
2013-07-25 02:36:54 +00:00
|
|
|
int main() {
|
2013-08-05 03:52:14 +00:00
|
|
|
// continue_on_violation(true);
|
2013-07-26 02:13:45 +00:00
|
|
|
tst_church_numbers();
|
2013-07-30 07:25:19 +00:00
|
|
|
tst1();
|
|
|
|
tst2();
|
2013-08-04 16:37:52 +00:00
|
|
|
tst3();
|
|
|
|
tst4();
|
2013-07-25 02:36:54 +00:00
|
|
|
return has_violations() ? 1 : 0;
|
|
|
|
}
|