diff options
Diffstat (limited to 'src/core/circuit.rs')
| -rw-r--r-- | src/core/circuit.rs | 477 |
1 files changed, 0 insertions, 477 deletions
diff --git a/src/core/circuit.rs b/src/core/circuit.rs deleted file mode 100644 index 6647f58..0000000 --- a/src/core/circuit.rs +++ /dev/null @@ -1,477 +0,0 @@ -use super::{CustomGate, QuantumState, Runtime, RuntimeConfig}; -use crate::{format_amplitude, format_probability, Vector}; -use core::fmt; -use std::sync::Arc; - -#[derive(Clone)] -pub enum GateOp { - H(usize), - X(usize), - Y(usize), - Z(usize), - S(usize), - T(usize), - Sdg(usize), - Tdg(usize), - Sx(usize), - Sxdg(usize), - Rx(usize, f64), - Ry(usize, f64), - Rz(usize, f64), - P(usize, f64), - U1(usize, f64), - U2(usize, f64, f64), - U3(usize, f64, f64, f64), - CNOT(usize, usize), - CZ(usize, usize), - SWAP(usize, usize), - CRx(usize, usize, f64), - CRy(usize, usize, f64), - CRz(usize, usize, f64), - CP(usize, usize, f64), - CCNOT(usize, usize, usize), - CSWAP(usize, usize, usize), - Measure(usize, usize), - Custom(Arc<CustomGate>, Vec<usize>), -} - -impl GateOp { - pub fn name(&self) -> &str { - match self { - GateOp::H(_) => "H", - GateOp::X(_) => "X", - GateOp::Y(_) => "Y", - GateOp::Z(_) => "Z", - GateOp::S(_) => "S", - GateOp::T(_) => "T", - GateOp::Sdg(_) => "S†", - GateOp::Tdg(_) => "T†", - GateOp::Sx(_) => "√X", - GateOp::Sxdg(_) => "√X†", - GateOp::Rx(_, _) => "Rx", - GateOp::Ry(_, _) => "Ry", - GateOp::Rz(_, _) => "Rz", - GateOp::P(_, _) => "P", - GateOp::U1(_, _) => "U1", - GateOp::U2(_, _, _) => "U2", - GateOp::U3(_, _, _, _) => "U3", - GateOp::CRx(_, _, _) => "CRx", - GateOp::CRy(_, _, _) => "CRy", - GateOp::CRz(_, _, _) => "CRz", - GateOp::CP(_, _, _) => "CP", - GateOp::CNOT(_, _) => "CNOT", - GateOp::CZ(_, _) => "CZ", - GateOp::SWAP(_, _) => "SWAP", - GateOp::CCNOT(_, _, _) => "CCNOT", - GateOp::CSWAP(_, _, _) => "CSWAP", - GateOp::Measure(_, _) => "M", - GateOp::Custom(gate, _) => &gate.name, - } - } - - pub fn quantum_targets(&self) -> Vec<usize> { - match self { - GateOp::H(t) - | GateOp::X(t) - | GateOp::Y(t) - | GateOp::Z(t) - | GateOp::S(t) - | GateOp::T(t) - | GateOp::Sdg(t) - | GateOp::Tdg(t) - | GateOp::Sx(t) - | GateOp::Sxdg(t) - | GateOp::Rx(t, _) - | GateOp::Ry(t, _) - | GateOp::Rz(t, _) - | GateOp::P(t, _) - | GateOp::U1(t, _) - | GateOp::U2(t, _, _) - | GateOp::U3(t, _, _, _) => vec![*t], - GateOp::CNOT(c, t) - | GateOp::CZ(c, t) - | GateOp::SWAP(c, t) - | GateOp::CRx(c, t, _) - | GateOp::CRy(c, t, _) - | GateOp::CRz(c, t, _) - | GateOp::CP(c, t, _) => vec![*c, *t], - GateOp::CCNOT(c1, c2, t) | GateOp::CSWAP(c1, c2, t) => vec![*c1, *c2, *t], - GateOp::Measure(q, _) => vec![*q], - GateOp::Custom(_, targets) => targets.clone(), - } - } - - pub fn classical_targets(&self) -> Vec<usize> { - match self { - GateOp::Measure(_, c) => vec![*c], - _ => vec![], - } - } - - pub fn is_measurement(&self) -> bool { - matches!(self, GateOp::Measure(_, _)) - } - - pub fn is_custom(&self) -> bool { - matches!(self, GateOp::Custom(_, _)) - } - - pub fn is_non_clifford(&self) -> bool { - matches!( - self, - GateOp::T(_) - | GateOp::Tdg(_) - | GateOp::Sx(_) - | GateOp::Sxdg(_) - | GateOp::Rx(_, _) - | GateOp::Ry(_, _) - | GateOp::Rz(_, _) - | GateOp::P(_, _) - | GateOp::U1(_, _) - | GateOp::U2(_, _, _) - | GateOp::U3(_, _, _, _) - | GateOp::CRx(_, _, _) - | GateOp::CRy(_, _, _) - | GateOp::CRz(_, _, _) - | GateOp::CP(_, _, _) - ) - } -} - -pub struct QuantumCircuit { - num_qubits: usize, - num_classical: usize, - operations: Vec<GateOp>, - computed_state: Option<QuantumState>, -} - -impl QuantumCircuit { - pub fn new(num_qubits: usize) -> QuantumCircuit { - QuantumCircuit { - num_qubits, - num_classical: 0, - operations: Vec::new(), - computed_state: None, - } - } - - pub fn with_classical(num_qubits: usize, num_classical: usize) -> QuantumCircuit { - QuantumCircuit { - num_qubits, - num_classical, - operations: Vec::new(), - computed_state: None, - } - } - - pub fn num_qubits(&self) -> usize { - self.num_qubits - } - - pub fn num_classical(&self) -> usize { - self.num_classical - } - - pub fn operations(&self) -> &[GateOp] { - &self.operations - } - - pub fn is_computed(&self) -> bool { - self.computed_state.is_some() - } - - pub fn compute(&mut self) -> &QuantumState { - self.compute_with(Runtime::default()) - } - - pub fn compute_with(&mut self, runtime: Runtime) -> &QuantumState { - if self.computed_state.is_none() { - self.computed_state = Some(runtime.compute(self.num_qubits, &self.operations)); - } - self.computed_state.as_ref().unwrap() - } - - pub fn compute_with_config(&mut self, config: RuntimeConfig) -> &QuantumState { - if self.computed_state.is_none() { - self.computed_state = Some(config.compute(self.num_qubits, &self.operations)); - } - self.computed_state.as_ref().unwrap() - } - - pub fn state(&mut self) -> &QuantumState { - self.compute() - } - - pub fn state_with(&mut self, runtime: Runtime) -> &QuantumState { - self.compute_with(runtime) - } - - pub fn state_with_config(&mut self, config: RuntimeConfig) -> &QuantumState { - self.compute_with_config(config) - } - - pub fn h(&mut self, target: usize) -> &mut Self { - self.operations.push(GateOp::H(target)); - self.computed_state = None; - self - } - - pub fn x(&mut self, target: usize) -> &mut Self { - self.operations.push(GateOp::X(target)); - self.computed_state = None; - self - } - - pub fn y(&mut self, target: usize) -> &mut Self { - self.operations.push(GateOp::Y(target)); - self.computed_state = None; - self - } - - pub fn z(&mut self, target: usize) -> &mut Self { - self.operations.push(GateOp::Z(target)); - self.computed_state = None; - self - } - - pub fn s(&mut self, target: usize) -> &mut Self { - self.operations.push(GateOp::S(target)); - self.computed_state = None; - self - } - - pub fn t(&mut self, target: usize) -> &mut Self { - self.operations.push(GateOp::T(target)); - self.computed_state = None; - self - } - - pub fn sdg(&mut self, target: usize) -> &mut Self { - self.operations.push(GateOp::Sdg(target)); - self.computed_state = None; - self - } - - pub fn tdg(&mut self, target: usize) -> &mut Self { - self.operations.push(GateOp::Tdg(target)); - self.computed_state = None; - self - } - - pub fn sx(&mut self, target: usize) -> &mut Self { - self.operations.push(GateOp::Sx(target)); - self.computed_state = None; - self - } - - pub fn sxdg(&mut self, target: usize) -> &mut Self { - self.operations.push(GateOp::Sxdg(target)); - self.computed_state = None; - self - } - - pub fn rx(&mut self, target: usize, theta: f64) -> &mut Self { - self.operations.push(GateOp::Rx(target, theta)); - self.computed_state = None; - self - } - - pub fn ry(&mut self, target: usize, theta: f64) -> &mut Self { - self.operations.push(GateOp::Ry(target, theta)); - self.computed_state = None; - self - } - - pub fn rz(&mut self, target: usize, theta: f64) -> &mut Self { - self.operations.push(GateOp::Rz(target, theta)); - self.computed_state = None; - self - } - - pub fn p(&mut self, target: usize, theta: f64) -> &mut Self { - self.operations.push(GateOp::P(target, theta)); - self.computed_state = None; - self - } - - pub fn u1(&mut self, target: usize, lambda: f64) -> &mut Self { - self.operations.push(GateOp::U1(target, lambda)); - self.computed_state = None; - self - } - - pub fn u2(&mut self, target: usize, phi: f64, lambda: f64) -> &mut Self { - self.operations.push(GateOp::U2(target, phi, lambda)); - self.computed_state = None; - self - } - - pub fn u3(&mut self, target: usize, theta: f64, phi: f64, lambda: f64) -> &mut Self { - self.operations.push(GateOp::U3(target, theta, phi, lambda)); - self.computed_state = None; - self - } - - pub fn crx(&mut self, control: usize, target: usize, theta: f64) -> &mut Self { - self.operations.push(GateOp::CRx(control, target, theta)); - self.computed_state = None; - self - } - - pub fn cry(&mut self, control: usize, target: usize, theta: f64) -> &mut Self { - self.operations.push(GateOp::CRy(control, target, theta)); - self.computed_state = None; - self - } - - pub fn crz(&mut self, control: usize, target: usize, theta: f64) -> &mut Self { - self.operations.push(GateOp::CRz(control, target, theta)); - self.computed_state = None; - self - } - - pub fn cp(&mut self, control: usize, target: usize, theta: f64) -> &mut Self { - self.operations.push(GateOp::CP(control, target, theta)); - self.computed_state = None; - self - } - - pub fn cnot(&mut self, control: usize, target: usize) -> &mut Self { - self.operations.push(GateOp::CNOT(control, target)); - self.computed_state = None; - self - } - - pub fn cx(&mut self, control: usize, target: usize) -> &mut Self { - self.cnot(control, target) - } - - pub fn cz(&mut self, control: usize, target: usize) -> &mut Self { - self.operations.push(GateOp::CZ(control, target)); - self.computed_state = None; - self - } - - pub fn swap(&mut self, qubit1: usize, qubit2: usize) -> &mut Self { - self.operations.push(GateOp::SWAP(qubit1, qubit2)); - self.computed_state = None; - self - } - - pub fn ccnot(&mut self, control1: usize, control2: usize, target: usize) -> &mut Self { - self.operations - .push(GateOp::CCNOT(control1, control2, target)); - self.computed_state = None; - self - } - - pub fn toffoli(&mut self, control1: usize, control2: usize, target: usize) -> &mut Self { - self.ccnot(control1, control2, target) - } - - pub fn cswap(&mut self, control: usize, target1: usize, target2: usize) -> &mut Self { - self.operations - .push(GateOp::CSWAP(control, target1, target2)); - self.computed_state = None; - self - } - - pub fn fredkin(&mut self, control: usize, target1: usize, target2: usize) -> &mut Self { - self.cswap(control, target1, target2) - } - - pub fn measure(&mut self, qubit: usize, classical: usize) -> &mut Self { - if classical >= self.num_classical { - self.num_classical = classical + 1; - } - self.operations.push(GateOp::Measure(qubit, classical)); - self - } - - pub fn measure_all(&mut self) -> &mut Self { - for i in 0..self.num_qubits { - self.measure(i, i); - } - self - } - - pub fn custom(&mut self, gate: &Arc<CustomGate>, targets: &[usize]) -> &mut Self { - self.operations - .push(GateOp::Custom(Arc::clone(gate), targets.to_vec())); - self.computed_state = None; - self - } - - pub fn apply_custom(&mut self, gate: CustomGate, targets: &[usize]) -> &mut Self { - self.operations - .push(GateOp::Custom(Arc::new(gate), targets.to_vec())); - self.computed_state = None; - self - } - - pub fn reset(&mut self) -> &mut Self { - self.operations.clear(); - self.computed_state = None; - self - } - - pub fn probability(&mut self, state_index: usize) -> f64 { - self.compute(); - let state = self.computed_state.as_ref().unwrap(); - let amp = state.get(state_index); - amp.norm2() - } - - pub fn probabilities(&mut self) -> Vec<f64> { - self.compute(); - let n = 1 << self.num_qubits; - let state = self.computed_state.as_ref().unwrap(); - (0..n).map(|i| state.get(i).norm2()).collect() - } - - pub fn print_probabilities(&mut self) { - let probs = self.probabilities(); - let n = self.num_qubits; - println!("Probabilities:"); - for (i, p) in probs.iter().enumerate() { - if *p > 1e-10 { - let basis: String = format!("{:0width$b}", i, width = n); - println!(" |{}⟩: {}", basis, format_probability(*p)); - } - } - } -} - -impl fmt::Display for QuantumCircuit { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - writeln!( - f, - "QuantumCircuit ({} qubits, {} classical)", - self.num_qubits, self.num_classical - )?; - writeln!(f, "Operations:")?; - for (i, op) in self.operations.iter().enumerate() { - match op { - GateOp::Measure(q, c) => writeln!(f, " {}: {} q{} → c{}", i, op.name(), q, c)?, - GateOp::Custom(gate, targets) => { - writeln!(f, " {}: [{}] on {:?}", i, gate.name, targets)? - } - _ => writeln!(f, " {}: {} on {:?}", i, op.name(), op.quantum_targets())?, - } - } - if let Some(state) = &self.computed_state { - writeln!(f, "State:")?; - let n = 1 << self.num_qubits; - for i in 0..n { - let amp = state.get(i); - if amp.real.abs() > 1e-10 || amp.imaginary.abs() > 1e-10 { - let basis: String = format!("{:0width$b}", i, width = self.num_qubits); - writeln!(f, " |{}⟩: {}", basis, format_amplitude(&))?; - } - } - } else { - writeln!(f, "State: (not computed)")?; - } - Ok(()) - } -} |
