145 lines
4.0 KiB
Rust
145 lines
4.0 KiB
Rust
//! Integration tests for symclaw-quantum.
|
|
//!
|
|
//! Cross-module scenarios: Pauli algebra → circuit → codegen → ZX.
|
|
|
|
use symclaw_quantum::circuit::QuantumCircuit;
|
|
use symclaw_quantum::clifford_gates::CliffordGate1Q;
|
|
use symclaw_quantum::codegen;
|
|
use symclaw_quantum::pauli::{Pauli, PauliOp, Phase};
|
|
use symclaw_quantum::zx::ZXDiagram;
|
|
|
|
// ── Pauli algebra ─────────────────────────────────────────────────
|
|
|
|
#[test]
|
|
fn pauli_x_y_anticommute() {
|
|
let x = PauliOp::single(Pauli::X, 0, 1);
|
|
let y = PauliOp::single(Pauli::Y, 0, 1);
|
|
assert!(!x.commutes_with(&y), "X and Y should anticommute");
|
|
}
|
|
|
|
#[test]
|
|
fn pauli_x_z_anticommute() {
|
|
let x = PauliOp::single(Pauli::X, 0, 1);
|
|
let z = PauliOp::single(Pauli::Z, 0, 1);
|
|
assert!(!x.commutes_with(&z), "X and Z should anticommute");
|
|
}
|
|
|
|
#[test]
|
|
fn pauli_z_z_commute() {
|
|
let z1 = PauliOp::single(Pauli::Z, 0, 2);
|
|
let z2 = PauliOp::single(Pauli::Z, 1, 2);
|
|
assert!(z1.commutes_with(&z2), "Z₀ and Z₁ should commute");
|
|
}
|
|
|
|
#[test]
|
|
fn pauli_weight_single_qubit() {
|
|
let x = PauliOp::single(Pauli::X, 0, 3);
|
|
assert_eq!(x.weight(), 1, "single-qubit X has weight 1");
|
|
}
|
|
|
|
#[test]
|
|
fn pauli_identity_weight_zero() {
|
|
let id = PauliOp::identity(4);
|
|
assert_eq!(id.weight(), 0, "Identity has weight 0");
|
|
}
|
|
|
|
#[test]
|
|
fn phase_cycle() {
|
|
// i^0=1, i^1=i, i^2=-1, i^3=-i, i^4=1
|
|
for k in 0..4u8 {
|
|
let p = Phase(k);
|
|
let p_neg = p.neg();
|
|
let p_back = p_neg.neg();
|
|
// neg twice = same phase
|
|
assert_eq!(p_back.0, p.0, "neg(neg(Phase({k}))) = Phase({k})");
|
|
}
|
|
}
|
|
|
|
// ── Circuit construction ──────────────────────────────────────────
|
|
|
|
#[test]
|
|
fn circuit_gate_count() {
|
|
let mut c = QuantumCircuit::new(2);
|
|
c.h(0).cnot(0, 1);
|
|
assert_eq!(c.gate_count(), 2, "Bell state circuit has 2 gates");
|
|
}
|
|
|
|
#[test]
|
|
fn circuit_t_count() {
|
|
let mut c = QuantumCircuit::new(3);
|
|
for _ in 0..7 {
|
|
c.t(0);
|
|
}
|
|
assert_eq!(c.t_count(), 7, "T-count should be 7");
|
|
}
|
|
|
|
#[test]
|
|
fn circuit_qubit_count() {
|
|
let c = QuantumCircuit::new(5);
|
|
assert_eq!(c.n_qubits, 5);
|
|
}
|
|
|
|
// ── Clifford gates ────────────────────────────────────────────────
|
|
|
|
#[test]
|
|
fn clifford_h_dagger_is_h() {
|
|
// H† = H (Hermitian)
|
|
let h = CliffordGate1Q::H;
|
|
assert_eq!(h.dagger(), CliffordGate1Q::H, "H† = H");
|
|
}
|
|
|
|
#[test]
|
|
fn clifford_s_dagger_is_sdg() {
|
|
let s = CliffordGate1Q::S;
|
|
assert_eq!(s.dagger(), CliffordGate1Q::Sdg, "S† = S†");
|
|
}
|
|
|
|
#[test]
|
|
fn clifford_x_dagger_is_x() {
|
|
let x = CliffordGate1Q::X;
|
|
assert_eq!(x.dagger(), CliffordGate1Q::X, "X† = X");
|
|
}
|
|
|
|
// ── ZX-calculus ───────────────────────────────────────────────────
|
|
|
|
#[test]
|
|
fn zx_add_nodes_and_wires() {
|
|
let mut d = ZXDiagram::new();
|
|
let i = d.add_input();
|
|
let o = d.add_output();
|
|
d.add_wire(i, o);
|
|
assert_eq!(d.degree(i), 1);
|
|
assert_eq!(d.degree(o), 1);
|
|
}
|
|
|
|
#[test]
|
|
fn zx_node_count() {
|
|
let mut d = ZXDiagram::new();
|
|
d.add_input();
|
|
d.add_input();
|
|
d.add_output();
|
|
// 3 nodes total
|
|
assert_eq!(d.node_count(), 3);
|
|
}
|
|
|
|
// ── Codegen pipeline ─────────────────────────────────────────────
|
|
|
|
#[test]
|
|
fn codegen_qasm3_bell_state_nonempty() {
|
|
let mut c = QuantumCircuit::new(2);
|
|
c.h(0).cnot(0, 1);
|
|
let qasm = codegen::to_openqasm3(&c);
|
|
assert!(!qasm.is_empty(), "OpenQASM3 output should not be empty");
|
|
}
|
|
|
|
#[test]
|
|
fn codegen_qasm3_contains_h_gate() {
|
|
let mut c = QuantumCircuit::new(1);
|
|
c.h(0);
|
|
let qasm = codegen::to_openqasm3(&c);
|
|
assert!(
|
|
qasm.to_lowercase().contains('h') || qasm.contains("H"),
|
|
"OpenQASM output should contain H gate: {qasm}"
|
|
);
|
|
}
|