From c5d960077dd640deb21168b743ad74421716de31 Mon Sep 17 00:00:00 2001 From: Manideep3969 Date: Tue, 18 Aug 2026 13:26:49 +0530 Subject: [PATCH] test(#55): add unitary equivalence tests for scheduling, fusion, and cutting Add comprehensive correctness tests: - Scheduling: unitary preservation for ASAP, ALAP, coherence_aware on Bell and GHZ circuits; verify ASAP/ALAP produce distinct methods - Fusion: unitary preservation on Bell, GHZ, RZ chains; global phase equivalence via Operator.equiv() - Cutting: _partition_qubits returns all qubits, groups are disjoint, and cuts separate qubit groups All 334 tests pass. --- 0 | 0 tests/test_cutting.py | 32 ++++++++++++++++++ tests/test_fusion.py | 54 ++++++++++++++++++++++++++++- tests/test_scheduling.py | 73 +++++++++++++++++++++++++++++++++++++++- 4 files changed, 157 insertions(+), 2 deletions(-) create mode 100644 0 diff --git a/0 b/0 new file mode 100644 index 0000000..e69de29 diff --git a/tests/test_cutting.py b/tests/test_cutting.py index 4652f21..4678226 100644 --- a/tests/test_cutting.py +++ b/tests/test_cutting.py @@ -290,6 +290,38 @@ def test_partition_with_cut(self, cutter): groups = cutter._partition_qubits(qc, cut_points) assert len(groups) >= 1 + def test_partition_no_cuts_returns_all_qubits(self, cutter): + qc = QuantumCircuit(4) + groups = cutter._partition_qubits(qc, []) + all_qubits = set() + for g in groups: + all_qubits.update(g) + assert all_qubits == {0, 1, 2, 3} + + def test_partition_single_cut_separates_qubits(self, cutter): + qc = QuantumCircuit(4) + qc.cx(0, 1) + qc.cx(1, 2) + qc.cx(2, 3) + groups = cutter._partition_qubits(qc, [(1, 2)]) + assert len(groups) == 2 + all_qubits = set() + for g in groups: + all_qubits.update(g) + assert all_qubits == {0, 1, 2, 3} + + def test_partition_groups_are_disjoint(self, cutter): + qc = QuantumCircuit(6) + for i in range(5): + qc.cx(i, i + 1) + groups = cutter._partition_qubits(qc, [(1, 2), (3, 4)]) + all_qubits = set() + for g in groups: + g_set = set(g) + assert g_set.isdisjoint(all_qubits) + all_qubits.update(g_set) + assert all_qubits == {0, 1, 2, 3, 4, 5} + class TestCuttingEdgeCases: """Tests for cutting edge cases and decision paths.""" diff --git a/tests/test_fusion.py b/tests/test_fusion.py index 66f1d2d..b4d7116 100644 --- a/tests/test_fusion.py +++ b/tests/test_fusion.py @@ -365,4 +365,56 @@ def test_three_qubit_multiple_chains(self, fusion): result = fusion.optimize(qc) original_unitary = Operator(qc) fused_unitary = Operator(result.optimized_circuit) - assert process_fidelity(fused_unitary, original_unitary) > 0.99 \ No newline at end of file + assert process_fidelity(fused_unitary, original_unitary) > 0.99 + + +class TestFusionUnitaryEquivalence: + """Comprehensive unitary equivalence tests for gate fusion (issue #55).""" + + @pytest.fixture + def fusion(self): + return GateFusion(cost_model=CostModel()) + + def test_single_qubit_chain_bell(self, fusion): + qc = QuantumCircuit(2) + qc.h(0) + qc.cx(0, 1) + result = fusion.optimize(qc) + assert process_fidelity(Operator(result.optimized_circuit), Operator(qc)) > 0.99 + + def test_single_qubit_chain_ghz(self, fusion): + qc = QuantumCircuit(4) + qc.h(0) + for i in range(3): + qc.cx(i, i + 1) + result = fusion.optimize(qc) + assert process_fidelity(Operator(result.optimized_circuit), Operator(qc)) > 0.99 + + def test_rz_chain_preserves_unitary(self, fusion): + qc = QuantumCircuit(2) + qc.h(0) + qc.rz(0.5, 0) + qc.rz(0.3, 0) + qc.cx(0, 1) + result = fusion.optimize(qc) + assert process_fidelity(Operator(result.optimized_circuit), Operator(qc)) > 0.99 + + def test_multi_qubit_chain_preserves_unitary(self, fusion): + qc = QuantumCircuit(3) + qc.h(0) + qc.h(1) + qc.h(2) + qc.cx(0, 1) + qc.cx(1, 2) + result = fusion.optimize(qc) + assert process_fidelity(Operator(result.optimized_circuit), Operator(qc)) > 0.99 + + def test_fusion_preserves_unitary_up_to_global_phase(self, fusion): + qc = QuantumCircuit(1) + qc.h(0) + qc.sx(0) + qc.rz(1.23, 0) + result = fusion.optimize(qc) + original_op = Operator(qc) + fused_op = Operator(result.optimized_circuit) + assert original_op.equiv(fused_op) \ No newline at end of file diff --git a/tests/test_scheduling.py b/tests/test_scheduling.py index d44e127..726e135 100644 --- a/tests/test_scheduling.py +++ b/tests/test_scheduling.py @@ -371,4 +371,75 @@ def test_alap_delays_gates_with_backend(self): assert result_alap.depth_alap > 0 assert Operator(qc).equiv(Operator(result_asap.circuit)) - assert Operator(qc).equiv(Operator(result_alap.circuit)) \ No newline at end of file + assert Operator(qc).equiv(Operator(result_alap.circuit)) + + +class TestSchedulingUnitaryEquivalence: + """Comprehensive unitary equivalence tests for all scheduling methods (issue #55).""" + + @pytest.fixture + def scheduler(self): + return CoherenceAwareScheduler(cost_model=CostModel()) + + def test_asap_preserves_unitary_bell(self, scheduler): + qc = QuantumCircuit(2) + qc.h(0) + qc.cx(0, 1) + result = scheduler.schedule(qc, method="asap") + assert Operator(qc).equiv(Operator(result.circuit)) + + def test_alap_preserves_unitary_bell(self, scheduler): + qc = QuantumCircuit(2) + qc.h(0) + qc.cx(0, 1) + result = scheduler.schedule(qc, method="alap") + assert Operator(qc).equiv(Operator(result.circuit)) + + def test_coherence_aware_preserves_unitary_bell(self, scheduler): + qc = QuantumCircuit(2) + qc.h(0) + qc.cx(0, 1) + result = scheduler.schedule(qc, method="coherence_aware") + assert Operator(qc).equiv(Operator(result.circuit)) + + def test_asap_preserves_unitary_ghz(self, scheduler): + qc = QuantumCircuit(4) + qc.h(0) + for i in range(3): + qc.cx(i, i + 1) + result = scheduler.schedule(qc, method="asap") + assert Operator(qc).equiv(Operator(result.circuit)) + + def test_alap_preserves_unitary_ghz(self, scheduler): + qc = QuantumCircuit(4) + qc.h(0) + for i in range(3): + qc.cx(i, i + 1) + result = scheduler.schedule(qc, method="alap") + assert Operator(qc).equiv(Operator(result.circuit)) + + def test_coherence_aware_preserves_unitary_ghz(self, scheduler): + qc = QuantumCircuit(4) + qc.h(0) + for i in range(3): + qc.cx(i, i + 1) + result = scheduler.schedule(qc, method="coherence_aware") + assert Operator(qc).equiv(Operator(result.circuit)) + + def test_alap_produces_different_schedule_than_asap(self, scheduler): + qc = QuantumCircuit(3) + qc.h(0) + qc.cx(0, 1) + qc.h(2) + qc.cx(1, 2) + qc.h(1) + + asap_result = scheduler.schedule(qc, method="asap") + alap_result = scheduler.schedule(qc, method="alap") + + assert Operator(qc).equiv(Operator(asap_result.circuit)) + assert Operator(qc).equiv(Operator(alap_result.circuit)) + + assert asap_result.method == "asap" + assert alap_result.method == "alap" + assert asap_result.method != alap_result.method \ No newline at end of file