use std::ffi::CString;
use crate::{
error::catch_quest_exception,
ffi::{
self,
pauliOpType as PauliOpType,
},
Qcomplex,
Qreal,
QuestEnv,
QuestError,
Qureg,
};
#[derive(Debug)]
pub struct PauliHamil(pub(crate) ffi::PauliHamil);
impl PauliHamil {
pub fn try_new(
num_qubits: i32,
num_sum_terms: i32,
) -> Result<Self, QuestError> {
catch_quest_exception(|| {
Self(unsafe { ffi::createPauliHamil(num_qubits, num_sum_terms) })
})
}
pub fn try_new_from_file(fn_: &str) -> Result<Self, QuestError> {
let filename = CString::new(fn_).map_err(QuestError::NulError)?;
catch_quest_exception(|| {
Self(unsafe { ffi::createPauliHamilFromFile((*filename).as_ptr()) })
})
}
}
impl Drop for PauliHamil {
fn drop(&mut self) {
catch_quest_exception(|| unsafe { ffi::destroyPauliHamil(self.0) })
.expect("dropping PauliHamil should always succeed");
}
}
#[derive(Debug)]
pub struct DiagonalOp<'a> {
pub(crate) env: &'a QuestEnv,
pub(crate) op: ffi::DiagonalOp,
}
impl<'a> DiagonalOp<'a> {
pub fn try_new(
num_qubits: i32,
env: &'a QuestEnv,
) -> Result<Self, QuestError> {
Ok(Self {
env,
op: catch_quest_exception(|| unsafe {
ffi::createDiagonalOp(num_qubits, env.0)
})?,
})
}
pub fn try_new_from_file(
fn_: &str,
env: &'a QuestEnv,
) -> Result<Self, QuestError> {
let filename = CString::new(fn_).map_err(QuestError::NulError)?;
Ok(Self {
env,
op: catch_quest_exception(|| unsafe {
ffi::createDiagonalOpFromPauliHamilFile(
(*filename).as_ptr(),
env.0,
)
})?,
})
}
}
impl<'a> Drop for DiagonalOp<'a> {
fn drop(&mut self) {
catch_quest_exception(|| unsafe {
ffi::destroyDiagonalOp(self.op, self.env.0);
})
.expect("dropping DiagonalOp should always succeed");
}
}
#[allow(clippy::needless_pass_by_ref_mut)]
pub fn init_pauli_hamil(
hamil: &mut PauliHamil,
coeffs: &[Qreal],
codes: &[PauliOpType],
) -> Result<(), QuestError> {
catch_quest_exception(|| unsafe {
ffi::initPauliHamil(hamil.0, coeffs.as_ptr(), codes.as_ptr());
})
}
#[allow(clippy::needless_pass_by_ref_mut)]
pub fn sync_diagonal_op(op: &mut DiagonalOp<'_>) -> Result<(), QuestError> {
catch_quest_exception(|| unsafe {
ffi::syncDiagonalOp(op.op);
})
}
#[allow(clippy::cast_sign_loss)]
#[allow(clippy::needless_pass_by_ref_mut)]
pub fn init_diagonal_op(
op: &mut DiagonalOp<'_>,
real: &[Qreal],
imag: &[Qreal],
) -> Result<(), QuestError> {
let len_required = 2usize.pow(op.op.numQubits as u32);
assert!(real.len() >= len_required);
assert!(imag.len() >= len_required);
catch_quest_exception(|| unsafe {
ffi::initDiagonalOp(op.op, real.as_ptr(), imag.as_ptr());
})
}
#[allow(clippy::needless_pass_by_ref_mut)]
pub fn init_diagonal_op_from_pauli_hamil(
op: &mut DiagonalOp<'_>,
hamil: &PauliHamil,
) -> Result<(), QuestError> {
catch_quest_exception(|| unsafe {
ffi::initDiagonalOpFromPauliHamil(op.op, hamil.0);
})
}
#[allow(clippy::cast_sign_loss)]
#[allow(clippy::cast_possible_truncation)]
#[allow(clippy::needless_pass_by_ref_mut)]
pub fn set_diagonal_op_elems(
op: &mut DiagonalOp<'_>,
start_ind: i64,
real: &[Qreal],
imag: &[Qreal],
num_elems: i64,
) -> Result<(), QuestError> {
assert!(real.len() >= num_elems as usize);
assert!(imag.len() >= num_elems as usize);
catch_quest_exception(|| unsafe {
ffi::setDiagonalOpElems(
op.op,
start_ind,
real.as_ptr(),
imag.as_ptr(),
num_elems,
);
})
}
#[allow(clippy::needless_pass_by_ref_mut)]
pub fn apply_diagonal_op(
qureg: &mut Qureg<'_>,
op: &DiagonalOp<'_>,
) -> Result<(), QuestError> {
catch_quest_exception(|| unsafe {
ffi::applyDiagonalOp(qureg.reg, op.op);
})
}
pub fn calc_expec_diagonal_op(
qureg: &Qureg<'_>,
op: &DiagonalOp<'_>,
) -> Result<Qcomplex, QuestError> {
catch_quest_exception(|| unsafe {
ffi::calcExpecDiagonalOp(qureg.reg, op.op)
})
.map(Into::into)
}