1#![deny(clippy::all, clippy::pedantic)]
5
6pub mod result_bool;
13
14pub mod exp;
15
16use bitvec::prelude::*;
17use num_bigint::BigUint;
18use num_complex::Complex64;
19use quantum_sparse_sim::QuantumSim;
20use std::cell::RefCell;
21use std::convert::TryInto;
22use std::ffi::c_char;
23use std::ffi::c_double;
24use std::ffi::{c_void, CString};
25use std::io::Write;
26use std::mem::size_of;
27
28use result_bool::{
29 __quantum__rt__result_equal, __quantum__rt__result_get_one, __quantum__rt__result_get_zero,
30};
31
32pub use qir_stdlib::{
33 arrays::*, bigints::*, callables::*, math::*, output_recording::*, range_support::*,
34 strings::*, tuples::*, *,
35};
36
37struct SimulatorState {
38 pub sim: QuantumSim,
39 pub res: BitVec,
40 pub max_qubit_id: usize,
41}
42
43thread_local! {
44 static SIM_STATE: RefCell<SimulatorState> = RefCell::new(SimulatorState {
45 sim: QuantumSim::default(),
46 res: bitvec![],
47 max_qubit_id: 0
48 });
49}
50
51pub fn set_rng_seed(seed: u64) {
53 SIM_STATE.with(|sim_state| {
54 let state = &mut *sim_state.borrow_mut();
55 state.sim.set_rng_seed(seed);
56 });
57}
58
59#[no_mangle]
61pub extern "C" fn __quantum__rt__initialize(_: *mut c_char) {
62 SIM_STATE.with(|sim_state| {
63 let state = &mut *sim_state.borrow_mut();
64 state.sim = QuantumSim::new(Some(state.sim.take_rng()));
67 state.res = bitvec![];
68 state.max_qubit_id = 0;
69 });
70}
71
72fn ensure_sufficient_qubits(sim: &mut QuantumSim, qubit_id: usize, max: &mut usize) {
73 while qubit_id + 1 > *max {
74 let _ = sim.allocate();
75 *max += 1;
76 }
77}
78
79#[allow(clippy::cast_ptr_alignment)]
82unsafe fn map_to_z_basis(
83 state: &mut SimulatorState,
84 paulis: *const QirArray,
85 qubits: *const QirArray,
86) -> Vec<(Pauli, usize)> {
87 let paulis_size = __quantum__rt__array_get_size_1d(paulis);
88 let qubits_size = __quantum__rt__array_get_size_1d(qubits);
89 if paulis_size != qubits_size {
90 __quantum__rt__fail(__quantum__rt__string_create(
91 CString::new("Pauli array and Qubit array must be the same size.")
92 .expect("Unable to allocate memory for failure message string.")
93 .as_bytes_with_nul()
94 .as_ptr() as *mut c_char,
95 ));
96 }
97
98 let combined_list: Vec<(Pauli, usize)> = (0..paulis_size)
99 .filter_map(|index| {
100 let p =
101 *__quantum__rt__array_get_element_ptr_1d(paulis, index).cast::<Pauli>() as Pauli;
102 let q = *__quantum__rt__array_get_element_ptr_1d(qubits, index).cast::<*mut c_void>()
103 as usize;
104 if let Pauli::I = p {
105 None
106 } else {
107 ensure_sufficient_qubits(&mut state.sim, q, &mut state.max_qubit_id);
108 Some((p, q))
109 }
110 })
111 .collect();
112
113 for (pauli, qubit) in &combined_list {
114 match pauli {
115 Pauli::X => state.sim.h(*qubit),
116 Pauli::Y => {
117 state.sim.h(*qubit);
118 state.sim.s(*qubit);
119 state.sim.h(*qubit);
120 }
121 _ => (),
122 }
123 }
124
125 combined_list
126}
127
128fn unmap_from_z_basis(state: &mut SimulatorState, combined_list: Vec<(Pauli, usize)>) {
131 for (pauli, qubit) in combined_list {
132 match pauli {
133 Pauli::X => state.sim.h(qubit),
134 Pauli::Y => {
135 state.sim.h(qubit);
136 state.sim.sadj(qubit);
137 state.sim.h(qubit);
138 }
139 _ => (),
140 }
141 }
142}
143
144macro_rules! single_qubit_gate {
145 ($(#[$meta:meta])*
146 $qir_name:ident, $gate:expr) => {
147 $(#[$meta])*
148 #[no_mangle]
149 pub extern "C" fn $qir_name(qubit: *mut c_void) {
150 SIM_STATE.with(|sim_state| {
151 let state = &mut *sim_state.borrow_mut();
152 ensure_sufficient_qubits(&mut state.sim, qubit as usize, &mut state.max_qubit_id);
153
154 $gate(&mut state.sim, qubit as usize);
155 });
156 }
157 };
158}
159
160single_qubit_gate!(
161 __quantum__qis__h__body,
163 QuantumSim::h
164);
165single_qubit_gate!(
166 __quantum__qis__s__body,
168 QuantumSim::s
169);
170single_qubit_gate!(
171 __quantum__qis__s__adj,
173 QuantumSim::sadj
174);
175single_qubit_gate!(
176 __quantum__qis__t__body,
178 QuantumSim::t
179);
180single_qubit_gate!(
181 __quantum__qis__t__adj,
183 QuantumSim::tadj
184);
185single_qubit_gate!(
186 __quantum__qis__x__body,
188 QuantumSim::x
189);
190single_qubit_gate!(
191 __quantum__qis__y__body,
193 QuantumSim::y
194);
195single_qubit_gate!(
196 __quantum__qis__z__body,
198 QuantumSim::z
199);
200
201macro_rules! controlled_qubit_gate {
202 ($(#[$meta:meta])*
203 $qir_name:ident, $gate:expr, 1) => {
204 $(#[$meta])*
205 #[no_mangle]
206 pub extern "C" fn $qir_name(control: *mut c_void, target: *mut c_void) {
207 SIM_STATE.with(|sim_state| {
208 let state = &mut *sim_state.borrow_mut();
209 ensure_sufficient_qubits(&mut state.sim, target as usize, &mut state.max_qubit_id);
210 ensure_sufficient_qubits(&mut state.sim, control as usize, &mut state.max_qubit_id);
211
212 $gate(&mut state.sim, &[control as usize], target as usize);
213 });
214 }
215 };
216
217 ($(#[$meta:meta])*
218 $qir_name:ident, $gate:expr, 2) => {
219 $(#[$meta])*
220 #[no_mangle]
221 pub extern "C" fn $qir_name(
222 control_1: *mut c_void,
223 control_2: *mut c_void,
224 target: *mut c_void,
225 ) {
226 SIM_STATE.with(|sim_state| {
227 let state = &mut *sim_state.borrow_mut();
228 ensure_sufficient_qubits(&mut state.sim, target as usize, &mut state.max_qubit_id);
229 ensure_sufficient_qubits(&mut state.sim, control_1 as usize, &mut state.max_qubit_id);
230 ensure_sufficient_qubits(&mut state.sim, control_2 as usize, &mut state.max_qubit_id);
231
232 $gate(&mut state.sim, &[control_1 as usize, control_2 as usize], target as usize);
233 });
234 }
235 };
236}
237
238controlled_qubit_gate!(
239 __quantum__qis__cnot__body,
241 QuantumSim::mcx,
242 1
243);
244controlled_qubit_gate!(
245 __quantum__qis__cx__body,
247 QuantumSim::mcx,
248 1
249);
250controlled_qubit_gate!(
251 __quantum__qis__ccx__body,
253 QuantumSim::mcx,
254 2
255);
256controlled_qubit_gate!(
257 __quantum__qis__cy__body,
259 QuantumSim::mcy,
260 1
261);
262controlled_qubit_gate!(
263 __quantum__qis__cz__body,
265 QuantumSim::mcz,
266 1
267);
268
269macro_rules! single_qubit_rotation {
270 ($(#[$meta:meta])*
271 $qir_name:ident, $gate:expr) => {
272 $(#[$meta])*
273 #[no_mangle]
274 pub extern "C" fn $qir_name(theta: c_double, qubit: *mut c_void) {
275 SIM_STATE.with(|sim_state| {
276 let state = &mut *sim_state.borrow_mut();
277 ensure_sufficient_qubits(&mut state.sim, qubit as usize, &mut state.max_qubit_id);
278
279 $gate(&mut state.sim, theta, qubit as usize);
280 });
281 }
282 };
283}
284
285single_qubit_rotation!(
286 __quantum__qis__rx__body,
288 QuantumSim::rx
289);
290single_qubit_rotation!(
291 __quantum__qis__ry__body,
293 QuantumSim::ry
294);
295single_qubit_rotation!(
296 __quantum__qis__rz__body,
298 QuantumSim::rz
299);
300
301macro_rules! multicontrolled_qubit_gate {
302 ($(#[$meta:meta])*
303 $qir_name:ident, $gate:expr) => {
304 $(#[$meta])*
305 #[no_mangle]
309 #[allow(clippy::cast_ptr_alignment)]
310 pub unsafe extern "C" fn $qir_name(ctls: *const QirArray, qubit: *mut c_void) {
311 SIM_STATE.with(|sim_state| {
312 let state = &mut *sim_state.borrow_mut();
313 ensure_sufficient_qubits(&mut state.sim, qubit as usize, &mut state.max_qubit_id);
314 let ctls_size = __quantum__rt__array_get_size_1d(ctls);
315 let ctls_list: Vec<usize> = (0..ctls_size)
316 .map(|index| {
317 let q = *__quantum__rt__array_get_element_ptr_1d(ctls, index)
318 .cast::<*mut c_void>() as usize;
319 ensure_sufficient_qubits(&mut state.sim, q, &mut state.max_qubit_id);
320 q
321 })
322 .collect();
323
324 $gate(&mut state.sim, &ctls_list, qubit as usize);
325 });
326 }
327 };
328}
329
330multicontrolled_qubit_gate!(
331 __quantum__qis__h__ctl,
333 QuantumSim::mch
334);
335multicontrolled_qubit_gate!(
336 __quantum__qis__s__ctl,
338 QuantumSim::mcs
339);
340multicontrolled_qubit_gate!(
341 __quantum__qis__s__ctladj,
343 QuantumSim::mcsadj
344);
345multicontrolled_qubit_gate!(
346 __quantum__qis__t__ctl,
348 QuantumSim::mct
349);
350multicontrolled_qubit_gate!(
351 __quantum__qis__t__ctladj,
353 QuantumSim::mctadj
354);
355multicontrolled_qubit_gate!(
356 __quantum__qis__x__ctl,
358 QuantumSim::mcx
359);
360multicontrolled_qubit_gate!(
361 __quantum__qis__y__ctl,
363 QuantumSim::mcy
364);
365multicontrolled_qubit_gate!(
366 __quantum__qis__z__ctl,
368 QuantumSim::mcz
369);
370
371#[derive(Copy, Clone)]
372#[repr(C)]
373struct RotationArgs {
374 theta: c_double,
375 qubit: *mut c_void,
376}
377
378macro_rules! multicontrolled_qubit_rotation {
379 ($(#[$meta:meta])*
380 $qir_name:ident, $gate:expr) => {
381 $(#[$meta])*
382 #[no_mangle]
386 #[allow(clippy::cast_ptr_alignment)]
387 pub unsafe extern "C" fn $qir_name(
388 ctls: *const QirArray,
389 arg_tuple: *mut *const Vec<u8>,
390 ) {
391 SIM_STATE.with(|sim_state| {
392 let state = &mut *sim_state.borrow_mut();
393
394 let args = *arg_tuple.cast::<RotationArgs>();
395
396 ensure_sufficient_qubits(&mut state.sim, args.qubit as usize, &mut state.max_qubit_id);
397 let ctls_size = __quantum__rt__array_get_size_1d(ctls);
398 let ctls_list: Vec<usize> = (0..ctls_size)
399 .map(|index| {
400 let q = *__quantum__rt__array_get_element_ptr_1d(ctls, index)
401 .cast::<*mut c_void>() as usize;
402 ensure_sufficient_qubits(&mut state.sim, q, &mut state.max_qubit_id);
403 q
404 })
405 .collect();
406
407 $gate(
408 &mut state.sim,
409 &ctls_list,
410 args.theta,
411 args.qubit as usize,
412 );
413 });
414 }
415 };
416}
417
418multicontrolled_qubit_rotation!(
419 __quantum__qis__rx__ctl,
421 QuantumSim::mcrx
422);
423multicontrolled_qubit_rotation!(
424 __quantum__qis__ry__ctl,
426 QuantumSim::mcry
427);
428multicontrolled_qubit_rotation!(
429 __quantum__qis__rz__ctl,
431 QuantumSim::mcrz
432);
433
434#[no_mangle]
436pub extern "C" fn __quantum__qis__sx__body(qubit: *mut c_void) {
437 __quantum__qis__h__body(qubit);
438 __quantum__qis__s__body(qubit);
439 __quantum__qis__h__body(qubit);
440}
441
442#[no_mangle]
444pub extern "C" fn __quantum__qis__rxx__body(
445 theta: c_double,
446 qubit1: *mut c_void,
447 qubit2: *mut c_void,
448) {
449 __quantum__qis__h__body(qubit1);
450
451 __quantum__qis__h__body(qubit2);
452
453 __quantum__qis__rzz__body(theta, qubit1, qubit2);
454
455 __quantum__qis__h__body(qubit2);
456
457 __quantum__qis__h__body(qubit1);
458}
459
460#[no_mangle]
462pub extern "C" fn __quantum__qis__ryy__body(
463 theta: c_double,
464 qubit1: *mut c_void,
465 qubit2: *mut c_void,
466) {
467 __quantum__qis__h__body(qubit1);
468 __quantum__qis__s__body(qubit1);
469 __quantum__qis__h__body(qubit1);
470
471 __quantum__qis__h__body(qubit2);
472 __quantum__qis__s__body(qubit2);
473 __quantum__qis__h__body(qubit2);
474
475 __quantum__qis__rzz__body(theta, qubit1, qubit2);
476
477 __quantum__qis__h__body(qubit2);
478 __quantum__qis__s__adj(qubit2);
479 __quantum__qis__h__body(qubit2);
480
481 __quantum__qis__h__body(qubit1);
482 __quantum__qis__s__adj(qubit1);
483 __quantum__qis__h__body(qubit1);
484}
485
486#[no_mangle]
488pub extern "C" fn __quantum__qis__rzz__body(
489 theta: c_double,
490 qubit1: *mut c_void,
491 qubit2: *mut c_void,
492) {
493 __quantum__qis__cx__body(qubit2, qubit1);
494 __quantum__qis__rz__body(theta, qubit1);
495 __quantum__qis__cx__body(qubit2, qubit1);
496}
497
498#[no_mangle]
500pub extern "C" fn __quantum__qis__r__body(pauli: Pauli, theta: c_double, qubit: *mut c_void) {
501 match pauli {
502 Pauli::I => (),
503 Pauli::X => __quantum__qis__rx__body(theta, qubit),
504 Pauli::Y => __quantum__qis__ry__body(theta, qubit),
505 Pauli::Z => __quantum__qis__rz__body(theta, qubit),
506 }
507}
508
509#[no_mangle]
511pub extern "C" fn __quantum__qis__r__adj(pauli: Pauli, theta: c_double, qubit: *mut c_void) {
512 __quantum__qis__r__body(pauli, -theta, qubit);
513}
514
515#[derive(Copy, Clone)]
516#[repr(C)]
517struct PauliRotationArgs {
518 pauli: Pauli,
519 theta: c_double,
520 qubit: *mut c_void,
521}
522
523#[allow(clippy::cast_ptr_alignment)]
528#[no_mangle]
529pub unsafe extern "C" fn __quantum__qis__r__ctl(
530 ctls: *const QirArray,
531 arg_tuple: *mut *const Vec<u8>,
532) {
533 let args = *arg_tuple.cast::<PauliRotationArgs>();
534 let rot_args = RotationArgs {
535 theta: args.theta,
536 qubit: args.qubit,
537 };
538 let rot_arg_tuple = __quantum__rt__tuple_create(size_of::<RotationArgs>() as u64);
539 *rot_arg_tuple.cast::<RotationArgs>() = rot_args;
540
541 match args.pauli {
542 Pauli::X => __quantum__qis__rx__ctl(ctls, rot_arg_tuple),
543 Pauli::Y => __quantum__qis__ry__ctl(ctls, rot_arg_tuple),
544 Pauli::Z => __quantum__qis__rz__ctl(ctls, rot_arg_tuple),
545 Pauli::I => {
546 if __quantum__rt__array_get_size_1d(ctls) > 0 {
547 SIM_STATE.with(|sim_state| {
548 let state = &mut *sim_state.borrow_mut();
549
550 ensure_sufficient_qubits(
551 &mut state.sim,
552 args.qubit as usize,
553 &mut state.max_qubit_id,
554 );
555 let ctls_size = __quantum__rt__array_get_size_1d(ctls);
556 let ctls_list: Vec<usize> = (0..ctls_size)
557 .map(|index| {
558 let q = *__quantum__rt__array_get_element_ptr_1d(ctls, index)
559 .cast::<*mut c_void>() as usize;
560 ensure_sufficient_qubits(&mut state.sim, q, &mut state.max_qubit_id);
561 q
562 })
563 .collect();
564
565 if let Some((head, rest)) = ctls_list.split_first() {
566 state.sim.mcphase(
567 rest,
568 Complex64::exp(Complex64::new(0.0, -args.theta / 2.0)),
569 *head,
570 );
571 }
572 });
573 }
574 }
575 }
576
577 __quantum__rt__tuple_update_reference_count(rot_arg_tuple, -1);
578}
579
580#[no_mangle]
585pub unsafe extern "C" fn __quantum__qis__r__ctladj(
586 ctls: *const QirArray,
587 arg_tuple: *mut *const Vec<u8>,
588) {
589 let args = *arg_tuple.cast::<PauliRotationArgs>();
590 let new_args = PauliRotationArgs {
591 pauli: args.pauli,
592 theta: -args.theta,
593 qubit: args.qubit,
594 };
595 let new_arg_tuple = __quantum__rt__tuple_create(size_of::<PauliRotationArgs>() as u64);
596 *new_arg_tuple.cast::<PauliRotationArgs>() = new_args;
597 __quantum__qis__r__ctl(ctls, new_arg_tuple);
598 __quantum__rt__tuple_update_reference_count(new_arg_tuple, -1);
599}
600
601#[no_mangle]
603pub extern "C" fn __quantum__qis__swap__body(qubit1: *mut c_void, qubit2: *mut c_void) {
604 SIM_STATE.with(|sim_state| {
605 let state = &mut *sim_state.borrow_mut();
606 ensure_sufficient_qubits(&mut state.sim, qubit1 as usize, &mut state.max_qubit_id);
607 ensure_sufficient_qubits(&mut state.sim, qubit2 as usize, &mut state.max_qubit_id);
608
609 state.sim.swap_qubit_ids(qubit1 as usize, qubit2 as usize);
610 });
611}
612
613#[no_mangle]
615pub extern "C" fn __quantum__qis__reset__body(qubit: *mut c_void) {
616 SIM_STATE.with(|sim_state| {
617 let state = &mut *sim_state.borrow_mut();
618 ensure_sufficient_qubits(&mut state.sim, qubit as usize, &mut state.max_qubit_id);
619
620 if state.sim.measure(qubit as usize) {
621 state.sim.x(qubit as usize);
622 }
623 });
624}
625
626#[allow(clippy::missing_panics_doc)]
629#[no_mangle]
631pub extern "C" fn __quantum__qis__mresetz__body(qubit: *mut c_void, result: *mut c_void) {
632 SIM_STATE.with(|sim_state| {
633 let state = &mut *sim_state.borrow_mut();
634 let res_id = result as usize;
635 ensure_sufficient_qubits(&mut state.sim, qubit as usize, &mut state.max_qubit_id);
636
637 if state.res.len() < res_id + 1 {
638 state.res.resize(res_id + 1, false);
639 }
640
641 let res = state.sim.measure(qubit as usize);
642
643 if res {
644 state.sim.x(qubit as usize);
645 }
646
647 *state
648 .res
649 .get_mut(res_id)
650 .expect("Result with given id missing after expansion.") = res;
651 });
652}
653
654#[allow(clippy::missing_panics_doc)]
656#[no_mangle]
658pub extern "C" fn __quantum__qis__mz__body(qubit: *mut c_void, result: *mut c_void) {
659 SIM_STATE.with(|sim_state| {
660 let state = &mut *sim_state.borrow_mut();
661 let res_id = result as usize;
662 ensure_sufficient_qubits(&mut state.sim, qubit as usize, &mut state.max_qubit_id);
663
664 if state.res.len() < res_id + 1 {
665 state.res.resize(res_id + 1, false);
666 }
667
668 *state
669 .res
670 .get_mut(res_id)
671 .expect("Result with given id missing after expansion.") =
672 state.sim.measure(qubit as usize);
673 });
674}
675
676#[allow(clippy::missing_panics_doc)]
679#[no_mangle]
681pub extern "C" fn __quantum__qis__read_result__body(result: *mut c_void) -> bool {
682 SIM_STATE.with(|sim_state| {
683 let res = &mut sim_state.borrow_mut().res;
684 let res_id = result as usize;
685 if res.len() < res_id + 1 {
686 res.resize(res_id + 1, false);
687 }
688
689 let b = *res
690 .get(res_id)
691 .expect("Result with given id missing after expansion.");
692 b
693 })
694}
695
696#[no_mangle]
698pub extern "C" fn __quantum__qis__m__body(qubit: *mut c_void) -> *mut c_void {
699 SIM_STATE.with(|sim_state| {
700 let state = &mut *sim_state.borrow_mut();
701 ensure_sufficient_qubits(&mut state.sim, qubit as usize, &mut state.max_qubit_id);
702
703 if state.sim.measure(qubit as usize) {
704 __quantum__rt__result_get_one()
705 } else {
706 __quantum__rt__result_get_zero()
707 }
708 })
709}
710
711#[allow(clippy::cast_ptr_alignment)]
719#[no_mangle]
720pub unsafe extern "C" fn __quantum__qis__measure__body(
721 paulis: *const QirArray,
722 qubits: *const QirArray,
723) -> *mut c_void {
724 SIM_STATE.with(|sim_state| {
725 let mut state = sim_state.borrow_mut();
726
727 let combined_list = map_to_z_basis(&mut state, paulis, qubits);
728
729 let res = state.sim.joint_measure(
730 &combined_list
731 .iter()
732 .map(|(_, q)| *q)
733 .collect::<Vec<usize>>(),
734 );
735
736 unmap_from_z_basis(&mut state, combined_list);
737
738 if res {
739 __quantum__rt__result_get_one()
740 } else {
741 __quantum__rt__result_get_zero()
742 }
743 })
744}
745
746pub fn qubit_is_zero(qubit: *mut c_void) -> bool {
748 SIM_STATE.with(|sim_state| {
749 let state = &mut *sim_state.borrow_mut();
750 ensure_sufficient_qubits(&mut state.sim, qubit as usize, &mut state.max_qubit_id);
751
752 state.sim.qubit_is_zero(qubit as usize)
753 })
754}
755
756#[no_mangle]
762pub unsafe extern "C" fn __quantum__qis__assertmeasurementprobability__body(
763 paulis: *const QirArray,
764 qubits: *const QirArray,
765 result: *mut c_void,
766 prob: c_double,
767 msg: *const CString,
768 tol: c_double,
769) {
770 SIM_STATE.with(|sim_state| {
771 let mut state = sim_state.borrow_mut();
772
773 let combined_list = map_to_z_basis(&mut state, paulis, qubits);
774
775 let mut actual_prob = state.sim.joint_probability(
776 &combined_list
777 .iter()
778 .map(|(_, q)| *q)
779 .collect::<Vec<usize>>(),
780 );
781
782 if __quantum__rt__result_equal(result, __quantum__rt__result_get_zero()) {
783 actual_prob = 1.0 - actual_prob;
784 }
785
786 if (actual_prob - prob).abs() > tol {
787 __quantum__rt__fail(msg);
788 }
789
790 unmap_from_z_basis(&mut state, combined_list);
791 });
792}
793
794#[derive(Copy, Clone)]
795#[repr(C)]
796struct AssertMeasurementProbabilityArgs {
797 paulis: *const QirArray,
798 qubits: *const QirArray,
799 result: *mut c_void,
800 prob: c_double,
801 msg: *const CString,
802 tol: c_double,
803}
804
805#[no_mangle]
812pub unsafe extern "C" fn __quantum__qis__assertmeasurementprobability__ctl(
813 _ctls: *const QirArray,
814 arg_tuple: *mut *const Vec<u8>,
815) {
816 let args = *arg_tuple.cast::<AssertMeasurementProbabilityArgs>();
817 __quantum__qis__assertmeasurementprobability__body(
818 args.paulis,
819 args.qubits,
820 args.result,
821 args.prob,
822 args.msg,
823 args.tol,
824 );
825}
826
827pub mod legacy_output {
828 use std::ffi::c_void;
829
830 use qir_stdlib::output_recording::record_output_str;
831
832 use crate::{
833 result_bool::{__quantum__rt__result_equal, __quantum__rt__result_get_one},
834 SIM_STATE,
835 };
836
837 #[allow(clippy::missing_panics_doc)]
838 #[allow(non_snake_case)]
840 pub extern "C" fn __quantum__rt__result_record_output(result: *mut c_void) {
841 SIM_STATE.with(|sim_state| {
842 let res = &mut sim_state.borrow_mut().res;
843 let res_id = result as usize;
844 let b = if res.is_empty() {
845 __quantum__rt__result_equal(result, __quantum__rt__result_get_one())
847 } else {
848 if res.len() < res_id + 1 {
849 res.resize(res_id + 1, false);
850 }
851 *res.get(res_id)
852 .expect("Result with given id missing after expansion.")
853 };
854
855 record_output_str(&format!("RESULT\t{}", if b { "1" } else { "0" }))
856 .expect("Failed to write result output");
857 });
858 }
859}
860
861#[allow(clippy::missing_panics_doc)]
863#[no_mangle]
867pub unsafe extern "C" fn __quantum__rt__result_record_output(
868 result: *mut c_void,
869 tag: *mut c_char,
870) {
871 SIM_STATE.with(|sim_state| {
872 let res = &mut sim_state.borrow_mut().res;
873 let res_id = result as usize;
874 let b = if res.is_empty() {
875 __quantum__rt__result_equal(result, __quantum__rt__result_get_one())
877 } else {
878 if res.len() < res_id + 1 {
879 res.resize(res_id + 1, false);
880 }
881 *res.get(res_id)
882 .expect("Result with given id missing after expansion.")
883 };
884
885 let val: i64 = i64::from(b);
886 record_output("RESULT", &val, tag).expect("Failed to write result output");
887 });
888}
889
890#[no_mangle]
892pub extern "C" fn __quantum__rt__qubit_allocate() -> *mut c_void {
893 SIM_STATE.with(|sim_state| {
894 let mut state = sim_state.borrow_mut();
895 let qubit_id = state.sim.allocate();
896
897 state.max_qubit_id = state.max_qubit_id.max(qubit_id + 1);
900
901 qubit_id as *mut c_void
902 })
903}
904
905#[allow(clippy::cast_ptr_alignment)]
909#[no_mangle]
910pub extern "C" fn __quantum__rt__qubit_allocate_array(size: u64) -> *const QirArray {
911 let arr = __quantum__rt__array_create_1d(
912 size_of::<usize>()
913 .try_into()
914 .expect("System pointer size too large to be described with u32."),
915 size,
916 );
917 for index in 0..size {
918 unsafe {
919 let elem = __quantum__rt__array_get_element_ptr_1d(arr, index).cast::<*mut c_void>();
920 *elem = __quantum__rt__qubit_allocate();
921 }
922 }
923 arr
924}
925
926#[allow(clippy::cast_ptr_alignment)]
931#[no_mangle]
932pub unsafe extern "C" fn __quantum__rt__qubit_release_array(arr: *const QirArray) {
933 for index in 0..__quantum__rt__array_get_size_1d(arr) {
934 let elem = __quantum__rt__array_get_element_ptr_1d(arr, index).cast::<*mut c_void>();
935 __quantum__rt__qubit_release(*elem);
936 }
937 __quantum__rt__array_update_alias_count(arr, -1);
938}
939
940#[no_mangle]
942pub extern "C" fn __quantum__rt__qubit_release(qubit: *mut c_void) {
943 SIM_STATE.with(|sim_state| {
944 let mut state = sim_state.borrow_mut();
945 state.sim.release(qubit as usize);
946 });
947}
948
949#[no_mangle]
953pub extern "C" fn __quantum__rt__qubit_to_string(qubit: *mut c_void) -> *const CString {
954 unsafe {
955 __quantum__rt__string_create(
956 CString::new(format!("{}", qubit as usize))
957 .expect("Unable to allocate memory for qubit string.")
958 .as_bytes_with_nul()
959 .as_ptr() as *mut c_char,
960 )
961 }
962}
963
964#[must_use]
968pub fn capture_quantum_state() -> (Vec<(BigUint, Complex64)>, usize) {
969 SIM_STATE.with(|sim_state| {
970 let mut state = sim_state.borrow_mut();
971 state.sim.get_state()
972 })
973}
974
975#[no_mangle]
979pub extern "C" fn __quantum__qis__dumpmachine__body(location: *mut c_void) {
980 if !location.is_null() {
981 unimplemented!("Dump to location is not implemented.")
982 }
983 SIM_STATE.with(|sim_state| {
984 let mut state = sim_state.borrow_mut();
985
986 if !state.res.is_empty() {
987 OUTPUT.with(|output| {
988 let mut output = output.borrow_mut();
989 output
990 .write_fmt(format_args!("Global Results: {}", state.res))
991 .expect("Failed to write global results");
992 output.write_newline();
993 });
994 }
995 OUTPUT.with(|output| {
996 let mut output = output.borrow_mut();
997 output
998 .write_all(state.sim.dump().as_bytes())
999 .expect("Failed to write simulator state");
1000 });
1001 });
1002}
1003
1004#[no_mangle]
1006pub extern "C" fn __quantum__qis__barrier__body() {
1007 }
1009
1010#[cfg(test)]
1011mod tests {
1012 use std::{f64::consts::PI, ffi::c_void, ptr::null_mut};
1013
1014 use crate::{
1015 __quantum__qis__cnot__body, __quantum__qis__cx__body, __quantum__qis__cz__body,
1016 __quantum__qis__dumpmachine__body, __quantum__qis__h__body, __quantum__qis__m__body,
1017 __quantum__qis__mresetz__body, __quantum__qis__mz__body, __quantum__qis__read_result__body,
1018 __quantum__qis__rx__body, __quantum__qis__rxx__body, __quantum__qis__ry__body,
1019 __quantum__qis__ryy__body, __quantum__qis__rz__body, __quantum__qis__rzz__body,
1020 __quantum__qis__s__adj, __quantum__qis__s__body, __quantum__qis__x__body,
1021 __quantum__rt__qubit_allocate, __quantum__rt__qubit_allocate_array,
1022 __quantum__rt__qubit_release, __quantum__rt__qubit_release_array,
1023 __quantum__rt__result_equal, capture_quantum_state, map_to_z_basis, qubit_is_zero,
1024 result_bool::__quantum__rt__result_get_one, unmap_from_z_basis, SIM_STATE,
1025 };
1026 use num_bigint::BigUint;
1027 use qir_stdlib::{
1028 arrays::{
1029 __quantum__rt__array_create_1d, __quantum__rt__array_get_element_ptr_1d,
1030 __quantum__rt__array_update_reference_count,
1031 },
1032 Pauli,
1033 };
1034
1035 #[test]
1036 fn basic_test_static() {
1037 let q0 = 5 as *mut c_void;
1038 let r0 = std::ptr::null_mut();
1039 let r1 = 1 as *mut c_void;
1040 __quantum__qis__mz__body(q0, r0);
1041 assert!(!__quantum__qis__read_result__body(r0));
1042 __quantum__qis__x__body(q0);
1043 __quantum__qis__mz__body(q0, r1);
1044 assert!(__quantum__qis__read_result__body(r1));
1045 __quantum__qis__x__body(q0);
1046 __quantum__qis__mz__body(q0, r0);
1047 assert!(!__quantum__qis__read_result__body(r0));
1048 assert!(!__quantum__qis__read_result__body(3 as *mut c_void));
1049 __quantum__qis__dumpmachine__body(null_mut());
1050 }
1051
1052 #[allow(clippy::cast_ptr_alignment)]
1053 #[test]
1054 fn basic_test_dynamic() {
1055 let q1 = __quantum__rt__qubit_allocate();
1056 let q2 = __quantum__rt__qubit_allocate();
1057 __quantum__qis__h__body(q1);
1058 __quantum__qis__cnot__body(q1, q2);
1059 let r1 = __quantum__qis__m__body(q1);
1060 let r2 = __quantum__qis__m__body(q2);
1061 assert!(__quantum__rt__result_equal(r1, r2));
1062 __quantum__qis__dumpmachine__body(null_mut());
1063 __quantum__rt__qubit_release(q2);
1064 __quantum__rt__qubit_release(q1);
1065 let qs = __quantum__rt__qubit_allocate_array(4);
1066 unsafe {
1067 let q_elem = __quantum__rt__array_get_element_ptr_1d(qs, 3).cast::<*mut c_void>();
1068 __quantum__qis__x__body(*q_elem);
1069 __quantum__qis__dumpmachine__body(null_mut());
1070 let r = __quantum__qis__m__body(*q_elem);
1071 assert!(__quantum__rt__result_equal(
1072 r,
1073 __quantum__rt__result_get_one()
1074 ));
1075 __quantum__rt__qubit_release_array(qs);
1076 }
1077 }
1078
1079 #[test]
1080 fn test_qubit_is_zero() {
1081 let q0 = __quantum__rt__qubit_allocate();
1082 assert!(qubit_is_zero(q0));
1083 __quantum__qis__x__body(q0);
1084 assert!(!qubit_is_zero(q0));
1085 __quantum__qis__h__body(q0);
1086 assert!(!qubit_is_zero(q0));
1087 let r = __quantum__qis__m__body(q0);
1088 assert!(
1089 qubit_is_zero(q0) != __quantum__rt__result_equal(r, __quantum__rt__result_get_one())
1090 );
1091 }
1092
1093 #[allow(clippy::cast_ptr_alignment)]
1094 #[test]
1095 fn test_map_unmap_are_adjoint() {
1096 unsafe fn check_map_unmap(pauli: Pauli) {
1097 let check_qubit = __quantum__rt__qubit_allocate();
1098 let qubits = __quantum__rt__qubit_allocate_array(1);
1099 let q = *__quantum__rt__array_get_element_ptr_1d(qubits, 0).cast::<*mut c_void>();
1100 let paulis = __quantum__rt__array_create_1d(1, 1);
1101 *__quantum__rt__array_get_element_ptr_1d(paulis, 0).cast::<Pauli>() = pauli;
1102
1103 __quantum__qis__h__body(check_qubit);
1104 __quantum__qis__cnot__body(check_qubit, q);
1105
1106 SIM_STATE.with(|sim_state| {
1107 let state = &mut *sim_state.borrow_mut();
1108 let combined_list = map_to_z_basis(state, paulis, qubits);
1109 unmap_from_z_basis(state, combined_list);
1110 });
1111
1112 __quantum__qis__cnot__body(check_qubit, q);
1113 __quantum__qis__h__body(check_qubit);
1114
1115 assert!(qubit_is_zero(q));
1116 assert!(qubit_is_zero(check_qubit));
1117
1118 __quantum__rt__array_update_reference_count(paulis, -1);
1119 __quantum__rt__qubit_release_array(qubits);
1120 __quantum__rt__qubit_release(check_qubit);
1121 }
1122
1123 unsafe {
1124 check_map_unmap(Pauli::X);
1125 check_map_unmap(Pauli::Y);
1126 check_map_unmap(Pauli::Z);
1127 }
1128 }
1129
1130 #[allow(clippy::cast_ptr_alignment)]
1131 #[test]
1132 fn test_map_pauli_x() {
1133 let qubits = __quantum__rt__qubit_allocate_array(1);
1134 unsafe {
1135 let q = *__quantum__rt__array_get_element_ptr_1d(qubits, 0).cast::<*mut c_void>();
1136 let paulis = __quantum__rt__array_create_1d(1, 1);
1137 *__quantum__rt__array_get_element_ptr_1d(paulis, 0).cast::<Pauli>() = Pauli::X;
1138
1139 __quantum__qis__h__body(q);
1140
1141 SIM_STATE.with(|sim_state| {
1142 let state = &mut *sim_state.borrow_mut();
1143 let _ = map_to_z_basis(state, paulis, qubits);
1144 });
1145
1146 qubit_is_zero(q);
1147
1148 __quantum__rt__array_update_reference_count(paulis, -1);
1149 __quantum__rt__qubit_release_array(qubits);
1150 }
1151 }
1152
1153 #[allow(clippy::cast_ptr_alignment)]
1154 #[test]
1155 fn test_map_pauli_y() {
1156 let qubits = __quantum__rt__qubit_allocate_array(1);
1157 unsafe {
1158 let q = *__quantum__rt__array_get_element_ptr_1d(qubits, 0).cast::<*mut c_void>();
1159 let paulis = __quantum__rt__array_create_1d(1, 1);
1160 *__quantum__rt__array_get_element_ptr_1d(paulis, 0).cast::<Pauli>() = Pauli::Y;
1161
1162 __quantum__qis__h__body(q);
1163 __quantum__qis__s__adj(q);
1164 __quantum__qis__h__body(q);
1165
1166 SIM_STATE.with(|sim_state| {
1167 let state = &mut *sim_state.borrow_mut();
1168 let _ = map_to_z_basis(state, paulis, qubits);
1169 });
1170
1171 qubit_is_zero(q);
1172
1173 __quantum__rt__array_update_reference_count(paulis, -1);
1174 __quantum__rt__qubit_release_array(qubits);
1175 }
1176 }
1177
1178 #[allow(clippy::cast_ptr_alignment)]
1179 #[test]
1180 fn test_map_pauli_z() {
1181 let qubits = __quantum__rt__qubit_allocate_array(1);
1182 unsafe {
1183 let q = *__quantum__rt__array_get_element_ptr_1d(qubits, 0).cast::<*mut c_void>();
1184 let paulis = __quantum__rt__array_create_1d(1, 1);
1185 *__quantum__rt__array_get_element_ptr_1d(paulis, 0).cast::<Pauli>() = Pauli::Z;
1186
1187 SIM_STATE.with(|sim_state| {
1188 let state = &mut *sim_state.borrow_mut();
1189 let _ = map_to_z_basis(state, paulis, qubits);
1190 });
1191
1192 qubit_is_zero(q);
1193
1194 __quantum__rt__array_update_reference_count(paulis, -1);
1195 __quantum__rt__qubit_release_array(qubits);
1196 }
1197 }
1198
1199 #[test]
1200 fn test_joint_zz() {
1201 let check_qubit = __quantum__rt__qubit_allocate();
1202 let q0 = __quantum__rt__qubit_allocate();
1203 let q1 = __quantum__rt__qubit_allocate();
1204
1205 __quantum__qis__h__body(check_qubit);
1206 __quantum__qis__cx__body(check_qubit, q0);
1207 __quantum__qis__cx__body(check_qubit, q1);
1208
1209 __quantum__qis__rzz__body(PI / 2.0, q0, q1);
1210 __quantum__qis__rz__body(-PI / 2.0, q0);
1211 __quantum__qis__rz__body(-PI / 2.0, q1);
1212
1213 __quantum__qis__cz__body(q0, q1);
1214
1215 __quantum__qis__cx__body(check_qubit, q1);
1216 __quantum__qis__cx__body(check_qubit, q0);
1217 __quantum__qis__h__body(check_qubit);
1218
1219 assert!(qubit_is_zero(check_qubit));
1220 assert!(qubit_is_zero(q0));
1221 assert!(qubit_is_zero(q1));
1222 }
1223
1224 #[test]
1225 fn test_joint_yy() {
1226 let check_qubit = __quantum__rt__qubit_allocate();
1227 let q0 = __quantum__rt__qubit_allocate();
1228 let q1 = __quantum__rt__qubit_allocate();
1229
1230 __quantum__qis__h__body(check_qubit);
1231 __quantum__qis__cx__body(check_qubit, q0);
1232 __quantum__qis__cx__body(check_qubit, q1);
1233
1234 __quantum__qis__h__body(q0);
1235 __quantum__qis__s__adj(q0);
1236 __quantum__qis__h__body(q0);
1237 __quantum__qis__h__body(q1);
1238 __quantum__qis__s__adj(q1);
1239 __quantum__qis__h__body(q1);
1240
1241 __quantum__qis__ryy__body(PI / 2.0, q0, q1);
1242 __quantum__qis__ry__body(-PI / 2.0, q0);
1243 __quantum__qis__ry__body(-PI / 2.0, q1);
1244
1245 __quantum__qis__h__body(q1);
1246 __quantum__qis__s__body(q1);
1247 __quantum__qis__h__body(q1);
1248 __quantum__qis__h__body(q0);
1249 __quantum__qis__s__body(q0);
1250 __quantum__qis__h__body(q0);
1251
1252 __quantum__qis__cz__body(q0, q1);
1253
1254 __quantum__qis__cx__body(check_qubit, q1);
1255 __quantum__qis__cx__body(check_qubit, q0);
1256 __quantum__qis__h__body(check_qubit);
1257
1258 assert!(qubit_is_zero(check_qubit));
1259 assert!(qubit_is_zero(q0));
1260 assert!(qubit_is_zero(q1));
1261 }
1262
1263 #[test]
1264 fn test_joint_xx() {
1265 let check_qubit = __quantum__rt__qubit_allocate();
1266 let q0 = __quantum__rt__qubit_allocate();
1267 let q1 = __quantum__rt__qubit_allocate();
1268
1269 __quantum__qis__h__body(check_qubit);
1270 __quantum__qis__cx__body(check_qubit, q0);
1271 __quantum__qis__cx__body(check_qubit, q1);
1272
1273 __quantum__qis__h__body(q0);
1274 __quantum__qis__h__body(q1);
1275
1276 __quantum__qis__rxx__body(PI / 2.0, q0, q1);
1277 __quantum__qis__rx__body(-PI / 2.0, q0);
1278 __quantum__qis__rx__body(-PI / 2.0, q1);
1279
1280 __quantum__qis__h__body(q0);
1281 __quantum__qis__h__body(q1);
1282
1283 __quantum__qis__cz__body(q0, q1);
1284
1285 __quantum__qis__cx__body(check_qubit, q1);
1286 __quantum__qis__cx__body(check_qubit, q0);
1287 __quantum__qis__h__body(check_qubit);
1288
1289 assert!(qubit_is_zero(check_qubit));
1290 assert!(qubit_is_zero(q0));
1291 assert!(qubit_is_zero(q1));
1292 }
1293
1294 #[test]
1295 fn test_mresetz() {
1296 let qubit = __quantum__rt__qubit_allocate();
1297 let r0 = std::ptr::null_mut();
1298 let r1 = 1 as *mut c_void;
1299 assert!(qubit_is_zero(qubit));
1300 __quantum__qis__mresetz__body(qubit, r0);
1301 assert!(!__quantum__qis__read_result__body(r0));
1302 assert!(qubit_is_zero(qubit));
1303 __quantum__qis__x__body(qubit);
1304 __quantum__qis__mresetz__body(qubit, r1);
1305 assert!(__quantum__qis__read_result__body(r1));
1306 assert!(qubit_is_zero(qubit));
1307 }
1308
1309 #[test]
1310 fn test_capture_quantum_state() {
1311 let qubit = __quantum__rt__qubit_allocate();
1312 let (state, qubit_count) = capture_quantum_state();
1313 assert_eq!(qubit_count, 1);
1314 assert_eq!(state.len(), 1);
1315 assert_eq!(state[0].0, BigUint::from(0u32));
1316 __quantum__qis__x__body(qubit);
1317 let (state, qubit_count) = capture_quantum_state();
1318 assert_eq!(qubit_count, 1);
1319 assert_eq!(state.len(), 1);
1320 assert_eq!(state[0].0, BigUint::from(1u32));
1321 __quantum__qis__h__body(qubit);
1322 let qubit2 = __quantum__rt__qubit_allocate();
1323 let (state, qubit_count) = capture_quantum_state();
1324 assert_eq!(qubit_count, 2);
1325 assert_eq!(state.len(), 2);
1326 assert_eq!(state[0].1, -state[1].1);
1327 __quantum__qis__h__body(qubit);
1328 __quantum__qis__x__body(qubit);
1329 let (state, qubit_count) = capture_quantum_state();
1330 assert_eq!(qubit_count, 2);
1331 assert_eq!(state.len(), 1);
1332 assert_eq!(state[0].0, BigUint::from(0u32));
1333 __quantum__rt__qubit_release(qubit);
1334 __quantum__rt__qubit_release(qubit2);
1335 let (state, qubit_count) = capture_quantum_state();
1336 assert_eq!(qubit_count, 0);
1337 assert_eq!(state.len(), 1);
1338 assert_eq!(state[0].0, BigUint::from(0u32));
1339 }
1340}