#![deny(clippy::all, clippy::pedantic)]
pub mod result_bool;
pub mod exp;
use bitvec::prelude::*;
use num_bigint::BigUint;
use num_complex::Complex64;
use quantum_sparse_sim::QuantumSim;
use std::cell::RefCell;
use std::convert::TryInto;
use std::ffi::c_char;
use std::ffi::c_double;
use std::ffi::{c_void, CString};
use std::io::Write;
use std::mem::size_of;
use result_bool::{
__quantum__rt__result_equal, __quantum__rt__result_get_one, __quantum__rt__result_get_zero,
};
pub use qir_stdlib::{
arrays::*, bigints::*, callables::*, math::*, output_recording::*, range_support::*,
strings::*, tuples::*, *,
};
struct SimulatorState {
pub sim: QuantumSim,
pub res: BitVec,
pub max_qubit_id: usize,
}
thread_local! {
static SIM_STATE: RefCell<SimulatorState> = RefCell::new(SimulatorState {
sim: QuantumSim::default(),
res: bitvec![],
max_qubit_id: 0
});
}
pub fn set_rng_seed(seed: u64) {
SIM_STATE.with(|sim_state| {
let state = &mut *sim_state.borrow_mut();
state.sim.set_rng_seed(seed);
});
}
#[no_mangle]
pub extern "C" fn __quantum__rt__initialize(_: *mut c_char) {
SIM_STATE.with(|sim_state| {
let state = &mut *sim_state.borrow_mut();
state.sim = QuantumSim::default();
state.res = bitvec![];
state.max_qubit_id = 0;
});
}
fn ensure_sufficient_qubits(sim: &mut QuantumSim, qubit_id: usize, max: &mut usize) {
while qubit_id + 1 > *max {
let _ = sim.allocate();
*max += 1;
}
}
#[allow(clippy::cast_ptr_alignment)]
unsafe fn map_to_z_basis(
state: &mut SimulatorState,
paulis: *const QirArray,
qubits: *const QirArray,
) -> Vec<(Pauli, usize)> {
let paulis_size = __quantum__rt__array_get_size_1d(paulis);
let qubits_size = __quantum__rt__array_get_size_1d(qubits);
if paulis_size != qubits_size {
__quantum__rt__fail(__quantum__rt__string_create(
CString::new("Pauli array and Qubit array must be the same size.")
.expect("Unable to allocate memory for failure message string.")
.as_bytes_with_nul()
.as_ptr() as *mut c_char,
));
}
let combined_list: Vec<(Pauli, usize)> = (0..paulis_size)
.filter_map(|index| {
let p =
*__quantum__rt__array_get_element_ptr_1d(paulis, index).cast::<Pauli>() as Pauli;
let q = *__quantum__rt__array_get_element_ptr_1d(qubits, index).cast::<*mut c_void>()
as usize;
if let Pauli::I = p {
None
} else {
ensure_sufficient_qubits(&mut state.sim, q, &mut state.max_qubit_id);
Some((p, q))
}
})
.collect();
for (pauli, qubit) in &combined_list {
match pauli {
Pauli::X => state.sim.h(*qubit),
Pauli::Y => {
state.sim.h(*qubit);
state.sim.s(*qubit);
state.sim.h(*qubit);
}
_ => (),
}
}
combined_list
}
fn unmap_from_z_basis(state: &mut SimulatorState, combined_list: Vec<(Pauli, usize)>) {
for (pauli, qubit) in combined_list {
match pauli {
Pauli::X => state.sim.h(qubit),
Pauli::Y => {
state.sim.h(qubit);
state.sim.sadj(qubit);
state.sim.h(qubit);
}
_ => (),
}
}
}
macro_rules! single_qubit_gate {
($(#[$meta:meta])*
$qir_name:ident, $gate:expr) => {
$(#[$meta])*
#[no_mangle]
pub extern "C" fn $qir_name(qubit: *mut c_void) {
SIM_STATE.with(|sim_state| {
let state = &mut *sim_state.borrow_mut();
ensure_sufficient_qubits(&mut state.sim, qubit as usize, &mut state.max_qubit_id);
$gate(&mut state.sim, qubit as usize);
});
}
};
}
single_qubit_gate!(
__quantum__qis__h__body,
QuantumSim::h
);
single_qubit_gate!(
__quantum__qis__s__body,
QuantumSim::s
);
single_qubit_gate!(
__quantum__qis__s__adj,
QuantumSim::sadj
);
single_qubit_gate!(
__quantum__qis__t__body,
QuantumSim::t
);
single_qubit_gate!(
__quantum__qis__t__adj,
QuantumSim::tadj
);
single_qubit_gate!(
__quantum__qis__x__body,
QuantumSim::x
);
single_qubit_gate!(
__quantum__qis__y__body,
QuantumSim::y
);
single_qubit_gate!(
__quantum__qis__z__body,
QuantumSim::z
);
macro_rules! controlled_qubit_gate {
($(#[$meta:meta])*
$qir_name:ident, $gate:expr, 1) => {
$(#[$meta])*
#[no_mangle]
pub extern "C" fn $qir_name(control: *mut c_void, target: *mut c_void) {
SIM_STATE.with(|sim_state| {
let state = &mut *sim_state.borrow_mut();
ensure_sufficient_qubits(&mut state.sim, target as usize, &mut state.max_qubit_id);
ensure_sufficient_qubits(&mut state.sim, control as usize, &mut state.max_qubit_id);
$gate(&mut state.sim, &[control as usize], target as usize);
});
}
};
($(#[$meta:meta])*
$qir_name:ident, $gate:expr, 2) => {
$(#[$meta])*
#[no_mangle]
pub extern "C" fn $qir_name(
control_1: *mut c_void,
control_2: *mut c_void,
target: *mut c_void,
) {
SIM_STATE.with(|sim_state| {
let state = &mut *sim_state.borrow_mut();
ensure_sufficient_qubits(&mut state.sim, target as usize, &mut state.max_qubit_id);
ensure_sufficient_qubits(&mut state.sim, control_1 as usize, &mut state.max_qubit_id);
ensure_sufficient_qubits(&mut state.sim, control_2 as usize, &mut state.max_qubit_id);
$gate(&mut state.sim, &[control_1 as usize, control_2 as usize], target as usize);
});
}
};
}
controlled_qubit_gate!(
__quantum__qis__cnot__body,
QuantumSim::mcx,
1
);
controlled_qubit_gate!(
__quantum__qis__cx__body,
QuantumSim::mcx,
1
);
controlled_qubit_gate!(
__quantum__qis__ccx__body,
QuantumSim::mcx,
2
);
controlled_qubit_gate!(
__quantum__qis__cy__body,
QuantumSim::mcy,
1
);
controlled_qubit_gate!(
__quantum__qis__cz__body,
QuantumSim::mcz,
1
);
macro_rules! single_qubit_rotation {
($(#[$meta:meta])*
$qir_name:ident, $gate:expr) => {
$(#[$meta])*
#[no_mangle]
pub extern "C" fn $qir_name(theta: c_double, qubit: *mut c_void) {
SIM_STATE.with(|sim_state| {
let state = &mut *sim_state.borrow_mut();
ensure_sufficient_qubits(&mut state.sim, qubit as usize, &mut state.max_qubit_id);
$gate(&mut state.sim, theta, qubit as usize);
});
}
};
}
single_qubit_rotation!(
__quantum__qis__rx__body,
QuantumSim::rx
);
single_qubit_rotation!(
__quantum__qis__ry__body,
QuantumSim::ry
);
single_qubit_rotation!(
__quantum__qis__rz__body,
QuantumSim::rz
);
macro_rules! multicontrolled_qubit_gate {
($(#[$meta:meta])*
$qir_name:ident, $gate:expr) => {
$(#[$meta])*
#[no_mangle]
pub unsafe extern "C" fn $qir_name(ctls: *const QirArray, qubit: *mut c_void) {
SIM_STATE.with(|sim_state| {
let state = &mut *sim_state.borrow_mut();
ensure_sufficient_qubits(&mut state.sim, qubit as usize, &mut state.max_qubit_id);
let ctls_size = __quantum__rt__array_get_size_1d(ctls);
let ctls_list: Vec<usize> = (0..ctls_size)
.map(|index| {
let q = *__quantum__rt__array_get_element_ptr_1d(ctls, index)
.cast::<*mut c_void>() as usize;
ensure_sufficient_qubits(&mut state.sim, q, &mut state.max_qubit_id);
q
})
.collect();
$gate(&mut state.sim, &ctls_list, qubit as usize);
});
}
};
}
multicontrolled_qubit_gate!(
__quantum__qis__h__ctl,
QuantumSim::mch
);
multicontrolled_qubit_gate!(
__quantum__qis__s__ctl,
QuantumSim::mcs
);
multicontrolled_qubit_gate!(
__quantum__qis__s__ctladj,
QuantumSim::mcsadj
);
multicontrolled_qubit_gate!(
__quantum__qis__t__ctl,
QuantumSim::mct
);
multicontrolled_qubit_gate!(
__quantum__qis__t__ctladj,
QuantumSim::mctadj
);
multicontrolled_qubit_gate!(
__quantum__qis__x__ctl,
QuantumSim::mcx
);
multicontrolled_qubit_gate!(
__quantum__qis__y__ctl,
QuantumSim::mcy
);
multicontrolled_qubit_gate!(
__quantum__qis__z__ctl,
QuantumSim::mcz
);
#[derive(Copy, Clone)]
#[repr(C)]
struct RotationArgs {
theta: c_double,
qubit: *mut c_void,
}
macro_rules! multicontrolled_qubit_rotation {
($(#[$meta:meta])*
$qir_name:ident, $gate:expr) => {
$(#[$meta])*
#[no_mangle]
pub unsafe extern "C" fn $qir_name(
ctls: *const QirArray,
arg_tuple: *mut *const Vec<u8>,
) {
SIM_STATE.with(|sim_state| {
let state = &mut *sim_state.borrow_mut();
let args = *arg_tuple.cast::<RotationArgs>();
ensure_sufficient_qubits(&mut state.sim, args.qubit as usize, &mut state.max_qubit_id);
let ctls_size = __quantum__rt__array_get_size_1d(ctls);
let ctls_list: Vec<usize> = (0..ctls_size)
.map(|index| {
let q = *__quantum__rt__array_get_element_ptr_1d(ctls, index)
.cast::<*mut c_void>() as usize;
ensure_sufficient_qubits(&mut state.sim, q, &mut state.max_qubit_id);
q
})
.collect();
$gate(
&mut state.sim,
&ctls_list,
args.theta,
args.qubit as usize,
);
});
}
};
}
multicontrolled_qubit_rotation!(
__quantum__qis__rx__ctl,
QuantumSim::mcrx
);
multicontrolled_qubit_rotation!(
__quantum__qis__ry__ctl,
QuantumSim::mcry
);
multicontrolled_qubit_rotation!(
__quantum__qis__rz__ctl,
QuantumSim::mcrz
);
#[no_mangle]
pub extern "C" fn __quantum__qis__rxx__body(
theta: c_double,
qubit1: *mut c_void,
qubit2: *mut c_void,
) {
__quantum__qis__h__body(qubit1);
__quantum__qis__h__body(qubit2);
__quantum__qis__rzz__body(theta, qubit1, qubit2);
__quantum__qis__h__body(qubit2);
__quantum__qis__h__body(qubit1);
}
#[no_mangle]
pub extern "C" fn __quantum__qis__ryy__body(
theta: c_double,
qubit1: *mut c_void,
qubit2: *mut c_void,
) {
__quantum__qis__h__body(qubit1);
__quantum__qis__s__body(qubit1);
__quantum__qis__h__body(qubit1);
__quantum__qis__h__body(qubit2);
__quantum__qis__s__body(qubit2);
__quantum__qis__h__body(qubit2);
__quantum__qis__rzz__body(theta, qubit1, qubit2);
__quantum__qis__h__body(qubit2);
__quantum__qis__s__adj(qubit2);
__quantum__qis__h__body(qubit2);
__quantum__qis__h__body(qubit1);
__quantum__qis__s__adj(qubit1);
__quantum__qis__h__body(qubit1);
}
#[no_mangle]
pub extern "C" fn __quantum__qis__rzz__body(
theta: c_double,
qubit1: *mut c_void,
qubit2: *mut c_void,
) {
__quantum__qis__cx__body(qubit2, qubit1);
__quantum__qis__rz__body(theta, qubit1);
__quantum__qis__cx__body(qubit2, qubit1);
}
#[no_mangle]
pub extern "C" fn __quantum__qis__r__body(pauli: Pauli, theta: c_double, qubit: *mut c_void) {
match pauli {
Pauli::I => (),
Pauli::X => __quantum__qis__rx__body(theta, qubit),
Pauli::Y => __quantum__qis__ry__body(theta, qubit),
Pauli::Z => __quantum__qis__rz__body(theta, qubit),
}
}
#[no_mangle]
pub extern "C" fn __quantum__qis__r__adj(pauli: Pauli, theta: c_double, qubit: *mut c_void) {
__quantum__qis__r__body(pauli, -theta, qubit);
}
#[derive(Copy, Clone)]
#[repr(C)]
struct PauliRotationArgs {
pauli: Pauli,
theta: c_double,
qubit: *mut c_void,
}
#[allow(clippy::cast_ptr_alignment)]
#[no_mangle]
pub unsafe extern "C" fn __quantum__qis__r__ctl(
ctls: *const QirArray,
arg_tuple: *mut *const Vec<u8>,
) {
let args = *arg_tuple.cast::<PauliRotationArgs>();
let rot_args = RotationArgs {
theta: args.theta,
qubit: args.qubit,
};
let rot_arg_tuple = __quantum__rt__tuple_create(size_of::<RotationArgs>() as u64);
*rot_arg_tuple.cast::<RotationArgs>() = rot_args;
match args.pauli {
Pauli::X => __quantum__qis__rx__ctl(ctls, rot_arg_tuple),
Pauli::Y => __quantum__qis__ry__ctl(ctls, rot_arg_tuple),
Pauli::Z => __quantum__qis__rz__ctl(ctls, rot_arg_tuple),
Pauli::I => {
if __quantum__rt__array_get_size_1d(ctls) > 0 {
SIM_STATE.with(|sim_state| {
let state = &mut *sim_state.borrow_mut();
ensure_sufficient_qubits(
&mut state.sim,
args.qubit as usize,
&mut state.max_qubit_id,
);
let ctls_size = __quantum__rt__array_get_size_1d(ctls);
let ctls_list: Vec<usize> = (0..ctls_size)
.map(|index| {
let q = *__quantum__rt__array_get_element_ptr_1d(ctls, index)
.cast::<*mut c_void>() as usize;
ensure_sufficient_qubits(&mut state.sim, q, &mut state.max_qubit_id);
q
})
.collect();
if let Some((head, rest)) = ctls_list.split_first() {
state.sim.mcphase(
rest,
Complex64::exp(Complex64::new(0.0, -args.theta / 2.0)),
*head,
);
}
});
}
}
};
__quantum__rt__tuple_update_reference_count(rot_arg_tuple, -1);
}
#[no_mangle]
pub unsafe extern "C" fn __quantum__qis__r__ctladj(
ctls: *const QirArray,
arg_tuple: *mut *const Vec<u8>,
) {
let args = *arg_tuple.cast::<PauliRotationArgs>();
let new_args = PauliRotationArgs {
pauli: args.pauli,
theta: -args.theta,
qubit: args.qubit,
};
let new_arg_tuple = __quantum__rt__tuple_create(size_of::<PauliRotationArgs>() as u64);
*new_arg_tuple.cast::<PauliRotationArgs>() = new_args;
__quantum__qis__r__ctl(ctls, new_arg_tuple);
__quantum__rt__tuple_update_reference_count(new_arg_tuple, -1);
}
#[no_mangle]
pub extern "C" fn __quantum__qis__swap__body(qubit1: *mut c_void, qubit2: *mut c_void) {
SIM_STATE.with(|sim_state| {
let state = &mut *sim_state.borrow_mut();
ensure_sufficient_qubits(&mut state.sim, qubit1 as usize, &mut state.max_qubit_id);
ensure_sufficient_qubits(&mut state.sim, qubit2 as usize, &mut state.max_qubit_id);
state.sim.swap_qubit_ids(qubit1 as usize, qubit2 as usize);
});
}
#[no_mangle]
pub extern "C" fn __quantum__qis__reset__body(qubit: *mut c_void) {
SIM_STATE.with(|sim_state| {
let state = &mut *sim_state.borrow_mut();
ensure_sufficient_qubits(&mut state.sim, qubit as usize, &mut state.max_qubit_id);
if state.sim.measure(qubit as usize) {
state.sim.x(qubit as usize);
}
});
}
#[allow(clippy::missing_panics_doc)]
#[no_mangle]
pub extern "C" fn __quantum__qis__mresetz__body(qubit: *mut c_void, result: *mut c_void) {
SIM_STATE.with(|sim_state| {
let state = &mut *sim_state.borrow_mut();
let res_id = result as usize;
ensure_sufficient_qubits(&mut state.sim, qubit as usize, &mut state.max_qubit_id);
if state.res.len() < res_id + 1 {
state.res.resize(res_id + 1, false);
}
let res = state.sim.measure(qubit as usize);
if res {
state.sim.x(qubit as usize);
}
*state
.res
.get_mut(res_id)
.expect("Result with given id missing after expansion.") = res;
});
}
#[allow(clippy::missing_panics_doc)]
#[no_mangle]
pub extern "C" fn __quantum__qis__mz__body(qubit: *mut c_void, result: *mut c_void) {
SIM_STATE.with(|sim_state| {
let state = &mut *sim_state.borrow_mut();
let res_id = result as usize;
ensure_sufficient_qubits(&mut state.sim, qubit as usize, &mut state.max_qubit_id);
if state.res.len() < res_id + 1 {
state.res.resize(res_id + 1, false);
}
*state
.res
.get_mut(res_id)
.expect("Result with given id missing after expansion.") =
state.sim.measure(qubit as usize);
});
}
#[allow(clippy::missing_panics_doc)]
#[no_mangle]
pub extern "C" fn __quantum__qis__read_result__body(result: *mut c_void) -> bool {
SIM_STATE.with(|sim_state| {
let res = &mut sim_state.borrow_mut().res;
let res_id = result as usize;
if res.len() < res_id + 1 {
res.resize(res_id + 1, false);
}
let b = *res
.get(res_id)
.expect("Result with given id missing after expansion.");
b
})
}
#[no_mangle]
pub extern "C" fn __quantum__qis__m__body(qubit: *mut c_void) -> *mut c_void {
SIM_STATE.with(|sim_state| {
let state = &mut *sim_state.borrow_mut();
ensure_sufficient_qubits(&mut state.sim, qubit as usize, &mut state.max_qubit_id);
if state.sim.measure(qubit as usize) {
__quantum__rt__result_get_one()
} else {
__quantum__rt__result_get_zero()
}
})
}
#[allow(clippy::cast_ptr_alignment)]
#[no_mangle]
pub unsafe extern "C" fn __quantum__qis__measure__body(
paulis: *const QirArray,
qubits: *const QirArray,
) -> *mut c_void {
SIM_STATE.with(|sim_state| {
let mut state = sim_state.borrow_mut();
let combined_list = map_to_z_basis(&mut state, paulis, qubits);
let res = state.sim.joint_measure(
&combined_list
.iter()
.map(|(_, q)| *q)
.collect::<Vec<usize>>(),
);
unmap_from_z_basis(&mut state, combined_list);
if res {
__quantum__rt__result_get_one()
} else {
__quantum__rt__result_get_zero()
}
})
}
pub fn qubit_is_zero(qubit: *mut c_void) -> bool {
SIM_STATE.with(|sim_state| {
let state = &mut *sim_state.borrow_mut();
ensure_sufficient_qubits(&mut state.sim, qubit as usize, &mut state.max_qubit_id);
state.sim.qubit_is_zero(qubit as usize)
})
}
#[no_mangle]
pub unsafe extern "C" fn __quantum__qis__assertmeasurementprobability__body(
paulis: *const QirArray,
qubits: *const QirArray,
result: *mut c_void,
prob: c_double,
msg: *const CString,
tol: c_double,
) {
SIM_STATE.with(|sim_state| {
let mut state = sim_state.borrow_mut();
let combined_list = map_to_z_basis(&mut state, paulis, qubits);
let mut actual_prob = state.sim.joint_probability(
&combined_list
.iter()
.map(|(_, q)| *q)
.collect::<Vec<usize>>(),
);
if __quantum__rt__result_equal(result, __quantum__rt__result_get_zero()) {
actual_prob = 1.0 - actual_prob;
}
if (actual_prob - prob).abs() > tol {
__quantum__rt__fail(msg);
}
unmap_from_z_basis(&mut state, combined_list);
});
}
#[derive(Copy, Clone)]
#[repr(C)]
struct AssertMeasurementProbabilityArgs {
paulis: *const QirArray,
qubits: *const QirArray,
result: *mut c_void,
prob: c_double,
msg: *const CString,
tol: c_double,
}
#[no_mangle]
pub unsafe extern "C" fn __quantum__qis__assertmeasurementprobability__ctl(
_ctls: *const QirArray,
arg_tuple: *mut *const Vec<u8>,
) {
let args = *arg_tuple.cast::<AssertMeasurementProbabilityArgs>();
__quantum__qis__assertmeasurementprobability__body(
args.paulis,
args.qubits,
args.result,
args.prob,
args.msg,
args.tol,
);
}
pub mod legacy_output {
use std::ffi::c_void;
use qir_stdlib::output_recording::record_output_str;
use crate::{
result_bool::{__quantum__rt__result_equal, __quantum__rt__result_get_one},
SIM_STATE,
};
#[allow(clippy::missing_panics_doc)]
#[allow(non_snake_case)]
pub extern "C" fn __quantum__rt__result_record_output(result: *mut c_void) {
SIM_STATE.with(|sim_state| {
let res = &mut sim_state.borrow_mut().res;
let res_id = result as usize;
let b = if res.is_empty() {
__quantum__rt__result_equal(result, __quantum__rt__result_get_one())
} else {
if res.len() < res_id + 1 {
res.resize(res_id + 1, false);
}
*res.get(res_id)
.expect("Result with given id missing after expansion.")
};
record_output_str(&format!("RESULT\t{}", if b { "1" } else { "0" }))
.expect("Failed to write result output");
});
}
}
#[allow(clippy::missing_panics_doc)]
#[no_mangle]
pub unsafe extern "C" fn __quantum__rt__result_record_output(
result: *mut c_void,
tag: *mut c_char,
) {
SIM_STATE.with(|sim_state| {
let res = &mut sim_state.borrow_mut().res;
let res_id = result as usize;
let b = if res.is_empty() {
__quantum__rt__result_equal(result, __quantum__rt__result_get_one())
} else {
if res.len() < res_id + 1 {
res.resize(res_id + 1, false);
}
*res.get(res_id)
.expect("Result with given id missing after expansion.")
};
let val: i64 = i64::from(b);
record_output("RESULT", &val, tag).expect("Failed to write result output");
});
}
#[no_mangle]
pub extern "C" fn __quantum__rt__qubit_allocate() -> *mut c_void {
SIM_STATE.with(|sim_state| {
let mut state = sim_state.borrow_mut();
let qubit_id = state.sim.allocate();
state.max_qubit_id = state.max_qubit_id.max(qubit_id + 1);
qubit_id as *mut c_void
})
}
#[allow(clippy::cast_ptr_alignment)]
#[no_mangle]
pub extern "C" fn __quantum__rt__qubit_allocate_array(size: u64) -> *const QirArray {
let arr = __quantum__rt__array_create_1d(
size_of::<usize>()
.try_into()
.expect("System pointer size too large to be described with u32."),
size,
);
for index in 0..size {
unsafe {
let elem = __quantum__rt__array_get_element_ptr_1d(arr, index).cast::<*mut c_void>();
*elem = __quantum__rt__qubit_allocate();
}
}
arr
}
#[allow(clippy::cast_ptr_alignment)]
#[no_mangle]
pub unsafe extern "C" fn __quantum__rt__qubit_release_array(arr: *const QirArray) {
for index in 0..__quantum__rt__array_get_size_1d(arr) {
let elem = __quantum__rt__array_get_element_ptr_1d(arr, index).cast::<*mut c_void>();
__quantum__rt__qubit_release(*elem);
}
__quantum__rt__array_update_alias_count(arr, -1);
}
#[no_mangle]
pub extern "C" fn __quantum__rt__qubit_release(qubit: *mut c_void) {
SIM_STATE.with(|sim_state| {
let mut state = sim_state.borrow_mut();
state.sim.release(qubit as usize);
});
}
#[no_mangle]
pub extern "C" fn __quantum__rt__qubit_to_string(qubit: *mut c_void) -> *const CString {
unsafe {
__quantum__rt__string_create(
CString::new(format!("{}", qubit as usize))
.expect("Unable to allocate memory for qubit string.")
.as_bytes_with_nul()
.as_ptr() as *mut c_char,
)
}
}
#[must_use]
pub fn capture_quantum_state() -> (Vec<(BigUint, Complex64)>, usize) {
SIM_STATE.with(|sim_state| {
let mut state = sim_state.borrow_mut();
state.sim.get_state()
})
}
#[no_mangle]
pub extern "C" fn __quantum__qis__dumpmachine__body(location: *mut c_void) {
if !location.is_null() {
unimplemented!("Dump to location is not implemented.")
}
SIM_STATE.with(|sim_state| {
let mut state = sim_state.borrow_mut();
if !state.res.is_empty() {
OUTPUT.with(|output| {
let mut output = output.borrow_mut();
output
.write_fmt(format_args!("Global Results: {}", state.res))
.expect("Failed to write global results");
output.write_newline();
});
}
OUTPUT.with(|output| {
let mut output = output.borrow_mut();
output
.write_all(state.sim.dump().as_bytes())
.expect("Failed to write simulator state");
});
});
}
#[cfg(test)]
mod tests {
use std::{f64::consts::PI, ffi::c_void, ptr::null_mut};
use crate::{
__quantum__qis__cnot__body, __quantum__qis__cx__body, __quantum__qis__cz__body,
__quantum__qis__dumpmachine__body, __quantum__qis__h__body, __quantum__qis__m__body,
__quantum__qis__mresetz__body, __quantum__qis__mz__body, __quantum__qis__read_result__body,
__quantum__qis__rx__body, __quantum__qis__rxx__body, __quantum__qis__ry__body,
__quantum__qis__ryy__body, __quantum__qis__rz__body, __quantum__qis__rzz__body,
__quantum__qis__s__adj, __quantum__qis__s__body, __quantum__qis__x__body,
__quantum__rt__qubit_allocate, __quantum__rt__qubit_allocate_array,
__quantum__rt__qubit_release, __quantum__rt__qubit_release_array,
__quantum__rt__result_equal, capture_quantum_state, map_to_z_basis, qubit_is_zero,
result_bool::__quantum__rt__result_get_one, unmap_from_z_basis, SIM_STATE,
};
use num_bigint::BigUint;
use qir_stdlib::{
arrays::{
__quantum__rt__array_create_1d, __quantum__rt__array_get_element_ptr_1d,
__quantum__rt__array_update_reference_count,
},
Pauli,
};
#[test]
fn basic_test_static() {
let q0 = 5 as *mut c_void;
let r0 = std::ptr::null_mut();
let r1 = 1 as *mut c_void;
__quantum__qis__mz__body(q0, r0);
assert!(!__quantum__qis__read_result__body(r0));
__quantum__qis__x__body(q0);
__quantum__qis__mz__body(q0, r1);
assert!(__quantum__qis__read_result__body(r1));
__quantum__qis__x__body(q0);
__quantum__qis__mz__body(q0, r0);
assert!(!__quantum__qis__read_result__body(r0));
assert!(!__quantum__qis__read_result__body(3 as *mut c_void));
__quantum__qis__dumpmachine__body(null_mut());
}
#[allow(clippy::cast_ptr_alignment)]
#[test]
fn basic_test_dynamic() {
let q1 = __quantum__rt__qubit_allocate();
let q2 = __quantum__rt__qubit_allocate();
__quantum__qis__h__body(q1);
__quantum__qis__cnot__body(q1, q2);
let r1 = __quantum__qis__m__body(q1);
let r2 = __quantum__qis__m__body(q2);
assert!(__quantum__rt__result_equal(r1, r2));
__quantum__qis__dumpmachine__body(null_mut());
__quantum__rt__qubit_release(q2);
__quantum__rt__qubit_release(q1);
let qs = __quantum__rt__qubit_allocate_array(4);
unsafe {
let q_elem = __quantum__rt__array_get_element_ptr_1d(qs, 3).cast::<*mut c_void>();
__quantum__qis__x__body(*q_elem);
__quantum__qis__dumpmachine__body(null_mut());
let r = __quantum__qis__m__body(*q_elem);
assert!(__quantum__rt__result_equal(
r,
__quantum__rt__result_get_one()
));
__quantum__rt__qubit_release_array(qs);
}
}
#[test]
fn test_qubit_is_zero() {
let q0 = __quantum__rt__qubit_allocate();
assert!(qubit_is_zero(q0));
__quantum__qis__x__body(q0);
assert!(!qubit_is_zero(q0));
__quantum__qis__h__body(q0);
assert!(!qubit_is_zero(q0));
let r = __quantum__qis__m__body(q0);
assert!(
qubit_is_zero(q0) != __quantum__rt__result_equal(r, __quantum__rt__result_get_one())
);
}
#[allow(clippy::cast_ptr_alignment)]
#[test]
fn test_map_unmap_are_adjoint() {
unsafe fn check_map_unmap(pauli: Pauli) {
let check_qubit = __quantum__rt__qubit_allocate();
let qubits = __quantum__rt__qubit_allocate_array(1);
let q = *__quantum__rt__array_get_element_ptr_1d(qubits, 0).cast::<*mut c_void>();
let paulis = __quantum__rt__array_create_1d(1, 1);
*__quantum__rt__array_get_element_ptr_1d(paulis, 0).cast::<Pauli>() = pauli;
__quantum__qis__h__body(check_qubit);
__quantum__qis__cnot__body(check_qubit, q);
SIM_STATE.with(|sim_state| {
let state = &mut *sim_state.borrow_mut();
let combined_list = map_to_z_basis(state, paulis, qubits);
unmap_from_z_basis(state, combined_list);
});
__quantum__qis__cnot__body(check_qubit, q);
__quantum__qis__h__body(check_qubit);
assert!(qubit_is_zero(q));
assert!(qubit_is_zero(check_qubit));
__quantum__rt__array_update_reference_count(paulis, -1);
__quantum__rt__qubit_release_array(qubits);
__quantum__rt__qubit_release(check_qubit);
}
unsafe {
check_map_unmap(Pauli::X);
check_map_unmap(Pauli::Y);
check_map_unmap(Pauli::Z);
}
}
#[allow(clippy::cast_ptr_alignment)]
#[test]
fn test_map_pauli_x() {
let qubits = __quantum__rt__qubit_allocate_array(1);
unsafe {
let q = *__quantum__rt__array_get_element_ptr_1d(qubits, 0).cast::<*mut c_void>();
let paulis = __quantum__rt__array_create_1d(1, 1);
*__quantum__rt__array_get_element_ptr_1d(paulis, 0).cast::<Pauli>() = Pauli::X;
__quantum__qis__h__body(q);
SIM_STATE.with(|sim_state| {
let state = &mut *sim_state.borrow_mut();
let _ = map_to_z_basis(state, paulis, qubits);
});
qubit_is_zero(q);
__quantum__rt__array_update_reference_count(paulis, -1);
__quantum__rt__qubit_release_array(qubits);
}
}
#[allow(clippy::cast_ptr_alignment)]
#[test]
fn test_map_pauli_y() {
let qubits = __quantum__rt__qubit_allocate_array(1);
unsafe {
let q = *__quantum__rt__array_get_element_ptr_1d(qubits, 0).cast::<*mut c_void>();
let paulis = __quantum__rt__array_create_1d(1, 1);
*__quantum__rt__array_get_element_ptr_1d(paulis, 0).cast::<Pauli>() = Pauli::Y;
__quantum__qis__h__body(q);
__quantum__qis__s__adj(q);
__quantum__qis__h__body(q);
SIM_STATE.with(|sim_state| {
let state = &mut *sim_state.borrow_mut();
let _ = map_to_z_basis(state, paulis, qubits);
});
qubit_is_zero(q);
__quantum__rt__array_update_reference_count(paulis, -1);
__quantum__rt__qubit_release_array(qubits);
}
}
#[allow(clippy::cast_ptr_alignment)]
#[test]
fn test_map_pauli_z() {
let qubits = __quantum__rt__qubit_allocate_array(1);
unsafe {
let q = *__quantum__rt__array_get_element_ptr_1d(qubits, 0).cast::<*mut c_void>();
let paulis = __quantum__rt__array_create_1d(1, 1);
*__quantum__rt__array_get_element_ptr_1d(paulis, 0).cast::<Pauli>() = Pauli::Z;
SIM_STATE.with(|sim_state| {
let state = &mut *sim_state.borrow_mut();
let _ = map_to_z_basis(state, paulis, qubits);
});
qubit_is_zero(q);
__quantum__rt__array_update_reference_count(paulis, -1);
__quantum__rt__qubit_release_array(qubits);
}
}
#[test]
fn test_joint_zz() {
let check_qubit = __quantum__rt__qubit_allocate();
let q0 = __quantum__rt__qubit_allocate();
let q1 = __quantum__rt__qubit_allocate();
__quantum__qis__h__body(check_qubit);
__quantum__qis__cx__body(check_qubit, q0);
__quantum__qis__cx__body(check_qubit, q1);
__quantum__qis__rzz__body(PI / 2.0, q0, q1);
__quantum__qis__rz__body(-PI / 2.0, q0);
__quantum__qis__rz__body(-PI / 2.0, q1);
__quantum__qis__cz__body(q0, q1);
__quantum__qis__cx__body(check_qubit, q1);
__quantum__qis__cx__body(check_qubit, q0);
__quantum__qis__h__body(check_qubit);
assert!(qubit_is_zero(check_qubit));
assert!(qubit_is_zero(q0));
assert!(qubit_is_zero(q1));
}
#[test]
fn test_joint_yy() {
let check_qubit = __quantum__rt__qubit_allocate();
let q0 = __quantum__rt__qubit_allocate();
let q1 = __quantum__rt__qubit_allocate();
__quantum__qis__h__body(check_qubit);
__quantum__qis__cx__body(check_qubit, q0);
__quantum__qis__cx__body(check_qubit, q1);
__quantum__qis__h__body(q0);
__quantum__qis__s__adj(q0);
__quantum__qis__h__body(q0);
__quantum__qis__h__body(q1);
__quantum__qis__s__adj(q1);
__quantum__qis__h__body(q1);
__quantum__qis__ryy__body(PI / 2.0, q0, q1);
__quantum__qis__ry__body(-PI / 2.0, q0);
__quantum__qis__ry__body(-PI / 2.0, q1);
__quantum__qis__h__body(q1);
__quantum__qis__s__body(q1);
__quantum__qis__h__body(q1);
__quantum__qis__h__body(q0);
__quantum__qis__s__body(q0);
__quantum__qis__h__body(q0);
__quantum__qis__cz__body(q0, q1);
__quantum__qis__cx__body(check_qubit, q1);
__quantum__qis__cx__body(check_qubit, q0);
__quantum__qis__h__body(check_qubit);
assert!(qubit_is_zero(check_qubit));
assert!(qubit_is_zero(q0));
assert!(qubit_is_zero(q1));
}
#[test]
fn test_joint_xx() {
let check_qubit = __quantum__rt__qubit_allocate();
let q0 = __quantum__rt__qubit_allocate();
let q1 = __quantum__rt__qubit_allocate();
__quantum__qis__h__body(check_qubit);
__quantum__qis__cx__body(check_qubit, q0);
__quantum__qis__cx__body(check_qubit, q1);
__quantum__qis__h__body(q0);
__quantum__qis__h__body(q1);
__quantum__qis__rxx__body(PI / 2.0, q0, q1);
__quantum__qis__rx__body(-PI / 2.0, q0);
__quantum__qis__rx__body(-PI / 2.0, q1);
__quantum__qis__h__body(q0);
__quantum__qis__h__body(q1);
__quantum__qis__cz__body(q0, q1);
__quantum__qis__cx__body(check_qubit, q1);
__quantum__qis__cx__body(check_qubit, q0);
__quantum__qis__h__body(check_qubit);
assert!(qubit_is_zero(check_qubit));
assert!(qubit_is_zero(q0));
assert!(qubit_is_zero(q1));
}
#[test]
fn test_mresetz() {
let qubit = __quantum__rt__qubit_allocate();
let r0 = std::ptr::null_mut();
let r1 = 1 as *mut c_void;
assert!(qubit_is_zero(qubit));
__quantum__qis__mresetz__body(qubit, r0);
assert!(!__quantum__qis__read_result__body(r0));
assert!(qubit_is_zero(qubit));
__quantum__qis__x__body(qubit);
__quantum__qis__mresetz__body(qubit, r1);
assert!(__quantum__qis__read_result__body(r1));
assert!(qubit_is_zero(qubit));
}
#[test]
fn test_capture_quantum_state() {
let qubit = __quantum__rt__qubit_allocate();
let (state, qubit_count) = capture_quantum_state();
assert_eq!(qubit_count, 1);
assert_eq!(state.len(), 1);
assert_eq!(state[0].0, BigUint::from(0u32));
__quantum__qis__x__body(qubit);
let (state, qubit_count) = capture_quantum_state();
assert_eq!(qubit_count, 1);
assert_eq!(state.len(), 1);
assert_eq!(state[0].0, BigUint::from(1u32));
__quantum__qis__h__body(qubit);
let qubit2 = __quantum__rt__qubit_allocate();
let (state, qubit_count) = capture_quantum_state();
assert_eq!(qubit_count, 2);
assert_eq!(state.len(), 2);
assert_eq!(state[0].1, -state[1].1);
__quantum__qis__h__body(qubit);
__quantum__qis__x__body(qubit);
let (state, qubit_count) = capture_quantum_state();
assert_eq!(qubit_count, 2);
assert_eq!(state.len(), 1);
assert_eq!(state[0].0, BigUint::from(0u32));
__quantum__rt__qubit_release(qubit);
__quantum__rt__qubit_release(qubit2);
let (state, qubit_count) = capture_quantum_state();
assert_eq!(qubit_count, 0);
assert_eq!(state.len(), 1);
assert_eq!(state[0].0, BigUint::from(0u32));
}
}