use crate::compile::CompilerError;
use crate::device::{Layout, LogicalQubit, PhysicalQubit};
use std::collections::{BTreeMap, HashMap};
#[derive(Debug, Clone)]
pub(crate) struct DenseRoutingLayout {
logical_qubits: Vec<LogicalQubit>,
logical_indices: HashMap<LogicalQubit, usize>,
logical_to_physical: Vec<usize>,
physical_to_logical: Vec<Option<usize>>,
}
impl DenseRoutingLayout {
pub(crate) fn from_layout(
layout: &Layout,
physical_qubits: &[PhysicalQubit],
) -> Result<Self, CompilerError> {
let logical_qubits = layout.logical_qubits().collect::<Vec<_>>();
let logical_indices = logical_qubits
.iter()
.copied()
.enumerate()
.map(|(index, logical)| (logical, index))
.collect::<HashMap<_, _>>();
let physical_indices = physical_qubits
.iter()
.copied()
.enumerate()
.map(|(index, physical)| (physical, index))
.collect::<HashMap<_, _>>();
let mut logical_to_physical = vec![usize::MAX; logical_qubits.len()];
let mut physical_to_logical = vec![None; physical_qubits.len()];
for (logical_index, logical) in logical_qubits.iter().copied().enumerate() {
let physical = layout.get_physical(logical).ok_or_else(|| {
CompilerError::InvariantViolation(format!(
"sabre layout does not map logical qubit {logical}"
))
})?;
let physical_index = *physical_indices.get(&physical).ok_or_else(|| {
CompilerError::InvariantViolation(format!(
"sabre layout maps logical qubit {logical} outside the routing target"
))
})?;
if physical_to_logical[physical_index]
.replace(logical_index)
.is_some()
{
return Err(CompilerError::InvariantViolation(format!(
"sabre layout maps multiple logical qubits to physical qubit {physical}"
)));
}
logical_to_physical[logical_index] = physical_index;
}
Ok(Self {
logical_qubits,
logical_indices,
logical_to_physical,
physical_to_logical,
})
}
#[inline]
pub(crate) fn physical_index(&self, logical: LogicalQubit) -> Result<usize, CompilerError> {
let logical_index = self.logical_indices.get(&logical).copied().ok_or_else(|| {
CompilerError::InvariantViolation(format!(
"sabre dense layout does not contain logical qubit {logical}"
))
})?;
Ok(self.logical_to_physical[logical_index])
}
#[inline]
pub(crate) fn swap_physical_indices(&mut self, left: usize, right: usize) {
if left == right {
return;
}
let left_logical = self.physical_to_logical[left];
let right_logical = self.physical_to_logical[right];
self.physical_to_logical.swap(left, right);
if let Some(logical) = left_logical {
self.logical_to_physical[logical] = right;
}
if let Some(logical) = right_logical {
self.logical_to_physical[logical] = left;
}
}
pub(crate) fn to_layout(
&self,
physical_qubits: &[PhysicalQubit],
) -> Result<Layout, CompilerError> {
let mapping = self
.logical_qubits
.iter()
.copied()
.enumerate()
.map(|(logical_index, logical)| {
(
logical,
physical_qubits[self.logical_to_physical[logical_index]],
)
})
.collect::<BTreeMap<_, _>>();
Layout::new(
self.logical_qubits.clone(),
physical_qubits.to_vec(),
Some(mapping),
)
.map_err(|error| {
CompilerError::InvariantViolation(format!(
"failed to rebuild SABRE layout from dense routing state: {error}"
))
})
}
pub(crate) fn signature(&self) -> &[Option<usize>] {
&self.physical_to_logical
}
}