Skip to main content

ppvm_traits/map/
hashmap.rs

1// SPDX-FileCopyrightText: 2026 The PPVM Authors
2// SPDX-License-Identifier: Apache-2.0
3
4use std::{collections::HashMap, hash::BuildHasher};
5
6use crate::traits::*;
7
8macro_rules! impl_acmap_base {
9    ($($seg:ident)::+) => {
10        impl<'a, V, Hasher, W> crate::traits::ACMapBase for $($seg)::+<W, V, Hasher>
11        where
12            V: Coefficient,
13            Hasher: Clone + BuildHasher + Default,
14            W:,
15        {
16            fn with_capacity(capacity: usize) -> Self {
17                Self::with_capacity_and_hasher(capacity, Hasher::default())
18            }
19
20            fn len(&self) -> usize {
21                $($seg)::+::len(self)
22            }
23
24            fn clear(&mut self) {
25                $($seg)::+::clear(self)
26            }
27        }
28    };
29}
30
31macro_rules! impl_acmap_add_assign {
32    ($($seg:ident)::+) => {
33        impl<'a, S, V, Hasher, W> crate::traits::ACMapAddAssign<S, V, Hasher, W> for $($seg)::+<W, V, Hasher>
34        where
35            S: PauliStorage + 'a,
36            V: Coefficient + 'a,
37            Hasher: Default + Clone + BuildHasher + 'a,
38            W: PauliWordTrait + 'a,
39        {
40            fn add_assign(&mut self, key: W, value: V) {
41                self.entry(key)
42                    .and_modify(|v| *v += value.clone())
43                    .or_insert(value);
44            }
45
46            fn map_add_assign<F>(&self, dest: &mut Self, f: F)
47            where
48                F: Fn(&W, &V) -> (W, V) + Sync + Send,
49            {
50                for (k, v) in self.iter() {
51                    let (new_k, new_v) = f(k, v);
52                    <Self as ACMapAddAssign<S, V, Hasher, W>>::add_assign(dest, new_k, new_v);
53                }
54            }
55        }
56    };
57}
58
59macro_rules! impl_acmap_mul_assign {
60    ($($seg:ident)::+) => {
61        impl<'a, V, Hasher, W> crate::traits::ACMapMulAssign<V, Hasher> for $($seg)::+<W, V, Hasher>
62        where
63            V: Coefficient + 'a,
64            Hasher: Default + Clone + BuildHasher + 'a,
65            W:,
66        {
67            fn mul_assign(&mut self, value: V) {
68                for v in self.values_mut() {
69                    *v *= value.clone();
70                }
71            }
72        }
73    };
74}
75
76macro_rules! impl_acmap_iter {
77    ($($seg:ident)::+) => {
78        impl<'a, V, Hasher, W> crate::traits::ACMapIter<'a> for $($seg)::+<W, V, Hasher>
79        where
80            V: Coefficient + 'a,
81            Hasher: Default + Clone + BuildHasher + 'a,
82            W: 'a,
83        {
84            type Item = (&'a W, &'a V);
85            type Iter = std::collections::hash_map::Iter<'a, W, V>;
86
87            fn iter(&'a self) -> Self::Iter {
88                Self::iter(self)
89            }
90        }
91    };
92}
93
94macro_rules! impl_acmap_trace {
95    ($($seg:ident)::+) => {
96        impl<'a, P, C, Hasher, W> crate::traits::Trace<'a, P> for $($seg)::+<W, C, Hasher>
97        where
98            P: crate::traits::Trace<'a, W, Output = bool> + 'a,
99            C: Coefficient + 'a,
100            Hasher: Default + Clone + BuildHasher + 'a,
101            W: 'a,
102        {
103            type Output = C;
104            fn trace(&'a self, value: &'a P) -> Self::Output {
105                let sum = C::zero();
106                self.iter().fold(sum, |mut acc, (k, v)| {
107                    value.trace(k).then(|| acc += v.clone());
108                    acc
109                })
110            }
111        }
112    };
113}
114
115macro_rules! impl_acmap_combine_unique {
116    ($($seg:ident)::+) => {
117        impl<C, Hasher, W> ACMapConsume for $($seg)::+<W, C, Hasher>
118        where
119            C: Coefficient,
120            Hasher: Default + Clone + BuildHasher,
121            W: std::hash::Hash + std::cmp::Eq,
122        {
123            fn consume(&mut self, dest: &mut Self) {
124                for (k, v) in dest.drain() {
125                    self.entry(k)
126                        .and_modify(|val| *val += v.clone())
127                        .or_insert(v);
128                }
129            }
130        }
131    };
132}
133
134macro_rules! impl_acmap_insert {
135    ($($seg:ident)::+) => {
136        impl<'a, S, C, Hasher, W> ACMapInsert<S, C, Hasher, W> for $($seg)::+<W, C, Hasher>
137        where
138            S: PauliStorage + 'a,
139            C: Coefficient + 'a,
140            Hasher: Default + Clone + BuildHasher + 'a,
141            W: PauliWordTrait + 'a,
142        {
143            fn map_insert_vec<F>(&mut self, dest: &mut Vec<(W, C)>, f: F)
144            where
145                F: Fn(&W, &mut C) -> Option<(W, C)> + Sync + Send,
146            {
147                for (k, v) in self.iter_mut() {
148                    if let Some(entry) = f(k, v) {
149                        dest.push(entry);
150                    }
151                }
152            }
153
154            fn map_insert_multiple<F>(&mut self, dest: &mut Self, f: F)
155            where
156                F: Fn(&W, &mut C) -> Option<Vec<(W, C)>> + Sync + Send,
157            {
158                for (k, v) in self.iter_mut() {
159                    if let Some(entries) = f(k, v) {
160                        for (new_k, new_v) in entries {
161                            dest.entry(new_k)
162                                .and_modify(|val| *val += new_v.clone())
163                                .or_insert(new_v);
164                        }
165                    }
166                }
167            }
168        }
169    };
170}
171
172macro_rules! impl_acmap_contains {
173    ($($seg:ident)::+) => {
174        impl<S, C, H, W> ACMapContains<S, C, H, W> for $($seg)::+<W, C, H>
175        where
176            S: PauliStorage,
177            C: Coefficient,
178            H: Default + Clone + BuildHasher,
179            W: PauliWordTrait,
180        {
181            fn contains_with<F>(&self, key: &W, f: F) -> bool
182            where
183                F: Fn(&C) -> bool,
184            {
185                match self.get(key) {
186                    Some(v) => f(v),
187                    None => false,
188                }
189            }
190        }
191    };
192}
193
194macro_rules! impl_acmap_scale {
195    ($($seg:ident)::+) => {
196        impl<S, V, H, W> ACMapScale<S, V, H, W> for $($seg)::+<W, V, H>
197        where
198            S: PauliStorage,
199            V: Coefficient,
200            H: BuildHasher + Clone + Default,
201            W: PauliWordTrait,
202        {
203            fn scale<F>(&mut self, f: F)
204            where
205                F: Fn(&W, &mut V) + Sync + Send,
206            {
207                for (k, v) in self.iter_mut() {
208                    f(k, v);
209                }
210            }
211        }
212    };
213}
214
215macro_rules! impl_acmap_retain {
216    ($($seg:ident)::+) => {
217        impl<S, V, H, W> ACMapRetain<S, V, H, W> for $($seg)::+<W, V, H>
218        where
219            S: PauliStorage,
220            V: Coefficient,
221            H: BuildHasher + Clone + Default,
222            W: PauliWordTrait,
223        {
224            fn retain<F>(&mut self, mut f: F)
225            where
226                F: FnMut(&W, &V) -> bool,
227            {
228                Self::retain(self, |k, v| f(k, v));
229            }
230        }
231    };
232}
233
234macro_rules! impl_acmap {
235    ($($seg:ident)::+) => {
236        impl_acmap_base!($($seg)::+);
237        impl_acmap_add_assign!($($seg)::+);
238        impl_acmap_mul_assign!($($seg)::+);
239        impl_acmap_iter!($($seg)::+);
240        impl_acmap_trace!($($seg)::+);
241        impl_acmap_combine_unique!($($seg)::+);
242        impl_acmap_insert!($($seg)::+);
243        impl_acmap_contains!($($seg)::+);
244        impl_acmap_scale!($($seg)::+);
245        impl_acmap_retain!($($seg)::+);
246    };
247}
248
249impl_acmap!(HashMap);
250
251#[cfg(feature = "indexmap")]
252mod indexmap_impl {
253    use super::*;
254
255    impl<'a, V, H, W> crate::traits::ACMapIter<'a> for indexmap::IndexMap<W, V, H>
256    where
257        V: Coefficient + 'a,
258        H: Default + Clone + BuildHasher + 'a,
259        W: 'a,
260    {
261        type Item = (&'a W, &'a V);
262        type Iter = indexmap::map::Iter<'a, W, V>;
263
264        fn iter(&'a self) -> Self::Iter {
265            Self::iter(self)
266        }
267    }
268
269    impl<C, H, W> ACMapConsume for indexmap::IndexMap<W, C, H>
270    where
271        C: Coefficient,
272        H: Default + Clone + BuildHasher,
273        W: std::hash::Hash + std::cmp::Eq,
274    {
275        fn consume(&mut self, dest: &mut Self) {
276            for (k, v) in dest.drain(..) {
277                self.entry(k)
278                    .and_modify(|val| *val += v.clone())
279                    .or_insert(v);
280            }
281        }
282    }
283
284    impl_acmap_base!(indexmap::IndexMap);
285    impl_acmap_add_assign!(indexmap::IndexMap);
286    impl_acmap_mul_assign!(indexmap::IndexMap);
287    impl_acmap_trace!(indexmap::IndexMap);
288    impl_acmap_insert!(indexmap::IndexMap);
289    impl_acmap_contains!(indexmap::IndexMap);
290    impl_acmap_scale!(indexmap::IndexMap);
291    impl_acmap_retain!(indexmap::IndexMap);
292}
293
294#[cfg(all(feature = "ahash", not(target_arch = "wasm32")))]
295mod ahash_impl {
296    use super::*;
297
298    impl<V, H, W> crate::traits::ACMapBase for ahash::AHashMap<W, V, H>
299    where
300        V: Coefficient,
301        H: Clone + BuildHasher + Default,
302        W:,
303    {
304        fn with_capacity(capacity: usize) -> Self {
305            Self::with_capacity_and_hasher(capacity, H::default())
306        }
307
308        fn len(&self) -> usize {
309            HashMap::len(self)
310        }
311
312        fn clear(&mut self) {
313            HashMap::clear(self)
314        }
315    }
316
317    impl<'a, V, H, W> crate::traits::ACMapIter<'a> for ahash::AHashMap<W, V, H>
318    where
319        V: Coefficient + 'a,
320        H: Default + Clone + BuildHasher + 'a,
321        W: 'a,
322    {
323        type Item = (&'a W, &'a V);
324        type Iter = std::collections::hash_map::Iter<'a, W, V>;
325
326        fn iter(&'a self) -> Self::Iter {
327            HashMap::iter(self)
328        }
329    }
330
331    impl<S, V, H, W> ACMapRetain<S, V, H, W> for ahash::AHashMap<W, V, H>
332    where
333        S: PauliStorage,
334        V: Coefficient,
335        H: BuildHasher + Clone + Default,
336        W: PauliWordTrait,
337    {
338        fn retain<F>(&mut self, mut f: F)
339        where
340            F: FnMut(&W, &V) -> bool,
341        {
342            HashMap::retain(self, |k, v| f(k, v));
343        }
344    }
345
346    impl_acmap_add_assign!(ahash::AHashMap);
347    impl_acmap_mul_assign!(ahash::AHashMap);
348    impl_acmap_trace!(ahash::AHashMap);
349    impl_acmap_combine_unique!(ahash::AHashMap);
350    impl_acmap_insert!(ahash::AHashMap);
351    impl_acmap_contains!(ahash::AHashMap);
352    impl_acmap_scale!(ahash::AHashMap);
353}