Add basic definitions and axioms

Signed-off-by: Leonardo de Moura <leonardo@microsoft.com>
This commit is contained in:
Leonardo de Moura 2013-08-05 20:06:07 -07:00
parent 8aee11e538
commit 30513398bb
15 changed files with 433 additions and 79 deletions

View file

@ -1,4 +1,4 @@
add_library(kernel expr.cpp max_sharing.cpp free_vars.cpp abstract.cpp add_library(kernel expr.cpp max_sharing.cpp free_vars.cpp abstract.cpp
instantiate.cpp deep_copy.cpp normalize.cpp level.cpp environment.cpp instantiate.cpp deep_copy.cpp normalize.cpp level.cpp environment.cpp
type_check.cpp context.cpp builtin.cpp) type_check.cpp context.cpp builtin.cpp toplevel.cpp)
target_link_libraries(kernel ${EXTRA_LIBS}) target_link_libraries(kernel ${EXTRA_LIBS})

View file

@ -33,9 +33,11 @@ inline expr abstract_p(expr const & e, expr const & s) { return abstract_p(e, 1,
*/ */
inline expr fun(name const & n, expr const & t, expr const & b) { return lambda(n, t, abstract(b, constant(n))); } inline expr fun(name const & n, expr const & t, expr const & b) { return lambda(n, t, abstract(b, constant(n))); }
inline expr fun(char const * n, expr const & t, expr const & b) { return fun(name(n), t, b); } inline expr fun(char const * n, expr const & t, expr const & b) { return fun(name(n), t, b); }
inline expr fun(expr const & n, expr const & t, expr const & b) { return lambda(const_name(n), t, abstract(b, n)); }
/** /**
\brief Create a Pi expression (pi (x : t) b), the term b is abstracted using abstract(b, constant(x)). \brief Create a Pi expression (pi (x : t) b), the term b is abstracted using abstract(b, constant(x)).
*/ */
inline expr Fun(name const & n, expr const & t, expr const & b) { return pi(n, t, abstract(b, constant(n))); } inline expr Fun(name const & n, expr const & t, expr const & b) { return pi(n, t, abstract(b, constant(n))); }
inline expr Fun(char const * n, expr const & t, expr const & b) { return Fun(name(n), t, b); } inline expr Fun(char const * n, expr const & t, expr const & b) { return Fun(name(n), t, b); }
inline expr Fun(expr const & n, expr const & t, expr const & b) { return pi(const_name(n), t, abstract(b, n)); }
} }

View file

@ -62,16 +62,15 @@ mpz const & int_value_numeral(expr const & e) {
template<char const * Name, unsigned Hash, typename F> template<char const * Name, unsigned Hash, typename F>
class int_bin_op : public value { class int_bin_op : public value {
expr m_type;
public: public:
static char const * g_kind; static char const * g_kind;
int_bin_op() {
m_type = arrow(int_type(), arrow(int_type(), int_type()));
}
virtual ~int_bin_op() {} virtual ~int_bin_op() {}
char const * kind() const { return g_kind; } char const * kind() const { return g_kind; }
virtual expr get_type() const { virtual expr get_type() const { return m_type; }
static thread_local expr r;
if (!r)
r = arrow(int_type(), arrow(int_type(), int_type()));
return r;
}
virtual bool operator==(value const & other) const { return other.kind() == kind(); } virtual bool operator==(value const & other) const { return other.kind() == kind(); }
virtual bool normalize(unsigned num_args, expr const * args, expr & r) const { virtual bool normalize(unsigned num_args, expr const * args, expr & r) const {
if (num_args == 3 && is_int_value(args[1]) && is_int_value(args[2])) { if (num_args == 3 && is_int_value(args[1]) && is_int_value(args[2])) {
@ -109,16 +108,15 @@ typedef int_bin_op<int_div_name, 61, int_div_eval> int_div_value;
MK_BUILTIN(int_div, int_div_value); MK_BUILTIN(int_div, int_div_value);
class int_leq_value : public value { class int_leq_value : public value {
expr m_type;
public: public:
static char const * g_kind; static char const * g_kind;
int_leq_value() {
m_type = arrow(int_type(), arrow(int_type(), bool_type()));
}
virtual ~int_leq_value() {} virtual ~int_leq_value() {}
char const * kind() const { return g_kind; } char const * kind() const { return g_kind; }
virtual expr get_type() const { virtual expr get_type() const { return m_type; }
static thread_local expr r;
if (!r)
r = arrow(int_type(), arrow(int_type(), bool_type()));
return r;
}
virtual bool operator==(value const & other) const { return other.kind() == kind(); } virtual bool operator==(value const & other) const { return other.kind() == kind(); }
virtual bool normalize(unsigned num_args, expr const * args, expr & r) const { virtual bool normalize(unsigned num_args, expr const * args, expr & r) const {
if (num_args == 3 && is_int_value(args[1]) && is_int_value(args[2])) { if (num_args == 3 && is_int_value(args[1]) && is_int_value(args[2])) {
@ -141,7 +139,6 @@ MK_CONSTANT(int_gt, name(name("int"), "gt"));
void add_int_theory(environment & env) { void add_int_theory(environment & env) {
expr p = arrow(int_type(), arrow(int_type(), bool_type())); expr p = arrow(int_type(), arrow(int_type(), bool_type()));
env.add_definition(int_geq_name_obj, p, lambda("x", int_type(), lambda("y", int_type(), app(int_leq(), var(0), var(1))))); env.add_definition(int_geq_name, p, lambda("x", int_type(), lambda("y", int_type(), app(int_leq(), var(0), var(1)))));
} }
} }

View file

@ -6,9 +6,32 @@ Author: Leonardo de Moura
*/ */
#include "builtin.h" #include "builtin.h"
#include "environment.h" #include "environment.h"
#include "abstract.h"
#ifndef LEAN_DEFAULT_LEVEL_SEPARATION
#define LEAN_DEFAULT_LEVEL_SEPARATION 512
#endif
namespace lean { namespace lean {
expr mk_bin_op(expr const & op, expr const & unit, unsigned num_args, expr const * args) {
if (num_args == 0) {
return unit;
} else {
expr r = args[num_args - 1];
unsigned i = num_args - 1;
while (i > 0) {
--i;
r = app(op, args[i], r);
}
return r;
}
}
expr mk_bin_op(expr const & op, expr const & unit, std::initializer_list<expr> const & l) {
return mk_bin_op(op, unit, l.size(), l.begin());
}
class bool_type_value : public value { class bool_type_value : public value {
public: public:
static char const * g_kind; static char const * g_kind;
@ -47,7 +70,9 @@ public:
char const * bool_value_value::g_kind = "bool_value"; char const * bool_value_value::g_kind = "bool_value";
expr bool_value(bool v) { expr bool_value(bool v) {
return to_expr(*(new bool_value_value(v))); static thread_local expr true_val = to_expr(*(new bool_value_value(true)));
static thread_local expr false_val = to_expr(*(new bool_value_value(false)));
return v ? true_val : false_val;
} }
bool is_bool_value(expr const & e) { bool is_bool_value(expr const & e) {
@ -67,6 +92,129 @@ bool is_false(expr const & e) {
return is_bool_value(e) && !to_bool(e); return is_bool_value(e) && !to_bool(e);
} }
static level m_lvl(name("m"));
static level u_lvl(name("u"));
expr m_type() {
static thread_local expr r = type(m_lvl);
return r;
}
expr u_type() {
static thread_local expr r = type(u_lvl);
return r;
}
class if_fn_value : public value {
expr m_type;
public:
static char const * g_kind;
if_fn_value() {
expr A = constant("A");
// Pi (A: Type), bool -> A -> A -> A
m_type = Fun("A", u_type(), arrow(bool_type(), arrow(A, arrow(A, A))));
}
virtual ~if_fn_value() {}
char const * kind() const { return g_kind; }
virtual expr get_type() const { return m_type; }
virtual bool normalize(unsigned num_args, expr const * args, expr & r) const {
if (num_args == 5 && is_bool_value(args[2])) {
if (to_bool(args[2]))
r = args[3]; // if A true a b --> a
else
r = args[4]; // if A false a b --> b
return true;
} if (num_args == 5 && args[3] == args[4]) {
r = args[3]; // if A c a a --> a
return true;
} else {
return false;
}
}
virtual bool operator==(value const & other) const { return other.kind() == kind(); }
virtual void display(std::ostream & out) const { out << "if"; }
virtual format pp() const { return format("if"); }
virtual unsigned hash() const { return 23; }
};
char const * if_fn_value::g_kind = "if";
MK_BUILTIN(if_fn, if_fn_value);
MK_CONSTANT(and_fn, name("and"));
MK_CONSTANT(or_fn, name("or"));
MK_CONSTANT(not_fn, name("not"));
MK_CONSTANT(forall_fn, name("forall"));
MK_CONSTANT(exists_fn, name("exists"));
MK_CONSTANT(refl_fn, name("refl"));
MK_CONSTANT(symm_fn, name("symm"));
MK_CONSTANT(trans_fn, name("trans"));
MK_CONSTANT(congr_fn, name("congr"));
MK_CONSTANT(ext_fn, name("ext"));
MK_CONSTANT(foralle_fn, name("foralle"));
MK_CONSTANT(foralli_fn, name("foralli"));
MK_CONSTANT(domain_inj_fn, name("domain_inj"));
MK_CONSTANT(range_inj_fn, name("range_inj"));
void add_basic_theory(environment & env) { void add_basic_theory(environment & env) {
env.define_uvar(uvar_name(m_lvl), level() + LEAN_DEFAULT_LEVEL_SEPARATION);
env.define_uvar(uvar_name(u_lvl), m_lvl + LEAN_DEFAULT_LEVEL_SEPARATION);
expr p1 = arrow(bool_type(), bool_type());
expr p2 = arrow(bool_type(), p1);
expr A = constant("A");
expr a = constant("a");
expr b = constant("b");
expr c = constant("a");
expr H = constant("H");
expr H1 = constant("H1");
expr H2 = constant("H2");
expr B = constant("B");
expr f = constant("f");
expr g = constant("g");
expr x = constant("x");
expr y = constant("y");
expr P = constant("P");
expr A1 = constant("A1");
expr B1 = constant("B1");
expr a1 = constant("a1");
// and(x, y) = (if bool x y false)
env.add_definition(and_fn_name, p2, fun(x, bool_type(), fun(y, bool_type(), mk_bool_if(x, y, bool_value(false)))));
// or(x, y) = (if bool x true y)
env.add_definition(or_fn_name, p2, fun(x, bool_type(), fun(y, bool_type(), mk_bool_if(x, bool_value(true), y))));
// not(x) = (if bool x false true)
env.add_definition(not_fn_name, p1, fun(x, bool_type(), mk_bool_if(x, bool_value(false), bool_value(true))));
// forall : Pi (A : Type u), (A -> Bool) -> Bool
expr A_pred = arrow(A, bool_type());
expr q_type = Fun(A, u_type(), arrow(A_pred, bool_type()));
env.add_var(forall_fn_name, q_type);
env.add_definition(exists_fn_name, q_type, fun(A, u_type(), fun(P, A_pred, mk_not(mk_forall(A, fun(x, A, mk_not(P(x))))))));
// refl : Pi (A : Type u) (a : A), a = a
env.add_axiom(refl_fn_name, Fun(A, u_type(), Fun(a, A, eq(a, a))));
// symm : Pi (A : Type u) (a b : A) (H : a = b), b = a
env.add_axiom(symm_fn_name, Fun(A, u_type(), Fun(a, A, Fun(b, A, Fun(H, eq(a, b), eq(b, a))))));
// trans: Pi (A: Type u) (a b c : A) (H1 : a = b) (H2 : b = c), a = c
env.add_axiom(trans_fn_name, Fun(A, u_type(), Fun(a, A, Fun(b, A, Fun(c, A, Fun(H1, eq(a, b), Fun(H2, eq(b, c), eq(a, c))))))));
// congr : Pi (A : Type u) (B : A -> Type u) (f g : Pi (x : A) B x) (a b : A) (H1 : f = g) (H2 : a = b), f a = g b
expr piABx = Fun(x, A, B(x));
expr A_arrow_u = arrow(A, u_type());
env.add_axiom(congr_fn_name, Fun(A, u_type(), Fun(B, A_arrow_u, Fun(f, piABx, Fun(g, piABx, Fun(a, A, Fun(b, A, Fun(H1, eq(f, g), Fun(H2, eq(a, b), eq(f(a), g(b)))))))))));
// ext : Pi (A : Type u) (B : A -> Type u) (f g : Pi (x : A) B x) (H : Pi x : A, (f x) = (g x)), f = g
env.add_axiom(ext_fn_name, Fun(A, u_type(), Fun(B, A_arrow_u, Fun(f, piABx, Fun(g, piABx, Fun(H, Fun(x, A, eq(f(x), g(x))), eq(f, g)))))));
// foralle : Pi (A : Type u) (P : A -> bool) (H : (forall A P)) (a : A), P a
env.add_axiom(foralle_fn_name, Fun(A, u_type(), Fun(P, A_pred, Fun(H, mk_forall(A, P), Fun(a, A, P(a))))));
// foralli : Pi (A : Type u) (P : A -> bool) (H : Pi (x : A), P x), (forall A P)
env.add_axiom(foralli_fn_name, Fun(A, u_type(), Fun(P, A_pred, Fun(H, Fun(x, A, P(x)), mk_forall(A, P)))));
// domain_inj : Pi (A A1: Type u) (B : A -> Type u) (B1 : A1 -> Type u) (H : (Pi (x : A), B x) = (Pi (x : A1), B1 x)), A = A1
expr piA1B1x = Fun(x, A1, B1(x));
env.add_axiom(domain_inj_fn_name, Fun(A, u_type(), Fun(A1, u_type(), Fun(B, A_arrow_u, Fun(B1, arrow(A1, u_type()), Fun(H, eq(piABx, piA1B1x), eq(A, A1)))))));
// range_inj : Pi (A A1: Type u) (B : A -> Type u) (B1 : A1 -> Type u) (a : A) (a1 : A1) (H : (Pi (x : A), B x) = (Pi (x : A1), B1 x)), (B a) = (B1 a1)
env.add_axiom(range_inj_fn_name, Fun(A, u_type(), Fun(A1, u_type(), Fun(B, A_arrow_u, Fun(B1, arrow(A1, u_type()), Fun(a, A, Fun(a1, A1, Fun(H, eq(piABx, piA1B1x), eq(B(a), B1(a1))))))))));
} }
} }

View file

@ -8,16 +8,109 @@ Author: Leonardo de Moura
#include "expr.h" #include "expr.h"
namespace lean { namespace lean {
/**
\brief Return unit if <tt>num_args == 0<\tt>, args[0] if <tt>num_args == 1<\tt>, and
<tt>(op args[0] (op args[1] (op ... )))<\tt>
*/
expr mk_bin_op(expr const & op, expr const & unit, unsigned num_args, expr const * args);
expr mk_bin_op(expr const & op, expr const & unit, std::initializer_list<expr> const & l);
/** \brief Return (Type m) m >= bottom + Offset */
expr m_type();
/** \brief Return (Type u) u >= m + Offset */
expr u_type();
/** \brief Return the Lean Boolean type. */
expr bool_type(); expr bool_type();
/** \brief Return true iff \c e is the Lean Boolean type. */
bool is_bool_type(expr const & e); bool is_bool_type(expr const & e);
/** \brief Create a Lean Boolean value (true/false) */
expr bool_value(bool v); expr bool_value(bool v);
/** \brief Return true iff \c e is a Lean Boolean value. */
bool is_bool_value(expr const & e); bool is_bool_value(expr const & e);
/**
\brief Convert a Lean Boolean value into a C++ Boolean value.
\pre is_bool_value(e)
*/
bool to_bool(expr const & e); bool to_bool(expr const & e);
/** \brief Return true iff \c e is the Lean true value. */
bool is_true(expr const & e); bool is_true(expr const & e);
/** \brief Return true iff \c e is the Lean false value. */
bool is_false(expr const & e); bool is_false(expr const & e);
/** \brief Return the Lean If-Then-Else operator. It has type: pi (A : Type), bool -> A -> A -> A */
expr if_fn();
/** \brief Return true iff \c e is the Lean If-Then-Else operator */
bool is_if_fn(expr const & e);
/** \brief Return the term (if A c t e) */
inline expr mk_if(expr const & A, expr const & c, expr const & t, expr const & e) { return app(if_fn(), A, c, t, e); }
/** \brief Return the term (if bool c t e) */
inline expr mk_bool_if(expr const & c, expr const & t, expr const & e) { return mk_if(bool_type(), c, t, e); }
/** \brief Return the Lean and operator */
expr and_fn();
/** \brief Return true iff \c e is the Lean and operator. */
bool is_and_fn(expr const & e);
/** \brief Return (and e1 e2) */
inline expr mk_and(expr const & e1, expr const & e2) { return app(and_fn(), e1, e2); }
inline expr mk_and(unsigned num_args, expr const * args) { return mk_bin_op(and_fn(), bool_value(true), num_args, args); }
inline expr mk_and(std::initializer_list<expr> const & l) { return mk_bin_op(and_fn(), bool_value(true), l); }
/** \brief Return the Lean or operator */
expr or_fn();
bool is_or_fn(expr const & e);
/** \brief Return (or e1 e2) */
inline expr mk_or(expr const & e1, expr const & e2) { return app(or_fn(), e1, e2); }
inline expr mk_or(unsigned num_args, expr const * args) { return mk_bin_op(or_fn(), bool_value(false), num_args, args); }
inline expr mk_or(std::initializer_list<expr> const & l) { return mk_bin_op(or_fn(), bool_value(false), l); }
/** \brief Return the Lean not operator */
expr not_fn();
bool is_not_fn(expr const & e);
/** \brief Return (not e) */
inline expr mk_not(expr const & e) { return app(not_fn(), e); }
/** \brief Return the Lean forall operator. It has type: <tt>Pi (A : Type), (A -> bool) -> Bool<\tt> */
expr forall_fn();
/** \brief Return true iff \c e is the Lean forall operator */
bool is_forall_fn(expr const & e);
/** \brief Return the term (forall A P), where A is a type and P : A -> bool */
inline expr mk_forall(expr const & A, expr const & P) { return app(forall_fn(), A, P); }
/** \brief Return the Lean exists operator. It has type: <tt>Pi (A : Type), (A -> Bool) -> Bool<\tt> */
expr exists_fn();
/** \brief Return true iff \c e is the Lean exists operator */
bool is_exists_fn(expr const & e);
/** \brief Return the term (exists A P), where A is a type and P : A -> bool */
inline expr mk_exists(expr const & A, expr const & P) { return app(exists_fn(), A, P); }
expr refl_fn();
bool is_refl_fn(expr const & e);
expr symm_fn();
bool is_symm_fn(expr const & e);
expr trans_fn();
bool is_trans_fn(expr const & e);
expr congr_fn();
bool is_congr_fn(expr const & e);
expr ext_fn();
bool is_ext_fn(expr const & e);
expr foralle_fn();
bool is_foralle_fn(expr const & e);
expr foralli_fn();
bool is_foralli_fn(expr const & e);
expr domain_inj_fn();
bool is_domain_inj_fn(expr const & e);
expr range_inj_fn();
bool is_range_inj_fn(expr const & e);
class environment; class environment;
/** \brief Initialize the environment with basic builtin declarations and axioms */
void add_basic_theory(environment & env); void add_basic_theory(environment & env);
/** /**
@ -25,9 +118,7 @@ void add_basic_theory(environment & env);
*/ */
#define MK_BUILTIN(Name, ClassName) \ #define MK_BUILTIN(Name, ClassName) \
expr Name() { \ expr Name() { \
static thread_local expr r; \ static thread_local expr r = to_expr(*(new ClassName())); \
if (!r) \
r = to_expr(*(new ClassName())); \
return r; \ return r; \
} \ } \
bool is_##Name(expr const & e) { \ bool is_##Name(expr const & e) { \
@ -37,16 +128,13 @@ bool is_##Name(expr const & e) { \
/** /**
\brief Helper macro for generating "defined" constants. \brief Helper macro for generating "defined" constants.
*/ */
#define MK_CONSTANT(Name, NameObj) \ #define MK_CONSTANT(Name, NameObj) \
static name Name ## _name_obj = NameObj; \ static name Name ## _name = NameObj; \
expr Name() { \ expr Name() { \
static thread_local expr r; \ static thread_local expr r = constant(Name ## _name); \
if (!r) \ return r ; \
r = constant(Name ## _name_obj); \ } \
return r; \ bool is_##Name(expr const & e) { \
} \ return is_constant(e) && const_name(e) == Name ## _name; \
bool is_##Name(expr const & e) { \
return is_constant(e) && const_name(e) == Name ## _name_obj; \
} }
} }

View file

@ -28,10 +28,6 @@ environment::definition::definition(name const & n, expr const & t, expr const &
environment::definition::~definition() { environment::definition::~definition() {
} }
environment::object_kind environment::definition::kind() const {
return object_kind::Definition;
}
void environment::definition::display(std::ostream & out) const { void environment::definition::display(std::ostream & out) const {
out << "Definition " << m_name << " : " << m_type << " := " << m_value << "\n"; out << "Definition " << m_name << " : " << m_type << " := " << m_value << "\n";
} }
@ -44,12 +40,9 @@ environment::fact::fact(name const & n, expr const & t):
environment::fact::~fact() { environment::fact::~fact() {
} }
environment::object_kind environment::fact::kind() const {
return object_kind::Fact;
}
void environment::fact::display(std::ostream & out) const { void environment::fact::display(std::ostream & out) const {
out << "Fact " << m_name << " : " << m_type << "\n"; display_header(out);
out << " " << m_name << " : " << m_type << "\n";
} }
/** \brief Implementation of the Lean environment. */ /** \brief Implementation of the Lean environment. */
@ -196,13 +189,23 @@ struct environment::imp {
} }
} }
void check_add(name const & n) {
check_no_children();
check_name(n);
}
void add_definition(name const & n, expr const & t, expr const & v, bool opaque) { void add_definition(name const & n, expr const & t, expr const & v, bool opaque) {
m_objects.push_back(new definition(n, t, v, opaque)); m_objects.push_back(new definition(n, t, v, opaque));
m_object_dictionary.insert(std::make_pair(n, m_objects.back())); m_object_dictionary.insert(std::make_pair(n, m_objects.back()));
} }
void add_fact(name const & n, expr const & t) { void add_axiom(name const & n, expr const & t) {
m_objects.push_back(new fact(n, t)); m_objects.push_back(new axiom(n, t));
m_object_dictionary.insert(std::make_pair(n, m_objects.back()));
}
void add_var(name const & n, expr const & t) {
m_objects.push_back(new variable(n, t));
m_object_dictionary.insert(std::make_pair(n, m_objects.back())); m_object_dictionary.insert(std::make_pair(n, m_objects.back()));
} }
@ -229,6 +232,20 @@ struct environment::imp {
} }
} }
void display_objects(std::ostream & out) const {
for (object const * obj : m_objects) {
obj->display(out);
}
}
/** \brief Display universal variable constraints and objects stored in this environment and its parents. */
void display(std::ostream & out) const {
if (has_parent())
m_parent->display(out);
display_uvars(out);
display_objects(out);
}
imp(): imp():
m_num_children(0) { m_num_children(0) {
init_uvars(); init_uvars();
@ -311,17 +328,21 @@ void environment::add_definition(name const & n, expr const & t, expr const & v,
} }
void environment::add_definition(name const & n, expr const & v, bool opaque) { void environment::add_definition(name const & n, expr const & v, bool opaque) {
m_imp->check_no_children(); m_imp->check_add(n);
m_imp->check_name(n);
expr v_t = infer_type(v, *this); expr v_t = infer_type(v, *this);
m_imp->add_definition(n, v_t, v, opaque); m_imp->add_definition(n, v_t, v, opaque);
} }
void environment::add_fact(name const & n, expr const & t) { void environment::add_axiom(name const & n, expr const & t) {
m_imp->check_no_children(); m_imp->check_add(n);
m_imp->check_name(n);
infer_universe(t, *this); infer_universe(t, *this);
m_imp->add_fact(n, t); m_imp->add_axiom(n, t);
}
void environment::add_var(name const & n, expr const & t) {
m_imp->check_add(n);
infer_universe(t, *this);
m_imp->add_var(n, t);
} }
environment::object const & environment::get_object(name const & n) const { environment::object const & environment::get_object(name const & n) const {
@ -331,4 +352,12 @@ environment::object const & environment::get_object(name const & n) const {
environment::object const * environment::get_object_ptr(name const & n) const { environment::object const * environment::get_object_ptr(name const & n) const {
return m_imp->get_object_ptr(n); return m_imp->get_object_ptr(n);
} }
void environment::display_objects(std::ostream & out) const {
m_imp->display_objects(out);
}
void environment::display(std::ostream & out) const {
m_imp->display(out);
}
} }

View file

@ -69,7 +69,7 @@ public:
*/ */
environment parent() const; environment parent() const;
enum class object_kind { Definition, Fact }; enum class object_kind { Definition, Var, Axiom };
/** /**
\brief Base class for environment objects \brief Base class for environment objects
@ -95,7 +95,7 @@ public:
public: public:
definition(name const & n, expr const & t, expr const & v, bool opaque); definition(name const & n, expr const & t, expr const & v, bool opaque);
virtual ~definition(); virtual ~definition();
virtual object_kind kind() const; virtual object_kind kind() const { return object_kind::Definition; }
name const & get_name() const { return m_name; } name const & get_name() const { return m_name; }
virtual expr const & get_type() const { return m_type; } virtual expr const & get_type() const { return m_type; }
expr const & get_value() const { return m_value; } expr const & get_value() const { return m_value; }
@ -104,19 +104,36 @@ public:
}; };
class fact : public object { class fact : public object {
protected:
name m_name; name m_name;
expr m_type; expr m_type;
virtual void display_header(std::ostream & out) const = 0;
public: public:
fact(name const & n, expr const & t); fact(name const & n, expr const & t);
virtual ~fact(); virtual ~fact();
virtual object_kind kind() const;
name const & get_name() const { return m_name; } name const & get_name() const { return m_name; }
virtual expr const & get_type() const { return m_type; } virtual expr const & get_type() const { return m_type; }
virtual void display(std::ostream & out) const; virtual void display(std::ostream & out) const;
}; };
class axiom : public fact {
virtual void display_header(std::ostream & out) const { out << "Axiom"; }
public:
axiom(name const & n, expr const & t):fact(n, t) {}
virtual object_kind kind() const { return object_kind::Axiom; }
};
class variable : public fact {
virtual void display_header(std::ostream & out) const { out << "Var"; }
public:
variable(name const & n, expr const & t):fact(n, t) {}
virtual object_kind kind() const { return object_kind::Var; }
};
friend bool is_definition(object const & o) { return o.kind() == object_kind::Definition; } friend bool is_definition(object const & o) { return o.kind() == object_kind::Definition; }
friend bool is_fact(object const & o) { return o.kind() == object_kind::Fact; } friend bool is_axiom(object const & o) { return o.kind() == object_kind::Axiom; }
friend bool is_var(object const & o) { return o.kind() == object_kind::Var; }
friend bool is_fact(object const & o) { return is_axiom(o) || is_var(o); }
friend definition const & to_definition(object const & o) { lean_assert(is_definition(o)); return static_cast<definition const &>(o); } friend definition const & to_definition(object const & o) { lean_assert(is_definition(o)); return static_cast<definition const &>(o); }
friend fact const & to_fact(object const & o) { lean_assert(is_fact(o)); return static_cast<fact const &>(o); } friend fact const & to_fact(object const & o) { lean_assert(is_fact(o)); return static_cast<fact const &>(o); }
@ -139,11 +156,13 @@ public:
void add_definition(char const * n, expr const & v, bool opaque = false) { add_definition(name(n), v, opaque); } void add_definition(char const * n, expr const & v, bool opaque = false) { add_definition(name(n), v, opaque); }
/** /**
\brief Add a new fact to the environment. \brief Add a new fact (Axiom or Fact) to the environment.
It throws an exception if there is already an object with the given name. It throws an exception if there is already an object with the given name.
*/ */
void add_fact(name const & n, expr const & t); void add_axiom(name const & n, expr const & t);
void add_fact(char const * n, expr const & t) { add_fact(name(n), t); } void add_axiom(char const * n, expr const & t) { add_axiom(name(n), t); }
void add_var(name const & n, expr const & t);
void add_var(char const * n, expr const & t) { add_var(name(n), t); }
/** /**
\brief Return the object with the given name. \brief Return the object with the given name.
@ -156,5 +175,12 @@ public:
Return nullptr if there is no object with the given name. Return nullptr if there is no object with the given name.
*/ */
object const * get_object_ptr(name const & n) const; object const * get_object_ptr(name const & n) const;
/** \brief Display all objects stored in the environment */
void display_objects(std::ostream & out) const;
/** \brief Display universal variable constraints and objects stored in this environment and its parents. */
void display(std::ostream & out) const;
}; };
inline std::ostream & operator<<(std::ostream & out, environment const & env) { env.display(out); return out; }
} }

View file

@ -15,6 +15,7 @@ namespace lean {
class has_free_vars_fn { class has_free_vars_fn {
protected: protected:
expr_cell_offset_set m_visited; expr_cell_offset_set m_visited;
bool m_set_closed_flag;
virtual bool process_var(expr const & x, unsigned offset) { virtual bool process_var(expr const & x, unsigned offset) {
return var_idx(x) >= offset; return var_idx(x) >= offset;
@ -62,17 +63,18 @@ protected:
break; break;
} }
if (!result) if (m_set_closed_flag && !result)
e.raw()->set_closed(); e.raw()->set_closed();
return result; return result;
} }
public: public:
has_free_vars_fn(bool s):m_set_closed_flag(s) {}
bool operator()(expr const & e) { return apply(e, 0); } bool operator()(expr const & e) { return apply(e, 0); }
}; };
bool has_free_vars(expr const & e) { bool has_free_vars(expr const & e) {
return has_free_vars_fn()(e); return has_free_vars_fn(true)(e);
} }
/** \brief Functional object for checking whether a kernel expression has a free variable in the range <tt>[low, high)</tt> or not. */ /** \brief Functional object for checking whether a kernel expression has a free variable in the range <tt>[low, high)</tt> or not. */
@ -83,7 +85,10 @@ class has_free_var_in_range_fn : public has_free_vars_fn {
return var_idx(x) >= offset + m_low && var_idx(x) < offset + m_high; return var_idx(x) >= offset + m_low && var_idx(x) < offset + m_high;
} }
public: public:
has_free_var_in_range_fn(unsigned low, unsigned high):m_low(low), m_high(high) { has_free_var_in_range_fn(unsigned low, unsigned high):
has_free_vars_fn(false /* We should not set the closed flag since we are only considering a range of free variables */),
m_low(low),
m_high(high) {
lean_assert(low < high); lean_assert(low < high);
} }
}; };

18
src/kernel/toplevel.cpp Normal file
View file

@ -0,0 +1,18 @@
/*
Copyright (c) 2013 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Author: Leonardo de Moura
*/
#include "toplevel.h"
#include "builtin.h"
#include "arith.h"
namespace lean {
environment mk_toplevel() {
environment r;
add_basic_theory(r);
add_int_theory(r);
return r;
}
}

15
src/kernel/toplevel.h Normal file
View file

@ -0,0 +1,15 @@
/*
Copyright (c) 2013 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Author: Leonardo de Moura
*/
#pragma once
#include "environment.h"
namespace lean {
/**
\brief Create top-level environment with builtin objects.
*/
environment mk_toplevel();
}

View file

@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE.
Author: Leonardo de Moura Author: Leonardo de Moura
*/ */
#include <thread>
#include "environment.h" #include "environment.h"
#include "type_check.h" #include "type_check.h"
#include "builtin.h" #include "builtin.h"
@ -77,13 +78,24 @@ static void tst4() {
static void tst5() { static void tst5() {
environment env; environment env;
env.add_fact(name("a"), int_type()); env.add_var(name("a"), int_type());
expr e = eq(int_value(3), int_value(4)); expr e = eq(int_value(3), int_value(4));
std::cout << e << " --> " << normalize(e, env) << "\n"; std::cout << e << " --> " << normalize(e, env) << "\n";
lean_assert(normalize(e, env) == bool_value(false)); lean_assert(normalize(e, env) == bool_value(false));
lean_assert(normalize(eq(constant("a"), int_value(3)), env) == eq(constant("a"), int_value(3))); lean_assert(normalize(eq(constant("a"), int_value(3)), env) == eq(constant("a"), int_value(3)));
} }
static void tst6() {
std::cout << "tst6\n";
std::cout << int_add().raw() << "\n";
std::cout << int_add().raw() << "\n";
std::thread t1([](){ std::cout << "t1: " << int_add().raw() << "\n"; });
t1.join();
std::thread t2([](){ std::cout << "t2: " << int_add().raw() << "\n"; });
t2.join();
std::cout << int_add().raw() << "\n";
}
int main() { int main() {
continue_on_violation(true); continue_on_violation(true);
tst1(); tst1();
@ -91,5 +103,6 @@ int main() {
tst3(); tst3();
tst4(); tst4();
tst5(); tst5();
tst6();
return has_violations() ? 1 : 0; return has_violations() ? 1 : 0;
} }

View file

@ -6,6 +6,7 @@ Author: Leonardo de Moura
*/ */
#include "environment.h" #include "environment.h"
#include "type_check.h" #include "type_check.h"
#include "toplevel.h"
#include "builtin.h" #include "builtin.h"
#include "arith.h" #include "arith.h"
#include "normalize.h" #include "normalize.h"
@ -98,7 +99,7 @@ static void tst3() {
lean_assert(normalize(constant("c"), c_env) == int_value(3)); lean_assert(normalize(constant("c"), c_env) == int_value(3));
try { try {
expr r = normalize(constant("c"), env); expr r = normalize(constant("c"), env);
lean_assert(r == int_value(3)) lean_assert(r == int_value(3));
lean_unreachable(); lean_unreachable();
} catch (exception const & ex) { } catch (exception const & ex) {
std::cout << "expected error: " << ex.what() << std::endl; std::cout << "expected error: " << ex.what() << std::endl;
@ -133,7 +134,7 @@ static void tst6() {
environment env; environment env;
level u = env.define_uvar("u", level() + 1); level u = env.define_uvar("u", level() + 1);
level w = env.define_uvar("w", u + 1); level w = env.define_uvar("w", u + 1);
env.add_fact("f", arrow(type(u), type(u))); env.add_var("f", arrow(type(u), type(u)));
expr t = app(constant("f"), int_type()); expr t = app(constant("f"), int_type());
std::cout << "type of " << t << " is " << infer_type(t, env) << "\n"; std::cout << "type of " << t << " is " << infer_type(t, env) << "\n";
try { try {
@ -156,6 +157,16 @@ static void tst6() {
lean_assert(infer_type(arrow(int_type(), int_type()), env) == type()); lean_assert(infer_type(arrow(int_type(), int_type()), env) == type());
} }
static void tst7() {
environment env = mk_toplevel();
env.add_var("a", int_type());
env.add_var("b", int_type());
expr t = app(if_fn(), int_type(), bool_value(true), constant("a"), constant("b"));
std::cout << t << " --> " << normalize(t, env) << "\n";
std::cout << infer_type(t, env) << "\n";
std::cout << "Environment\n" << env;
}
int main() { int main() {
enable_trace("is_convertible"); enable_trace("is_convertible");
continue_on_violation(true); continue_on_violation(true);
@ -165,5 +176,6 @@ int main() {
tst4(); tst4();
tst5(); tst5();
tst6(); tst6();
tst7();
return has_violations() ? 1 : 0; return has_violations() ? 1 : 0;
} }

View file

@ -80,10 +80,10 @@ unsigned count(expr const & a) {
static void tst_church_numbers() { static void tst_church_numbers() {
environment env; environment env;
env.add_fact("t", type(level())); env.add_var("t", type(level()));
env.add_fact("N", type(level())); env.add_var("N", type(level()));
env.add_fact("z", constant("N")); env.add_var("z", constant("N"));
env.add_fact("s", constant("N")); env.add_var("s", constant("N"));
expr N = constant("N"); expr N = constant("N");
expr z = constant("z"); expr z = constant("z");
expr s = constant("s"); expr s = constant("s");
@ -112,13 +112,13 @@ static void tst_church_numbers() {
static void tst1() { static void tst1() {
environment env; environment env;
env.add_fact("t", type(level())); env.add_var("t", type(level()));
expr t = type(level()); expr t = type(level());
env.add_fact("f", arrow(t, t)); env.add_var("f", arrow(t, t));
expr f = constant("f"); expr f = constant("f");
env.add_fact("a", t); env.add_var("a", t);
expr a = constant("a"); expr a = constant("a");
env.add_fact("b", t); env.add_var("b", t);
expr b = constant("b"); expr b = constant("b");
expr x = var(0); expr x = var(0);
expr y = var(1); expr y = var(1);
@ -140,13 +140,13 @@ static void tst1() {
static void tst2() { static void tst2() {
environment env; environment env;
expr t = type(level()); expr t = type(level());
env.add_fact("f", arrow(t, t)); env.add_var("f", arrow(t, t));
expr f = constant("f"); expr f = constant("f");
env.add_fact("a", t); env.add_var("a", t);
expr a = constant("a"); expr a = constant("a");
env.add_fact("b", t); env.add_var("b", t);
expr b = constant("b"); expr b = constant("b");
env.add_fact("h", arrow(t, t)); env.add_var("h", arrow(t, t));
expr h = constant("h"); expr h = constant("h");
expr x = var(0); expr x = var(0);
expr y = var(1); expr y = var(1);
@ -180,7 +180,7 @@ static void tst2() {
static void tst3() { static void tst3() {
environment env; environment env;
env.add_fact("a", bool_type()); env.add_var("a", bool_type());
expr t1 = constant("a"); expr t1 = constant("a");
expr t2 = constant("a"); expr t2 = constant("a");
expr e = eq(t1, t2); expr e = eq(t1, t2);
@ -190,7 +190,7 @@ static void tst3() {
static void tst4() { static void tst4() {
environment env; environment env;
env.add_fact("b", type(level())); env.add_var("b", type(level()));
expr t1 = let("a", constant("b"), lambda("c", type(), var(1)(var(0)))); expr t1 = let("a", constant("b"), lambda("c", type(), var(1)(var(0))));
std::cout << t1 << " --> " << normalize(t1, env) << "\n"; std::cout << t1 << " --> " << normalize(t1, env) << "\n";
lean_assert(normalize(t1, env) == lambda("c", type(), constant("b")(var(0)))); lean_assert(normalize(t1, env) == lambda("c", type(), constant("b")(var(0))));

View file

@ -19,10 +19,10 @@ using namespace lean;
expr normalize(expr const & e) { expr normalize(expr const & e) {
environment env; environment env;
env.add_fact("a", int_type()); env.add_var("a", int_type());
env.add_fact("b", int_type()); env.add_var("b", int_type());
env.add_fact("f", arrow(int_type(), arrow(int_type(), int_type()))); env.add_var("f", arrow(int_type(), arrow(int_type(), int_type())));
env.add_fact("h", arrow(int_type(), arrow(int_type(), int_type()))); env.add_var("h", arrow(int_type(), arrow(int_type(), int_type())));
return normalize(e, env); return normalize(e, env);
} }

View file

@ -266,5 +266,6 @@ std::ostream & operator<<(std::ostream & out, name::sep const & s) {
name::imp::display(out, s.m_sep, s.m_name.m_ptr); name::imp::display(out, s.m_sep, s.m_name.m_ptr);
return out; return out;
} }
} }
void pp(lean::name const & n) { std::cout << n << std::endl; }