diff --git a/testing/test_overlap_measurement.py b/testing/test_overlap_measurement.py index 440f6c732a..f76df296e2 100644 --- a/testing/test_overlap_measurement.py +++ b/testing/test_overlap_measurement.py @@ -18,81 +18,55 @@ import pytest import numpy as np -from .conftest import TESTING_BACKENDS +from .utils import TESTING_BACKENDS, get_backend_config from qumat import QuMat +@pytest.mark.parametrize("backend_name", TESTING_BACKENDS) class TestOverlapMeasurement: """Test overlap measurement functionality across different backends.""" - def get_backend_config(self, backend_name): - """Get backend configuration by name.""" - configs = { - "qiskit": { - "backend_name": "qiskit", - "backend_options": { - "simulator_type": "aer_simulator", - "shots": 10000, - }, - }, - "cirq": { - "backend_name": "cirq", - "backend_options": { - "simulator_type": "default", - "shots": 10000, - }, - }, - "amazon_braket": { - "backend_name": "amazon_braket", - "backend_options": { - "simulator_type": "local", - "shots": 10000, - }, - }, - } - return configs.get(backend_name) - - @pytest.mark.parametrize("backend_name", TESTING_BACKENDS) def test_identical_zero_states(self, backend_name): """Test overlap measurement with two identical |0> states.""" - qumat = QuMat(self.get_backend_config(backend_name)) + backend_config = get_backend_config(backend_name) + qumat = QuMat(backend_config) qumat.create_empty_circuit(num_qubits=3) overlap = qumat.measure_overlap(qubit1=1, qubit2=2, ancilla_qubit=0) assert overlap > 0.95 - @pytest.mark.parametrize("backend_name", TESTING_BACKENDS) def test_identical_one_states(self, backend_name): """Test overlap measurement with two identical |1> states.""" - qumat = QuMat(self.get_backend_config(backend_name)) + backend_config = get_backend_config(backend_name) + qumat = QuMat(backend_config) qumat.create_empty_circuit(num_qubits=3) qumat.apply_pauli_x_gate(1) qumat.apply_pauli_x_gate(2) overlap = qumat.measure_overlap(qubit1=1, qubit2=2, ancilla_qubit=0) assert overlap > 0.95 - @pytest.mark.parametrize("backend_name", TESTING_BACKENDS) def test_orthogonal_states(self, backend_name): """Test overlap measurement with orthogonal states |0> and |1>.""" - qumat = QuMat(self.get_backend_config(backend_name)) + backend_config = get_backend_config(backend_name) + qumat = QuMat(backend_config) qumat.create_empty_circuit(num_qubits=3) qumat.apply_pauli_x_gate(2) overlap = qumat.measure_overlap(qubit1=1, qubit2=2, ancilla_qubit=0) assert overlap < 0.05 - @pytest.mark.parametrize("backend_name", TESTING_BACKENDS) def test_identical_plus_states(self, backend_name): """Test overlap measurement with two identical |+> states.""" - qumat = QuMat(self.get_backend_config(backend_name)) + backend_config = get_backend_config(backend_name) + qumat = QuMat(backend_config) qumat.create_empty_circuit(num_qubits=3) qumat.apply_hadamard_gate(1) qumat.apply_hadamard_gate(2) overlap = qumat.measure_overlap(qubit1=1, qubit2=2, ancilla_qubit=0) assert overlap > 0.95 - @pytest.mark.parametrize("backend_name", TESTING_BACKENDS) def test_plus_minus_states(self, backend_name): """Test overlap measurement with |+> and |-> states.""" - qumat = QuMat(self.get_backend_config(backend_name)) + backend_config = get_backend_config(backend_name) + qumat = QuMat(backend_config) qumat.create_empty_circuit(num_qubits=3) qumat.apply_hadamard_gate(1) qumat.apply_pauli_x_gate(2) @@ -100,29 +74,29 @@ def test_plus_minus_states(self, backend_name): overlap = qumat.measure_overlap(qubit1=1, qubit2=2, ancilla_qubit=0) assert overlap < 0.05 - @pytest.mark.parametrize("backend_name", TESTING_BACKENDS) def test_partial_overlap_states(self, backend_name): """Test overlap measurement with states having partial overlap.""" - qumat = QuMat(self.get_backend_config(backend_name)) + backend_config = get_backend_config(backend_name) + qumat = QuMat(backend_config) qumat.create_empty_circuit(num_qubits=3) qumat.apply_hadamard_gate(1) overlap = qumat.measure_overlap(qubit1=1, qubit2=2, ancilla_qubit=0) assert 0.4 < overlap < 0.6 - @pytest.mark.parametrize("backend_name", TESTING_BACKENDS) def test_rotated_states(self, backend_name): """Test overlap measurement with rotated states.""" - qumat = QuMat(self.get_backend_config(backend_name)) + backend_config = get_backend_config(backend_name) + qumat = QuMat(backend_config) qumat.create_empty_circuit(num_qubits=3) qumat.apply_ry_gate(1, np.pi / 4) qumat.apply_ry_gate(2, np.pi / 4) overlap = qumat.measure_overlap(qubit1=1, qubit2=2, ancilla_qubit=0) assert overlap > 0.95 - @pytest.mark.parametrize("backend_name", TESTING_BACKENDS) def test_different_rotated_states(self, backend_name): """Test overlap measurement with differently rotated states.""" - qumat = QuMat(self.get_backend_config(backend_name)) + backend_config = get_backend_config(backend_name) + qumat = QuMat(backend_config) qumat.create_empty_circuit(num_qubits=3) qumat.apply_ry_gate(1, np.pi / 4) qumat.apply_ry_gate(2, np.pi / 2) @@ -130,10 +104,10 @@ def test_different_rotated_states(self, backend_name): expected_overlap = np.cos(np.pi / 8) ** 2 assert abs(overlap - expected_overlap) < 0.05 - @pytest.mark.parametrize("backend_name", TESTING_BACKENDS) def test_entangled_states_same(self, backend_name): """Test overlap measurement with identical entangled states (Bell states).""" - qumat = QuMat(self.get_backend_config(backend_name)) + backend_config = get_backend_config(backend_name) + qumat = QuMat(backend_config) qumat.create_empty_circuit(num_qubits=5) qumat.apply_hadamard_gate(1) qumat.apply_cnot_gate(1, 2) @@ -142,25 +116,9 @@ def test_entangled_states_same(self, backend_name): overlap = qumat.measure_overlap(qubit1=1, qubit2=3, ancilla_qubit=0) assert 0.0 <= overlap <= 1.0 - def test_all_backends_consistency(self, testing_backends): - """Test that all backends produce consistent results.""" - results = {} - for backend_name in testing_backends: - qumat = QuMat(self.get_backend_config(backend_name)) - qumat.create_empty_circuit(num_qubits=3) - results[backend_name] = qumat.measure_overlap( - qubit1=1, qubit2=2, ancilla_qubit=0 - ) - - overlaps = list(results.values()) - for i in range(len(overlaps)): - for j in range(i + 1, len(overlaps)): - assert abs(overlaps[i] - overlaps[j]) < 0.05 - - @pytest.mark.parametrize("backend_name", TESTING_BACKENDS) def test_measure_overlap_with_different_ancilla(self, backend_name): """Test overlap measurement with different ancilla qubit positions.""" - backend_config = self.get_backend_config(backend_name) + backend_config = get_backend_config(backend_name) qumat1 = QuMat(backend_config) qumat1.create_empty_circuit(num_qubits=4) @@ -177,3 +135,23 @@ def test_measure_overlap_with_different_ancilla(self, backend_name): assert overlap1 > 0.95 assert overlap2 > 0.95 assert abs(overlap1 - overlap2) < 0.05 + + +class TestOverlapMeasurementConsistency: + """Test class for consistency checks across all backends.""" + + def test_all_backends_consistency(self): + """Test that all backends produce consistent results.""" + results = {} + for backend_name in TESTING_BACKENDS: + backend_config = get_backend_config(backend_name) + qumat = QuMat(backend_config) + qumat.create_empty_circuit(num_qubits=3) + results[backend_name] = qumat.measure_overlap( + qubit1=1, qubit2=2, ancilla_qubit=0 + ) + + overlaps = list(results.values()) + for i in range(len(overlaps)): + for j in range(i + 1, len(overlaps)): + assert abs(overlaps[i] - overlaps[j]) < 0.05 diff --git a/testing/test_swap_test.py b/testing/test_swap_test.py index 02d7f884e1..ac98643f48 100644 --- a/testing/test_swap_test.py +++ b/testing/test_swap_test.py @@ -17,7 +17,7 @@ import pytest -from .utils import TESTING_BACKENDS +from .utils import TESTING_BACKENDS, get_backend_config from qumat import QuMat @@ -25,33 +25,6 @@ class TestSwapTest: """Test class for swap test functionality across different backends.""" - def get_backend_config(self, backend_name): - """Helper method to get backend configuration.""" - if backend_name == "qiskit": - return { - "backend_name": backend_name, - "backend_options": { - "simulator_type": "aer_simulator", - "shots": 10000, - }, - } - elif backend_name == "cirq": - return { - "backend_name": backend_name, - "backend_options": { - "simulator_type": "default", - "shots": 10000, - }, - } - elif backend_name == "amazon_braket": - return { - "backend_name": backend_name, - "backend_options": { - "simulator_type": "local", - "shots": 10000, - }, - } - def calculate_prob_zero(self, results, backend_name): """Calculate probability of measuring ancilla qubit in |0> state.""" if isinstance(results, list): @@ -79,7 +52,7 @@ def calculate_prob_zero(self, results, backend_name): def test_identical_zero_states(self, backend_name): """Test swap test with two identical |0> states.""" - backend_config = self.get_backend_config(backend_name) + backend_config = get_backend_config(backend_name) qumat = QuMat(backend_config) # Create circuit with 3 qubits: ancilla, state1, state2 @@ -99,7 +72,7 @@ def test_identical_zero_states(self, backend_name): def test_orthogonal_states(self, backend_name): """Test swap test with orthogonal states |0> and |1>.""" - backend_config = self.get_backend_config(backend_name) + backend_config = get_backend_config(backend_name) qumat = QuMat(backend_config) # Create circuit with 3 qubits @@ -126,7 +99,7 @@ def test_identical_one_states(self, backend_name): predominantly |1⟩ instead of |0⟩ for identical |1⟩ states. The key is that identical states give deterministic results (close to 0 or 1). """ - backend_config = self.get_backend_config(backend_name) + backend_config = get_backend_config(backend_name) qumat = QuMat(backend_config) # Create circuit with 3 qubits @@ -150,7 +123,7 @@ def test_identical_one_states(self, backend_name): def test_cswap_gate_exists(self, backend_name): """Test that the CSWAP gate is properly implemented.""" - backend_config = self.get_backend_config(backend_name) + backend_config = get_backend_config(backend_name) qumat = QuMat(backend_config) # Create a simple circuit @@ -166,33 +139,6 @@ def test_cswap_gate_exists(self, backend_name): class TestSwapTestConsistency: """Test class for consistency checks across all backends.""" - def get_backend_config(self, backend_name): - """Helper method to get backend configuration.""" - if backend_name == "qiskit": - return { - "backend_name": backend_name, - "backend_options": { - "simulator_type": "aer_simulator", - "shots": 10000, - }, - } - elif backend_name == "cirq": - return { - "backend_name": backend_name, - "backend_options": { - "simulator_type": "default", - "shots": 10000, - }, - } - elif backend_name == "amazon_braket": - return { - "backend_name": backend_name, - "backend_options": { - "simulator_type": "local", - "shots": 10000, - }, - } - def calculate_prob_zero(self, results, backend_name): """Calculate probability of measuring ancilla qubit in |0> state.""" if isinstance(results, list): @@ -223,7 +169,7 @@ def test_all_backends_consistency(self): results_dict = {} for backend_name in TESTING_BACKENDS: - backend_config = self.get_backend_config(backend_name) + backend_config = get_backend_config(backend_name) qumat = QuMat(backend_config) # Create circuit with identical |0> states diff --git a/testing/utils/__init__.py b/testing/utils/__init__.py index 8c752e381e..6c1051bb11 100644 --- a/testing/utils/__init__.py +++ b/testing/utils/__init__.py @@ -16,5 +16,6 @@ # from .constants import TESTING_BACKENDS +from .qumat_helpers import get_backend_config -__all__ = ["TESTING_BACKENDS"] +__all__ = ["TESTING_BACKENDS", "get_backend_config"] diff --git a/testing/utils/qumat_helpers.py b/testing/utils/qumat_helpers.py index 693b86005c..ccd1891e26 100644 --- a/testing/utils/qumat_helpers.py +++ b/testing/utils/qumat_helpers.py @@ -19,6 +19,35 @@ from qumat.qumat import QuMat +def get_backend_config(backend_name: str) -> dict | None: + """Helper function to get backend configuration by name.""" + configs = { + "qiskit": { + "backend_name": "qiskit", + "backend_options": { + "simulator_type": "aer_simulator", + "shots": 10000, + }, + }, + "cirq": { + "backend_name": "cirq", + "backend_options": { + "simulator_type": "default", + "shots": 10000, + }, + }, + "amazon_braket": { + "backend_name": "amazon_braket", + "backend_options": { + "simulator_type": "local", + "shots": 10000, + }, + }, + } + + return configs.get(backend_name) + + class BinaryString(str): def __new__(cls, value): if not all(char in ["0", "1"] for char in value):