use crate::{convert_into_circuit, CircuitWrapper};
use ndarray::{Array, Array1};
use num_complex::Complex64;
use numpy::{PyArray1, PyArray2, ToPyArray};
use pyo3::exceptions::{PyRuntimeError, PyTypeError};
use pyo3::prelude::*;
use pyo3::types::PySet;
use pyo3::PyObjectProtocol;
use qoqo_calculator::CalculatorFloat;
use qoqo_calculator_pyo3::{convert_into_calculator_float, CalculatorFloatWrapper};
use qoqo_macros::*;
use roqoqo::operations::*;
use roqoqo::Circuit;
use std::collections::HashMap;
#[wrap(Operate, OperatePragma)]
struct PragmaSetNumberOfMeasurements {
number_measurements: usize,
readout: String,
}
#[pymodule]
fn pragma_set_statevector(_py: Python, module: &PyModule) -> PyResult<()> {
module.add_class::<PragmaSetStateVectorWrapper>()?;
Ok(())
}
#[pyclass(name = "PragmaSetStateVector", module = "qoqo.operations")]
#[derive(Clone, Debug, PartialEq)]
pub struct PragmaSetStateVectorWrapper {
pub internal: PragmaSetStateVector,
}
insert_pyany_to_operation!(
"PragmaSetStateVector" =>{
let array = op.call_method0("statevector").expect("error extracting");
let statevec_casted: Vec<Complex64> = array.extract().unwrap();
let statevec_array: Array1<Complex64> = Array1::from(statevec_casted);
Ok(PragmaSetStateVector::new(statevec_array).into())
}
);
insert_operation_to_pyobject!(
Operation::PragmaSetStateVector(internal) => {
{
let pyref: Py<PragmaSetStateVectorWrapper> =
Py::new(py, PragmaSetStateVectorWrapper { internal }).unwrap();
let pyobject: PyObject = pyref.to_object(py);
Ok(pyobject)
}
}
);
#[pymethods]
impl PragmaSetStateVectorWrapper {
#[new]
fn new(statevector: Py<PyAny>) -> Self {
let statevec_casted: Vec<Complex64> = Python::with_gil(|py| -> Vec<Complex64> {
Vec::extract(statevector.as_ref(py)).unwrap()
});
let statevec_array: Array1<Complex64> = Array1::from(statevec_casted);
Self {
internal: PragmaSetStateVector::new(statevec_array),
}
}
fn statevector(&self) -> Py<PyArray1<Complex64>> {
Python::with_gil(|py| -> Py<PyArray1<Complex64>> {
self.internal.statevector().to_pyarray(py).to_owned()
})
}
fn involved_qubits(&self) -> PyObject {
let pyobject: PyObject =
Python::with_gil(|py| -> PyObject { PySet::new(py, &["All"]).unwrap().to_object(py) });
pyobject
}
fn tags(&self) -> Vec<String> {
self.internal.tags().iter().map(|s| s.to_string()).collect()
}
fn hqslang(&self) -> &'static str {
self.internal.hqslang()
}
fn is_parametrized(&self) -> bool {
self.internal.is_parametrized()
}
fn substitute_parameters(
&self,
substitution_parameters: std::collections::HashMap<&str, f64>,
) -> PyResult<Self> {
let mut calculator = qoqo_calculator::Calculator::new();
for (key, val) in substitution_parameters.iter() {
calculator.set_variable(key, *val);
}
Ok(Self {
internal: self
.internal
.substitute_parameters(&mut calculator)
.map_err(|x| {
pyo3::exceptions::PyRuntimeError::new_err(format!(
"Parameter Substitution failed: {:?}",
x
))
})?,
})
}
fn remap_qubits(&self, mapping: std::collections::HashMap<usize, usize>) -> PyResult<Self> {
let new_internal = self
.internal
.remap_qubits(&mapping)
.map_err(|_| pyo3::exceptions::PyRuntimeError::new_err("Qubit remapping failed: "))?;
Ok(Self {
internal: new_internal,
})
}
fn __copy__(&self) -> PragmaSetStateVectorWrapper {
self.clone()
}
fn __deepcopy__(&self, _memodict: Py<PyAny>) -> PragmaSetStateVectorWrapper {
self.clone()
}
}
#[pyproto]
impl PyObjectProtocol for PragmaSetStateVectorWrapper {
fn __repr__(&self) -> PyResult<String> {
Ok(format!("{:?}", self.internal))
}
fn __format__(&self, _format_spec: &str) -> PyResult<String> {
Ok(format!("{:?}", self.internal))
}
fn __richcmp__(&self, other: Py<PyAny>, op: pyo3::class::basic::CompareOp) -> PyResult<bool> {
let other: Operation = Python::with_gil(|py| -> PyResult<Operation> {
let other_ref = other.as_ref(py);
crate::operations::convert_pyany_to_operation(other_ref).map_err(|_| {
pyo3::exceptions::PyTypeError::new_err(
"Right hand side can not be converted to Operation",
)
})
})?;
match op {
pyo3::class::basic::CompareOp::Eq => {
Ok(Operation::from(self.internal.clone()) == other)
}
pyo3::class::basic::CompareOp::Ne => {
Ok(Operation::from(self.internal.clone()) != other)
}
_ => Err(pyo3::exceptions::PyNotImplementedError::new_err(
"Other comparison not implemented.",
)),
}
}
}
#[pymodule]
fn pragma_set_density_matrix(_py: Python, module: &PyModule) -> PyResult<()> {
module.add_class::<PragmaSetDensityMatrixWrapper>()?;
Ok(())
}
#[pyclass(name = "PragmaSetDensityMatrix", module = "qoqo.operations")]
#[derive(Clone, Debug, PartialEq)]
pub struct PragmaSetDensityMatrixWrapper {
pub internal: PragmaSetDensityMatrix,
}
insert_pyany_to_operation!(
"PragmaSetDensityMatrix" =>{
let array = op.call_method0("density_matrix")
.map_err(|_| QoqoError::ConversionError)?;
let densmat_casted: Vec<Complex64> = Vec::extract(array).unwrap();
let length: usize = densmat_casted.len();
let dim: usize = (length as f64).sqrt() as usize;
let densmat_array = Array::from_shape_vec((dim, dim), densmat_casted).unwrap();
Ok(PragmaSetDensityMatrix::new(densmat_array).into())
}
);
insert_operation_to_pyobject!(
Operation::PragmaSetDensityMatrix(internal) => {
{
let pyref: Py<PragmaSetDensityMatrixWrapper> =
Py::new(py, PragmaSetDensityMatrixWrapper { internal }).unwrap();
let pyobject: PyObject = pyref.to_object(py);
Ok(pyobject)
}
}
);
#[pymethods]
impl PragmaSetDensityMatrixWrapper {
#[new]
fn new(density_matrix: Py<PyAny>) -> PyResult<Self> {
let densmat_casted: Vec<Complex64> = Python::with_gil(|py| -> PyResult<Vec<Complex64>> {
Vec::extract(density_matrix.as_ref(py)).map_err(|_| {
PyTypeError::new_err(
"density_matrix input cannot be converted to list of complex numbers",
)
})
})?;
let length: usize = densmat_casted.len();
let dim: usize = (length as f64).sqrt() as usize;
let densmat_array = Array::from_shape_vec((dim, dim), densmat_casted).unwrap();
Ok(Self {
internal: PragmaSetDensityMatrix::new(densmat_array),
})
}
fn density_matrix(&self) -> Py<PyArray1<Complex64>> {
let array: Vec<Complex64> = self.internal.density_matrix().iter().cloned().collect();
Python::with_gil(|py| -> Py<PyArray1<Complex64>> { array.to_pyarray(py).to_owned() })
}
fn involved_qubits(&self) -> PyObject {
let pyobject: PyObject =
Python::with_gil(|py| -> PyObject { PySet::new(py, &["All"]).unwrap().to_object(py) });
pyobject
}
fn tags(&self) -> Vec<String> {
self.internal.tags().iter().map(|s| s.to_string()).collect()
}
fn hqslang(&self) -> &'static str {
self.internal.hqslang()
}
fn is_parametrized(&self) -> bool {
self.internal.is_parametrized()
}
fn substitute_parameters(
&self,
substitution_parameters: std::collections::HashMap<&str, f64>,
) -> PyResult<Self> {
let mut calculator = qoqo_calculator::Calculator::new();
for (key, val) in substitution_parameters.iter() {
calculator.set_variable(key, *val);
}
Ok(Self {
internal: self
.internal
.substitute_parameters(&mut calculator)
.map_err(|x| {
pyo3::exceptions::PyRuntimeError::new_err(format!(
"Parameter Substitution failed: {:?}",
x
))
})?,
})
}
fn remap_qubits(&self, mapping: std::collections::HashMap<usize, usize>) -> PyResult<Self> {
let new_internal = self
.internal
.remap_qubits(&mapping)
.map_err(|_| pyo3::exceptions::PyRuntimeError::new_err("Qubit remapping failed: "))?;
Ok(Self {
internal: new_internal,
})
}
fn __copy__(&self) -> PragmaSetDensityMatrixWrapper {
self.clone()
}
fn __deepcopy__(&self, _memodict: Py<PyAny>) -> PragmaSetDensityMatrixWrapper {
self.clone()
}
}
#[pyproto]
impl PyObjectProtocol for PragmaSetDensityMatrixWrapper {
fn __repr__(&self) -> PyResult<String> {
Ok(format!("{:?}", self.internal))
}
fn __format__(&self, _format_spec: &str) -> PyResult<String> {
Ok(format!("{:?}", self.internal))
}
fn __richcmp__(&self, other: Py<PyAny>, op: pyo3::class::basic::CompareOp) -> PyResult<bool> {
let other: Operation = Python::with_gil(|py| -> PyResult<Operation> {
let other_ref = other.as_ref(py);
crate::operations::convert_pyany_to_operation(other_ref).map_err(|_| {
pyo3::exceptions::PyTypeError::new_err(
"Right hand side can not be converted to Operation",
)
})
})?;
match op {
pyo3::class::basic::CompareOp::Eq => {
Ok(Operation::from(self.internal.clone()) == other)
}
pyo3::class::basic::CompareOp::Ne => {
Ok(Operation::from(self.internal.clone()) != other)
}
_ => Err(pyo3::exceptions::PyNotImplementedError::new_err(
"Other comparison not implemented.",
)),
}
}
}
#[wrap(Operate, OperatePragma)]
struct PragmaRepeatGate {
repetition_coefficient: usize,
}
#[wrap(Operate, OperatePragma, OperateMultiQubit)]
struct PragmaOverrotation {
gate_hqslang: String,
qubits: Vec<usize>,
amplitude: f64,
variance: f64,
}
#[wrap(Operate, OperatePragma)]
struct PragmaBoostNoise {
noise_coefficient: CalculatorFloat,
}
#[wrap(Operate, OperateMultiQubit, OperatePragma)]
struct PragmaStopParallelBlock {
qubits: Vec<usize>,
execution_time: CalculatorFloat,
}
#[wrap(Operate)]
struct PragmaGlobalPhase {
phase: CalculatorFloat,
}
#[wrap(Operate, OperateMultiQubit, OperatePragma)]
pub struct PragmaSleep {
qubits: Vec<usize>,
sleep_time: CalculatorFloat,
}
#[wrap(Operate, OperateSingleQubit, OperatePragma)]
pub struct PragmaActiveReset {
qubit: usize,
}
#[wrap(Operate, OperateMultiQubit, OperatePragma)]
pub struct PragmaStartDecompositionBlock {
qubits: Vec<usize>,
reordering_dictionary: HashMap<usize, usize>,
}
#[wrap(Operate, OperateMultiQubit, OperatePragma)]
pub struct PragmaStopDecompositionBlock {
qubits: Vec<usize>,
}
#[wrap(Operate, OperateSingleQubit, OperatePragma)]
pub struct PragmaDamping {
qubit: usize,
gate_time: CalculatorFloat,
rate: CalculatorFloat,
}
#[pymethods]
impl PragmaDampingWrapper {
pub fn superoperator(&self) -> PyResult<Py<PyArray2<f64>>> {
Ok(Python::with_gil(|py| -> Py<PyArray2<f64>> {
self.internal
.superoperator()
.unwrap()
.to_pyarray(py)
.to_owned()
}))
}
pub fn probability(&self) -> CalculatorFloatWrapper {
CalculatorFloatWrapper {
cf_internal: self.internal.probability(),
}
}
pub fn powercf(&self, power: CalculatorFloatWrapper) -> Self {
Self {
internal: self.internal.powercf(power.cf_internal),
}
}
}
#[wrap(Operate, OperateSingleQubit, OperatePragma)]
pub struct PragmaDepolarising {
qubit: usize,
gate_time: CalculatorFloat,
rate: CalculatorFloat,
}
#[pymethods]
impl PragmaDepolarisingWrapper {
pub fn superoperator(&self) -> PyResult<Py<PyArray2<f64>>> {
Ok(Python::with_gil(|py| -> Py<PyArray2<f64>> {
self.internal
.superoperator()
.unwrap()
.to_pyarray(py)
.to_owned()
}))
}
pub fn probability(&self) -> CalculatorFloatWrapper {
CalculatorFloatWrapper {
cf_internal: self.internal.probability(),
}
}
pub fn powercf(&self, power: CalculatorFloatWrapper) -> Self {
Self {
internal: self.internal.powercf(power.cf_internal),
}
}
}
#[wrap(Operate, OperateSingleQubit, OperatePragma)]
pub struct PragmaDephasing {
qubit: usize,
gate_time: CalculatorFloat,
rate: CalculatorFloat,
}
#[pymethods]
impl PragmaDephasingWrapper {
pub fn superoperator(&self) -> PyResult<Py<PyArray2<f64>>> {
Ok(Python::with_gil(|py| -> Py<PyArray2<f64>> {
self.internal
.superoperator()
.unwrap()
.to_pyarray(py)
.to_owned()
}))
}
pub fn probability(&self) -> CalculatorFloatWrapper {
CalculatorFloatWrapper {
cf_internal: self.internal.probability(),
}
}
pub fn powercf(&self, power: CalculatorFloatWrapper) -> Self {
Self {
internal: self.internal.powercf(power.cf_internal),
}
}
}
#[wrap(Operate, OperateSingleQubit, OperatePragma)]
pub struct PragmaRandomNoise {
qubit: usize,
gate_time: CalculatorFloat,
depolarising_rate: CalculatorFloat,
dephasing_rate: CalculatorFloat,
}
#[pymethods]
impl PragmaRandomNoiseWrapper {
pub fn superoperator(&self) -> PyResult<Py<PyArray2<f64>>> {
Ok(Python::with_gil(|py| -> Py<PyArray2<f64>> {
self.internal
.superoperator()
.unwrap()
.to_pyarray(py)
.to_owned()
}))
}
pub fn probability(&self) -> CalculatorFloatWrapper {
CalculatorFloatWrapper {
cf_internal: self.internal.probability(),
}
}
pub fn powercf(&self, power: CalculatorFloatWrapper) -> Self {
Self {
internal: self.internal.powercf(power.cf_internal),
}
}
}
#[pymodule]
fn pragma_general_noise(_py: Python, module: &PyModule) -> PyResult<()> {
module.add_class::<PragmaGeneralNoiseWrapper>()?;
Ok(())
}
#[pyclass(name = "PragmaGeneralNoise", module = "qoqo.operations")]
#[derive(Clone, Debug, PartialEq)]
pub struct PragmaGeneralNoiseWrapper {
pub internal: PragmaGeneralNoise,
}
insert_pyany_to_operation!(
"PragmaGeneralNoise" =>{
let qbt = op.call_method0("qubit")
.map_err(|_| QoqoError::ConversionError)?;
let qubit: usize = qbt.extract()
.map_err(|_| QoqoError::ConversionError)?;
let gatetm = op.call_method0("gate_time")
.map_err(|_| QoqoError::ConversionError)?;
let gate_time: CalculatorFloat = convert_into_calculator_float(gatetm).map_err(|_| {
QoqoError::ConversionError
})?;
let rt = op.call_method0("rate")
.map_err(|_| QoqoError::ConversionError)?;
let rate: CalculatorFloat = convert_into_calculator_float(rt).map_err(|_| {
QoqoError::ConversionError
})?;
let array = op.call_method0("operators")
.map_err(|_| QoqoError::ConversionError)?;
let densmat_casted: Vec<Complex64> = Vec::extract(array).unwrap();
let length: usize = densmat_casted.len();
let dim: usize = (length as f64).sqrt() as usize;
let operators = Array::from_shape_vec((dim, dim), densmat_casted).unwrap();
Ok(PragmaGeneralNoise::new(qubit, gate_time, rate, operators).into())
}
);
insert_operation_to_pyobject!(
Operation::PragmaGeneralNoise(internal) => {
{
let pyref: Py<PragmaGeneralNoiseWrapper> =
Py::new(py, PragmaGeneralNoiseWrapper { internal }).unwrap();
let pyobject: PyObject = pyref.to_object(py);
Ok(pyobject)
}
}
);
#[pymethods]
impl PragmaGeneralNoiseWrapper {
#[new]
fn new(
qubit: usize,
gate_time: Py<PyAny>,
rate: Py<PyAny>,
operators: Py<PyAny>,
) -> PyResult<Self> {
let operators_casted: Vec<Complex64> = Python::with_gil(|py| -> Vec<Complex64> {
Vec::extract(operators.as_ref(py)).unwrap()
});
let operators_array = Array::from_shape_vec((3, 3), operators_casted).unwrap();
let gate_time_cf = Python::with_gil(|py| -> PyResult<CalculatorFloat> {
convert_into_calculator_float(gate_time.as_ref(py)).map_err(|_| {
pyo3::exceptions::PyTypeError::new_err(
"Argument gate time cannot be converted to CalculatorFloat",
)
})
})?;
let rate_cf = Python::with_gil(|py| -> PyResult<CalculatorFloat> {
convert_into_calculator_float(rate.as_ref(py)).map_err(|_| {
pyo3::exceptions::PyTypeError::new_err(
"Argument rate cannot be converted to CalculatorFloat",
)
})
})?;
Ok(Self {
internal: PragmaGeneralNoise::new(qubit, gate_time_cf, rate_cf, operators_array),
})
}
fn qubit(&self) -> usize {
*self.internal.qubit()
}
fn gate_time(&self) -> CalculatorFloatWrapper {
CalculatorFloatWrapper {
cf_internal: self.internal.gate_time().clone(),
}
}
fn rate(&self) -> CalculatorFloatWrapper {
CalculatorFloatWrapper {
cf_internal: self.internal.rate().clone(),
}
}
fn operators(&self) -> Py<PyArray1<Complex64>> {
Python::with_gil(|py| -> Py<PyArray1<Complex64>> {
self.internal
.operators()
.iter()
.cloned()
.collect::<Vec<Complex64>>()
.to_pyarray(py)
.to_owned()
})
}
fn involved_qubits(&self) -> PyObject {
let pyobject: PyObject = Python::with_gil(|py| -> PyObject {
PySet::new(py, &[*self.internal.qubit()])
.unwrap()
.to_object(py)
});
pyobject
}
fn tags(&self) -> Vec<String> {
self.internal.tags().iter().map(|s| s.to_string()).collect()
}
fn hqslang(&self) -> &'static str {
self.internal.hqslang()
}
fn is_parametrized(&self) -> bool {
self.internal.is_parametrized()
}
fn substitute_parameters(
&self,
substitution_parameters: std::collections::HashMap<&str, f64>,
) -> PyResult<Self> {
let mut calculator = qoqo_calculator::Calculator::new();
for (key, val) in substitution_parameters.iter() {
calculator.set_variable(key, *val);
}
Ok(Self {
internal: self
.internal
.substitute_parameters(&mut calculator)
.map_err(|x| {
pyo3::exceptions::PyRuntimeError::new_err(format!(
"Parameter Substitution failed: {:?}",
x
))
})?,
})
}
fn remap_qubits(&self, mapping: std::collections::HashMap<usize, usize>) -> PyResult<Self> {
let new_internal = self
.internal
.remap_qubits(&mapping)
.map_err(|_| pyo3::exceptions::PyRuntimeError::new_err("Qubit remapping failed: "))?;
Ok(Self {
internal: new_internal,
})
}
fn __copy__(&self) -> PragmaGeneralNoiseWrapper {
self.clone()
}
fn __deepcopy__(&self, _memodict: Py<PyAny>) -> PragmaGeneralNoiseWrapper {
self.clone()
}
}
#[pyproto]
impl PyObjectProtocol for PragmaGeneralNoiseWrapper {
fn __repr__(&self) -> PyResult<String> {
Ok(format!("{:?}", self.internal))
}
fn __format__(&self, _format_spec: &str) -> PyResult<String> {
Ok(format!("{:?}", self.internal))
}
fn __richcmp__(&self, other: Py<PyAny>, op: pyo3::class::basic::CompareOp) -> PyResult<bool> {
let other: Operation = Python::with_gil(|py| -> PyResult<Operation> {
let other_ref = other.as_ref(py);
crate::operations::convert_pyany_to_operation(other_ref).map_err(|_| {
pyo3::exceptions::PyTypeError::new_err(
"Right hand side can not be converted to Operation",
)
})
})?;
match op {
pyo3::class::basic::CompareOp::Eq => {
Ok(Operation::from(self.internal.clone()) == other)
}
pyo3::class::basic::CompareOp::Ne => {
Ok(Operation::from(self.internal.clone()) != other)
}
_ => Err(pyo3::exceptions::PyNotImplementedError::new_err(
"Other comparison not implemented.",
)),
}
}
}
#[wrap(Operate, OperatePragma)]
pub struct PragmaConditional {
condition_register: String,
condition_index: usize,
circuit: Circuit,
}