ket/c_api/
process.rs

1// SPDX-FileCopyrightText: 2020 Evandro Chagas Ribeiro da Rosa <evandro@quantuloop.com>
2// SPDX-FileCopyrightText: 2020 Rafael de Santiago <r.santiago@ufsc.br>
3//
4// SPDX-License-Identifier: Apache-2.0
5
6//! C API for the `Process` struct.
7
8use super::error::wrapper;
9use crate::{
10    execution::{LogicalQubit, Qubit},
11    prelude::*,
12};
13
14/// Creates a new `Process` instance with the given process ID.
15///
16/// # Arguments
17///
18/// * `config` -  \[in\] A mutable pointer to a `Configuration` instance.
19/// * `process` -  \[out\] A mutable pointer to a `Process` pointer.
20///
21/// # Returns
22///
23/// An integer representing the error code. `0` indicates success.
24///
25/// # Safety
26///
27/// This function is marked as unsafe because it deals with raw pointers.
28#[no_mangle]
29pub unsafe extern "C" fn ket_process_new(
30    config: *mut Configuration,
31    process: &mut *mut Process,
32) -> i32 {
33    let config = unsafe { Box::from_raw(config) };
34    *process = Box::into_raw(Box::new(Process::new(*config)));
35    KetError::Success.error_code()
36}
37
38/// Deletes the `Process` instance.
39///
40/// # Arguments
41///
42/// * `process` -  \[in\] A pointer to the `Process` instance to be deleted.
43///
44/// # Returns
45///
46/// An integer representing the error code. `0` indicates success.
47///
48/// # Safety
49///
50/// This function is marked as unsafe because it deals with raw pointers.
51#[no_mangle]
52pub unsafe extern "C" fn ket_process_delete(process: *mut Process) -> i32 {
53    unsafe {
54        let _ = Box::from_raw(process);
55    }
56    KetError::Success.error_code()
57}
58
59/// Allocates a qubit for the `Process` instance.
60///
61/// # Arguments
62///
63/// * `process` -  \[in\] A mutable reference to the `Process` instance.
64/// * `qubit` -  \[out\] A mutable pointer to a `usize`.
65///
66/// # Returns
67///
68/// An integer representing the error code. `0` indicates success.
69#[no_mangle]
70pub extern "C" fn ket_process_allocate_qubit(process: &mut Process, qubit: &mut usize) -> i32 {
71    match process.alloc() {
72        Ok(result) => {
73            *qubit = result.index();
74            KetError::Success.error_code()
75        }
76        Err(error) => error.error_code(),
77    }
78}
79
80/// Applies a quantum gate to the target `Qubit` in the `Process` instance.
81///
82/// # Arguments
83///
84/// * `process` -  \[in\] A mutable reference to the `Process` instance.
85/// * `gate` -  \[in\] An integer representing the gate type. See the function body for the mapping of gate values to gate types.
86/// * `pi_fraction_top` -  \[in\] The numerator of the fraction part of the angle, used by certain gate types.
87/// * `pi_fraction_bottom` -  \[in\] The denominator of the fraction part of the angle, used by certain gate types.
88/// * `scalar` -  \[in\] A floating-point parameter value used by certain gate types.
89/// * `target` -  \[in\] A reference to the target `Qubit` instance.
90///
91/// # Returns
92///
93/// An integer representing the error code. `0` indicates success.
94#[no_mangle]
95pub extern "C" fn ket_process_apply_gate(
96    process: &mut Process,
97    gate: i32,
98    angle: f64,
99    target: usize,
100) -> i32 {
101    let gate = match gate {
102        1 => QuantumGate::PauliX,
103        2 => QuantumGate::PauliY,
104        3 => QuantumGate::PauliZ,
105        10 => QuantumGate::RotationX(angle),
106        20 => QuantumGate::RotationY(angle),
107        30 => QuantumGate::RotationZ(angle),
108        31 => QuantumGate::Phase(angle),
109        0 => QuantumGate::Hadamard,
110        _ => panic!("Undefined Pauli index. Use 0 for H, 1 for X, 2 for Y, and 3 for Z"),
111    };
112
113    wrapper(process.gate(gate, LogicalQubit::main(target)))
114}
115
116/// Applies a global phase.
117///
118/// # Arguments
119///
120/// * `process` -  \[in\] A mutable reference to the `Process` instance.
121/// * `pi_fraction_top` -  \[in\] The numerator of the fraction part of the angle.
122/// * `pi_fraction_bottom` -  \[in\] The denominator of the fraction part of the angle.
123/// * `scalar` -  \[in\] A floating-point parameter value.
124///
125/// # Returns
126///
127/// An integer representing the error code. `0` indicates success.
128#[no_mangle]
129pub extern "C" fn ket_process_apply_global_phase(process: &mut Process, angle: f64) -> i32 {
130    wrapper(process.global_phase(angle))
131}
132
133/// Measures the specified qubits in the `Process` instance.
134///
135/// # Arguments
136///
137/// * `process` -  \[in\] A mutable reference to the `Process` instance.
138/// * `qubits` -  \[in\] A mutable pointer to an array of mutable references to `Qubit` instances.
139/// * `qubits_size` -  \[in\] The size of the `qubits` array.
140/// * `result` -  \[out\] A mutable pointer to a `usize` where the measurement result will be stored.
141///
142/// # Returns
143///
144/// An integer representing the error code. `0` indicates success.
145///
146/// # Safety
147///
148/// This function is marked as unsafe due to the use of raw pointers.
149#[no_mangle]
150pub unsafe extern "C" fn ket_process_measure(
151    process: &mut Process,
152    qubits: *const usize,
153    qubits_size: usize,
154    result: &mut usize,
155) -> i32 {
156    let qubits = unsafe { std::slice::from_raw_parts(qubits, qubits_size) };
157    let qubits = qubits
158        .iter()
159        .map(|index| LogicalQubit::main(*index))
160        .collect::<Vec<_>>();
161
162    match process.measure(&qubits) {
163        Ok(result_id) => {
164            *result = result_id;
165            KetError::Success.error_code()
166        }
167        Err(error) => error.error_code(),
168    }
169}
170
171/// Creates a new `PauliHamiltonian` instance.
172///
173/// # Arguments
174///
175/// * `hamiltonian` -  \[out\] A mutable pointer to a `PauliHamiltonian` pointer.
176///
177/// # Returns
178///
179/// An integer representing the error code. `0` indicates success.
180#[no_mangle]
181pub extern "C" fn ket_hamiltonian_new(hamiltonian: &mut *mut Hamiltonian<LogicalQubit>) -> i32 {
182    *hamiltonian = Box::into_raw(Box::default());
183
184    KetError::Success.error_code()
185}
186
187/// Adds a term to the `PauliHamiltonian`.
188///
189/// # Arguments
190///
191/// * `hamiltonian` -  \[in\] A mutable reference to the `PauliHamiltonian` instance.
192/// * `pauli` -  \[in\] A pointer to an array of integers representing the Pauli operators (1 for X, 2 for Y, 3 for Z).
193/// * `pauli_size` -  \[in\] The size of the `pauli` array.
194/// * `qubits` -  \[in\] A pointer to an array of integers representing the qubit indices for each Pauli operator.
195/// * `qubits_size` -  \[in\] The size of the `qubits` array.
196/// * `coefficients` -  \[in\] The coefficient for the term.
197///
198/// # Returns
199///
200/// An integer representing the error code. `0` indicates success.
201///
202/// # Safety
203///
204/// This function is marked as unsafe due to the use of raw pointers.
205#[no_mangle]
206pub unsafe extern "C" fn ket_hamiltonian_add(
207    hamiltonian: &mut Hamiltonian<LogicalQubit>,
208    pauli: *const i32,
209    pauli_size: usize,
210    qubits: *const usize,
211    qubits_size: usize,
212    coefficients: f64,
213) -> i32 {
214    assert_eq!(pauli_size, qubits_size);
215
216    let pauli = unsafe { std::slice::from_raw_parts(pauli, pauli_size) };
217    let qubits = unsafe { std::slice::from_raw_parts(qubits, qubits_size) };
218    let qubits = qubits
219        .iter()
220        .map(|index| LogicalQubit::main(*index))
221        .collect::<Vec<_>>();
222
223    let pauli_product: PauliProduct<_> = pauli
224        .iter()
225        .zip(qubits.iter())
226        .map(|(pauli, qubit)| {
227            let pauli = match pauli {
228                1 => Pauli::PauliX,
229                2 => Pauli::PauliY,
230                3 => Pauli::PauliZ,
231                _ => panic!("Undefined Pauli index. Use 1 for X, 2 for Y, and 3 for Z"),
232            };
233
234            PauliTerm {
235                pauli,
236                qubit: *qubit,
237            }
238        })
239        .collect();
240
241    hamiltonian.products.push(pauli_product);
242    hamiltonian.coefficients.push(coefficients);
243
244    KetError::Success.error_code()
245}
246
247/// Calculates the expected value of the `PauliHamiltonian` in the `Process` instance.
248///
249/// # Arguments
250///
251/// * `process` -  \[in\] A mutable reference to the `Process` instance.
252/// * `hamiltonian` -  \[in\] A mutable pointer to a `PauliHamiltonian`.
253/// * `result` -  \[out\] A mutable pointer to a `usize` where the result identifier will be stored.
254///
255/// # Returns
256///
257/// An integer representing the error code. `0` indicates success.
258///
259/// # Safety
260///
261/// This function is marked as unsafe due to the use of raw pointers.
262#[no_mangle]
263pub unsafe extern "C" fn ket_process_exp_value(
264    process: &mut Process,
265    hamiltonian: *mut Hamiltonian<LogicalQubit>,
266    result: &mut usize,
267) -> i32 {
268    let hamiltonian = unsafe { Box::from_raw(hamiltonian) };
269    match process.exp_value(*hamiltonian) {
270        Ok(result_id) => {
271            *result = result_id;
272
273            KetError::Success.error_code()
274        }
275        Err(error) => error.error_code(),
276    }
277}
278
279/// Samples the specified qubits in the `Process` instance.
280///
281/// # Arguments
282///
283/// * `process` -  \[in\] A mutable reference to the `Process` instance.
284/// * `qubits` -  \[in\] A pointer to an array of integers representing the qubit indices to be sampled.
285/// * `qubits_size` -  \[in\] The size of the `qubits` array.
286/// * `shots` -  \[in\] The number of measurement shots.
287/// * `result` -  \[out\] A mutable pointer to a `usize` where the result identifier will be stored.
288///
289/// # Returns
290///
291/// An integer representing the error code. `0` indicates success.
292///
293/// # Safety
294///
295/// This function is marked as unsafe due to the use of raw pointers.
296#[no_mangle]
297pub unsafe extern "C" fn ket_process_sample(
298    process: &mut Process,
299    qubits: *const usize,
300    qubits_size: usize,
301    shots: usize,
302    result: &mut usize,
303) -> i32 {
304    let qubits = unsafe { std::slice::from_raw_parts(qubits, qubits_size) };
305    let qubits = qubits
306        .iter()
307        .map(|index| LogicalQubit::main(*index))
308        .collect::<Vec<_>>();
309
310    match process.sample(&qubits, shots) {
311        Ok(result_id) => {
312            *result = result_id;
313
314            KetError::Success.error_code()
315        }
316        Err(error) => error.error_code(),
317    }
318}
319
320/// Dumps the state of the specified qubits in the `Process` instance.
321///
322/// # Arguments
323///
324/// * `process` -  \[in\] A mutable reference to the `Process` instance.
325/// * `qubits` -  \[in\] A pointer to an array of qubit indices to be dumped.
326/// * `qubits_size` -  \[in\] The size of the `qubits` array.
327/// * `result` -  \[out\] A mutable pointer to a `usize` representing the result index of the dump.
328///
329/// # Returns
330///
331/// An integer representing the error code. `0` indicates success.
332///
333/// # Safety
334///
335/// This function is marked as unsafe due to the use of raw pointers.
336#[no_mangle]
337pub unsafe extern "C" fn ket_process_dump(
338    process: &mut Process,
339    qubits: *const usize,
340    qubits_size: usize,
341    result: &mut usize,
342) -> i32 {
343    let qubits = unsafe { std::slice::from_raw_parts(qubits, qubits_size) };
344    let qubits = qubits
345        .iter()
346        .map(|index| LogicalQubit::main(*index))
347        .collect::<Vec<_>>();
348
349    match process.dump(&qubits) {
350        Ok(result_id) => {
351            *result = result_id;
352
353            KetError::Success.error_code()
354        }
355        Err(error) => error.error_code(),
356    }
357}
358
359/// Pushes control qubits onto the control stack in the `Process` instance.
360///
361/// # Arguments
362///
363/// * `process` -  \[in\] A mutable reference to the `Process` instance.
364/// * `qubits` -  \[in\] A pointer to an array of qubit indices to be pushed onto the control stack.
365/// * `qubits_size` -  \[in\] The size of the `qubits` array.
366///
367/// # Returns
368///
369/// An integer representing the error code. `0` indicates success.
370///
371/// # Safety
372///
373/// This function is marked as unsafe due to the use of raw pointers.
374#[no_mangle]
375pub unsafe extern "C" fn ket_process_ctrl_push(
376    process: &mut Process,
377    qubits: *const usize,
378    qubits_size: usize,
379) -> i32 {
380    let qubits = unsafe { std::slice::from_raw_parts(qubits, qubits_size) };
381    let qubits = qubits
382        .iter()
383        .map(|index| LogicalQubit::main(*index))
384        .collect::<Vec<_>>();
385
386    wrapper(process.ctrl_push(&qubits))
387}
388
389/// Pops control qubits from the control stack in the `Process` instance.
390///
391/// # Arguments
392///
393/// * `process` -  \[in\] A mutable reference to the `Process` instance.
394///
395/// # Returns
396///
397/// An integer representing the error code. `0` indicates success.
398#[no_mangle]
399pub extern "C" fn ket_process_ctrl_pop(process: &mut Process) -> i32 {
400    wrapper(process.ctrl_pop())
401}
402
403/// Pushes control stack in the `Process` instance.
404///
405/// # Arguments
406///
407/// * `process` -  \[in\] A mutable reference to the `Process` instance.
408///
409/// # Returns
410///
411/// An integer representing the error code. `0` indicates success.
412///
413/// # Safety
414///
415/// This function is marked as unsafe due to the use of raw pointers.
416#[no_mangle]
417pub unsafe extern "C" fn ket_process_ctrl_stack(process: &mut Process) -> i32 {
418    wrapper(process.ctrl_begin())
419}
420
421/// Pops control stack from the `Process` instance.
422///
423/// # Arguments
424///
425/// * `process` -  \[in\] A mutable reference to the `Process` instance.
426///
427/// # Returns
428///
429/// An integer representing the error code. `0` indicates success.
430#[no_mangle]
431pub extern "C" fn ket_process_ctrl_unstack(process: &mut Process) -> i32 {
432    wrapper(process.ctrl_end())
433}
434
435/// Begins an adjoint operation in the `Process` instance.
436///
437/// # Arguments
438///
439/// * `process` -  \[in\] A mutable reference to the `Process` instance.
440///
441/// # Returns
442///
443/// An integer representing the error code. `0` indicates success.
444#[no_mangle]
445pub extern "C" fn ket_process_adj_begin(process: &mut Process) -> i32 {
446    wrapper(process.adj_begin())
447}
448
449/// Ends an adjoint operation in the `Process` instance.
450///
451/// # Arguments
452///
453/// * `process` -  \[in\] A mutable reference to the `Process` instance.
454///
455/// # Returns
456///
457/// An integer representing the error code. `0` indicates success.
458#[no_mangle]
459pub extern "C" fn ket_process_adj_end(process: &mut Process) -> i32 {
460    wrapper(process.adj_end())
461}
462
463/// Prepares the `Process` instance for execution.
464///
465/// # Arguments
466///
467/// * `process` -  \[in\] A mutable reference to the `Process` instance.
468///
469/// # Returns
470///
471/// An integer representing the error code. `0` indicates success.
472#[no_mangle]
473pub extern "C" fn ket_process_execute(process: &mut Process) -> i32 {
474    wrapper(process.execute())
475}
476
477#[no_mangle]
478pub extern "C" fn ket_process_transpile(process: &mut Process) -> i32 {
479    process.transpile();
480    wrapper(Ok(()))
481}
482
483/// Gets the JSON representation of the logical instructions in the `Process` instance.
484///
485/// # Arguments
486///
487/// * `process` -  \[in\] A mutable reference to the `Process` instance.
488/// * `buffer` -  \[in/out\] A mutable pointer to a buffer to store the JSON representation.
489/// * `buffer_size` -  \[in\] The size of the provided buffer.
490/// * `write_size` -  \[out\] A mutable pointer to the actual size of the written data.
491///
492/// # Returns
493///
494/// An integer representing the error code. `0` indicates success.
495///
496/// # Safety
497///
498/// This function is marked as unsafe due to the use of raw pointers.
499#[no_mangle]
500pub unsafe extern "C" fn ket_process_instructions_json(
501    process: &mut Process,
502    buffer: *mut u8,
503    buffer_size: usize,
504    write_size: &mut usize,
505) -> i32 {
506    let instructions = process.instructions_json();
507    let instructions = instructions.as_bytes();
508    *write_size = instructions.len();
509    if buffer_size >= *write_size {
510        let buffer = unsafe { std::slice::from_raw_parts_mut(buffer, buffer_size) };
511        buffer[..*write_size].copy_from_slice(instructions);
512    }
513
514    KetError::Success.error_code()
515}
516
517/// Gets the JSON representation of the physical instructions in the `Process` instance.
518///
519/// # Arguments
520///
521/// * `process` -  \[in\] A mutable reference to the `Process` instance.
522/// * `buffer` -  \[in/out\] A mutable pointer to a buffer to store the JSON representation.
523/// * `buffer_size` -  \[in\] The size of the provided buffer.
524/// * `write_size` -  \[out\] A mutable pointer to the actual size of the written data.
525///
526/// # Returns
527///
528/// An integer representing the error code. `0` indicates success.
529///
530/// # Safety
531///
532/// This function is marked as unsafe due to the use of raw pointers.
533#[no_mangle]
534pub unsafe extern "C" fn ket_process_isa_instructions_json(
535    process: &mut Process,
536    buffer: *mut u8,
537    buffer_size: usize,
538    write_size: &mut usize,
539) -> i32 {
540    let instructions = process.isa_instructions_json();
541    let instructions = instructions.as_bytes();
542    *write_size = instructions.len();
543    if buffer_size >= *write_size {
544        let buffer = unsafe { std::slice::from_raw_parts_mut(buffer, buffer_size) };
545        buffer[..*write_size].copy_from_slice(instructions);
546    }
547
548    KetError::Success.error_code()
549}
550
551/// Gets the JSON representation of the metadata in the `Process` instance.
552///
553/// # Arguments
554///
555/// * `process` -  \[in\] A mutable reference to the `Process` instance.
556/// * `buffer` -  \[in/out\] A mutable pointer to a buffer to store the JSON representation.
557/// * `buffer_size` -  \[in\] The size of the provided buffer.
558/// * `write_size` -  \[out\] A mutable pointer to the actual size of the written data.
559///
560/// # Returns
561///
562/// An integer representing the error code. `0` indicates success.
563///
564/// # Safety
565///
566/// This function is marked as unsafe due to the use of raw pointers.
567#[no_mangle]
568pub unsafe extern "C" fn ket_process_metadata_json(
569    process: &mut Process,
570    buffer: *mut u8,
571    buffer_size: usize,
572    write_size: &mut usize,
573) -> i32 {
574    let metadata = process.metadata();
575    let metadata = serde_json::to_string(&metadata).unwrap();
576    let metadata = metadata.as_bytes();
577    *write_size = metadata.len();
578
579    if buffer_size >= *write_size {
580        let buffer = unsafe { std::slice::from_raw_parts_mut(buffer, buffer_size) };
581        buffer[..*write_size].copy_from_slice(metadata);
582    }
583
584    KetError::Success.error_code()
585}