1use crate::{ensure_sufficient_qubits, SIM_STATE};
11use qir_stdlib::{
12 arrays::{QirArray, __quantum__rt__array_get_element_ptr_1d, __quantum__rt__array_get_size_1d},
13 tuples::{__quantum__rt__tuple_create, __quantum__rt__tuple_update_reference_count},
14 Pauli,
15};
16use quantum_sparse_sim::exp::Pauli as SparsePauli;
17use std::{
18 mem::size_of,
19 os::raw::{c_double, c_void},
20};
21
22fn map_pauli(pauli: Pauli) -> SparsePauli {
23 match pauli {
24 Pauli::I => SparsePauli::I,
25 Pauli::X => SparsePauli::X,
26 Pauli::Z => SparsePauli::Z,
27 Pauli::Y => SparsePauli::Y,
28 }
29}
30
31#[allow(clippy::cast_ptr_alignment)]
36#[no_mangle]
37pub unsafe extern "C" fn __quantum__qis__exp__body(
38 paulis: *const QirArray,
39 theta: c_double,
40 qubits: *const QirArray,
41) {
42 SIM_STATE.with(|sim_state| {
43 let state = &mut *sim_state.borrow_mut();
44
45 let paulis_size = __quantum__rt__array_get_size_1d(paulis);
46 let paulis: Vec<SparsePauli> = (0..paulis_size)
47 .map(|index| {
48 map_pauli(*__quantum__rt__array_get_element_ptr_1d(paulis, index).cast::<Pauli>())
49 })
50 .collect();
51
52 let qubits_size = __quantum__rt__array_get_size_1d(qubits);
53 let targets: Vec<usize> = (0..qubits_size)
54 .map(|index| {
55 let qubit_id = *__quantum__rt__array_get_element_ptr_1d(qubits, index)
56 .cast::<*mut c_void>() as usize;
57 ensure_sufficient_qubits(&mut state.sim, qubit_id, &mut state.max_qubit_id);
58 qubit_id
59 })
60 .collect();
61
62 state.sim.exp(&paulis, theta, &targets);
63 });
64}
65
66#[no_mangle]
71pub unsafe extern "C" fn __quantum__qis__exp__adj(
72 paulis: *const QirArray,
73 theta: c_double,
74 qubits: *const QirArray,
75) {
76 __quantum__qis__exp__body(paulis, -theta, qubits);
77}
78
79#[derive(Copy, Clone)]
80#[repr(C)]
81struct ExpArgs {
82 paulis: *const QirArray,
83 theta: c_double,
84 qubits: *const QirArray,
85}
86
87#[allow(clippy::cast_ptr_alignment)]
92#[no_mangle]
93pub unsafe extern "C" fn __quantum__qis__exp__ctl(
94 ctls: *const QirArray,
95 arg_tuple: *mut *const Vec<u8>,
96) {
97 SIM_STATE.with(|sim_state| {
98 let state = &mut *sim_state.borrow_mut();
99 let args = *arg_tuple.cast::<ExpArgs>();
100
101 let ctls_size = __quantum__rt__array_get_size_1d(ctls);
102 let ctls: Vec<usize> = (0..ctls_size)
103 .map(|index| {
104 let qubit_id = *__quantum__rt__array_get_element_ptr_1d(ctls, index)
105 .cast::<*mut c_void>() as usize;
106 ensure_sufficient_qubits(&mut state.sim, qubit_id, &mut state.max_qubit_id);
107 qubit_id
108 })
109 .collect();
110
111 let paulis_size = __quantum__rt__array_get_size_1d(args.paulis);
112 let paulis: Vec<SparsePauli> = (0..paulis_size)
113 .map(|index| {
114 map_pauli(
115 *__quantum__rt__array_get_element_ptr_1d(args.paulis, index).cast::<Pauli>(),
116 )
117 })
118 .collect();
119
120 let qubits_size = __quantum__rt__array_get_size_1d(args.qubits);
121 let targets: Vec<usize> = (0..qubits_size)
122 .map(|index| {
123 let qubit_id = *__quantum__rt__array_get_element_ptr_1d(args.qubits, index)
124 .cast::<*mut c_void>() as usize;
125 ensure_sufficient_qubits(&mut state.sim, qubit_id, &mut state.max_qubit_id);
126 qubit_id
127 })
128 .collect();
129
130 state.sim.mcexp(&ctls, &paulis, args.theta, &targets);
131 });
132}
133
134#[allow(clippy::cast_ptr_alignment)]
139#[no_mangle]
140pub unsafe extern "C" fn __quantum__qis__exp__ctladj(
141 ctls: *const QirArray,
142 arg_tuple: *mut *const Vec<u8>,
143) {
144 let args = *arg_tuple.cast::<ExpArgs>();
145 let new_args = ExpArgs {
146 paulis: args.paulis,
147 theta: -args.theta,
148 qubits: args.qubits,
149 };
150 let new_arg_tuple = __quantum__rt__tuple_create(size_of::<ExpArgs>() as u64);
151 *new_arg_tuple.cast::<ExpArgs>() = new_args;
152 __quantum__qis__exp__ctl(ctls, new_arg_tuple);
153 __quantum__rt__tuple_update_reference_count(new_arg_tuple, -1);
154}