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#[allow(clippy::missing_panics_doc)]
716#[unsafe(no_mangle)]
718pub extern "C" fn __quantum__rt__write_result(value: bool, result: *mut c_void) {
719 SIM_STATE.with(|sim_state| {
720 let res = &mut sim_state.borrow_mut().res;
721 let res_id = result as usize;
722 if res.len() < res_id + 1 {
723 res.resize(res_id + 1, false);
724 }
725
726 *res.get_mut(res_id)
727 .expect("Result with given id missing after expansion.") = value;
728 });
729}
730
731#[unsafe(no_mangle)]
733pub extern "C" fn __quantum__qis__m__body(qubit: *mut c_void) -> *mut c_void {
734 SIM_STATE.with(|sim_state| {
735 let state = &mut *sim_state.borrow_mut();
736 ensure_sufficient_qubits(&mut state.sim, qubit as usize, &mut state.max_qubit_id);
737
738 if state.sim.measure(qubit as usize) {
739 __quantum__rt__result_get_one()
740 } else {
741 __quantum__rt__result_get_zero()
742 }
743 })
744}
745
746#[allow(clippy::cast_ptr_alignment)]
754#[unsafe(no_mangle)]
755pub unsafe extern "C" fn __quantum__qis__measure__body(
756 paulis: *const QirArray,
757 qubits: *const QirArray,
758) -> *mut c_void {
759 unsafe {
760 SIM_STATE.with(|sim_state| {
761 let mut state = sim_state.borrow_mut();
762
763 let combined_list = map_to_z_basis(&mut state, paulis, qubits);
764
765 let res = state.sim.joint_measure(
766 &combined_list
767 .iter()
768 .map(|(_, q)| *q)
769 .collect::<Vec<usize>>(),
770 );
771
772 unmap_from_z_basis(&mut state, combined_list);
773
774 if res {
775 __quantum__rt__result_get_one()
776 } else {
777 __quantum__rt__result_get_zero()
778 }
779 })
780 }
781}
782
783pub fn qubit_is_zero(qubit: *mut c_void) -> bool {
785 SIM_STATE.with(|sim_state| {
786 let state = &mut *sim_state.borrow_mut();
787 ensure_sufficient_qubits(&mut state.sim, qubit as usize, &mut state.max_qubit_id);
788
789 state.sim.qubit_is_zero(qubit as usize)
790 })
791}
792
793#[unsafe(no_mangle)]
799pub unsafe extern "C" fn __quantum__qis__assertmeasurementprobability__body(
800 paulis: *const QirArray,
801 qubits: *const QirArray,
802 result: *mut c_void,
803 prob: c_double,
804 msg: *const CString,
805 tol: c_double,
806) {
807 unsafe {
808 SIM_STATE.with(|sim_state| {
809 let mut state = sim_state.borrow_mut();
810
811 let combined_list = map_to_z_basis(&mut state, paulis, qubits);
812
813 let mut actual_prob = state.sim.joint_probability(
814 &combined_list
815 .iter()
816 .map(|(_, q)| *q)
817 .collect::<Vec<usize>>(),
818 );
819
820 if __quantum__rt__result_equal(result, __quantum__rt__result_get_zero()) {
821 actual_prob = 1.0 - actual_prob;
822 }
823
824 if (actual_prob - prob).abs() > tol {
825 __quantum__rt__fail(msg);
826 }
827
828 unmap_from_z_basis(&mut state, combined_list);
829 });
830 }
831}
832
833#[derive(Copy, Clone)]
834#[repr(C)]
835struct AssertMeasurementProbabilityArgs {
836 paulis: *const QirArray,
837 qubits: *const QirArray,
838 result: *mut c_void,
839 prob: c_double,
840 msg: *const CString,
841 tol: c_double,
842}
843
844#[unsafe(no_mangle)]
851pub unsafe extern "C" fn __quantum__qis__assertmeasurementprobability__ctl(
852 _ctls: *const QirArray,
853 arg_tuple: *mut *const Vec<u8>,
854) {
855 unsafe {
856 let args = *arg_tuple.cast::<AssertMeasurementProbabilityArgs>();
857 __quantum__qis__assertmeasurementprobability__body(
858 args.paulis,
859 args.qubits,
860 args.result,
861 args.prob,
862 args.msg,
863 args.tol,
864 );
865 }
866}
867
868pub mod legacy_output {
869 use std::ffi::c_void;
870
871 use qir_stdlib::output_recording::record_output_str;
872
873 use crate::{
874 SIM_STATE,
875 result_bool::{__quantum__rt__result_equal, __quantum__rt__result_get_one},
876 };
877
878 #[allow(clippy::missing_panics_doc)]
879 #[allow(non_snake_case)]
881 pub extern "C" fn __quantum__rt__result_record_output(result: *mut c_void) {
882 SIM_STATE.with(|sim_state| {
883 let res = &mut sim_state.borrow_mut().res;
884 let res_id = result as usize;
885 let b = if res.is_empty() {
886 __quantum__rt__result_equal(result, __quantum__rt__result_get_one())
888 } else {
889 if res.len() < res_id + 1 {
890 res.resize(res_id + 1, false);
891 }
892 *res.get(res_id)
893 .expect("Result with given id missing after expansion.")
894 };
895
896 record_output_str(&format!("RESULT\t{}", if b { "1" } else { "0" }))
897 .expect("Failed to write result output");
898 });
899 }
900}
901
902#[allow(clippy::missing_panics_doc)]
904#[unsafe(no_mangle)]
908pub unsafe extern "C" fn __quantum__rt__result_record_output(
909 result: *mut c_void,
910 tag: *mut c_char,
911) {
912 unsafe {
913 SIM_STATE.with(|sim_state| {
914 let res = &mut sim_state.borrow_mut().res;
915 let res_id = result as usize;
916 let b = if res.is_empty() {
917 __quantum__rt__result_equal(result, __quantum__rt__result_get_one())
919 } else {
920 if res.len() < res_id + 1 {
921 res.resize(res_id + 1, false);
922 }
923 *res.get(res_id)
924 .expect("Result with given id missing after expansion.")
925 };
926
927 let val: i64 = i64::from(b);
928 record_output("RESULT", &val, tag).expect("Failed to write result output");
929 });
930 }
931}
932
933#[unsafe(no_mangle)]
935pub extern "C" fn __quantum__rt__qubit_allocate() -> *mut c_void {
936 SIM_STATE.with(|sim_state| {
937 let mut state = sim_state.borrow_mut();
938 let qubit_id = state.sim.allocate();
939
940 state.max_qubit_id = state.max_qubit_id.max(qubit_id + 1);
943
944 qubit_id as *mut c_void
945 })
946}
947
948#[allow(clippy::cast_ptr_alignment)]
952#[unsafe(no_mangle)]
953pub extern "C" fn __quantum__rt__qubit_allocate_array(size: u64) -> *const QirArray {
954 let arr = __quantum__rt__array_create_1d(
955 size_of::<usize>()
956 .try_into()
957 .expect("System pointer size too large to be described with u32."),
958 size,
959 );
960 for index in 0..size {
961 unsafe {
962 let elem = __quantum__rt__array_get_element_ptr_1d(arr, index).cast::<*mut c_void>();
963 *elem = __quantum__rt__qubit_allocate();
964 }
965 }
966 arr
967}
968
969#[allow(clippy::cast_ptr_alignment)]
974#[unsafe(no_mangle)]
975pub unsafe extern "C" fn __quantum__rt__qubit_release_array(arr: *const QirArray) {
976 unsafe {
977 for index in 0..__quantum__rt__array_get_size_1d(arr) {
978 let elem = __quantum__rt__array_get_element_ptr_1d(arr, index).cast::<*mut c_void>();
979 __quantum__rt__qubit_release(*elem);
980 }
981 __quantum__rt__array_update_alias_count(arr, -1);
982 }
983}
984
985#[unsafe(no_mangle)]
987pub extern "C" fn __quantum__rt__qubit_release(qubit: *mut c_void) {
988 SIM_STATE.with(|sim_state| {
989 let mut state = sim_state.borrow_mut();
990 state.sim.release(qubit as usize);
991 });
992}
993
994#[unsafe(no_mangle)]
998pub extern "C" fn __quantum__rt__qubit_to_string(qubit: *mut c_void) -> *const CString {
999 unsafe {
1000 __quantum__rt__string_create(
1001 CString::new(format!("{}", qubit as usize))
1002 .expect("Unable to allocate memory for qubit string.")
1003 .as_bytes_with_nul()
1004 .as_ptr() as *mut c_char,
1005 )
1006 }
1007}
1008
1009#[must_use]
1013pub fn capture_quantum_state() -> (Vec<(BigUint, Complex64)>, usize) {
1014 SIM_STATE.with(|sim_state| {
1015 let mut state = sim_state.borrow_mut();
1016 state.sim.get_state()
1017 })
1018}
1019
1020#[unsafe(no_mangle)]
1024pub extern "C" fn __quantum__qis__dumpmachine__body(location: *mut c_void) {
1025 if !location.is_null() {
1026 unimplemented!("Dump to location is not implemented.")
1027 }
1028 SIM_STATE.with(|sim_state| {
1029 let mut state = sim_state.borrow_mut();
1030
1031 if !state.res.is_empty() {
1032 OUTPUT.with(|output| {
1033 let mut output = output.borrow_mut();
1034 output
1035 .write_fmt(format_args!("Global Results: {}", state.res))
1036 .expect("Failed to write global results");
1037 output.write_newline();
1038 });
1039 }
1040 OUTPUT.with(|output| {
1041 let mut output = output.borrow_mut();
1042 output
1043 .write_all(state.sim.dump().as_bytes())
1044 .expect("Failed to write simulator state");
1045 });
1046 });
1047}
1048
1049#[unsafe(no_mangle)]
1051pub extern "C" fn __quantum__qis__barrier__body() {
1052 }
1054
1055#[cfg(test)]
1056#[allow(clippy::manual_dangling_ptr)]
1057mod tests {
1058 use std::{f64::consts::PI, ffi::c_void, ptr::null_mut};
1059
1060 use crate::{
1061 __quantum__qis__cnot__body, __quantum__qis__cx__body, __quantum__qis__cz__body,
1062 __quantum__qis__dumpmachine__body, __quantum__qis__h__body, __quantum__qis__m__body,
1063 __quantum__qis__mresetz__body, __quantum__qis__mz__body, __quantum__qis__read_result__body,
1064 __quantum__qis__rx__body, __quantum__qis__rxx__body, __quantum__qis__ry__body,
1065 __quantum__qis__ryy__body, __quantum__qis__rz__body, __quantum__qis__rzz__body,
1066 __quantum__qis__s__adj, __quantum__qis__s__body, __quantum__qis__x__body,
1067 __quantum__rt__qubit_allocate, __quantum__rt__qubit_allocate_array,
1068 __quantum__rt__qubit_release, __quantum__rt__qubit_release_array,
1069 __quantum__rt__result_equal, SIM_STATE, capture_quantum_state, map_to_z_basis,
1070 qubit_is_zero, result_bool::__quantum__rt__result_get_one, unmap_from_z_basis,
1071 };
1072 use num_bigint::BigUint;
1073 use qir_stdlib::{
1074 Pauli,
1075 arrays::{
1076 __quantum__rt__array_create_1d, __quantum__rt__array_get_element_ptr_1d,
1077 __quantum__rt__array_update_reference_count,
1078 },
1079 };
1080
1081 #[test]
1082 fn basic_test_static() {
1083 let q0 = 5 as *mut c_void;
1084 let r0 = std::ptr::null_mut();
1085 let r1 = 1 as *mut c_void;
1086 __quantum__qis__mz__body(q0, r0);
1087 assert!(!__quantum__qis__read_result__body(r0));
1088 __quantum__qis__x__body(q0);
1089 __quantum__qis__mz__body(q0, r1);
1090 assert!(__quantum__qis__read_result__body(r1));
1091 __quantum__qis__x__body(q0);
1092 __quantum__qis__mz__body(q0, r0);
1093 assert!(!__quantum__qis__read_result__body(r0));
1094 assert!(!__quantum__qis__read_result__body(3 as *mut c_void));
1095 __quantum__qis__dumpmachine__body(null_mut());
1096 }
1097
1098 #[allow(clippy::cast_ptr_alignment)]
1099 #[test]
1100 fn basic_test_dynamic() {
1101 let q1 = __quantum__rt__qubit_allocate();
1102 let q2 = __quantum__rt__qubit_allocate();
1103 __quantum__qis__h__body(q1);
1104 __quantum__qis__cnot__body(q1, q2);
1105 let r1 = __quantum__qis__m__body(q1);
1106 let r2 = __quantum__qis__m__body(q2);
1107 assert!(__quantum__rt__result_equal(r1, r2));
1108 __quantum__qis__dumpmachine__body(null_mut());
1109 __quantum__rt__qubit_release(q2);
1110 __quantum__rt__qubit_release(q1);
1111 let qs = __quantum__rt__qubit_allocate_array(4);
1112 unsafe {
1113 let q_elem = __quantum__rt__array_get_element_ptr_1d(qs, 3).cast::<*mut c_void>();
1114 __quantum__qis__x__body(*q_elem);
1115 __quantum__qis__dumpmachine__body(null_mut());
1116 let r = __quantum__qis__m__body(*q_elem);
1117 assert!(__quantum__rt__result_equal(
1118 r,
1119 __quantum__rt__result_get_one()
1120 ));
1121 __quantum__rt__qubit_release_array(qs);
1122 }
1123 }
1124
1125 #[test]
1126 fn test_qubit_is_zero() {
1127 let q0 = __quantum__rt__qubit_allocate();
1128 assert!(qubit_is_zero(q0));
1129 __quantum__qis__x__body(q0);
1130 assert!(!qubit_is_zero(q0));
1131 __quantum__qis__h__body(q0);
1132 assert!(!qubit_is_zero(q0));
1133 let r = __quantum__qis__m__body(q0);
1134 assert!(
1135 qubit_is_zero(q0) != __quantum__rt__result_equal(r, __quantum__rt__result_get_one())
1136 );
1137 }
1138
1139 #[allow(clippy::cast_ptr_alignment)]
1140 #[test]
1141 fn test_map_unmap_are_adjoint() {
1142 unsafe fn check_map_unmap(pauli: Pauli) {
1143 unsafe {
1144 let check_qubit = __quantum__rt__qubit_allocate();
1145 let qubits = __quantum__rt__qubit_allocate_array(1);
1146 let q = *__quantum__rt__array_get_element_ptr_1d(qubits, 0).cast::<*mut c_void>();
1147 let paulis = __quantum__rt__array_create_1d(1, 1);
1148 *__quantum__rt__array_get_element_ptr_1d(paulis, 0).cast::<Pauli>() = pauli;
1149
1150 __quantum__qis__h__body(check_qubit);
1151 __quantum__qis__cnot__body(check_qubit, q);
1152
1153 SIM_STATE.with(|sim_state| {
1154 let state = &mut *sim_state.borrow_mut();
1155 let combined_list = map_to_z_basis(state, paulis, qubits);
1156 unmap_from_z_basis(state, combined_list);
1157 });
1158
1159 __quantum__qis__cnot__body(check_qubit, q);
1160 __quantum__qis__h__body(check_qubit);
1161
1162 assert!(qubit_is_zero(q));
1163 assert!(qubit_is_zero(check_qubit));
1164
1165 __quantum__rt__array_update_reference_count(paulis, -1);
1166 __quantum__rt__qubit_release_array(qubits);
1167 __quantum__rt__qubit_release(check_qubit);
1168 }
1169 }
1170
1171 unsafe {
1172 check_map_unmap(Pauli::X);
1173 check_map_unmap(Pauli::Y);
1174 check_map_unmap(Pauli::Z);
1175 }
1176 }
1177
1178 #[allow(clippy::cast_ptr_alignment)]
1179 #[test]
1180 fn test_map_pauli_x() {
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::X;
1186
1187 __quantum__qis__h__body(q);
1188
1189 SIM_STATE.with(|sim_state| {
1190 let state = &mut *sim_state.borrow_mut();
1191 let _ = map_to_z_basis(state, paulis, qubits);
1192 });
1193
1194 qubit_is_zero(q);
1195
1196 __quantum__rt__array_update_reference_count(paulis, -1);
1197 __quantum__rt__qubit_release_array(qubits);
1198 }
1199 }
1200
1201 #[allow(clippy::cast_ptr_alignment)]
1202 #[test]
1203 fn test_map_pauli_y() {
1204 let qubits = __quantum__rt__qubit_allocate_array(1);
1205 unsafe {
1206 let q = *__quantum__rt__array_get_element_ptr_1d(qubits, 0).cast::<*mut c_void>();
1207 let paulis = __quantum__rt__array_create_1d(1, 1);
1208 *__quantum__rt__array_get_element_ptr_1d(paulis, 0).cast::<Pauli>() = Pauli::Y;
1209
1210 __quantum__qis__h__body(q);
1211 __quantum__qis__s__adj(q);
1212 __quantum__qis__h__body(q);
1213
1214 SIM_STATE.with(|sim_state| {
1215 let state = &mut *sim_state.borrow_mut();
1216 let _ = map_to_z_basis(state, paulis, qubits);
1217 });
1218
1219 qubit_is_zero(q);
1220
1221 __quantum__rt__array_update_reference_count(paulis, -1);
1222 __quantum__rt__qubit_release_array(qubits);
1223 }
1224 }
1225
1226 #[allow(clippy::cast_ptr_alignment)]
1227 #[test]
1228 fn test_map_pauli_z() {
1229 let qubits = __quantum__rt__qubit_allocate_array(1);
1230 unsafe {
1231 let q = *__quantum__rt__array_get_element_ptr_1d(qubits, 0).cast::<*mut c_void>();
1232 let paulis = __quantum__rt__array_create_1d(1, 1);
1233 *__quantum__rt__array_get_element_ptr_1d(paulis, 0).cast::<Pauli>() = Pauli::Z;
1234
1235 SIM_STATE.with(|sim_state| {
1236 let state = &mut *sim_state.borrow_mut();
1237 let _ = map_to_z_basis(state, paulis, qubits);
1238 });
1239
1240 qubit_is_zero(q);
1241
1242 __quantum__rt__array_update_reference_count(paulis, -1);
1243 __quantum__rt__qubit_release_array(qubits);
1244 }
1245 }
1246
1247 #[test]
1248 fn test_joint_zz() {
1249 let check_qubit = __quantum__rt__qubit_allocate();
1250 let q0 = __quantum__rt__qubit_allocate();
1251 let q1 = __quantum__rt__qubit_allocate();
1252
1253 __quantum__qis__h__body(check_qubit);
1254 __quantum__qis__cx__body(check_qubit, q0);
1255 __quantum__qis__cx__body(check_qubit, q1);
1256
1257 __quantum__qis__rzz__body(PI / 2.0, q0, q1);
1258 __quantum__qis__rz__body(-PI / 2.0, q0);
1259 __quantum__qis__rz__body(-PI / 2.0, q1);
1260
1261 __quantum__qis__cz__body(q0, q1);
1262
1263 __quantum__qis__cx__body(check_qubit, q1);
1264 __quantum__qis__cx__body(check_qubit, q0);
1265 __quantum__qis__h__body(check_qubit);
1266
1267 assert!(qubit_is_zero(check_qubit));
1268 assert!(qubit_is_zero(q0));
1269 assert!(qubit_is_zero(q1));
1270 }
1271
1272 #[test]
1273 fn test_joint_yy() {
1274 let check_qubit = __quantum__rt__qubit_allocate();
1275 let q0 = __quantum__rt__qubit_allocate();
1276 let q1 = __quantum__rt__qubit_allocate();
1277
1278 __quantum__qis__h__body(check_qubit);
1279 __quantum__qis__cx__body(check_qubit, q0);
1280 __quantum__qis__cx__body(check_qubit, q1);
1281
1282 __quantum__qis__h__body(q0);
1283 __quantum__qis__s__adj(q0);
1284 __quantum__qis__h__body(q0);
1285 __quantum__qis__h__body(q1);
1286 __quantum__qis__s__adj(q1);
1287 __quantum__qis__h__body(q1);
1288
1289 __quantum__qis__ryy__body(PI / 2.0, q0, q1);
1290 __quantum__qis__ry__body(-PI / 2.0, q0);
1291 __quantum__qis__ry__body(-PI / 2.0, q1);
1292
1293 __quantum__qis__h__body(q1);
1294 __quantum__qis__s__body(q1);
1295 __quantum__qis__h__body(q1);
1296 __quantum__qis__h__body(q0);
1297 __quantum__qis__s__body(q0);
1298 __quantum__qis__h__body(q0);
1299
1300 __quantum__qis__cz__body(q0, q1);
1301
1302 __quantum__qis__cx__body(check_qubit, q1);
1303 __quantum__qis__cx__body(check_qubit, q0);
1304 __quantum__qis__h__body(check_qubit);
1305
1306 assert!(qubit_is_zero(check_qubit));
1307 assert!(qubit_is_zero(q0));
1308 assert!(qubit_is_zero(q1));
1309 }
1310
1311 #[test]
1312 fn test_joint_xx() {
1313 let check_qubit = __quantum__rt__qubit_allocate();
1314 let q0 = __quantum__rt__qubit_allocate();
1315 let q1 = __quantum__rt__qubit_allocate();
1316
1317 __quantum__qis__h__body(check_qubit);
1318 __quantum__qis__cx__body(check_qubit, q0);
1319 __quantum__qis__cx__body(check_qubit, q1);
1320
1321 __quantum__qis__h__body(q0);
1322 __quantum__qis__h__body(q1);
1323
1324 __quantum__qis__rxx__body(PI / 2.0, q0, q1);
1325 __quantum__qis__rx__body(-PI / 2.0, q0);
1326 __quantum__qis__rx__body(-PI / 2.0, q1);
1327
1328 __quantum__qis__h__body(q0);
1329 __quantum__qis__h__body(q1);
1330
1331 __quantum__qis__cz__body(q0, q1);
1332
1333 __quantum__qis__cx__body(check_qubit, q1);
1334 __quantum__qis__cx__body(check_qubit, q0);
1335 __quantum__qis__h__body(check_qubit);
1336
1337 assert!(qubit_is_zero(check_qubit));
1338 assert!(qubit_is_zero(q0));
1339 assert!(qubit_is_zero(q1));
1340 }
1341
1342 #[test]
1343 fn test_mresetz() {
1344 let qubit = __quantum__rt__qubit_allocate();
1345 let r0 = std::ptr::null_mut();
1346 let r1 = 1 as *mut c_void;
1347 assert!(qubit_is_zero(qubit));
1348 __quantum__qis__mresetz__body(qubit, r0);
1349 assert!(!__quantum__qis__read_result__body(r0));
1350 assert!(qubit_is_zero(qubit));
1351 __quantum__qis__x__body(qubit);
1352 __quantum__qis__mresetz__body(qubit, r1);
1353 assert!(__quantum__qis__read_result__body(r1));
1354 assert!(qubit_is_zero(qubit));
1355 }
1356
1357 #[test]
1358 fn test_capture_quantum_state() {
1359 let qubit = __quantum__rt__qubit_allocate();
1360 let (state, qubit_count) = capture_quantum_state();
1361 assert_eq!(qubit_count, 1);
1362 assert_eq!(state.len(), 1);
1363 assert_eq!(state[0].0, BigUint::from(0u32));
1364 __quantum__qis__x__body(qubit);
1365 let (state, qubit_count) = capture_quantum_state();
1366 assert_eq!(qubit_count, 1);
1367 assert_eq!(state.len(), 1);
1368 assert_eq!(state[0].0, BigUint::from(1u32));
1369 __quantum__qis__h__body(qubit);
1370 let qubit2 = __quantum__rt__qubit_allocate();
1371 let (state, qubit_count) = capture_quantum_state();
1372 assert_eq!(qubit_count, 2);
1373 assert_eq!(state.len(), 2);
1374 assert_eq!(state[0].1, -state[1].1);
1375 __quantum__qis__h__body(qubit);
1376 __quantum__qis__x__body(qubit);
1377 let (state, qubit_count) = capture_quantum_state();
1378 assert_eq!(qubit_count, 2);
1379 assert_eq!(state.len(), 1);
1380 assert_eq!(state[0].0, BigUint::from(0u32));
1381 __quantum__rt__qubit_release(qubit);
1382 __quantum__rt__qubit_release(qubit2);
1383 let (state, qubit_count) = capture_quantum_state();
1384 assert_eq!(qubit_count, 0);
1385 assert_eq!(state.len(), 1);
1386 assert_eq!(state[0].0, BigUint::from(0u32));
1387 }
1388}