aboutsummaryrefslogtreecommitdiff
path: root/src/core
diff options
context:
space:
mode:
Diffstat (limited to 'src/core')
-rw-r--r--src/core/classical_components.rs63
-rw-r--r--src/core/custom_gate.rs245
-rw-r--r--src/core/gates.rs253
-rw-r--r--src/core/mod.rs17
-rw-r--r--src/core/noise.rs559
-rw-r--r--src/core/quantum_components.rs318
6 files changed, 0 insertions, 1455 deletions
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<ClassicalBit<'a>>,
- 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<ClassicalBit<'a>> = Vec::new();
- for &name in names {
- bits.push(ClassicalBit::new(name, false));
- }
- ClassicalRegister { name, bits }
- }
-
- pub fn set_bits(&mut self, bits: Vec<ClassicalBit<'a>>) {
- self.bits = bits;
- }
-
- pub fn get_bits(&self) -> Vec<ClassicalBit<'a>> {
- self.bits.clone()
- }
-
- pub fn get_name(&self) -> &'a str {
- self.name
- }
-}
-
-impl<'a> ops::Index<usize> for ClassicalRegister<'a> {
- type Output = ClassicalBit<'a>;
-
- fn index(&self, index: usize) -> &Self::Output {
- &self.bits[index]
- }
-}
-
-impl<'a> ops::IndexMut<usize> 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<Complex<f64>>),
- Composite(Vec<(CompositeOp, Vec<usize>)>),
-}
-
-#[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<Complex<f64>>) -> 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<usize>)>,
- ) -> 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<usize>)]) -> Matrix<Complex<f64>> {
- 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<Complex<f64>>,
- targets: &[usize],
- total_qubits: usize,
-) -> Matrix<Complex<f64>> {
- 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<Complex<f64>>, b: &Matrix<Complex<f64>>) -> Matrix<Complex<f64>> {
- 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<usize>)>,
-}
-
-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<Complex<f64>> {
- 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<Complex<f64>> {
- 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<Complex<f64>> {
- 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<Complex<f64>> {
- 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<Complex<f64>> {
- p_matrix(lambda)
-}
-
-pub fn u2_matrix(phi: f64, lambda: f64) -> Matrix<Complex<f64>> {
- 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<Complex<f64>> {
- 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<Complex<f64>> {
- 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<Complex<f64>> {
- 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<Complex<f64>> {
- 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<Complex<f64>> {
- 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<Complex<f64>>,
- pub name: String,
-}
-
-impl KrausOperator {
- pub fn new(name: &str, matrix: Matrix<Complex<f64>>) -> Self {
- Self {
- matrix,
- name: name.to_string(),
- }
- }
-}
-
-#[derive(Clone, Debug)]
-pub struct NoiseChannel {
- pub name: String,
- pub operators: Vec<KrausOperator>,
- pub num_qubits: usize,
-}
-
-impl NoiseChannel {
- pub fn new(name: &str, operators: Vec<KrausOperator>, 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<Complex<f64>>,
- 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<f64>]) -> 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<f64> {
- self.data[row * self.dim + col]
- }
-
- pub fn set(&mut self, row: usize, col: usize, value: Complex<f64>) {
- self.data[row * self.dim + col] = value;
- }
-
- pub fn trace(&self) -> Complex<f64> {
- 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<f64> {
- (0..self.dim).map(|i| self.get(i, i).real).collect()
- }
-
- pub fn apply_unitary(&mut self, gate: &Matrix<Complex<f64>>, targets: &[usize]) {
- let g = targets.len();
- let gate_dim = 1 << g;
-
- let target_bits: Vec<usize> = 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>]) -> 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<Complex<f64>>;
-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<T: Float>(size: usize) -> Matrix<T> {
- 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<QuantumBit<'a>>,
-}
-
-#[derive(Clone)]
-pub struct QuantumGate<'a> {
- pub name: &'a str,
- pub matrix: Matrix<Complex<f64>>,
- pub num_qubits: usize,
-}
-
-impl<'a> QuantumGate<'a> {
- pub fn new(name: &'a str, matrix: Matrix<Complex<f64>>, 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<Complex<f64>>) -> 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<QuantumBit<'a>> = 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<Matrix<Complex<f64>>> = 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<QuantumBit<'_>> {
- 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<Complex<f64>> {
- 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<Complex<f64>> {
- let n = self.num_qubits();
- let g = gate.num_qubits;
-
- let mut result: Option<Matrix<Complex<f64>>> = None;
-
- for i in 0..n {
- let part: Matrix<Complex<f64>> = 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<usize> for QuantumRegister<'a> {
- type Output = QuantumBit<'a>;
-
- fn index(&self, index: usize) -> &Self::Output {
- &self.qubits[index]
- }
-}
-
-impl<'a> ops::IndexMut<usize> 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)
- }
-}