lay_simulator_blueqat/
lib.rs

1use std::sync::atomic;
2use lay::{Layer, Measured, OpsVec, operations::{opid, OpArgs}};
3use lay::gates::{PauliGate, CXGate, HGate, SGate, TGate};
4use cpython::{Python, PyResult};
5
6pub fn raw_pyscript(s: String) -> OpArgs<BlueqatSimulator> {
7    OpArgs::Var(opid::USERDEF, Box::new(s))
8}
9
10pub trait RawScriptGate {
11    fn raw_pyscript(&mut self, s: String);
12}
13
14impl RawScriptGate for OpsVec<BlueqatSimulator> {
15    fn raw_pyscript(&mut self, s: String) {
16        self.as_mut_vec().push(raw_pyscript(s));
17    }
18}
19
20const UNASSIGNED: u32 = 0xffffffff;
21
22#[derive(Debug)]
23pub struct BlueqatSimulator {
24    slot: [u32; 64],
25}
26
27#[derive(Debug)]
28pub struct BlueqatMeasured([bool; 64]);
29
30impl BlueqatMeasured {
31    pub fn new() -> BlueqatMeasured {
32        Self([false; 64])
33    }
34}
35
36impl Measured for BlueqatMeasured {
37    type Slot = u32;
38    fn get(&self, n: u32) -> bool {
39        (self.0)[n as usize]
40    }
41}
42
43
44// BlueqatSimulator is a singleton.
45// ... If I make circuit as local scope or make unique id as variable name,
46// singleton is not necessary.
47static USED: atomic::AtomicBool = atomic::AtomicBool::new(false);
48
49impl BlueqatSimulator {
50    fn import_blueqat() -> PyResult<()> {
51        Python::acquire_gil().python().run(include_str!("blueqat_initialize.py"), None, None)
52    }
53
54    pub fn new() -> Result<Self, ()> {
55        if USED.swap(true, atomic::Ordering::SeqCst) {
56            return Err(());
57        }
58        // This error handling is too crude.
59        Self::import_blueqat().map_err(|_| ())?;
60        Ok(Self { slot: [UNASSIGNED; 64] })
61    }
62
63    #[inline]
64    fn op_to_script(op: &OpArgs<BlueqatSimulator>) -> String {
65        match op {
66            OpArgs::Empty(id) if *id == opid::INIT =>
67                "c = Circuit()".to_owned(),
68            OpArgs::QS(id, q, _) if *id == opid::MEAS => {
69                //assert_eq!(q, s, "Qubit and slot must be same in this simulator.");
70                format!("c.m[{}]", q)
71            }
72            OpArgs::QQ(id, c, t) if *id == opid::CX =>
73                format!("c.cx[{}, {}]", c, t),
74            OpArgs::Q(id, q) if *id == opid::X =>
75                format!("c.x[{}]", q),
76            OpArgs::Q(id, q) if *id == opid::Y =>
77                format!("c.y[{}]", q),
78            OpArgs::Q(id, q) if *id == opid::Z =>
79                format!("c.z[{}]", q),
80            OpArgs::Q(id, q) if *id == opid::H =>
81                format!("c.h[{}]", q),
82            OpArgs::Q(id, q) if *id == opid::S =>
83                format!("c.s[{}]", q),
84            OpArgs::Q(id, q) if *id == opid::SDG =>
85                format!("c.sdg[{}]", q),
86            OpArgs::Q(id, q) if *id == opid::T =>
87                format!("c.t[{}]", q),
88            OpArgs::Q(id, q) if *id == opid::TDG =>
89                format!("c.tdg[{}]", q),
90            OpArgs::Var(id, cmd) if *id == opid::USERDEF => {
91                cmd.downcast_ref::<String>().unwrap().clone()
92            }
93            _ => unimplemented!("Unknown op {:?}", op)
94        }
95    }
96
97    fn ops_to_script(ops: &[OpArgs<BlueqatSimulator>]) -> String {
98        ops.iter().map(Self::op_to_script).collect::<Vec<_>>().join("\n")
99    }
100
101    fn assign_slot(&mut self, ops: &[OpArgs<BlueqatSimulator>]) {
102        for op in ops {
103            if let OpArgs::QS(id, q, s) = op {
104                if *id != opid::MEAS { continue; }
105                if self.slot[*q as usize] == UNASSIGNED {
106                    self.slot[*q as usize] = *s as u32;
107                } else {
108                    panic!("This simulator cannot measure same qubit without receive former result.");
109                }
110            }
111        }
112    }
113
114    fn write_buf_reset_slot(&mut self, measured: &str, buf: &mut BlueqatMeasured) {
115        let measured = measured.as_bytes();
116        for (q, s) in self.slot.iter_mut().enumerate() {
117            if *s != UNASSIGNED {
118                (buf.0)[*s as usize] = measured[q] == b'1';
119                *s = UNASSIGNED;
120            }
121        }
122    }
123}
124
125impl Drop for BlueqatSimulator {
126    fn drop(&mut self) {
127        USED.store(false, atomic::Ordering::SeqCst);
128    }
129}
130
131impl PauliGate for BlueqatSimulator {}
132impl HGate for BlueqatSimulator {}
133impl SGate for BlueqatSimulator {}
134impl TGate for BlueqatSimulator {}
135impl CXGate for BlueqatSimulator {}
136
137impl Layer for BlueqatSimulator {
138    type Operation = OpArgs<Self>;
139    type Qubit = u32;
140    type Slot = u32;
141    type Buffer = BlueqatMeasured;
142    type Requested = PyResult<()>;
143    type Response = PyResult<()>;
144
145    fn send(&mut self, ops: &[OpArgs<Self>]) -> Self::Requested {
146        let script = Self::ops_to_script(ops);
147        self.assign_slot(ops);
148        eprintln!("{}", script);
149        eprintln!("# --- send ---");
150        Python::acquire_gil().python().run(&script, None, None)?;
151        Ok(())
152    }
153
154    fn receive(&mut self, buf: &mut Self::Buffer) -> Self::Response {
155        let s = Python::acquire_gil().python()
156                                         .eval("c.run(shots=1).most_common()[0][0]", None, None)?
157                                         .to_string();
158        eprintln!("# --- receive ---");
159        self.write_buf_reset_slot(&s, buf);
160        eprintln!("# raw: {}", s);
161        eprint!("# map: ");
162        for b in 0..s.len() {
163            eprint!("{}", buf.get(b as u32) as u8);
164        }
165        eprintln!();
166        Ok(())
167    }
168
169    fn send_receive(&mut self, ops: &[OpArgs<Self>], buf: &mut Self::Buffer) -> Self::Response {
170        let script = Self::ops_to_script(ops);
171        self.assign_slot(ops);
172        Python::acquire_gil().python().run(&script, None, None)?;
173        //eprintln!("Circuit: {}", Python::acquire_gil().python().eval("c", None, None).unwrap().to_string());
174        let s = Python::acquire_gil().python()
175                                         .eval("c.run(shots=1).most_common()[0][0]", None, None)?
176                                         .to_string();
177        eprintln!("{}", script);
178        eprintln!("# --- send_receive ---");
179        self.write_buf_reset_slot(&s, buf);
180        eprintln!("# raw: {}", s);
181        eprint!("# map: ");
182        for b in 0..s.len() {
183            eprint!("{}", buf.get(b as u32) as u8);
184        }
185        eprintln!();
186        Ok(())
187    }
188
189    fn make_buffer(&self) -> Self::Buffer {
190        Self::Buffer::new()
191    }
192}
193
194#[cfg(test)]
195mod tests {
196    use crate::{BlueqatSimulator, BlueqatMeasured, RawScriptGate};
197    use lay::{Layer, Measured, OpsVec};
198
199    #[test]
200    fn it_works() {
201        assert_eq!(2 + 2, 4);
202    }
203
204    #[test]
205    fn python_raw() {
206        let mut sim = BlueqatSimulator::new().unwrap();
207        let mut ops = OpsVec::new();
208
209        ops.initialize();
210        ops.raw_pyscript("import numpy as np".to_owned());
211        ops.raw_pyscript("print(np.eye(2))".to_owned());
212        ops.raw_pyscript("if True: c.x[0]".to_owned());
213        ops.raw_pyscript("if False: c.x[1]".to_owned());
214        ops.measure(0, 0);
215        ops.measure(1, 1);
216        let mut measured = BlueqatMeasured::new();
217        sim.send_receive(ops.as_ref(), &mut measured).unwrap();
218        assert_eq!(measured.get(0), true);
219        assert_eq!(measured.get(1), false);
220    }
221}