use std::collections::HashMap;
use super::Device;
use super::GenericDevice;
use crate::RoqoqoError;
use ndarray::Array2;
#[derive(Clone, Debug, PartialEq, Default)]
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "json_schema", derive(schemars::JsonSchema))]
pub struct SquareLatticeDevice {
number_rows: usize,
number_columns: usize,
generic_device: GenericDevice,
}
impl SquareLatticeDevice {
pub fn new(
number_rows: usize,
number_columns: usize,
single_qubit_gates: &[String],
two_qubit_gates: &[String],
default_gate_time: f64,
) -> Self {
let generic = GenericDevice {
number_qubits: number_rows * number_columns,
single_qubit_gates: HashMap::with_capacity(single_qubit_gates.len()),
two_qubit_gates: HashMap::with_capacity(two_qubit_gates.len()),
multi_qubit_gates: HashMap::new(),
decoherence_rates: HashMap::with_capacity(number_rows * number_columns),
};
let mut new = Self {
number_rows,
number_columns,
generic_device: generic,
};
for gate_name in single_qubit_gates {
new = new.set_all_single_qubit_gate_times(gate_name, default_gate_time);
}
for gate_name in two_qubit_gates {
new = new.set_all_two_qubit_gate_times(gate_name, default_gate_time);
}
new = new
.set_all_qubit_decoherence_rates(Array2::zeros((3, 3)))
.expect("Internal bug");
new
}
pub fn number_columns(&self) -> usize {
self.number_columns
}
pub fn number_rows(&self) -> usize {
self.number_rows
}
pub fn set_all_single_qubit_gate_times(mut self, gate: &str, gate_time: f64) -> Self {
let number_qubits = <Self as Device>::number_qubits(&self);
if let Some(gate_times) = self.generic_device.single_qubit_gates.get_mut(gate) {
for gatetime in gate_times.values_mut() {
*gatetime = gate_time
}
} else {
let mut gatetimes: HashMap<usize, f64> = HashMap::with_capacity(number_qubits);
for qubit in 0..number_qubits {
gatetimes.insert(qubit, gate_time);
}
self.generic_device
.single_qubit_gates
.insert(gate.to_string(), gatetimes);
}
self
}
pub fn set_all_two_qubit_gate_times(mut self, gate: &str, gate_time: f64) -> Self {
let number_qubits = <Self as Device>::number_qubits(&self);
if let Some(gate_times) = self.generic_device.two_qubit_gates.get_mut(gate) {
for gatetime in gate_times.values_mut() {
*gatetime = gate_time
}
} else {
let mut gatetimes: HashMap<(usize, usize), f64> =
HashMap::with_capacity(number_qubits * 4);
for row in 0..self.number_rows() {
for column in 0..self.number_columns() - 1 {
gatetimes.insert(
(
row * self.number_columns + column,
row * self.number_columns + column + 1,
),
gate_time,
);
gatetimes.insert(
(
row * self.number_columns + column + 1,
row * self.number_columns + column,
),
gate_time,
);
}
}
for row in 0..self.number_rows - 1 {
for column in 0..self.number_columns {
gatetimes.insert(
(
row * self.number_columns + column,
(row + 1) * self.number_columns + column,
),
gate_time,
);
gatetimes.insert(
(
(row + 1) * self.number_columns + column,
row * self.number_columns + column,
),
gate_time,
);
}
}
self.generic_device
.two_qubit_gates
.insert(gate.to_string(), gatetimes);
}
self
}
pub fn set_single_qubit_gate_time(
&mut self,
gate: &str,
qubit: usize,
gate_time: f64,
) -> Result<(), RoqoqoError> {
self.generic_device
.set_single_qubit_gate_time(gate, qubit, gate_time)
}
pub fn set_two_qubit_gate_time(
&mut self,
gate: &str,
control: usize,
target: usize,
gate_time: f64,
) -> Result<(), RoqoqoError> {
let row_control: i64 = (control / self.number_columns)
.try_into()
.expect("Qubit number too large");
let column_control: i64 = (control % self.number_columns)
.try_into()
.expect("Qubit number too large");
let row_target: i64 = (target / self.number_columns)
.try_into()
.expect("Qubit number too large");
let column_target: i64 = (target % self.number_columns)
.try_into()
.expect("Qubit number too large");
if ((row_control - row_target).abs() == 1 && column_control == column_target)
|| (row_control == row_target && (column_control - column_target).abs() == 1)
{
self.generic_device
.set_two_qubit_gate_time(gate, control, target, gate_time)
} else {
Err(RoqoqoError::GenericError{msg: format!("Two qubit gate between psotions ({row_control}, {column_control}, qubit: {control}) and ({row_target}, {column_target}, qubit:{target}) not possible on SquareLattice")})
}
}
pub fn set_three_qubit_gate_time(
&mut self,
gate: &str,
control_0: usize,
control_1: usize,
target: usize,
gate_time: f64,
) -> Result<(), RoqoqoError> {
self.generic_device
.set_three_qubit_gate_time(gate, control_0, control_1, target, gate_time)
}
pub fn set_multi_qubit_gate_time(
&mut self,
gate: &str,
qubits: Vec<usize>,
gate_time: f64,
) -> Result<(), RoqoqoError> {
self.generic_device
.set_multi_qubit_gate_time(gate, qubits, gate_time)
}
pub fn set_all_qubit_decoherence_rates(
mut self,
rates: Array2<f64>,
) -> Result<Self, RoqoqoError> {
let number_qubits = <Self as Device>::number_qubits(&self);
let shape = rates.shape();
if shape == [3, 3] {
for qubit in 0..number_qubits {
self.generic_device
.set_qubit_decoherence_rates(qubit, rates.clone())?;
}
Ok(self)
} else {
Err(RoqoqoError::GenericError {
msg: "The input parameter `rates` needs to be a (3x3)-matrix.".to_string(),
})
}
}
pub fn set_qubit_decoherence_rates(
&mut self,
qubit: usize,
rates: Array2<f64>,
) -> Result<(), RoqoqoError> {
self.generic_device
.set_qubit_decoherence_rates(qubit, rates)
}
pub fn add_damping(&mut self, qubit: usize, damping: f64) -> Result<(), RoqoqoError> {
self.generic_device.add_damping(qubit, damping)
}
pub fn add_dephasing(&mut self, qubit: usize, dephasing: f64) -> Result<(), RoqoqoError> {
self.generic_device.add_dephasing(qubit, dephasing)
}
pub fn add_depolarising(&mut self, qubit: usize, depolarising: f64) -> Result<(), RoqoqoError> {
self.generic_device.add_depolarising(qubit, depolarising)
}
pub fn add_damping_all(mut self, damping: f64) -> Self {
let number_qubits = <Self as Device>::number_qubits(&self);
for qubit in 0..number_qubits {
self.generic_device
.add_damping(qubit, damping)
.expect("Checked insertion fails");
}
self
}
pub fn add_dephasing_all(mut self, dephasing: f64) -> Self {
let number_qubits = <Self as Device>::number_qubits(&self);
for qubit in 0..number_qubits {
self.generic_device
.add_dephasing(qubit, dephasing)
.expect("Checked insertion fails");
}
self
}
pub fn add_depolarising_all(mut self, depolarising: f64) -> Self {
let number_qubits = <Self as Device>::number_qubits(&self);
for qubit in 0..number_qubits {
self.generic_device
.add_depolarising(qubit, depolarising)
.expect("Checked insertion fails");
}
self
}
}
impl Device for SquareLatticeDevice {
fn number_qubits(&self) -> usize {
self.generic_device.number_qubits
}
fn single_qubit_gate_time(&self, hqslang: &str, qubit: &usize) -> Option<f64> {
self.generic_device.single_qubit_gate_time(hqslang, qubit)
}
fn two_qubit_gate_time(&self, hqslang: &str, control: &usize, target: &usize) -> Option<f64> {
self.generic_device
.two_qubit_gate_time(hqslang, control, target)
}
fn three_qubit_gate_time(
&self,
hqslang: &str,
control_0: &usize,
control_1: &usize,
target: &usize,
) -> Option<f64> {
self.generic_device
.three_qubit_gate_time(hqslang, control_0, control_1, target)
}
fn multi_qubit_gate_time(&self, hqslang: &str, qubits: &[usize]) -> Option<f64> {
self.generic_device.multi_qubit_gate_time(hqslang, qubits)
}
fn qubit_decoherence_rates(&self, qubit: &usize) -> Option<Array2<f64>> {
self.generic_device.qubit_decoherence_rates(qubit)
}
fn to_generic_device(&self) -> GenericDevice {
self.generic_device.clone()
}
fn two_qubit_edges(&self) -> Vec<(usize, usize)> {
let mut vector: Vec<(usize, usize)> = Vec::new();
for row in 0..self.number_rows {
for column in 0..self.number_columns - 1 {
vector.push((
row * self.number_columns + column,
row * self.number_columns + column + 1,
));
}
}
for row in 0..self.number_rows - 1 {
for column in 0..self.number_columns {
vector.push((
row * self.number_columns + column,
(row + 1) * self.number_columns + column,
));
}
}
vector
}
fn single_qubit_gate_names(&self) -> Vec<String> {
self.generic_device
.single_qubit_gates
.keys()
.cloned()
.collect()
}
fn two_qubit_gate_names(&self) -> Vec<String> {
self.generic_device
.two_qubit_gates
.keys()
.cloned()
.collect()
}
fn multi_qubit_gate_names(&self) -> Vec<String> {
self.generic_device
.multi_qubit_gates
.keys()
.cloned()
.collect()
}
}
impl crate::operations::SupportedVersion for SquareLatticeDevice {}