use crate::pauli_string::PauliString;
use crate::pauli_sum::hash::Gf2Hash;
use crate::pauli_sum::storage::DEFAULT_TARGET_BUCKET_LEN;
use crate::pauli_sum::storage::{desired_bits, DEFAULT_HASH_SEED, DEFAULT_MIN_BUCKETS};
use crate::pauli_sum::PauliSum;
use hashbrown::HashMap;
use num_complex::Complex64;
use rustc_hash::FxBuildHasher;
pub struct BuildAccumulator<const W: usize> {
map: HashMap<PauliString<W>, Complex64, FxBuildHasher>,
num_qubits: usize,
}
impl<const W: usize> BuildAccumulator<W> {
pub fn new(num_qubits: usize) -> Self {
Self { map: HashMap::with_hasher(FxBuildHasher), num_qubits }
}
pub fn with_capacity(num_qubits: usize, capacity: usize) -> Self {
Self { map: HashMap::with_capacity_and_hasher(capacity, FxBuildHasher), num_qubits }
}
pub fn add_term(&mut self, p: PauliString<W>, c: Complex64) {
self.map.entry(p).and_modify(|e| *e += c).or_insert(c);
}
pub fn finalize(self) -> PauliSum<W> {
let zero = Complex64::new(0.0, 0.0);
let mut entries: Vec<(PauliString<W>, Complex64)> =
self.map.into_iter().filter(|(_, c)| *c != zero).collect();
entries.sort_unstable_by(|a, b| a.0.cmp(&b.0));
let n = entries.len();
let mut x = Vec::with_capacity(n);
let mut z = Vec::with_capacity(n);
let mut coeff = Vec::with_capacity(n);
for (p, c) in entries {
x.push(p.x);
z.push(p.z);
coeff.push(c);
}
let bits = desired_bits(n, DEFAULT_TARGET_BUCKET_LEN, DEFAULT_MIN_BUCKETS);
let hash = Gf2Hash::new(self.num_qubits, bits, DEFAULT_HASH_SEED);
PauliSum::from_key_sorted(&x, &z, &coeff, hash, self.num_qubits)
}
}
#[cfg(test)]
mod tests;