use bincode::{deserialize, serialize};
use ndarray::Array2;
use numpy::{PyArray2, PyReadonlyArray2, ToPyArray};
use pyo3::exceptions::{PyTypeError, PyValueError};
use pyo3::prelude::*;
use pyo3::types::{PyByteArray, PyType};
use qoqo_macros::devicewrapper;
use roqoqo::devices::{AllToAllDevice, Device, GenericChain, GenericDevice, GenericGrid};
#[pymodule]
pub fn devices(_py: Python, module: &PyModule) -> PyResult<()> {
module.add_class::<GenericGridWrapper>()?;
module.add_class::<GenericChainWrapper>()?;
module.add_class::<GenericDeviceWrapper>()?;
module.add_class::<AllToAllDeviceWrapper>()?;
Ok(())
}
#[pyclass(name = "GenericGrid", module = "devices")]
#[derive(Clone, Debug, PartialEq)]
pub struct GenericGridWrapper {
pub internal: GenericGrid,
}
#[devicewrapper]
impl GenericGridWrapper {
#[new]
pub fn new(
number_rows: usize,
number_columns: usize,
single_qubit_gates: Vec<String>,
two_qubit_gates: Vec<String>,
multi_qubit_gates: Vec<String>,
) -> PyResult<Self> {
Ok(Self {
internal: GenericGrid::new(
number_rows,
number_columns,
&single_qubit_gates,
&two_qubit_gates,
&multi_qubit_gates,
),
})
}
pub fn number_rows(&self) -> usize {
self.internal.number_rows()
}
pub fn number_columns(&self) -> usize {
self.internal.number_columns()
}
fn qubit_decoherence_rates(&self, qubit: usize) -> Py<PyArray2<f64>> {
Python::with_gil(|py| -> Py<PyArray2<f64>> {
match self.internal.qubit_decoherence_rates(&qubit) {
Some(matrix) => matrix.to_pyarray(py).to_owned(),
None => {
let matrix = Array2::<f64>::zeros((3, 3));
matrix.to_pyarray(py).to_owned()
}
}
})
}
pub fn set_all_qubit_decoherence_rates(&self, rates: PyReadonlyArray2<f64>) -> PyResult<Self> {
let rates_matrix = rates.as_array().to_owned();
Ok(Self {
internal: self
.internal
.clone()
.set_all_qubit_decoherence_rates(rates_matrix)
.map_err(|_| {
PyValueError::new_err("The input parameter `rates` needs to be a (3x3)-matrix.")
})?,
})
}
}
#[pyclass(name = "AllToAllDevice", module = "devices")]
#[derive(Clone, Debug, PartialEq)]
pub struct AllToAllDeviceWrapper {
pub internal: AllToAllDevice,
}
#[devicewrapper]
impl AllToAllDeviceWrapper {
#[new]
pub fn new(
number_qubits: usize,
single_qubit_gates: Vec<String>,
two_qubit_gates: Vec<String>,
multi_qubit_gates: Vec<String>,
) -> PyResult<Self> {
Ok(Self {
internal: AllToAllDevice::new(
number_qubits,
&single_qubit_gates,
&two_qubit_gates,
&multi_qubit_gates,
),
})
}
fn qubit_decoherence_rates(&self, qubit: usize) -> Py<PyArray2<f64>> {
Python::with_gil(|py| -> Py<PyArray2<f64>> {
match self.internal.qubit_decoherence_rates(&qubit) {
Some(matrix) => matrix.to_pyarray(py).to_owned(),
None => {
let matrix = Array2::<f64>::zeros((3, 3));
matrix.to_pyarray(py).to_owned()
}
}
})
}
pub fn set_all_qubit_decoherence_rates(&self, rates: PyReadonlyArray2<f64>) -> PyResult<Self> {
let rates_matrix = rates.as_array().to_owned();
Ok(Self {
internal: self
.internal
.clone()
.set_all_qubit_decoherence_rates(rates_matrix)
.map_err(|_| {
PyValueError::new_err("The input parameter `rates` needs to be a (3x3)-matrix.")
})?,
})
}
}
#[pyclass(name = "GenericDevice", module = "devices")]
#[derive(Clone, Debug, PartialEq)]
pub struct GenericDeviceWrapper {
pub internal: GenericDevice,
}
#[devicewrapper]
impl GenericDeviceWrapper {
#[new]
pub fn new(
number_qubits: usize,
single_qubit_gates: Vec<String>,
two_qubit_gates: Vec<String>,
multi_qubit_gates: Vec<String>,
) -> PyResult<Self> {
Ok(Self {
internal: GenericDevice::new(
number_qubits,
&single_qubit_gates,
&two_qubit_gates,
&multi_qubit_gates,
),
})
}
fn qubit_decoherence_rates(&self, qubit: usize) -> Py<PyArray2<f64>> {
Python::with_gil(|py| -> Py<PyArray2<f64>> {
match self.internal.qubit_decoherence_rates(&qubit) {
Some(matrix) => matrix.to_pyarray(py).to_owned(),
None => {
let matrix = Array2::<f64>::zeros((3, 3));
matrix.to_pyarray(py).to_owned()
}
}
})
}
pub fn set_all_qubit_decoherence_rates(&self, rates: PyReadonlyArray2<f64>) -> PyResult<Self> {
let rates_matrix = rates.as_array().to_owned();
Ok(Self {
internal: self
.internal
.clone()
.set_all_qubit_decoherence_rates(rates_matrix)
.map_err(|_| {
PyValueError::new_err("The input parameter `rates` needs to be a (3x3)-matrix.")
})?,
})
}
}
#[pyclass(name = "GenericChain", module = "devices")]
#[derive(Clone, Debug, PartialEq)]
pub struct GenericChainWrapper {
pub internal: GenericChain,
}
#[devicewrapper]
impl GenericChainWrapper {
#[new]
pub fn new(
number_qubits: usize,
single_qubit_gates: Vec<String>,
two_qubit_gates: Vec<String>,
multi_qubit_gates: Vec<String>,
) -> PyResult<Self> {
Ok(Self {
internal: GenericChain::new(
number_qubits,
&single_qubit_gates,
&two_qubit_gates,
&multi_qubit_gates,
),
})
}
fn qubit_decoherence_rates(&self, qubit: usize) -> Py<PyArray2<f64>> {
Python::with_gil(|py| -> Py<PyArray2<f64>> {
match self.internal.qubit_decoherence_rates(&qubit) {
Some(matrix) => matrix.to_pyarray(py).to_owned(),
None => {
let matrix = Array2::<f64>::zeros((3, 3));
matrix.to_pyarray(py).to_owned()
}
}
})
}
pub fn set_all_qubit_decoherence_rates(&self, rates: PyReadonlyArray2<f64>) -> PyResult<Self> {
let rates_matrix = rates.as_array().to_owned();
Ok(Self {
internal: self
.internal
.clone()
.set_all_qubit_decoherence_rates(rates_matrix)
.map_err(|_| {
PyValueError::new_err("The input parameter `rates` needs to be a (3x3)-matrix.")
})?,
})
}
}