//! 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}" ); }