1use crate::{SIM_STATE, ensure_sufficient_qubits};
11use qir_stdlib::arrays::{
12 __quantum__rt__array_get_element_ptr_1d, __quantum__rt__array_get_size_1d, QirArray,
13};
14use quantum_sparse_sim::exp::Pauli as SparsePauli;
15use std::os::raw::{c_double, c_void};
16
17fn map_pauli(pauli: u8) -> SparsePauli {
18 match pauli & 3 {
19 0 => SparsePauli::I,
20 1 => SparsePauli::X,
21 2 => SparsePauli::Z,
22 3 => SparsePauli::Y,
23 _ => unreachable!(),
24 }
25}
26
27#[allow(clippy::cast_ptr_alignment)]
32#[unsafe(no_mangle)]
33pub unsafe extern "C" fn __quantum__qis__exp__body(
34 paulis: *const QirArray,
35 theta: c_double,
36 qubits: *const QirArray,
37) {
38 SIM_STATE.with(|sim_state| {
39 let state = &mut *sim_state.borrow_mut();
40
41 let paulis_size = unsafe { __quantum__rt__array_get_size_1d(paulis) };
42 let paulis: Vec<SparsePauli> = (0..paulis_size)
43 .map(|index| {
44 map_pauli(unsafe {
45 *__quantum__rt__array_get_element_ptr_1d(paulis, index).cast::<u8>()
46 })
47 })
48 .collect();
49
50 let qubits_size = unsafe { __quantum__rt__array_get_size_1d(qubits) };
51 let targets: Vec<usize> = (0..qubits_size)
52 .map(|index| {
53 let qubit_id = unsafe {
54 *__quantum__rt__array_get_element_ptr_1d(qubits, index).cast::<*mut c_void>()
55 as usize
56 };
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#[unsafe(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 unsafe {
77 __quantum__qis__exp__body(paulis, -theta, qubits);
78 }
79}
80
81#[derive(Copy, Clone)]
82#[repr(C)]
83struct ExpArgs {
84 paulis: *const QirArray,
85 theta: c_double,
86 qubits: *const QirArray,
87}
88
89#[allow(clippy::cast_ptr_alignment)]
90unsafe fn apply_controlled_exp(
91 paulis: *const QirArray,
92 theta: c_double,
93 ctls: *const QirArray,
94 qubits: *const QirArray,
95) {
96 SIM_STATE.with(|sim_state| {
97 let state = &mut *sim_state.borrow_mut();
98
99 let ctls_size = unsafe { __quantum__rt__array_get_size_1d(ctls) };
100 let ctls: Vec<usize> = (0..ctls_size)
101 .map(|index| {
102 let qubit_id = unsafe {
103 *__quantum__rt__array_get_element_ptr_1d(ctls, index).cast::<*mut c_void>()
104 } as usize;
105 ensure_sufficient_qubits(&mut state.sim, qubit_id, &mut state.max_qubit_id);
106 qubit_id
107 })
108 .collect();
109
110 let paulis_size = unsafe { __quantum__rt__array_get_size_1d(paulis) };
111 let paulis: Vec<SparsePauli> = (0..paulis_size)
112 .map(|index| {
113 map_pauli(unsafe {
114 *__quantum__rt__array_get_element_ptr_1d(paulis, index).cast::<u8>()
115 })
116 })
117 .collect();
118
119 let qubits_size = unsafe { __quantum__rt__array_get_size_1d(qubits) };
120 let targets: Vec<usize> = (0..qubits_size)
121 .map(|index| {
122 let qubit_id = unsafe {
123 *__quantum__rt__array_get_element_ptr_1d(qubits, index).cast::<*mut c_void>()
124 } 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, theta, &targets);
131 });
132}
133
134#[allow(clippy::cast_ptr_alignment)]
139#[unsafe(no_mangle)]
140pub unsafe extern "C" fn __quantum__qis__exp__ctl(
141 ctls: *const QirArray,
142 arg_tuple: *mut *const Vec<u8>,
143) {
144 let args = unsafe { *arg_tuple.cast::<ExpArgs>() };
145 unsafe { apply_controlled_exp(args.paulis, args.theta, ctls, args.qubits) };
146}
147
148#[allow(clippy::cast_ptr_alignment)]
153#[unsafe(no_mangle)]
154pub unsafe extern "C" fn __quantum__qis__exp__ctladj(
155 ctls: *const QirArray,
156 arg_tuple: *mut *const Vec<u8>,
157) {
158 let args = unsafe { *arg_tuple.cast::<ExpArgs>() };
159 unsafe { apply_controlled_exp(args.paulis, -args.theta, ctls, args.qubits) };
160}
161
162#[allow(non_snake_case)]
167pub unsafe extern "C" fn __quantum__qis__exp__ctl_flat(
168 paulis: *const QirArray,
169 theta: c_double,
170 ctls: *const QirArray,
171 qubits: *const QirArray,
172) {
173 unsafe { apply_controlled_exp(paulis, theta, ctls, qubits) };
174}
175
176#[allow(non_snake_case)]
181pub unsafe extern "C" fn __quantum__qis__exp__ctladj_flat(
182 paulis: *const QirArray,
183 theta: c_double,
184 ctls: *const QirArray,
185 qubits: *const QirArray,
186) {
187 unsafe { apply_controlled_exp(paulis, -theta, ctls, qubits) };
188}