paulistrings/channel/
mod.rs1pub(crate) mod prepared;
4pub(crate) mod ptm;
5pub(crate) mod rotation;
6
7pub use ptm::PtmChannel;
8pub use rotation::PauliRotation;
9
10pub(crate) use prepared::Prepare;
11
12use crate::pauli_string::qubit_mask;
13use crate::pauli_sum::hash::Gf2Hash;
14use num_complex::Complex64;
15use prepared::{PrepareToken, Prepared};
16
17pub struct OutputBuffer<const W: usize> {
19 x: Vec<[u64; W]>,
20 z: Vec<[u64; W]>,
21 coeff: Vec<Complex64>,
22}
23
24impl<const W: usize> OutputBuffer<W> {
25 pub fn push(&mut self, x: [u64; W], z: [u64; W], coeff: Complex64) {
27 self.x.push(x);
28 self.z.push(z);
29 self.coeff.push(coeff);
30 }
31
32 pub(crate) fn new() -> Self {
33 Self { x: Vec::new(), z: Vec::new(), coeff: Vec::new() }
34 }
35
36 pub(crate) fn clear(&mut self) {
38 self.x.clear();
39 self.z.clear();
40 self.coeff.clear();
41 }
42
43 pub(crate) fn terms(
45 &self,
46 ) -> impl ExactSizeIterator<Item = ([u64; W], [u64; W], Complex64)> + '_ {
47 self.x.iter().zip(&self.z).zip(&self.coeff).map(|((&x, &z), &coeff)| (x, z, coeff))
48 }
49}
50
51pub fn support_mask<const W: usize>(qubits: &[usize]) -> [u64; W] {
57 qubit_mask(qubits.iter().copied(), 64 * W)
58}
59
60fn qubit_loc(q: usize) -> (usize, usize, u64) {
62 let word = q / 64;
63 let bit = q % 64;
64 (word, bit, 1u64 << bit)
65}
66
67fn read_pauli<const W: usize>(x: &[u64; W], z: &[u64; W], word: usize, bit: usize) -> usize {
69 let x_bit = (x[word] >> bit) & 1;
70 let z_bit = (z[word] >> bit) & 1;
71 (x_bit | (z_bit << 1)) as usize
72}
73
74fn write_pauli<const W: usize>(
76 x: &mut [u64; W],
77 z: &mut [u64; W],
78 word: usize,
79 bit: usize,
80 mask: u64,
81 p: usize,
82) {
83 let x_bit = (p & 1) as u64;
84 let z_bit = ((p >> 1) & 1) as u64;
85 x[word] = (x[word] & !mask) | (x_bit << bit);
86 z[word] = (z[word] & !mask) | (z_bit << bit);
87}
88
89pub trait Channel<const W: usize>: Send + Sync {
94 fn support(&self) -> [u64; W];
98
99 fn debug_name(&self) -> &'static str {
103 let full = core::any::type_name::<Self>();
104 let head = match full.find('<') {
105 Some(i) => &full[..i],
106 None => full,
107 };
108 match head.rfind("::") {
109 Some(i) => &head[i + 2..],
110 None => head,
111 }
112 }
113
114 fn apply(
116 &self,
117 input_x: &[u64; W],
118 input_z: &[u64; W],
119 coeff: Complex64,
120 out: &mut OutputBuffer<W>,
121 );
122
123 fn apply_adjoint(
127 &self,
128 input_x: &[u64; W],
129 input_z: &[u64; W],
130 coeff: Complex64,
131 out: &mut OutputBuffer<W>,
132 );
133
134 #[doc(hidden)]
137 fn prepare_for_layer(
138 &self,
139 hash: &Gf2Hash<W>,
140 adjoint: bool,
141 _: PrepareToken,
142 ) -> Option<Prepared<W>> {
143 Prepared::derive_local(self, hash, adjoint)
144 }
145}
146
147#[cfg(test)]
148mod tests;