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

🚨 adapt for Qiskit 0.46.0 #422

Merged
merged 3 commits into from
Feb 5, 2024
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
5 changes: 4 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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]
Expand Down
7 changes: 1 addition & 6 deletions src/mqt/qmap/load_calibration.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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

Expand Down
49 changes: 2 additions & 47 deletions src/mqt/qmap/qiskit/backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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.

Expand Down
15 changes: 14 additions & 1 deletion src/mqt/qmap/subarchitectures.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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.
Expand Down
2 changes: 1 addition & 1 deletion test/python/constraints.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
5 changes: 2 additions & 3 deletions test/python/test_cliffordsynthesis.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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()

Expand Down
21 changes: 14 additions & 7 deletions test/python/test_exact_mapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,29 @@

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)
qc.cx(0, 1)
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
Expand All @@ -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)
Expand All @@ -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
Expand All @@ -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)
Expand All @@ -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
Expand Down
21 changes: 14 additions & 7 deletions test/python/test_heuristic_mapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,29 @@

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)
qc.cx(0, 1)
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
Expand All @@ -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)
Expand All @@ -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
Expand All @@ -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)
Expand All @@ -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
Expand Down
47 changes: 10 additions & 37 deletions test/python/test_qiskit_backend_imports.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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
Loading
Loading