1use std::{
27 ffi::{c_char, CStr, CString},
28 ptr::null,
29};
30
31use crate::{
32 c_api::c_ok,
33 error::KetError,
34 execution::{
35 BatchExecution, DumpData, ExpValueStrategy, GradientStrategy, LiveExecution, NativeGate,
36 NativeGateSet, QuantumExecution, SampleData,
37 },
38 ir::{gate::GateInstruction, hamiltonian::Hamiltonian},
39 matrix::Matrix,
40 process::QPUConfig,
41};
42
43#[repr(C)]
56#[derive(Debug, Clone)]
57pub struct CLiveExecution {
58 pub compute_gate: fn(json: *const c_char) -> i32,
63 pub compute_native_gates: fn(json: *const c_char) -> i32,
69
70 pub measure: fn(qubits: *const usize, len: usize, result: &mut u64) -> i32,
76
77 pub dump: fn(qubits: *const usize, len: usize, result_json: &mut *const c_char) -> i32,
84
85 pub sample:
91 fn(qubits: *const usize, len: usize, shots: usize, result_json: &mut *const c_char) -> i32,
92
93 pub exp_value: fn(hamiltonian_json: *const c_char, result: &mut f64) -> i32,
99}
100
101impl LiveExecution for CLiveExecution {
102 fn compute_gate(&mut self, gate: &GateInstruction) -> Result<(), KetError> {
103 let Ok(json) = serde_json::to_string(gate) else {
104 return Err(KetError::SerdeError);
105 };
106
107 let Ok(json) = CString::new(json) else {
108 return Err(KetError::SerdeError);
109 };
110
111 let err = KetError::from_error_code((self.compute_gate)(json.as_ptr()));
112
113 match err {
114 KetError::Success => Ok(()),
115 err => Err(err),
116 }
117 }
118
119 fn compute_native_gates(&mut self, gates: &[NativeGate]) -> Result<(), KetError> {
120 let Ok(gates) = serde_json::to_string(gates) else {
121 return Err(KetError::SerdeError);
122 };
123
124 let Ok(gates) = CString::new(gates) else {
125 return Err(KetError::SerdeError);
126 };
127
128 let err = KetError::from_error_code((self.compute_native_gates)(gates.as_ptr()));
129 match err {
130 KetError::Success => Ok(()),
131 err => Err(err),
132 }
133 }
134
135 fn measure(&mut self, qubits: &[usize]) -> Result<u64, KetError> {
136 let mut result = 42;
137
138 let err =
139 KetError::from_error_code((self.measure)(qubits.as_ptr(), qubits.len(), &mut result));
140
141 match err {
142 KetError::Success => Ok(result),
143 err => Err(err),
144 }
145 }
146
147 fn sample(&mut self, qubits: &[usize], shots: usize) -> Result<SampleData, KetError> {
148 let mut result_json = null();
149
150 let err = KetError::from_error_code((self.sample)(
151 qubits.as_ptr(),
152 qubits.len(),
153 shots,
154 &mut result_json,
155 ));
156
157 match err {
158 KetError::Success => {
159 let Ok(result_json) = { unsafe { CStr::from_ptr(result_json) } }.to_str() else {
160 return Err(KetError::SerdeError);
161 };
162
163 match serde_json::from_str::<SampleData>(result_json) {
164 Ok(sample_date) => Ok(sample_date),
165 Err(_) => Err(KetError::SerdeError),
166 }
167 }
168 err => Err(err),
169 }
170 }
171
172 fn exp_value(&mut self, hamiltonian: Hamiltonian) -> Result<f64, KetError> {
173 let mut result = f64::NAN;
174
175 let Ok(json) = serde_json::to_string(&hamiltonian) else {
176 return Err(KetError::SerdeError);
177 };
178
179 let Ok(json) = CString::new(json) else {
180 return Err(KetError::SerdeError);
181 };
182
183 let err = KetError::from_error_code((self.exp_value)(json.as_ptr(), &mut result));
184
185 match err {
186 KetError::Success => Ok(result),
187 err => Err(err),
188 }
189 }
190
191 fn dump(&mut self, qubits: &[usize]) -> Result<DumpData, KetError> {
192 let mut result_json = null();
193
194 let err =
195 KetError::from_error_code((self.dump)(qubits.as_ptr(), qubits.len(), &mut result_json));
196
197 match err {
198 KetError::Success => {
199 let Ok(result_json) = { unsafe { CStr::from_ptr(result_json) } }.to_str() else {
200 return Err(KetError::SerdeError);
201 };
202
203 match serde_json::from_str::<DumpData>(result_json) {
204 Ok(dump_data) => Ok(dump_data),
205 Err(_) => Err(KetError::SerdeError),
206 }
207 }
208 err => Err(err),
209 }
210 }
211}
212
213#[repr(C)]
226#[derive(Debug, Clone)]
227pub struct CBatchExecution {
228 pub sample: fn(
229 gates_json: *const c_char,
230 qubits_to_sample: *const usize,
231 qubits_to_sample_len: usize,
232 shots: usize,
233 sample_json: &mut *const c_char,
234 ) -> i32,
235
236 pub exp_value: fn(
237 gates_json: *const c_char,
238 hamiltonian_list_json: *const c_char,
239 result: *mut f64,
240 ) -> i32,
241
242 pub sample_native: fn(
243 gates_json: *const c_char,
244 qubits_to_sample: *const usize,
245 qubits_to_sample_len: usize,
246 shots: usize,
247 sample_json: &mut *const c_char,
248 ) -> i32,
249
250 pub exp_value_native: fn(
251 gates_json: *const c_char,
252 hamiltonian_list_json: *const c_char,
253 result: *mut f64,
254 ) -> i32,
255
256 pub gradient: fn(
257 gates_json: *const c_char,
258 hamiltonian_list_json: *const c_char,
259 exp_result: &mut f64,
260 grad_json: &mut *const c_char,
261 ) -> i32,
262}
263
264impl BatchExecution for CBatchExecution {
265 fn sample(
266 &self,
267 gates: &[GateInstruction],
268 qubits_to_sample: &[usize],
269 shots: usize,
270 ) -> Result<SampleData, KetError> {
271 let mut sample_json = std::ptr::null();
272
273 let Ok(gates_json) = serde_json::to_string(gates) else {
274 return Err(KetError::SerdeError);
275 };
276 let Ok(gates_json) = CString::new(gates_json) else {
277 return Err(KetError::SerdeError);
278 };
279
280 let err = KetError::from_error_code((self.sample)(
281 gates_json.as_ptr(),
282 qubits_to_sample.as_ptr(),
283 qubits_to_sample.len(),
284 shots,
285 &mut sample_json,
286 ));
287
288 match err {
289 KetError::Success => {
290 let Ok(result_json) = { unsafe { CStr::from_ptr(sample_json) } }.to_str() else {
291 return Err(KetError::SerdeError);
292 };
293
294 match serde_json::from_str::<SampleData>(result_json) {
295 Ok(sample_data) => Ok(sample_data),
296 Err(_) => Err(KetError::SerdeError),
297 }
298 }
299 err => Err(err),
300 }
301 }
302
303 fn exp_value(
304 &self,
305 gates: &[GateInstruction],
306 hamiltonian_list: &[Hamiltonian],
307 ) -> Result<Vec<f64>, KetError> {
308 let mut result = vec![f64::NAN; hamiltonian_list.len()];
309
310 let Ok(gates_json) = serde_json::to_string(gates) else {
311 return Err(KetError::SerdeError);
312 };
313 let Ok(gates_json) = CString::new(gates_json) else {
314 return Err(KetError::SerdeError);
315 };
316
317 let Ok(ham_json) = serde_json::to_string(&hamiltonian_list) else {
318 return Err(KetError::SerdeError);
319 };
320 let Ok(ham_json) = CString::new(ham_json) else {
321 return Err(KetError::SerdeError);
322 };
323
324 let err = KetError::from_error_code((self.exp_value)(
325 gates_json.as_ptr(),
326 ham_json.as_ptr(),
327 result.as_mut_ptr(),
328 ));
329
330 match err {
331 KetError::Success => Ok(result),
332 err => Err(err),
333 }
334 }
335
336 fn sample_native(
337 &self,
338 gates: &[NativeGate],
339 qubits_to_sample: &[usize],
340 shots: usize,
341 ) -> Result<SampleData, KetError> {
342 let mut sample_json = std::ptr::null();
343
344 let Ok(gates_json) = serde_json::to_string(gates) else {
345 return Err(KetError::SerdeError);
346 };
347 let Ok(gates_json) = CString::new(gates_json) else {
348 return Err(KetError::SerdeError);
349 };
350
351 let err = KetError::from_error_code((self.sample_native)(
352 gates_json.as_ptr(),
353 qubits_to_sample.as_ptr(),
354 qubits_to_sample.len(),
355 shots,
356 &mut sample_json,
357 ));
358
359 match err {
360 KetError::Success => {
361 let Ok(result_json) = { unsafe { CStr::from_ptr(sample_json) } }.to_str() else {
362 return Err(KetError::SerdeError);
363 };
364
365 match serde_json::from_str::<SampleData>(result_json) {
366 Ok(sample_data) => Ok(sample_data),
367 Err(_) => Err(KetError::SerdeError),
368 }
369 }
370 err => Err(err),
371 }
372 }
373
374 fn exp_value_native(
375 &self,
376 gates: &[NativeGate],
377 hamiltonian_list: &[Hamiltonian],
378 ) -> Result<Vec<f64>, KetError> {
379 let mut result = vec![f64::NAN; hamiltonian_list.len()];
380
381 let Ok(gates_json) = serde_json::to_string(gates) else {
382 return Err(KetError::SerdeError);
383 };
384 let Ok(gates_json) = CString::new(gates_json) else {
385 return Err(KetError::SerdeError);
386 };
387
388 let Ok(ham_json) = serde_json::to_string(&hamiltonian_list) else {
389 return Err(KetError::SerdeError);
390 };
391 let Ok(ham_json) = CString::new(ham_json) else {
392 return Err(KetError::SerdeError);
393 };
394
395 let err = KetError::from_error_code((self.exp_value_native)(
396 gates_json.as_ptr(),
397 ham_json.as_ptr(),
398 result.as_mut_ptr(),
399 ));
400
401 match err {
402 KetError::Success => Ok(result),
403 err => Err(err),
404 }
405 }
406
407 fn gradient(
408 &self,
409 gates: &[GateInstruction],
410 hamiltonian: &Hamiltonian,
411 ) -> Result<(f64, Vec<f64>), KetError> {
412 let mut exp_result = 0.0;
413
414 let Ok(gates_json) = serde_json::to_string(gates) else {
415 return Err(KetError::SerdeError);
416 };
417 let Ok(gates_json) = CString::new(gates_json) else {
418 return Err(KetError::SerdeError);
419 };
420
421 let Ok(ham_json) = serde_json::to_string(hamiltonian) else {
422 return Err(KetError::SerdeError);
423 };
424 let Ok(ham_json) = CString::new(ham_json) else {
425 return Err(KetError::SerdeError);
426 };
427
428 let mut grad_json = std::ptr::null();
429
430 let err = KetError::from_error_code((self.gradient)(
431 gates_json.as_ptr(),
432 ham_json.as_ptr(),
433 &mut exp_result,
434 &mut grad_json,
435 ));
436
437 match err {
438 KetError::Success => {
439 let Ok(grad_json) = { unsafe { CStr::from_ptr(grad_json) } }.to_str() else {
440 return Err(KetError::SerdeError);
441 };
442
443 match serde_json::from_str::<Vec<f64>>(grad_json) {
444 Ok(grad_json) => Ok((exp_result, grad_json)),
445 Err(_) => Err(KetError::SerdeError),
446 }
447 }
448 err => Err(err),
449 }
450 }
451}
452
453#[repr(C)]
467#[derive(Debug, Clone)]
468pub struct CNativeGateSet {
469 pub translate:
478 fn(gate_json: *const c_char, target: usize, native_gate_json: &mut *const c_char) -> i32,
479
480 pub cnot: fn(control: usize, target: usize, native_gate_json: &mut *const c_char) -> i32,
487}
488
489impl NativeGateSet for CNativeGateSet {
490 fn translate(&self, matrix: &Matrix, target: usize) -> Result<Vec<NativeGate>, KetError> {
491 let matrix_json = [
492 [
493 matrix[0][0].re,
494 matrix[0][0].im,
495 matrix[0][1].re,
496 matrix[0][1].im,
497 ],
498 [
499 matrix[1][0].re,
500 matrix[1][0].im,
501 matrix[1][1].re,
502 matrix[1][1].im,
503 ],
504 ];
505 let Ok(gate) = serde_json::to_string(&matrix_json) else {
506 return Err(KetError::SerdeError);
507 };
508 let Ok(gate) = CString::new(gate) else {
509 return Err(KetError::SerdeError);
510 };
511
512 let mut result_json = null();
513
514 let err =
515 KetError::from_error_code((self.translate)(gate.as_ptr(), target, &mut result_json));
516
517 match err {
518 KetError::Success => {
519 let Ok(result_json) = { unsafe { CStr::from_ptr(result_json) } }.to_str() else {
520 return Err(KetError::SerdeError);
521 };
522 match serde_json::from_str(result_json) {
523 Ok(result) => Ok(result),
524 Err(_) => Err(KetError::SerdeError),
525 }
526 }
527 err => Err(err),
528 }
529 }
530
531 fn cnot(&self, control: usize, target: usize) -> Result<Vec<NativeGate>, KetError> {
532 let mut result_json = null();
533
534 let err = KetError::from_error_code((self.cnot)(control, target, &mut result_json));
535
536 match err {
537 KetError::Success => {
538 let Ok(result_json) = { unsafe { CStr::from_ptr(result_json) } }.to_str() else {
539 return Err(KetError::SerdeError);
540 };
541 match serde_json::from_str(result_json) {
542 Ok(result) => Ok(result),
543 Err(_) => Err(KetError::SerdeError),
544 }
545 }
546 err => Err(err),
547 }
548 }
549}
550
551#[no_mangle]
570pub extern "C" fn ket_quantum_execution_live(
571 num_qubits: usize,
572 live: &CLiveExecution,
573 decompose: bool,
574 native_gate_set: *const CNativeGateSet,
575 qpu_config: &mut *mut QPUConfig,
576) -> i32 {
577 let native_gate_set = if native_gate_set.is_null() {
578 None
579 } else {
580 Some(Box::new(unsafe { &*native_gate_set }.clone()) as Box<dyn NativeGateSet>)
581 };
582
583 let execution = QuantumExecution::Live {
584 qpu: Box::new(live.clone()),
585 decompose,
586 native_gate_set,
587 };
588
589 *qpu_config = Box::into_raw(Box::new(QPUConfig {
590 num_qubits,
591 quantum_execution: Some(execution),
592 }));
593
594 c_ok()
595}
596
597#[no_mangle]
620pub extern "C" fn ket_quantum_execution_batch(
621 num_qubits: usize,
622 batch: &CBatchExecution,
623 native_gate_set: *const CNativeGateSet,
624 decompose: bool,
625 gradient: bool,
626 coupling_graph_json: *const c_char,
627 exp_value_strategy_json: *const c_char,
628 qpu_config: &mut *mut QPUConfig,
629) -> i32 {
630 let native_gate_set: Option<Box<dyn NativeGateSet>> = unsafe {
631 if native_gate_set.is_null() {
632 None
633 } else {
634 Some(Box::new((*native_gate_set).clone()))
635 }
636 };
637
638 let coupling_graph = from_json!(coupling_graph_json, Option<Vec<(usize, usize)>>);
639 let exp_value = from_json!(exp_value_strategy_json, ExpValueStrategy);
640
641 let execution = QuantumExecution::Batch {
642 qpu: Box::new(batch.clone()),
643 native_gate_set,
644 gradient: if gradient {
645 GradientStrategy::ParameterShiftRule
646 } else {
647 GradientStrategy::None
648 },
649 exp_value,
650 coupling_graph,
651 decompose,
652 };
653
654 *qpu_config = Box::into_raw(Box::new(QPUConfig {
655 num_qubits,
656 quantum_execution: Some(execution),
657 }));
658
659 c_ok()
660}