Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 41 additions & 63 deletions testing/test_overlap_measurement.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,122 +18,96 @@
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)
qumat.apply_hadamard_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_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)
overlap = qumat.measure_overlap(qubit1=1, qubit2=2, ancilla_qubit=0)
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)
Expand All @@ -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)
Expand All @@ -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
66 changes: 6 additions & 60 deletions testing/test_swap_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,41 +17,14 @@

import pytest

from .utils import TESTING_BACKENDS
from .utils import TESTING_BACKENDS, get_backend_config
from qumat import QuMat


@pytest.mark.parametrize("backend_name", TESTING_BACKENDS)
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):
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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):
Expand Down Expand Up @@ -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
Expand Down
3 changes: 2 additions & 1 deletion testing/utils/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"]
29 changes: 29 additions & 0 deletions testing/utils/qumat_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down