1use 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}