Skip to content

Commit d849993

Browse files
committed
Update equal? to compare graphs using the Union-Find algorithm
Signed-off-by: yamacir-kit <[email protected]>
1 parent 6753d86 commit d849993

File tree

6 files changed

+119
-10
lines changed

6 files changed

+119
-10
lines changed

README.md

+4-4
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ Subset of R7RS-small.
7373
cmake -B build -DCMAKE_BUILD_TYPE=Release
7474
cd build
7575
make package
76-
sudo apt install build/meevax_0.4.777_amd64.deb
76+
sudo apt install build/meevax_0.4.778_amd64.deb
7777
```
7878

7979
or
@@ -105,15 +105,15 @@ sudo rm -rf /usr/local/share/meevax
105105

106106
| Target Name | Description
107107
|-----------------|-------------
108-
| `all` (default) | Build shared-library `libmeevax.0.4.777.so` and executable `meevax`
108+
| `all` (default) | Build shared-library `libmeevax.0.4.778.so` and executable `meevax`
109109
| `test` | Test executable `meevax`
110-
| `package` | Generate debian package `meevax_0.4.777_amd64.deb`
110+
| `package` | Generate debian package `meevax_0.4.778_amd64.deb`
111111
| `install` | Copy files into `/usr/local` directly
112112

113113
## Usage
114114

115115
```
116-
Meevax Lisp 0.4.777
116+
Meevax Lisp 0.4.778
117117
118118
Usage:
119119
meevax [option...] [file...]

VERSION

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
0.4.777
1+
0.4.778

include/meevax/kernel/pair.hpp

+9
Original file line numberDiff line numberDiff line change
@@ -169,4 +169,13 @@ inline namespace kernel
169169
} // namespace kernel
170170
} // namespace meevax
171171

172+
template <>
173+
struct std::hash<meevax::object>
174+
{
175+
auto operator ()(meevax::object const& x) const noexcept
176+
{
177+
return std::hash<decltype(x.get())>()(x.get());
178+
}
179+
};
180+
172181
#endif // INCLUDED_MEEVAX_KERNEL_PAIR_HPP

src/kernel/comparator.cpp

+92-2
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,100 @@ namespace meevax
2020
{
2121
inline namespace kernel
2222
{
23+
struct box : public virtual pair // (value . unit)
24+
{
25+
auto unbox() -> object &
26+
{
27+
return first;
28+
}
29+
30+
auto unbox() const -> object const&
31+
{
32+
return first;
33+
}
34+
35+
auto set(object const& x) -> object const&
36+
{
37+
return first = x;
38+
}
39+
};
40+
41+
auto find(let const& b) -> object const&
42+
{
43+
if (let x = b.as<box>().unbox(); x.is<box>())
44+
{
45+
return b.as<box>().set(find(x));
46+
}
47+
else
48+
{
49+
return b;
50+
}
51+
}
52+
53+
/*
54+
Efficient Nondestructive Equality Checking for Trees and Graphs
55+
*/
56+
auto union_find(object const& x, object const& y, std::unordered_map<object, object> & forest)
57+
{
58+
using rank = std::uint32_t;
59+
60+
if (auto iterator_x = forest.find(x); iterator_x != forest.end())
61+
{
62+
if (auto iterator_y = forest.find(y); iterator_y != forest.end())
63+
{
64+
if (let root_x = find(iterator_x->second),
65+
root_y = find(iterator_y->second); eq(root_x, root_y))
66+
{
67+
return true;
68+
}
69+
else
70+
{
71+
if (auto rank_x = root_x.as<box>().unbox().as<rank>(),
72+
rank_y = root_y.as<box>().unbox().as<rank>(); rank_x > rank_y)
73+
{
74+
root_x.as<box>().set(make<rank>(rank_x + rank_y));
75+
root_y.as<box>().set(root_x);
76+
}
77+
else
78+
{
79+
root_x.as<box>().set(root_y);
80+
root_y.as<box>().set(make<rank>(rank_x + rank_y));
81+
}
82+
}
83+
}
84+
else
85+
{
86+
forest.emplace(y, find(iterator_x->second));
87+
}
88+
}
89+
else
90+
{
91+
if (auto iterator_y = forest.find(y); iterator_y != forest.end())
92+
{
93+
forest.emplace(x, find(iterator_y->second));
94+
}
95+
else
96+
{
97+
let const b = make<box>(make<rank>(1));
98+
forest.emplace(x, b);
99+
forest.emplace(y, b);
100+
}
101+
}
102+
103+
return false;
104+
}
105+
106+
auto equal(object const& x, object const& y, std::unordered_map<object, object> & forest) -> bool
107+
{
108+
return eqv(x, y) or (x.is<pair>() and
109+
y.is<pair>() and (union_find(x, y, forest) or (equal(car(x), car(y), forest) and
110+
equal(cdr(x), cdr(y), forest))));
111+
}
112+
23113
auto equal(object const& x, object const& y) -> bool
24114
{
25-
return eqv(x, y) or std::equal(x.cbegin(), x.cend(),
26-
y.cbegin(), y.cend(), equal);
115+
auto forest = std::unordered_map<object, object>();
116+
return equal(x, y, forest);
27117
}
28118
} // namespace kernel
29119
} // namespace meevax

test/list.cpp

+10
Original file line numberDiff line numberDiff line change
@@ -48,5 +48,15 @@ auto main() -> int
4848
}
4949
}
5050

51+
{
52+
let x = list(a, b);
53+
cddr(x) = x;
54+
55+
let y = list(a, b, a, b);
56+
cddddr(y) = y;
57+
58+
assert(equal(x, y));
59+
}
60+
5161
return EXIT_SUCCESS;
5262
}

test/r7rs.ss

+3-3
Original file line numberDiff line numberDiff line change
@@ -856,8 +856,8 @@
856856
(check (equal? (make-vector 5 'a)
857857
(make-vector 5 'a)) => #t)
858858

859-
; (check (equal? '#1=(a b . #1#)
860-
; '#2=(a b a b . #2#)) => #t)
859+
(check (equal? '#1=(a b . #1#)
860+
'#2=(a b a b . #2#)) => #t)
861861

862862
(check (equal? (lambda (x) x)
863863
(lambda (y) y)) => #f) ; unspecified
@@ -1611,4 +1611,4 @@
16111611

16121612
(check-report)
16131613

1614-
(exit (check-passed? 431))
1614+
(exit (check-passed? 432))

0 commit comments

Comments
 (0)