Add basic semantic attachments for arithmetic

Signed-off-by: Leonardo de Moura <leonardo@microsoft.com>
This commit is contained in:
Leonardo de Moura 2013-08-03 19:57:06 -07:00
parent 15a4152ce8
commit b979436c40
9 changed files with 253 additions and 3 deletions

View file

@ -50,6 +50,7 @@ include_directories(${LEAN_SOURCE_DIR}/util/numerics)
include_directories(${LEAN_SOURCE_DIR}/util/sexpr)
include_directories(${LEAN_SOURCE_DIR}/interval)
include_directories(${LEAN_SOURCE_DIR}/kernel)
include_directories(${LEAN_SOURCE_DIR}/kernel/arith)
include_directories(${LEAN_SOURCE_DIR}/parsers)
add_subdirectory(util)
@ -62,6 +63,8 @@ add_subdirectory(interval)
set(EXTRA_LIBS ${EXTRA_LIBS} interval)
add_subdirectory(kernel)
set(EXTRA_LIBS ${EXTRA_LIBS} kernel)
add_subdirectory(kernel/arith)
set(EXTRA_LIBS ${EXTRA_LIBS} kernel_arith)
add_subdirectory(parsers)
set(EXTRA_LIBS ${EXTRA_LIBS} parser_common)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -pthread")

View file

@ -0,0 +1,2 @@
add_library(kernel_arith arith.cpp)
target_link_libraries(kernel_arith ${EXTRA_LIBS})

116
src/kernel/arith/arith.cpp Normal file
View file

@ -0,0 +1,116 @@
/*
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 "arith.h"
namespace lean {
class int_type_value : public value {
public:
static char const * g_kind;
virtual ~int_type_value() {}
char const * kind() const { return g_kind; }
virtual expr get_type() const { return type(level()); }
virtual bool normalize(unsigned num_args, expr const * args, expr & r) const { return false; }
virtual bool operator==(value const & other) const { return other.kind() == kind(); }
virtual void display(std::ostream & out) const { out << "int"; }
virtual format pp() const { return format("int"); }
virtual unsigned hash() const { return 41; }
};
char const * int_type_value::g_kind = "int";
expr int_type() {
static thread_local expr r;
if (!r)
r = to_expr(*(new int_type_value()));
return r;
}
bool is_int_type(expr const & e) {
return is_value(e) && to_value(e).kind() == int_type_value::g_kind;
}
class int_value_value : public value {
mpz m_val;
public:
static char const * g_kind;
int_value_value(mpz const & v):m_val(v) {}
virtual ~int_value_value() {}
char const * kind() const { return g_kind; }
virtual expr get_type() const { return int_type(); }
virtual bool normalize(unsigned num_args, expr const * args, expr & r) const { return false; }
virtual bool operator==(value const & other) const {
return other.kind() == kind() && m_val == static_cast<int_value_value const &>(other).m_val;
}
virtual void display(std::ostream & out) const { out << m_val; }
virtual format pp() const { return format(m_val); }
virtual unsigned hash() const { return m_val.hash(); }
mpz const & get_num() const { return m_val; }
};
char const * int_value_value::g_kind = "int_num";
expr int_value(mpz const & v) {
return to_expr(*(new int_value_value(v)));
}
bool is_int_value(expr const & e) {
return is_value(e) && to_value(e).kind() == int_value_value::g_kind;
}
mpz const & int_value_numeral(expr const & e) {
lean_assert(is_int_value(e));
return static_cast<int_value_value const &>(to_value(e)).get_num();
}
template<char const * Name, unsigned Hash, typename F>
class int_bin_op : public value {
public:
static char const * g_kind;
virtual ~int_bin_op() {}
char const * kind() const { return g_kind; }
virtual expr get_type() const {
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 normalize(unsigned num_args, expr const * args, expr & r) const {
if (num_args == 3 && is_int_value(args[1]) && is_int_value(args[2])) {
r = int_value(F()(int_value_numeral(args[1]), int_value_numeral(args[2])));
return true;
} else {
return false;
}
}
virtual void display(std::ostream & out) const { out << Name; }
virtual format pp() const { return format(Name); }
virtual unsigned hash() const { return Hash; }
};
template<char const * Name, unsigned Hash, typename F> char const * int_bin_op<Name, Hash, F>::g_kind = Name;
constexpr char int_add_name[] = "+";
struct int_add_eval { mpz operator()(mpz const & v1, mpz const & v2) { return v1 + v2; }; };
typedef int_bin_op<int_add_name, 43, int_add_eval> int_add_value;
expr int_add() { return to_expr(*(new int_add_value())); }
bool is_int_add(expr const & e) { return is_value(e) && to_value(e).kind() == int_add_value::g_kind; }
constexpr char int_sub_name[] = "-";
struct int_sub_eval { mpz operator()(mpz const & v1, mpz const & v2) { return v1 - v2; }; };
typedef int_bin_op<int_sub_name, 43, int_sub_eval> int_sub_value;
expr int_sub() { return to_expr(*(new int_sub_value())); }
bool is_int_sub(expr const & e) { return is_value(e) && to_value(e).kind() == int_sub_value::g_kind; }
constexpr char int_mul_name[] = "*";
struct int_mul_eval { mpz operator()(mpz const & v1, mpz const & v2) { return v1 * v2; }; };
typedef int_bin_op<int_mul_name, 43, int_mul_eval> int_mul_value;
expr int_mul() { return to_expr(*(new int_mul_value())); }
bool is_int_mul(expr const & e) { return is_value(e) && to_value(e).kind() == int_mul_value::g_kind; }
}

29
src/kernel/arith/arith.h Normal file
View file

@ -0,0 +1,29 @@
/*
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 "expr.h"
#include "mpz.h"
#include "mpq.h"
namespace lean {
expr int_type();
bool is_int_type(expr const & e);
expr int_value(mpz const & v);
inline expr int_value(int v) { return int_value(mpz(v)); }
bool is_int_value(expr const & e);
mpz const & int_value_numeral(expr const & e);
expr int_add();
bool is_int_add(expr const & e);
expr int_sub();
bool is_int_sub(expr const & e);
expr int_mul();
bool is_int_mul(expr const & e);
}

View file

@ -111,6 +111,13 @@ void expr_cell::dealloc() {
}
}
expr type() {
static thread_local expr r;
if (!r)
r = type(level());
return r;
}
class eq_fn {
expr_cell_pair_set m_eq_visited;

View file

@ -179,7 +179,7 @@ public:
virtual ~value() {}
virtual char const * kind() const = 0;
virtual expr get_type() const = 0;
virtual expr normalize(unsigned num_args, expr const * args) const = 0;
virtual bool normalize(unsigned num_args, expr const * args, expr & r) const = 0;
virtual bool operator==(value const & other) const = 0;
virtual void display(std::ostream & out) const = 0;
virtual format pp() const = 0;
@ -237,6 +237,7 @@ inline expr pi(name const & n, expr const & t, expr const & e) { return expr(new
inline expr pi(char const * n, expr const & t, expr const & e) { return pi(name(n), t, e); }
inline expr arrow(expr const & t, expr const & e) { return pi(name("_"), t, e); }
inline expr type(level const & l) { return expr(new expr_type(l)); }
expr type();
inline expr expr::operator()(expr const & a1) const { return app(*this, a1); }
inline expr expr::operator()(expr const & a1, expr const & a2) const { return app(*this, a1, a2); }

View file

@ -149,11 +149,16 @@ class normalize_fn {
i++;
}
else {
// TODO: support for interpreted symbols
buffer<expr> new_args;
new_args.push_back(reify(f, k));
expr new_f = reify(f, k);
new_args.push_back(new_f);
for (; i < n; i++)
new_args.push_back(reify(normalize(arg(a, i), s, k), k));
if (is_value(new_f)) {
expr r;
if (to_value(new_f).normalize(new_args.size(), new_args.data(), r))
return svalue(r);
}
return svalue(app(new_args.size(), new_args.data()));
}
}

View file

@ -19,3 +19,6 @@ add_test(replace ${CMAKE_CURRENT_BINARY_DIR}/replace)
add_executable(type_check type_check.cpp)
target_link_libraries(type_check ${EXTRA_LIBS})
add_test(type_check ${CMAKE_CURRENT_BINARY_DIR}/type_check)
add_executable(arith arith.cpp)
target_link_libraries(arith ${EXTRA_LIBS})
add_test(arith ${CMAKE_CURRENT_BINARY_DIR}/arith)

View file

@ -0,0 +1,84 @@
/*
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 "environment.h"
#include "type_check.h"
#include "arith.h"
#include "normalize.h"
#include "abstract.h"
#include "test.h"
using namespace lean;
static void tst1() {
environment env;
expr e = int_value(mpz(10));
lean_assert(is_int_value(e));
lean_assert(infer_type(e, env) == int_type());
std::cout << "e: " << e << "\n";
}
static void tst2() {
environment env;
expr e = app(int_add(), int_value(10), int_value(30));
std::cout << e << "\n";
std::cout << normalize(e, env) << "\n";
lean_assert(normalize(e, env) == int_value(40));
std::cout << infer_type(int_add(), env) << "\n";
lean_assert(infer_type(e, env) == int_type());
lean_assert(infer_type(app(int_add(), int_value(10)), env) == arrow(int_type(), int_type()));
lean_assert(is_int_add(int_add()));
lean_assert(!is_int_add(int_mul()));
lean_assert(is_int_value(normalize(e, env)));
expr e2 = fun("a", int_type(), app(int_add(), constant("a"), app(int_add(), int_value(10), int_value(30))));
std::cout << e2 << " --> " << normalize(e2, env) << "\n";
lean_assert(infer_type(e2, env) == arrow(int_type(), int_type()));
lean_assert(normalize(e2, env) == fun("a", int_type(), app(int_add(), constant("a"), int_value(40))));
}
static void tst3() {
environment env;
expr e = app(int_mul(), int_value(10), int_value(30));
std::cout << e << "\n";
std::cout << normalize(e, env) << "\n";
lean_assert(normalize(e, env) == int_value(300));
std::cout << infer_type(int_mul(), env) << "\n";
lean_assert(infer_type(e, env) == int_type());
lean_assert(infer_type(app(int_mul(), int_value(10)), env) == arrow(int_type(), int_type()));
lean_assert(is_int_mul(int_mul()));
lean_assert(!is_int_mul(int_add()));
lean_assert(is_int_value(normalize(e, env)));
expr e2 = fun("a", int_type(), app(int_mul(), constant("a"), app(int_mul(), int_value(10), int_value(30))));
std::cout << e2 << " --> " << normalize(e2, env) << "\n";
lean_assert(infer_type(e2, env) == arrow(int_type(), int_type()));
lean_assert(normalize(e2, env) == fun("a", int_type(), app(int_mul(), constant("a"), int_value(300))));
}
static void tst4() {
environment env;
expr e = app(int_sub(), int_value(10), int_value(30));
std::cout << e << "\n";
std::cout << normalize(e, env) << "\n";
lean_assert(normalize(e, env) == int_value(-20));
std::cout << infer_type(int_sub(), env) << "\n";
lean_assert(infer_type(e, env) == int_type());
lean_assert(infer_type(app(int_sub(), int_value(10)), env) == arrow(int_type(), int_type()));
lean_assert(is_int_sub(int_sub()));
lean_assert(!is_int_sub(int_add()));
lean_assert(is_int_value(normalize(e, env)));
expr e2 = fun("a", int_type(), app(int_sub(), constant("a"), app(int_sub(), int_value(10), int_value(30))));
std::cout << e2 << " --> " << normalize(e2, env) << "\n";
lean_assert(infer_type(e2, env) == arrow(int_type(), int_type()));
lean_assert(normalize(e2, env) == fun("a", int_type(), app(int_sub(), constant("a"), int_value(-20))));
}
int main() {
continue_on_violation(true);
tst1();
tst2();
tst3();
tst4();
return has_violations() ? 1 : 0;
}