Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

215 unittest to pytest #217

Merged
merged 14 commits into from
Jun 5, 2024
85 changes: 44 additions & 41 deletions test/decomposer/test_cnot_decomposer.py
Original file line number Diff line number Diff line change
@@ -1,43 +1,46 @@
import unittest
from test.ir_equality_test_base import IREqualityTestBase
from __future__ import annotations

import math

import pytest

from opensquirrel.decomposer.cnot_decomposer import CNOTDecomposer
from opensquirrel.default_gates import *
from opensquirrel.ir import Float, Qubit


class CNOTDecomposerTest(IREqualityTestBase):
def test_ignores_1q_gates(self):
self.assertEqual(CNOTDecomposer().decompose(H(Qubit(0))), [H(Qubit(0))])
self.assertEqual(CNOTDecomposer().decompose(Rz(Qubit(0), Float(2.345))), [Rz(Qubit(0), Float(2.345))])

def test_ignores_matrix_gate(self):
self.assertEqual(CNOTDecomposer().decompose(SWAP(Qubit(4), Qubit(3))), [SWAP(Qubit(4), Qubit(3))])

def test_ignores_double_controlled(self):
g = ControlledGate(
control_qubit=Qubit(5), target_gate=ControlledGate(control_qubit=Qubit(2), target_gate=X(Qubit(0)))
)
self.assertEqual(CNOTDecomposer().decompose(g), [g])

def test_CNOT(self):
self.assertEqual(
CNOTDecomposer().decompose(CNOT(Qubit(0), Qubit(1))),
[CNOT(Qubit(0), Qubit(1))],
)

def test_CZ(self):
self.assertEqual(
CNOTDecomposer().decompose(CZ(Qubit(0), Qubit(1))),
[
Rz(Qubit(1), Float(math.pi)),
Ry(Qubit(1), Float(math.pi / 2)),
CNOT(Qubit(0), Qubit(1)),
Ry(Qubit(1), Float(-math.pi / 2)),
Rz(Qubit(1), Float(math.pi)),
],
)


if __name__ == "__main__":
unittest.main()
from opensquirrel.default_gates import CNOT, CZ, SWAP, ControlledGate, H, Ry, Rz, X
from opensquirrel.ir import Float, Gate, Qubit


@pytest.fixture(name="decomposer")
def decomposer_fixture() -> CNOTDecomposer:
return CNOTDecomposer()


@pytest.mark.parametrize(
"gate,expected_result", [(H(Qubit(0)), [H(Qubit(0))]), (Rz(Qubit(0), Float(2.345)), [Rz(Qubit(0), Float(2.345))])]
)
def test_ignores_1q_gates(decomposer: CNOTDecomposer, gate: Gate, expected_result: list[Gate]) -> None:
assert decomposer.decompose(gate) == expected_result


def test_ignores_matrix_gate(decomposer: CNOTDecomposer) -> None:
assert decomposer.decompose(SWAP(Qubit(4), Qubit(3))) == [SWAP(Qubit(4), Qubit(3))]


def test_ignores_double_controlled(decomposer: CNOTDecomposer) -> None:
g = ControlledGate(
control_qubit=Qubit(5), target_gate=ControlledGate(control_qubit=Qubit(2), target_gate=X(Qubit(0)))
)
assert decomposer.decompose(g) == [g]


def test_CNOT(decomposer: CNOTDecomposer) -> None:
assert decomposer.decompose(CNOT(Qubit(0), Qubit(1))) == [CNOT(Qubit(0), Qubit(1))]


def test_CZ(decomposer: CNOTDecomposer) -> None:
assert decomposer.decompose(CZ(Qubit(0), Qubit(1))) == [
Rz(Qubit(1), Float(math.pi)),
Ry(Qubit(1), Float(math.pi / 2)),
CNOT(Qubit(0), Qubit(1)),
Ry(Qubit(1), Float(-math.pi / 2)),
Rz(Qubit(1), Float(math.pi)),
]
131 changes: 61 additions & 70 deletions test/decomposer/test_mckay_decomposer.py
Original file line number Diff line number Diff line change
@@ -1,72 +1,63 @@
import unittest
from test.ir_equality_test_base import IREqualityTestBase
import math

import pytest

from opensquirrel.decomposer.mckay_decomposer import McKayDecomposer
from opensquirrel.default_gates import *
from opensquirrel.ir import Float, Qubit


class DecomposeMcKayTests(IREqualityTestBase):
def test_ignores_2q_gates(self):
self.assertEqual(McKayDecomposer().decompose(CNOT(Qubit(0), Qubit(1))), [CNOT(Qubit(0), Qubit(1))])
self.assertEqual(
McKayDecomposer().decompose(CR(Qubit(2), Qubit(3), Float(2.123))), [CR(Qubit(2), Qubit(3), Float(2.123))]
)

def test_identity_empty_decomposition(self):
self.assertEqual(McKayDecomposer().decompose(BlochSphereRotation.identity(Qubit(0))), [])

def test_x(self):
self.assertEqual(
McKayDecomposer().decompose(X(Qubit(0))),
[
# FIXME: we can do better here. See https://github.com/QuTech-Delft/OpenSquirrel/issues/89.
Rz(Qubit(0), Float(-math.pi / 2)),
X90(Qubit(0)),
X90(Qubit(0)),
Rz(Qubit(0), Float(-math.pi / 2)),
],
)

def test_y(self):
self.assertEqual(
McKayDecomposer().decompose(Y(Qubit(0))), [Rz(Qubit(0), Float(math.pi)), X90(Qubit(0)), X90(Qubit(0))]
)

def test_z(self):
self.assertEqual(
McKayDecomposer().decompose(Z(Qubit(0))),
[
Rz(Qubit(0), Float(-math.pi / 2)),
X90(Qubit(0)),
Rz(Qubit(0), Float(math.pi)),
X90(Qubit(0)),
Rz(Qubit(0), Float(math.pi / 2)),
],
)

def test_hadamard(self):
self.assertEqual(
McKayDecomposer().decompose(H(Qubit(0))),
[
BlochSphereRotation(Qubit(0), axis=(1, 0, 0), angle=math.pi / 2, phase=0.0),
BlochSphereRotation(Qubit(0), axis=(0, 0, 1), angle=math.pi / 2, phase=0.0),
BlochSphereRotation(Qubit(0), axis=(1, 0, 0), angle=math.pi / 2, phase=0.0),
],
)

def test_arbitrary(self):
self.assertEqual(
McKayDecomposer().decompose(BlochSphereRotation(qubit=Qubit(0), angle=5.21, axis=(1, 2, 3), phase=0.324)),
[
Rz(Qubit(0), Float(0.018644578210707863)),
X90(Qubit(0)),
Rz(Qubit(0), Float(2.520651583905213)),
X90(Qubit(0)),
Rz(Qubit(0), Float(2.2329420137988887)),
],
)


if __name__ == "__main__":
unittest.main()
from opensquirrel.default_gates import CNOT, CR, X90, H, Rz, X, Y, Z
from opensquirrel.ir import BlochSphereRotation, Float, Qubit


@pytest.fixture(name="decomposer")
def decomposer_fixture() -> McKayDecomposer:
return McKayDecomposer()


def test_ignores_2q_gates(decomposer: McKayDecomposer) -> None:
assert decomposer.decompose(CNOT(Qubit(0), Qubit(1))) == [CNOT(Qubit(0), Qubit(1))]
assert decomposer.decompose(CR(Qubit(2), Qubit(3), Float(2.123))) == [CR(Qubit(2), Qubit(3), Float(2.123))]


def test_identity_empty_decomposition(decomposer: McKayDecomposer) -> None:
assert decomposer.decompose(BlochSphereRotation.identity(Qubit(0))) == []


def test_x(decomposer: McKayDecomposer) -> None:
assert decomposer.decompose(X(Qubit(0))) == [
# FIXME: we can do better here. See https://github.com/QuTech-Delft/OpenSquirrel/issues/89.
Rz(Qubit(0), Float(-math.pi / 2)),
X90(Qubit(0)),
X90(Qubit(0)),
Rz(Qubit(0), Float(-math.pi / 2)),
]


def test_y(decomposer: McKayDecomposer) -> None:
assert decomposer.decompose(Y(Qubit(0))) == [Rz(Qubit(0), Float(math.pi)), X90(Qubit(0)), X90(Qubit(0))]


def test_z(decomposer: McKayDecomposer) -> None:
assert decomposer.decompose(Z(Qubit(0))) == [
Rz(Qubit(0), Float(-math.pi / 2)),
X90(Qubit(0)),
Rz(Qubit(0), Float(math.pi)),
X90(Qubit(0)),
Rz(Qubit(0), Float(math.pi / 2)),
]


def test_hadamard(decomposer: McKayDecomposer) -> None:
assert decomposer.decompose(H(Qubit(0))) == [
BlochSphereRotation(Qubit(0), axis=(1, 0, 0), angle=math.pi / 2, phase=0.0),
BlochSphereRotation(Qubit(0), axis=(0, 0, 1), angle=math.pi / 2, phase=0.0),
BlochSphereRotation(Qubit(0), axis=(1, 0, 0), angle=math.pi / 2, phase=0.0),
]


def test_arbitrary(decomposer: McKayDecomposer) -> None:
assert decomposer.decompose(BlochSphereRotation(qubit=Qubit(0), angle=5.21, axis=(1, 2, 3), phase=0.324)) == [
Rz(Qubit(0), Float(0.018644578210707863)),
X90(Qubit(0)),
Rz(Qubit(0), Float(2.520651583905213)),
X90(Qubit(0)),
Rz(Qubit(0), Float(2.2329420137988887)),
]
27 changes: 13 additions & 14 deletions test/exporter/test_quantify_scheduler_exporter.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import contextlib
import importlib.util
import math
import unittest
import unittest.mock

import pytest

from opensquirrel.circuit import Circuit
from opensquirrel.common import ATOL
from opensquirrel.default_gates import CCZ, CZ, SWAP, H, Ry, Rz, X
Expand Down Expand Up @@ -38,7 +39,7 @@ def __exit__(self, exc_type, exc_value, exc_traceback):
self._stack.__exit__(exc_type, exc_value, exc_traceback)


class QuantifySchedulerExporterTest(unittest.TestCase):
class TestQuantifySchedulerExporter:
def test_export(self):
register_manager = RegisterManager(qubit_register_size=3)
ir = IR()
Expand Down Expand Up @@ -68,15 +69,15 @@ def test_export(self):
)
mock_quantify_scheduler_gates.CZ.assert_called_once_with(qC="q[0]", qT="q[1]")
mock_quantify_scheduler_gates.Rz.assert_called_once_with(theta=FloatEq(math.degrees(2.34)), qubit="q[1]")
self.assertEqual(mock_schedule.add.call_count, 7)
assert mock_schedule.add.call_count == 7

def check_gate_not_supported(self, g: Gate):
def check_gate_not_supported(self, g: Gate) -> None:
register_manager = RegisterManager(qubit_register_size=3)
ir = IR()
ir.add_gate(g)

with MockedQuantifyScheduler():
with self.assertRaisesRegex(Exception, "Cannot exporter circuit: it contains unsupported gates"):
with pytest.raises(Exception, match="Cannot exporter circuit: it contains unsupported gates"):
quantify_scheduler_exporter.export(Circuit(register_manager, ir))

def test_gates_not_supported(self):
Expand All @@ -86,12 +87,10 @@ def test_gates_not_supported(self):
self.check_gate_not_supported(CCZ(Qubit(0), Qubit(1), Qubit(2)))


class QuantifySchedulerNotInstalledTest(unittest.TestCase):
@unittest.skipIf(
importlib.util.find_spec("quantify_scheduler") is not None, reason="quantify_scheduler is installed"
)
def test_quantify_scheduler_not_installed(self):
with self.assertRaisesRegex(
Exception, "quantify-scheduler is not installed, or cannot be installed on your system"
):
quantify_scheduler_exporter.export(unittest.mock.MagicMock())
@pytest.mark.skipif(
importlib.util.find_spec("quantify_scheduler") is not None, reason="quantify_scheduler is installed"
)
def test_quantify_scheduler_not_installed() -> None:
empty_circuit = Circuit(RegisterManager(1), IR())
with pytest.raises(Exception, match="quantify-scheduler is not installed, or cannot be installed on your system"):
quantify_scheduler_exporter.export(empty_circuit)
49 changes: 28 additions & 21 deletions test/ir_equality_test_base.py
Original file line number Diff line number Diff line change
@@ -1,30 +1,37 @@
import unittest
from __future__ import annotations

from opensquirrel import circuit_matrix_calculator
from opensquirrel.circuit import Circuit
from collections.abc import Callable
from typing import Any

import numpy as np
from numpy.typing import NDArray

from opensquirrel import Circuit, circuit_matrix_calculator
from opensquirrel.common import are_matrices_equivalent_up_to_global_phase


class IREqualityTestBase(unittest.TestCase):
def check_equivalence_up_to_global_phase(self, matrix_a, matrix_b):
self.assertTrue(are_matrices_equivalent_up_to_global_phase(matrix_a, matrix_b))
def check_equivalence_up_to_global_phase(matrix_a: NDArray[np.complex_], matrix_b: NDArray[np.complex_]) -> None:
assert are_matrices_equivalent_up_to_global_phase(matrix_a, matrix_b)


def modify_circuit_and_check(self, circuit, action, expected_circuit=None):
"""
Checks whether the action preserves:
- the number of qubits,
- the qubit register name(s),
- the circuit matrix up to a global phase factor.
"""
# Store matrix before decompositions.
expected_matrix = circuit_matrix_calculator.get_circuit_matrix(circuit)
def modify_circuit_and_check(
circuit: Circuit, action: Callable[[Circuit, Any]], expected_circuit: Circuit | None = None
):
"""
Checks whether the action preserves:
- the number of qubits,
- the qubit register name(s),
- the circuit matrix up to a global phase factor.
"""
# Store matrix before decompositions.
expected_matrix = circuit_matrix_calculator.get_circuit_matrix(circuit)

action(circuit)
action(circuit)

# Get matrix after decompositions.
actual_matrix = circuit_matrix_calculator.get_circuit_matrix(circuit)
# Get matrix after decompositions.
actual_matrix = circuit_matrix_calculator.get_circuit_matrix(circuit)

self.check_equivalence_up_to_global_phase(actual_matrix, expected_matrix)
check_equivalence_up_to_global_phase(actual_matrix, expected_matrix)

if expected_circuit is not None:
self.assertEqual(circuit, expected_circuit)
if expected_circuit is not None:
assert circuit == expected_circuit
2 changes: 0 additions & 2 deletions test/mapper/test_qubit_remapper.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
from typing import List

import pytest

from opensquirrel.circuit import Circuit
Expand Down
Loading
Loading