1use super::simulator::*;
11use super::types::*;
12use super::util_macros::*;
13use super::visualize::*;
14use clap::ValueEnum;
15#[cfg(feature = "python_binding")]
16use pyo3::prelude::*;
17use serde::{Deserialize, Serialize};
18use ErrorType::*;
19
20#[cfg_attr(feature = "python_binding", pyclass)]
23#[derive(Debug, Clone, Serialize, Deserialize, ValueEnum, PartialEq, Eq, PartialOrd, Ord, Copy)]
24#[serde(deny_unknown_fields)]
25pub enum CodeType {
26 StandardPlanarCode,
28 RotatedPlanarCode,
30 StandardXZZXCode,
32 RotatedXZZXCode,
34 StandardTailoredCode,
36 RotatedTailoredCode,
38 RotatedTailoredCodeBellInit,
40 PeriodicRotatedTailoredCode,
42 Customized,
44}
45
46#[cfg_attr(feature = "python_binding", cfg_eval)]
48#[cfg_attr(feature = "python_binding", pyclass)]
49#[derive(Debug, Serialize, Clone)]
50pub struct CodeSize {
51 #[cfg_attr(feature = "python_binding", pyo3(get, set))]
52 pub noisy_measurements: usize,
53 #[cfg_attr(feature = "python_binding", pyo3(get, set))]
54 pub di: usize,
55 #[cfg_attr(feature = "python_binding", pyo3(get, set))]
56 pub dj: usize,
57}
58
59#[cfg_attr(feature = "python_binding", cfg_eval)]
60#[cfg_attr(feature = "python_binding", pymethods)]
61impl CodeSize {
62 #[cfg_attr(feature = "python_binding", new)]
63 pub fn new(noisy_measurements: usize, di: usize, dj: usize) -> Self {
64 CodeSize {
65 noisy_measurements,
66 di,
67 dj,
68 }
69 }
70}
71
72#[cfg_attr(feature = "python_binding", pymethods)]
73impl CodeType {
74 pub fn get_left(&self, i: usize, j: usize, code_size: &CodeSize) -> (usize, usize) {
76 match self {
77 &CodeType::RotatedTailoredCode | &CodeType::RotatedTailoredCodeBellInit => {
78 if j > 0 {
79 (i, j - 1)
80 } else {
81 (i, usize::MAX)
82 }
83 }
84 &CodeType::PeriodicRotatedTailoredCode => {
85 let dp = code_size.di;
86 let dn = code_size.dj;
87 let (di, dj) = (dp - 1, dn - 1);
88 if i + j == dj {
89 (i + (di + 1), j + di)
90 } else if i == j + dj + 1 {
91 (i - (dj + 1), j + dj)
92 } else {
93 (i, j - 1)
94 }
95 }
96 _ => unimplemented!("left position not implemented for this code type, please fill the implementation"),
97 }
98 }
99
100 pub fn get_up(&self, i: usize, j: usize, code_size: &CodeSize) -> (usize, usize) {
102 match self {
103 &CodeType::RotatedTailoredCode | &CodeType::RotatedTailoredCodeBellInit => {
104 if i > 0 {
105 (i - 1, j)
106 } else {
107 (usize::MAX, j)
108 }
109 }
110 &CodeType::PeriodicRotatedTailoredCode => {
111 let dp = code_size.di;
112 let dn = code_size.dj;
113 let (di, dj) = (dp - 1, dn - 1);
114 if i == 0 && j == dj {
115 (di + dj + 1, di)
116 } else if i + j == dj {
117 (i + di, j + (di + 1))
118 } else if j == i + dj {
119 (i + dj, j - (dj + 1))
120 } else {
121 (i - 1, j)
122 }
123 }
124 _ => unimplemented!("left position not implemented for this code type, please fill the implementation"),
125 }
126 }
127
128 pub fn get_right(&self, i: usize, j: usize, code_size: &CodeSize) -> (usize, usize) {
130 match self {
131 &CodeType::RotatedTailoredCode | &CodeType::RotatedTailoredCodeBellInit => (i, j + 1),
132 &CodeType::PeriodicRotatedTailoredCode => {
133 let dp = code_size.di;
134 let dn = code_size.dj;
135 let (di, dj) = (dp - 1, dn - 1);
136 if i + j == 2 * di + dj + 1 {
137 (i - (di + 1), j - di)
138 } else if j == i + dj {
139 (i + (dj + 1), j - dj)
140 } else {
141 (i, j + 1)
142 }
143 }
144 _ => unimplemented!("left position not implemented for this code type, please fill the implementation"),
145 }
146 }
147
148 pub fn get_down(&self, i: usize, j: usize, code_size: &CodeSize) -> (usize, usize) {
150 match self {
151 &CodeType::RotatedTailoredCode | &CodeType::RotatedTailoredCodeBellInit => (i + 1, j),
152 &CodeType::PeriodicRotatedTailoredCode => {
153 let dp = code_size.di;
154 let dn = code_size.dj;
155 let (di, dj) = (dp - 1, dn - 1);
156 if i == di + dj + 1 && j == di {
157 (0, dj)
158 } else if i + j == 2 * di + dj + 1 {
159 (i - di, j - (di + 1))
160 } else if i == j + dj + 1 {
161 (i - dj, j + (dj + 1))
162 } else {
163 (i + 1, j)
164 }
165 }
166 _ => unimplemented!("left position not implemented for this code type, please fill the implementation"),
167 }
168 }
169
170 pub fn get_left_up(&self, i: usize, j: usize, code_size: &CodeSize) -> (usize, usize) {
172 let (i, j) = self.get_left(i, j, code_size);
173 self.get_up(i, j, code_size)
174 }
175
176 pub fn get_left_down(&self, i: usize, j: usize, code_size: &CodeSize) -> (usize, usize) {
178 let (i, j) = self.get_left(i, j, code_size);
179 self.get_down(i, j, code_size)
180 }
181
182 pub fn get_right_up(&self, i: usize, j: usize, code_size: &CodeSize) -> (usize, usize) {
184 let (i, j) = self.get_right(i, j, code_size);
185 self.get_up(i, j, code_size)
186 }
187
188 pub fn get_right_down(&self, i: usize, j: usize, code_size: &CodeSize) -> (usize, usize) {
190 let (i, j) = self.get_right(i, j, code_size);
191 self.get_down(i, j, code_size)
192 }
193}
194
195pub fn build_code(simulator: &mut Simulator) {
196 let code_type = &simulator.code_type;
197 let code_size = &simulator.code_size;
198 match code_type {
199 &CodeType::StandardPlanarCode | &CodeType::RotatedPlanarCode => {
200 let di = code_size.di;
201 let dj = code_size.dj;
202 let noisy_measurements = code_size.noisy_measurements;
203 simulator.measurement_cycles = 6;
204 assert!(di > 0, "code distance must be positive integer");
205 assert!(dj > 0, "code distance must be positive integer");
206 let is_rotated = matches!(code_type, CodeType::RotatedPlanarCode { .. });
207 if is_rotated {
208 assert!(di % 2 == 1, "code distance must be odd integer, current: di = {}", di);
209 assert!(dj % 2 == 1, "code distance must be odd integer, current: dj = {}", dj);
210 }
211 let (vertical, horizontal) = if is_rotated {
213 (di + dj + 1, di + dj + 1)
214 } else {
215 (2 * di + 1, 2 * dj + 1)
216 };
217 let height = simulator.measurement_cycles * (noisy_measurements + 1) + 1;
218 let mut nodes = Vec::with_capacity(height);
220 let is_real = |i: usize, j: usize| -> bool {
221 if is_rotated {
222 let is_real_dj = |pi, pj| pi + pj < dj || (pi + pj == dj && pi % 2 == 0 && pi > 0);
223 let is_real_di = |pi, pj| pi + pj < di || (pi + pj == di && pj % 2 == 0 && pj > 0);
224 if i <= dj && j <= dj {
225 is_real_dj(dj - i, dj - j)
226 } else if i >= di && j >= di {
227 is_real_dj(i - di, j - di)
228 } else if i >= dj && j <= di {
229 is_real_di(i - dj, di - j)
230 } else if i <= di && j >= dj {
231 is_real_di(di - i, j - dj)
232 } else {
233 unreachable!()
234 }
235 } else {
236 i > 0 && j > 0 && i < vertical - 1 && j < horizontal - 1
237 }
238 };
239 let is_virtual = |i: usize, j: usize| -> bool {
240 if is_rotated {
241 let is_virtual_dj = |pi, pj| pi + pj == dj && (pi % 2 == 1 || pi == 0);
242 let is_virtual_di = |pi, pj| pi + pj == di && (pj % 2 == 1 || pj == 0);
243 if i <= dj && j <= dj {
244 is_virtual_dj(dj - i, dj - j)
245 } else if i >= di && j >= di {
246 is_virtual_dj(i - di, j - di)
247 } else if i >= dj && j <= di {
248 is_virtual_di(i - dj, di - j)
249 } else if i <= di && j >= dj {
250 is_virtual_di(di - i, j - dj)
251 } else {
252 unreachable!()
253 }
254 } else if i == 0 || i == vertical - 1 {
255 j % 2 == 1
256 } else if j == 0 || j == horizontal - 1 {
257 i % 2 == 1
258 } else {
259 false
260 }
261 };
262 let is_present = |i: usize, j: usize| -> bool {
263 let is_this_real = is_real(i, j);
264 let is_this_virtual = is_virtual(i, j);
265 assert!(
266 !(is_this_real && is_this_virtual),
267 "a position cannot be both real and virtual"
268 );
269 is_this_real || is_this_virtual
270 };
271 for t in 0..height {
272 let mut row_i = Vec::with_capacity(vertical);
273 for i in 0..vertical {
274 let mut row_j = Vec::with_capacity(horizontal);
275 for j in 0..horizontal {
276 if is_present(i, j) {
277 let qubit_type = if (i + j) % 2 == 0 {
278 assert!(is_real(i, j), "data qubits should not be virtual");
279 QubitType::Data
280 } else if i % 2 == 1 {
281 QubitType::StabZ
282 } else {
283 QubitType::StabX
284 };
285 let mut gate_type = GateType::None;
286 let mut gate_peer = None;
287 match t % simulator.measurement_cycles {
288 1 => {
289 match qubit_type {
291 QubitType::StabZ => {
292 gate_type = GateType::InitializeZ;
293 }
294 QubitType::StabX => {
295 gate_type = GateType::InitializeX;
296 }
297 QubitType::Data => {}
298 _ => {
299 unreachable!()
300 }
301 }
302 }
303 2 => {
304 if qubit_type == QubitType::Data {
306 if i + 1 < vertical && is_present(i + 1, j) {
307 gate_type = if j % 2 == 1 {
308 GateType::CXGateTarget
309 } else {
310 GateType::CXGateControl
311 };
312 gate_peer = Some(pos!(t, i + 1, j));
313 }
314 } else if i >= 1 && is_present(i - 1, j) {
315 gate_type = if j % 2 == 1 {
316 GateType::CXGateControl
317 } else {
318 GateType::CXGateTarget
319 };
320 gate_peer = Some(pos!(t, i - 1, j));
321 }
322 }
323 3 => {
324 if j % 2 == 1 {
326 if is_present(i, j + 1) {
328 gate_type = GateType::CXGateControl;
329 gate_peer = Some(pos!(t, i, j + 1));
330 }
331 } else {
332 if j >= 1 && is_present(i, j - 1) {
334 gate_type = GateType::CXGateTarget;
335 gate_peer = Some(pos!(t, i, j - 1));
336 }
337 }
338 }
339 4 => {
340 if j % 2 == 1 {
342 if j >= 1 && is_present(i, j - 1) {
344 gate_type = GateType::CXGateControl;
345 gate_peer = Some(pos!(t, i, j - 1));
346 }
347 } else {
348 if is_present(i, j + 1) {
350 gate_type = GateType::CXGateTarget;
351 gate_peer = Some(pos!(t, i, j + 1));
352 }
353 }
354 }
355 5 => {
356 if qubit_type == QubitType::Data {
358 if i >= 1 && is_present(i - 1, j) {
359 gate_type = if j % 2 == 1 {
360 GateType::CXGateTarget
361 } else {
362 GateType::CXGateControl
363 };
364 gate_peer = Some(pos!(t, i - 1, j));
365 }
366 } else if i + 1 < vertical && is_present(i + 1, j) {
367 gate_type = if j % 2 == 1 {
368 GateType::CXGateControl
369 } else {
370 GateType::CXGateTarget
371 };
372 gate_peer = Some(pos!(t, i + 1, j));
373 }
374 }
375 0 => {
376 match qubit_type {
378 QubitType::StabZ => {
379 gate_type = GateType::MeasureZ;
380 }
381 QubitType::StabX => {
382 gate_type = GateType::MeasureX;
383 }
384 QubitType::Data => {}
385 _ => {
386 unreachable!()
387 }
388 }
389 }
390 _ => unreachable!(),
391 }
392 row_j.push(Some(Box::new(
393 SimulatorNode::new(qubit_type, gate_type, gate_peer.clone()).set_virtual(
394 is_virtual(i, j),
395 gate_peer.map_or(false, |peer| is_virtual(peer.i, peer.j)),
396 ),
397 )));
398 } else {
399 row_j.push(None);
400 }
401 }
402 row_i.push(row_j);
403 }
404 nodes.push(row_i)
405 }
406 simulator.vertical = vertical;
407 simulator.horizontal = horizontal;
408 simulator.height = height;
409 simulator.nodes = nodes;
410 }
411 &CodeType::StandardTailoredCode | &CodeType::RotatedTailoredCode | &CodeType::RotatedTailoredCodeBellInit => {
412 let di = code_size.di;
413 let dj = code_size.dj;
414 let noisy_measurements = code_size.noisy_measurements;
415 simulator.measurement_cycles = 6;
416 assert!(di > 0, "code distance must be positive integer");
417 assert!(dj > 0, "code distance must be positive integer");
418 let is_rotated = matches!(code_type, CodeType::RotatedTailoredCode { .. })
419 || matches!(code_type, CodeType::RotatedTailoredCodeBellInit { .. });
420 let is_bell_init = matches!(code_type, CodeType::RotatedTailoredCodeBellInit { .. });
421 if is_rotated {
422 assert!(di % 2 == 1, "code distance must be odd integer, current: di = {}", di);
423 assert!(dj % 2 == 1, "code distance must be odd integer, current: dj = {}", dj);
424 }
425 let (vertical, horizontal) = if is_rotated {
427 (di + dj + 1, di + dj + 1)
428 } else {
429 (2 * di + 1, 2 * dj + 1)
430 };
431 let height = simulator.measurement_cycles * (noisy_measurements + 1) + 1;
432 let mut nodes = Vec::with_capacity(height);
434 let is_real = |i: usize, j: usize| -> bool {
435 if is_rotated {
436 let is_real_dj = |pi, pj| pi + pj < dj || (pi + pj == dj && pi % 2 == 0 && pi > 0);
437 let is_real_di = |pi, pj| pi + pj < di || (pi + pj == di && pj % 2 == 0 && pj > 0);
438 if i <= dj && j <= dj {
439 is_real_dj(dj - i, dj - j)
440 } else if i >= di && j >= di {
441 is_real_dj(i - di, j - di)
442 } else if i >= dj && j <= di {
443 is_real_di(i - dj, di - j)
444 } else if i <= di && j >= dj {
445 is_real_di(di - i, j - dj)
446 } else {
447 unreachable!()
448 }
449 } else {
450 i > 0 && j > 0 && i < vertical - 1 && j < horizontal - 1
451 }
452 };
453 let is_virtual = |i: usize, j: usize| -> bool {
454 if is_rotated {
455 let is_virtual_dj = |pi, pj| pi + pj == dj && (pi % 2 == 1 || pi == 0);
456 let is_virtual_di = |pi, pj| pi + pj == di && (pj % 2 == 1 || pj == 0);
457 if i <= dj && j <= dj {
458 is_virtual_dj(dj - i, dj - j)
459 } else if i >= di && j >= di {
460 is_virtual_dj(i - di, j - di)
461 } else if i >= dj && j <= di {
462 is_virtual_di(i - dj, di - j)
463 } else if i <= di && j >= dj {
464 is_virtual_di(di - i, j - dj)
465 } else {
466 unreachable!()
467 }
468 } else if i == 0 || i == vertical - 1 {
469 j % 2 == 1
470 } else if j == 0 || j == horizontal - 1 {
471 i % 2 == 1
472 } else {
473 false
474 }
475 };
476 let is_present = |i: usize, j: usize| -> bool {
477 let is_this_real = is_real(i, j);
478 let is_this_virtual = is_virtual(i, j);
479 assert!(
480 !(is_this_real && is_this_virtual),
481 "a position cannot be both real and virtual"
482 );
483 is_this_real || is_this_virtual
484 };
485 let is_bell_init_anc = |i: usize, j: usize| -> bool {
487 is_real(i, j) && i < j + dj - 3 && ((i % 4 == 1 && j % 4 == 0) || (i % 4 == 3 && j % 4 == 2))
488 };
489 let is_bell_init_top = |i: usize, j: usize| -> bool {
490 is_real(i, j) && i < j + dj - 1 && ((i % 4 == 0 && j % 4 == 0) || (i % 4 == 2 && j % 4 == 2))
491 };
492 let is_bell_init_left = |i: usize, j: usize| -> bool {
493 is_real(i, j) && i < j + dj - 1 && ((i % 4 == 1 && j % 4 == 3) || (i % 4 == 3 && j % 4 == 1))
494 };
495 let is_bell_init_right = |i: usize, j: usize| -> bool {
496 is_real(i, j) && i < j + dj - 1 && ((i % 4 == 1 && j % 4 == 1) || (i % 4 == 3 && j % 4 == 3))
497 };
498 let is_bell_init_bot = |i: usize, j: usize| -> bool {
499 is_real(i, j) && i < j + dj - 1 && ((i % 4 == 2 && j % 4 == 0) || (i % 4 == 0 && j % 4 == 2))
500 };
501
502 for t in 0..height {
503 let mut row_i = Vec::with_capacity(vertical);
504 for i in 0..vertical {
505 let mut row_j = Vec::with_capacity(horizontal);
506 for j in 0..horizontal {
507 if is_present(i, j) {
508 let qubit_type = if (i + j) % 2 == 0 {
509 assert!(is_real(i, j), "data qubits should not be virtual");
510 QubitType::Data
511 } else if i % 2 == 1 {
512 QubitType::StabY
513 } else {
514 QubitType::StabX
515 };
516 let mut gate_type = GateType::None;
517 let mut gate_peer = None;
518 let (is_corner, peer_corner): (bool, Option<Position>) = if is_rotated {
520 if i == 0 && j == dj {
521 (true, Some(pos!(t, 1, dj + 1)))
522 } else if j == 0 && i == dj {
523 (true, Some(pos!(t, dj - 1, 1)))
524 } else if i == vertical - 1 && j == di {
525 (true, Some(pos!(t, vertical - 2, di - 1)))
526 } else if i == di && j == vertical - 1 {
527 (true, Some(pos!(t, di + 1, vertical - 2)))
528 } else {
529 (false, None)
530 }
531 } else if i == 0 && j == 1 {
532 (true, Some(pos!(t, 1, 0)))
533 } else if i == 1 && j == horizontal - 1 {
534 (true, Some(pos!(t, 0, horizontal - 2)))
535 } else if i == vertical - 2 && j == 0 {
536 (true, Some(pos!(t, vertical - 1, 1)))
537 } else if i == vertical - 1 && j == horizontal - 2 {
538 (true, Some(pos!(t, vertical - 2, horizontal - 1)))
539 } else {
540 (false, None)
541 };
542 if is_bell_init && t > 0 && t <= simulator.measurement_cycles {
543 match t % simulator.measurement_cycles {
545 1 => {
546 if is_bell_init_anc(i, j) && is_bell_init_top(i - 1, j) {
548 gate_type = GateType::CXGateControl;
549 gate_peer = Some(pos!(t, i - 1, j));
550 } else if is_bell_init_top(i, j) && is_bell_init_anc(i + 1, j) {
551 gate_type = GateType::CXGateTarget;
552 gate_peer = Some(pos!(t, i + 1, j));
553 } else {
554 match qubit_type {
555 QubitType::StabY => {
556 gate_type = GateType::InitializeX;
557 }
558 QubitType::StabX => {
559 gate_type = GateType::InitializeX;
560 }
561 QubitType::Data => {}
562 _ => {
563 unreachable!()
564 }
565 }
566 }
567 }
568 2 => {
569 if is_bell_init_anc(i, j) && is_bell_init_left(i, j - 1) {
571 gate_type = GateType::CXGateControl;
572 gate_peer = Some(pos!(t, i, j - 1));
573 }
574 if is_bell_init_left(i, j) && is_bell_init_anc(i, j + 1) {
575 gate_type = GateType::CXGateTarget;
576 gate_peer = Some(pos!(t, i, j + 1));
577 }
578 }
579 3 => {
580 if is_bell_init_anc(i, j) && is_bell_init_right(i, j + 1) {
582 gate_type = GateType::CXGateControl;
583 gate_peer = Some(pos!(t, i, j + 1));
584 }
585 if is_bell_init_right(i, j) && is_bell_init_anc(i, j - 1) {
586 gate_type = GateType::CXGateTarget;
587 gate_peer = Some(pos!(t, i, j - 1));
588 }
589 }
590 4 | 0 => {
591 if is_bell_init_anc(i, j) && is_bell_init_bot(i + 1, j) {
593 gate_type = GateType::CXGateControl;
594 gate_peer = Some(pos!(t, i + 1, j));
595 }
596 if is_bell_init_bot(i, j) && is_bell_init_anc(i - 1, j) {
597 gate_type = GateType::CXGateTarget;
598 gate_peer = Some(pos!(t, i - 1, j));
599 }
600 }
601 5 => {
602 if is_bell_init_anc(i, j) && is_bell_init_bot(i + 1, j) {
604 gate_type = GateType::CXGateTarget;
605 gate_peer = Some(pos!(t, i + 1, j));
606 }
607 if is_bell_init_bot(i, j) && is_bell_init_anc(i - 1, j) {
608 gate_type = GateType::CXGateControl;
609 gate_peer = Some(pos!(t, i - 1, j));
610 }
611 }
612 _ => {
613 unreachable!()
614 }
615 }
616 } else {
617 match t % simulator.measurement_cycles {
619 1 => {
620 match qubit_type {
622 QubitType::StabY => {
623 gate_type = GateType::InitializeX;
624 }
625 QubitType::StabX => {
626 gate_type = GateType::InitializeX;
627 }
628 QubitType::Data => {}
629 _ => {
630 unreachable!()
631 }
632 }
633 }
634 2 => {
635 if qubit_type == QubitType::Data {
637 if i + 1 < vertical && is_present(i + 1, j) {
638 gate_type = if j % 2 == 1 {
639 GateType::CXGateTarget
640 } else {
641 GateType::CYGateTarget
642 };
643 gate_peer = Some(pos!(t, i + 1, j));
644 }
645 } else if i >= 1 && is_present(i - 1, j) {
646 gate_type = if j % 2 == 1 {
647 GateType::CXGateControl
648 } else {
649 GateType::CYGateControl
650 };
651 gate_peer = Some(pos!(t, i - 1, j));
652 }
653 }
654 3 => {
655 if j % 2 == 1 {
657 if is_present(i, j + 1) {
659 gate_type = if qubit_type == QubitType::Data {
660 GateType::CYGateTarget
661 } else {
662 GateType::CXGateControl
663 };
664 gate_peer = Some(pos!(t, i, j + 1));
665 }
666 } else {
667 if j >= 1 && is_present(i, j - 1) {
669 gate_type = if qubit_type == QubitType::Data {
670 GateType::CXGateTarget
671 } else {
672 GateType::CYGateControl
673 };
674 gate_peer = Some(pos!(t, i, j - 1));
675 }
676 }
677 }
678 4 => {
679 if j % 2 == 1 {
681 if j >= 1 && is_present(i, j - 1) {
683 gate_type = if qubit_type == QubitType::Data {
684 GateType::CYGateTarget
685 } else {
686 GateType::CXGateControl
687 };
688 gate_peer = Some(pos!(t, i, j - 1));
689 }
690 } else {
691 if is_present(i, j + 1) {
693 gate_type = if qubit_type == QubitType::Data {
694 GateType::CXGateTarget
695 } else {
696 GateType::CYGateControl
697 };
698 gate_peer = Some(pos!(t, i, j + 1));
699 }
700 }
701 }
702 5 => {
703 if qubit_type == QubitType::Data {
705 if i >= 1 && is_present(i - 1, j) {
706 gate_type = if j % 2 == 1 {
707 GateType::CXGateTarget
708 } else {
709 GateType::CYGateTarget
710 };
711 gate_peer = Some(pos!(t, i - 1, j));
712 }
713 } else if i + 1 < vertical && is_present(i + 1, j) {
714 gate_type = if j % 2 == 1 {
715 GateType::CXGateControl
716 } else {
717 GateType::CYGateControl
718 };
719 gate_peer = Some(pos!(t, i + 1, j));
720 }
721 }
722 0 => {
723 match qubit_type {
725 QubitType::StabY => {
726 gate_type = GateType::MeasureX;
727 }
728 QubitType::StabX => {
729 gate_type = GateType::MeasureX;
730 }
731 QubitType::Data => {}
732 _ => {
733 unreachable!()
734 }
735 }
736 }
737 _ => unreachable!(),
738 }
739 }
740 row_j.push(Some(Box::new(
741 SimulatorNode::new(qubit_type, gate_type, gate_peer.clone())
742 .set_virtual(
743 is_virtual(i, j),
744 gate_peer.map_or(false, |peer| is_virtual(peer.i, peer.j)),
745 )
746 .with_miscellaneous(if is_corner {
747 Some(json!({ "is_corner": true, "peer_corner": peer_corner.unwrap() }))
748 } else {
749 None
750 }),
751 )));
752 } else {
753 row_j.push(None);
754 }
755 }
756 row_i.push(row_j);
757 }
758 nodes.push(row_i)
759 }
760 simulator.vertical = vertical;
761 simulator.horizontal = horizontal;
762 simulator.height = height;
763 simulator.nodes = nodes;
764 }
765 &CodeType::PeriodicRotatedTailoredCode => {
766 let dp = code_size.di;
767 let dn = code_size.dj;
768 let noisy_measurements = code_size.noisy_measurements;
769 simulator.measurement_cycles = 6;
770 assert!(dp > 0, "code distance must be positive integer");
771 assert!(dn > 0, "code distance must be positive integer");
772 assert!(dp % 2 == 0, "code distance must be even integer, current: dp = {}", dp);
773 assert!(dn % 2 == 0, "code distance must be even integer, current: dn = {}", dn);
774 let di = dp - 1; let dj = dn - 1;
777 let (vertical, horizontal) = (di + dj + 2, di + dj + 1);
778 let height = simulator.measurement_cycles * (noisy_measurements + 1) + 1;
779 let mut nodes = Vec::with_capacity(height);
781 let is_present = |i: usize, j: usize| -> bool {
782 let is_present_dj = |pi, pj| pi + pj <= dj;
783 let is_present_di = |pi, pj| pi + pj <= di;
784 let presented = if i <= dj && j <= dj {
785 is_present_dj(dj - i, dj - j)
786 } else if i >= di && j >= di {
787 is_present_dj(i - di, j - di)
788 } else if i >= dj && j <= di {
789 is_present_di(i - dj, di - j)
790 } else if i <= di && j >= dj {
791 is_present_di(di - i, j - dj)
792 } else {
793 unreachable!()
794 };
795 presented || i == j + dj + 1 || i + j == 2 * di + dj + 1
796 };
797 for t in 0..height {
798 let mut row_i = Vec::with_capacity(vertical);
799 for i in 0..vertical {
800 let mut row_j = Vec::with_capacity(horizontal);
801 for j in 0..horizontal {
802 if is_present(i, j) {
803 let qubit_type = if (i + j) % 2 == 0 {
804 QubitType::Data
805 } else if i % 2 == 1 {
806 QubitType::StabY
807 } else {
808 QubitType::StabX
809 };
810 let mut gate_type = GateType::None;
811 let mut gate_peer = None;
812 match t % simulator.measurement_cycles {
813 1 => {
814 match qubit_type {
816 QubitType::StabY => {
817 gate_type = GateType::InitializeX;
818 }
819 QubitType::StabX => {
820 gate_type = GateType::InitializeX;
821 }
822 QubitType::Data => {}
823 _ => {
824 unreachable!()
825 }
826 }
827 }
828 2 => {
829 if qubit_type == QubitType::Data {
831 let (pi, pj) = code_type.get_down(i, j, code_size);
832 gate_type = if j % 2 == 1 {
833 GateType::CXGateTarget
834 } else {
835 GateType::CYGateTarget
836 };
837 gate_peer = Some(pos!(t, pi, pj));
838 } else {
839 let (pi, pj) = code_type.get_up(i, j, code_size);
840 gate_type = if j % 2 == 1 {
841 GateType::CXGateControl
842 } else {
843 GateType::CYGateControl
844 };
845 gate_peer = Some(pos!(t, pi, pj));
846 }
847 }
848 3 => {
849 if j % 2 == 1 {
851 let (pi, pj) = code_type.get_right(i, j, code_size);
853 gate_type = if qubit_type == QubitType::Data {
854 GateType::CYGateTarget
855 } else {
856 GateType::CXGateControl
857 };
858 gate_peer = Some(pos!(t, pi, pj));
859 } else {
860 let (pi, pj) = code_type.get_left(i, j, code_size);
862 gate_type = if qubit_type == QubitType::Data {
863 GateType::CXGateTarget
864 } else {
865 GateType::CYGateControl
866 };
867 gate_peer = Some(pos!(t, pi, pj));
868 }
869 }
870 4 => {
871 if j % 2 == 1 {
873 let (pi, pj) = code_type.get_left(i, j, code_size);
875 gate_type = if qubit_type == QubitType::Data {
876 GateType::CYGateTarget
877 } else {
878 GateType::CXGateControl
879 };
880 gate_peer = Some(pos!(t, pi, pj));
881 } else {
882 let (pi, pj) = code_type.get_right(i, j, code_size);
884 gate_type = if qubit_type == QubitType::Data {
885 GateType::CXGateTarget
886 } else {
887 GateType::CYGateControl
888 };
889 gate_peer = Some(pos!(t, pi, pj));
890 }
891 }
892 5 => {
893 if qubit_type == QubitType::Data {
895 let (pi, pj) = code_type.get_up(i, j, code_size);
896 gate_type = if j % 2 == 1 {
897 GateType::CXGateTarget
898 } else {
899 GateType::CYGateTarget
900 };
901 gate_peer = Some(pos!(t, pi, pj));
902 } else {
903 let (pi, pj) = code_type.get_down(i, j, code_size);
904 gate_type = if j % 2 == 1 {
905 GateType::CXGateControl
906 } else {
907 GateType::CYGateControl
908 };
909 gate_peer = Some(pos!(t, pi, pj));
910 }
911 }
912 0 => {
913 match qubit_type {
915 QubitType::StabY => {
916 gate_type = GateType::MeasureX;
917 }
918 QubitType::StabX => {
919 gate_type = GateType::MeasureX;
920 }
921 QubitType::Data => {}
922 _ => {
923 unreachable!()
924 }
925 }
926 }
927 _ => unreachable!(),
928 }
929 row_j.push(Some(Box::new(SimulatorNode::new(qubit_type, gate_type, gate_peer.clone()))));
930 } else {
931 row_j.push(None);
932 }
933 }
934 row_i.push(row_j);
935 }
936 nodes.push(row_i)
937 }
938 simulator.vertical = vertical;
939 simulator.horizontal = horizontal;
940 simulator.height = height;
941 simulator.nodes = nodes;
942 }
943 CodeType::Customized => {
944 }
946 &CodeType::StandardXZZXCode | &CodeType::RotatedXZZXCode => {
947 let di = code_size.di;
948 let dj = code_size.dj;
949 let noisy_measurements = code_size.noisy_measurements;
950 simulator.measurement_cycles = 6;
951 assert!(di > 0, "code distance must be positive integer");
952 assert!(dj > 0, "code distance must be positive integer");
953 let is_rotated = matches!(code_type, CodeType::RotatedXZZXCode { .. });
954 if is_rotated {
955 assert!(di % 2 == 1, "code distance must be odd integer, current: di = {}", di);
956 assert!(dj % 2 == 1, "code distance must be odd integer, current: dj = {}", dj);
957 }
958 let (vertical, horizontal) = if is_rotated {
960 (di + dj + 1, di + dj + 1)
961 } else {
962 (2 * di + 1, 2 * dj + 1)
963 };
964 let height = simulator.measurement_cycles * (noisy_measurements + 1) + 1;
965 let mut nodes = Vec::with_capacity(height);
967 let is_real = |i: usize, j: usize| -> bool {
968 if is_rotated {
969 let is_real_dj = |pi, pj| pi + pj < dj || (pi + pj == dj && pi % 2 == 0 && pi > 0);
970 let is_real_di = |pi, pj| pi + pj < di || (pi + pj == di && pj % 2 == 0 && pj > 0);
971 if i <= dj && j <= dj {
972 is_real_dj(dj - i, dj - j)
973 } else if i >= di && j >= di {
974 is_real_dj(i - di, j - di)
975 } else if i >= dj && j <= di {
976 is_real_di(i - dj, di - j)
977 } else if i <= di && j >= dj {
978 is_real_di(di - i, j - dj)
979 } else {
980 unreachable!()
981 }
982 } else {
983 i > 0 && j > 0 && i < vertical - 1 && j < horizontal - 1
984 }
985 };
986 let is_virtual = |i: usize, j: usize| -> bool {
987 if is_rotated {
988 let is_virtual_dj = |pi, pj| pi + pj == dj && (pi % 2 == 1 || pi == 0);
989 let is_virtual_di = |pi, pj| pi + pj == di && (pj % 2 == 1 || pj == 0);
990 if i <= dj && j <= dj {
991 is_virtual_dj(dj - i, dj - j)
992 } else if i >= di && j >= di {
993 is_virtual_dj(i - di, j - di)
994 } else if i >= dj && j <= di {
995 is_virtual_di(i - dj, di - j)
996 } else if i <= di && j >= dj {
997 is_virtual_di(di - i, j - dj)
998 } else {
999 unreachable!()
1000 }
1001 } else if i == 0 || i == vertical - 1 {
1002 j % 2 == 1
1003 } else if j == 0 || j == horizontal - 1 {
1004 i % 2 == 1
1005 } else {
1006 false
1007 }
1008 };
1009 let is_present = |i: usize, j: usize| -> bool {
1010 let is_this_real = is_real(i, j);
1011 let is_this_virtual = is_virtual(i, j);
1012 assert!(
1013 !(is_this_real && is_this_virtual),
1014 "a position cannot be both real and virtual"
1015 );
1016 is_this_real || is_this_virtual
1017 };
1018 for t in 0..height {
1019 let mut row_i = Vec::with_capacity(vertical);
1020 for i in 0..vertical {
1021 let mut row_j = Vec::with_capacity(horizontal);
1022 for j in 0..horizontal {
1023 if is_present(i, j) {
1024 let qubit_type = if (i + j) % 2 == 0 {
1025 assert!(is_real(i, j), "data qubits should not be virtual");
1026 QubitType::Data
1027 } else if i % 2 == 1 {
1028 QubitType::StabXZZXLogicalZ
1029 } else {
1030 QubitType::StabXZZXLogicalX
1031 };
1032 let mut gate_type = GateType::None;
1033 let mut gate_peer = None;
1034 match t % simulator.measurement_cycles {
1035 1 => {
1036 match qubit_type {
1038 QubitType::StabXZZXLogicalZ => {
1039 gate_type = GateType::InitializeX;
1040 }
1041 QubitType::StabXZZXLogicalX => {
1042 gate_type = GateType::InitializeX;
1043 }
1044 QubitType::Data => {}
1045 _ => {
1046 unreachable!()
1047 }
1048 }
1049 }
1050 2 => {
1051 if qubit_type == QubitType::Data {
1053 if i + 1 < vertical && is_present(i + 1, j) {
1054 gate_type = GateType::CZGate;
1055 gate_peer = Some(pos!(t, i + 1, j));
1056 }
1057 } else if i >= 1 && is_present(i - 1, j) {
1058 gate_type = GateType::CZGate;
1059 gate_peer = Some(pos!(t, i - 1, j));
1060 }
1061 }
1062 3 => {
1063 if qubit_type == QubitType::Data {
1065 if j + 1 < horizontal && is_present(i, j + 1) {
1066 gate_type = GateType::CXGateTarget;
1067 gate_peer = Some(pos!(t, i, j + 1));
1068 }
1069 } else if j >= 1 && is_present(i, j - 1) {
1070 gate_type = GateType::CXGateControl;
1071 gate_peer = Some(pos!(t, i, j - 1));
1072 }
1073 }
1074 4 => {
1075 if qubit_type == QubitType::Data {
1077 if j >= 1 && is_present(i, j - 1) {
1078 gate_type = GateType::CXGateTarget;
1079 gate_peer = Some(pos!(t, i, j - 1));
1080 }
1081 } else if j + 1 < horizontal && is_present(i, j + 1) {
1082 gate_type = GateType::CXGateControl;
1083 gate_peer = Some(pos!(t, i, j + 1));
1084 }
1085 }
1086 5 => {
1087 if qubit_type == QubitType::Data {
1089 if i >= 1 && is_present(i - 1, j) {
1090 gate_type = GateType::CZGate;
1091 gate_peer = Some(pos!(t, i - 1, j));
1092 }
1093 } else if i + 1 < vertical && is_present(i + 1, j) {
1094 gate_type = GateType::CZGate;
1095 gate_peer = Some(pos!(t, i + 1, j));
1096 }
1097 }
1098 0 => {
1099 match qubit_type {
1101 QubitType::StabXZZXLogicalZ => {
1102 gate_type = GateType::MeasureX;
1103 }
1104 QubitType::StabXZZXLogicalX => {
1105 gate_type = GateType::MeasureX;
1106 }
1107 QubitType::Data => {}
1108 _ => {
1109 unreachable!()
1110 }
1111 }
1112 }
1113 _ => unreachable!(),
1114 }
1115 row_j.push(Some(Box::new(
1116 SimulatorNode::new(qubit_type, gate_type, gate_peer.clone()).set_virtual(
1117 is_virtual(i, j),
1118 gate_peer.map_or(false, |peer| is_virtual(peer.i, peer.j)),
1119 ),
1120 )));
1121 } else {
1122 row_j.push(None);
1123 }
1124 }
1125 row_i.push(row_j);
1126 }
1127 nodes.push(row_i)
1128 }
1129 simulator.vertical = vertical;
1130 simulator.horizontal = horizontal;
1131 simulator.height = height;
1132 simulator.nodes = nodes;
1133 }
1134 }
1135}
1136
1137pub fn visualize_positions(simulator: &Simulator) -> Vec<Vec<VisualizePosition>> {
1139 (0..simulator.vertical)
1140 .map(|i| {
1141 let x = i as f64 - (simulator.vertical as f64 - 1.) / 2.;
1142 (0..simulator.horizontal)
1143 .map(|j| {
1144 let y = j as f64 - (simulator.horizontal as f64 - 1.) / 2.;
1145 VisualizePosition::new(x, y)
1146 })
1147 .collect::<Vec<VisualizePosition>>()
1148 })
1149 .collect::<Vec<Vec<VisualizePosition>>>()
1150}
1151
1152pub fn code_builder_sanity_check(simulator: &Simulator) -> Result<(), String> {
1154 simulator_iter!(simulator, position, node, {
1155 if node.qubit_type == QubitType::Data {
1157 if node.gate_type.is_initialization() {
1158 return Err(format!(
1159 "data qubit at {} cannot be initialized: gate_type = {:?}",
1160 position, node.gate_type
1161 ));
1162 }
1163 if node.gate_type.is_measurement() {
1164 return Err(format!(
1165 "data qubit at {} cannot be initialized: gate_type = {:?}",
1166 position, node.gate_type
1167 ));
1168 }
1169 }
1170 match node.gate_peer.as_ref() {
1171 Some(peer_position) => {
1172 if node.gate_type.is_single_qubit_gate() {
1173 return Err(format!(
1174 "{} has single qubit gate {:?} should not have peer",
1175 position, node.gate_type
1176 ));
1177 }
1178 if !simulator.is_node_exist(peer_position) {
1179 return Err(format!("{}'s peer not exist: {}", position, peer_position));
1180 }
1181 let peer_node = simulator.get_node_unwrap(peer_position);
1182 match &peer_node.gate_peer {
1183 Some(peer_peer_position) => {
1184 if peer_peer_position.as_ref() != position {
1185 return Err(format!(
1186 "{}, as the peer of {}, doesn't have correct peer but {}",
1187 peer_position, position, peer_peer_position
1188 ));
1189 }
1190 if peer_node.gate_type.is_single_qubit_gate() {
1191 return Err(format!(
1192 "{}, as the peer of {}, doesn't have two-qubit gate",
1193 peer_position, position
1194 ));
1195 }
1196 if node.gate_type.peer_gate() != peer_node.gate_type {
1197 return Err(format!(
1198 "{}, as the peer of {}, doesn't have correct peer gate {:?}, the correct one should be {:?}",
1199 peer_position,
1200 position,
1201 node.gate_type.peer_gate(),
1202 peer_node.gate_type
1203 ));
1204 }
1205 }
1206 None => {
1207 return Err(format!(
1208 "{}, as the peer of {}, doesn't have peer which is invalid",
1209 peer_position, position
1210 ))
1211 }
1212 }
1213 }
1214 None => {
1215 if !node.gate_type.is_single_qubit_gate() {
1216 return Err(format!("two qubit gate {:?} should have peer", node.gate_type));
1217 }
1218 }
1219 }
1220 });
1221 simulator_iter!(simulator, base_position, _base_node, t => 0, {
1222 let mut previous_initialization = GateType::None;
1224 for t in 1..simulator.height {
1225 let position = &mut base_position.clone();
1226 position.t = t;
1227 let node = simulator.get_node_unwrap(position);
1228 if node.gate_type.is_initialization() {
1229 previous_initialization = node.gate_type;
1230 }
1231 if node.gate_type.is_measurement() && !node.gate_type.is_corresponding_initialization(&previous_initialization) {
1232 return Err(format!("measurement and initialization not in the same basis: node {} has gate type {:?} but previous initialization is {:?}"
1233 , position, node.gate_type, previous_initialization))
1234 }
1235 }
1236 });
1237 Ok(())
1238}
1239
1240pub fn code_builder_validate_correction(simulator: &mut Simulator, correction: &SparseCorrection) -> Option<(bool, bool)> {
1241 let top_t = simulator.height - 1;
1243 for (position, error) in correction.iter() {
1244 assert_eq!(position.t, top_t, "correction pattern must only be at top layer");
1245 let node = simulator.get_node_mut_unwrap(position);
1246 node.propagated = node.propagated.multiply(error);
1247 }
1248 let code_type = &simulator.code_type;
1250 let code_size = &simulator.code_size;
1251 let result = match code_type {
1252 &CodeType::StandardPlanarCode => {
1253 let mut top_cardinality = 0;
1255 for j in (1..simulator.horizontal).step_by(2) {
1256 let node = simulator.get_node_unwrap(&pos!(top_t, 1, j));
1257 if node.propagated == Z || node.propagated == Y {
1258 top_cardinality += 1;
1259 }
1260 }
1261 let logical_i = top_cardinality % 2 != 0; let mut left_cardinality = 0;
1264 for i in (1..simulator.vertical).step_by(2) {
1265 let node = simulator.get_node_unwrap(&pos!(top_t, i, 1));
1266 if node.propagated == X || node.propagated == Y {
1267 left_cardinality += 1;
1268 }
1269 }
1270 let logical_j = left_cardinality % 2 != 0; Some((logical_i, logical_j))
1272 }
1273 &CodeType::RotatedPlanarCode => {
1274 let dp = code_size.di;
1276 let dn = code_size.dj;
1277 let mut top_cardinality = 0;
1278 for delta in 0..dn {
1279 let node = simulator.get_node_unwrap(&pos!(top_t, dn - delta, 1 + delta));
1280 if node.propagated == Z || node.propagated == Y {
1281 top_cardinality += 1;
1282 }
1283 }
1284 let logical_p = top_cardinality % 2 != 0; let mut left_cardinality = 0;
1287 for delta in 0..dp {
1288 let node = simulator.get_node_unwrap(&pos!(top_t, dn + delta, 1 + delta));
1289 if node.propagated == X || node.propagated == Y {
1290 left_cardinality += 1;
1291 }
1292 }
1293 let logical_n = left_cardinality % 2 != 0; Some((logical_p, logical_n))
1295 }
1296 &CodeType::StandardTailoredCode => {
1297 let mut top_cardinality = 0;
1299 for j in (1..simulator.horizontal).step_by(2) {
1300 let node = simulator.get_node_unwrap(&pos!(top_t, 1, j));
1301 if node.propagated == Y || node.propagated == Z {
1302 top_cardinality += 1;
1303 }
1304 }
1305 let logical_i = top_cardinality % 2 != 0; let mut left_cardinality = 0;
1308 for i in (1..simulator.vertical).step_by(2) {
1309 let node = simulator.get_node_unwrap(&pos!(top_t, i, 1));
1310 if node.propagated == X || node.propagated == Z {
1311 left_cardinality += 1;
1312 }
1313 }
1314 let logical_j = left_cardinality % 2 != 0; Some((logical_i, logical_j))
1316 }
1317 &CodeType::RotatedTailoredCode | &CodeType::RotatedTailoredCodeBellInit => {
1318 let dp = code_size.di;
1320 let dn = code_size.dj;
1321 let mut top_cardinality = 0;
1322 for delta in 0..dn {
1323 let node = simulator.get_node_unwrap(&pos!(top_t, dn - delta, 1 + delta));
1324 if node.propagated == Y || node.propagated == Z {
1325 top_cardinality += 1;
1326 }
1327 }
1328 let logical_p = top_cardinality % 2 != 0; let mut left_cardinality = 0;
1331 for delta in 0..dp {
1332 let node = simulator.get_node_unwrap(&pos!(top_t, dn + delta, 1 + delta));
1333 if node.propagated == X || node.propagated == Z {
1334 left_cardinality += 1;
1335 }
1336 }
1337 let logical_n = left_cardinality % 2 != 0; Some((logical_p, logical_n))
1339 }
1340 &CodeType::PeriodicRotatedTailoredCode => {
1341 let dp = code_size.di;
1342 let dn = code_size.dj;
1343 let mut top_cardinality_y = 0;
1345 let mut top_cardinality_x = 0;
1346 for delta in 0..dn {
1347 let node = simulator.get_node_unwrap(&pos!(top_t, dn - delta, delta));
1348 if node.propagated == Y || node.propagated == Z {
1349 top_cardinality_y += 1;
1350 }
1351 if node.propagated == X || node.propagated == Z {
1352 top_cardinality_x += 1;
1353 }
1354 }
1355 let mut left_cardinality_y = 0;
1357 let mut left_cardinality_x = 0;
1358 for delta in 0..dp {
1359 let node = simulator.get_node_unwrap(&pos!(top_t, dn + delta, delta));
1360 if node.propagated == Y || node.propagated == Z {
1361 left_cardinality_y += 1;
1362 }
1363 if node.propagated == X || node.propagated == Z {
1364 left_cardinality_x += 1;
1365 }
1366 }
1367 let logical_p = top_cardinality_y % 2 != 0 || left_cardinality_y % 2 != 0;
1369 let logical_n = top_cardinality_x % 2 != 0 || left_cardinality_x % 2 != 0;
1370 Some((logical_p, logical_n))
1371 }
1372 &CodeType::StandardXZZXCode => {
1373 let mut top_cardinality = 0;
1375 for j in (1..simulator.horizontal).step_by(2) {
1376 let node = simulator.get_node_unwrap(&pos!(top_t, 1, j));
1377 if node.propagated == X || node.propagated == Y {
1378 top_cardinality += 1;
1379 }
1380 }
1381 let logical_i = top_cardinality % 2 != 0; let mut left_cardinality = 0;
1384 for i in (1..simulator.vertical).step_by(2) {
1385 let node = simulator.get_node_unwrap(&pos!(top_t, i, 1));
1386 if node.propagated == Z || node.propagated == Y {
1387 left_cardinality += 1;
1388 }
1389 }
1390 let logical_j = left_cardinality % 2 != 0; Some((logical_i, logical_j))
1392 }
1393 &CodeType::RotatedXZZXCode => {
1394 let dp = code_size.di;
1395 let dn = code_size.dj;
1396 let mut top_cardinality = 0;
1398 for delta in 0..dn {
1399 let node = simulator.get_node_unwrap(&pos!(top_t, dn - delta, 1 + delta));
1400 if node.propagated == X || node.propagated == Y {
1401 top_cardinality += 1;
1402 }
1403 }
1404 let logical_p = top_cardinality % 2 != 0; let mut left_cardinality = 0;
1407 for delta in 0..dp {
1408 let node = simulator.get_node_unwrap(&pos!(top_t, dn + delta, 1 + delta));
1409 if node.propagated == Z || node.propagated == Y {
1410 left_cardinality += 1;
1411 }
1412 }
1413 let logical_n = left_cardinality % 2 != 0; Some((logical_p, logical_n))
1415 }
1416 _ => None,
1417 };
1418 for (position, error) in correction.iter() {
1420 let node = simulator.get_node_mut_unwrap(position);
1421 node.propagated = node.propagated.multiply(error);
1422 }
1423 result
1424}
1425
1426#[allow(dead_code)]
1428pub fn code_builder_sanity_check_correction(
1429 simulator: &mut Simulator,
1430 correction: &SparseCorrection,
1431) -> Result<(), Vec<Position>> {
1432 let top_t = simulator.height - 1;
1434 for (position, error) in correction.iter() {
1435 assert_eq!(position.t, top_t, "correction pattern must only be at top layer");
1436 let mut position = position.clone();
1437 position.t -= simulator.measurement_cycles; let node = simulator.get_node_mut_unwrap(&position);
1439 node.error = node.error.multiply(error);
1440 }
1441 simulator.clear_propagate_errors();
1442 simulator.propagate_errors();
1443 let mut violating_positions = Vec::new();
1445 simulator_iter_real!(simulator, position, node, t => top_t, {
1446 if node.gate_type.is_measurement() {
1447 let minus_one = node.gate_type.stabilizer_measurement(&node.propagated);
1448 if minus_one {
1449 violating_positions.push(position.clone());
1450 }
1451 }
1452 });
1453 for (position, error) in correction.iter() {
1455 let mut position = position.clone();
1456 position.t -= simulator.measurement_cycles; let node = simulator.get_node_mut_unwrap(&position);
1458 node.error = node.error.multiply(error);
1459 }
1460 simulator.clear_propagate_errors();
1461 simulator.propagate_errors();
1462 if !violating_positions.is_empty() {
1463 Err(violating_positions)
1464 } else {
1465 Ok(())
1466 }
1467}
1468
1469#[cfg(feature = "python_binding")]
1470#[pyfunction]
1471pub(crate) fn register(py: Python<'_>, m: &PyModule) -> PyResult<()> {
1472 m.add_class::<CodeType>()?;
1473 m.add_class::<CodeSize>()?;
1474 use crate::pyo3::PyTypeInfo;
1475 m.add("BuiltinCodeInformation", CodeSize::type_object(py))?; Ok(())
1477}
1478
1479#[cfg(test)]
1480mod tests {
1481 use super::*;
1482
1483 #[macro_export]
1484 macro_rules! assert_measurement {
1485 ($simulator:ident, $errors:expr, $expected_measurements:expr) => {
1486 $simulator.clear_all_errors();
1487 for (position, error) in $errors.iter() {
1488 let node = $simulator.get_node_mut_unwrap(position);
1489 assert_eq!(
1490 node.error,
1491 ErrorType::I,
1492 "do not set the error at a same position twice: {} {}",
1493 position,
1494 error
1495 );
1496 node.error = *error;
1497 }
1498 $simulator.propagate_errors();
1499 assert_eq!(
1500 $simulator.generate_sparse_measurement().to_vec(),
1501 $expected_measurements
1502 );
1503 };
1504 }
1505
1506 #[test]
1507 fn code_builder_standard_planar_code() {
1508 let di = 7;
1510 let dj = 5;
1511 let noisy_measurements = 3;
1512 let mut simulator = Simulator::new(CodeType::StandardPlanarCode, CodeSize::new(noisy_measurements, di, dj));
1513 code_builder_sanity_check(&simulator).unwrap();
1514 {
1515 let mut nodes_count = 0;
1517 let mut virtual_nodes_count = 0;
1518 simulator_iter!(simulator, position, node, {
1519 nodes_count += 1;
1521 if node.is_virtual {
1522 virtual_nodes_count += 1;
1523 }
1524 });
1525 let each_layer_real_node_count = (2 * di - 1) * (2 * dj - 1);
1526 let each_layer_virtual_node_count = 2 * (di + dj);
1527 let layer_count = 6 * (noisy_measurements + 1) + 1;
1528 assert_eq!(
1529 nodes_count,
1530 layer_count * (each_layer_real_node_count + each_layer_virtual_node_count)
1531 );
1532 assert_eq!(virtual_nodes_count, layer_count * each_layer_virtual_node_count);
1533 }
1534 {
1535 {
1537 let node = simulator.get_node_unwrap(&pos!(0, 0, 1));
1538 assert_eq!(node.qubit_type, QubitType::StabX);
1539 assert_eq!(node.gate_type, GateType::MeasureX);
1540 assert!(node.is_virtual);
1541 }
1542 {
1543 let node = simulator.get_node_unwrap(&pos!(0, 0, 2 * dj - 1));
1544 assert_eq!(node.qubit_type, QubitType::StabX);
1545 assert_eq!(node.gate_type, GateType::MeasureX);
1546 assert!(node.is_virtual);
1547 }
1548 {
1549 let node = simulator.get_node_unwrap(&pos!(0, 1, 0));
1550 assert_eq!(node.qubit_type, QubitType::StabZ);
1551 assert_eq!(node.gate_type, GateType::MeasureZ);
1552 assert!(node.is_virtual);
1553 }
1554 {
1555 let node = simulator.get_node_unwrap(&pos!(0, 2 * di - 1, 0));
1556 assert_eq!(node.qubit_type, QubitType::StabZ);
1557 assert_eq!(node.gate_type, GateType::MeasureZ);
1558 assert!(node.is_virtual);
1559 }
1560 {
1561 let node = simulator.get_node_unwrap(&pos!(0, 1, 1));
1562 assert_eq!(node.qubit_type, QubitType::Data);
1563 assert_eq!(node.gate_type, GateType::None);
1564 assert!(!node.is_virtual);
1565 }
1566 {
1567 let node = simulator.get_node_unwrap(&pos!(0, 1, 2));
1568 assert_eq!(node.qubit_type, QubitType::StabZ);
1569 assert_eq!(node.gate_type, GateType::MeasureZ);
1570 assert!(!node.is_virtual);
1571 }
1572 {
1573 let node = simulator.get_node_unwrap(&pos!(0, 2, 1));
1574 assert_eq!(node.qubit_type, QubitType::StabX);
1575 assert_eq!(node.gate_type, GateType::MeasureX);
1576 assert!(!node.is_virtual);
1577 }
1578 }
1579 {
1580 {
1582 let node = simulator.get_node_unwrap(&pos!(1, 1, 1));
1584 assert!(!node.is_peer_virtual);
1585 assert_eq!(node.gate_type, GateType::None);
1586 let node = simulator.get_node_unwrap(&pos!(2, 1, 1));
1587 assert!(!node.is_peer_virtual);
1588 assert_eq!(node.gate_type, GateType::CXGateTarget);
1589 assert_eq!(node.gate_peer.as_ref().map(|x| (**x).clone()), Some(pos!(2, 2, 1)));
1590 let node = simulator.get_node_unwrap(&pos!(3, 1, 1));
1591 assert!(!node.is_peer_virtual);
1592 assert_eq!(node.gate_type, GateType::CXGateControl);
1593 assert_eq!(node.gate_peer.as_ref().map(|x| (**x).clone()), Some(pos!(3, 1, 2)));
1594 let node = simulator.get_node_unwrap(&pos!(4, 1, 1));
1595 assert!(node.is_peer_virtual);
1596 assert_eq!(node.gate_type, GateType::CXGateControl);
1597 assert_eq!(node.gate_peer.as_ref().map(|x| (**x).clone()), Some(pos!(4, 1, 0)));
1598 let node = simulator.get_node_unwrap(&pos!(5, 1, 1));
1599 assert!(node.is_peer_virtual);
1600 assert_eq!(node.gate_type, GateType::CXGateTarget);
1601 assert_eq!(node.gate_peer.as_ref().map(|x| (**x).clone()), Some(pos!(5, 0, 1)));
1602 }
1603 }
1604 {
1605 assert_measurement!(simulator, [(pos!(0, 1, 1), X)], [pos!(6, 1, 2)]);
1608 assert_measurement!(simulator, [(pos!(0, 1, 1), Z)], [pos!(6, 2, 1)]);
1609 assert_measurement!(simulator, [(pos!(0, 1, 1), Y)], [pos!(6, 1, 2), pos!(6, 2, 1)]);
1610 assert_measurement!(simulator, [(pos!(0, 2, 2), X)], [pos!(6, 1, 2), pos!(6, 3, 2)]);
1612 assert_measurement!(simulator, [(pos!(0, 2, 2), Z)], [pos!(6, 2, 1), pos!(6, 2, 3)]);
1613 assert_measurement!(
1614 simulator,
1615 [(pos!(0, 2, 2), Y)],
1616 [pos!(6, 1, 2), pos!(6, 2, 1), pos!(6, 2, 3), pos!(6, 3, 2)]
1617 );
1618 assert_measurement!(simulator, [(pos!(5, 1, 2), X)], [pos!(6, 1, 2), pos!(12, 1, 2)]);
1620 assert_measurement!(simulator, [(pos!(5, 1, 2), Z)], []); assert_measurement!(simulator, [(pos!(5, 1, 2), Y)], [pos!(6, 1, 2), pos!(12, 1, 2)]);
1622 assert_measurement!(simulator, [(pos!(5, 2, 1), X)], []); assert_measurement!(simulator, [(pos!(5, 2, 1), Z)], [pos!(6, 2, 1), pos!(12, 2, 1)]);
1625 assert_measurement!(simulator, [(pos!(5, 2, 1), Y)], [pos!(6, 2, 1), pos!(12, 2, 1)]);
1626 }
1627 }
1628
1629 #[test]
1630 fn code_builder_standard_tailored_code() {
1631 let di = 7;
1633 let dj = 5;
1634 let noisy_measurements = 3;
1635 let mut simulator = Simulator::new(CodeType::StandardTailoredCode, CodeSize::new(noisy_measurements, di, dj));
1636 code_builder_sanity_check(&simulator).unwrap();
1637 {
1638 assert_measurement!(simulator, [(pos!(0, 1, 1), X)], [pos!(6, 1, 2)]);
1641 assert_measurement!(simulator, [(pos!(0, 1, 1), Z)], [pos!(6, 1, 2), pos!(6, 2, 1)]);
1642 assert_measurement!(simulator, [(pos!(0, 1, 1), Y)], [pos!(6, 2, 1)]);
1643 assert_measurement!(simulator, [(pos!(0, 2, 2), X)], [pos!(6, 1, 2), pos!(6, 3, 2)]);
1645 assert_measurement!(
1646 simulator,
1647 [(pos!(0, 2, 2), Z)],
1648 [pos!(6, 1, 2), pos!(6, 2, 1), pos!(6, 2, 3), pos!(6, 3, 2)]
1649 );
1650 assert_measurement!(simulator, [(pos!(0, 2, 2), Y)], [pos!(6, 2, 1), pos!(6, 2, 3)]);
1651 assert_measurement!(simulator, [(pos!(5, 1, 2), X)], []);
1653 assert_measurement!(simulator, [(pos!(5, 1, 2), Z)], [pos!(6, 1, 2), pos!(12, 1, 2)]); assert_measurement!(simulator, [(pos!(5, 1, 2), Y)], [pos!(6, 1, 2), pos!(12, 1, 2)]);
1655 assert_measurement!(simulator, [(pos!(5, 2, 1), X)], []); assert_measurement!(simulator, [(pos!(5, 2, 1), Z)], [pos!(6, 2, 1), pos!(12, 2, 1)]);
1658 assert_measurement!(simulator, [(pos!(5, 2, 1), Y)], [pos!(6, 2, 1), pos!(12, 2, 1)]);
1659 }
1660 }
1661
1662 #[test]
1663 fn code_builder_periodic_rotated_tailored_code() {
1664 let di = 7;
1666 let dj = 5;
1667 let noisy_measurements = 0;
1668 let mut simulator = Simulator::new(
1669 CodeType::PeriodicRotatedTailoredCode,
1670 CodeSize::new(noisy_measurements, di + 1, dj + 1),
1671 );
1672 code_builder_sanity_check(&simulator).unwrap();
1673 {
1674 assert_measurement!(simulator, [(pos!(0, 1, 5), X)], [pos!(6, 1, 4), pos!(6, 1, 6)]);
1677 assert_measurement!(
1678 simulator,
1679 [(pos!(0, 1, 5), Z)],
1680 [pos!(6, 0, 5), pos!(6, 1, 4), pos!(6, 1, 6), pos!(6, 2, 5)]
1681 );
1682 assert_measurement!(simulator, [(pos!(0, 1, 5), Y)], [pos!(6, 0, 5), pos!(6, 2, 5)]);
1683 assert_measurement!(simulator, [(pos!(0, 6, 0), X)], [pos!(6, 1, 6), pos!(6, 5, 0)]);
1685 assert_measurement!(
1686 simulator,
1687 [(pos!(0, 6, 0), Z)],
1688 [pos!(6, 0, 5), pos!(6, 1, 6), pos!(6, 5, 0), pos!(6, 6, 1)]
1689 );
1690 assert_measurement!(simulator, [(pos!(0, 6, 0), Y)], [pos!(6, 0, 5), pos!(6, 6, 1)]);
1691 assert_measurement!(simulator, [(pos!(0, 7, 1), X)], [pos!(6, 1, 6), pos!(6, 7, 2)]);
1693 assert_measurement!(
1694 simulator,
1695 [(pos!(0, 7, 1), Z)],
1696 [pos!(6, 1, 6), pos!(6, 2, 7), pos!(6, 6, 1), pos!(6, 7, 2)]
1697 );
1698 assert_measurement!(simulator, [(pos!(0, 7, 1), Y)], [pos!(6, 2, 7), pos!(6, 6, 1)]);
1699 assert_measurement!(simulator, [(pos!(0, 13, 7), X)], [pos!(6, 5, 0), pos!(6, 7, 12)]);
1701 assert_measurement!(
1702 simulator,
1703 [(pos!(0, 13, 7), Z)],
1704 [pos!(6, 0, 5), pos!(6, 5, 0), pos!(6, 7, 12), pos!(6, 12, 7)]
1705 );
1706 assert_measurement!(simulator, [(pos!(0, 13, 7), Y)], [pos!(6, 0, 5), pos!(6, 12, 7)]);
1707 assert_measurement!(simulator, [(pos!(0, 8, 12), X)], [pos!(6, 1, 4), pos!(6, 7, 12)]);
1709 assert_measurement!(
1710 simulator,
1711 [(pos!(0, 8, 12), Z)],
1712 [pos!(6, 0, 5), pos!(6, 1, 4), pos!(6, 7, 12), pos!(6, 8, 11)]
1713 );
1714 assert_measurement!(simulator, [(pos!(0, 8, 12), Y)], [pos!(6, 0, 5), pos!(6, 8, 11)]);
1715 }
1716 }
1717
1718 #[test]
1719 fn code_builder_visualize_standard_planar_code() {
1720 let visualize_filename = "code_builder_visualize_standard_planar_code.json".to_string();
1722 print_visualize_link(visualize_filename.clone());
1723 let di = 7;
1724 let dj = 5;
1725 let noisy_measurements = 0;
1726 let simulator = Simulator::new(CodeType::StandardPlanarCode, CodeSize::new(noisy_measurements, di, dj));
1727 code_builder_sanity_check(&simulator).unwrap();
1728 let mut visualizer = Visualizer::new(Some(visualize_data_folder() + visualize_filename.as_str())).unwrap();
1729 visualizer.add_component(&simulator).unwrap();
1730 }
1731
1732 #[test]
1733 fn code_builder_visualize_rotated_planar_code() {
1734 let visualize_filename = "code_builder_visualize_rotated_planar_code.json".to_string();
1736 print_visualize_link(visualize_filename.clone());
1737 let di = 7;
1738 let dj = 5;
1739 let noisy_measurements = 0;
1740 let simulator = Simulator::new(CodeType::RotatedPlanarCode, CodeSize::new(noisy_measurements, di, dj));
1741 code_builder_sanity_check(&simulator).unwrap();
1742 let mut visualizer = Visualizer::new(Some(visualize_data_folder() + visualize_filename.as_str())).unwrap();
1743 visualizer.add_component(&simulator).unwrap();
1744 }
1745
1746 #[test]
1747 fn code_builder_visualize_standard_planar_code_noisy() {
1748 let visualize_filename = "code_builder_visualize_standard_planar_code_noisy.json".to_string();
1750 print_visualize_link(visualize_filename.clone());
1751 let di = 5;
1752 let dj = 5;
1753 let noisy_measurements = 2;
1754 let simulator = Simulator::new(CodeType::StandardPlanarCode, CodeSize::new(noisy_measurements, di, dj));
1755 code_builder_sanity_check(&simulator).unwrap();
1756 let mut visualizer = Visualizer::new(Some(visualize_data_folder() + visualize_filename.as_str())).unwrap();
1757 visualizer.add_component(&simulator).unwrap();
1758 }
1759
1760 #[test]
1761 fn code_builder_visualize_rotated_planar_code_noisy() {
1762 let visualize_filename = "code_builder_visualize_rotated_planar_code_noisy.json".to_string();
1764 print_visualize_link(visualize_filename.clone());
1765 let di = 5;
1766 let dj = 5;
1767 let noisy_measurements = 2;
1768 let simulator = Simulator::new(CodeType::RotatedPlanarCode, CodeSize::new(noisy_measurements, di, dj));
1769 code_builder_sanity_check(&simulator).unwrap();
1770 let mut visualizer = Visualizer::new(Some(visualize_data_folder() + visualize_filename.as_str())).unwrap();
1771 visualizer.add_component(&simulator).unwrap();
1772 }
1773
1774 #[test]
1775 fn code_builder_visualize_standard_xzzx_code() {
1776 let visualize_filename = "code_builder_visualize_standard_xzzx_code.json".to_string();
1778 print_visualize_link(visualize_filename.clone());
1779 let di = 7;
1780 let dj = 5;
1781 let noisy_measurements = 0;
1782 let simulator = Simulator::new(CodeType::StandardXZZXCode, CodeSize::new(noisy_measurements, di, dj));
1783 code_builder_sanity_check(&simulator).unwrap();
1784 let mut visualizer = Visualizer::new(Some(visualize_data_folder() + visualize_filename.as_str())).unwrap();
1785 visualizer.add_component(&simulator).unwrap();
1786 }
1787
1788 #[test]
1789 fn code_builder_visualize_rotated_xzzx_code() {
1790 let visualize_filename = "code_builder_visualize_rotated_xzzx_code.json".to_string();
1792 print_visualize_link(visualize_filename.clone());
1793 let di = 7;
1794 let dj = 5;
1795 let noisy_measurements = 0;
1796 let simulator = Simulator::new(CodeType::RotatedXZZXCode, CodeSize::new(noisy_measurements, di, dj));
1797 code_builder_sanity_check(&simulator).unwrap();
1798 let mut visualizer = Visualizer::new(Some(visualize_data_folder() + visualize_filename.as_str())).unwrap();
1799 visualizer.add_component(&simulator).unwrap();
1800 }
1801
1802 #[test]
1803 fn code_builder_visualize_standard_tailored_code() {
1804 let visualize_filename = "code_builder_visualize_standard_tailored_code.json".to_string();
1806 print_visualize_link(visualize_filename.clone());
1807 let di = 7;
1808 let dj = 5;
1809 let noisy_measurements = 0;
1810 let simulator = Simulator::new(CodeType::StandardTailoredCode, CodeSize::new(noisy_measurements, di, dj));
1811 code_builder_sanity_check(&simulator).unwrap();
1812 let mut visualizer = Visualizer::new(Some(visualize_data_folder() + visualize_filename.as_str())).unwrap();
1813 visualizer.add_component(&simulator).unwrap();
1814 }
1815
1816 #[test]
1817 fn code_builder_visualize_rotated_tailored_code() {
1818 let visualize_filename = "code_builder_visualize_rotated_tailored_code.json".to_string();
1820 print_visualize_link(visualize_filename.clone());
1821 let di = 7;
1822 let dj = 5;
1823 let noisy_measurements = 0;
1824 let simulator = Simulator::new(CodeType::RotatedTailoredCode, CodeSize::new(noisy_measurements, di, dj));
1825 code_builder_sanity_check(&simulator).unwrap();
1826 let mut visualizer = Visualizer::new(Some(visualize_data_folder() + visualize_filename.as_str())).unwrap();
1827 visualizer.add_component(&simulator).unwrap();
1828 }
1829}