-
Notifications
You must be signed in to change notification settings - Fork 80
Expand file tree
/
Copy pathexpr_eq_fn.cpp
More file actions
135 lines (124 loc) · 4.59 KB
/
expr_eq_fn.cpp
File metadata and controls
135 lines (124 loc) · 4.59 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
/*
Copyright (c) 2014 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Author: Leonardo de Moura
*/
#include <vector>
#include <memory>
#include "util/interrupt.h"
#include "util/thread.h"
#include "kernel/expr.h"
#include "kernel/expr_sets.h"
#ifndef LEAN_EQ_CACHE_CAPACITY
#define LEAN_EQ_CACHE_CAPACITY 1024*8
#endif
namespace lean {
struct eq_cache {
struct entry {
expr_ptr m_a;
expr_ptr m_b;
entry():m_a(nullptr), m_b(nullptr) {}
};
unsigned m_capacity;
std::vector<entry> m_cache;
std::vector<unsigned> m_used;
eq_cache():m_capacity(LEAN_EQ_CACHE_CAPACITY), m_cache(LEAN_EQ_CACHE_CAPACITY) {}
bool check(expr const & a, expr const & b) {
if (!is_shared(a) || !is_shared(b))
return false;
unsigned i = hash(a.hash(), b.hash()) % m_capacity;
if (m_cache[i].m_a == a.raw() && m_cache[i].m_b == b.raw()) {
return true;
} else {
if (m_cache[i].m_a == nullptr)
m_used.push_back(i);
m_cache[i].m_a = a.raw();
m_cache[i].m_b = b.raw();
return false;
}
}
void clear() {
for (unsigned i : m_used)
m_cache[i].m_a = nullptr;
m_used.clear();
}
};
/* CACHE_RESET: No */
MK_THREAD_LOCAL_GET_DEF(eq_cache, get_eq_cache);
/** \brief Functional object for comparing expressions.
Remark if CompareBinderInfo is true, then functional object will also compare
binder information attached to lambda and Pi expressions */
template<bool CompareBinderInfo>
class expr_eq_fn {
eq_cache & m_cache;
static void check_system() { ::lean::check_system("expression equality test"); }
bool apply(expr const & a, expr const & b) {
if (is_eqp(a, b)) return true;
if (a.hash() != b.hash()) return false;
if (a.kind() != b.kind()) return false;
if (is_var(a)) return var_idx(a) == var_idx(b);
if (m_cache.check(a, b))
return true;
switch (a.kind()) {
case expr_kind::Var:
lean_unreachable(); // LCOV_EXCL_LINE
case expr_kind::Constant:
return
const_name(a) == const_name(b) &&
compare(const_levels(a), const_levels(b), [](level const & l1, level const & l2) { return l1 == l2; });
case expr_kind::Meta:
return
mlocal_name(a) == mlocal_name(b) &&
apply(mlocal_type(a), mlocal_type(b)) &&
(!CompareBinderInfo || mlocal_pp_name(a) == mlocal_pp_name(b));
case expr_kind::Local:
return
mlocal_name(a) == mlocal_name(b) &&
apply(mlocal_type(a), mlocal_type(b)) &&
(!CompareBinderInfo || mlocal_pp_name(a) == mlocal_pp_name(b)) &&
(!CompareBinderInfo || local_info(a) == local_info(b));
case expr_kind::App:
check_system();
return
apply(app_fn(a), app_fn(b)) &&
apply(app_arg(a), app_arg(b));
case expr_kind::Lambda: case expr_kind::Pi:
check_system();
return
apply(binding_domain(a), binding_domain(b)) &&
apply(binding_body(a), binding_body(b)) &&
(!CompareBinderInfo || binding_name(a) == binding_name(b)) &&
(!CompareBinderInfo || binding_info(a) == binding_info(b));
case expr_kind::Let:
check_system();
return
apply(let_type(a), let_type(b)) &&
apply(let_value(a), let_value(b)) &&
apply(let_body(a), let_body(b)) &&
(!CompareBinderInfo || let_name(a) == let_name(b));
case expr_kind::Sort:
return sort_level(a) == sort_level(b);
case expr_kind::Macro:
check_system();
if (macro_def(a) != macro_def(b) || macro_num_args(a) != macro_num_args(b))
return false;
for (unsigned i = 0; i < macro_num_args(a); i++) {
if (!apply(macro_arg(a, i), macro_arg(b, i)))
return false;
}
return true;
}
lean_unreachable(); // LCOV_EXCL_LINE
}
public:
expr_eq_fn():m_cache(get_eq_cache()) {}
~expr_eq_fn() { m_cache.clear(); }
bool operator()(expr const & a, expr const & b) { return apply(a, b); }
};
bool is_equal(expr const & a, expr const & b) {
return expr_eq_fn<false>()(a, b);
}
bool is_bi_equal(expr const & a, expr const & b) {
return expr_eq_fn<true>()(a, b);
}
}