aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorhachem <im@hachem.wtf>2025-12-10 06:27:29 +0100
committerhachem <im@hachem.wtf>2025-12-10 06:27:29 +0100
commit140daa490485812ef50756796435538b9f6d9428 (patch)
tree635d792ae7d4db123d538ef30304bc65cde739b2
parente77aef153c8676ff90659433ac0ca157a3c585c2 (diff)
[add]: add support for non-clifford gates
-rw-r--r--libpsi-core/src/core/circuit.rs191
-rw-r--r--libpsi-core/src/core/gates.rs126
-rw-r--r--libpsi-core/src/core/runtime.rs160
-rw-r--r--libpsi-visualizer/src/cli/horizontal_cli.rs174
-rw-r--r--libpsi-visualizer/src/cli/vertical_cli.rs47
-rw-r--r--tester/src/benchmarks.rs90
-rw-r--r--tester/src/clifford.rs126
-rw-r--r--tester/src/common.rs171
-rw-r--r--tester/src/custom_gates.rs121
-rw-r--r--tester/src/main.rs524
-rw-r--r--tester/src/non_clifford.rs137
11 files changed, 1370 insertions, 497 deletions
diff --git a/libpsi-core/src/core/circuit.rs b/libpsi-core/src/core/circuit.rs
index 5bb17ff..e5d7847 100644
--- a/libpsi-core/src/core/circuit.rs
+++ b/libpsi-core/src/core/circuit.rs
@@ -1,7 +1,7 @@
use super::{CustomGate, QuantumState, Runtime};
use crate::{format_amplitude, format_probability, Vector};
-use std::sync::Arc;
use core::fmt;
+use std::sync::Arc;
#[derive(Clone)]
pub enum GateOp {
@@ -11,9 +11,24 @@ pub enum GateOp {
Z(usize),
S(usize),
T(usize),
+ Sdg(usize),
+ Tdg(usize),
+ Sx(usize),
+ Sxdg(usize),
+ Rx(usize, f64),
+ Ry(usize, f64),
+ Rz(usize, f64),
+ P(usize, f64),
+ U1(usize, f64),
+ U2(usize, f64, f64),
+ U3(usize, f64, f64, f64),
CNOT(usize, usize),
CZ(usize, usize),
SWAP(usize, usize),
+ CRx(usize, usize, f64),
+ CRy(usize, usize, f64),
+ CRz(usize, usize, f64),
+ CP(usize, usize, f64),
CCNOT(usize, usize, usize),
CSWAP(usize, usize, usize),
Measure(usize, usize),
@@ -29,6 +44,21 @@ impl GateOp {
GateOp::Z(_) => "Z",
GateOp::S(_) => "S",
GateOp::T(_) => "T",
+ GateOp::Sdg(_) => "S†",
+ GateOp::Tdg(_) => "T†",
+ GateOp::Sx(_) => "√X",
+ GateOp::Sxdg(_) => "√X†",
+ GateOp::Rx(_, _) => "Rx",
+ GateOp::Ry(_, _) => "Ry",
+ GateOp::Rz(_, _) => "Rz",
+ GateOp::P(_, _) => "P",
+ GateOp::U1(_, _) => "U1",
+ GateOp::U2(_, _, _) => "U2",
+ GateOp::U3(_, _, _, _) => "U3",
+ GateOp::CRx(_, _, _) => "CRx",
+ GateOp::CRy(_, _, _) => "CRy",
+ GateOp::CRz(_, _, _) => "CRz",
+ GateOp::CP(_, _, _) => "CP",
GateOp::CNOT(_, _) => "CNOT",
GateOp::CZ(_, _) => "CZ",
GateOp::SWAP(_, _) => "SWAP",
@@ -41,8 +71,30 @@ impl GateOp {
pub fn quantum_targets(&self) -> Vec<usize> {
match self {
- GateOp::H(t) | GateOp::X(t) | GateOp::Y(t) | GateOp::Z(t) | GateOp::S(t) | GateOp::T(t) => vec![*t],
- GateOp::CNOT(c, t) | GateOp::CZ(c, t) | GateOp::SWAP(c, t) => vec![*c, *t],
+ GateOp::H(t)
+ | GateOp::X(t)
+ | GateOp::Y(t)
+ | GateOp::Z(t)
+ | GateOp::S(t)
+ | GateOp::T(t)
+ | GateOp::Sdg(t)
+ | GateOp::Tdg(t)
+ | GateOp::Sx(t)
+ | GateOp::Sxdg(t)
+ | GateOp::Rx(t, _)
+ | GateOp::Ry(t, _)
+ | GateOp::Rz(t, _)
+ | GateOp::P(t, _)
+ | GateOp::U1(t, _)
+ | GateOp::U2(t, _, _)
+ | GateOp::U3(t, _, _, _) => vec![*t],
+ GateOp::CNOT(c, t)
+ | GateOp::CZ(c, t)
+ | GateOp::SWAP(c, t)
+ | GateOp::CRx(c, t, _)
+ | GateOp::CRy(c, t, _)
+ | GateOp::CRz(c, t, _)
+ | GateOp::CP(c, t, _) => vec![*c, *t],
GateOp::CCNOT(c1, c2, t) | GateOp::CSWAP(c1, c2, t) => vec![*c1, *c2, *t],
GateOp::Measure(q, _) => vec![*q],
GateOp::Custom(_, targets) => targets.clone(),
@@ -63,6 +115,27 @@ impl GateOp {
pub fn is_custom(&self) -> bool {
matches!(self, GateOp::Custom(_, _))
}
+
+ pub fn is_non_clifford(&self) -> bool {
+ matches!(
+ self,
+ GateOp::T(_)
+ | GateOp::Tdg(_)
+ | GateOp::Sx(_)
+ | GateOp::Sxdg(_)
+ | GateOp::Rx(_, _)
+ | GateOp::Ry(_, _)
+ | GateOp::Rz(_, _)
+ | GateOp::P(_, _)
+ | GateOp::U1(_, _)
+ | GateOp::U2(_, _, _)
+ | GateOp::U3(_, _, _, _)
+ | GateOp::CRx(_, _, _)
+ | GateOp::CRy(_, _, _)
+ | GateOp::CRz(_, _, _)
+ | GateOp::CP(_, _, _)
+ )
+ }
}
pub struct QuantumCircuit {
@@ -164,6 +237,96 @@ impl QuantumCircuit {
self
}
+ pub fn sdg(&mut self, target: usize) -> &mut Self {
+ self.operations.push(GateOp::Sdg(target));
+ self.computed_state = None;
+ self
+ }
+
+ pub fn tdg(&mut self, target: usize) -> &mut Self {
+ self.operations.push(GateOp::Tdg(target));
+ self.computed_state = None;
+ self
+ }
+
+ pub fn sx(&mut self, target: usize) -> &mut Self {
+ self.operations.push(GateOp::Sx(target));
+ self.computed_state = None;
+ self
+ }
+
+ pub fn sxdg(&mut self, target: usize) -> &mut Self {
+ self.operations.push(GateOp::Sxdg(target));
+ self.computed_state = None;
+ self
+ }
+
+ pub fn rx(&mut self, target: usize, theta: f64) -> &mut Self {
+ self.operations.push(GateOp::Rx(target, theta));
+ self.computed_state = None;
+ self
+ }
+
+ pub fn ry(&mut self, target: usize, theta: f64) -> &mut Self {
+ self.operations.push(GateOp::Ry(target, theta));
+ self.computed_state = None;
+ self
+ }
+
+ pub fn rz(&mut self, target: usize, theta: f64) -> &mut Self {
+ self.operations.push(GateOp::Rz(target, theta));
+ self.computed_state = None;
+ self
+ }
+
+ pub fn p(&mut self, target: usize, theta: f64) -> &mut Self {
+ self.operations.push(GateOp::P(target, theta));
+ self.computed_state = None;
+ self
+ }
+
+ pub fn u1(&mut self, target: usize, lambda: f64) -> &mut Self {
+ self.operations.push(GateOp::U1(target, lambda));
+ self.computed_state = None;
+ self
+ }
+
+ pub fn u2(&mut self, target: usize, phi: f64, lambda: f64) -> &mut Self {
+ self.operations.push(GateOp::U2(target, phi, lambda));
+ self.computed_state = None;
+ self
+ }
+
+ pub fn u3(&mut self, target: usize, theta: f64, phi: f64, lambda: f64) -> &mut Self {
+ self.operations.push(GateOp::U3(target, theta, phi, lambda));
+ self.computed_state = None;
+ self
+ }
+
+ pub fn crx(&mut self, control: usize, target: usize, theta: f64) -> &mut Self {
+ self.operations.push(GateOp::CRx(control, target, theta));
+ self.computed_state = None;
+ self
+ }
+
+ pub fn cry(&mut self, control: usize, target: usize, theta: f64) -> &mut Self {
+ self.operations.push(GateOp::CRy(control, target, theta));
+ self.computed_state = None;
+ self
+ }
+
+ pub fn crz(&mut self, control: usize, target: usize, theta: f64) -> &mut Self {
+ self.operations.push(GateOp::CRz(control, target, theta));
+ self.computed_state = None;
+ self
+ }
+
+ pub fn cp(&mut self, control: usize, target: usize, theta: f64) -> &mut Self {
+ self.operations.push(GateOp::CP(control, target, theta));
+ self.computed_state = None;
+ self
+ }
+
pub fn cnot(&mut self, control: usize, target: usize) -> &mut Self {
self.operations.push(GateOp::CNOT(control, target));
self.computed_state = None;
@@ -187,7 +350,8 @@ impl QuantumCircuit {
}
pub fn ccnot(&mut self, control1: usize, control2: usize, target: usize) -> &mut Self {
- self.operations.push(GateOp::CCNOT(control1, control2, target));
+ self.operations
+ .push(GateOp::CCNOT(control1, control2, target));
self.computed_state = None;
self
}
@@ -197,7 +361,8 @@ impl QuantumCircuit {
}
pub fn cswap(&mut self, control: usize, target1: usize, target2: usize) -> &mut Self {
- self.operations.push(GateOp::CSWAP(control, target1, target2));
+ self.operations
+ .push(GateOp::CSWAP(control, target1, target2));
self.computed_state = None;
self
}
@@ -222,13 +387,15 @@ impl QuantumCircuit {
}
pub fn custom(&mut self, gate: &Arc<CustomGate>, targets: &[usize]) -> &mut Self {
- self.operations.push(GateOp::Custom(Arc::clone(gate), targets.to_vec()));
+ self.operations
+ .push(GateOp::Custom(Arc::clone(gate), targets.to_vec()));
self.computed_state = None;
self
}
pub fn apply_custom(&mut self, gate: CustomGate, targets: &[usize]) -> &mut Self {
- self.operations.push(GateOp::Custom(Arc::new(gate), targets.to_vec()));
+ self.operations
+ .push(GateOp::Custom(Arc::new(gate), targets.to_vec()));
self.computed_state = None;
self
}
@@ -268,12 +435,18 @@ impl QuantumCircuit {
impl fmt::Display for QuantumCircuit {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- writeln!(f, "QuantumCircuit ({} qubits, {} classical)", self.num_qubits, self.num_classical)?;
+ writeln!(
+ f,
+ "QuantumCircuit ({} qubits, {} classical)",
+ self.num_qubits, self.num_classical
+ )?;
writeln!(f, "Operations:")?;
for (i, op) in self.operations.iter().enumerate() {
match op {
GateOp::Measure(q, c) => writeln!(f, " {}: {} q{} → c{}", i, op.name(), q, c)?,
- GateOp::Custom(gate, targets) => writeln!(f, " {}: [{}] on {:?}", i, gate.name, targets)?,
+ GateOp::Custom(gate, targets) => {
+ writeln!(f, " {}: [{}] on {:?}", i, gate.name, targets)?
+ }
_ => writeln!(f, " {}: {} on {:?}", i, op.name(), op.quantum_targets())?,
}
}
diff --git a/libpsi-core/src/core/gates.rs b/libpsi-core/src/core/gates.rs
index 4f922a8..cee4ebc 100644
--- a/libpsi-core/src/core/gates.rs
+++ b/libpsi-core/src/core/gates.rs
@@ -1,4 +1,100 @@
-use crate::{complex, matrix, QuantumGate};
+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! {
@@ -45,6 +141,34 @@ lazy_static::lazy_static! {
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)];
diff --git a/libpsi-core/src/core/runtime.rs b/libpsi-core/src/core/runtime.rs
index 7b73c47..0a78f0f 100644
--- a/libpsi-core/src/core/runtime.rs
+++ b/libpsi-core/src/core/runtime.rs
@@ -1,5 +1,10 @@
use super::{GateOp, QuantumGate, QuantumRegister, QuantumState};
-use crate::gates::*;
+use crate::gates::{
+ cp_matrix, crx_matrix, cry_matrix, crz_matrix, p_matrix, rx_matrix, ry_matrix,
+ rz_matrix, u1_matrix, u2_matrix, u3_matrix, CNOT, CZ, FREDKIN, HADAMARD,
+ PAULI_X, PAULI_Y, PAULI_Z, SDG_GATE, SWAP, SXDG_GATE, SX_GATE, S_GATE, TDG_GATE,
+ TOFFOLI, T_GATE,
+};
use crate::maths::vector::Vector;
use crate::{complex, Complex, Matrix};
use rayon::prelude::*;
@@ -48,17 +53,118 @@ impl Runtime {
for op in operations {
match op {
+ // Clifford gates
GateOp::H(t) => register.apply_gate(&HADAMARD, &[*t]),
GateOp::X(t) => register.apply_gate(&PAULI_X, &[*t]),
GateOp::Y(t) => register.apply_gate(&PAULI_Y, &[*t]),
GateOp::Z(t) => register.apply_gate(&PAULI_Z, &[*t]),
GateOp::S(t) => register.apply_gate(&S_GATE, &[*t]),
- GateOp::T(t) => register.apply_gate(&T_GATE, &[*t]),
GateOp::CNOT(c, t) => register.apply_gate(&CNOT, &[*c, *t]),
GateOp::CZ(c, t) => register.apply_gate(&CZ, &[*c, *t]),
GateOp::SWAP(a, b) => register.apply_gate(&SWAP, &[*a, *b]),
GateOp::CCNOT(c1, c2, t) => register.apply_gate(&TOFFOLI, &[*c1, *c2, *t]),
GateOp::CSWAP(c, t1, t2) => register.apply_gate(&FREDKIN, &[*c, *t1, *t2]),
+
+ // Non-Clifford fixed gates
+ GateOp::T(t) => register.apply_gate(&T_GATE, &[*t]),
+ GateOp::Sdg(t) => register.apply_gate(&SDG_GATE, &[*t]),
+ GateOp::Tdg(t) => register.apply_gate(&TDG_GATE, &[*t]),
+ GateOp::Sx(t) => register.apply_gate(&SX_GATE, &[*t]),
+ GateOp::Sxdg(t) => register.apply_gate(&SXDG_GATE, &[*t]),
+
+ // Parametric single-qubit gates (non-Clifford for most angles)
+ GateOp::Rx(t, theta) => {
+ let gate = QuantumGate {
+ name: "Rx",
+ matrix: rx_matrix(*theta),
+ num_qubits: 1,
+ };
+ register.apply_gate(&gate, &[*t]);
+ }
+ GateOp::Ry(t, theta) => {
+ let gate = QuantumGate {
+ name: "Ry",
+ matrix: ry_matrix(*theta),
+ num_qubits: 1,
+ };
+ register.apply_gate(&gate, &[*t]);
+ }
+ GateOp::Rz(t, theta) => {
+ let gate = QuantumGate {
+ name: "Rz",
+ matrix: rz_matrix(*theta),
+ num_qubits: 1,
+ };
+ register.apply_gate(&gate, &[*t]);
+ }
+ GateOp::P(t, theta) => {
+ let gate = QuantumGate {
+ name: "P",
+ matrix: p_matrix(*theta),
+ num_qubits: 1,
+ };
+ register.apply_gate(&gate, &[*t]);
+ }
+ GateOp::U1(t, lambda) => {
+ let gate = QuantumGate {
+ name: "U1",
+ matrix: u1_matrix(*lambda),
+ num_qubits: 1,
+ };
+ register.apply_gate(&gate, &[*t]);
+ }
+ GateOp::U2(t, phi, lambda) => {
+ let gate = QuantumGate {
+ name: "U2",
+ matrix: u2_matrix(*phi, *lambda),
+ num_qubits: 1,
+ };
+ register.apply_gate(&gate, &[*t]);
+ }
+ GateOp::U3(t, theta, phi, lambda) => {
+ let gate = QuantumGate {
+ name: "U3",
+ matrix: u3_matrix(*theta, *phi, *lambda),
+ num_qubits: 1,
+ };
+ register.apply_gate(&gate, &[*t]);
+ }
+
+ // Controlled parametric gates
+ GateOp::CRx(c, t, theta) => {
+ let gate = QuantumGate {
+ name: "CRx",
+ matrix: crx_matrix(*theta),
+ num_qubits: 2,
+ };
+ register.apply_gate(&gate, &[*c, *t]);
+ }
+ GateOp::CRy(c, t, theta) => {
+ let gate = QuantumGate {
+ name: "CRy",
+ matrix: cry_matrix(*theta),
+ num_qubits: 2,
+ };
+ register.apply_gate(&gate, &[*c, *t]);
+ }
+ GateOp::CRz(c, t, theta) => {
+ let gate = QuantumGate {
+ name: "CRz",
+ matrix: crz_matrix(*theta),
+ num_qubits: 2,
+ };
+ register.apply_gate(&gate, &[*c, *t]);
+ }
+ GateOp::CP(c, t, theta) => {
+ let gate = QuantumGate {
+ name: "CP",
+ matrix: cp_matrix(*theta),
+ num_qubits: 2,
+ };
+ register.apply_gate(&gate, &[*c, *t]);
+ }
+
+ // Measurement and custom gates
GateOp::Measure(_, _) => {}
GateOp::Custom(gate, targets) => {
let quantum_gate = gate.to_quantum_gate();
@@ -83,18 +189,42 @@ impl Runtime {
state[0] = complex!(1.0, 0.0);
for op in operations {
- let (gate, targets): (&QuantumGate, Vec<usize>) = match op {
- GateOp::H(t) => (&HADAMARD, vec![*t]),
- GateOp::X(t) => (&PAULI_X, vec![*t]),
- GateOp::Y(t) => (&PAULI_Y, vec![*t]),
- GateOp::Z(t) => (&PAULI_Z, vec![*t]),
- GateOp::S(t) => (&S_GATE, vec![*t]),
- GateOp::T(t) => (&T_GATE, vec![*t]),
- GateOp::CNOT(c, t) => (&CNOT, vec![*c, *t]),
- GateOp::CZ(c, t) => (&CZ, vec![*c, *t]),
- GateOp::SWAP(a, b) => (&SWAP, vec![*a, *b]),
- GateOp::CCNOT(c1, c2, t) => (&TOFFOLI, vec![*c1, *c2, *t]),
- GateOp::CSWAP(c, t1, t2) => (&FREDKIN, vec![*c, *t1, *t2]),
+ let (gate_matrix, targets): (Matrix<Complex<f64>>, Vec<usize>) = match op {
+ // Clifford gates
+ GateOp::H(t) => (HADAMARD.matrix.clone(), vec![*t]),
+ GateOp::X(t) => (PAULI_X.matrix.clone(), vec![*t]),
+ GateOp::Y(t) => (PAULI_Y.matrix.clone(), vec![*t]),
+ GateOp::Z(t) => (PAULI_Z.matrix.clone(), vec![*t]),
+ GateOp::S(t) => (S_GATE.matrix.clone(), vec![*t]),
+ GateOp::CNOT(c, t) => (CNOT.matrix.clone(), vec![*c, *t]),
+ GateOp::CZ(c, t) => (CZ.matrix.clone(), vec![*c, *t]),
+ GateOp::SWAP(a, b) => (SWAP.matrix.clone(), vec![*a, *b]),
+ GateOp::CCNOT(c1, c2, t) => (TOFFOLI.matrix.clone(), vec![*c1, *c2, *t]),
+ GateOp::CSWAP(c, t1, t2) => (FREDKIN.matrix.clone(), vec![*c, *t1, *t2]),
+
+ // Non-Clifford fixed gates
+ GateOp::T(t) => (T_GATE.matrix.clone(), vec![*t]),
+ GateOp::Sdg(t) => (SDG_GATE.matrix.clone(), vec![*t]),
+ GateOp::Tdg(t) => (TDG_GATE.matrix.clone(), vec![*t]),
+ GateOp::Sx(t) => (SX_GATE.matrix.clone(), vec![*t]),
+ GateOp::Sxdg(t) => (SXDG_GATE.matrix.clone(), vec![*t]),
+
+ // Parametric single-qubit gates
+ GateOp::Rx(t, theta) => (rx_matrix(*theta), vec![*t]),
+ GateOp::Ry(t, theta) => (ry_matrix(*theta), vec![*t]),
+ GateOp::Rz(t, theta) => (rz_matrix(*theta), vec![*t]),
+ GateOp::P(t, theta) => (p_matrix(*theta), vec![*t]),
+ GateOp::U1(t, lambda) => (u1_matrix(*lambda), vec![*t]),
+ GateOp::U2(t, phi, lambda) => (u2_matrix(*phi, *lambda), vec![*t]),
+ GateOp::U3(t, theta, phi, lambda) => (u3_matrix(*theta, *phi, *lambda), vec![*t]),
+
+ // Controlled parametric gates
+ GateOp::CRx(c, t, theta) => (crx_matrix(*theta), vec![*c, *t]),
+ GateOp::CRy(c, t, theta) => (cry_matrix(*theta), vec![*c, *t]),
+ GateOp::CRz(c, t, theta) => (crz_matrix(*theta), vec![*c, *t]),
+ GateOp::CP(c, t, theta) => (cp_matrix(*theta), vec![*c, *t]),
+
+ // Measurement (skip) and custom gates
GateOp::Measure(_, _) => continue,
GateOp::Custom(custom_gate, tgts) => {
let quantum_gate = custom_gate.to_quantum_gate();
@@ -103,7 +233,7 @@ impl Runtime {
}
};
- state = apply_gate_parallel(&state, &gate.matrix, &targets, num_qubits);
+ state = apply_gate_parallel(&state, &gate_matrix, &targets, num_qubits);
}
QuantumState::new(state)
diff --git a/libpsi-visualizer/src/cli/horizontal_cli.rs b/libpsi-visualizer/src/cli/horizontal_cli.rs
index bac0c5e..f1a6ba4 100644
--- a/libpsi-visualizer/src/cli/horizontal_cli.rs
+++ b/libpsi-visualizer/src/cli/horizontal_cli.rs
@@ -144,6 +144,180 @@ impl<'a> fmt::Display for HorizontalRenderer<'a> {
}
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 {
diff --git a/libpsi-visualizer/src/cli/vertical_cli.rs b/libpsi-visualizer/src/cli/vertical_cli.rs
index 317833c..6698961 100644
--- a/libpsi-visualizer/src/cli/vertical_cli.rs
+++ b/libpsi-visualizer/src/cli/vertical_cli.rs
@@ -19,6 +19,21 @@ impl<'a> VerticalRenderer<'a> {
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(),
@@ -121,7 +136,18 @@ impl<'a> fmt::Display for VerticalRenderer<'a> {
| GateOp::Y(t)
| GateOp::Z(t)
| GateOp::S(t)
- | GateOp::T(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<char> = vec![' '; total_width];
for i in 0..nq {
@@ -145,24 +171,37 @@ impl<'a> fmt::Display for VerticalRenderer<'a> {
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::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<char> = vec![' '; total_width];
for i in 0..nq {
- let center = i * (col_width + 1) + col_width / 2;
+ 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 {
- line[center] = sym2;
+ // 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;
+ }
}
}
diff --git a/tester/src/benchmarks.rs b/tester/src/benchmarks.rs
new file mode 100644
index 0000000..0a88502
--- /dev/null
+++ b/tester/src/benchmarks.rs
@@ -0,0 +1,90 @@
+use crate::common::{benchmark_circuit, print_section, BenchmarkResult};
+use libpsi_core::QuantumCircuit;
+use libpsi_visualizer::HorizontalRenderer;
+
+pub fn run_all(results: &mut Vec<BenchmarkResult>) {
+ println!("═══════════════════════════════════════════════════════════════");
+ println!(" BENCHMARK CIRCUITS");
+ println!("═══════════════════════════════════════════════════════════════\n");
+
+ test_8_qubit(results);
+ test_10_qubit(results);
+ test_12_qubit(results);
+ test_14_qubit(results);
+}
+
+pub fn test_8_qubit(results: &mut Vec<BenchmarkResult>) {
+ print_section("8-qubit Entangled Circuit");
+
+ let builder = || {
+ let mut circuit = QuantumCircuit::new(8);
+ for i in 0..8 {
+ circuit.h(i);
+ }
+ for i in 0..7 {
+ circuit.cnot(i, i + 1);
+ }
+ circuit
+ };
+
+ println!("{}", HorizontalRenderer::new(&builder()));
+ results.push(benchmark_circuit("8-qubit entangled", builder));
+}
+
+pub fn test_10_qubit(results: &mut Vec<BenchmarkResult>) {
+ print_section("10-qubit Entangled Circuit");
+
+ let builder = || {
+ let mut circuit = QuantumCircuit::new(10);
+ for i in 0..10 {
+ circuit.h(i);
+ }
+ for i in 0..9 {
+ circuit.cnot(i, i + 1);
+ }
+ circuit.cz(0, 9);
+ circuit
+ };
+
+ println!("{}", HorizontalRenderer::new(&builder()));
+ results.push(benchmark_circuit("10-qubit entangled", builder));
+}
+
+pub fn test_12_qubit(results: &mut Vec<BenchmarkResult>) {
+ print_section("12-qubit Entangled Circuit");
+
+ let builder = || {
+ let mut circuit = QuantumCircuit::new(12);
+ for i in 0..12 {
+ circuit.h(i);
+ }
+ for i in 0..11 {
+ circuit.cnot(i, i + 1);
+ }
+ circuit.cz(0, 11);
+ circuit.swap(5, 6);
+ circuit
+ };
+
+ println!("{}", HorizontalRenderer::new(&builder()));
+ results.push(benchmark_circuit("12-qubit entangled", builder));
+}
+
+pub fn test_14_qubit(results: &mut Vec<BenchmarkResult>) {
+ print_section("14-qubit Entangled Circuit");
+
+ let builder = || {
+ let mut circuit = QuantumCircuit::new(14);
+ for i in 0..14 {
+ circuit.h(i);
+ }
+ for i in 0..13 {
+ circuit.cnot(i, i + 1);
+ }
+ circuit
+ };
+
+ println!("{}", HorizontalRenderer::new(&builder()));
+ results.push(benchmark_circuit("14-qubit entangled", builder));
+}
+
diff --git a/tester/src/clifford.rs b/tester/src/clifford.rs
new file mode 100644
index 0000000..5c0b453
--- /dev/null
+++ b/tester/src/clifford.rs
@@ -0,0 +1,126 @@
+use crate::common::{benchmark_circuit, print_circuit, print_section, BenchmarkResult};
+use libpsi_core::QuantumCircuit;
+
+pub fn run_all(results: &mut Vec<BenchmarkResult>) {
+ println!("═══════════════════════════════════════════════════════════════");
+ println!(" CLIFFORD GATES TESTS");
+ println!("═══════════════════════════════════════════════════════════════\n");
+
+ test_bell_state(results);
+ test_ghz_state(results);
+ test_swap_via_cnots(results);
+ test_toffoli(results);
+ test_hadamard_measure(results);
+ test_complex_circuit(results);
+}
+
+pub fn test_bell_state(results: &mut Vec<BenchmarkResult>) {
+ print_section("Bell State with Measurement");
+
+ let builder = || {
+ let mut circuit = QuantumCircuit::with_classical(2, 2);
+ circuit.h(0).cnot(0, 1).measure(0, 0).measure(1, 1);
+ circuit
+ };
+
+ print_circuit(&builder());
+ results.push(benchmark_circuit("Bell State (2 qubits)", builder));
+
+ let mut display = builder();
+ display.compute();
+ println!("{}\n", display);
+}
+
+pub fn test_ghz_state(results: &mut Vec<BenchmarkResult>) {
+ print_section("GHZ State");
+
+ let builder = || {
+ let mut circuit = QuantumCircuit::new(3);
+ circuit.h(0).cnot(0, 1).cnot(0, 2);
+ circuit
+ };
+
+ print_circuit(&builder());
+ results.push(benchmark_circuit("GHZ State (3 qubits)", builder));
+
+ let mut display = builder();
+ display.compute();
+ println!("{}\n", display);
+}
+
+pub fn test_swap_via_cnots(results: &mut Vec<BenchmarkResult>) {
+ print_section("SWAP via 3 CNOTs");
+
+ let builder = || {
+ let mut circuit = QuantumCircuit::new(2);
+ circuit.x(0).cnot(0, 1).cnot(1, 0).cnot(0, 1);
+ circuit
+ };
+
+ print_circuit(&builder());
+ results.push(benchmark_circuit("SWAP via CNOTs (2 qubits)", builder));
+
+ let mut display = builder();
+ display.compute();
+ println!("{}\n", display);
+}
+
+pub fn test_toffoli(results: &mut Vec<BenchmarkResult>) {
+ print_section("Toffoli Gate");
+
+ let builder = || {
+ let mut circuit = QuantumCircuit::new(3);
+ circuit.x(0).x(1).toffoli(0, 1, 2);
+ circuit
+ };
+
+ print_circuit(&builder());
+ results.push(benchmark_circuit("Toffoli (3 qubits)", builder));
+
+ let mut display = builder();
+ display.compute();
+ println!("{}\n", display);
+}
+
+pub fn test_hadamard_measure(results: &mut Vec<BenchmarkResult>) {
+ print_section("Full Circuit with Measurements");
+
+ let builder = || {
+ let mut circuit = QuantumCircuit::with_classical(3, 3);
+ circuit.h(0).h(1).h(2).measure_all();
+ circuit
+ };
+
+ print_circuit(&builder());
+ results.push(benchmark_circuit("3-qubit Hadamard + Measure", builder));
+
+ let mut display = builder();
+ display.compute();
+ println!("{}\n", display);
+}
+
+pub fn test_complex_circuit(results: &mut Vec<BenchmarkResult>) {
+ print_section("Complex Circuit");
+
+ let builder = || {
+ let mut circuit = QuantumCircuit::with_classical(4, 2);
+ circuit
+ .h(0)
+ .h(1)
+ .cnot(0, 2)
+ .cnot(1, 3)
+ .cz(2, 3)
+ .swap(0, 1)
+ .measure(0, 0)
+ .measure(1, 1);
+ circuit
+ };
+
+ print_circuit(&builder());
+ results.push(benchmark_circuit("Complex (4 qubits)", builder));
+
+ let mut display = builder();
+ display.compute();
+ println!("{}\n", display);
+}
+
diff --git a/tester/src/common.rs b/tester/src/common.rs
new file mode 100644
index 0000000..90eabd8
--- /dev/null
+++ b/tester/src/common.rs
@@ -0,0 +1,171 @@
+use libpsi_core::{QuantumCircuit, QuantumState, Runtime, Vector};
+use libpsi_visualizer::{HorizontalRenderer, VerticalRenderer};
+use std::time::{Duration, Instant};
+
+pub struct BenchmarkResult {
+ pub name: String,
+ pub basic_time: Duration,
+ pub mt_time: Duration,
+ pub results_match: bool,
+}
+
+pub fn benchmark_circuit<F>(name: &str, circuit_builder: F) -> BenchmarkResult
+where
+ F: Fn() -> QuantumCircuit,
+{
+ let mut circuit_st = circuit_builder();
+ let mut circuit_mt = circuit_builder();
+
+ let start_st = Instant::now();
+ circuit_st.compute_with(Runtime::BasicRT);
+ let basic_time = start_st.elapsed();
+
+ let start_mt = Instant::now();
+ circuit_mt.compute_with(Runtime::BasicRTMT);
+ let mt_time = start_mt.elapsed();
+
+ let state_st = circuit_st.state();
+ let state_mt = circuit_mt.state();
+
+ let results_match = states_equal(state_st, state_mt);
+
+ BenchmarkResult {
+ name: name.to_string(),
+ basic_time,
+ mt_time,
+ results_match,
+ }
+}
+
+pub fn states_equal(a: &QuantumState, b: &QuantumState) -> bool {
+ if a.size() != b.size() {
+ return false;
+ }
+ for i in 0..a.size() {
+ let amp_a = a.get(i);
+ let amp_b = b.get(i);
+ let diff_real = (amp_a.real - amp_b.real).abs();
+ let diff_imag = (amp_a.imaginary - amp_b.imaginary).abs();
+ if diff_real > 1e-10 || diff_imag > 1e-10 {
+ return false;
+ }
+ }
+ true
+}
+
+pub fn format_duration(d: Duration) -> String {
+ if d.as_secs() > 0 {
+ format!("{:.3}s", d.as_secs_f64())
+ } else if d.as_millis() > 0 {
+ format!("{:.3}ms", d.as_secs_f64() * 1000.0)
+ } else {
+ format!("{:.3}us", d.as_secs_f64() * 1_000_000.0)
+ }
+}
+
+pub fn print_section(title: &str) {
+ let width = 61;
+ let padding = width - title.len() - 2;
+ println!("┌{}┐", "─".repeat(width));
+ println!("│ {}{} │", title, " ".repeat(padding));
+ println!("└{}┘\n", "─".repeat(width));
+}
+
+pub fn print_circuit(circuit: &QuantumCircuit) {
+ println!("Horizontal:\n{}", HorizontalRenderer::new(circuit));
+ println!("Vertical:\n{}", VerticalRenderer::new(circuit));
+}
+
+pub fn print_benchmark_table(results: &[BenchmarkResult]) {
+ const C1: usize = 30;
+ const C2: usize = 12;
+ const C3: usize = 12;
+ const C4: usize = 10;
+ const C5: usize = 5;
+
+ let top = format!(
+ "╔{}═{}═{}═{}═{}╗",
+ "═".repeat(C1 + 2),
+ "═".repeat(C2 + 2),
+ "═".repeat(C3 + 2),
+ "═".repeat(C4 + 2),
+ "═".repeat(C5 + 2)
+ );
+ let title = format!(
+ "╠{}╤{}╤{}╤{}╤{}╣",
+ "═".repeat(C1 + 2),
+ "═".repeat(C2 + 2),
+ "═".repeat(C3 + 2),
+ "═".repeat(C4 + 2),
+ "═".repeat(C5 + 2)
+ );
+ let header = format!(
+ "╠{}╪{}╪{}╪{}╪{}╣",
+ "═".repeat(C1 + 2),
+ "═".repeat(C2 + 2),
+ "═".repeat(C3 + 2),
+ "═".repeat(C4 + 2),
+ "═".repeat(C5 + 2)
+ );
+ let bottom = format!(
+ "╚{}╧{}╧{}╧{}╧{}╝",
+ "═".repeat(C1 + 2),
+ "═".repeat(C2 + 2),
+ "═".repeat(C3 + 2),
+ "═".repeat(C4 + 2),
+ "═".repeat(C5 + 2)
+ );
+
+ let total_width = C1 + C2 + C3 + C4 + C5 + 14;
+
+ println!("\n{}", top);
+ println!(
+ "║{:^width$}║",
+ "RUNTIME BENCHMARK RESULTS",
+ width = total_width
+ );
+ println!("{}", title);
+ println!(
+ "║ {:<C1$} │ {:^C2$} │ {:^C3$} │ {:^C4$} │ {:^C5$} ║",
+ "Circuit", "BasicRT", "BasicRTMT", "Speedup", "Match",
+ );
+ println!("{}", header);
+
+ for r in results {
+ let speedup = r.basic_time.as_secs_f64() / r.mt_time.as_secs_f64();
+ let speedup_str = format!("{:.2}x", speedup);
+ let match_str = if r.results_match { "✓" } else { "✗" };
+
+ println!(
+ "║ {:<C1$} │ {:>C2$} │ {:>C3$} │ {:>C4$} │ {:^C5$} ║",
+ r.name,
+ format_duration(r.basic_time),
+ format_duration(r.mt_time),
+ speedup_str,
+ match_str,
+ );
+ }
+
+ println!("{}", bottom);
+}
+
+pub fn print_summary(results: &[BenchmarkResult]) {
+ let all_match = results.iter().all(|r| r.results_match);
+ println!("\n");
+ if all_match {
+ println!("✓ All circuits produced identical results with both runtimes!");
+ } else {
+ println!("✗ WARNING: Some circuits produced different results!");
+ }
+
+ let total_basic: Duration = results.iter().map(|r| r.basic_time).sum();
+ let total_mt: Duration = results.iter().map(|r| r.mt_time).sum();
+ let overall_speedup = total_basic.as_secs_f64() / total_mt.as_secs_f64();
+
+ println!(
+ "\nTotal time - BasicRT: {} | BasicRTMT: {} | Overall speedup: {:.2}x",
+ format_duration(total_basic),
+ format_duration(total_mt),
+ overall_speedup
+ );
+}
diff --git a/tester/src/custom_gates.rs b/tester/src/custom_gates.rs
new file mode 100644
index 0000000..0e21614
--- /dev/null
+++ b/tester/src/custom_gates.rs
@@ -0,0 +1,121 @@
+use crate::common::{benchmark_circuit, print_circuit, print_section, BenchmarkResult};
+use libpsi_core::{complex, matrix, CustomGate, CustomGateBuilder, QuantumCircuit};
+
+pub fn run_all(results: &mut Vec<BenchmarkResult>) {
+ println!("═══════════════════════════════════════════════════════════════");
+ println!(" CUSTOM GATES TESTS");
+ println!("═══════════════════════════════════════════════════════════════\n");
+
+ test_bell_gate(results);
+ test_swap_gate(results);
+ test_sqrt_x_gate(results);
+}
+
+pub fn test_bell_gate(results: &mut Vec<BenchmarkResult>) {
+ print_section("Custom Gate: Bell Pair Creator");
+
+ let bell_gate = CustomGateBuilder::new("BELL", 2).h(0).cnot(0, 1).build();
+ let gate_clone = bell_gate.clone();
+
+ let builder = move || {
+ let mut circuit = QuantumCircuit::new(4);
+ circuit
+ .apply_custom(gate_clone.clone(), &[0, 1])
+ .apply_custom(gate_clone.clone(), &[2, 3]);
+ circuit
+ };
+
+ let display_circuit = {
+ let mut circuit = QuantumCircuit::new(4);
+ circuit
+ .apply_custom(bell_gate.clone(), &[0, 1])
+ .apply_custom(bell_gate.clone(), &[2, 3]);
+ circuit
+ };
+ print_circuit(&display_circuit);
+ results.push(benchmark_circuit("Custom BELL (4 qubits)", builder));
+
+ let mut display = {
+ let mut circuit = QuantumCircuit::new(4);
+ circuit
+ .apply_custom(bell_gate.clone(), &[0, 1])
+ .apply_custom(bell_gate.clone(), &[2, 3]);
+ circuit
+ };
+ display.compute();
+ println!("{}\n", display);
+}
+
+pub fn test_swap_gate(results: &mut Vec<BenchmarkResult>) {
+ print_section("Custom Gate: Swap via CNOTs");
+
+ let swap_gate = CustomGateBuilder::new("MYSWAP", 2)
+ .cnot(0, 1)
+ .cnot(1, 0)
+ .cnot(0, 1)
+ .build();
+ let gate_clone = swap_gate.clone();
+
+ let builder = move || {
+ let mut circuit = QuantumCircuit::new(2);
+ circuit.x(0).apply_custom(gate_clone.clone(), &[0, 1]);
+ circuit
+ };
+
+ let display_circuit = {
+ let mut circuit = QuantumCircuit::new(2);
+ circuit.x(0).apply_custom(swap_gate.clone(), &[0, 1]);
+ circuit
+ };
+ print_circuit(&display_circuit);
+ results.push(benchmark_circuit("Custom SWAP (2 qubits)", builder));
+
+ let mut display = {
+ let mut circuit = QuantumCircuit::new(2);
+ circuit.x(0).apply_custom(swap_gate.clone(), &[0, 1]);
+ circuit
+ };
+ display.compute();
+ println!("{}\n", display);
+}
+
+pub fn test_sqrt_x_gate(results: &mut Vec<BenchmarkResult>) {
+ print_section("Custom Gate: Matrix-defined √X gate");
+
+ let sqrt_x_matrix = matrix!(
+ [complex!(0.5, 0.5), complex!(0.5, -0.5)];
+ [complex!(0.5, -0.5), complex!(0.5, 0.5)]
+ );
+ let sqrt_x = CustomGate::from_matrix("√X", sqrt_x_matrix);
+ let gate_clone = sqrt_x.clone();
+
+ let builder = move || {
+ let mut circuit = QuantumCircuit::new(1);
+ circuit
+ .apply_custom(gate_clone.clone(), &[0])
+ .apply_custom(gate_clone.clone(), &[0]);
+ circuit
+ };
+
+ let display_circuit = {
+ let mut circuit = QuantumCircuit::new(1);
+ circuit
+ .apply_custom(sqrt_x.clone(), &[0])
+ .apply_custom(sqrt_x.clone(), &[0]);
+ circuit
+ };
+ print_circuit(&display_circuit);
+ results.push(benchmark_circuit("√X gate (1 qubit)", builder));
+
+ let mut display = {
+ let mut circuit = QuantumCircuit::new(1);
+ circuit
+ .apply_custom(sqrt_x.clone(), &[0])
+ .apply_custom(sqrt_x.clone(), &[0]);
+ circuit
+ };
+ display.compute();
+ println!("{}", display);
+ println!("(Two √X gates should equal X, so |0⟩ becomes |1⟩)\n");
+}
+
diff --git a/tester/src/main.rs b/tester/src/main.rs
index 660dc2b..ac0a61f 100644
--- a/tester/src/main.rs
+++ b/tester/src/main.rs
@@ -1,487 +1,75 @@
-use libpsi_core::*;
-use libpsi_visualizer::*;
-use std::time::{Duration, Instant};
+mod benchmarks;
+mod clifford;
+mod common;
+mod custom_gates;
+mod non_clifford;
-struct BenchmarkResult {
- name: String,
- basic_time: Duration,
- mt_time: Duration,
- results_match: bool,
-}
-
-fn benchmark_circuit<F>(name: &str, circuit_builder: F) -> BenchmarkResult
-where
- F: Fn() -> QuantumCircuit,
-{
- let mut circuit_st = circuit_builder();
- let mut circuit_mt = circuit_builder();
-
- let start_st = Instant::now();
- circuit_st.compute_with(Runtime::BasicRT);
- let basic_time = start_st.elapsed();
-
- let start_mt = Instant::now();
- circuit_mt.compute_with(Runtime::BasicRTMT);
- let mt_time = start_mt.elapsed();
-
- let state_st = circuit_st.state();
- let state_mt = circuit_mt.state();
-
- let results_match = states_equal(state_st, state_mt);
-
- BenchmarkResult {
- name: name.to_string(),
- basic_time,
- mt_time,
- results_match,
- }
-}
+use common::{print_benchmark_table, print_summary, BenchmarkResult};
+use std::env;
-fn states_equal(a: &QuantumState, b: &QuantumState) -> bool {
- use crate::maths::vector::Vector;
- if a.size() != b.size() {
- return false;
- }
- for i in 0..a.size() {
- let amp_a = a.get(i);
- let amp_b = b.get(i);
- let diff_real = (amp_a.real - amp_b.real).abs();
- let diff_imag = (amp_a.imaginary - amp_b.imaginary).abs();
- if diff_real > 1e-10 || diff_imag > 1e-10 {
- return false;
- }
- }
- true
+fn print_header() {
+ println!("═══════════════════════════════════════════════════════════════");
+ println!(" PSI Quantum Simulator");
+ println!("═══════════════════════════════════════════════════════════════\n");
}
-fn format_duration(d: Duration) -> String {
- if d.as_secs() > 0 {
- format!("{:.3}s", d.as_secs_f64())
- } else if d.as_millis() > 0 {
- format!("{:.3}ms", d.as_secs_f64() * 1000.0)
- } else {
- format!("{:.3}us", d.as_secs_f64() * 1_000_000.0)
- }
+fn print_usage() {
+ println!("Usage: tester [OPTIONS]");
+ println!();
+ println!("Options:");
+ println!(" all Run all tests (default)");
+ println!(" clifford Run Clifford gate tests only");
+ println!(" non-clifford Run non-Clifford gate tests only");
+ println!(" custom Run custom gate tests only");
+ println!(" bench Run benchmark tests only");
+ println!(" help Show this help message");
+ println!();
+ println!("Examples:");
+ println!(" tester # Run all tests");
+ println!(" tester clifford # Run only Clifford gate tests");
+ println!(" tester non-clifford # Run only rotation/parametric gate tests");
+ println!(" tester custom bench # Run custom gates and benchmarks");
}
-fn print_benchmark_table(results: &[BenchmarkResult]) {
- // Column widths (content only, not including borders)
- const C1: usize = 30; // Circuit name
- const C2: usize = 12; // BasicRT
- const C3: usize = 12; // BasicRTMT
- const C4: usize = 10; // Speedup
- const C5: usize = 5; // Match
-
- let top = format!(
- "╔{}═{}═{}═{}═{}╗",
- "═".repeat(C1 + 2),
- "═".repeat(C2 + 2),
- "═".repeat(C3 + 2),
- "═".repeat(C4 + 2),
- "═".repeat(C5 + 2)
- );
- let title = format!(
- "╠{}╤{}╤{}╤{}╤{}╣",
- "═".repeat(C1 + 2),
- "═".repeat(C2 + 2),
- "═".repeat(C3 + 2),
- "═".repeat(C4 + 2),
- "═".repeat(C5 + 2)
- );
- let header = format!(
- "╠{}╪{}╪{}╪{}╪{}╣",
- "═".repeat(C1 + 2),
- "═".repeat(C2 + 2),
- "═".repeat(C3 + 2),
- "═".repeat(C4 + 2),
- "═".repeat(C5 + 2)
- );
- let bottom = format!(
- "╚{}╧{}╧{}╧{}╧{}╝",
- "═".repeat(C1 + 2),
- "═".repeat(C2 + 2),
- "═".repeat(C3 + 2),
- "═".repeat(C4 + 2),
- "═".repeat(C5 + 2)
- );
-
- let total_width = C1 + C2 + C3 + C4 + C5 + 14;
-
- println!("\n{}", top);
- println!(
- "║{:^width$}║",
- "RUNTIME BENCHMARK RESULTS",
- width = total_width
- );
- println!("{}", title);
- println!(
- "║ {:<C1$} │ {:^C2$} │ {:^C3$} │ {:^C4$} │ {:^C5$} ║",
- "Circuit",
- "BasicRT",
- "BasicRTMT",
- "Speedup",
- "Match",
- C1 = C1,
- C2 = C2,
- C3 = C3,
- C4 = C4,
- C5 = C5
- );
- println!("{}", header);
-
- for r in results {
- let speedup = r.basic_time.as_secs_f64() / r.mt_time.as_secs_f64();
- let speedup_str = format!("{:.2}x", speedup);
- let match_str = if r.results_match { "✓" } else { "✗" };
+fn main() {
+ let args: Vec<String> = env::args().skip(1).collect();
- println!(
- "║ {:<C1$} │ {:>C2$} │ {:>C3$} │ {:>C4$} │ {:^C5$} ║",
- r.name,
- format_duration(r.basic_time),
- format_duration(r.mt_time),
- speedup_str,
- match_str,
- C1 = C1,
- C2 = C2,
- C3 = C3,
- C4 = C4,
- C5 = C5
- );
+ if args
+ .iter()
+ .any(|a| a == "help" || a == "--help" || a == "-h")
+ {
+ print_usage();
+ return;
}
- println!("{}", bottom);
-}
-
-fn main() {
- println!("═══════════════════════════════════════════════════════════════");
- println!(" PSI Quantum Simulator");
- println!("═══════════════════════════════════════════════════════════════\n");
+ print_header();
let mut results: Vec<BenchmarkResult> = Vec::new();
- println!("┌─────────────────────────────────────────────────────────────┐");
- println!("│ Bell State with Measurement │");
- println!("└─────────────────────────────────────────────────────────────┘\n");
-
- let bell_builder = || {
- let mut circuit = QuantumCircuit::with_classical(2, 2);
- circuit.h(0).cnot(0, 1).measure(0, 0).measure(1, 1);
- circuit
- };
-
- let bell = bell_builder();
- println!("Horizontal:\n{}", HorizontalRenderer::new(&bell));
- println!("Vertical:\n{}", VerticalRenderer::new(&bell));
-
- results.push(benchmark_circuit("Bell State (2 qubits)", bell_builder));
- let mut bell_display = bell_builder();
- bell_display.compute();
- println!("{}\n", bell_display);
-
- println!("┌─────────────────────────────────────────────────────────────┐");
- println!("│ GHZ State │");
- println!("└─────────────────────────────────────────────────────────────┘\n");
-
- let ghz_builder = || {
- let mut circuit = QuantumCircuit::new(3);
- circuit.h(0).cnot(0, 1).cnot(0, 2);
- circuit
- };
-
- let ghz = ghz_builder();
- println!("Horizontal:\n{}", HorizontalRenderer::new(&ghz));
- println!("Vertical:\n{}", VerticalRenderer::new(&ghz));
-
- results.push(benchmark_circuit("GHZ State (3 qubits)", ghz_builder));
- let mut ghz_display = ghz_builder();
- ghz_display.compute();
- println!("{}\n", ghz_display);
-
- println!("┌─────────────────────────────────────────────────────────────┐");
- println!("│ SWAP via 3 CNOTs │");
- println!("└─────────────────────────────────────────────────────────────┘\n");
-
- let swap_builder = || {
- let mut circuit = QuantumCircuit::new(2);
- circuit.x(0).cnot(0, 1).cnot(1, 0).cnot(0, 1);
- circuit
- };
-
- let swap_circuit = swap_builder();
- println!("Horizontal:\n{}", HorizontalRenderer::new(&swap_circuit));
- println!("Vertical:\n{}", VerticalRenderer::new(&swap_circuit));
+ let run_all = args.is_empty() || args.iter().any(|a| a == "all");
+ let run_clifford = run_all || args.iter().any(|a| a == "clifford");
+ let run_non_clifford = run_all || args.iter().any(|a| a == "non-clifford");
+ let run_custom = run_all || args.iter().any(|a| a == "custom");
+ let run_bench = run_all || args.iter().any(|a| a == "bench");
- results.push(benchmark_circuit("SWAP via CNOTs (2 qubits)", swap_builder));
- let mut swap_display = swap_builder();
- swap_display.compute();
- println!("{}\n", swap_display);
-
- println!("┌─────────────────────────────────────────────────────────────┐");
- println!("│ Toffoli Gate │");
- println!("└─────────────────────────────────────────────────────────────┘\n");
-
- let toffoli_builder = || {
- let mut circuit = QuantumCircuit::new(3);
- circuit.x(0).x(1).toffoli(0, 1, 2);
- circuit
- };
-
- let toffoli = toffoli_builder();
- println!("Horizontal:\n{}", HorizontalRenderer::new(&toffoli));
- println!("Vertical:\n{}", VerticalRenderer::new(&toffoli));
-
- results.push(benchmark_circuit("Toffoli (3 qubits)", toffoli_builder));
- let mut toffoli_display = toffoli_builder();
- toffoli_display.compute();
- println!("{}\n", toffoli_display);
-
- println!("┌─────────────────────────────────────────────────────────────┐");
- println!("│ Full Circuit with Measurements │");
- println!("└─────────────────────────────────────────────────────────────┘\n");
-
- let full_builder = || {
- let mut circuit = QuantumCircuit::with_classical(3, 3);
- circuit.h(0).h(1).h(2).measure_all();
- circuit
- };
-
- let full = full_builder();
- println!("Horizontal:\n{}", HorizontalRenderer::new(&full));
- println!("Vertical:\n{}", VerticalRenderer::new(&full));
-
- results.push(benchmark_circuit(
- "3-qubit Hadamard + Measure",
- full_builder,
- ));
- let mut full_display = full_builder();
- full_display.compute();
- println!("{}\n", full_display);
-
- println!("┌─────────────────────────────────────────────────────────────┐");
- println!("│ Complex Circuit │");
- println!("└─────────────────────────────────────────────────────────────┘\n");
-
- let complex_builder = || {
- let mut circuit = QuantumCircuit::with_classical(4, 2);
- circuit
- .h(0)
- .h(1)
- .cnot(0, 2)
- .cnot(1, 3)
- .cz(2, 3)
- .swap(0, 1)
- .measure(0, 0)
- .measure(1, 1);
- circuit
- };
-
- let complex = complex_builder();
- println!("Horizontal:\n{}", HorizontalRenderer::new(&complex));
- println!("Vertical:\n{}", VerticalRenderer::new(&complex));
-
- results.push(benchmark_circuit("Complex (4 qubits)", complex_builder));
- let mut complex_display = complex_builder();
- complex_display.compute();
- println!("{}\n", complex_display);
-
- println!("┌─────────────────────────────────────────────────────────────┐");
- println!("│ Custom Gate: Bell Pair Creator │");
- println!("└─────────────────────────────────────────────────────────────┘\n");
-
- let bell_gate = CustomGateBuilder::new("BELL", 2).h(0).cnot(0, 1).build();
- let bell_gate_clone = bell_gate.clone();
-
- let custom_bell_builder = move || {
- let mut circuit = QuantumCircuit::new(4);
- circuit
- .apply_custom(bell_gate_clone.clone(), &[0, 1])
- .apply_custom(bell_gate_clone.clone(), &[2, 3]);
- circuit
- };
-
- let custom_bell = {
- let mut circuit = QuantumCircuit::new(4);
- circuit
- .apply_custom(bell_gate.clone(), &[0, 1])
- .apply_custom(bell_gate.clone(), &[2, 3]);
- circuit
- };
- println!("Horizontal:\n{}", HorizontalRenderer::new(&custom_bell));
- println!("Vertical:\n{}", VerticalRenderer::new(&custom_bell));
-
- results.push(benchmark_circuit(
- "Custom BELL (4 qubits)",
- custom_bell_builder,
- ));
- let mut custom_bell_display = {
- let mut circuit = QuantumCircuit::new(4);
- circuit
- .apply_custom(bell_gate.clone(), &[0, 1])
- .apply_custom(bell_gate.clone(), &[2, 3]);
- circuit
- };
- custom_bell_display.compute();
- println!("{}\n", custom_bell_display);
-
- println!("┌─────────────────────────────────────────────────────────────┐");
- println!("│ Custom Gate: Swap via CNOTs │");
- println!("└─────────────────────────────────────────────────────────────┘\n");
-
- let swap_gate = CustomGateBuilder::new("MYSWAP", 2)
- .cnot(0, 1)
- .cnot(1, 0)
- .cnot(0, 1)
- .build();
- let swap_gate_clone = swap_gate.clone();
-
- let custom_swap_builder = move || {
- let mut circuit = QuantumCircuit::new(2);
- circuit.x(0).apply_custom(swap_gate_clone.clone(), &[0, 1]);
- circuit
- };
-
- let custom_swap = {
- let mut circuit = QuantumCircuit::new(2);
- circuit.x(0).apply_custom(swap_gate.clone(), &[0, 1]);
- circuit
- };
- println!("Horizontal:\n{}", HorizontalRenderer::new(&custom_swap));
- println!("Vertical:\n{}", VerticalRenderer::new(&custom_swap));
-
- results.push(benchmark_circuit(
- "Custom SWAP (2 qubits)",
- custom_swap_builder,
- ));
- let mut custom_swap_display = {
- let mut circuit = QuantumCircuit::new(2);
- circuit.x(0).apply_custom(swap_gate.clone(), &[0, 1]);
- circuit
- };
- custom_swap_display.compute();
- println!("{}\n", custom_swap_display);
-
- println!("┌─────────────────────────────────────────────────────────────┐");
- println!("│ Custom Gate: Matrix-defined √X gate │");
- println!("└─────────────────────────────────────────────────────────────┘\n");
-
- let sqrt_x_matrix = matrix!(
- [complex!(0.5, 0.5), complex!(0.5, -0.5)];
- [complex!(0.5, -0.5), complex!(0.5, 0.5)]
- );
- let sqrt_x = CustomGate::from_matrix("√X", sqrt_x_matrix);
- let sqrt_x_clone = sqrt_x.clone();
-
- let sqrt_x_builder = move || {
- let mut circuit = QuantumCircuit::new(1);
- circuit
- .apply_custom(sqrt_x_clone.clone(), &[0])
- .apply_custom(sqrt_x_clone.clone(), &[0]);
- circuit
- };
-
- let sqrt_x_circuit = {
- let mut circuit = QuantumCircuit::new(1);
- circuit
- .apply_custom(sqrt_x.clone(), &[0])
- .apply_custom(sqrt_x.clone(), &[0]);
- circuit
- };
- println!("Horizontal:\n{}", HorizontalRenderer::new(&sqrt_x_circuit));
- println!("Vertical:\n{}", VerticalRenderer::new(&sqrt_x_circuit));
-
- results.push(benchmark_circuit("√X gate (1 qubit)", sqrt_x_builder));
- let mut sqrt_x_display = {
- let mut circuit = QuantumCircuit::new(1);
- circuit
- .apply_custom(sqrt_x.clone(), &[0])
- .apply_custom(sqrt_x.clone(), &[0]);
- circuit
- };
- sqrt_x_display.compute();
- println!("{}", sqrt_x_display);
- println!("(Two √X gates should equal X, so |0⟩ becomes |1⟩)\n");
-
- println!("┌─────────────────────────────────────────────────────────────┐");
- println!("│ Larger Circuits (for benchmark comparison) │");
- println!("└─────────────────────────────────────────────────────────────┘\n");
-
- let large_8_builder = || {
- let mut circuit = QuantumCircuit::new(8);
- for i in 0..8 {
- circuit.h(i);
- }
- for i in 0..7 {
- circuit.cnot(i, i + 1);
- }
- circuit
- };
- println!("8-qubit entangled:");
- println!("{}", HorizontalRenderer::new(&large_8_builder()));
- results.push(benchmark_circuit("8-qubit entangled", large_8_builder));
-
- let large_10_builder = || {
- let mut circuit = QuantumCircuit::new(10);
- for i in 0..10 {
- circuit.h(i);
- }
- for i in 0..9 {
- circuit.cnot(i, i + 1);
- }
- circuit.cz(0, 9);
- circuit
- };
- println!("10-qubit entangled:");
- println!("{}", HorizontalRenderer::new(&large_10_builder()));
- results.push(benchmark_circuit("10-qubit entangled", large_10_builder));
-
- let large_12_builder = || {
- let mut circuit = QuantumCircuit::new(12);
- for i in 0..12 {
- circuit.h(i);
- }
- for i in 0..11 {
- circuit.cnot(i, i + 1);
- }
- circuit.cz(0, 11);
- circuit.swap(5, 6);
- circuit
- };
- println!("12-qubit entangled:");
- println!("{}", HorizontalRenderer::new(&large_12_builder()));
- results.push(benchmark_circuit("12-qubit entangled", large_12_builder));
-
- let large_14_builder = || {
- let mut circuit = QuantumCircuit::new(14);
- for i in 0..14 {
- circuit.h(i);
- }
- for i in 0..13 {
- circuit.cnot(i, i + 1);
- }
- circuit
- };
- println!("14-qubit entangled:");
- println!("{}", HorizontalRenderer::new(&large_14_builder()));
- results.push(benchmark_circuit("14-qubit entangled", large_14_builder));
+ if run_clifford {
+ clifford::run_all(&mut results);
+ }
- print_benchmark_table(&results);
+ if run_non_clifford {
+ non_clifford::run_all(&mut results);
+ }
- let all_match = results.iter().all(|r| r.results_match);
- println!("\n");
- if all_match {
- println!("✓ All circuits produced identical results with both runtimes!");
- } else {
- println!("✗ WARNING: Some circuits produced different results!");
+ if run_custom {
+ custom_gates::run_all(&mut results);
}
- let total_basic: Duration = results.iter().map(|r| r.basic_time).sum();
- let total_mt: Duration = results.iter().map(|r| r.mt_time).sum();
- let overall_speedup = total_basic.as_secs_f64() / total_mt.as_secs_f64();
+ if run_bench {
+ benchmarks::run_all(&mut results);
+ }
- println!(
- "\nTotal time - BasicRT: {} | BasicRTMT: {} | Overall speedup: {:.2}x",
- format_duration(total_basic),
- format_duration(total_mt),
- overall_speedup
- );
+ if !results.is_empty() {
+ print_benchmark_table(&results);
+ print_summary(&results);
+ }
}
diff --git a/tester/src/non_clifford.rs b/tester/src/non_clifford.rs
new file mode 100644
index 0000000..8545d01
--- /dev/null
+++ b/tester/src/non_clifford.rs
@@ -0,0 +1,137 @@
+use crate::common::{benchmark_circuit, print_circuit, print_section, BenchmarkResult};
+use libpsi_core::QuantumCircuit;
+use std::f64::consts::PI;
+
+pub fn run_all(results: &mut Vec<BenchmarkResult>) {
+ println!("═══════════════════════════════════════════════════════════════");
+ println!(" NON-CLIFFORD GATES TESTS");
+ println!("═══════════════════════════════════════════════════════════════\n");
+
+ test_fixed_gates(results);
+ test_rotation_gates(results);
+ test_phase_gates(results);
+ test_general_unitaries(results);
+ test_controlled_rotations(results);
+ test_variational_circuit(results);
+}
+
+pub fn test_fixed_gates(results: &mut Vec<BenchmarkResult>) {
+ print_section("Non-Clifford Gates: T, T†, √X, S†");
+
+ let builder = || {
+ let mut circuit = QuantumCircuit::new(2);
+ circuit.h(0).t(0).tdg(0).sx(1).sxdg(1).h(0).s(0).sdg(0);
+ circuit
+ };
+
+ print_circuit(&builder());
+ results.push(benchmark_circuit("Non-Clifford fixed gates", builder));
+
+ let mut display = builder();
+ display.compute();
+ println!("{}\n", display);
+}
+
+pub fn test_rotation_gates(results: &mut Vec<BenchmarkResult>) {
+ print_section("Rotation Gates: Rx, Ry, Rz");
+
+ let builder = || {
+ let mut circuit = QuantumCircuit::new(3);
+ circuit
+ .rx(0, PI / 4.0)
+ .ry(1, PI / 2.0)
+ .rz(2, PI)
+ .rx(0, -PI / 4.0);
+ circuit
+ };
+
+ print_circuit(&builder());
+ results.push(benchmark_circuit("Rotation gates (3 qubits)", builder));
+
+ let mut display = builder();
+ display.compute();
+ println!("{}\n", display);
+}
+
+pub fn test_phase_gates(results: &mut Vec<BenchmarkResult>) {
+ print_section("Phase Gate: P(θ)");
+
+ let builder = || {
+ let mut circuit = QuantumCircuit::new(2);
+ circuit.h(0).p(0, PI / 4.0).h(1).p(1, PI / 2.0);
+ circuit
+ };
+
+ print_circuit(&builder());
+ results.push(benchmark_circuit("Phase gates (2 qubits)", builder));
+
+ let mut display = builder();
+ display.compute();
+ println!("{}\n", display);
+}
+
+pub fn test_general_unitaries(results: &mut Vec<BenchmarkResult>) {
+ print_section("General Unitaries: U1, U2, U3");
+
+ let builder = || {
+ let mut circuit = QuantumCircuit::new(3);
+ circuit
+ .u1(0, PI / 4.0)
+ .u2(1, 0.0, PI)
+ .u3(2, PI / 2.0, 0.0, PI);
+ circuit
+ };
+
+ print_circuit(&builder());
+ results.push(benchmark_circuit("General unitaries (3 qubits)", builder));
+
+ let mut display = builder();
+ display.compute();
+ println!("{}\n", display);
+}
+
+pub fn test_controlled_rotations(results: &mut Vec<BenchmarkResult>) {
+ print_section("Controlled Rotation Gates: CRx, CRy, CRz, CP");
+
+ let builder = || {
+ let mut circuit = QuantumCircuit::new(4);
+ circuit
+ .x(0)
+ .crx(0, 1, PI / 2.0)
+ .x(2)
+ .cry(2, 3, PI / 4.0)
+ .crz(0, 2, PI)
+ .cp(1, 3, PI / 2.0);
+ circuit
+ };
+
+ print_circuit(&builder());
+ results.push(benchmark_circuit(
+ "Controlled rotations (4 qubits)",
+ builder,
+ ));
+
+ let mut display = builder();
+ display.compute();
+ println!("{}\n", display);
+}
+
+pub fn test_variational_circuit(results: &mut Vec<BenchmarkResult>) {
+ print_section("Variational Circuit (VQE-like)");
+
+ let builder = || {
+ let mut circuit = QuantumCircuit::new(3);
+ circuit.ry(0, 0.5).ry(1, 0.3).ry(2, 0.7);
+ circuit.cnot(0, 1).cnot(1, 2);
+ circuit.rx(0, 0.2).rx(1, 0.4).rx(2, 0.6);
+ circuit.cz(0, 2);
+ circuit
+ };
+
+ print_circuit(&builder());
+ results.push(benchmark_circuit("Variational circuit (3 qubits)", builder));
+
+ let mut display = builder();
+ display.compute();
+ println!("{}\n", display);
+}