slotted_egraphs/
slotmap.rs1use smallvec::SmallVec;
2
3use crate::*;
4use std::ops::Index;
5
6pub(crate) type Perm = Bijection;
9
10pub(crate) type Bijection = SlotMap;
12
13#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Default)]
14pub struct SlotMap {
18 map: SmallVec<[(Slot, Slot); 10]>,
21}
22
23impl SlotMap {
24 pub fn new() -> Self {
25 SlotMap {
26 map: Default::default(),
27 }
28 }
29
30 pub fn len(&self) -> usize {
31 self.map.len()
32 }
33
34 pub fn is_empty(&self) -> bool {
35 self.map.is_empty()
36 }
37
38 fn search(&self, l: Slot) -> Result<usize, usize> {
39 self.map.binary_search_by_key(&l, |(x, _)| *x)
40 }
41
42 pub fn contains_key(&self, k: Slot) -> bool {
43 self.get(k).is_some()
44 }
45
46 pub fn insert(&mut self, l: Slot, r: Slot) {
47 match self.search(l) {
48 Ok(i) => {
49 self.map[i] = (l, r);
50 }
51 Err(i) => {
52 self.map.insert(i, (l, r));
53 }
54 }
55 }
56
57 pub fn get(&self, l: Slot) -> Option<Slot> {
58 self.search(l).ok().map(|i| self.map[i].1)
59 }
60
61 pub fn iter(&self) -> impl Iterator<Item = (Slot, Slot)> + '_ {
62 self.map.iter().copied()
63 }
64
65 pub fn into_iter(self) -> impl Iterator<Item = (Slot, Slot)> {
66 self.map.into_iter()
67 }
68
69 pub fn values_mut(&mut self) -> impl Iterator<Item = &mut Slot> + '_ {
71 self.map.iter_mut().map(|(_, y)| y)
72 }
73
74 pub fn values_immut(&self) -> impl Iterator<Item = &Slot> + '_ {
75 self.map.iter().map(|(_, y)| y)
76 }
77
78 pub fn keys(&self) -> SmallHashSet<Slot> {
79 self.iter().map(|(x, _)| x).collect()
80 }
81 pub fn values(&self) -> SmallHashSet<Slot> {
82 self.iter().map(|(_, y)| y).collect()
83 }
84 pub fn keys_vec(&self) -> Vec<Slot> {
85 self.iter().map(|(x, _)| x).collect()
86 }
87 pub fn values_vec(&self) -> Vec<Slot> {
88 self.iter().map(|(_, y)| y).collect()
89 }
90
91 pub fn inverse(&self) -> SlotMap {
92 if CHECKS {
93 assert!(self.is_bijection());
94 }
95
96 let mut out = Self::new();
97 for (x, y) in self.iter() {
98 out.insert(y, x);
99 }
100
101 out
102 }
103
104 pub fn is_bijection(&self) -> bool {
105 let mut found = HashSet::default();
106
107 for (_, x) in self.iter() {
108 if found.contains(&x) {
109 return false;
110 }
111
112 found.insert(x);
113 }
114
115 true
116 }
117
118 pub fn is_perm(&self) -> bool {
119 self.is_bijection() && self.keys() == self.values()
120 }
121
122 #[track_caller]
123 pub fn compose(&self, other: &SlotMap) -> SlotMap {
124 if CHECKS {
125 assert_eq!(self.values(), other.keys(), "SlotMap::compose() failed!");
126 }
127
128 self.compose_partial(other)
129 }
130
131 pub fn compose_partial(&self, other: &SlotMap) -> SlotMap {
137 let mut out = SlotMap::new();
138 for (x, y) in self.iter() {
139 if let Some(z) = other.get(y) {
140 out.insert(x, z);
141 }
142 }
143 out
144 }
145
146 pub fn compose_fresh(&self, other: &SlotMap) -> SlotMap {
149 let mut out = SlotMap::new();
150 for (x, y) in self.iter() {
151 if let Some(z) = other.get(y) {
152 out.insert(x, z);
153 } else {
154 out.insert(x, Slot::fresh());
155 }
156 }
157 out
158 }
159
160 pub fn identity(set: &SmallHashSet<Slot>) -> SlotMap {
161 let mut out = SlotMap::new();
162 for &x in set {
163 out.insert(x, x);
164 }
165 out
166 }
167
168 pub fn bijection_from_fresh_to(set: &SmallHashSet<Slot>) -> SlotMap {
169 let mut out = SlotMap::new();
170 for &x in set {
171 out.insert(Slot::fresh(), x);
172 }
173 out
174 }
175
176 pub fn remove(&mut self, x: Slot) {
177 if let Ok(i) = self.search(x) {
178 self.map.remove(i);
179 }
180 }
181
182 pub fn from_pairs(pairs: &[(Slot, Slot)]) -> SlotMap {
183 pairs.iter().copied().collect()
184 }
185
186 #[track_caller]
188 pub fn union(&self, other: &SlotMap) -> Self {
189 let mut out = self.clone();
190
191 for (x, y) in other.iter() {
192 if CHECKS {
193 if let Some(z) = out.get(x) {
194 assert_eq!(
195 y, z,
196 "SlotMap::union: The SlotMaps disagree! {:?} -> {:?} / {:?}",
197 x, z, y
198 );
199 }
200 }
201 out.insert(x, y);
202 }
203
204 out
205 }
206
207 pub fn try_union(&self, other: &SlotMap) -> Option<Self> {
208 let mut out = self.clone();
209
210 for (x, y) in other.iter() {
211 if let Some(z) = out.get(x) {
212 if y != z {
213 return None;
214 }
215 }
216 out.insert(x, y);
217 }
218
219 Some(out)
220 }
221
222 #[allow(unused)]
224 fn check(&self) {
225 let mut sorted = self.map.clone();
227 sorted.sort_by_key(|(l, _)| *l);
228 assert_eq!(&self.map, &sorted);
229
230 let mut found = HashSet::default();
232 for &(x, _) in self.map.iter() {
233 assert!(!found.contains(&x));
234 found.insert(x);
235 }
236 }
237}
238
239impl Index<Slot> for SlotMap {
240 type Output = Slot;
241
242 #[track_caller]
243 #[inline]
244 fn index(&self, l: Slot) -> &Slot {
245 let Ok(i) = self.search(l) else {
246 panic!("SlotMap::index({:?}): index missing!", l);
247 };
248
249 &self.map[i].1
250 }
251}
252
253impl FromIterator<(Slot, Slot)> for SlotMap {
254 fn from_iter<T>(iter: T) -> Self
255 where
256 T: IntoIterator<Item = (Slot, Slot)>,
257 {
258 let mut m = SlotMap::new();
259 for (x, y) in iter.into_iter() {
260 if CHECKS {
261 assert!(!m.contains_key(x));
262 }
263 m.insert(x, y);
264 }
265 m
266 }
267}
268
269impl<const N: usize> From<[(Slot, Slot); N]> for SlotMap {
270 fn from(pairs: [(Slot, Slot); N]) -> Self {
271 let mut m = SlotMap::new();
272 for (x, y) in pairs {
273 if CHECKS {
274 assert!(!m.contains_key(x));
275 }
276
277 m.insert(x, y);
278 }
279 m
280 }
281}
282
283#[test]
284fn test_slotmap() {
285 let mut m: SlotMap = SlotMap::new();
286 m.insert(Slot::numeric(3), Slot::numeric(7));
287 m.insert(Slot::numeric(2), Slot::numeric(7));
288 m.insert(Slot::numeric(3), Slot::numeric(8));
289 m.insert(Slot::numeric(4), Slot::numeric(7));
290 assert_eq!(m[Slot::numeric(3)], Slot::numeric(8));
291
292 m.check();
293}