use std::collections::HashMap;
use crate::channel::prepared::Prepared;
use crate::channel::Prepare;
use crate::circuit::Circuit;
use crate::engine::plan::PartitionPlan;
use crate::pauli_sum::hash::{Gf2Hash, PartitionRows};
#[derive(Clone, Debug, PartialEq)]
pub struct GeneratorWeight<const W: usize> {
pub mask_x: [u64; W],
pub mask_z: [u64; W],
pub weight: f64,
pub name: &'static str,
}
pub fn circuit_generators<const W: usize>(
circuit: &Circuit<W>,
hash: &Gf2Hash<W>,
adjoint: bool,
) -> Vec<GeneratorWeight<W>> {
let n = circuit.channels.len();
let mut out: Vec<GeneratorWeight<W>> = Vec::new();
let mut seen: HashMap<Mask<W>, usize> = HashMap::new();
for k in 0..n {
let index = if adjoint { n - 1 - k } else { k };
let channel = &circuit.channels[index];
let prepared = channel
.prepare(hash, adjoint)
.unwrap_or_else(|| panic!("circuit_generators: layer {index} declined preparation"));
for m in prepared.key_delta_masks() {
if mask_is_zero(&m) {
continue;
}
match seen.get(&m) {
Some(&i) => out[i].weight += 1.0,
None => {
seen.insert(m, out.len());
out.push(GeneratorWeight {
mask_x: m.0,
mask_z: m.1,
weight: 1.0,
name: channel.debug_name(),
});
}
}
}
}
out
}
type Mask<const W: usize> = ([u64; W], [u64; W]);
fn mask_is_zero<const W: usize>(m: &Mask<W>) -> bool {
m.0.iter().chain(m.1.iter()).all(|w| *w == 0)
}
pub fn count_remote_deltas<const W: usize>(
circuit: &Circuit<W>,
hash: &Gf2Hash<W>,
rows: &PartitionRows<W>,
adjoint: bool,
) -> Vec<(usize, usize)> {
let n = circuit.channels.len();
(0..n)
.map(|k| if adjoint { n - 1 - k } else { k })
.map(|index| {
let prepared = circuit.channels[index].prepare(hash, adjoint).unwrap_or_else(|| {
panic!("count_remote_deltas: layer {index} declined preparation")
});
let plan = PartitionPlan::new(&prepared, rows, 0);
let local = plan.local_entries.iter().filter(|b| **b).count();
(local, plan.remote.len())
})
.collect()
}
impl PartitionPlan {
pub(crate) fn new<const W: usize>(
prepared: &Prepared<W>,
rows: &PartitionRows<W>,
rank: u32,
) -> Self {
let mut plan = Self::default();
plan.rebuild(prepared, rows, rank);
plan
}
}
#[cfg(test)]
mod tests;