Add basic semantic attachments for arithmetic
Signed-off-by: Leonardo de Moura <leonardo@microsoft.com>
This commit is contained in:
parent
15a4152ce8
commit
b979436c40
9 changed files with 253 additions and 3 deletions
|
@ -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")
|
||||
|
|
2
src/kernel/arith/CMakeLists.txt
Normal file
2
src/kernel/arith/CMakeLists.txt
Normal 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
116
src/kernel/arith/arith.cpp
Normal 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
29
src/kernel/arith/arith.h
Normal 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);
|
||||
}
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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); }
|
||||
|
|
|
@ -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()));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
84
src/tests/kernel/arith.cpp
Normal file
84
src/tests/kernel/arith.cpp
Normal 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;
|
||||
}
|
Loading…
Reference in a new issue