|
|
|
|
|
|
|
|
|
|
| use serde::{Deserialize, Serialize};
|
| use thiserror::Error;
|
|
|
|
|
| #[derive(Error, Debug, Clone, PartialEq, Eq)]
|
| pub enum CircuitError {
|
|
|
| #[error("qubit index {0} out of bounds (circuit has {1} qubits)")]
|
| QubitOutOfBounds(usize, usize),
|
|
|
|
|
| #[error("duplicate measurement on qubit {0}")]
|
| DuplicateMeasurement(usize),
|
|
|
|
|
| #[error("circuit is empty")]
|
| EmptyCircuit,
|
| }
|
|
|
|
|
| #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
| pub struct Qubit(pub usize);
|
|
|
|
|
| #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
| pub enum SingleGate {
|
|
|
| PauliX,
|
|
|
| PauliY,
|
|
|
| PauliZ,
|
|
|
| Hadamard,
|
|
|
| TGate,
|
|
|
| SGate,
|
| }
|
|
|
|
|
| #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
| pub enum DoubleGate {
|
|
|
| CNOT,
|
|
|
| CZ,
|
|
|
| SWAP,
|
| }
|
|
|
|
|
| #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
| pub enum Gate {
|
|
|
| Single {
|
|
|
| gate: SingleGate,
|
|
|
| target: Qubit,
|
| },
|
|
|
| Double {
|
|
|
| gate: DoubleGate,
|
|
|
| control: Qubit,
|
|
|
| target: Qubit,
|
| },
|
|
|
| Rotation {
|
|
|
| target: Qubit,
|
|
|
| angle: f64,
|
| },
|
| }
|
|
|
|
|
| #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
| pub struct Measurement {
|
|
|
| pub qubit: Qubit,
|
|
|
| pub classical_bit: usize,
|
| }
|
|
|
|
|
| #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
| pub struct Circuit {
|
|
|
| pub num_qubits: usize,
|
|
|
| pub num_classical_bits: usize,
|
|
|
| pub gates: Vec<Gate>,
|
|
|
| pub measurements: Vec<Measurement>,
|
| }
|
|
|
| impl Circuit {
|
|
|
| pub fn new(num_qubits: usize, num_classical_bits: usize) -> Self {
|
| Self {
|
| num_qubits,
|
| num_classical_bits,
|
| gates: Vec::new(),
|
| measurements: Vec::new(),
|
| }
|
| }
|
|
|
|
|
| pub fn add_gate(&mut self, gate: Gate) -> Result<(), CircuitError> {
|
| match &gate {
|
| Gate::Single { target, .. } => {
|
| if target.0 >= self.num_qubits {
|
| return Err(CircuitError::QubitOutOfBounds(target.0, self.num_qubits));
|
| }
|
| }
|
| Gate::Double { control, target, .. } => {
|
| if control.0 >= self.num_qubits {
|
| return Err(CircuitError::QubitOutOfBounds(control.0, self.num_qubits));
|
| }
|
| if target.0 >= self.num_qubits {
|
| return Err(CircuitError::QubitOutOfBounds(target.0, self.num_qubits));
|
| }
|
| }
|
| Gate::Rotation { target, .. } => {
|
| if target.0 >= self.num_qubits {
|
| return Err(CircuitError::QubitOutOfBounds(target.0, self.num_qubits));
|
| }
|
| }
|
| }
|
| self.gates.push(gate);
|
| Ok(())
|
| }
|
|
|
|
|
| pub fn add_measurement(&mut self, qubit: Qubit, classical_bit: usize) -> Result<(), CircuitError> {
|
| if qubit.0 >= self.num_qubits {
|
| return Err(CircuitError::QubitOutOfBounds(qubit.0, self.num_qubits));
|
| }
|
| if self.measurements.iter().any(|m| m.qubit == qubit) {
|
| return Err(CircuitError::DuplicateMeasurement(qubit.0));
|
| }
|
| self.measurements.push(Measurement { qubit, classical_bit });
|
| Ok(())
|
| }
|
|
|
|
|
| pub fn depth(&self) -> usize {
|
| self.gates.len()
|
| }
|
|
|
|
|
| pub fn validate(&self) -> Result<(), CircuitError> {
|
| if self.gates.is_empty() && self.measurements.is_empty() {
|
| return Err(CircuitError::EmptyCircuit);
|
| }
|
| Ok(())
|
| }
|
| }
|
|
|
|
|
| pub trait Pass {
|
|
|
| type Input;
|
|
|
| type Output;
|
|
|
|
|
| fn name(&self) -> &'static str;
|
|
|
|
|
| fn run(&self, input: Self::Input) -> Result<Self::Output, CircuitError>;
|
| }
|
|
|
|
|