use super::GenericDeviceWrapper;
use bincode::{deserialize, serialize};
use ndarray::Array2;
use numpy::{PyArray2, PyReadonlyArray2, ToPyArray};
use pyo3::exceptions::{PyTypeError, PyValueError};
use pyo3::prelude::*;
use pyo3::types::PyByteArray;
use qoqo_macros::devicewrapper;
use roqoqo::devices::{Device, SquareLatticeDevice};
#[cfg(feature = "json_schema")]
use roqoqo::{operations::SupportedVersion, ROQOQO_VERSION};
#[pyclass(name = "SquareLatticeDevice", module = "devices")]
#[derive(Clone, Debug, PartialEq)]
pub struct SquareLatticeDeviceWrapper {
pub internal: SquareLatticeDevice,
}
#[devicewrapper]
impl SquareLatticeDeviceWrapper {
#[new]
#[pyo3(
text_signature = "(number_rows, number_columns, single_qubit_gates, two_qubit_gates, default_gate_time)"
)]
pub fn new(
number_rows: usize,
number_columns: usize,
single_qubit_gates: Vec<String>,
two_qubit_gates: Vec<String>,
default_gate_time: f64,
) -> PyResult<Self> {
Ok(Self {
internal: SquareLatticeDevice::new(
number_rows,
number_columns,
&single_qubit_gates,
&two_qubit_gates,
default_gate_time,
),
})
}
pub fn number_rows(&self) -> usize {
self.internal.number_rows()
}
pub fn number_columns(&self) -> usize {
self.internal.number_columns()
}
#[pyo3(text_signature = "(gate, gate_time, /)")]
pub fn set_all_two_qubit_gate_times(&self, gate: &str, gate_time: f64) -> Self {
Self {
internal: self
.internal
.clone()
.set_all_two_qubit_gate_times(gate, gate_time),
}
}
#[pyo3(text_signature = "(gate, gate_time, /)")]
pub fn set_all_single_qubit_gate_times(&self, gate: &str, gate_time: f64) -> Self {
Self {
internal: self
.internal
.clone()
.set_all_single_qubit_gate_times(gate, gate_time),
}
}
#[pyo3(text_signature = "(rates, /)")]
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.")
})?,
})
}
#[pyo3(text_signature = "(damping, /)")]
pub fn add_damping_all(&mut self, damping: f64) -> Self {
Self {
internal: self.internal.clone().add_damping_all(damping),
}
}
#[pyo3(text_signature = "(dephasing, /)")]
pub fn add_dephasing_all(&mut self, dephasing: f64) -> Self {
Self {
internal: self.internal.clone().add_dephasing_all(dephasing),
}
}
#[pyo3(text_signature = "(depolarising, /)")]
pub fn add_depolarising_all(&mut self, depolarising: f64) -> Self {
Self {
internal: self.internal.clone().add_depolarising_all(depolarising),
}
}
#[cfg(feature = "json_schema")]
#[staticmethod]
pub fn json_schema() -> String {
let schema = schemars::schema_for!(SquareLatticeDevice);
serde_json::to_string_pretty(&schema).expect("Unexpected failure to serialize schema")
}
#[cfg(feature = "json_schema")]
#[staticmethod]
pub fn current_version() -> String {
ROQOQO_VERSION.to_string()
}
#[cfg(feature = "json_schema")]
pub fn min_supported_version(&self) -> String {
let min_version: (u32, u32, u32) =
SquareLatticeDevice::minimum_supported_roqoqo_version(&self.internal);
format!("{}.{}.{}", min_version.0, min_version.1, min_version.2)
}
}
impl SquareLatticeDeviceWrapper {
pub fn from_pyany(input: Py<PyAny>) -> PyResult<SquareLatticeDevice> {
Python::with_gil(|py| -> PyResult<SquareLatticeDevice> {
let input = input.as_ref(py);
if let Ok(try_downcast) = input.extract::<SquareLatticeDeviceWrapper>() {
Ok(try_downcast.internal)
} else {
let get_bytes = input.call_method0("to_bincode")?;
let bytes = get_bytes.extract::<Vec<u8>>()?;
deserialize(&bytes[..]).map_err(|err| {
PyValueError::new_err(format!(
"Cannot treat input as SquareLatticeDevice: {}",
err
))
})
}
})
}
}