paulistrings/pauli_sum/
accumulator.rs1use crate::pauli_string::PauliString;
4use crate::pauli_sum::hash::Gf2Hash;
5use crate::pauli_sum::storage::DEFAULT_TARGET_BUCKET_LEN;
6use crate::pauli_sum::storage::{desired_bits, DEFAULT_HASH_SEED, DEFAULT_MIN_BUCKETS};
7use crate::pauli_sum::PauliSum;
8use hashbrown::HashMap;
9use num_complex::Complex64;
10use rustc_hash::FxBuildHasher;
11
12pub struct BuildAccumulator<const W: usize> {
14 map: HashMap<PauliString<W>, Complex64, FxBuildHasher>,
15 num_qubits: usize,
16}
17
18impl<const W: usize> BuildAccumulator<W> {
19 pub fn new(num_qubits: usize) -> Self {
21 Self { map: HashMap::with_hasher(FxBuildHasher), num_qubits }
22 }
23
24 pub fn with_capacity(num_qubits: usize, capacity: usize) -> Self {
26 Self { map: HashMap::with_capacity_and_hasher(capacity, FxBuildHasher), num_qubits }
27 }
28
29 pub fn add_term(&mut self, p: PauliString<W>, c: Complex64) {
31 self.map.entry(p).and_modify(|e| *e += c).or_insert(c);
32 }
33
34 pub fn finalize(self) -> PauliSum<W> {
36 let zero = Complex64::new(0.0, 0.0);
37 let mut entries: Vec<(PauliString<W>, Complex64)> =
38 self.map.into_iter().filter(|(_, c)| *c != zero).collect();
39 entries.sort_unstable_by(|a, b| a.0.cmp(&b.0));
40 let n = entries.len();
41 let mut x = Vec::with_capacity(n);
42 let mut z = Vec::with_capacity(n);
43 let mut coeff = Vec::with_capacity(n);
44 for (p, c) in entries {
45 x.push(p.x);
46 z.push(p.z);
47 coeff.push(c);
48 }
49 let bits = desired_bits(n, DEFAULT_TARGET_BUCKET_LEN, DEFAULT_MIN_BUCKETS);
50 let hash = Gf2Hash::new(self.num_qubits, bits, DEFAULT_HASH_SEED);
51 PauliSum::from_key_sorted(&x, &z, &coeff, hash, self.num_qubits)
52 }
53}
54
55#[cfg(test)]
56mod tests;