From c0405cc8a81e6197df976d3135db413b6c74ba90 Mon Sep 17 00:00:00 2001 From: hachem Date: Sun, 13 Sep 2026 07:48:33 +0200 Subject: chore: remove replaced rust sources --- src/core/classical_components.rs | 63 ----- src/core/custom_gate.rs | 245 ----------------- src/core/gates.rs | 253 ------------------ src/core/mod.rs | 17 -- src/core/noise.rs | 559 --------------------------------------- src/core/quantum_components.rs | 318 ---------------------- src/lib.rs | 21 -- src/maths/mod.rs | 14 - src/visualizer/horizontal_cli.rs | 463 -------------------------------- src/visualizer/mod.rs | 7 - src/visualizer/renderer.rs | 3 - src/visualizer/vertical_cli.rs | 367 ------------------------- 12 files changed, 2330 deletions(-) delete mode 100644 src/core/classical_components.rs delete mode 100644 src/core/custom_gate.rs delete mode 100644 src/core/gates.rs delete mode 100644 src/core/mod.rs delete mode 100644 src/core/noise.rs delete mode 100644 src/core/quantum_components.rs delete mode 100644 src/lib.rs delete mode 100644 src/maths/mod.rs delete mode 100644 src/visualizer/horizontal_cli.rs delete mode 100644 src/visualizer/mod.rs delete mode 100644 src/visualizer/renderer.rs delete mode 100644 src/visualizer/vertical_cli.rs (limited to 'src') diff --git a/src/core/classical_components.rs b/src/core/classical_components.rs deleted file mode 100644 index b2018d4..0000000 --- a/src/core/classical_components.rs +++ /dev/null @@ -1,63 +0,0 @@ -use core::ops; - -#[derive(Clone, Copy)] -pub struct ClassicalBit<'a> { - state: bool, - name: &'a str, -} - -#[derive(Clone)] -pub struct ClassicalRegister<'a> { - bits: Vec>, - name: &'a str, -} - -impl<'a> ClassicalBit<'a> { - pub fn new(name: &'a str, state: bool) -> ClassicalBit<'a> { - ClassicalBit { name, state } - } - - pub fn get_name(&self) -> &'a str { - self.name - } - - pub fn get_state(&self) -> bool { - self.state - } -} - -impl<'a> ClassicalRegister<'a> { - pub fn new(name: &'a str, names: &'a [&'a str]) -> ClassicalRegister<'a> { - let mut bits: Vec> = Vec::new(); - for &name in names { - bits.push(ClassicalBit::new(name, false)); - } - ClassicalRegister { name, bits } - } - - pub fn set_bits(&mut self, bits: Vec>) { - self.bits = bits; - } - - pub fn get_bits(&self) -> Vec> { - self.bits.clone() - } - - pub fn get_name(&self) -> &'a str { - self.name - } -} - -impl<'a> ops::Index for ClassicalRegister<'a> { - type Output = ClassicalBit<'a>; - - fn index(&self, index: usize) -> &Self::Output { - &self.bits[index] - } -} - -impl<'a> ops::IndexMut for ClassicalRegister<'a> { - fn index_mut(&mut self, index: usize) -> &mut Self::Output { - &mut self.bits[index] - } -} diff --git a/src/core/custom_gate.rs b/src/core/custom_gate.rs deleted file mode 100644 index 51d3a56..0000000 --- a/src/core/custom_gate.rs +++ /dev/null @@ -1,245 +0,0 @@ -use crate::{Complex, Matrix, QuantumGate}; - -#[derive(Clone)] -pub enum CustomGateDefinition { - Matrix(Matrix>), - Composite(Vec<(CompositeOp, Vec)>), -} - -#[derive(Clone, Copy)] -pub enum CompositeOp { - H, - X, - Y, - Z, - S, - T, - CNOT, - CZ, - SWAP, - CCNOT, - CSWAP, -} - -#[derive(Clone)] -pub struct CustomGate { - pub name: String, - pub num_qubits: usize, - pub definition: CustomGateDefinition, -} - -impl CustomGate { - pub fn from_matrix(name: &str, matrix: Matrix>) -> Self { - let dim = matrix.rows; - let num_qubits = (dim as f64).log2() as usize; - assert_eq!( - 1 << num_qubits, - dim, - "Matrix dimension must be a power of 2" - ); - assert_eq!(matrix.rows, matrix.cols, "Matrix must be square"); - - CustomGate { - name: String::from(name), - num_qubits, - definition: CustomGateDefinition::Matrix(matrix), - } - } - - pub fn from_composite( - name: &str, - num_qubits: usize, - ops: Vec<(CompositeOp, Vec)>, - ) -> Self { - CustomGate { - name: String::from(name), - num_qubits, - definition: CustomGateDefinition::Composite(ops), - } - } - - pub fn to_quantum_gate(&self) -> QuantumGate<'static> { - match &self.definition { - CustomGateDefinition::Matrix(matrix) => { - let name: &'static str = Box::leak(self.name.clone().into_boxed_str()); - QuantumGate { - name, - matrix: matrix.clone(), - num_qubits: self.num_qubits, - } - } - CustomGateDefinition::Composite(ops) => { - let matrix = self.compute_composite_matrix(ops); - let name: &'static str = Box::leak(self.name.clone().into_boxed_str()); - QuantumGate { - name, - matrix, - num_qubits: self.num_qubits, - } - } - } - } - - fn compute_composite_matrix(&self, ops: &[(CompositeOp, Vec)]) -> Matrix> { - use crate::gates::*; - use crate::Complex; - - let dim = 1 << self.num_qubits; - let mut result = Matrix::new(dim, dim, vec![Complex::new(0.0, 0.0); dim * dim]); - for i in 0..dim { - result.data[i * dim + i] = Complex::new(1.0, 0.0); - } - - for (op, targets) in ops { - let gate: &QuantumGate = match op { - CompositeOp::H => &HADAMARD, - CompositeOp::X => &PAULI_X, - CompositeOp::Y => &PAULI_Y, - CompositeOp::Z => &PAULI_Z, - CompositeOp::S => &S_GATE, - CompositeOp::T => &T_GATE, - CompositeOp::CNOT => &CNOT, - CompositeOp::CZ => &CZ, - CompositeOp::SWAP => &SWAP, - CompositeOp::CCNOT => &TOFFOLI, - CompositeOp::CSWAP => &FREDKIN, - }; - - let full_gate = build_full_operator(&gate.matrix, targets, self.num_qubits); - result = matrix_multiply(&full_gate, &result); - } - - result - } -} - -fn build_full_operator( - gate_matrix: &Matrix>, - targets: &[usize], - total_qubits: usize, -) -> Matrix> { - let dim = 1 << total_qubits; - let gate_dim = gate_matrix.rows; - let num_gate_qubits = targets.len(); - - let mut result = Matrix::new(dim, dim, vec![Complex::new(0.0, 0.0); dim * dim]); - - for i in 0..dim { - for j in 0..dim { - let mut gate_i = 0usize; - let mut gate_j = 0usize; - let mut match_non_targets = true; - - for q in 0..total_qubits { - let bit_i = (i >> (total_qubits - 1 - q)) & 1; - let bit_j = (j >> (total_qubits - 1 - q)) & 1; - - if let Some(pos) = targets.iter().position(|&t| t == q) { - gate_i |= bit_i << (num_gate_qubits - 1 - pos); - gate_j |= bit_j << (num_gate_qubits - 1 - pos); - } else if bit_i != bit_j { - match_non_targets = false; - break; - } - } - - if match_non_targets { - result.data[i * dim + j] = gate_matrix.data[gate_i * gate_dim + gate_j]; - } - } - } - - result -} - -fn matrix_multiply(a: &Matrix>, b: &Matrix>) -> Matrix> { - let n = a.rows; - let mut result = Matrix::new(n, n, vec![Complex::new(0.0, 0.0); n * n]); - - for i in 0..n { - for j in 0..n { - let mut sum = Complex::new(0.0, 0.0); - for k in 0..n { - sum += a.data[i * n + k] * b.data[k * n + j]; - } - result.data[i * n + j] = sum; - } - } - - result -} - -pub struct CustomGateBuilder { - name: String, - num_qubits: usize, - ops: Vec<(CompositeOp, Vec)>, -} - -impl CustomGateBuilder { - pub fn new(name: &str, num_qubits: usize) -> Self { - CustomGateBuilder { - name: String::from(name), - num_qubits, - ops: Vec::new(), - } - } - - pub fn h(mut self, target: usize) -> Self { - self.ops.push((CompositeOp::H, vec![target])); - self - } - - pub fn x(mut self, target: usize) -> Self { - self.ops.push((CompositeOp::X, vec![target])); - self - } - - pub fn y(mut self, target: usize) -> Self { - self.ops.push((CompositeOp::Y, vec![target])); - self - } - - pub fn z(mut self, target: usize) -> Self { - self.ops.push((CompositeOp::Z, vec![target])); - self - } - - pub fn s(mut self, target: usize) -> Self { - self.ops.push((CompositeOp::S, vec![target])); - self - } - - pub fn t(mut self, target: usize) -> Self { - self.ops.push((CompositeOp::T, vec![target])); - self - } - - pub fn cnot(mut self, control: usize, target: usize) -> Self { - self.ops.push((CompositeOp::CNOT, vec![control, target])); - self - } - - pub fn cz(mut self, control: usize, target: usize) -> Self { - self.ops.push((CompositeOp::CZ, vec![control, target])); - self - } - - pub fn swap(mut self, a: usize, b: usize) -> Self { - self.ops.push((CompositeOp::SWAP, vec![a, b])); - self - } - - pub fn ccnot(mut self, c1: usize, c2: usize, target: usize) -> Self { - self.ops.push((CompositeOp::CCNOT, vec![c1, c2, target])); - self - } - - pub fn cswap(mut self, control: usize, t1: usize, t2: usize) -> Self { - self.ops.push((CompositeOp::CSWAP, vec![control, t1, t2])); - self - } - - pub fn build(self) -> CustomGate { - CustomGate::from_composite(&self.name, self.num_qubits, self.ops) - } -} diff --git a/src/core/gates.rs b/src/core/gates.rs deleted file mode 100644 index cee4ebc..0000000 --- a/src/core/gates.rs +++ /dev/null @@ -1,253 +0,0 @@ -use crate::{complex, matrix, Complex, Matrix, QuantumGate}; -use std::f64::consts::FRAC_1_SQRT_2; - -pub fn rx_matrix(theta: f64) -> Matrix> { - let cos = (theta / 2.0).cos(); - let sin = (theta / 2.0).sin(); - matrix!( - [complex!(cos, 0.0), complex!(0.0, -sin)]; - [complex!(0.0, -sin), complex!(cos, 0.0)] - ) -} - -pub fn ry_matrix(theta: f64) -> Matrix> { - let cos = (theta / 2.0).cos(); - let sin = (theta / 2.0).sin(); - matrix!( - [complex!(cos, 0.0), complex!(-sin, 0.0)]; - [complex!(sin, 0.0), complex!(cos, 0.0)] - ) -} - -pub fn rz_matrix(theta: f64) -> Matrix> { - let half = theta / 2.0; - matrix!( - [complex!(half.cos(), -half.sin()), complex!(0.0, 0.0)]; - [complex!(0.0, 0.0), complex!(half.cos(), half.sin())] - ) -} - -pub fn p_matrix(theta: f64) -> Matrix> { - matrix!( - [complex!(1.0, 0.0), complex!(0.0, 0.0)]; - [complex!(0.0, 0.0), complex!(theta.cos(), theta.sin())] - ) -} - -pub fn u1_matrix(lambda: f64) -> Matrix> { - p_matrix(lambda) -} - -pub fn u2_matrix(phi: f64, lambda: f64) -> Matrix> { - let inv_sqrt2 = FRAC_1_SQRT_2; - matrix!( - [complex!(inv_sqrt2, 0.0), complex!(-inv_sqrt2 * lambda.cos(), -inv_sqrt2 * lambda.sin())]; - [complex!(inv_sqrt2 * phi.cos(), inv_sqrt2 * phi.sin()), complex!((phi + lambda).cos() * inv_sqrt2, (phi + lambda).sin() * inv_sqrt2)] - ) -} - -pub fn u3_matrix(theta: f64, phi: f64, lambda: f64) -> Matrix> { - let cos = (theta / 2.0).cos(); - let sin = (theta / 2.0).sin(); - matrix!( - [complex!(cos, 0.0), complex!(-sin * lambda.cos(), -sin * lambda.sin())]; - [complex!(sin * phi.cos(), sin * phi.sin()), complex!(cos * (phi + lambda).cos(), cos * (phi + lambda).sin())] - ) -} - -pub fn crx_matrix(theta: f64) -> Matrix> { - let cos = (theta / 2.0).cos(); - let sin = (theta / 2.0).sin(); - matrix!( - [complex!(1.0, 0.0), complex!(0.0, 0.0), complex!(0.0, 0.0), complex!(0.0, 0.0)]; - [complex!(0.0, 0.0), complex!(1.0, 0.0), complex!(0.0, 0.0), complex!(0.0, 0.0)]; - [complex!(0.0, 0.0), complex!(0.0, 0.0), complex!(cos, 0.0), complex!(0.0, -sin)]; - [complex!(0.0, 0.0), complex!(0.0, 0.0), complex!(0.0, -sin), complex!(cos, 0.0)] - ) -} - -pub fn cry_matrix(theta: f64) -> Matrix> { - let cos = (theta / 2.0).cos(); - let sin = (theta / 2.0).sin(); - matrix!( - [complex!(1.0, 0.0), complex!(0.0, 0.0), complex!(0.0, 0.0), complex!(0.0, 0.0)]; - [complex!(0.0, 0.0), complex!(1.0, 0.0), complex!(0.0, 0.0), complex!(0.0, 0.0)]; - [complex!(0.0, 0.0), complex!(0.0, 0.0), complex!(cos, 0.0), complex!(-sin, 0.0)]; - [complex!(0.0, 0.0), complex!(0.0, 0.0), complex!(sin, 0.0), complex!(cos, 0.0)] - ) -} - -pub fn crz_matrix(theta: f64) -> Matrix> { - let half = theta / 2.0; - matrix!( - [complex!(1.0, 0.0), complex!(0.0, 0.0), complex!(0.0, 0.0), complex!(0.0, 0.0)]; - [complex!(0.0, 0.0), complex!(1.0, 0.0), complex!(0.0, 0.0), complex!(0.0, 0.0)]; - [complex!(0.0, 0.0), complex!(0.0, 0.0), complex!(half.cos(), -half.sin()), complex!(0.0, 0.0)]; - [complex!(0.0, 0.0), complex!(0.0, 0.0), complex!(0.0, 0.0), complex!(half.cos(), half.sin())] - ) -} - -pub fn cp_matrix(theta: f64) -> Matrix> { - matrix!( - [complex!(1.0, 0.0), complex!(0.0, 0.0), complex!(0.0, 0.0), complex!(0.0, 0.0)]; - [complex!(0.0, 0.0), complex!(1.0, 0.0), complex!(0.0, 0.0), complex!(0.0, 0.0)]; - [complex!(0.0, 0.0), complex!(0.0, 0.0), complex!(1.0, 0.0), complex!(0.0, 0.0)]; - [complex!(0.0, 0.0), complex!(0.0, 0.0), complex!(0.0, 0.0), complex!(theta.cos(), theta.sin())] - ) -} - -#[rustfmt::skip] -lazy_static::lazy_static! { - pub static ref HADAMARD: QuantumGate<'static> = QuantumGate { - name: "H", - matrix: matrix!([complex!(1.0, 0.0), complex!( 1.0, 0.0)]; - [complex!(1.0, 0.0), complex!(-1.0, 0.0)]) * - complex!(1.0/2.0_f64.sqrt(), 0.0), - num_qubits: 1, - }; - - pub static ref PAULI_X: QuantumGate<'static> = QuantumGate { - name: "X", - matrix: matrix!([complex!(0.0, 0.0), complex!(1.0, 0.0)]; - [complex!(1.0, 0.0), complex!(0.0, 0.0)]), - num_qubits: 1, - }; - - pub static ref PAULI_Y: QuantumGate<'static> = QuantumGate { - name: "Y", - matrix: matrix!([complex!(0.0, 0.0), complex!(0.0, -1.0)]; - [complex!(0.0, 1.0), complex!(0.0, 0.0)]), - num_qubits: 1, - }; - - pub static ref PAULI_Z: QuantumGate<'static> = QuantumGate { - name: "Z", - matrix: matrix!([complex!(1.0, 0.0), complex!( 0.0, 0.0)]; - [complex!(0.0, 0.0), complex!(-1.0, 0.0)]), - num_qubits: 1, - }; - - pub static ref S_GATE: QuantumGate<'static> = QuantumGate { - name: "S", - matrix: matrix!([complex!(1.0, 0.0), complex!(0.0, 0.0)]; - [complex!(0.0, 0.0), complex!(0.0, 1.0)]), - num_qubits: 1, - }; - - pub static ref T_GATE: QuantumGate<'static> = QuantumGate { - name: "T", - matrix: matrix!([complex!(1.0, 0.0), complex!(0.0, 0.0)]; - [complex!(0.0, 0.0), complex!(core::f64::consts::FRAC_1_SQRT_2, core::f64::consts::FRAC_1_SQRT_2)]), - num_qubits: 1, - }; - - pub static ref SDG_GATE: QuantumGate<'static> = QuantumGate { - name: "S†", - matrix: matrix!([complex!(1.0, 0.0), complex!(0.0, 0.0)]; - [complex!(0.0, 0.0), complex!(0.0, -1.0)]), - num_qubits: 1, - }; - - pub static ref TDG_GATE: QuantumGate<'static> = QuantumGate { - name: "T†", - matrix: matrix!([complex!(1.0, 0.0), complex!(0.0, 0.0)]; - [complex!(0.0, 0.0), complex!(core::f64::consts::FRAC_1_SQRT_2, -core::f64::consts::FRAC_1_SQRT_2)]), - num_qubits: 1, - }; - - pub static ref SX_GATE: QuantumGate<'static> = QuantumGate { - name: "√X", - matrix: matrix!([complex!(0.5, 0.5), complex!(0.5, -0.5)]; - [complex!(0.5, -0.5), complex!(0.5, 0.5)]), - num_qubits: 1, - }; - - pub static ref SXDG_GATE: QuantumGate<'static> = QuantumGate { - name: "√X†", - matrix: matrix!([complex!(0.5, -0.5), complex!(0.5, 0.5)]; - [complex!(0.5, 0.5), complex!(0.5, -0.5)]), - num_qubits: 1, - }; - - pub static ref IDENTITY: QuantumGate<'static> = QuantumGate { - name: "I", - matrix: matrix!([complex!(1.0, 0.0), complex!(0.0, 0.0)]; - [complex!(0.0, 0.0), complex!(1.0, 0.0)]), - num_qubits: 1, - }; - - pub static ref CNOT: QuantumGate<'static> = QuantumGate { - name: "CNOT", - matrix: matrix!([complex!(1.0, 0.0), complex!(0.0, 0.0), complex!(0.0, 0.0), complex!(0.0, 0.0)]; - [complex!(0.0, 0.0), complex!(1.0, 0.0), complex!(0.0, 0.0), complex!(0.0, 0.0)]; - [complex!(0.0, 0.0), complex!(0.0, 0.0), complex!(0.0, 0.0), complex!(1.0, 0.0)]; - [complex!(0.0, 0.0), complex!(0.0, 0.0), complex!(1.0, 0.0), complex!(0.0, 0.0)]), - num_qubits: 2, - }; - - pub static ref CZ: QuantumGate<'static> = QuantumGate { - name: "CZ", - matrix: matrix!([complex!(1.0, 0.0), complex!(0.0, 0.0), complex!(0.0, 0.0), complex!( 0.0, 0.0)]; - [complex!(0.0, 0.0), complex!(1.0, 0.0), complex!(0.0, 0.0), complex!( 0.0, 0.0)]; - [complex!(0.0, 0.0), complex!(0.0, 0.0), complex!(1.0, 0.0), complex!( 0.0, 0.0)]; - [complex!(0.0, 0.0), complex!(0.0, 0.0), complex!(0.0, 0.0), complex!(-1.0, 0.0)]), - num_qubits: 2, - }; - - pub static ref SWAP: QuantumGate<'static> = QuantumGate { - name: "SWAP", - matrix: matrix!([complex!(1.0, 0.0), complex!(0.0, 0.0), complex!(0.0, 0.0), complex!(0.0, 0.0)]; - [complex!(0.0, 0.0), complex!(0.0, 0.0), complex!(1.0, 0.0), complex!(0.0, 0.0)]; - [complex!(0.0, 0.0), complex!(1.0, 0.0), complex!(0.0, 0.0), complex!(0.0, 0.0)]; - [complex!(0.0, 0.0), complex!(0.0, 0.0), complex!(0.0, 0.0), complex!(1.0, 0.0)]), - num_qubits: 2, - }; - - pub static ref ISWAP: QuantumGate<'static> = QuantumGate { - name: "iSWAP", - matrix: matrix!([complex!(1.0, 0.0), complex!(0.0, 0.0), complex!(0.0, 0.0), complex!(0.0, 0.0)]; - [complex!(0.0, 0.0), complex!(0.0, 0.0), complex!(0.0, 1.0), complex!(0.0, 0.0)]; - [complex!(0.0, 0.0), complex!(0.0, 1.0), complex!(0.0, 0.0), complex!(0.0, 0.0)]; - [complex!(0.0, 0.0), complex!(0.0, 0.0), complex!(0.0, 0.0), complex!(1.0, 0.0)]), - num_qubits: 2, - }; - - pub static ref SQRT_SWAP: QuantumGate<'static> = QuantumGate { - name: "√SWAP", - matrix: matrix!([complex!(1.0, 0.0), complex!(0.0, 0.0), complex!(0.0, 0.0), complex!(0.0, 0.0)]; - [complex!(0.0, 0.0), complex!(0.5, 0.5), complex!(0.5, -0.5), complex!(0.0, 0.0)]; - [complex!(0.0, 0.0), complex!(0.5, -0.5), complex!(0.5, 0.5), complex!(0.0, 0.0)]; - [complex!(0.0, 0.0), complex!(0.0, 0.0), complex!(0.0, 0.0), complex!(1.0, 0.0)]), - num_qubits: 2, - }; - - pub static ref TOFFOLI: QuantumGate<'static> = QuantumGate { - name: "CCNOT", - matrix: matrix!( - [complex!(1.0, 0.0), complex!(0.0, 0.0), complex!(0.0, 0.0), complex!(0.0, 0.0), complex!(0.0, 0.0), complex!(0.0, 0.0), complex!(0.0, 0.0), complex!(0.0, 0.0)]; - [complex!(0.0, 0.0), complex!(1.0, 0.0), complex!(0.0, 0.0), complex!(0.0, 0.0), complex!(0.0, 0.0), complex!(0.0, 0.0), complex!(0.0, 0.0), complex!(0.0, 0.0)]; - [complex!(0.0, 0.0), complex!(0.0, 0.0), complex!(1.0, 0.0), complex!(0.0, 0.0), complex!(0.0, 0.0), complex!(0.0, 0.0), complex!(0.0, 0.0), complex!(0.0, 0.0)]; - [complex!(0.0, 0.0), complex!(0.0, 0.0), complex!(0.0, 0.0), complex!(1.0, 0.0), complex!(0.0, 0.0), complex!(0.0, 0.0), complex!(0.0, 0.0), complex!(0.0, 0.0)]; - [complex!(0.0, 0.0), complex!(0.0, 0.0), complex!(0.0, 0.0), complex!(0.0, 0.0), complex!(1.0, 0.0), complex!(0.0, 0.0), complex!(0.0, 0.0), complex!(0.0, 0.0)]; - [complex!(0.0, 0.0), complex!(0.0, 0.0), complex!(0.0, 0.0), complex!(0.0, 0.0), complex!(0.0, 0.0), complex!(1.0, 0.0), complex!(0.0, 0.0), complex!(0.0, 0.0)]; - [complex!(0.0, 0.0), complex!(0.0, 0.0), complex!(0.0, 0.0), complex!(0.0, 0.0), complex!(0.0, 0.0), complex!(0.0, 0.0), complex!(0.0, 0.0), complex!(1.0, 0.0)]; - [complex!(0.0, 0.0), complex!(0.0, 0.0), complex!(0.0, 0.0), complex!(0.0, 0.0), complex!(0.0, 0.0), complex!(0.0, 0.0), complex!(1.0, 0.0), complex!(0.0, 0.0)] - ), - num_qubits: 3, - }; - - pub static ref FREDKIN: QuantumGate<'static> = QuantumGate { - name: "CSWAP", - matrix: matrix!( - [complex!(1.0, 0.0), complex!(0.0, 0.0), complex!(0.0, 0.0), complex!(0.0, 0.0), complex!(0.0, 0.0), complex!(0.0, 0.0), complex!(0.0, 0.0), complex!(0.0, 0.0)]; - [complex!(0.0, 0.0), complex!(1.0, 0.0), complex!(0.0, 0.0), complex!(0.0, 0.0), complex!(0.0, 0.0), complex!(0.0, 0.0), complex!(0.0, 0.0), complex!(0.0, 0.0)]; - [complex!(0.0, 0.0), complex!(0.0, 0.0), complex!(1.0, 0.0), complex!(0.0, 0.0), complex!(0.0, 0.0), complex!(0.0, 0.0), complex!(0.0, 0.0), complex!(0.0, 0.0)]; - [complex!(0.0, 0.0), complex!(0.0, 0.0), complex!(0.0, 0.0), complex!(1.0, 0.0), complex!(0.0, 0.0), complex!(0.0, 0.0), complex!(0.0, 0.0), complex!(0.0, 0.0)]; - [complex!(0.0, 0.0), complex!(0.0, 0.0), complex!(0.0, 0.0), complex!(0.0, 0.0), complex!(1.0, 0.0), complex!(0.0, 0.0), complex!(0.0, 0.0), complex!(0.0, 0.0)]; - [complex!(0.0, 0.0), complex!(0.0, 0.0), complex!(0.0, 0.0), complex!(0.0, 0.0), complex!(0.0, 0.0), complex!(0.0, 0.0), complex!(1.0, 0.0), complex!(0.0, 0.0)]; - [complex!(0.0, 0.0), complex!(0.0, 0.0), complex!(0.0, 0.0), complex!(0.0, 0.0), complex!(0.0, 0.0), complex!(1.0, 0.0), complex!(0.0, 0.0), complex!(0.0, 0.0)]; - [complex!(0.0, 0.0), complex!(0.0, 0.0), complex!(0.0, 0.0), complex!(0.0, 0.0), complex!(0.0, 0.0), complex!(0.0, 0.0), complex!(0.0, 0.0), complex!(1.0, 0.0)] - ), - num_qubits: 3, - }; -} diff --git a/src/core/mod.rs b/src/core/mod.rs deleted file mode 100644 index c38cf38..0000000 --- a/src/core/mod.rs +++ /dev/null @@ -1,17 +0,0 @@ -pub mod circuit; -pub mod classical_components; -pub mod custom_gate; -pub mod gates; -pub mod kernel; -pub mod noise; -pub mod quantum_components; -pub mod runtime; - -pub use circuit::*; -pub use classical_components::*; -pub use custom_gate::*; -pub use gates::*; -pub use kernel::*; -pub use noise::*; -pub use quantum_components::*; -pub use runtime::*; diff --git a/src/core/noise.rs b/src/core/noise.rs deleted file mode 100644 index 8d56953..0000000 --- a/src/core/noise.rs +++ /dev/null @@ -1,559 +0,0 @@ -use crate::{complex, Complex, Matrix}; - -#[derive(Clone, Debug)] -pub struct KrausOperator { - pub matrix: Matrix>, - pub name: String, -} - -impl KrausOperator { - pub fn new(name: &str, matrix: Matrix>) -> Self { - Self { - matrix, - name: name.to_string(), - } - } -} - -#[derive(Clone, Debug)] -pub struct NoiseChannel { - pub name: String, - pub operators: Vec, - pub num_qubits: usize, -} - -impl NoiseChannel { - pub fn new(name: &str, operators: Vec, num_qubits: usize) -> Self { - Self { - name: name.to_string(), - operators, - num_qubits, - } - } - - pub fn depolarising(p: f64) -> Self { - let sqrt_1_p = (1.0 - p).sqrt(); - let sqrt_p3 = (p / 3.0).sqrt(); - - let k0 = Matrix::new( - 2, - 2, - vec![ - complex!(sqrt_1_p, 0.0), - complex!(0.0, 0.0), - complex!(0.0, 0.0), - complex!(sqrt_1_p, 0.0), - ], - ); - - let k1 = Matrix::new( - 2, - 2, - vec![ - complex!(0.0, 0.0), - complex!(sqrt_p3, 0.0), - complex!(sqrt_p3, 0.0), - complex!(0.0, 0.0), - ], - ); - - let k2 = Matrix::new( - 2, - 2, - vec![ - complex!(0.0, 0.0), - complex!(0.0, -sqrt_p3), - complex!(0.0, sqrt_p3), - complex!(0.0, 0.0), - ], - ); - - let k3 = Matrix::new( - 2, - 2, - vec![ - complex!(sqrt_p3, 0.0), - complex!(0.0, 0.0), - complex!(0.0, 0.0), - complex!(-sqrt_p3, 0.0), - ], - ); - - Self::new( - "Depolarising", - vec![ - KrausOperator::new("K0", k0), - KrausOperator::new("K1(X)", k1), - KrausOperator::new("K2(Y)", k2), - KrausOperator::new("K3(Z)", k3), - ], - 1, - ) - } - - pub fn amplitude_damping(gamma: f64) -> Self { - let sqrt_gamma = gamma.sqrt(); - let sqrt_1_gamma = (1.0 - gamma).sqrt(); - - let k0 = Matrix::new( - 2, - 2, - vec![ - complex!(1.0, 0.0), - complex!(0.0, 0.0), - complex!(0.0, 0.0), - complex!(sqrt_1_gamma, 0.0), - ], - ); - - let k1 = Matrix::new( - 2, - 2, - vec![ - complex!(0.0, 0.0), - complex!(sqrt_gamma, 0.0), - complex!(0.0, 0.0), - complex!(0.0, 0.0), - ], - ); - - Self::new( - "AmplitudeDamping", - vec![ - KrausOperator::new("K0", k0), - KrausOperator::new("K1", k1), - ], - 1, - ) - } - - pub fn phase_damping(gamma: f64) -> Self { - let sqrt_gamma = gamma.sqrt(); - let sqrt_1_gamma = (1.0 - gamma).sqrt(); - - let k0 = Matrix::new( - 2, - 2, - vec![ - complex!(1.0, 0.0), - complex!(0.0, 0.0), - complex!(0.0, 0.0), - complex!(sqrt_1_gamma, 0.0), - ], - ); - - let k1 = Matrix::new( - 2, - 2, - vec![ - complex!(0.0, 0.0), - complex!(0.0, 0.0), - complex!(0.0, 0.0), - complex!(sqrt_gamma, 0.0), - ], - ); - - Self::new( - "PhaseDamping", - vec![ - KrausOperator::new("K0", k0), - KrausOperator::new("K1", k1), - ], - 1, - ) - } - - pub fn bit_flip(p: f64) -> Self { - let sqrt_1_p = (1.0 - p).sqrt(); - let sqrt_p = p.sqrt(); - - let k0 = Matrix::new( - 2, - 2, - vec![ - complex!(sqrt_1_p, 0.0), - complex!(0.0, 0.0), - complex!(0.0, 0.0), - complex!(sqrt_1_p, 0.0), - ], - ); - - let k1 = Matrix::new( - 2, - 2, - vec![ - complex!(0.0, 0.0), - complex!(sqrt_p, 0.0), - complex!(sqrt_p, 0.0), - complex!(0.0, 0.0), - ], - ); - - Self::new( - "BitFlip", - vec![ - KrausOperator::new("K0(I)", k0), - KrausOperator::new("K1(X)", k1), - ], - 1, - ) - } - - pub fn phase_flip(p: f64) -> Self { - let sqrt_1_p = (1.0 - p).sqrt(); - let sqrt_p = p.sqrt(); - - let k0 = Matrix::new( - 2, - 2, - vec![ - complex!(sqrt_1_p, 0.0), - complex!(0.0, 0.0), - complex!(0.0, 0.0), - complex!(sqrt_1_p, 0.0), - ], - ); - - let k1 = Matrix::new( - 2, - 2, - vec![ - complex!(sqrt_p, 0.0), - complex!(0.0, 0.0), - complex!(0.0, 0.0), - complex!(-sqrt_p, 0.0), - ], - ); - - Self::new( - "PhaseFlip", - vec![ - KrausOperator::new("K0(I)", k0), - KrausOperator::new("K1(Z)", k1), - ], - 1, - ) - } - - pub fn bit_phase_flip(p: f64) -> Self { - let sqrt_1_p = (1.0 - p).sqrt(); - let sqrt_p = p.sqrt(); - - let k0 = Matrix::new( - 2, - 2, - vec![ - complex!(sqrt_1_p, 0.0), - complex!(0.0, 0.0), - complex!(0.0, 0.0), - complex!(sqrt_1_p, 0.0), - ], - ); - - let k1 = Matrix::new( - 2, - 2, - vec![ - complex!(0.0, 0.0), - complex!(0.0, -sqrt_p), - complex!(0.0, sqrt_p), - complex!(0.0, 0.0), - ], - ); - - Self::new( - "BitPhaseFlip", - vec![ - KrausOperator::new("K0(I)", k0), - KrausOperator::new("K1(Y)", k1), - ], - 1, - ) - } - - pub fn generalised_amplitude_damping(p: f64, gamma: f64) -> Self { - let sqrt_p = p.sqrt(); - let sqrt_1_p = (1.0 - p).sqrt(); - let sqrt_gamma = gamma.sqrt(); - let sqrt_1_gamma = (1.0 - gamma).sqrt(); - - let k0 = Matrix::new( - 2, - 2, - vec![ - complex!(sqrt_p, 0.0), - complex!(0.0, 0.0), - complex!(0.0, 0.0), - complex!(sqrt_p * sqrt_1_gamma, 0.0), - ], - ); - - let k1 = Matrix::new( - 2, - 2, - vec![ - complex!(0.0, 0.0), - complex!(sqrt_p * sqrt_gamma, 0.0), - complex!(0.0, 0.0), - complex!(0.0, 0.0), - ], - ); - - let k2 = Matrix::new( - 2, - 2, - vec![ - complex!(sqrt_1_p * sqrt_1_gamma, 0.0), - complex!(0.0, 0.0), - complex!(0.0, 0.0), - complex!(sqrt_1_p, 0.0), - ], - ); - - let k3 = Matrix::new( - 2, - 2, - vec![ - complex!(0.0, 0.0), - complex!(0.0, 0.0), - complex!(sqrt_1_p * sqrt_gamma, 0.0), - complex!(0.0, 0.0), - ], - ); - - Self::new( - "GeneralisedAmplitudeDamping", - vec![ - KrausOperator::new("K0", k0), - KrausOperator::new("K1", k1), - KrausOperator::new("K2", k2), - KrausOperator::new("K3", k3), - ], - 1, - ) - } -} - -#[derive(Clone)] -pub struct DensityMatrix { - pub data: Vec>, - pub dim: usize, - pub num_qubits: usize, -} - -impl DensityMatrix { - pub fn new(num_qubits: usize) -> Self { - let dim = 1 << num_qubits; - let mut data = vec![complex!(0.0, 0.0); dim * dim]; - data[0] = complex!(1.0, 0.0); - Self { - data, - dim, - num_qubits, - } - } - - pub fn from_state_vector(state: &[Complex]) -> Self { - let dim = state.len(); - let num_qubits = (dim as f64).log2() as usize; - let mut data = vec![complex!(0.0, 0.0); dim * dim]; - - for i in 0..dim { - for j in 0..dim { - data[i * dim + j] = state[i] * state[j].get_conjugate(); - } - } - - Self { - data, - dim, - num_qubits, - } - } - - pub fn get(&self, row: usize, col: usize) -> Complex { - self.data[row * self.dim + col] - } - - pub fn set(&mut self, row: usize, col: usize, value: Complex) { - self.data[row * self.dim + col] = value; - } - - pub fn trace(&self) -> Complex { - let mut sum = complex!(0.0, 0.0); - for i in 0..self.dim { - sum += self.get(i, i); - } - sum - } - - pub fn purity(&self) -> f64 { - let mut sum = complex!(0.0, 0.0); - for i in 0..self.dim { - for j in 0..self.dim { - let rho_ij = self.get(i, j); - let rho_ji = self.get(j, i); - sum += rho_ij * rho_ji; - } - } - sum.real - } - - pub fn is_pure(&self, tolerance: f64) -> bool { - (self.purity() - 1.0).abs() < tolerance - } - - pub fn probabilities(&self) -> Vec { - (0..self.dim).map(|i| self.get(i, i).real).collect() - } - - pub fn apply_unitary(&mut self, gate: &Matrix>, targets: &[usize]) { - let g = targets.len(); - let gate_dim = 1 << g; - - let target_bits: Vec = targets - .iter() - .map(|&t| self.num_qubits - 1 - t) - .collect(); - - let mut non_target_mask: usize = (1 << self.num_qubits) - 1; - for &pos in &target_bits { - non_target_mask &= !(1 << pos); - } - - let mut new_data = vec![complex!(0.0, 0.0); self.dim * self.dim]; - - for i in 0..self.dim { - for j in 0..self.dim { - let mut sum = complex!(0.0, 0.0); - - for k in 0..gate_dim { - for l in 0..gate_dim { - let mut src_i = i & non_target_mask; - let mut src_j = j & non_target_mask; - - for (idx, &pos) in target_bits.iter().enumerate() { - if (k >> (g - 1 - idx)) & 1 == 1 { - src_i |= 1 << pos; - } - if (l >> (g - 1 - idx)) & 1 == 1 { - src_j |= 1 << pos; - } - } - - let mut tgt_i = 0usize; - let mut tgt_j = 0usize; - for (idx, &pos) in target_bits.iter().enumerate() { - if (i >> pos) & 1 == 1 { - tgt_i |= 1 << (g - 1 - idx); - } - if (j >> pos) & 1 == 1 { - tgt_j |= 1 << (g - 1 - idx); - } - } - - let u_ik = gate.data[tgt_i * gate_dim + k]; - let u_jl_dag = gate.data[tgt_j * gate_dim + l].get_conjugate(); - let rho_kl = self.get(src_i, src_j); - - sum += u_ik * rho_kl * u_jl_dag; - } - } - - new_data[i * self.dim + j] = sum; - } - } - - self.data = new_data; - } - - pub fn apply_noise_channel(&mut self, channel: &NoiseChannel, target: usize) { - if channel.num_qubits != 1 { - panic!("Only single-qubit noise channels are currently supported"); - } - - let target_bit = self.num_qubits - 1 - target; - let mut new_data = vec![complex!(0.0, 0.0); self.dim * self.dim]; - - for kraus in &channel.operators { - let k = &kraus.matrix; - - for i in 0..self.dim { - for j in 0..self.dim { - let i_target = (i >> target_bit) & 1; - let j_target = (j >> target_bit) & 1; - - for ki in 0..2 { - for kj in 0..2 { - let src_i = (i & !(1 << target_bit)) | (ki << target_bit); - let src_j = (j & !(1 << target_bit)) | (kj << target_bit); - - let k_elem = k.data[i_target * 2 + ki]; - let k_dag_elem = k.data[j_target * 2 + kj].get_conjugate(); - let rho_elem = self.get(src_i, src_j); - - new_data[i * self.dim + j] += k_elem * rho_elem * k_dag_elem; - } - } - } - } - } - - self.data = new_data; - } - - pub fn measure_probability(&self, qubit: usize, outcome: usize) -> f64 { - let target_bit = self.num_qubits - 1 - qubit; - let mut prob = 0.0; - - for i in 0..self.dim { - if (i >> target_bit) & 1 == outcome { - prob += self.get(i, i).real; - } - } - - prob - } - - pub fn fidelity_with_pure_state(&self, state: &[Complex]) -> f64 { - let mut sum = complex!(0.0, 0.0); - - for i in 0..self.dim { - for j in 0..self.dim { - sum += state[i].get_conjugate() * self.get(i, j) * state[j]; - } - } - - sum.real - } -} - -impl std::fmt::Display for DensityMatrix { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - writeln!(f, "DensityMatrix ({} qubits, {}×{}):", self.num_qubits, self.dim, self.dim)?; - writeln!(f, " Trace: {:.6}", self.trace().real)?; - writeln!(f, " Purity: {:.6}", self.purity())?; - writeln!(f, " Pure: {}", self.is_pure(1e-10))?; - writeln!(f, " Probabilities: {:?}", self.probabilities())?; - Ok(()) - } -} - -impl std::fmt::Debug for DensityMatrix { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - writeln!(f, "DensityMatrix {}×{}:", self.dim, self.dim)?; - for i in 0..self.dim { - write!(f, " [")?; - for j in 0..self.dim { - let val = self.get(i, j); - if j > 0 { - write!(f, ", ")?; - } - write!(f, "{:.4}+{:.4}i", val.real, val.imaginary)?; - } - writeln!(f, "]")?; - } - Ok(()) - } -} - diff --git a/src/core/quantum_components.rs b/src/core/quantum_components.rs deleted file mode 100644 index f07b8ef..0000000 --- a/src/core/quantum_components.rs +++ /dev/null @@ -1,318 +0,0 @@ -use crate::{column_vector, complex, ColumnVector, Complex, Float, Matrix, Vector, VectorMatrix}; -use core::{fmt, ops}; - -#[macro_export] -macro_rules! count { - () => { 0 }; - ($head:expr $(,$tail:expr)*) => { 1 + count!($( $tail ),*) }; -} - -#[macro_export] -macro_rules! qubit { - ($(($re:expr, $im:expr)),*) => { - { - let mut vector = Vec::new(); - $( - vector.push(complex!($re, $im)); - )* - QuantumBit::new(vector) - } - }; -} - -#[macro_export] -macro_rules! quantum_register { - ($($bit:expr),*) => { - { - const N: usize = count!($($bit),*); - let mut bits: [QuantumBit; N] = [$($bit),*]; - QuantumRegister::from(&mut bits) - } - }; -} - -pub type QuantumState = ColumnVector>; -impl QuantumState { - pub fn state_0() -> QuantumState { - column_vector![complex!(1.0, 0.0), complex!(0.0, 0.0)] - } - - pub fn state_1() -> QuantumState { - column_vector![complex!(0.0, 0.0), complex!(1.0, 0.0)] - } -} - -fn identity_matrix(size: usize) -> Matrix { - let mut data = vec![T::zero(); size * size]; - for i in 0..size { - data[i * size + i] = T::one(); - } - Matrix::new(size, size, data) -} - -#[derive(Clone)] -pub struct QuantumBit<'a> { - state: QuantumState, - name: &'a str, -} - -#[derive(Clone)] -pub struct QuantumRegister<'a> { - state_vector: QuantumState, - name: &'a str, - qubits: Vec>, -} - -#[derive(Clone)] -pub struct QuantumGate<'a> { - pub name: &'a str, - pub matrix: Matrix>, - pub num_qubits: usize, -} - -impl<'a> QuantumGate<'a> { - pub fn new(name: &'a str, matrix: Matrix>, num_qubits: usize) -> Self { - let expected_dim = 1 << num_qubits; - assert_eq!( - matrix.rows, expected_dim, - "Gate matrix rows must be 2^num_qubits" - ); - assert_eq!( - matrix.cols, expected_dim, - "Gate matrix cols must be 2^num_qubits" - ); - QuantumGate { - name, - matrix, - num_qubits, - } - } - - pub fn from_matrix(name: &'a str, matrix: Matrix>) -> Self { - assert_eq!(matrix.rows, matrix.cols, "Gate matrix must be square"); - let dim = matrix.rows; - assert!( - dim > 0 && (dim & (dim - 1)) == 0, - "Matrix dimension must be a power of 2" - ); - let num_qubits = (dim as f64).log2() as usize; - QuantumGate { - name, - matrix, - num_qubits, - } - } -} - -impl<'a> QuantumBit<'a> { - pub fn new(name: &'a str, state: QuantumState) -> QuantumBit<'a> { - QuantumBit { name, state } - } - - pub fn get_state(&self) -> QuantumState { - self.state.clone() - } - - pub fn get_name(&self) -> &'a str { - self.name - } -} - -impl<'a> QuantumRegister<'a> { - pub fn new(name: &'a str, names: &[&'a str]) -> QuantumRegister<'a> { - let mut bits: Vec> = Vec::new(); - for &name in names { - bits.push(QuantumBit::new(name, QuantumState::state_0())) - } - - QuantumRegister::from(name, &mut bits) - } - - pub fn from(name: &'a str, bits: &mut [QuantumBit<'a>]) -> QuantumRegister<'a> { - let mut register = QuantumRegister { - name, - qubits: bits.to_vec(), - state_vector: ColumnVector::new(vec![]), - }; - - register.update(); - register - } - - fn update(&mut self) { - let matrices: Vec>> = self - .qubits - .iter() - .map(|qubit| qubit.state.to_matrix()) - .collect(); - let mut new_result = matrices[0].clone(); - for matrix in &matrices[1..] { - new_result = new_result.kronecker(matrix); - } - - self.state_vector = ColumnVector::from_matrix(&new_result); - } - - pub fn get_bits(&self) -> Vec> { - self.qubits.clone() - } - - pub fn get_state(&self) -> QuantumState { - self.state_vector.clone() - } - - pub fn get_name(&self) -> &'a str { - self.name - } - - pub fn num_qubits(&self) -> usize { - self.qubits.len() - } - - pub fn apply_gate(&mut self, gate: &QuantumGate, targets: &[usize]) { - let n = self.num_qubits(); - - assert_eq!( - gate.num_qubits, - targets.len(), - "Number of target qubits must match gate's qubit count" - ); - for &t in targets { - assert!( - t < n, - "Target qubit index {} out of range for {}-qubit register", - t, - n - ); - } - - let mut sorted_targets = targets.to_vec(); - sorted_targets.sort(); - for i in 1..sorted_targets.len() { - assert_ne!( - sorted_targets[i], - sorted_targets[i - 1], - "Duplicate target qubit indices are not allowed" - ); - } - - let full_operator = self.build_full_operator(gate, targets); - - self.state_vector = self - .state_vector - .mul_matrix(&full_operator) - .expect("Matrix multiplication failed during gate application"); - } - - fn build_full_operator(&self, gate: &QuantumGate, targets: &[usize]) -> Matrix> { - let n = self.num_qubits(); - let g = gate.num_qubits; - let dim = 1 << n; - - let mut contiguous = true; - for i in 1..targets.len() { - if targets[i] != targets[i - 1] + 1 { - contiguous = false; - break; - } - } - - if contiguous && g == n { - return gate.matrix.clone(); - } - - if contiguous { - return self.build_contiguous_operator(gate, targets[0]); - } - - let mut result = Matrix::new(dim, dim, vec![complex!(0.0, 0.0); dim * dim]); - - for col in 0..dim { - for row in 0..dim { - let mut target_row_bits = 0usize; - let mut target_col_bits = 0usize; - - for (i, &t) in targets.iter().enumerate() { - let qubit_pos = n - 1 - t; - if (row >> qubit_pos) & 1 == 1 { - target_row_bits |= 1 << (g - 1 - i); - } - if (col >> qubit_pos) & 1 == 1 { - target_col_bits |= 1 << (g - 1 - i); - } - } - - let mut non_target_match = true; - for q in 0..n { - if !targets.contains(&q) { - let qubit_pos = n - 1 - q; - if ((row >> qubit_pos) & 1) != ((col >> qubit_pos) & 1) { - non_target_match = false; - break; - } - } - } - - if non_target_match { - result.set(row, col, gate.matrix.get(target_row_bits, target_col_bits)); - } - } - } - - result - } - - fn build_contiguous_operator( - &self, - gate: &QuantumGate, - start_idx: usize, - ) -> Matrix> { - let n = self.num_qubits(); - let g = gate.num_qubits; - - let mut result: Option>> = None; - - for i in 0..n { - let part: Matrix> = if i == start_idx { - gate.matrix.clone() - } else if i > start_idx && i < start_idx + g { - continue; - } else { - identity_matrix(2) - }; - - result = Some(match result { - None => part, - Some(r) => r.kronecker(&part), - }); - } - - result.unwrap_or_else(|| identity_matrix(1 << n)) - } - - pub fn apply_gates(&mut self, operations: &[(&QuantumGate, &[usize])]) { - for (gate, targets) in operations { - self.apply_gate(gate, targets); - } - } -} - -impl<'a> ops::Index for QuantumRegister<'a> { - type Output = QuantumBit<'a>; - - fn index(&self, index: usize) -> &Self::Output { - &self.qubits[index] - } -} - -impl<'a> ops::IndexMut for QuantumRegister<'a> { - fn index_mut(&mut self, index: usize) -> &mut Self::Output { - &mut self.qubits[index] - } -} - -impl<'a> fmt::Display for QuantumGate<'a> { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.name) - } -} diff --git a/src/lib.rs b/src/lib.rs deleted file mode 100644 index 6f54357..0000000 --- a/src/lib.rs +++ /dev/null @@ -1,21 +0,0 @@ -pub mod core; -pub mod maths; -pub mod visualizer; - -pub use maths::complex::*; -pub use maths::format::*; -pub use maths::matrix::*; -pub use maths::numeric::*; -pub use maths::simd::*; -pub use maths::vector::*; - -pub use core::circuit::*; -pub use core::classical_components::*; -pub use core::custom_gate::*; -pub use core::gates; -pub use core::kernel::*; -pub use core::noise::*; -pub use core::quantum_components::*; -pub use core::runtime::*; - -pub use visualizer::*; diff --git a/src/maths/mod.rs b/src/maths/mod.rs deleted file mode 100644 index 85f4872..0000000 --- a/src/maths/mod.rs +++ /dev/null @@ -1,14 +0,0 @@ -pub mod complex; -pub mod format; -pub mod matrix; -pub mod numeric; -pub mod simd; -pub mod vector; -pub mod vector_ops; - -pub use complex::*; -pub use format::*; -pub use matrix::*; -pub use numeric::*; -pub use simd::*; -pub use vector::*; diff --git a/src/visualizer/horizontal_cli.rs b/src/visualizer/horizontal_cli.rs deleted file mode 100644 index 28cdb5a..0000000 --- a/src/visualizer/horizontal_cli.rs +++ /dev/null @@ -1,463 +0,0 @@ -use super::renderer::Visualizer; -use core::fmt; -use crate::{GateOp, QuantumCircuit}; - -pub struct HorizontalRenderer<'a> { - circuit: &'a QuantumCircuit, -} - -impl<'a> HorizontalRenderer<'a> { - pub fn new(circuit: &'a QuantumCircuit) -> Self { - HorizontalRenderer { circuit } - } -} - -impl<'a> Visualizer for HorizontalRenderer<'a> { - fn export(&self) -> String { - format!("{}", self) - } -} - -impl<'a> fmt::Display for HorizontalRenderer<'a> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let nq = self.circuit.num_qubits(); - let nc = self.circuit.num_classical(); - let ops = self.circuit.operations(); - - let mut q_lines: Vec = (0..nq).map(|i| format!("q{}: ", i)).collect(); - let mut c_lines: Vec = (0..nc).map(|i| format!("c{}: ", i)).collect(); - - let max_label = q_lines - .iter() - .chain(c_lines.iter()) - .map(|s| s.len()) - .max() - .unwrap_or(3); - - for line in &mut q_lines { - while line.len() < max_label { - line.insert(0, ' '); - } - } - for line in &mut c_lines { - while line.len() < max_label { - line.insert(0, ' '); - } - } - let mut gap_line = " ".repeat(max_label); - - if ops.is_empty() { - for line in &q_lines { - writeln!(f, "{}───░", line)?; - } - if nc > 0 { - writeln!(f, "{} ░", gap_line)?; - for line in &c_lines { - writeln!(f, "{}═══░", line)?; - } - } - return Ok(()); - } - - for op in ops { - let q_targets = op.quantum_targets(); - - let min_q = q_targets.iter().min().copied().unwrap_or(0); - let max_q = q_targets.iter().max().copied().unwrap_or(0); - - match op { - GateOp::H(t) => { - for (i, line) in q_lines.iter_mut().enumerate() { - if i == *t { - line.push_str("─[H]─"); - } else { - line.push_str("─────"); - } - } - for line in c_lines.iter_mut() { - line.push_str("═════"); - } - gap_line.push_str(" "); - } - GateOp::X(t) => { - for (i, line) in q_lines.iter_mut().enumerate() { - if i == *t { - line.push_str("─[X]─"); - } else { - line.push_str("─────"); - } - } - for line in c_lines.iter_mut() { - line.push_str("═════"); - } - gap_line.push_str(" "); - } - GateOp::Y(t) => { - for (i, line) in q_lines.iter_mut().enumerate() { - if i == *t { - line.push_str("─[Y]─"); - } else { - line.push_str("─────"); - } - } - for line in c_lines.iter_mut() { - line.push_str("═════"); - } - gap_line.push_str(" "); - } - GateOp::Z(t) => { - for (i, line) in q_lines.iter_mut().enumerate() { - if i == *t { - line.push_str("─[Z]─"); - } else { - line.push_str("─────"); - } - } - for line in c_lines.iter_mut() { - line.push_str("═════"); - } - gap_line.push_str(" "); - } - GateOp::S(t) => { - for (i, line) in q_lines.iter_mut().enumerate() { - if i == *t { - line.push_str("─[S]─"); - } else { - line.push_str("─────"); - } - } - for line in c_lines.iter_mut() { - line.push_str("═════"); - } - gap_line.push_str(" "); - } - GateOp::T(t) => { - for (i, line) in q_lines.iter_mut().enumerate() { - if i == *t { - line.push_str("─[T]─"); - } else { - line.push_str("─────"); - } - } - for line in c_lines.iter_mut() { - line.push_str("═════"); - } - gap_line.push_str(" "); - } - GateOp::Sdg(t) => { - for (i, line) in q_lines.iter_mut().enumerate() { - if i == *t { - line.push_str("─[S†]─"); - } else { - line.push_str("──────"); - } - } - for line in c_lines.iter_mut() { - line.push_str("══════"); - } - gap_line.push_str(" "); - } - GateOp::Tdg(t) => { - for (i, line) in q_lines.iter_mut().enumerate() { - if i == *t { - line.push_str("─[T†]─"); - } else { - line.push_str("──────"); - } - } - for line in c_lines.iter_mut() { - line.push_str("══════"); - } - gap_line.push_str(" "); - } - GateOp::Sx(t) => { - for (i, line) in q_lines.iter_mut().enumerate() { - if i == *t { - line.push_str("─[√X]─"); - } else { - line.push_str("──────"); - } - } - for line in c_lines.iter_mut() { - line.push_str("══════"); - } - gap_line.push_str(" "); - } - GateOp::Sxdg(t) => { - for (i, line) in q_lines.iter_mut().enumerate() { - if i == *t { - line.push_str("─[√X†]─"); - } else { - line.push_str("───────"); - } - } - for line in c_lines.iter_mut() { - line.push_str("═══════"); - } - gap_line.push_str(" "); - } - GateOp::Rx(t, theta) => { - let label = format!("[Rx({:.2})]", theta); - for (i, line) in q_lines.iter_mut().enumerate() { - if i == *t { - line.push_str(&format!("─{}─", label)); - } else { - line.push_str(&format!("─{}─", "─".repeat(label.len()))); - } - } - for line in c_lines.iter_mut() { - line.push_str(&format!("═{}═", "═".repeat(label.len()))); - } - gap_line.push_str(&format!(" {} ", " ".repeat(label.len()))); - } - GateOp::Ry(t, theta) => { - let label = format!("[Ry({:.2})]", theta); - for (i, line) in q_lines.iter_mut().enumerate() { - if i == *t { - line.push_str(&format!("─{}─", label)); - } else { - line.push_str(&format!("─{}─", "─".repeat(label.len()))); - } - } - for line in c_lines.iter_mut() { - line.push_str(&format!("═{}═", "═".repeat(label.len()))); - } - gap_line.push_str(&format!(" {} ", " ".repeat(label.len()))); - } - GateOp::Rz(t, theta) => { - let label = format!("[Rz({:.2})]", theta); - for (i, line) in q_lines.iter_mut().enumerate() { - if i == *t { - line.push_str(&format!("─{}─", label)); - } else { - line.push_str(&format!("─{}─", "─".repeat(label.len()))); - } - } - for line in c_lines.iter_mut() { - line.push_str(&format!("═{}═", "═".repeat(label.len()))); - } - gap_line.push_str(&format!(" {} ", " ".repeat(label.len()))); - } - GateOp::P(t, theta) => { - let label = format!("[P({:.2})]", theta); - for (i, line) in q_lines.iter_mut().enumerate() { - if i == *t { - line.push_str(&format!("─{}─", label)); - } else { - line.push_str(&format!("─{}─", "─".repeat(label.len()))); - } - } - for line in c_lines.iter_mut() { - line.push_str(&format!("═{}═", "═".repeat(label.len()))); - } - gap_line.push_str(&format!(" {} ", " ".repeat(label.len()))); - } - GateOp::U1(t, lambda) => { - let label = format!("[U1({:.2})]", lambda); - for (i, line) in q_lines.iter_mut().enumerate() { - if i == *t { - line.push_str(&format!("─{}─", label)); - } else { - line.push_str(&format!("─{}─", "─".repeat(label.len()))); - } - } - for line in c_lines.iter_mut() { - line.push_str(&format!("═{}═", "═".repeat(label.len()))); - } - gap_line.push_str(&format!(" {} ", " ".repeat(label.len()))); - } - GateOp::U2(t, _, _) => { - let label = "[U2]"; - for (i, line) in q_lines.iter_mut().enumerate() { - if i == *t { - line.push_str(&format!("─{}─", label)); - } else { - line.push_str(&format!("─{}─", "─".repeat(label.len()))); - } - } - for line in c_lines.iter_mut() { - line.push_str(&format!("═{}═", "═".repeat(label.len()))); - } - gap_line.push_str(&format!(" {} ", " ".repeat(label.len()))); - } - GateOp::U3(t, _, _, _) => { - let label = "[U3]"; - for (i, line) in q_lines.iter_mut().enumerate() { - if i == *t { - line.push_str(&format!("─{}─", label)); - } else { - line.push_str(&format!("─{}─", "─".repeat(label.len()))); - } - } - for line in c_lines.iter_mut() { - line.push_str(&format!("═{}═", "═".repeat(label.len()))); - } - gap_line.push_str(&format!(" {} ", " ".repeat(label.len()))); - } - GateOp::CRx(c, t, theta) | GateOp::CRy(c, t, theta) | GateOp::CRz(c, t, theta) | GateOp::CP(c, t, theta) => { - let label = match op { - GateOp::CRx(_, _, _) => format!("[CRx({:.2})]", theta), - GateOp::CRy(_, _, _) => format!("[CRy({:.2})]", theta), - GateOp::CRz(_, _, _) => format!("[CRz({:.2})]", theta), - GateOp::CP(_, _, _) => format!("[CP({:.2})]", theta), - _ => unreachable!(), - }; - for (i, line) in q_lines.iter_mut().enumerate() { - if i == *c { - line.push_str(&format!("─{}─", "●".to_string() + &"─".repeat(label.len() - 1))); - } else if i == *t { - line.push_str(&format!("─{}─", label)); - } else if i > min_q && i < max_q { - line.push_str(&format!("─{}─", "│".to_string() + &"─".repeat(label.len() - 1))); - } else { - line.push_str(&format!("─{}─", "─".repeat(label.len()))); - } - } - for line in c_lines.iter_mut() { - line.push_str(&format!("═{}═", "═".repeat(label.len()))); - } - gap_line.push_str(&format!(" {} ", " ".repeat(label.len()))); - } - GateOp::CNOT(c, t) => { - for (i, line) in q_lines.iter_mut().enumerate() { - if i == *c { - line.push_str("──●──"); - } else if i == *t { - line.push_str("──⊕──"); - } else if i > min_q && i < max_q { - line.push_str("──│──"); - } else { - line.push_str("─────"); - } - } - for line in c_lines.iter_mut() { - line.push_str("═════"); - } - gap_line.push_str(" "); - } - GateOp::CZ(c, t) => { - for (i, line) in q_lines.iter_mut().enumerate() { - if i == *c || i == *t { - line.push_str("──●──"); - } else if i > min_q && i < max_q { - line.push_str("──│──"); - } else { - line.push_str("─────"); - } - } - for line in c_lines.iter_mut() { - line.push_str("═════"); - } - gap_line.push_str(" "); - } - GateOp::SWAP(a, b) => { - for (i, line) in q_lines.iter_mut().enumerate() { - if i == *a || i == *b { - line.push_str("──╳──"); - } else if i > min_q && i < max_q { - line.push_str("──│──"); - } else { - line.push_str("─────"); - } - } - for line in c_lines.iter_mut() { - line.push_str("═════"); - } - gap_line.push_str(" "); - } - GateOp::CCNOT(c1, c2, t) => { - for (i, line) in q_lines.iter_mut().enumerate() { - if i == *c1 || i == *c2 { - line.push_str("──●──"); - } else if i == *t { - line.push_str("──⊕──"); - } else if i > min_q && i < max_q { - line.push_str("──│──"); - } else { - line.push_str("─────"); - } - } - for line in c_lines.iter_mut() { - line.push_str("═════"); - } - gap_line.push_str(" "); - } - GateOp::CSWAP(c, t1, t2) => { - for (i, line) in q_lines.iter_mut().enumerate() { - if i == *c { - line.push_str("──●──"); - } else if i == *t1 || i == *t2 { - line.push_str("──╳──"); - } else if i > min_q && i < max_q { - line.push_str("──│──"); - } else { - line.push_str("─────"); - } - } - for line in c_lines.iter_mut() { - line.push_str("═════"); - } - gap_line.push_str(" "); - } - GateOp::Measure(q, c) => { - for (i, line) in q_lines.iter_mut().enumerate() { - if i == *q { - line.push_str("─[M]─"); - } else if i > *q { - line.push_str("──║──"); - } else { - line.push_str("─────"); - } - } - for (i, line) in c_lines.iter_mut().enumerate() { - if i == *c { - line.push_str("══╩══"); - } else if i < *c { - line.push_str("══║══"); - } else { - line.push_str("═════"); - } - } - gap_line.push_str(" ║ "); - } - GateOp::Custom(gate, targets) => { - let name = &gate.name; - let label = format!("[{}]", name); - - for (i, line) in q_lines.iter_mut().enumerate() { - if targets.contains(&i) { - if i == targets[0] { - line.push_str(&format!("─{}─", label)); - } else { - line.push_str(&format!("─{}─", "─".repeat(label.len()))); - } - } else if i > min_q && i < max_q { - line.push_str(&format!( - "─{}─", - "│".to_string() + &"─".repeat(label.len() - 1) - )); - } else { - line.push_str(&format!("─{}─", "─".repeat(label.len()))); - } - } - for line in c_lines.iter_mut() { - line.push_str(&format!("═{}═", "═".repeat(label.len()))); - } - gap_line.push_str(&format!(" {} ", " ".repeat(label.len()))); - } - } - } - - for line in &q_lines { - writeln!(f, "{}░", line)?; - } - if nc > 0 { - writeln!(f, "{}░", gap_line)?; - for line in &c_lines { - writeln!(f, "{}░", line)?; - } - } - - Ok(()) - } -} diff --git a/src/visualizer/mod.rs b/src/visualizer/mod.rs deleted file mode 100644 index ff53c44..0000000 --- a/src/visualizer/mod.rs +++ /dev/null @@ -1,7 +0,0 @@ -pub mod horizontal_cli; -pub mod vertical_cli; -pub mod renderer; - -pub use horizontal_cli::*; -pub use vertical_cli::*; -pub use renderer::*; diff --git a/src/visualizer/renderer.rs b/src/visualizer/renderer.rs deleted file mode 100644 index 33f730f..0000000 --- a/src/visualizer/renderer.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub trait Visualizer { - fn export(&self) -> String; -} diff --git a/src/visualizer/vertical_cli.rs b/src/visualizer/vertical_cli.rs deleted file mode 100644 index e9322bf..0000000 --- a/src/visualizer/vertical_cli.rs +++ /dev/null @@ -1,367 +0,0 @@ -use super::renderer::Visualizer; -use core::fmt; -use crate::{GateOp, QuantumCircuit}; - -pub struct VerticalRenderer<'a> { - circuit: &'a QuantumCircuit, -} - -impl<'a> VerticalRenderer<'a> { - pub fn new(circuit: &'a QuantumCircuit) -> Self { - VerticalRenderer { circuit } - } - - fn gate_label(op: &GateOp) -> String { - match op { - GateOp::H(_) => "[H]".to_string(), - GateOp::X(_) => "[X]".to_string(), - GateOp::Y(_) => "[Y]".to_string(), - GateOp::Z(_) => "[Z]".to_string(), - GateOp::S(_) => "[S]".to_string(), - GateOp::T(_) => "[T]".to_string(), - GateOp::Sdg(_) => "[S†]".to_string(), - GateOp::Tdg(_) => "[T†]".to_string(), - GateOp::Sx(_) => "[√X]".to_string(), - GateOp::Sxdg(_) => "[√X†]".to_string(), - GateOp::Rx(_, theta) => format!("[Rx({:.2})]", theta), - GateOp::Ry(_, theta) => format!("[Ry({:.2})]", theta), - GateOp::Rz(_, theta) => format!("[Rz({:.2})]", theta), - GateOp::P(_, theta) => format!("[P({:.2})]", theta), - GateOp::U1(_, lambda) => format!("[U1({:.2})]", lambda), - GateOp::U2(_, _, _) => "[U2]".to_string(), - GateOp::U3(_, _, _, _) => "[U3]".to_string(), - GateOp::CRx(_, _, _) => "[CRx]".to_string(), - GateOp::CRy(_, _, _) => "[CRy]".to_string(), - GateOp::CRz(_, _, _) => "[CRz]".to_string(), - GateOp::CP(_, _, _) => "[CP]".to_string(), - GateOp::CNOT(_, _) => "●".to_string(), - GateOp::CZ(_, _) => "●".to_string(), - GateOp::SWAP(_, _) => "╳".to_string(), - GateOp::CCNOT(_, _, _) => "●".to_string(), - GateOp::CSWAP(_, _, _) => "●".to_string(), - GateOp::Measure(_, _) => "[M]".to_string(), - GateOp::Custom(gate, _) => format!("[{}]", gate.name), - } - } - - fn calculate_col_width(&self) -> usize { - let min_width = 3; - let mut max_label_len = min_width; - - for op in self.circuit.operations() { - let label = Self::gate_label(op); - let char_count: usize = label.chars().count(); - if char_count > max_label_len { - max_label_len = char_count; - } - } - - let width = max_label_len + 2; - if width % 2 == 0 { - width + 1 - } else { - width - } - } -} - -impl<'a> Visualizer for VerticalRenderer<'a> { - fn export(&self) -> String { - format!("{}", self) - } -} - -impl<'a> fmt::Display for VerticalRenderer<'a> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let nq = self.circuit.num_qubits(); - let nc = self.circuit.num_classical(); - let ops = self.circuit.operations(); - - let col_width = self.calculate_col_width(); - let gap_width = 3; - - let q_header: String = (0..nq) - .map(|i| format!("{:^width$}", format!("q{}", i), width = col_width)) - .collect::>() - .join(" "); - - let c_header: String = (0..nc) - .map(|i| format!("{:^width$}", format!("c{}", i), width = col_width)) - .collect::>() - .join(" "); - - if nc > 0 { - writeln!(f, "{}{}{}", q_header, " ".repeat(gap_width), c_header)?; - } else { - writeln!(f, "{}", q_header)?; - } - - let q_wires: String = (0..nq) - .map(|_| format!("{:^width$}", "│", width = col_width)) - .collect::>() - .join(" "); - - let c_wires: String = (0..nc) - .map(|_| format!("{:^width$}", "║", width = col_width)) - .collect::>() - .join(" "); - - let full_wires = if nc > 0 { - format!("{}{}{}", q_wires, " ".repeat(gap_width), c_wires) - } else { - q_wires.clone() - }; - - if ops.is_empty() { - writeln!(f, "{}", full_wires)?; - return Ok(()); - } - - let q_total = nq * col_width + (nq - 1); - let c_total = if nc > 0 { nc * col_width + (nc - 1) } else { 0 }; - let total_width = q_total + gap_width + c_total; - - for op in ops { - writeln!(f, "{}", full_wires)?; - - let q_targets = op.quantum_targets(); - let min_q = q_targets.iter().min().copied().unwrap_or(0); - let max_q = q_targets.iter().max().copied().unwrap_or(0); - - let label = Self::gate_label(op); - - match op { - 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, _, _, _) => { - let mut line: Vec = vec![' '; total_width]; - - for i in 0..nq { - let col_start = i * (col_width + 1); - let center = col_start + col_width / 2; - if i == *t { - let label_start = col_start + (col_width - label.chars().count()) / 2; - for (j, ch) in label.chars().enumerate() { - line[label_start + j] = ch; - } - } else { - line[center] = '│'; - } - } - - for i in 0..nc { - let center = q_total + gap_width + i * (col_width + 1) + col_width / 2; - line[center] = '║'; - } - - let gate_line: String = line.into_iter().collect(); - writeln!(f, "{}", gate_line)?; - } - 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, _) => { - let (sym1, sym2) = match op { - GateOp::CNOT(_, _) => ('●', '⊕'), - GateOp::CZ(_, _) => ('●', '●'), - GateOp::SWAP(_, _) => ('╳', '╳'), - GateOp::CRx(_, _, _) | GateOp::CRy(_, _, _) | GateOp::CRz(_, _, _) | GateOp::CP(_, _, _) => ('●', '□'), - _ => unreachable!(), - }; - - let mut line: Vec = vec![' '; total_width]; - - for i in 0..nq { - let col_start = i * (col_width + 1); - let center = col_start + col_width / 2; - if i < min_q || i > max_q { - line[center] = '│'; - } else if i == *c { - line[center] = sym1; - } else if i == *t { - // For controlled parametric gates, show the gate label on target - if matches!(op, GateOp::CRx(_, _, _) | GateOp::CRy(_, _, _) | GateOp::CRz(_, _, _) | GateOp::CP(_, _, _)) { - let label_start = col_start + (col_width - label.chars().count()) / 2; - for (j, ch) in label.chars().enumerate() { - if label_start + j < line.len() { - line[label_start + j] = ch; - } - } - } else { - line[center] = sym2; - } - } - } - - let min_center = min_q * (col_width + 1) + col_width / 2; - let max_center = max_q * (col_width + 1) + col_width / 2; - for cell in &mut line[(min_center + 1)..max_center] { - if *cell == ' ' { - *cell = '─'; - } - } - - for i in 0..nc { - let center = q_total + gap_width + i * (col_width + 1) + col_width / 2; - line[center] = '║'; - } - - let gate_line: String = line.into_iter().collect(); - writeln!(f, "{}", gate_line)?; - } - GateOp::CCNOT(c1, c2, t) | GateOp::CSWAP(c1, c2, t) => { - let (sym_c, sym_t) = match op { - GateOp::CCNOT(_, _, _) => ('●', '⊕'), - GateOp::CSWAP(_, _, _) => ('●', '╳'), - _ => unreachable!(), - }; - let is_cswap = matches!(op, GateOp::CSWAP(_, _, _)); - - let mut line: Vec = vec![' '; total_width]; - - for i in 0..nq { - let center = i * (col_width + 1) + col_width / 2; - if i < min_q || i > max_q { - line[center] = '│'; - } else if i == *c1 { - line[center] = sym_c; - } else if i == *c2 { - line[center] = if is_cswap { sym_t } else { sym_c }; - } else if i == *t { - line[center] = sym_t; - } - } - - let min_center = min_q * (col_width + 1) + col_width / 2; - let max_center = max_q * (col_width + 1) + col_width / 2; - for cell in &mut line[(min_center + 1)..max_center] { - if *cell == ' ' { - *cell = '─'; - } - } - - for i in 0..nc { - let center = q_total + gap_width + i * (col_width + 1) + col_width / 2; - line[center] = '║'; - } - - let gate_line: String = line.into_iter().collect(); - writeln!(f, "{}", gate_line)?; - } - GateOp::Measure(mq, mc) => { - let mut line: Vec = vec![' '; total_width]; - - for i in 0..nq { - let col_start = i * (col_width + 1); - let center = col_start + col_width / 2; - if i < *mq { - line[center] = '│'; - } else if i == *mq { - let label_start = col_start + (col_width - label.chars().count()) / 2; - for (j, ch) in label.chars().enumerate() { - line[label_start + j] = ch; - } - } - } - - let mq_col_start = *mq * (col_width + 1); - let mq_center = mq_col_start + col_width / 2; - let mc_start = q_total + gap_width; - let mc_center = mc_start + *mc * (col_width + 1) + col_width / 2; - - for cell in &mut line[(mq_center + 2)..=mc_center] { - if *cell == ' ' { - *cell = '═'; - } - } - line[mc_center] = '╣'; - - for i in 0..nc { - let center = mc_start + i * (col_width + 1) + col_width / 2; - if i > *mc { - line[center] = '║'; - } - } - - let measure_line: String = line.into_iter().collect(); - writeln!(f, "{}", measure_line)?; - } - GateOp::Custom(_, targets) => { - let mut line: Vec = vec![' '; total_width]; - - if targets.len() == 1 { - for i in 0..nq { - let col_start = i * (col_width + 1); - let center = col_start + col_width / 2; - if i == targets[0] { - let label_start = - col_start + (col_width - label.chars().count()) / 2; - for (j, ch) in label.chars().enumerate() { - line[label_start + j] = ch; - } - } else { - line[center] = '│'; - } - } - - for i in 0..nc { - let center = q_total + gap_width + i * (col_width + 1) + col_width / 2; - line[center] = '║'; - } - } else { - for i in 0..nq { - let col_start = i * (col_width + 1); - let center = col_start + col_width / 2; - if i < min_q || i > max_q { - line[center] = '│'; - } else if i == targets[0] { - let label_start = - col_start + (col_width - label.chars().count()) / 2; - for (j, ch) in label.chars().enumerate() { - line[label_start + j] = ch; - } - } else if targets.contains(&i) { - line[center] = '□'; - } - } - - let min_center = min_q * (col_width + 1) + col_width / 2; - let max_center = max_q * (col_width + 1) + col_width / 2; - for cell in &mut line[(min_center + 1)..max_center] { - if *cell == ' ' { - *cell = '─'; - } - } - - for i in 0..nc { - let center = q_total + gap_width + i * (col_width + 1) + col_width / 2; - line[center] = '║'; - } - } - - let gate_line: String = line.into_iter().collect(); - writeln!(f, "{}", gate_line)?; - } - } - } - - writeln!(f, "{}", full_wires)?; - - let end_line: String = "░".repeat(total_width); - writeln!(f, "{}", end_line)?; - - Ok(()) - } -} -- cgit v1.3