use core::{error, fmt};
use alloc::{vec, vec::Vec};
use num_complex::Complex64;
use super::gate::Gate;
const MAX_QUBITS: u8 = 32;
#[derive(Debug)]
pub enum QubitError {
IndexOutOfBounds,
DuplicatedIndex,
}
impl fmt::Display for QubitError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
QubitError::IndexOutOfBounds => write!(f, "Index is out of bounds"),
QubitError::DuplicatedIndex => write!(f, "Duplicated index"),
}
}
}
impl error::Error for QubitError {}
pub trait QubitIndices: IntoIterator<Item = u8> {
type Iter: ExactSizeIterator<Item = u8>;
fn into_count_iter(self) -> (usize, Self::Iter);
}
impl<T> QubitIndices for T
where
T: IntoIterator<Item = u8>,
T::IntoIter: ExactSizeIterator,
{
type Iter = T::IntoIter;
fn into_count_iter(self) -> (usize, Self::Iter) {
let iter = self.into_iter();
let count = iter.len();
(count, iter)
}
}
#[derive(Debug, Clone)]
#[cfg_attr(test, derive(PartialEq))]
struct MappedGate {
gate: Gate,
state_map: Vec<usize>,
qubits_mask: usize,
}
impl MappedGate {
fn calc_local_bit_pos(input_index: usize, qubit_count: usize, n_controlled: usize) -> usize {
if input_index < n_controlled {
qubit_count - input_index - 1
} else {
input_index - n_controlled
}
}
fn new<I: QubitIndices>(
gate: Gate,
qubit_indices: I,
max_qubits: Option<u8>,
) -> Result<Self, QubitError> {
let (qubit_count, qubit_iter) = qubit_indices.into_count_iter();
let mut state_map = vec![0; 1 << qubit_count];
let mut qubits_mask = 0;
let n_controlled = gate.count_controlled() as usize;
for (input_index, qubit_index) in qubit_iter.enumerate() {
let local_bit_pos = Self::calc_local_bit_pos(input_index, qubit_count, n_controlled);
if let Some(max_qubits) = max_qubits {
if qubit_index >= max_qubits {
return Err(QubitError::IndexOutOfBounds);
}
}
let qubit_mask = 1 << qubit_index;
if qubits_mask & qubit_mask != 0 {
return Err(QubitError::DuplicatedIndex);
}
qubits_mask |= qubit_mask;
for (i, inner_index) in state_map.iter_mut().enumerate() {
if (i & (1 << local_bit_pos)) != 0 {
*inner_index |= qubit_mask;
}
}
}
Ok(Self {
gate,
state_map,
qubits_mask,
})
}
fn apply(&self, state: &mut [Complex64]) {
let mut substate = vec![Complex64::ZERO; self.state_map.len()];
let mut outer_index = 0;
for _ in 0..state.len() / substate.len() {
for (i, inner_index) in self.state_map.iter().enumerate() {
substate[i] = state[outer_index | inner_index];
}
self.gate.apply(&mut substate);
for (i, inner_index) in self.state_map.iter().enumerate() {
state[outer_index | inner_index] = substate[i];
}
outer_index = ((outer_index | self.qubits_mask) + 1) & !self.qubits_mask;
}
}
}
#[derive(Debug, Clone)]
#[cfg_attr(test, derive(PartialEq))]
pub struct Circuit {
qubit_count: Option<u8>,
gates: Vec<MappedGate>,
}
impl Circuit {
pub fn new(qubit_count: u8) -> Self {
assert!(
qubit_count <= MAX_QUBITS,
"Circuit can't have more than {MAX_QUBITS} qubits",
);
Self {
qubit_count: Some(qubit_count),
gates: Vec::new(),
}
}
pub fn add_gate<I: QubitIndices>(
&mut self,
gate: Gate,
qubit_indices: I,
) -> Result<(), QubitError> {
self.gates
.push(MappedGate::new(gate, qubit_indices, self.qubit_count)?);
Ok(())
}
pub fn from_gate<I: QubitIndices>(gate: Gate, qubit_indices: I) -> Result<Self, QubitError> {
Ok(Self {
qubit_count: None,
gates: vec![MappedGate::new(gate, qubit_indices, None)?],
})
}
pub fn into_gate(self) -> Gate {
Gate::circuit(self)
}
pub fn inverse(&self) -> Self {
let inverted_gates = self
.gates
.iter()
.rev()
.map(|mapped_gate| MappedGate {
gate: mapped_gate.gate.inverse(),
state_map: mapped_gate.state_map.clone(),
qubits_mask: mapped_gate.qubits_mask,
})
.collect();
Self {
qubit_count: self.qubit_count,
gates: inverted_gates,
}
}
pub fn apply(&self, state: &mut [Complex64]) {
for gate in &self.gates {
gate.apply(state)
}
}
}