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
44static 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 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 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 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}