lay_steane/
lib.rs

1use lay::{Layer, Measured, OpsVec, operations::{opid, OpArgs, Operation, PauliOperation, HOperation, SOperation, CXOperation}, gates::{PauliGate, HGate, SGate, CXGate}};
2use lay_simulator_gk::{ GottesmanKnillSimulator, DefaultRng };
3
4use num_traits::cast::{cast, NumCast};
5
6macro_rules! cast { ($n:expr) => { cast($n).unwrap() } }
7
8const PHYSQUBIT_PER_LOGQUBIT: u32 = 7;
9const MEASURE_ANCILLA_QUBITS: u32 = 6;
10
11#[derive(Debug)]
12pub struct SteaneLayer<L: Layer> {
13    pub instance: L,
14    n_logical_qubits: u32,
15    instance_buf: L::Buffer,
16    measured: Vec<bool>,
17}
18
19const ERR_TABLE_X: [u32;8] = [999 /* dummy */, 0, 1, 6, 2, 4, 3, 5];
20const ERR_TABLE_Z: [u32;8] = [999 /* dummy */, 3, 4, 6, 5, 0, 1, 2];
21
22pub fn required_physical_qubits(n_logical_qubits: u32) -> u32 {
23    PHYSQUBIT_PER_LOGQUBIT * n_logical_qubits + MEASURE_ANCILLA_QUBITS
24}
25
26impl<L: Layer> SteaneLayer<L> {
27    pub fn from_instance(instance: L, n_logical_qubits: u32) -> Self {
28        let instance_buf = instance.make_buffer();
29        Self { instance,
30               n_logical_qubits,
31               instance_buf,
32               measured: vec![false; n_logical_qubits as usize]
33        }
34    }
35}
36
37impl SteaneLayer<GottesmanKnillSimulator<DefaultRng>> {
38    pub fn from_seed_with_gk(n_logical_qubits: u32, seed: u64) -> Self {
39        SteaneLayer::from_instance(
40            GottesmanKnillSimulator::from_seed(required_physical_qubits(n_logical_qubits) as _, seed),
41            n_logical_qubits)
42    }
43}
44
45#[derive(Debug, PartialEq, Eq)]
46pub struct SteaneBuffer(Vec<bool>);
47
48impl Measured for SteaneBuffer
49{
50    type Slot = u32;
51    fn get(&self, s: u32) -> bool {
52        (self.0)[s as usize]
53    }
54}
55
56impl<L: Layer + PauliGate + HGate + SGate + CXGate> Layer for SteaneLayer<L>
57where
58        L : Layer + PauliGate + HGate + SGate + CXGate,
59        L::Operation: Operation<L> + PauliOperation<L> + HOperation<L> + SOperation<L> + CXOperation<L>,
60        L::Qubit: NumCast,
61        L::Slot : NumCast,
62{
63    type Operation = OpArgs<Self>;
64    type Qubit = u32;
65    type Slot = u32;
66    type Buffer = SteaneBuffer;
67    type Requested = L::Requested;
68    type Response = L::Response;
69
70    fn send(&mut self, ops: &[Self::Operation]) -> L::Requested {
71        let mut lowlevel_ops = OpsVec::new();
72        for op in ops {
73            match op {
74                OpArgs::Empty(id) if *id == opid::INIT => {
75                    self.initialize(&mut lowlevel_ops);
76                },
77                OpArgs::Empty(id) if *id == opid::USERDEF => {
78                    self.syndrome_measure_and_recover(&mut lowlevel_ops);
79                },
80                OpArgs::Q(id, q) => {
81                    match *id {
82                        opid::X => {
83                            self.x(*q, &mut lowlevel_ops);
84                        },
85                        opid::Y => {
86                            self.y(*q, &mut lowlevel_ops);
87                        },
88                        opid::Z => {
89                            self.z(*q, &mut lowlevel_ops);
90                        },
91                        opid::H => {
92                            self.h(*q, &mut lowlevel_ops);
93                        },
94                        opid::S => {
95                            self.s(*q, &mut lowlevel_ops);
96                        },
97                        opid::SDG => {
98                            self.sdg(*q, &mut lowlevel_ops);
99                        },
100                        _ => {
101                            unimplemented!("Unknown 1 qubit op");
102                        }
103                    }
104                },
105                OpArgs::QS(id, q, s) if *id == opid::MEAS => {
106                    self.measure(*q, *s, &mut lowlevel_ops);
107                },
108                OpArgs::QQ(id, c, t) if *id == opid::CX => {
109                    self.cx(*c, *t, &mut lowlevel_ops);
110                },
111                _ => unimplemented!("Unknown op")
112            }
113        }
114        self.instance.send(lowlevel_ops.as_ref())
115    }
116
117    fn receive(&mut self, buf: &mut Self::Buffer) -> L::Response {
118        let res = self.instance.receive(&mut self.instance_buf);
119        std::mem::swap(&mut self.measured, &mut buf.0);
120        res
121    }
122
123    fn send_receive(&mut self, ops: &[Self::Operation], buf: &mut Self::Buffer) -> L::Response {
124        self.send(&ops);
125        self.receive(buf)
126    }
127
128    fn make_buffer(&self) -> Self::Buffer {
129        SteaneBuffer(vec![false; self.n_logical_qubits as usize])
130    }
131}
132
133impl<L: Layer + PauliGate + HGate + SGate + CXGate> PauliGate for SteaneLayer<L>
134where
135        L : Layer + PauliGate + HGate + SGate + CXGate,
136        L::Operation: Operation<L> + PauliOperation<L> + HOperation<L> + SOperation<L> + CXOperation<L>,
137        L::Qubit : NumCast,
138        L::Slot : NumCast {}
139
140impl<L: Layer + PauliGate + HGate + SGate + CXGate> HGate for SteaneLayer<L>
141where
142        L : Layer + PauliGate + HGate + SGate + CXGate,
143        L::Operation: Operation<L> + PauliOperation<L> + HOperation<L> + SOperation<L> + CXOperation<L>,
144        L::Qubit : NumCast,
145        L::Slot : NumCast {}
146
147impl<L: Layer + PauliGate + HGate + SGate + CXGate> SGate for SteaneLayer<L>
148where
149        L : Layer + PauliGate + HGate + SGate + CXGate,
150        L::Operation: Operation<L> + PauliOperation<L> + HOperation<L> + SOperation<L> + CXOperation<L>,
151        L::Qubit : NumCast,
152        L::Slot : NumCast {}
153
154impl<L: Layer + PauliGate + HGate + SGate + CXGate> CXGate for SteaneLayer<L>
155where
156        L : Layer + PauliGate + HGate + SGate + CXGate,
157        L::Operation: Operation<L> + PauliOperation<L> + HOperation<L> + SOperation<L> + CXOperation<L>,
158        L::Qubit : NumCast,
159        L::Slot : NumCast {}
160
161impl<L: Layer + PauliGate + HGate + SGate + CXGate> SteaneLayer<L>
162where
163        L : Layer + PauliGate + HGate + SGate + CXGate,
164        L::Operation: Operation<L> + PauliOperation<L> + HOperation<L> + SOperation<L> + CXOperation<L>,
165        L::Qubit : NumCast,
166        L::Slot : NumCast,
167{
168    fn measure_ancilla(&self) -> u32 {
169        //self.sim.n_qubits() as Qubit - MEASURE_ANCILLA_QUBITS
170        self.n_logical_qubits * PHYSQUBIT_PER_LOGQUBIT
171    }
172
173    fn initialize(&mut self, ops: &mut OpsVec<L>) {
174        ops.initialize();
175        self.syndrome_measure_and_recover(ops);
176    }
177
178    fn syndrome_measure_and_recover(&mut self, ops: &mut OpsVec<L>) {
179        // eprintln!("START syndrome_measure_and_recover");
180        let m0 = self.measure_ancilla();
181        for i in 0..self.n_logical_qubits {
182            let offset = i * PHYSQUBIT_PER_LOGQUBIT;
183            for j in 0..PHYSQUBIT_PER_LOGQUBIT {
184                ops.h(cast!(offset + j));
185            }
186            ops.cx(cast!(offset), cast!(m0));
187            ops.cx(cast!(offset + 1), cast!(m0 + 1));
188            ops.cx(cast!(offset + 2), cast!(m0 + 2));
189            ops.cx(cast!(offset + 3), cast!(m0 + 1));
190            ops.cx(cast!(offset + 3), cast!(m0 + 2));
191            ops.cx(cast!(offset + 4), cast!(m0));
192            ops.cx(cast!(offset + 4), cast!(m0 + 2));
193            ops.cx(cast!(offset + 5), cast!(m0));
194            ops.cx(cast!(offset + 5), cast!(m0 + 1));
195            ops.cx(cast!(offset + 5), cast!(m0 + 2));
196            ops.cx(cast!(offset + 6), cast!(m0));
197            ops.cx(cast!(offset + 6), cast!(m0 + 1));
198
199            for j in 0..PHYSQUBIT_PER_LOGQUBIT {
200                ops.h(cast!(offset + j));
201            }
202            ops.cx(cast!(offset), cast!(m0 + 3));
203            ops.cx(cast!(offset), cast!(m0 + 5));
204            ops.cx(cast!(offset + 1), cast!(m0 + 4));
205            ops.cx(cast!(offset + 1), cast!(m0 + 5));
206            ops.cx(cast!(offset + 2), cast!(m0 + 3));
207            ops.cx(cast!(offset + 2), cast!(m0 + 4));
208            ops.cx(cast!(offset + 2), cast!(m0 + 5));
209            ops.cx(cast!(offset + 3), cast!(m0 + 3));
210            ops.cx(cast!(offset + 4), cast!(m0 + 4));
211            ops.cx(cast!(offset + 5), cast!(m0 + 5));
212            ops.cx(cast!(offset + 6), cast!(m0 + 3));
213            ops.cx(cast!(offset + 6), cast!(m0 + 4));
214            for j in 0..MEASURE_ANCILLA_QUBITS {
215                ops.measure(cast!(m0 + j), cast!(j));
216            }
217            let mut buf = self.instance.make_buffer();
218            self.instance.send_receive(ops.as_ref(), &mut buf);
219            let measured = buf.get_range_u8(0, MEASURE_ANCILLA_QUBITS as usize);
220            // eprintln!("logical qubit: {}, measured: {:b}", i, measured);
221            ops.clear();
222            for j in 0..MEASURE_ANCILLA_QUBITS {
223                // reset
224                if measured & (1 << j) != 0 {
225                    ops.x(cast!(m0 + j));
226                }
227            }
228            if measured & 7 > 0 {
229                let err_x = ERR_TABLE_X[(measured & 7) as usize] + i * PHYSQUBIT_PER_LOGQUBIT;
230                // eprintln!("Z Err on {}", err_x);
231                ops.z(cast!(err_x));
232            }
233            if (measured >> 3) > 0 {
234                let err_z = ERR_TABLE_Z[(measured >> 3) as usize] + i * PHYSQUBIT_PER_LOGQUBIT;
235                // eprintln!("X Err on {}", err_z);
236                ops.x(cast!(err_z));
237            }
238        }
239        // eprintln!("END   syndrome_measure_and_recover");
240    }
241
242    fn x(&mut self, q: u32, ops: &mut OpsVec<L>) {
243        for i in (q * PHYSQUBIT_PER_LOGQUBIT)..(q * PHYSQUBIT_PER_LOGQUBIT + PHYSQUBIT_PER_LOGQUBIT) {
244            ops.x(cast!(i));
245        }
246    }
247
248    fn y(&mut self, q: u32, ops: &mut OpsVec<L>) {
249        for i in (q * PHYSQUBIT_PER_LOGQUBIT)..(q * PHYSQUBIT_PER_LOGQUBIT + PHYSQUBIT_PER_LOGQUBIT) {
250            ops.y(cast!(i));
251        }
252    }
253
254    fn z(&mut self, q: u32, ops: &mut OpsVec<L>) {
255        for i in (q * PHYSQUBIT_PER_LOGQUBIT)..(q * PHYSQUBIT_PER_LOGQUBIT + PHYSQUBIT_PER_LOGQUBIT) {
256            ops.z(cast!(i));
257        }
258    }
259
260    fn h(&mut self, q: u32, ops: &mut OpsVec<L>) {
261        for i in (q * PHYSQUBIT_PER_LOGQUBIT)..(q * PHYSQUBIT_PER_LOGQUBIT + PHYSQUBIT_PER_LOGQUBIT) {
262            ops.h(cast!(i));
263        }
264    }
265
266    fn s(&mut self, q: u32, ops: &mut OpsVec<L>) {
267        for i in (q * PHYSQUBIT_PER_LOGQUBIT)..(q * PHYSQUBIT_PER_LOGQUBIT + PHYSQUBIT_PER_LOGQUBIT) {
268            ops.s(cast!(i));
269        }
270    }
271
272    fn sdg(&mut self, q: u32, ops: &mut OpsVec<L>) {
273        for i in (q * PHYSQUBIT_PER_LOGQUBIT)..(q * PHYSQUBIT_PER_LOGQUBIT + PHYSQUBIT_PER_LOGQUBIT) {
274            ops.sdg(cast!(i));
275        }
276    }
277
278    fn cx(&mut self, c: u32, t: u32, ops: &mut OpsVec<L>) {
279        for i in 0..PHYSQUBIT_PER_LOGQUBIT {
280            ops.cx(cast!(c * PHYSQUBIT_PER_LOGQUBIT + i), cast!(t * PHYSQUBIT_PER_LOGQUBIT + i));
281        }
282    }
283
284    fn measure(&mut self, q: u32, s: u32, ops: &mut OpsVec<L>) {
285        let m0 = self.measure_ancilla();
286        for i in 0..PHYSQUBIT_PER_LOGQUBIT {
287            ops.cx(cast!(q * PHYSQUBIT_PER_LOGQUBIT + i), cast!(m0));
288        }
289        ops.measure(cast!(m0), cast!(0));
290        self.instance.send_receive(ops.as_ref(), &mut self.instance_buf);
291        ops.clear();
292        let result = self.instance_buf.get(cast!(0));
293        self.measured[s as usize] = result;
294        // eprintln!("Slot {}, measure: {}", s, result as u8);
295        if result {
296            ops.x(cast!(m0));
297        }
298    }
299}
300
301pub trait Syndrome<L>
302where
303        L : Layer + PauliGate + HGate + SGate + CXGate,
304        L::Operation : Operation<L>,
305        L::Qubit : NumCast,
306        L::Slot : NumCast
307{
308    fn syndrome(&mut self);
309}
310
311impl<L> Syndrome<L> for OpsVec<SteaneLayer<L>>
312where
313        L : Layer + PauliGate + HGate + SGate + CXGate,
314        L::Operation : Operation<L> + PauliOperation<L> + HOperation<L> + SOperation<L> + CXOperation<L>,
315        L::Qubit : NumCast,
316        L::Slot : NumCast
317{
318    fn syndrome(&mut self) {
319        self.as_mut_vec().push(OpArgs::Empty(opid::USERDEF));
320    }
321}
322
323#[cfg(test)]
324mod tests {
325    #[allow(unused_imports)]
326    use lay::{Layer, OpsVec, Measured};
327    #[allow(unused_imports)]
328    use lay_simulator_gk::{ GottesmanKnillSimulator, DefaultRng };
329    #[allow(unused_imports)]
330    use crate::{SteaneLayer, Syndrome};
331
332    #[test]
333    fn initialize() {
334        let mut steane = SteaneLayer::from_seed_with_gk(16, 1);
335        let mut ops = OpsVec::<SteaneLayer<_>>::new();
336        ops.initialize();
337        steane.send(ops.as_ref());
338    }
339
340    #[test]
341    fn initialize_and_measure() {
342        let mut steane = SteaneLayer::from_seed_with_gk(16, 1);
343        let mut ops = steane.opsvec();
344        let mut buf = steane.make_buffer();
345        ops.initialize();
346        ops.x(1);
347        ops.measure(0, 0);
348        ops.measure(1, 1);
349        steane.send_receive(ops.as_ref(), &mut buf);
350        assert_eq!(buf.get(0), false);
351        assert_eq!(buf.get(1), true);
352    }
353
354    #[test]
355    fn cx() {
356        let mut steane = SteaneLayer::from_seed_with_gk(4, 4);
357        let mut ops = steane.opsvec();
358        let mut buf = steane.make_buffer();
359        ops.initialize();
360        ops.x(1);
361        ops.cx(1, 0);
362        ops.measure(0, 0);
363        for i in 0..10 {
364            steane.send_receive(ops.as_ref(), &mut buf);
365            assert!(buf.get(0));
366        }
367    }
368
369    #[test]
370    fn cx2() {
371        let mut steane = SteaneLayer::from_seed_with_gk(4, 4);
372        let mut ops = steane.opsvec();
373        let mut buf = steane.make_buffer();
374        ops.initialize();
375        ops.x(1);
376        ops.cx(1, 0);
377        ops.measure(0, 0);
378        ops.measure(1, 1);
379        for i in 0..10 {
380            steane.send_receive(ops.as_ref(), &mut buf);
381            assert!(buf.get(0));
382            assert!(buf.get(1));
383        }
384    }
385
386    #[test]
387    fn cx3() {
388        let mut steane = SteaneLayer::from_seed_with_gk(4, 4);
389        let mut ops = steane.opsvec();
390        let mut buf = steane.make_buffer();
391        ops.initialize();
392        ops.cx(0, 2);
393        ops.measure(0, 0);
394        ops.measure(2, 2);
395        for i in 0..10 {
396            steane.send_receive(ops.as_ref(), &mut buf);
397            assert!(!buf.get(0));
398            assert!(!buf.get(2));
399        }
400    }
401
402    #[test]
403    fn bell() {
404        let mut steane = SteaneLayer::from_seed_with_gk(4, 4);
405        let mut ops = steane.opsvec();
406        let mut buf = steane.make_buffer();
407        ops.initialize();
408        ops.h(1);
409        ops.cx(1, 0);
410        ops.measure(0, 0);
411        ops.measure(1, 1);
412        for i in 0..10 {
413            steane.send_receive(ops.as_ref(), &mut buf);
414            eprintln!("try: {}, |{}{}>", i, buf.get(0) as u8, buf.get(1) as u8);
415            assert_eq!(buf.get(0), buf.get(1));
416        }
417    }
418
419    #[test]
420    fn ghz() {
421        let mut steane = SteaneLayer::from_seed_with_gk(4, 4);
422        let mut ops = steane.opsvec();
423        let mut buf = steane.make_buffer();
424        ops.initialize();
425        ops.h(1);
426        ops.cx(1, 0);
427        ops.cx(1, 2);
428        ops.measure(0, 0);
429        ops.measure(1, 1);
430        ops.measure(2, 2);
431        for i in 0..10 {
432            steane.send_receive(ops.as_ref(), &mut buf);
433            let m0 = buf.get(0);
434            let m1 = buf.get(1);
435            let m2 = buf.get(2);
436            eprintln!("try: {}, |{}{}{}>", i, m0 as u8, m1 as u8, m2 as u8);
437            assert_eq!(m0, m1);
438            assert_eq!(m0, m2);
439        }
440    }
441
442    #[cfg(feature = "test-blueqat")]
443    #[test]
444    fn bell_bq() {
445        use lay_simulator_blueqat::BlueqatSimulator;
446        let mut steane = SteaneLayer::from_instance(
447            BlueqatSimulator::new().unwrap(),
448            2,
449        );
450        let mut ops = steane.opsvec();
451        let mut buf = steane.make_buffer();
452        ops.initialize();
453        ops.h(1);
454        ops.cx(1, 0);
455        ops.measure(0, 0);
456        let mut ops2 = steane.opsvec();
457        ops2.measure(1, 1);
458        for i in 0..10 {
459            steane.send_receive(ops.as_ref(), &mut buf).unwrap();
460            let s0 = buf.get(0);
461            steane.send_receive(ops2.as_ref(), &mut buf).unwrap();
462            let s1 = buf.get(1);
463            eprintln!("try: {}, |{}{}>", i, buf.get(0) as u8, buf.get(1) as u8);
464            assert_eq!(s0, s1);
465        }
466    }
467}