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::{CString, c_void};
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#[unsafe(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 unsafe {
88 let paulis_size = __quantum__rt__array_get_size_1d(paulis);
89 let qubits_size = __quantum__rt__array_get_size_1d(qubits);
90 if paulis_size != qubits_size {
91 __quantum__rt__fail(__quantum__rt__string_create(
92 CString::new("Pauli array and Qubit array must be the same size.")
93 .expect("Unable to allocate memory for failure message string.")
94 .as_bytes_with_nul()
95 .as_ptr() as *mut c_char,
96 ));
97 }
98
99 let combined_list: Vec<(Pauli, usize)> = (0..paulis_size)
100 .filter_map(|index| {
101 let p = *__quantum__rt__array_get_element_ptr_1d(paulis, index).cast::<Pauli>()
102 as Pauli;
103 let q = *__quantum__rt__array_get_element_ptr_1d(qubits, index)
104 .cast::<*mut c_void>() as usize;
105 if let Pauli::I = p {
106 None
107 } else {
108 ensure_sufficient_qubits(&mut state.sim, q, &mut state.max_qubit_id);
109 Some((p, q))
110 }
111 })
112 .collect();
113
114 for (pauli, qubit) in &combined_list {
115 match pauli {
116 Pauli::X => state.sim.h(*qubit),
117 Pauli::Y => {
118 state.sim.h(*qubit);
119 state.sim.s(*qubit);
120 state.sim.h(*qubit);
121 }
122 _ => (),
123 }
124 }
125
126 combined_list
127 }
128}
129
130fn unmap_from_z_basis(state: &mut SimulatorState, combined_list: Vec<(Pauli, usize)>) {
133 for (pauli, qubit) in combined_list {
134 match pauli {
135 Pauli::X => state.sim.h(qubit),
136 Pauli::Y => {
137 state.sim.h(qubit);
138 state.sim.sadj(qubit);
139 state.sim.h(qubit);
140 }
141 _ => (),
142 }
143 }
144}
145
146macro_rules! single_qubit_gate {
147 ($(#[$meta:meta])*
148 $qir_name:ident, $gate:expr) => {
149 $(#[$meta])*
150 #[unsafe(no_mangle)]
151 pub extern "C" fn $qir_name(qubit: *mut c_void) {
152 SIM_STATE.with(|sim_state| {
153 let state = &mut *sim_state.borrow_mut();
154 ensure_sufficient_qubits(&mut state.sim, qubit as usize, &mut state.max_qubit_id);
155
156 $gate(&mut state.sim, qubit as usize);
157 });
158 }
159 };
160}
161
162single_qubit_gate!(
163 __quantum__qis__h__body,
165 QuantumSim::h
166);
167single_qubit_gate!(
168 __quantum__qis__s__body,
170 QuantumSim::s
171);
172single_qubit_gate!(
173 __quantum__qis__s__adj,
175 QuantumSim::sadj
176);
177single_qubit_gate!(
178 __quantum__qis__t__body,
180 QuantumSim::t
181);
182single_qubit_gate!(
183 __quantum__qis__t__adj,
185 QuantumSim::tadj
186);
187single_qubit_gate!(
188 __quantum__qis__x__body,
190 QuantumSim::x
191);
192single_qubit_gate!(
193 __quantum__qis__y__body,
195 QuantumSim::y
196);
197single_qubit_gate!(
198 __quantum__qis__z__body,
200 QuantumSim::z
201);
202
203macro_rules! controlled_qubit_gate {
204 ($(#[$meta:meta])*
205 $qir_name:ident, $gate:expr, 1) => {
206 $(#[$meta])*
207 #[unsafe(no_mangle)]
208 pub extern "C" fn $qir_name(control: *mut c_void, target: *mut c_void) {
209 SIM_STATE.with(|sim_state| {
210 let state = &mut *sim_state.borrow_mut();
211 ensure_sufficient_qubits(&mut state.sim, target as usize, &mut state.max_qubit_id);
212 ensure_sufficient_qubits(&mut state.sim, control as usize, &mut state.max_qubit_id);
213
214 $gate(&mut state.sim, &[control as usize], target as usize);
215 });
216 }
217 };
218
219 ($(#[$meta:meta])*
220 $qir_name:ident, $gate:expr, 2) => {
221 $(#[$meta])*
222 #[unsafe(no_mangle)]
223 pub extern "C" fn $qir_name(
224 control_1: *mut c_void,
225 control_2: *mut c_void,
226 target: *mut c_void,
227 ) {
228 SIM_STATE.with(|sim_state| {
229 let state = &mut *sim_state.borrow_mut();
230 ensure_sufficient_qubits(&mut state.sim, target as usize, &mut state.max_qubit_id);
231 ensure_sufficient_qubits(&mut state.sim, control_1 as usize, &mut state.max_qubit_id);
232 ensure_sufficient_qubits(&mut state.sim, control_2 as usize, &mut state.max_qubit_id);
233
234 $gate(&mut state.sim, &[control_1 as usize, control_2 as usize], target as usize);
235 });
236 }
237 };
238}
239
240controlled_qubit_gate!(
241 __quantum__qis__cnot__body,
243 QuantumSim::mcx,
244 1
245);
246controlled_qubit_gate!(
247 __quantum__qis__cx__body,
249 QuantumSim::mcx,
250 1
251);
252controlled_qubit_gate!(
253 __quantum__qis__ccx__body,
255 QuantumSim::mcx,
256 2
257);
258controlled_qubit_gate!(
259 __quantum__qis__cy__body,
261 QuantumSim::mcy,
262 1
263);
264controlled_qubit_gate!(
265 __quantum__qis__cz__body,
267 QuantumSim::mcz,
268 1
269);
270
271macro_rules! single_qubit_rotation {
272 ($(#[$meta:meta])*
273 $qir_name:ident, $gate:expr) => {
274 $(#[$meta])*
275 #[unsafe(no_mangle)]
276 pub extern "C" fn $qir_name(theta: c_double, qubit: *mut c_void) {
277 SIM_STATE.with(|sim_state| {
278 let state = &mut *sim_state.borrow_mut();
279 ensure_sufficient_qubits(&mut state.sim, qubit as usize, &mut state.max_qubit_id);
280
281 $gate(&mut state.sim, theta, qubit as usize);
282 });
283 }
284 };
285}
286
287single_qubit_rotation!(
288 __quantum__qis__rx__body,
290 QuantumSim::rx
291);
292single_qubit_rotation!(
293 __quantum__qis__ry__body,
295 QuantumSim::ry
296);
297single_qubit_rotation!(
298 __quantum__qis__rz__body,
300 QuantumSim::rz
301);
302
303macro_rules! multicontrolled_qubit_gate {
304 ($(#[$meta:meta])*
305 $qir_name:ident, $gate:expr) => {
306 $(#[$meta])*
307 #[unsafe(no_mangle)]
311 #[allow(clippy::cast_ptr_alignment)]
312 pub unsafe extern "C" fn $qir_name(ctls: *const QirArray, qubit: *mut c_void) { unsafe {
313 SIM_STATE.with(|sim_state| {
314 let state = &mut *sim_state.borrow_mut();
315 ensure_sufficient_qubits(&mut state.sim, qubit as usize, &mut state.max_qubit_id);
316 let ctls_size = __quantum__rt__array_get_size_1d(ctls);
317 let ctls_list: Vec<usize> = (0..ctls_size)
318 .map(|index| {
319 let q = *__quantum__rt__array_get_element_ptr_1d(ctls, index)
320 .cast::<*mut c_void>() as usize;
321 ensure_sufficient_qubits(&mut state.sim, q, &mut state.max_qubit_id);
322 q
323 })
324 .collect();
325
326 $gate(&mut state.sim, &ctls_list, qubit as usize);
327 });
328 }}
329 };
330}
331
332multicontrolled_qubit_gate!(
333 __quantum__qis__h__ctl,
335 QuantumSim::mch
336);
337multicontrolled_qubit_gate!(
338 __quantum__qis__s__ctl,
340 QuantumSim::mcs
341);
342multicontrolled_qubit_gate!(
343 __quantum__qis__s__ctladj,
345 QuantumSim::mcsadj
346);
347multicontrolled_qubit_gate!(
348 __quantum__qis__t__ctl,
350 QuantumSim::mct
351);
352multicontrolled_qubit_gate!(
353 __quantum__qis__t__ctladj,
355 QuantumSim::mctadj
356);
357multicontrolled_qubit_gate!(
358 __quantum__qis__x__ctl,
360 QuantumSim::mcx
361);
362multicontrolled_qubit_gate!(
363 __quantum__qis__y__ctl,
365 QuantumSim::mcy
366);
367multicontrolled_qubit_gate!(
368 __quantum__qis__z__ctl,
370 QuantumSim::mcz
371);
372
373#[derive(Copy, Clone)]
374#[repr(C)]
375struct RotationArgs {
376 theta: c_double,
377 qubit: *mut c_void,
378}
379
380macro_rules! multicontrolled_qubit_rotation {
381 ($(#[$meta:meta])*
382 $qir_name:ident, $gate:expr) => {
383 $(#[$meta])*
384 #[unsafe(no_mangle)]
388 #[allow(clippy::cast_ptr_alignment)]
389 pub unsafe extern "C" fn $qir_name(
390 ctls: *const QirArray,
391 arg_tuple: *mut *const Vec<u8>,
392 ) { unsafe {
393 SIM_STATE.with(|sim_state| {
394 let state = &mut *sim_state.borrow_mut();
395
396 let args = *arg_tuple.cast::<RotationArgs>();
397
398 ensure_sufficient_qubits(&mut state.sim, args.qubit as usize, &mut state.max_qubit_id);
399 let ctls_size = __quantum__rt__array_get_size_1d(ctls);
400 let ctls_list: Vec<usize> = (0..ctls_size)
401 .map(|index| {
402 let q = *__quantum__rt__array_get_element_ptr_1d(ctls, index)
403 .cast::<*mut c_void>() as usize;
404 ensure_sufficient_qubits(&mut state.sim, q, &mut state.max_qubit_id);
405 q
406 })
407 .collect();
408
409 $gate(
410 &mut state.sim,
411 &ctls_list,
412 args.theta,
413 args.qubit as usize,
414 );
415 });
416 }}
417 };
418}
419
420multicontrolled_qubit_rotation!(
421 __quantum__qis__rx__ctl,
423 QuantumSim::mcrx
424);
425multicontrolled_qubit_rotation!(
426 __quantum__qis__ry__ctl,
428 QuantumSim::mcry
429);
430multicontrolled_qubit_rotation!(
431 __quantum__qis__rz__ctl,
433 QuantumSim::mcrz
434);
435
436#[unsafe(no_mangle)]
438pub extern "C" fn __quantum__qis__sx__body(qubit: *mut c_void) {
439 __quantum__qis__h__body(qubit);
440 __quantum__qis__s__body(qubit);
441 __quantum__qis__h__body(qubit);
442}
443
444#[unsafe(no_mangle)]
446pub extern "C" fn __quantum__qis__rxx__body(
447 theta: c_double,
448 qubit1: *mut c_void,
449 qubit2: *mut c_void,
450) {
451 __quantum__qis__h__body(qubit1);
452
453 __quantum__qis__h__body(qubit2);
454
455 __quantum__qis__rzz__body(theta, qubit1, qubit2);
456
457 __quantum__qis__h__body(qubit2);
458
459 __quantum__qis__h__body(qubit1);
460}
461
462#[unsafe(no_mangle)]
464pub extern "C" fn __quantum__qis__ryy__body(
465 theta: c_double,
466 qubit1: *mut c_void,
467 qubit2: *mut c_void,
468) {
469 __quantum__qis__h__body(qubit1);
470 __quantum__qis__s__body(qubit1);
471 __quantum__qis__h__body(qubit1);
472
473 __quantum__qis__h__body(qubit2);
474 __quantum__qis__s__body(qubit2);
475 __quantum__qis__h__body(qubit2);
476
477 __quantum__qis__rzz__body(theta, qubit1, qubit2);
478
479 __quantum__qis__h__body(qubit2);
480 __quantum__qis__s__adj(qubit2);
481 __quantum__qis__h__body(qubit2);
482
483 __quantum__qis__h__body(qubit1);
484 __quantum__qis__s__adj(qubit1);
485 __quantum__qis__h__body(qubit1);
486}
487
488#[unsafe(no_mangle)]
490pub extern "C" fn __quantum__qis__rzz__body(
491 theta: c_double,
492 qubit1: *mut c_void,
493 qubit2: *mut c_void,
494) {
495 __quantum__qis__cx__body(qubit2, qubit1);
496 __quantum__qis__rz__body(theta, qubit1);
497 __quantum__qis__cx__body(qubit2, qubit1);
498}
499
500#[unsafe(no_mangle)]
502pub extern "C" fn __quantum__qis__r__body(pauli: Pauli, theta: c_double, qubit: *mut c_void) {
503 match pauli {
504 Pauli::I => (),
505 Pauli::X => __quantum__qis__rx__body(theta, qubit),
506 Pauli::Y => __quantum__qis__ry__body(theta, qubit),
507 Pauli::Z => __quantum__qis__rz__body(theta, qubit),
508 }
509}
510
511#[unsafe(no_mangle)]
513pub extern "C" fn __quantum__qis__r__adj(pauli: Pauli, theta: c_double, qubit: *mut c_void) {
514 __quantum__qis__r__body(pauli, -theta, qubit);
515}
516
517#[derive(Copy, Clone)]
518#[repr(C)]
519struct PauliRotationArgs {
520 pauli: Pauli,
521 theta: c_double,
522 qubit: *mut c_void,
523}
524
525#[allow(clippy::cast_ptr_alignment)]
530#[unsafe(no_mangle)]
531pub unsafe extern "C" fn __quantum__qis__r__ctl(
532 ctls: *const QirArray,
533 arg_tuple: *mut *const Vec<u8>,
534) {
535 unsafe {
536 let args = *arg_tuple.cast::<PauliRotationArgs>();
537 let rot_args = RotationArgs {
538 theta: args.theta,
539 qubit: args.qubit,
540 };
541 let rot_arg_tuple = __quantum__rt__tuple_create(size_of::<RotationArgs>() as u64);
542 *rot_arg_tuple.cast::<RotationArgs>() = rot_args;
543
544 match args.pauli {
545 Pauli::X => __quantum__qis__rx__ctl(ctls, rot_arg_tuple),
546 Pauli::Y => __quantum__qis__ry__ctl(ctls, rot_arg_tuple),
547 Pauli::Z => __quantum__qis__rz__ctl(ctls, rot_arg_tuple),
548 Pauli::I => {
549 if __quantum__rt__array_get_size_1d(ctls) > 0 {
550 SIM_STATE.with(|sim_state| {
551 let state = &mut *sim_state.borrow_mut();
552
553 ensure_sufficient_qubits(
554 &mut state.sim,
555 args.qubit as usize,
556 &mut state.max_qubit_id,
557 );
558 let ctls_size = __quantum__rt__array_get_size_1d(ctls);
559 let ctls_list: Vec<usize> = (0..ctls_size)
560 .map(|index| {
561 let q = *__quantum__rt__array_get_element_ptr_1d(ctls, index)
562 .cast::<*mut c_void>()
563 as usize;
564 ensure_sufficient_qubits(
565 &mut state.sim,
566 q,
567 &mut state.max_qubit_id,
568 );
569 q
570 })
571 .collect();
572
573 if let Some((head, rest)) = ctls_list.split_first() {
574 state.sim.mcphase(
575 rest,
576 Complex64::exp(Complex64::new(0.0, -args.theta / 2.0)),
577 *head,
578 );
579 }
580 });
581 }
582 }
583 }
584
585 __quantum__rt__tuple_update_reference_count(rot_arg_tuple, -1);
586 }
587}
588
589#[unsafe(no_mangle)]
594pub unsafe extern "C" fn __quantum__qis__r__ctladj(
595 ctls: *const QirArray,
596 arg_tuple: *mut *const Vec<u8>,
597) {
598 unsafe {
599 let args = *arg_tuple.cast::<PauliRotationArgs>();
600 let new_args = PauliRotationArgs {
601 pauli: args.pauli,
602 theta: -args.theta,
603 qubit: args.qubit,
604 };
605 let new_arg_tuple = __quantum__rt__tuple_create(size_of::<PauliRotationArgs>() as u64);
606 *new_arg_tuple.cast::<PauliRotationArgs>() = new_args;
607 __quantum__qis__r__ctl(ctls, new_arg_tuple);
608 __quantum__rt__tuple_update_reference_count(new_arg_tuple, -1);
609 }
610}
611
612#[unsafe(no_mangle)]
614pub extern "C" fn __quantum__qis__swap__body(qubit1: *mut c_void, qubit2: *mut c_void) {
615 SIM_STATE.with(|sim_state| {
616 let state = &mut *sim_state.borrow_mut();
617 ensure_sufficient_qubits(&mut state.sim, qubit1 as usize, &mut state.max_qubit_id);
618 ensure_sufficient_qubits(&mut state.sim, qubit2 as usize, &mut state.max_qubit_id);
619
620 state.sim.swap_qubit_ids(qubit1 as usize, qubit2 as usize);
621 });
622}
623
624#[unsafe(no_mangle)]
626pub extern "C" fn __quantum__qis__reset__body(qubit: *mut c_void) {
627 SIM_STATE.with(|sim_state| {
628 let state = &mut *sim_state.borrow_mut();
629 ensure_sufficient_qubits(&mut state.sim, qubit as usize, &mut state.max_qubit_id);
630
631 if state.sim.measure(qubit as usize) {
632 state.sim.x(qubit as usize);
633 }
634 });
635}
636
637#[allow(clippy::missing_panics_doc)]
640#[unsafe(no_mangle)]
642pub extern "C" fn __quantum__qis__mresetz__body(qubit: *mut c_void, result: *mut c_void) {
643 SIM_STATE.with(|sim_state| {
644 let state = &mut *sim_state.borrow_mut();
645 let res_id = result as usize;
646 ensure_sufficient_qubits(&mut state.sim, qubit as usize, &mut state.max_qubit_id);
647
648 if state.res.len() < res_id + 1 {
649 state.res.resize(res_id + 1, false);
650 }
651
652 let res = state.sim.measure(qubit as usize);
653
654 if res {
655 state.sim.x(qubit as usize);
656 }
657
658 *state
659 .res
660 .get_mut(res_id)
661 .expect("Result with given id missing after expansion.") = res;
662 });
663}
664
665#[allow(clippy::missing_panics_doc)]
667#[unsafe(no_mangle)]
669pub extern "C" fn __quantum__qis__mz__body(qubit: *mut c_void, result: *mut c_void) {
670 SIM_STATE.with(|sim_state| {
671 let state = &mut *sim_state.borrow_mut();
672 let res_id = result as usize;
673 ensure_sufficient_qubits(&mut state.sim, qubit as usize, &mut state.max_qubit_id);
674
675 if state.res.len() < res_id + 1 {
676 state.res.resize(res_id + 1, false);
677 }
678
679 *state
680 .res
681 .get_mut(res_id)
682 .expect("Result with given id missing after expansion.") =
683 state.sim.measure(qubit as usize);
684 });
685}
686
687#[allow(clippy::missing_panics_doc)]
690#[unsafe(no_mangle)]
692pub extern "C" fn __quantum__qis__read_result__body(result: *mut c_void) -> bool {
693 SIM_STATE.with(|sim_state| {
694 let res = &mut sim_state.borrow_mut().res;
695 let res_id = result as usize;
696 if res.len() < res_id + 1 {
697 res.resize(res_id + 1, false);
698 }
699
700 *res.get(res_id)
701 .expect("Result with given id missing after expansion.")
702 })
703}
704
705#[allow(clippy::missing_panics_doc)]
708#[unsafe(no_mangle)]
710pub extern "C" fn __quantum__rt__read_result(result: *mut c_void) -> bool {
711 __quantum__qis__read_result__body(result)
712}
713
714#[unsafe(no_mangle)]
716pub extern "C" fn __quantum__qis__m__body(qubit: *mut c_void) -> *mut c_void {
717 SIM_STATE.with(|sim_state| {
718 let state = &mut *sim_state.borrow_mut();
719 ensure_sufficient_qubits(&mut state.sim, qubit as usize, &mut state.max_qubit_id);
720
721 if state.sim.measure(qubit as usize) {
722 __quantum__rt__result_get_one()
723 } else {
724 __quantum__rt__result_get_zero()
725 }
726 })
727}
728
729#[allow(clippy::cast_ptr_alignment)]
737#[unsafe(no_mangle)]
738pub unsafe extern "C" fn __quantum__qis__measure__body(
739 paulis: *const QirArray,
740 qubits: *const QirArray,
741) -> *mut c_void {
742 unsafe {
743 SIM_STATE.with(|sim_state| {
744 let mut state = sim_state.borrow_mut();
745
746 let combined_list = map_to_z_basis(&mut state, paulis, qubits);
747
748 let res = state.sim.joint_measure(
749 &combined_list
750 .iter()
751 .map(|(_, q)| *q)
752 .collect::<Vec<usize>>(),
753 );
754
755 unmap_from_z_basis(&mut state, combined_list);
756
757 if res {
758 __quantum__rt__result_get_one()
759 } else {
760 __quantum__rt__result_get_zero()
761 }
762 })
763 }
764}
765
766pub fn qubit_is_zero(qubit: *mut c_void) -> bool {
768 SIM_STATE.with(|sim_state| {
769 let state = &mut *sim_state.borrow_mut();
770 ensure_sufficient_qubits(&mut state.sim, qubit as usize, &mut state.max_qubit_id);
771
772 state.sim.qubit_is_zero(qubit as usize)
773 })
774}
775
776#[unsafe(no_mangle)]
782pub unsafe extern "C" fn __quantum__qis__assertmeasurementprobability__body(
783 paulis: *const QirArray,
784 qubits: *const QirArray,
785 result: *mut c_void,
786 prob: c_double,
787 msg: *const CString,
788 tol: c_double,
789) {
790 unsafe {
791 SIM_STATE.with(|sim_state| {
792 let mut state = sim_state.borrow_mut();
793
794 let combined_list = map_to_z_basis(&mut state, paulis, qubits);
795
796 let mut actual_prob = state.sim.joint_probability(
797 &combined_list
798 .iter()
799 .map(|(_, q)| *q)
800 .collect::<Vec<usize>>(),
801 );
802
803 if __quantum__rt__result_equal(result, __quantum__rt__result_get_zero()) {
804 actual_prob = 1.0 - actual_prob;
805 }
806
807 if (actual_prob - prob).abs() > tol {
808 __quantum__rt__fail(msg);
809 }
810
811 unmap_from_z_basis(&mut state, combined_list);
812 });
813 }
814}
815
816#[derive(Copy, Clone)]
817#[repr(C)]
818struct AssertMeasurementProbabilityArgs {
819 paulis: *const QirArray,
820 qubits: *const QirArray,
821 result: *mut c_void,
822 prob: c_double,
823 msg: *const CString,
824 tol: c_double,
825}
826
827#[unsafe(no_mangle)]
834pub unsafe extern "C" fn __quantum__qis__assertmeasurementprobability__ctl(
835 _ctls: *const QirArray,
836 arg_tuple: *mut *const Vec<u8>,
837) {
838 unsafe {
839 let args = *arg_tuple.cast::<AssertMeasurementProbabilityArgs>();
840 __quantum__qis__assertmeasurementprobability__body(
841 args.paulis,
842 args.qubits,
843 args.result,
844 args.prob,
845 args.msg,
846 args.tol,
847 );
848 }
849}
850
851pub mod legacy_output {
852 use std::ffi::c_void;
853
854 use qir_stdlib::output_recording::record_output_str;
855
856 use crate::{
857 SIM_STATE,
858 result_bool::{__quantum__rt__result_equal, __quantum__rt__result_get_one},
859 };
860
861 #[allow(clippy::missing_panics_doc)]
862 #[allow(non_snake_case)]
864 pub extern "C" fn __quantum__rt__result_record_output(result: *mut c_void) {
865 SIM_STATE.with(|sim_state| {
866 let res = &mut sim_state.borrow_mut().res;
867 let res_id = result as usize;
868 let b = if res.is_empty() {
869 __quantum__rt__result_equal(result, __quantum__rt__result_get_one())
871 } else {
872 if res.len() < res_id + 1 {
873 res.resize(res_id + 1, false);
874 }
875 *res.get(res_id)
876 .expect("Result with given id missing after expansion.")
877 };
878
879 record_output_str(&format!("RESULT\t{}", if b { "1" } else { "0" }))
880 .expect("Failed to write result output");
881 });
882 }
883}
884
885#[allow(clippy::missing_panics_doc)]
887#[unsafe(no_mangle)]
891pub unsafe extern "C" fn __quantum__rt__result_record_output(
892 result: *mut c_void,
893 tag: *mut c_char,
894) {
895 unsafe {
896 SIM_STATE.with(|sim_state| {
897 let res = &mut sim_state.borrow_mut().res;
898 let res_id = result as usize;
899 let b = if res.is_empty() {
900 __quantum__rt__result_equal(result, __quantum__rt__result_get_one())
902 } else {
903 if res.len() < res_id + 1 {
904 res.resize(res_id + 1, false);
905 }
906 *res.get(res_id)
907 .expect("Result with given id missing after expansion.")
908 };
909
910 let val: i64 = i64::from(b);
911 record_output("RESULT", &val, tag).expect("Failed to write result output");
912 });
913 }
914}
915
916#[unsafe(no_mangle)]
918pub extern "C" fn __quantum__rt__qubit_allocate() -> *mut c_void {
919 SIM_STATE.with(|sim_state| {
920 let mut state = sim_state.borrow_mut();
921 let qubit_id = state.sim.allocate();
922
923 state.max_qubit_id = state.max_qubit_id.max(qubit_id + 1);
926
927 qubit_id as *mut c_void
928 })
929}
930
931#[allow(clippy::cast_ptr_alignment)]
935#[unsafe(no_mangle)]
936pub extern "C" fn __quantum__rt__qubit_allocate_array(size: u64) -> *const QirArray {
937 let arr = __quantum__rt__array_create_1d(
938 size_of::<usize>()
939 .try_into()
940 .expect("System pointer size too large to be described with u32."),
941 size,
942 );
943 for index in 0..size {
944 unsafe {
945 let elem = __quantum__rt__array_get_element_ptr_1d(arr, index).cast::<*mut c_void>();
946 *elem = __quantum__rt__qubit_allocate();
947 }
948 }
949 arr
950}
951
952#[allow(clippy::cast_ptr_alignment)]
957#[unsafe(no_mangle)]
958pub unsafe extern "C" fn __quantum__rt__qubit_release_array(arr: *const QirArray) {
959 unsafe {
960 for index in 0..__quantum__rt__array_get_size_1d(arr) {
961 let elem = __quantum__rt__array_get_element_ptr_1d(arr, index).cast::<*mut c_void>();
962 __quantum__rt__qubit_release(*elem);
963 }
964 __quantum__rt__array_update_alias_count(arr, -1);
965 }
966}
967
968#[unsafe(no_mangle)]
970pub extern "C" fn __quantum__rt__qubit_release(qubit: *mut c_void) {
971 SIM_STATE.with(|sim_state| {
972 let mut state = sim_state.borrow_mut();
973 state.sim.release(qubit as usize);
974 });
975}
976
977#[unsafe(no_mangle)]
981pub extern "C" fn __quantum__rt__qubit_to_string(qubit: *mut c_void) -> *const CString {
982 unsafe {
983 __quantum__rt__string_create(
984 CString::new(format!("{}", qubit as usize))
985 .expect("Unable to allocate memory for qubit string.")
986 .as_bytes_with_nul()
987 .as_ptr() as *mut c_char,
988 )
989 }
990}
991
992#[must_use]
996pub fn capture_quantum_state() -> (Vec<(BigUint, Complex64)>, usize) {
997 SIM_STATE.with(|sim_state| {
998 let mut state = sim_state.borrow_mut();
999 state.sim.get_state()
1000 })
1001}
1002
1003#[unsafe(no_mangle)]
1007pub extern "C" fn __quantum__qis__dumpmachine__body(location: *mut c_void) {
1008 if !location.is_null() {
1009 unimplemented!("Dump to location is not implemented.")
1010 }
1011 SIM_STATE.with(|sim_state| {
1012 let mut state = sim_state.borrow_mut();
1013
1014 if !state.res.is_empty() {
1015 OUTPUT.with(|output| {
1016 let mut output = output.borrow_mut();
1017 output
1018 .write_fmt(format_args!("Global Results: {}", state.res))
1019 .expect("Failed to write global results");
1020 output.write_newline();
1021 });
1022 }
1023 OUTPUT.with(|output| {
1024 let mut output = output.borrow_mut();
1025 output
1026 .write_all(state.sim.dump().as_bytes())
1027 .expect("Failed to write simulator state");
1028 });
1029 });
1030}
1031
1032#[unsafe(no_mangle)]
1034pub extern "C" fn __quantum__qis__barrier__body() {
1035 }
1037
1038#[cfg(test)]
1039#[allow(clippy::manual_dangling_ptr)]
1040mod tests {
1041 use std::{f64::consts::PI, ffi::c_void, ptr::null_mut};
1042
1043 use crate::{
1044 __quantum__qis__cnot__body, __quantum__qis__cx__body, __quantum__qis__cz__body,
1045 __quantum__qis__dumpmachine__body, __quantum__qis__h__body, __quantum__qis__m__body,
1046 __quantum__qis__mresetz__body, __quantum__qis__mz__body, __quantum__qis__read_result__body,
1047 __quantum__qis__rx__body, __quantum__qis__rxx__body, __quantum__qis__ry__body,
1048 __quantum__qis__ryy__body, __quantum__qis__rz__body, __quantum__qis__rzz__body,
1049 __quantum__qis__s__adj, __quantum__qis__s__body, __quantum__qis__x__body,
1050 __quantum__rt__qubit_allocate, __quantum__rt__qubit_allocate_array,
1051 __quantum__rt__qubit_release, __quantum__rt__qubit_release_array,
1052 __quantum__rt__result_equal, SIM_STATE, capture_quantum_state, map_to_z_basis,
1053 qubit_is_zero, result_bool::__quantum__rt__result_get_one, unmap_from_z_basis,
1054 };
1055 use num_bigint::BigUint;
1056 use qir_stdlib::{
1057 Pauli,
1058 arrays::{
1059 __quantum__rt__array_create_1d, __quantum__rt__array_get_element_ptr_1d,
1060 __quantum__rt__array_update_reference_count,
1061 },
1062 };
1063
1064 #[test]
1065 fn basic_test_static() {
1066 let q0 = 5 as *mut c_void;
1067 let r0 = std::ptr::null_mut();
1068 let r1 = 1 as *mut c_void;
1069 __quantum__qis__mz__body(q0, r0);
1070 assert!(!__quantum__qis__read_result__body(r0));
1071 __quantum__qis__x__body(q0);
1072 __quantum__qis__mz__body(q0, r1);
1073 assert!(__quantum__qis__read_result__body(r1));
1074 __quantum__qis__x__body(q0);
1075 __quantum__qis__mz__body(q0, r0);
1076 assert!(!__quantum__qis__read_result__body(r0));
1077 assert!(!__quantum__qis__read_result__body(3 as *mut c_void));
1078 __quantum__qis__dumpmachine__body(null_mut());
1079 }
1080
1081 #[allow(clippy::cast_ptr_alignment)]
1082 #[test]
1083 fn basic_test_dynamic() {
1084 let q1 = __quantum__rt__qubit_allocate();
1085 let q2 = __quantum__rt__qubit_allocate();
1086 __quantum__qis__h__body(q1);
1087 __quantum__qis__cnot__body(q1, q2);
1088 let r1 = __quantum__qis__m__body(q1);
1089 let r2 = __quantum__qis__m__body(q2);
1090 assert!(__quantum__rt__result_equal(r1, r2));
1091 __quantum__qis__dumpmachine__body(null_mut());
1092 __quantum__rt__qubit_release(q2);
1093 __quantum__rt__qubit_release(q1);
1094 let qs = __quantum__rt__qubit_allocate_array(4);
1095 unsafe {
1096 let q_elem = __quantum__rt__array_get_element_ptr_1d(qs, 3).cast::<*mut c_void>();
1097 __quantum__qis__x__body(*q_elem);
1098 __quantum__qis__dumpmachine__body(null_mut());
1099 let r = __quantum__qis__m__body(*q_elem);
1100 assert!(__quantum__rt__result_equal(
1101 r,
1102 __quantum__rt__result_get_one()
1103 ));
1104 __quantum__rt__qubit_release_array(qs);
1105 }
1106 }
1107
1108 #[test]
1109 fn test_qubit_is_zero() {
1110 let q0 = __quantum__rt__qubit_allocate();
1111 assert!(qubit_is_zero(q0));
1112 __quantum__qis__x__body(q0);
1113 assert!(!qubit_is_zero(q0));
1114 __quantum__qis__h__body(q0);
1115 assert!(!qubit_is_zero(q0));
1116 let r = __quantum__qis__m__body(q0);
1117 assert!(
1118 qubit_is_zero(q0) != __quantum__rt__result_equal(r, __quantum__rt__result_get_one())
1119 );
1120 }
1121
1122 #[allow(clippy::cast_ptr_alignment)]
1123 #[test]
1124 fn test_map_unmap_are_adjoint() {
1125 unsafe fn check_map_unmap(pauli: Pauli) {
1126 unsafe {
1127 let check_qubit = __quantum__rt__qubit_allocate();
1128 let qubits = __quantum__rt__qubit_allocate_array(1);
1129 let q = *__quantum__rt__array_get_element_ptr_1d(qubits, 0).cast::<*mut c_void>();
1130 let paulis = __quantum__rt__array_create_1d(1, 1);
1131 *__quantum__rt__array_get_element_ptr_1d(paulis, 0).cast::<Pauli>() = pauli;
1132
1133 __quantum__qis__h__body(check_qubit);
1134 __quantum__qis__cnot__body(check_qubit, q);
1135
1136 SIM_STATE.with(|sim_state| {
1137 let state = &mut *sim_state.borrow_mut();
1138 let combined_list = map_to_z_basis(state, paulis, qubits);
1139 unmap_from_z_basis(state, combined_list);
1140 });
1141
1142 __quantum__qis__cnot__body(check_qubit, q);
1143 __quantum__qis__h__body(check_qubit);
1144
1145 assert!(qubit_is_zero(q));
1146 assert!(qubit_is_zero(check_qubit));
1147
1148 __quantum__rt__array_update_reference_count(paulis, -1);
1149 __quantum__rt__qubit_release_array(qubits);
1150 __quantum__rt__qubit_release(check_qubit);
1151 }
1152 }
1153
1154 unsafe {
1155 check_map_unmap(Pauli::X);
1156 check_map_unmap(Pauli::Y);
1157 check_map_unmap(Pauli::Z);
1158 }
1159 }
1160
1161 #[allow(clippy::cast_ptr_alignment)]
1162 #[test]
1163 fn test_map_pauli_x() {
1164 let qubits = __quantum__rt__qubit_allocate_array(1);
1165 unsafe {
1166 let q = *__quantum__rt__array_get_element_ptr_1d(qubits, 0).cast::<*mut c_void>();
1167 let paulis = __quantum__rt__array_create_1d(1, 1);
1168 *__quantum__rt__array_get_element_ptr_1d(paulis, 0).cast::<Pauli>() = Pauli::X;
1169
1170 __quantum__qis__h__body(q);
1171
1172 SIM_STATE.with(|sim_state| {
1173 let state = &mut *sim_state.borrow_mut();
1174 let _ = map_to_z_basis(state, paulis, qubits);
1175 });
1176
1177 qubit_is_zero(q);
1178
1179 __quantum__rt__array_update_reference_count(paulis, -1);
1180 __quantum__rt__qubit_release_array(qubits);
1181 }
1182 }
1183
1184 #[allow(clippy::cast_ptr_alignment)]
1185 #[test]
1186 fn test_map_pauli_y() {
1187 let qubits = __quantum__rt__qubit_allocate_array(1);
1188 unsafe {
1189 let q = *__quantum__rt__array_get_element_ptr_1d(qubits, 0).cast::<*mut c_void>();
1190 let paulis = __quantum__rt__array_create_1d(1, 1);
1191 *__quantum__rt__array_get_element_ptr_1d(paulis, 0).cast::<Pauli>() = Pauli::Y;
1192
1193 __quantum__qis__h__body(q);
1194 __quantum__qis__s__adj(q);
1195 __quantum__qis__h__body(q);
1196
1197 SIM_STATE.with(|sim_state| {
1198 let state = &mut *sim_state.borrow_mut();
1199 let _ = map_to_z_basis(state, paulis, qubits);
1200 });
1201
1202 qubit_is_zero(q);
1203
1204 __quantum__rt__array_update_reference_count(paulis, -1);
1205 __quantum__rt__qubit_release_array(qubits);
1206 }
1207 }
1208
1209 #[allow(clippy::cast_ptr_alignment)]
1210 #[test]
1211 fn test_map_pauli_z() {
1212 let qubits = __quantum__rt__qubit_allocate_array(1);
1213 unsafe {
1214 let q = *__quantum__rt__array_get_element_ptr_1d(qubits, 0).cast::<*mut c_void>();
1215 let paulis = __quantum__rt__array_create_1d(1, 1);
1216 *__quantum__rt__array_get_element_ptr_1d(paulis, 0).cast::<Pauli>() = Pauli::Z;
1217
1218 SIM_STATE.with(|sim_state| {
1219 let state = &mut *sim_state.borrow_mut();
1220 let _ = map_to_z_basis(state, paulis, qubits);
1221 });
1222
1223 qubit_is_zero(q);
1224
1225 __quantum__rt__array_update_reference_count(paulis, -1);
1226 __quantum__rt__qubit_release_array(qubits);
1227 }
1228 }
1229
1230 #[test]
1231 fn test_joint_zz() {
1232 let check_qubit = __quantum__rt__qubit_allocate();
1233 let q0 = __quantum__rt__qubit_allocate();
1234 let q1 = __quantum__rt__qubit_allocate();
1235
1236 __quantum__qis__h__body(check_qubit);
1237 __quantum__qis__cx__body(check_qubit, q0);
1238 __quantum__qis__cx__body(check_qubit, q1);
1239
1240 __quantum__qis__rzz__body(PI / 2.0, q0, q1);
1241 __quantum__qis__rz__body(-PI / 2.0, q0);
1242 __quantum__qis__rz__body(-PI / 2.0, q1);
1243
1244 __quantum__qis__cz__body(q0, q1);
1245
1246 __quantum__qis__cx__body(check_qubit, q1);
1247 __quantum__qis__cx__body(check_qubit, q0);
1248 __quantum__qis__h__body(check_qubit);
1249
1250 assert!(qubit_is_zero(check_qubit));
1251 assert!(qubit_is_zero(q0));
1252 assert!(qubit_is_zero(q1));
1253 }
1254
1255 #[test]
1256 fn test_joint_yy() {
1257 let check_qubit = __quantum__rt__qubit_allocate();
1258 let q0 = __quantum__rt__qubit_allocate();
1259 let q1 = __quantum__rt__qubit_allocate();
1260
1261 __quantum__qis__h__body(check_qubit);
1262 __quantum__qis__cx__body(check_qubit, q0);
1263 __quantum__qis__cx__body(check_qubit, q1);
1264
1265 __quantum__qis__h__body(q0);
1266 __quantum__qis__s__adj(q0);
1267 __quantum__qis__h__body(q0);
1268 __quantum__qis__h__body(q1);
1269 __quantum__qis__s__adj(q1);
1270 __quantum__qis__h__body(q1);
1271
1272 __quantum__qis__ryy__body(PI / 2.0, q0, q1);
1273 __quantum__qis__ry__body(-PI / 2.0, q0);
1274 __quantum__qis__ry__body(-PI / 2.0, q1);
1275
1276 __quantum__qis__h__body(q1);
1277 __quantum__qis__s__body(q1);
1278 __quantum__qis__h__body(q1);
1279 __quantum__qis__h__body(q0);
1280 __quantum__qis__s__body(q0);
1281 __quantum__qis__h__body(q0);
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_joint_xx() {
1296 let check_qubit = __quantum__rt__qubit_allocate();
1297 let q0 = __quantum__rt__qubit_allocate();
1298 let q1 = __quantum__rt__qubit_allocate();
1299
1300 __quantum__qis__h__body(check_qubit);
1301 __quantum__qis__cx__body(check_qubit, q0);
1302 __quantum__qis__cx__body(check_qubit, q1);
1303
1304 __quantum__qis__h__body(q0);
1305 __quantum__qis__h__body(q1);
1306
1307 __quantum__qis__rxx__body(PI / 2.0, q0, q1);
1308 __quantum__qis__rx__body(-PI / 2.0, q0);
1309 __quantum__qis__rx__body(-PI / 2.0, q1);
1310
1311 __quantum__qis__h__body(q0);
1312 __quantum__qis__h__body(q1);
1313
1314 __quantum__qis__cz__body(q0, q1);
1315
1316 __quantum__qis__cx__body(check_qubit, q1);
1317 __quantum__qis__cx__body(check_qubit, q0);
1318 __quantum__qis__h__body(check_qubit);
1319
1320 assert!(qubit_is_zero(check_qubit));
1321 assert!(qubit_is_zero(q0));
1322 assert!(qubit_is_zero(q1));
1323 }
1324
1325 #[test]
1326 fn test_mresetz() {
1327 let qubit = __quantum__rt__qubit_allocate();
1328 let r0 = std::ptr::null_mut();
1329 let r1 = 1 as *mut c_void;
1330 assert!(qubit_is_zero(qubit));
1331 __quantum__qis__mresetz__body(qubit, r0);
1332 assert!(!__quantum__qis__read_result__body(r0));
1333 assert!(qubit_is_zero(qubit));
1334 __quantum__qis__x__body(qubit);
1335 __quantum__qis__mresetz__body(qubit, r1);
1336 assert!(__quantum__qis__read_result__body(r1));
1337 assert!(qubit_is_zero(qubit));
1338 }
1339
1340 #[test]
1341 fn test_capture_quantum_state() {
1342 let qubit = __quantum__rt__qubit_allocate();
1343 let (state, qubit_count) = capture_quantum_state();
1344 assert_eq!(qubit_count, 1);
1345 assert_eq!(state.len(), 1);
1346 assert_eq!(state[0].0, BigUint::from(0u32));
1347 __quantum__qis__x__body(qubit);
1348 let (state, qubit_count) = capture_quantum_state();
1349 assert_eq!(qubit_count, 1);
1350 assert_eq!(state.len(), 1);
1351 assert_eq!(state[0].0, BigUint::from(1u32));
1352 __quantum__qis__h__body(qubit);
1353 let qubit2 = __quantum__rt__qubit_allocate();
1354 let (state, qubit_count) = capture_quantum_state();
1355 assert_eq!(qubit_count, 2);
1356 assert_eq!(state.len(), 2);
1357 assert_eq!(state[0].1, -state[1].1);
1358 __quantum__qis__h__body(qubit);
1359 __quantum__qis__x__body(qubit);
1360 let (state, qubit_count) = capture_quantum_state();
1361 assert_eq!(qubit_count, 2);
1362 assert_eq!(state.len(), 1);
1363 assert_eq!(state[0].0, BigUint::from(0u32));
1364 __quantum__rt__qubit_release(qubit);
1365 __quantum__rt__qubit_release(qubit2);
1366 let (state, qubit_count) = capture_quantum_state();
1367 assert_eq!(qubit_count, 0);
1368 assert_eq!(state.len(), 1);
1369 assert_eq!(state[0].0, BigUint::from(0u32));
1370 }
1371}