1use crate::{SIM_STATE, ensure_sufficient_qubits};
11use qir_stdlib::{
12 Pauli,
13 arrays::{__quantum__rt__array_get_element_ptr_1d, __quantum__rt__array_get_size_1d, QirArray},
14 tuples::{__quantum__rt__tuple_create, __quantum__rt__tuple_update_reference_count},
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#[unsafe(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 = unsafe { __quantum__rt__array_get_size_1d(paulis) };
46 let paulis: Vec<SparsePauli> = (0..paulis_size)
47 .map(|index| {
48 map_pauli(unsafe {
49 *__quantum__rt__array_get_element_ptr_1d(paulis, index).cast::<Pauli>()
50 })
51 })
52 .collect();
53
54 let qubits_size = unsafe { __quantum__rt__array_get_size_1d(qubits) };
55 let targets: Vec<usize> = (0..qubits_size)
56 .map(|index| {
57 let qubit_id = unsafe {
58 *__quantum__rt__array_get_element_ptr_1d(qubits, index).cast::<*mut c_void>()
59 as usize
60 };
61 ensure_sufficient_qubits(&mut state.sim, qubit_id, &mut state.max_qubit_id);
62 qubit_id
63 })
64 .collect();
65
66 state.sim.exp(&paulis, theta, &targets);
67 });
68}
69
70#[unsafe(no_mangle)]
75pub unsafe extern "C" fn __quantum__qis__exp__adj(
76 paulis: *const QirArray,
77 theta: c_double,
78 qubits: *const QirArray,
79) {
80 unsafe {
81 __quantum__qis__exp__body(paulis, -theta, qubits);
82 }
83}
84
85#[derive(Copy, Clone)]
86#[repr(C)]
87struct ExpArgs {
88 paulis: *const QirArray,
89 theta: c_double,
90 qubits: *const QirArray,
91}
92
93#[allow(clippy::cast_ptr_alignment)]
98#[unsafe(no_mangle)]
99pub unsafe extern "C" fn __quantum__qis__exp__ctl(
100 ctls: *const QirArray,
101 arg_tuple: *mut *const Vec<u8>,
102) {
103 SIM_STATE.with(|sim_state| {
104 let state = &mut *sim_state.borrow_mut();
105 let args = unsafe { *arg_tuple.cast::<ExpArgs>() };
106
107 let ctls_size = unsafe { __quantum__rt__array_get_size_1d(ctls) };
108 let ctls: Vec<usize> = (0..ctls_size)
109 .map(|index| {
110 let qubit_id = unsafe {
111 *__quantum__rt__array_get_element_ptr_1d(ctls, index).cast::<*mut c_void>()
112 } as usize;
113 ensure_sufficient_qubits(&mut state.sim, qubit_id, &mut state.max_qubit_id);
114 qubit_id
115 })
116 .collect();
117
118 let paulis_size = unsafe { __quantum__rt__array_get_size_1d(args.paulis) };
119 let paulis: Vec<SparsePauli> = (0..paulis_size)
120 .map(|index| {
121 map_pauli(unsafe {
122 *__quantum__rt__array_get_element_ptr_1d(args.paulis, index).cast::<Pauli>()
123 })
124 })
125 .collect();
126
127 let qubits_size = unsafe { __quantum__rt__array_get_size_1d(args.qubits) };
128 let targets: Vec<usize> = (0..qubits_size)
129 .map(|index| {
130 let qubit_id = unsafe {
131 *__quantum__rt__array_get_element_ptr_1d(args.qubits, index)
132 .cast::<*mut c_void>()
133 } as usize;
134 ensure_sufficient_qubits(&mut state.sim, qubit_id, &mut state.max_qubit_id);
135 qubit_id
136 })
137 .collect();
138
139 state.sim.mcexp(&ctls, &paulis, args.theta, &targets);
140 });
141}
142
143#[allow(clippy::cast_ptr_alignment)]
148#[unsafe(no_mangle)]
149pub unsafe extern "C" fn __quantum__qis__exp__ctladj(
150 ctls: *const QirArray,
151 arg_tuple: *mut *const Vec<u8>,
152) {
153 let args = unsafe { *arg_tuple.cast::<ExpArgs>() };
154 let new_args = ExpArgs {
155 paulis: args.paulis,
156 theta: -args.theta,
157 qubits: args.qubits,
158 };
159 let new_arg_tuple = __quantum__rt__tuple_create(size_of::<ExpArgs>() as u64);
160 unsafe {
161 *new_arg_tuple.cast::<ExpArgs>() = new_args;
162 __quantum__qis__exp__ctl(ctls, new_arg_tuple);
163 __quantum__rt__tuple_update_reference_count(new_arg_tuple, -1);
164 }
165}