From 0fe420758f0e197ef81ece1ae13c6d6b49f29595 Mon Sep 17 00:00:00 2001 From: burgholzer Date: Mon, 5 Feb 2024 17:47:27 +0100 Subject: [PATCH 1/3] =?UTF-8?q?=E2=AC=86=EF=B8=8F=20raise=20Qiskit=20versi?= =?UTF-8?q?on=20to=200.46.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: burgholzer --- pyproject.toml | 5 ++++- test/python/constraints.txt | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index e633ae123..849df5e22 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -36,7 +36,7 @@ classifiers = [ ] requires-python = ">=3.8" dependencies = [ - "qiskit[qasm3-import]>=0.45.0", + "qiskit[qasm3-import]>=0.46.0", "rustworkx[all]>=0.13.0", "importlib_resources>=5.0; python_version < '3.10'", "typing_extensions>=4.0" @@ -146,6 +146,9 @@ filterwarnings = [ "ignore:.*qiskit.utils.algorithm_globals.QiskitAlgorithmGlobals*:DeprecationWarning:qiskit", "ignore:.*qiskit.extensions module is pending deprecation*:PendingDeprecationWarning:qiskit", 'ignore:.*datetime\.datetime\.utcfromtimestamp.*:DeprecationWarning:', + 'ignore:.*qiskit.utils.parallel*:DeprecationWarning:qiskit', + 'ignore:.*qiskit.tools.events*:DeprecationWarning:qiskit', + 'ignore:.*qiskit.qasm*:DeprecationWarning:qiskit', ] [tool.coverage] diff --git a/test/python/constraints.txt b/test/python/constraints.txt index a6b63750d..56f5be411 100644 --- a/test/python/constraints.txt +++ b/test/python/constraints.txt @@ -4,7 +4,7 @@ pybind11==2.11.0 pytest==7.0.0 importlib_resources==5.0.0 typing_extensions==4.0.0 -qiskit==0.45.0 +qiskit==0.46.0 rustworkx==0.13.0 mqt.qcec==2.0.0 distinctipy==1.2.2 From d382e6419be63aad0726269652039d4f338d4b34 Mon Sep 17 00:00:00 2001 From: burgholzer Date: Mon, 5 Feb 2024 17:49:03 +0100 Subject: [PATCH 2/3] =?UTF-8?q?=F0=9F=91=BD=20update=20`FakeBackend`=20cod?= =?UTF-8?q?e?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: burgholzer --- src/mqt/qmap/subarchitectures.py | 15 ++++++- test/python/test_cliffordsynthesis.py | 5 +-- test/python/test_exact_mapper.py | 21 ++++++---- test/python/test_heuristic_mapper.py | 21 ++++++---- test/python/test_qiskit_backend_imports.py | 47 +++++----------------- test/python/test_subarchitectures.py | 8 ++-- 6 files changed, 58 insertions(+), 59 deletions(-) diff --git a/src/mqt/qmap/subarchitectures.py b/src/mqt/qmap/subarchitectures.py index 7d2855331..c10918730 100644 --- a/src/mqt/qmap/subarchitectures.py +++ b/src/mqt/qmap/subarchitectures.py @@ -20,7 +20,7 @@ from collections.abc import Iterable from matplotlib import figure - from qiskit.providers import BackendV1 + from qiskit.providers import BackendV1, BackendV2 from typing_extensions import TypeAlias from . import Architecture @@ -104,6 +104,19 @@ def from_backend(cls, backend: BackendV1) -> SubarchitectureOrder: coupling_map = [(c[0], c[1]) for c in backend.configuration().coupling_map] return cls.from_coupling_map(coupling_map) + @classmethod + def from_backend_v2(cls, backend: BackendV2) -> SubarchitectureOrder: + """Construct the partial order from a coupling map defined as a Qiskit backend. + + Args: + backend: Qiskit backend. + + Returns: + The resulting partial order. + """ + coupling_map = [(c[0], c[1]) for c in backend.coupling_map] + return cls.from_coupling_map(coupling_map) + @classmethod def from_qmap_architecture(cls, arch: Architecture) -> SubarchitectureOrder: """Construct the partial order from a QMAP :class:`~mqt.qmap.Architecture` object. diff --git a/test/python/test_cliffordsynthesis.py b/test/python/test_cliffordsynthesis.py index a1c3e969f..68f6446ae 100644 --- a/test/python/test_cliffordsynthesis.py +++ b/test/python/test_cliffordsynthesis.py @@ -7,7 +7,7 @@ from pathlib import Path import pytest -from qiskit import QuantumCircuit +from qiskit import QuantumCircuit, qasm2 from qiskit.quantum_info import Clifford, PauliList from mqt import qcec, qmap @@ -236,8 +236,7 @@ def test_optimize_quantum_computation(bell_circuit: QuantumCircuit) -> None: def test_optimize_from_qasm_file(bell_circuit: QuantumCircuit) -> None: """Test that we can optimize from a QASM file.""" - with Path("bell.qasm").open("w") as f: - f.write(bell_circuit.qasm()) + qasm2.dump(bell_circuit, Path("bell.qasm")) circ, _ = qmap.optimize_clifford(circuit="bell.qasm") assert qcec.verify(circ, bell_circuit).considered_equivalent() diff --git a/test/python/test_exact_mapper.py b/test/python/test_exact_mapper.py index ee52fc414..3efc841de 100644 --- a/test/python/test_exact_mapper.py +++ b/test/python/test_exact_mapper.py @@ -2,14 +2,21 @@ from __future__ import annotations +import pytest from qiskit import QuantumCircuit -from qiskit.providers.fake_provider import FakeLondon +from qiskit.providers.fake_provider import GenericBackendV2 from mqt import qmap from mqt.qcec import verify -def test_exact_no_swaps_trivial_layout() -> None: +@pytest.fixture() +def backend() -> GenericBackendV2: + """Return a test backend.""" + return GenericBackendV2(num_qubits=5, coupling_map=[[0, 1], [1, 0], [1, 2], [2, 1], [1, 3], [3, 1], [3, 4], [4, 3]]) + + +def test_exact_no_swaps_trivial_layout(backend: GenericBackendV2) -> None: """Verify that the exact mapper works on a simple circuit that requires no swaps on a trivial initial layout.""" qc = QuantumCircuit(3) qc.h(0) @@ -17,7 +24,7 @@ def test_exact_no_swaps_trivial_layout() -> None: qc.cx(1, 2) qc.measure_all() - qc_mapped, results = qmap.compile(qc, arch=FakeLondon(), method="exact") + qc_mapped, results = qmap.compile(qc, arch=backend, method="exact") assert results.timeout is False assert results.mapped_circuit assert results.output.swaps == 0 @@ -26,7 +33,7 @@ def test_exact_no_swaps_trivial_layout() -> None: assert result.considered_equivalent() is True -def test_exact_no_swaps_non_trivial_layout() -> None: +def test_exact_no_swaps_non_trivial_layout(backend: GenericBackendV2) -> None: """Verify that the exact mapper works on a simple circuit that requires a non-trivial layout to achieve no swaps.""" qc = QuantumCircuit(4) qc.h(0) @@ -35,7 +42,7 @@ def test_exact_no_swaps_non_trivial_layout() -> None: qc.cx(0, 3) qc.measure_all() - qc_mapped, results = qmap.compile(qc, arch=FakeLondon(), method="exact") + qc_mapped, results = qmap.compile(qc, arch=backend, method="exact") assert results.timeout is False assert results.mapped_circuit @@ -45,7 +52,7 @@ def test_exact_no_swaps_non_trivial_layout() -> None: assert result.considered_equivalent() is True -def test_exact_non_trivial_swaps() -> None: +def test_exact_non_trivial_swaps(backend: GenericBackendV2) -> None: """Verify that the exact mapper works on a simple circuit that requires at least a single SWAP.""" qc = QuantumCircuit(3) qc.h(0) @@ -54,7 +61,7 @@ def test_exact_non_trivial_swaps() -> None: qc.cx(2, 0) qc.measure_all() - qc_mapped, results = qmap.compile(qc, arch=FakeLondon(), method="exact") + qc_mapped, results = qmap.compile(qc, arch=backend, method="exact") assert results.timeout is False assert results.mapped_circuit diff --git a/test/python/test_heuristic_mapper.py b/test/python/test_heuristic_mapper.py index b5c5d4704..7d771796f 100644 --- a/test/python/test_heuristic_mapper.py +++ b/test/python/test_heuristic_mapper.py @@ -2,14 +2,21 @@ from __future__ import annotations +import pytest from qiskit import QuantumCircuit -from qiskit.providers.fake_provider import FakeLondon +from qiskit.providers.fake_provider import GenericBackendV2 from mqt import qmap from mqt.qcec import verify -def test_heuristic_no_swaps_trivial_layout() -> None: +@pytest.fixture() +def backend() -> GenericBackendV2: + """Return a test backend.""" + return GenericBackendV2(num_qubits=5, coupling_map=[[0, 1], [1, 0], [1, 2], [2, 1], [1, 3], [3, 1], [3, 4], [4, 3]]) + + +def test_heuristic_no_swaps_trivial_layout(backend: GenericBackendV2) -> None: """Verify that the heuristic mapper works on a simple circuit that requires no swaps on a trivial initial layout.""" qc = QuantumCircuit(3) qc.h(0) @@ -17,7 +24,7 @@ def test_heuristic_no_swaps_trivial_layout() -> None: qc.cx(1, 2) qc.measure_all() - qc_mapped, results = qmap.compile(qc, arch=FakeLondon()) + qc_mapped, results = qmap.compile(qc, arch=backend) assert results.timeout is False assert results.mapped_circuit # assert results.output.swaps == 0 @@ -26,7 +33,7 @@ def test_heuristic_no_swaps_trivial_layout() -> None: assert result.considered_equivalent() is True -def test_heuristic_no_swaps_non_trivial_layout() -> None: +def test_heuristic_no_swaps_non_trivial_layout(backend: GenericBackendV2) -> None: """Verify that the heuristic mapper works on a simple circuit that requires a non-trivial layout to achieve no swaps.""" qc = QuantumCircuit(4) qc.h(0) @@ -35,7 +42,7 @@ def test_heuristic_no_swaps_non_trivial_layout() -> None: qc.cx(0, 3) qc.measure_all() - qc_mapped, results = qmap.compile(qc, arch=FakeLondon()) + qc_mapped, results = qmap.compile(qc, arch=backend) assert results.timeout is False assert results.mapped_circuit @@ -45,7 +52,7 @@ def test_heuristic_no_swaps_non_trivial_layout() -> None: assert result.considered_equivalent() is True -def test_heuristic_non_trivial_swaps() -> None: +def test_heuristic_non_trivial_swaps(backend: GenericBackendV2) -> None: """Verify that the heuristic mapper works on a simple circuit that requires at least a single SWAP.""" qc = QuantumCircuit(3) qc.h(0) @@ -54,7 +61,7 @@ def test_heuristic_non_trivial_swaps() -> None: qc.cx(2, 0) qc.measure_all() - qc_mapped, results = qmap.compile(qc, arch=FakeLondon()) + qc_mapped, results = qmap.compile(qc, arch=backend) assert results.timeout is False assert results.mapped_circuit diff --git a/test/python/test_qiskit_backend_imports.py b/test/python/test_qiskit_backend_imports.py index 48f9cdb29..11ea22927 100644 --- a/test/python/test_qiskit_backend_imports.py +++ b/test/python/test_qiskit_backend_imports.py @@ -4,12 +4,7 @@ import pytest from qiskit import QuantumCircuit -from qiskit.providers.fake_provider import ( - FakeAthens, - FakeAthensV2, - FakeLondon, - FakeLondonV2, -) +from qiskit.providers.fake_provider import GenericBackendV2 from mqt import qmap @@ -25,43 +20,21 @@ def example_circuit() -> QuantumCircuit: return qc -def test_old_backend_v1(example_circuit: QuantumCircuit) -> None: - """Test that circuits can be mapped to Qiskit BackendV1 instances providing the old basis_gates.""" - _, results = qmap.compile(example_circuit, arch=FakeLondon()) - assert results.timeout is False - assert results.mapped_circuit - - -def test_old_backend_v2(example_circuit: QuantumCircuit) -> None: - """Test that circuits can be mapped to Qiskit BackendV2 instances providing the old basis_gates.""" - _, results = qmap.compile(example_circuit, arch=FakeLondonV2()) - assert results.timeout is False - assert results.mapped_circuit - - -def test_new_backend_v1(example_circuit: QuantumCircuit) -> None: - """Test that circuits can be mapped to Qiskit BackendV1 instances providing the new basis_gates.""" - _, results = qmap.compile(example_circuit, arch=FakeAthens()) - assert results.timeout is False - assert results.mapped_circuit - - -def test_new_backend_v2(example_circuit: QuantumCircuit) -> None: - """Test that circuits can be mapped to Qiskit BackendV2 instances providing the new basis_gates.""" - _, results = qmap.compile(example_circuit, arch=FakeAthensV2()) - assert results.timeout is False - assert results.mapped_circuit +@pytest.fixture() +def backend() -> GenericBackendV2: + """Return a test backend.""" + return GenericBackendV2(num_qubits=5, coupling_map=[[0, 1], [1, 0], [1, 2], [2, 1], [1, 3], [3, 1], [3, 4], [4, 3]]) -def test_architecture_from_v1_backend_properties(example_circuit: QuantumCircuit) -> None: - """Test that circuits can be mapped by simply providing the backend properties (the BackendV1 way).""" - _, results = qmap.compile(example_circuit, arch=None, calibration=FakeLondon().properties()) +def test_backend_v2(example_circuit: QuantumCircuit, backend: GenericBackendV2) -> None: + """Test that circuits can be mapped to Qiskit BackendV1 instances providing the old basis_gates.""" + _, results = qmap.compile(example_circuit, arch=backend) assert results.timeout is False assert results.mapped_circuit -def test_architecture_from_v2_target(example_circuit: QuantumCircuit) -> None: +def test_architecture_from_v2_target(example_circuit: QuantumCircuit, backend: GenericBackendV2) -> None: """Test that circuits can be mapped by simply providing the target (the BackendV2 way).""" - _, results = qmap.compile(example_circuit, arch=None, calibration=FakeLondonV2().target) + _, results = qmap.compile(example_circuit, arch=None, calibration=backend.target) assert results.timeout is False assert results.mapped_circuit diff --git a/test/python/test_subarchitectures.py b/test/python/test_subarchitectures.py index 6b28279ed..4e6cff05c 100644 --- a/test/python/test_subarchitectures.py +++ b/test/python/test_subarchitectures.py @@ -8,7 +8,7 @@ import pytest import rustworkx as rx -from qiskit.providers.fake_provider import FakeLondon +from qiskit.providers.fake_provider import GenericBackendV2 from mqt.qmap import Architecture from mqt.qmap.subarchitectures import ( @@ -219,9 +219,9 @@ def test_subarchitecture_from_qmap_arch() -> None: def test_subarchitecture_from_qiskit_backend() -> None: """Verify that subarchitecture order can be created from Qiskit backends.""" - arch = FakeLondon() - so_arch = SubarchitectureOrder.from_backend(arch) - cm = [(c[0], c[1]) for c in arch.configuration().coupling_map] + arch = GenericBackendV2(num_qubits=5, coupling_map=[[0, 1], [1, 0], [1, 2], [2, 1], [1, 3], [3, 1], [3, 4], [4, 3]]) + so_arch = SubarchitectureOrder.from_backend_v2(arch) + cm = [(c[0], c[1]) for c in arch.coupling_map] so_cm = SubarchitectureOrder.from_coupling_map(cm) assert so_arch.subarch_order == so_cm.subarch_order From ab0a6e8009252a6b90faeb94269defb87e2527a7 Mon Sep 17 00:00:00 2001 From: burgholzer Date: Mon, 5 Feb 2024 23:07:13 +0100 Subject: [PATCH 3/3] =?UTF-8?q?=F0=9F=94=A5=20remove=20outdated=20code?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: burgholzer --- src/mqt/qmap/load_calibration.py | 7 +---- src/mqt/qmap/qiskit/backend.py | 49 ++------------------------------ 2 files changed, 3 insertions(+), 53 deletions(-) diff --git a/src/mqt/qmap/load_calibration.py b/src/mqt/qmap/load_calibration.py index ec0fbbde0..49a438944 100644 --- a/src/mqt/qmap/load_calibration.py +++ b/src/mqt/qmap/load_calibration.py @@ -4,14 +4,13 @@ from typing import TYPE_CHECKING -from qiskit.providers.models import BackendProperties from qiskit.transpiler.target import Target if TYPE_CHECKING: from .pyqmap import Architecture -def load_calibration(architecture: Architecture, calibration: str | BackendProperties | Target | None = None) -> None: +def load_calibration(architecture: Architecture, calibration: str | Target | None = None) -> None: """Load a calibration from a string, BackendProperties, or Target. Args: @@ -23,10 +22,6 @@ def load_calibration(architecture: Architecture, calibration: str | BackendPrope if isinstance(calibration, str): architecture.load_properties(calibration) - elif isinstance(calibration, BackendProperties): - from mqt.qmap.qiskit.backend import import_backend_properties - - architecture.load_properties(import_backend_properties(calibration)) elif isinstance(calibration, Target): from mqt.qmap.qiskit.backend import import_target diff --git a/src/mqt/qmap/qiskit/backend.py b/src/mqt/qmap/qiskit/backend.py index 671aff571..2a48b158f 100644 --- a/src/mqt/qmap/qiskit/backend.py +++ b/src/mqt/qmap/qiskit/backend.py @@ -4,10 +4,9 @@ from typing import TYPE_CHECKING -from qiskit.providers import Backend, BackendV1, BackendV2 +from qiskit.providers import Backend, BackendV1, BackendV2, BackendV2Converter if TYPE_CHECKING: - from qiskit.providers.models import BackendProperties from qiskit.transpiler import Target from mqt.qmap import Architecture @@ -24,57 +23,13 @@ def import_backend(backend: Backend) -> Architecture: """ if isinstance(backend, BackendV1): - return import_backend_v1(backend) + return import_backend_v2(BackendV2Converter(backend)) if isinstance(backend, BackendV2): return import_backend_v2(backend) msg = f"Backend type {type(backend)} not supported." raise TypeError(msg) -def import_backend_properties(backend_properties: BackendProperties) -> Architecture.Properties: - """Import backend properties from qiskit.providers.models.BackendProperties. - - Args: - backend_properties: The backend properties to import. - - Returns: - The imported backend properties as an Architecture.Properties object. - """ - props = Architecture.Properties() - props.name = backend_properties.backend_name - props.num_qubits = len(backend_properties.qubits) - for qubit in range(props.num_qubits): - props.set_t1(qubit, backend_properties.t1(qubit)) - props.set_t2(qubit, backend_properties.t2(qubit)) - props.set_frequency(qubit, backend_properties.frequency(qubit)) - props.set_readout_error(qubit, backend_properties.readout_error(qubit)) - - for gate in backend_properties.gates: - if gate.gate == "reset": - continue - - if len(gate.qubits) == 1: - props.set_single_qubit_error( - gate.qubits[0], gate.gate, backend_properties.gate_error(gate.gate, gate.qubits) - ) - elif len(gate.qubits) == 2: - props.set_two_qubit_error( - gate.qubits[0], gate.qubits[1], backend_properties.gate_error(gate.gate, gate.qubits), gate.gate - ) - return props - - -def import_backend_v1(backend: BackendV1) -> Architecture: - """Import a backend from qiskit.providers.BackendV1.""" - arch = Architecture() - arch.name = backend.name() - arch.num_qubits = backend.configuration().n_qubits - arch.coupling_map = {(c[0], c[1]) for c in backend.configuration().coupling_map} - arch.properties = import_backend_properties(backend.properties()) - - return arch - - def import_target(target: Target) -> Architecture.Properties: """Import a target from qiskit.transpiler.Target.