diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 5a96655..58388a2 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -35,3 +35,7 @@ repos: - id: check-executables-have-shebangs - id: check-merge-conflict - id: detect-private-key + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.6.9 + hooks: + - id: ruff diff --git a/docs/build-docs b/docs/build-docs index 772e12a..7e5ce87 100755 --- a/docs/build-docs +++ b/docs/build-docs @@ -1,9 +1,9 @@ #!/usr/bin/env python import argparse -from datetime import date import shutil import subprocess import sys +from datetime import date from importlib import import_module from pathlib import Path from typing import Any @@ -90,7 +90,7 @@ if __name__ == "__main__": parser.add_argument("-d", "--dest", help="copy artifacts into destination folder") args = parser.parse_args() - print("Building docs for modules:", MODULE) + print("Building docs for modules:", MODULE) # noqa: T201 build_module_docs() if args.dest is not None: diff --git a/docs/conf.py b/docs/conf.py index b940db7..712b4fe 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -1,13 +1,9 @@ import re -from typing import Any -from typing import Dict -from typing import Optional -from typing import Tuple +from typing import Any, Optional from urllib.parse import urljoin from docutils import nodes -from docutils.nodes import Element -from docutils.nodes import TextElement +from docutils.nodes import Element, TextElement from sphinx.application import Sphinx from sphinx.environment import BuildEnvironment @@ -118,10 +114,10 @@ def correct_signature( what: str, name: str, obj: Any, - options: Dict, + options: dict, signature: str, return_annotation: str, -) -> Tuple[str, str]: +) -> tuple[str, str]: new_signature = signature new_return_annotation = return_annotation for k, v in app.config.custom_internal_mapping.items(): diff --git a/noxfile.py b/noxfile.py index f7b420f..71993bc 100644 --- a/noxfile.py +++ b/noxfile.py @@ -3,9 +3,9 @@ import os import shlex import sys +from collections.abc import Iterable from pathlib import Path from textwrap import dedent -from typing import Iterable import nox diff --git a/pytket/extensions/aqt/__init__.py b/pytket/extensions/aqt/__init__.py index c3bcd6e..9d54a5d 100644 --- a/pytket/extensions/aqt/__init__.py +++ b/pytket/extensions/aqt/__init__.py @@ -12,10 +12,11 @@ # See the License for the specific language governing permissions and # limitations under the License. """Backends for processing pytket circuits with AQT devices.""" + from .backends import AQTBackend from .backends.config import ( - AQTConfig, - set_aqt_config, AQTAccessToken, + AQTConfig, print_available_devices, + set_aqt_config, ) diff --git a/pytket/extensions/aqt/backends/__init__.py b/pytket/extensions/aqt/backends/__init__.py index bd1ed2c..74d6b2c 100644 --- a/pytket/extensions/aqt/backends/__init__.py +++ b/pytket/extensions/aqt/backends/__init__.py @@ -11,6 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -"""Backends for processing pytket circuits with AQT devices -""" +"""Backends for processing pytket circuits with AQT devices""" + from .aqt import AQTBackend diff --git a/pytket/extensions/aqt/backends/aqt.py b/pytket/extensions/aqt/backends/aqt.py index 8ce768b..d4c12d9 100644 --- a/pytket/extensions/aqt/backends/aqt.py +++ b/pytket/extensions/aqt/backends/aqt.py @@ -14,66 +14,56 @@ import json import logging import time -from typing import Any -from typing import cast -from typing import Dict -from typing import List -from typing import Optional -from typing import Sequence -from typing import Tuple -from typing import Union -from typing_extensions import assert_never +from collections.abc import Sequence +from typing import Any, Optional, Union, cast import numpy from qiskit_aqt_provider import api_models, api_models_generated from qiskit_aqt_provider.aqt_provider import OFFLINE_SIMULATORS +from typing_extensions import assert_never -from pytket.backends import Backend -from pytket.backends import CircuitStatus -from pytket.backends import ResultHandle -from pytket.backends import StatusEnum +from pytket.backends import Backend, CircuitStatus, ResultHandle, StatusEnum from pytket.backends.backend import KwargTypes from pytket.backends.backend_exceptions import CircuitNotRunError, CircuitNotValidError -from pytket.backends.backendinfo import BackendInfo -from pytket.backends.backendinfo import fully_connected_backendinfo +from pytket.backends.backendinfo import BackendInfo, fully_connected_backendinfo from pytket.backends.backendresult import BackendResult from pytket.backends.resulthandle import _ResultIdTuple -from pytket.circuit import Circuit -from pytket.circuit import OpType -from pytket.circuit import Qubit -from pytket.passes import auto_rebase_pass -from pytket.passes import BasePass -from pytket.passes import DecomposeBoxes -from pytket.passes import EulerAngleReduction -from pytket.passes import FlattenRegisters -from pytket.passes import FullPeepholeOptimise -from pytket.passes import RenameQubitsPass -from pytket.passes import SequencePass -from pytket.passes import SimplifyInitial -from pytket.passes import SynthesiseTket -from pytket.predicates import GateSetPredicate -from pytket.predicates import MaxNQubitsPredicate -from pytket.predicates import NoClassicalControlPredicate -from pytket.predicates import NoFastFeedforwardPredicate -from pytket.predicates import NoMidMeasurePredicate -from pytket.predicates import NoSymbolsPredicate -from pytket.predicates import Predicate +from pytket.circuit import Circuit, OpType, Qubit +from pytket.passes import ( + BasePass, + DecomposeBoxes, + EulerAngleReduction, + FlattenRegisters, + FullPeepholeOptimise, + RenameQubitsPass, + SequencePass, + SimplifyInitial, + SynthesiseTket, + auto_rebase_pass, +) +from pytket.predicates import ( + GateSetPredicate, + MaxNQubitsPredicate, + NoClassicalControlPredicate, + NoFastFeedforwardPredicate, + NoMidMeasurePredicate, + NoSymbolsPredicate, + Predicate, +) from pytket.utils import prepare_circuit from pytket.utils.outcomearray import OutcomeArray +from ..extension_version import __extension_version__ from .aqt_api import ( - AqtOfflineApi, - AqtRemoteApi, - AqtMockApi, AQT_MOCK_DEVICES, AqtApi, + AqtMockApi, + AqtOfflineApi, + AqtRemoteApi, unwrap, ) from .aqt_job_data import PytketAqtJob, PytketAqtJobCircuitData -from ..extension_version import __extension_version__ - - logger = logging.getLogger(__name__) AQT_PORTAL_URL = "https://arnica.aqt.eu/api/v1" @@ -92,7 +82,7 @@ OpType.Barrier, } -AQTResult = Tuple[int, List[int]] # (n_qubits, list of readouts) +AQTResult = tuple[int, list[int]] # (n_qubits, list of readouts) AQT_OFFLINE_SIMULATORS = {sim.id: sim for sim in OFFLINE_SIMULATORS} @@ -218,7 +208,7 @@ def print_device_table(cls, access_token: Optional[str] = None) -> None: @classmethod def available_devices( cls, access_token: Optional[str] = None, **kwargs: Any - ) -> List[BackendInfo]: + ) -> list[BackendInfo]: """ See :py:meth:`pytket.backends.Backend.available_devices`. Supported kwargs: none. @@ -246,7 +236,7 @@ def available_devices( ] @property - def required_predicates(self) -> List[Predicate]: + def required_predicates(self) -> list[Predicate]: preds = [ NoClassicalControlPredicate(), NoFastFeedforwardPredicate(), @@ -358,7 +348,7 @@ def process_circuits( n_shots: Union[None, int, Sequence[Optional[int]]] = None, valid_check: bool = True, **kwargs: KwargTypes, - ) -> List[ResultHandle]: + ) -> list[ResultHandle]: """ See :py:meth:`pytket.backends.Backend.process_circuits`. @@ -418,7 +408,7 @@ def process_circuits( return handles def _update_cache_result( - self, handle: ResultHandle, result_dict: Dict[str, BackendResult] + self, handle: ResultHandle, result_dict: dict[str, BackendResult] ) -> None: if handle in self._cache: self._cache[handle].update(result_dict) diff --git a/pytket/extensions/aqt/backends/aqt_api.py b/pytket/extensions/aqt/backends/aqt_api.py index 127c1ba..4d56591 100644 --- a/pytket/extensions/aqt/backends/aqt_api.py +++ b/pytket/extensions/aqt/backends/aqt_api.py @@ -12,28 +12,32 @@ # See the License for the specific language governing permissions and # limitations under the License. from __future__ import annotations + import json import uuid from dataclasses import dataclass -from typing import Protocol, Final, TypeVar +from typing import TYPE_CHECKING, Final, Protocol, TypeVar -import httpx from qiskit_aqt_provider import AQTProvider, api_models from qiskit_aqt_provider.api_models_generated import ( + JobResponseRRFinished, JobUser, - RRFinished, ResultItem, - JobResponseRRFinished, + RRFinished, ) from qiskit_aqt_provider.aqt_job import AQTJob from qiskit_aqt_provider.aqt_options import AQTOptions -from qiskit_aqt_provider.aqt_provider import OfflineSimulator from qiskit_aqt_provider.aqt_resource import AQTResource, OfflineSimulatorResource from qiskit_aqt_provider.circuit_to_aqt import aqt_to_qiskit_circuit -from .aqt_job_data import PytketAqtJob from .config import AQTAccessToken +if TYPE_CHECKING: + import httpx + from qiskit_aqt_provider.aqt_provider import OfflineSimulator + + from .aqt_job_data import PytketAqtJob + @dataclass class AqtDevice: @@ -57,7 +61,7 @@ def from_aqt_resource(cls, aqt_resource: AQTResource) -> AqtDevice: def unwrap(obj: T | None) -> T: if obj is None: - raise ValueError(f"Value cannot be None") + raise ValueError("Value cannot be None") return obj @@ -96,7 +100,7 @@ def get_devices(self) -> list[AqtDevice]: def print_device_table(self) -> None: aqt_provider = AQTProvider(access_token=self._access_token) backend_table = aqt_provider.backends() - print(backend_table) + print(backend_table) # noqa: T201 def post_aqt_job(self, job: PytketAqtJob, aqt_device: AqtDevice) -> str: aqt_job = _aqt_job_from_pytket_aqt_job(job) @@ -142,7 +146,7 @@ def get_devices(self) -> list[AqtDevice]: def print_device_table(self) -> None: backend_table = self._aqt_provider.backends() - print(backend_table) + print(backend_table) # noqa: T201 def post_aqt_job(self, aqt_job: PytketAqtJob, aqt_device: AqtDevice) -> str: circuits = [ @@ -184,7 +188,7 @@ def get_devices(self) -> list[AqtDevice]: return AQT_MOCK_DEVICES def print_device_table(self) -> None: - print("Mock device table") + print("Mock device table") # noqa: T201 def post_aqt_job(self, aqt_job: PytketAqtJob, aqt_device: AqtDevice) -> str: job_id = str(uuid.uuid4()) diff --git a/pytket/extensions/aqt/backends/aqt_job_data.py b/pytket/extensions/aqt/backends/aqt_job_data.py index 7fd8c41..5e3d463 100644 --- a/pytket/extensions/aqt/backends/aqt_job_data.py +++ b/pytket/extensions/aqt/backends/aqt_job_data.py @@ -12,8 +12,10 @@ # See the License for the specific language governing permissions and # limitations under the License. import json +from collections.abc import Sequence from dataclasses import dataclass -from typing import Optional, Sequence +from typing import Optional + from qiskit_aqt_provider import api_models from pytket import Circuit diff --git a/pytket/extensions/aqt/backends/aqt_multi_zone.py b/pytket/extensions/aqt/backends/aqt_multi_zone.py index e5d91ac..87e95cb 100644 --- a/pytket/extensions/aqt/backends/aqt_multi_zone.py +++ b/pytket/extensions/aqt/backends/aqt_multi_zone.py @@ -12,52 +12,44 @@ # See the License for the specific language governing permissions and # limitations under the License. import json +from collections.abc import Sequence from copy import deepcopy -from typing import Any, cast -from typing import Dict -from typing import List -from typing import Optional -from typing import Sequence -from typing import Tuple -from typing import Union +from typing import Any, Optional, Union, cast - -from pytket.unit_id import UnitID -from pytket.backends import Backend -from pytket.backends import CircuitStatus -from pytket.backends import ResultHandle -from pytket.backends import StatusEnum +from pytket.backends import Backend, CircuitStatus, ResultHandle, StatusEnum from pytket.backends.backend import KwargTypes -from pytket.backends.backendinfo import BackendInfo -from pytket.backends.backendinfo import fully_connected_backendinfo +from pytket.backends.backendinfo import BackendInfo, fully_connected_backendinfo from pytket.backends.backendresult import BackendResult from pytket.backends.resulthandle import _ResultIdTuple -from pytket.circuit import Circuit -from pytket.circuit import OpType -from pytket.circuit import Qubit -from pytket.passes import auto_rebase_pass -from pytket.passes import BasePass -from pytket.passes import DecomposeBoxes -from pytket.passes import EulerAngleReduction -from pytket.passes import FlattenRegisters -from pytket.passes import FullPeepholeOptimise -from pytket.passes import RenameQubitsPass -from pytket.passes import SequencePass -from pytket.passes import SynthesiseTket -from pytket.predicates import GateSetPredicate -from pytket.predicates import MaxNQubitsPredicate -from pytket.predicates import NoClassicalControlPredicate -from pytket.predicates import NoFastFeedforwardPredicate -from pytket.predicates import NoMidMeasurePredicate -from pytket.predicates import NoSymbolsPredicate -from pytket.predicates import Predicate +from pytket.circuit import Circuit, OpType, Qubit +from pytket.passes import ( + BasePass, + DecomposeBoxes, + EulerAngleReduction, + FlattenRegisters, + FullPeepholeOptimise, + RenameQubitsPass, + SequencePass, + SynthesiseTket, + auto_rebase_pass, +) +from pytket.predicates import ( + GateSetPredicate, + MaxNQubitsPredicate, + NoClassicalControlPredicate, + NoFastFeedforwardPredicate, + NoMidMeasurePredicate, + NoSymbolsPredicate, + Predicate, +) +from pytket.unit_id import UnitID from ..backends.config import AQTConfig +from ..extension_version import __extension_version__ from ..multi_zone_architecture.architecture import MultiZoneArchitecture from ..multi_zone_architecture.circuit.multizone_circuit import ( MultiZoneCircuit, ) -from ..extension_version import __extension_version__ from ..multi_zone_architecture.circuit_routing.route_circuit import ( route_circuit, ) @@ -79,7 +71,7 @@ OpType.Barrier, } -AQTResult = Tuple[int, List[int]] # (n_qubits, list of readouts) +AQTResult = tuple[int, list[int]] # (n_qubits, list of readouts) # TODO add more _STATUS_MAP = { @@ -141,7 +133,7 @@ def __init__( self._header = {"Ocp-Apim-Subscription-Key": access_token, "SDK": "pytket"} self._backend_info: Optional[BackendInfo] = None - self._qm: Dict[Qubit, Qubit] = {} + self._qm: dict[Qubit, Qubit] = {} self._architecture = architecture self._backend_info = fully_connected_backendinfo( type(self).__name__, @@ -164,7 +156,7 @@ def backend_info(self) -> Optional[BackendInfo]: return self._backend_info @classmethod - def available_devices(cls, **kwargs: Any) -> List[BackendInfo]: + def available_devices(cls, **kwargs: Any) -> list[BackendInfo]: """ See :py:meth:`pytket.backends.Backend.available_devices`. Supported kwargs: none. @@ -172,7 +164,7 @@ def available_devices(cls, **kwargs: Any) -> List[BackendInfo]: return [] @property - def required_predicates(self) -> List[Predicate]: + def required_predicates(self) -> list[Predicate]: preds = [ NoClassicalControlPredicate(), NoFastFeedforwardPredicate(), @@ -228,7 +220,7 @@ def process_circuits( n_shots: Union[None, int, Sequence[Optional[int]]] = None, valid_check: bool = True, **kwargs: KwargTypes, - ) -> List[ResultHandle]: + ) -> list[ResultHandle]: """ See :py:meth:`pytket.backends.Backend.process_circuits`. Supported kwargs: none. @@ -236,7 +228,7 @@ def process_circuits( raise NotImplementedError def _update_cache_result( - self, handle: ResultHandle, result_dict: Dict[str, BackendResult] + self, handle: ResultHandle, result_dict: dict[str, BackendResult] ) -> None: raise NotImplementedError @@ -365,7 +357,7 @@ def compile_manually_routed_multi_zone_circuit( new_circuit.multi_zone_operations = deepcopy(circuit.multi_zone_operations) current_multiop_index_per_qubit: dict[int, int] = { - k: 0 for k in new_circuit.multi_zone_operations.keys() + k: 0 for k in new_circuit.multi_zone_operations } for cmd in compiled_circuit: op = cmd.op @@ -390,7 +382,7 @@ def compile_manually_routed_multi_zone_circuit( def get_aqt_json_syntax_for_compiled_circuit( circuit: MultiZoneCircuit | Circuit, -) -> List[List]: +) -> list[list]: """Get python List object containing circuit instructions in AQT JSON Syntax""" aqt_syntax_operation_list: list[list[Any]] = [] if isinstance(circuit, MultiZoneCircuit): @@ -415,7 +407,7 @@ def get_aqt_json_syntax_for_compiled_circuit( def _get_initial_zone_to_qubit_data( circ: Circuit, -) -> Tuple[dict[int, tuple[int, int]], dict[int, tuple[int, int]]]: +) -> tuple[dict[int, tuple[int, int]], dict[int, tuple[int, int]]]: """ From the initialization operations at the beginning of a circuit routed to a MultiZoneArchitecture, determine the initial mapping of @@ -443,11 +435,11 @@ def _get_initial_zone_to_qubit_data( return qubit_to_zone_position, zone_to_occupancy_offset -def _translate_aqt(circ: Circuit) -> Tuple[List[List], str]: +def _translate_aqt(circ: Circuit) -> tuple[list[list], str]: """Convert a circuit in the AQT gate set to AQT list representation, along with a JSON string describing the measure result permutations.""" - gates: List = list() - measures: List = list() + gates: list = list() + measures: list = list() qubit_to_zone_position, zone_to_occupancy_offset = _get_initial_zone_to_qubit_data( circ ) diff --git a/pytket/extensions/aqt/backends/config.py b/pytket/extensions/aqt/backends/config.py index b317ee8..50284af 100644 --- a/pytket/extensions/aqt/backends/config.py +++ b/pytket/extensions/aqt/backends/config.py @@ -12,14 +12,12 @@ # See the License for the specific language governing permissions and # limitations under the License. """AQT config.""" + import logging from dataclasses import dataclass from getpass import getpass -from typing import Any -from typing import ClassVar -from typing import Dict -from typing import Optional -from typing import Type +from typing import Any, ClassVar, Optional + from qiskit_aqt_provider.aqt_provider import AQTProvider from pytket.config import PytketExtConfig @@ -35,9 +33,9 @@ class AQTConfig(PytketExtConfig): @classmethod def from_extension_dict( - cls: Type["AQTConfig"], ext_dict: Dict[str, Any] + cls: type["AQTConfig"], ext_dict: dict[str, Any] ) -> "AQTConfig": - return cls(ext_dict.get("access_token", None)) + return cls(ext_dict.get("access_token")) def set_aqt_config( @@ -119,4 +117,4 @@ def print_available_devices(access_token: Optional[str] = None) -> None: backends = aqt_provider.backends() backends.headers[1] = "Device ID" backends.headers[3] = "Device type" - print(backends) + print(backends) # noqa: T201 diff --git a/pytket/extensions/aqt/multi_zone_architecture/architecture.py b/pytket/extensions/aqt/multi_zone_architecture/architecture.py index a285acb..c084125 100644 --- a/pytket/extensions/aqt/multi_zone_architecture/architecture.py +++ b/pytket/extensions/aqt/multi_zone_architecture/architecture.py @@ -13,11 +13,9 @@ # limitations under the License. import os from enum import Enum -from typing import Dict -from typing import List from typing import Union -from pydantic import ConfigDict, BaseModel +from pydantic import BaseModel, ConfigDict class EdgeType(str, Enum): @@ -107,8 +105,8 @@ class ZoneType(BaseModel): name: str max_ions: int min_ions: int - zone_connections: Dict[str, ZoneConnection] - operations: List[Operation] + zone_connections: dict[str, ZoneConnection] + operations: list[Operation] class Zone(BaseModel): @@ -116,7 +114,7 @@ class Zone(BaseModel): name: str zone_type_id: int - connected_zones: Dict[int, str] + connected_zones: dict[int, str] class MultiZoneArchitecture(BaseModel): @@ -124,8 +122,8 @@ class MultiZoneArchitecture(BaseModel): n_qubits_max: int n_zones: int - zone_types: List[ZoneType] - zones: List[Zone] + zone_types: list[ZoneType] + zones: list[Zone] def get_connection_type( self, zone_index_source: int, zone_index_target: int @@ -144,7 +142,7 @@ def __str__(self) -> str: arch_spec_lines = [ f"Max number of qubits: {self.n_qubits_max}", f"Number of zones: {self.n_zones}", - f"", + "", ] for zone_id, zone in enumerate(self.zones): zone_type = self.zone_types[zone.zone_type_id] @@ -153,7 +151,7 @@ def __str__(self) -> str: f"Zone {zone_id}:", f" Max qubits {zone_type.max_ions}", f" Min qubits {zone_type.min_ions}", - f" Connections:", + " Connections:", ] ) for connected_zone, connection_name in zone.connected_zones.items(): diff --git a/pytket/extensions/aqt/multi_zone_architecture/circuit/multizone_circuit.py b/pytket/extensions/aqt/multi_zone_architecture/circuit/multizone_circuit.py index aadee0f..15db6da 100644 --- a/pytket/extensions/aqt/multi_zone_architecture/circuit/multizone_circuit.py +++ b/pytket/extensions/aqt/multi_zone_architecture/circuit/multizone_circuit.py @@ -13,26 +13,28 @@ # limitations under the License. import itertools +from collections.abc import Iterator from copy import deepcopy -from dataclasses import dataclass -from dataclasses import field +from dataclasses import dataclass, field from enum import Enum -from typing import Any, Optional, Iterator, TypeAlias +from typing import Any, Optional, TypeAlias -from sympy import symbols, Expr # type: ignore +from sympy import Expr, symbols # type: ignore -from pytket.circuit import UnitID -from pytket.circuit import Circuit -from pytket.circuit import CustomGateDef -from pytket.circuit import OpType +from pytket.circuit import Circuit, CustomGateDef, OpType, UnitID -from ..architecture import EdgeType, ConnectionType -from ..architecture import MultiZoneArchitecture -from ..architecture import source_edge_type -from ..architecture import target_edge_type -from ..macro_architecture_graph import empty_macro_arch_from_architecture -from ..macro_architecture_graph import MultiZoneMacroArch -from ..macro_architecture_graph import ZoneId +from ..architecture import ( + ConnectionType, + EdgeType, + MultiZoneArchitecture, + source_edge_type, + target_edge_type, +) +from ..macro_architecture_graph import ( + MultiZoneMacroArch, + ZoneId, + empty_macro_arch_from_architecture, +) ParamType: TypeAlias = Expr | float @@ -454,7 +456,7 @@ def validate(self) -> None: return current_multiop_index_per_qubit: dict[int, int] = { - k: 0 for k in self.multi_zone_operations.keys() + k: 0 for k in self.multi_zone_operations } for i, cmd in enumerate(self.pytket_circuit): op = cmd.op diff --git a/pytket/extensions/aqt/multi_zone_architecture/circuit_routing/greedy_routing.py b/pytket/extensions/aqt/multi_zone_architecture/circuit_routing/greedy_routing.py index 17f1272..54181b6 100644 --- a/pytket/extensions/aqt/multi_zone_architecture/circuit_routing/greedy_routing.py +++ b/pytket/extensions/aqt/multi_zone_architecture/circuit_routing/greedy_routing.py @@ -15,10 +15,10 @@ from pytket import Circuit, Qubit -from .settings import RoutingSettings from ..architecture import MultiZoneArchitecture -from ..circuit.multizone_circuit import MultiZoneCircuit from ..circuit.helpers import ZonePlacement, ZoneRoutingError +from ..circuit.multizone_circuit import MultiZoneCircuit +from .settings import RoutingSettings class GreedyCircuitRouter: diff --git a/pytket/extensions/aqt/multi_zone_architecture/circuit_routing/partition_routing.py b/pytket/extensions/aqt/multi_zone_architecture/circuit_routing/partition_routing.py index 7a2d592..632fda3 100644 --- a/pytket/extensions/aqt/multi_zone_architecture/circuit_routing/partition_routing.py +++ b/pytket/extensions/aqt/multi_zone_architecture/circuit_routing/partition_routing.py @@ -12,23 +12,23 @@ # See the License for the specific language governing permissions and # limitations under the License. import math +from collections.abc import Generator from copy import deepcopy -from typing import Generator from pytket import Circuit -from ..circuit.helpers import ZonePlacement, ZoneRoutingError -from .settings import RoutingSettings from ..architecture import MultiZoneArchitecture +from ..circuit.helpers import ZonePlacement, ZoneRoutingError from ..circuit.multizone_circuit import MultiZoneCircuit from ..depth_list.depth_list import ( + DepthList, get_initial_depth_list, get_updated_depth_list, - DepthList, ) from ..graph_algs.graph import GraphData from ..graph_algs.mt_kahypar import MtKahyparPartitioner -from ..macro_architecture_graph import empty_macro_arch_from_architecture, ZoneId +from ..macro_architecture_graph import ZoneId, empty_macro_arch_from_architecture +from .settings import RoutingSettings class PartitionCircuitRouter: @@ -65,7 +65,7 @@ def get_routed_circuit(self) -> MultiZoneCircuit: ) for old_place, new_place in self.placement_generator(depth_list): if self._settings.debug_level > 0: - print("-------") + print("-------") # noqa: T201 for zone in range(self._arch.n_zones): changes_str = ", ".join( [ @@ -77,7 +77,7 @@ def get_routed_circuit(self) -> MultiZoneCircuit: for i in set(old_place[zone]).difference(new_place[zone]) ] ) - print( + print( # noqa: T201 f"Z{zone}: {old_place[zone]} ->" f" {new_place[zone]} -- ({changes_str})" ) @@ -183,9 +183,9 @@ def new_placement_graph_partition_alg( self._settings.n_threads, log_level=self._settings.debug_level ) if self._settings.debug_level > 0: - print("Depth List:") + print("Depth List:") # noqa: T201 for i in range(min(4, len(depth_list))): - print(depth_list[i]) + print(depth_list[i]) # noqa: T201 vertex_to_part = partitioner.partition_graph(shuttle_graph_data, num_zones) new_placement: ZonePlacement = {i: [] for i in range(num_zones)} part_to_zone = [-1] * num_zones diff --git a/pytket/extensions/aqt/multi_zone_architecture/circuit_routing/route_circuit.py b/pytket/extensions/aqt/multi_zone_architecture/circuit_routing/route_circuit.py index b704770..5d5aebf 100644 --- a/pytket/extensions/aqt/multi_zone_architecture/circuit_routing/route_circuit.py +++ b/pytket/extensions/aqt/multi_zone_architecture/circuit_routing/route_circuit.py @@ -12,8 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. from pytket.circuit import Circuit -from .greedy_routing import GreedyCircuitRouter -from .settings import RoutingSettings, RoutingAlg + from ..architecture import MultiZoneArchitecture from ..circuit.helpers import ZonePlacement from ..circuit.multizone_circuit import MultiZoneCircuit @@ -21,6 +20,8 @@ MT_KAHYPAR_INSTALLED, MissingMtKahyparInstallError, ) +from .greedy_routing import GreedyCircuitRouter +from .settings import RoutingAlg, RoutingSettings if MT_KAHYPAR_INSTALLED: from .partition_routing import PartitionCircuitRouter diff --git a/pytket/extensions/aqt/multi_zone_architecture/circuit_routing/settings.py b/pytket/extensions/aqt/multi_zone_architecture/circuit_routing/settings.py index 7d4de80..a0a6751 100644 --- a/pytket/extensions/aqt/multi_zone_architecture/circuit_routing/settings.py +++ b/pytket/extensions/aqt/multi_zone_architecture/circuit_routing/settings.py @@ -12,6 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. from __future__ import annotations + from dataclasses import dataclass from enum import Enum diff --git a/pytket/extensions/aqt/multi_zone_architecture/compilation_settings.py b/pytket/extensions/aqt/multi_zone_architecture/compilation_settings.py index 93b7f47..274f883 100644 --- a/pytket/extensions/aqt/multi_zone_architecture/compilation_settings.py +++ b/pytket/extensions/aqt/multi_zone_architecture/compilation_settings.py @@ -12,6 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. from __future__ import annotations + from dataclasses import dataclass, field from typing import Final diff --git a/pytket/extensions/aqt/multi_zone_architecture/depth_list/depth_list.py b/pytket/extensions/aqt/multi_zone_architecture/depth_list/depth_list.py index 8d7f9dd..83ea5fc 100644 --- a/pytket/extensions/aqt/multi_zone_architecture/depth_list/depth_list.py +++ b/pytket/extensions/aqt/multi_zone_architecture/depth_list/depth_list.py @@ -43,13 +43,16 @@ def get_depth_list(n_qubits: int, gate_pairs: list[tuple[int, int]]) -> DepthLis qubit1 = pair[1] depth = max(current_depth_per_qubit[qubit0], current_depth_per_qubit[qubit1]) assert len(depth_list) >= depth - if depth > 0: - if (qubit0, qubit1) in depth_list[depth - 1] or ( + if depth > 0 and ( + (qubit0, qubit1) in depth_list[depth - 1] + or ( qubit1, qubit0, - ) in depth_list[depth - 1]: - depth_list[depth - 1].append((qubit0, qubit1)) - continue + ) + in depth_list[depth - 1] + ): + depth_list[depth - 1].append((qubit0, qubit1)) + continue if len(depth_list) > depth: depth_list[depth].append((qubit0, qubit1)) else: @@ -84,9 +87,7 @@ def get_updated_depth_list( for i, depth in enumerate(depth_list): for qubit_pair in depth: if qubit_to_zone[qubit_pair[0]] == qubit_to_zone[qubit_pair[1]]: - if not prune_stage: - pruned_depth_list[i].remove(qubit_pair) - elif ( + if not prune_stage or ( qubit_pair[0] not in prune_touched and qubit_pair[1] not in prune_touched ): diff --git a/pytket/extensions/aqt/multi_zone_architecture/graph_algs/mt_kahypar.py b/pytket/extensions/aqt/multi_zone_architecture/graph_algs/mt_kahypar.py index 4185ccd..bb29cc2 100644 --- a/pytket/extensions/aqt/multi_zone_architecture/graph_algs/mt_kahypar.py +++ b/pytket/extensions/aqt/multi_zone_architecture/graph_algs/mt_kahypar.py @@ -65,7 +65,7 @@ def partition_graph( graph.addFixedVertices(graph_data.fixed_list, num_parts) part_graph = graph.partition(self.context) if self.log_level > 0: - print("cut_cost: ", part_graph.cut()) + print("cut_cost: ", part_graph.cut()) # noqa: T201 vertex_part_id: list[int] = [] for vertex in range(graph_data.n_vertices): vertex_part_id.append(part_graph.blockID(vertex)) diff --git a/pytket/extensions/aqt/multi_zone_architecture/graph_algs/mt_kahypar_check.py b/pytket/extensions/aqt/multi_zone_architecture/graph_algs/mt_kahypar_check.py index 47bab2b..99e1a7e 100644 --- a/pytket/extensions/aqt/multi_zone_architecture/graph_algs/mt_kahypar_check.py +++ b/pytket/extensions/aqt/multi_zone_architecture/graph_algs/mt_kahypar_check.py @@ -18,6 +18,5 @@ class MissingMtKahyparInstallError(Exception): - def __init__(self) -> None: super().__init__("Graph partitioning requires mtkahypar package") diff --git a/pytket/extensions/aqt/multi_zone_architecture/initial_placement/initial_placement_generators.py b/pytket/extensions/aqt/multi_zone_architecture/initial_placement/initial_placement_generators.py index be0bb3c..1d6efc0 100644 --- a/pytket/extensions/aqt/multi_zone_architecture/initial_placement/initial_placement_generators.py +++ b/pytket/extensions/aqt/multi_zone_architecture/initial_placement/initial_placement_generators.py @@ -13,21 +13,20 @@ # limitations under the License. import math from dataclasses import dataclass -from typing import Protocol from logging import getLogger +from typing import Protocol from pytket import Circuit +from ..architecture import MultiZoneArchitecture +from ..circuit.helpers import ZonePlacement +from ..depth_list.depth_list import DepthList, get_initial_depth_list +from ..graph_algs.graph import GraphData from ..graph_algs.mt_kahypar_check import ( MT_KAHYPAR_INSTALLED, MissingMtKahyparInstallError, ) -from ..circuit.helpers import ZonePlacement -from .settings import InitialPlacementSettings, InitialPlacementAlg - -from ..architecture import MultiZoneArchitecture -from ..depth_list.depth_list import get_initial_depth_list, DepthList -from ..graph_algs.graph import GraphData +from .settings import InitialPlacementAlg, InitialPlacementSettings logger = getLogger("initial_placement_logger") @@ -83,7 +82,7 @@ def initial_placement( f" Missing qubits: {unplaced_qubits}" ) for zone in range(arch.n_zones): - if zone not in self.placement.keys(): + if zone not in self.placement: self.placement[zone] = [] return self.placement @@ -229,7 +228,7 @@ def get_arch_graph_data(arch: MultiZoneArchitecture) -> GraphData: arch_edges = [] arch_edge_weights = [] for i, zone in enumerate(arch.zones): - for connected_zone in zone.connected_zones.keys(): + for connected_zone in zone.connected_zones: if (i, connected_zone) not in arch_edges and ( connected_zone, i, diff --git a/pytket/extensions/aqt/multi_zone_architecture/initial_placement/settings.py b/pytket/extensions/aqt/multi_zone_architecture/initial_placement/settings.py index 9129775..d4f32b7 100644 --- a/pytket/extensions/aqt/multi_zone_architecture/initial_placement/settings.py +++ b/pytket/extensions/aqt/multi_zone_architecture/initial_placement/settings.py @@ -12,11 +12,13 @@ # See the License for the specific language governing permissions and # limitations under the License. from __future__ import annotations + from dataclasses import dataclass from enum import Enum -from typing import Final +from typing import TYPE_CHECKING, Final -from ..circuit_routing.route_circuit import ZonePlacement +if TYPE_CHECKING: + from ..circuit_routing.route_circuit import ZonePlacement class InitialPlacementSettingsError(Exception): diff --git a/pytket/extensions/aqt/multi_zone_architecture/macro_architecture_graph.py b/pytket/extensions/aqt/multi_zone_architecture/macro_architecture_graph.py index ac0f1da..75935b0 100644 --- a/pytket/extensions/aqt/multi_zone_architecture/macro_architecture_graph.py +++ b/pytket/extensions/aqt/multi_zone_architecture/macro_architecture_graph.py @@ -12,12 +12,13 @@ # See the License for the specific language governing permissions and # limitations under the License. -from dataclasses import dataclass -from dataclasses import field +from dataclasses import dataclass, field from typing import NewType -from networkx import Graph # type: ignore -from networkx import shortest_path +from networkx import ( # type: ignore + Graph, + shortest_path, +) from .architecture import MultiZoneArchitecture diff --git a/pytket/extensions/aqt/multi_zone_architecture/named_architectures.py b/pytket/extensions/aqt/multi_zone_architecture/named_architectures.py index f6d4639..61e0bcd 100644 --- a/pytket/extensions/aqt/multi_zone_architecture/named_architectures.py +++ b/pytket/extensions/aqt/multi_zone_architecture/named_architectures.py @@ -13,12 +13,14 @@ # limitations under the License. """Pre-defined named multi-zone architectures for use in multi-zone circuits""" -from .architecture import ConnectionType -from .architecture import MultiZoneArchitecture -from .architecture import Operation -from .architecture import Zone -from .architecture import ZoneConnection -from .architecture import ZoneType +from .architecture import ( + ConnectionType, + MultiZoneArchitecture, + Operation, + Zone, + ZoneConnection, + ZoneType, +) standardOperations = [ Operation(operation_spec="[X, t, [self, o, p]]", fidelity="0.993"), diff --git a/ruff.toml b/ruff.toml new file mode 100644 index 0000000..f2146f6 --- /dev/null +++ b/ruff.toml @@ -0,0 +1,44 @@ +target-version = "py39" + +line-length = 88 + +extend-exclude = ["examples"] + +select = [ + "E", # pycodestyle Errors + "W", # pycodestyle Warnings + + # "A", # flake8-builtins + # "B", # flake8-Bugbear + # "C4", # flake8-comprehensions + # "COM", # flake8-commas + # "EXE", # flake8-executable + "F", # pyFlakes + # "FA", # flake8-future-annotations + # "FIX", # flake8-fixme + # "FLY", # flynt + "I", # isort + # "INP", # flake8-no-pep420 + # "ISC", # flake8-implicit-str-concat + # "N", # pep8-Naming + # "NPY", # NumPy-specific + # "PERF", # Perflint + # "PGH", # pygrep-hooks + # "PIE", # flake8-pie + # "PL", # pylint + # "PT", # flake8-pytest-style + # "RSE", # flake8-raise + # "RUF", # Ruff-specific + # "S", # flake8-bandit (Security) + "SIM", # flake8-simplify + # "SLF", # flake8-self + "T20", # flake8-print + "TCH", # flake8-type-checking + # "TRY", # tryceratops + "UP", # pyupgrade + # "YTT", # flake8-2020 +] + +[per-file-ignores] +".github/workflows/docs/conf.py" = ["E402"] +"__init__.py" = ["F401"] # module imported but unused (6) diff --git a/tests/backend_test.py b/tests/backend_test.py index 3932cdf..173c4f6 100644 --- a/tests/backend_test.py +++ b/tests/backend_test.py @@ -17,14 +17,13 @@ import numpy as np import pytest from _pytest.logging import LogCaptureFixture -from hypothesis import given -from hypothesis import strategies +from hypothesis import given, strategies from pydantic_core import ValidationError + from pytket import Qubit from pytket.backends import StatusEnum from pytket.circuit import Circuit from pytket.extensions.aqt import AQTBackend - from pytket.extensions.aqt.backends.aqt import AqtAccessError skip_remote_tests: bool = os.getenv("PYTKET_RUN_REMOTE_TESTS") is None diff --git a/tests/convert_test.py b/tests/convert_test.py index 277cd91..0cc275c 100644 --- a/tests/convert_test.py +++ b/tests/convert_test.py @@ -15,11 +15,13 @@ import numpy as np from qiskit_aqt_provider import api_models -from pytket.circuit import Circuit -from pytket.circuit import OpType -from pytket.extensions.aqt.backends.aqt import _aqt_rebase -from pytket.extensions.aqt.backends.aqt import _pytket_to_aqt_circuit -from pytket.extensions.aqt.backends.aqt import AQTBackend + +from pytket.circuit import Circuit, OpType +from pytket.extensions.aqt.backends.aqt import ( + AQTBackend, + _aqt_rebase, + _pytket_to_aqt_circuit, +) def tk_to_aqt(circ: Circuit) -> tuple[api_models.Circuit, str]: diff --git a/tests/multi_zone/compilation_settings_test.py b/tests/multi_zone/compilation_settings_test.py index 36f7892..5a79640 100644 --- a/tests/multi_zone/compilation_settings_test.py +++ b/tests/multi_zone/compilation_settings_test.py @@ -12,33 +12,28 @@ # See the License for the specific language governing permissions and # limitations under the License. import pytest -from pytket import Circuit +from pytket import Circuit from pytket.extensions.aqt.backends.aqt_multi_zone import AQTMultiZoneBackend - -from pytket.extensions.aqt.multi_zone_architecture.named_architectures import ( - four_zones_in_a_line, - grid7, -) - -from pytket.extensions.aqt.multi_zone_architecture.initial_placement.settings import ( - InitialPlacementSettings, - InitialPlacementAlg, -) - from pytket.extensions.aqt.multi_zone_architecture.circuit_routing.settings import ( - RoutingSettings, RoutingAlg, + RoutingSettings, ) - from pytket.extensions.aqt.multi_zone_architecture.compilation_settings import ( CompilationSettings, ) - from pytket.extensions.aqt.multi_zone_architecture.graph_algs.mt_kahypar_check import ( MT_KAHYPAR_INSTALLED, MissingMtKahyparInstallError, ) +from pytket.extensions.aqt.multi_zone_architecture.initial_placement.settings import ( + InitialPlacementAlg, + InitialPlacementSettings, +) +from pytket.extensions.aqt.multi_zone_architecture.named_architectures import ( + four_zones_in_a_line, + grid7, +) @pytest.fixture @@ -104,7 +99,7 @@ def test_compilation_settings_linearch( routing=routing_settings, ) compiled = backend.compile_circuit_with_routing(ghz_circuit, compilation_settings) - print("Shuttles: ", compiled.get_n_shuttles()) + print("Shuttles: ", compiled.get_n_shuttles()) # noqa: T201 mtkahypar_skipif = pytest.mark.skipif( @@ -174,4 +169,4 @@ def test_compilation_settings_gridarch( routing=routing_settings, ) compiled = backend.compile_circuit_with_routing(ghz_circuit, compilation_settings) - print("Shuttles: ", compiled.get_n_shuttles()) + print("Shuttles: ", compiled.get_n_shuttles()) # noqa: T201 diff --git a/tests/multi_zone/multi_zone_backend_test.py b/tests/multi_zone/multi_zone_backend_test.py index 2130753..8d6ddea 100644 --- a/tests/multi_zone/multi_zone_backend_test.py +++ b/tests/multi_zone/multi_zone_backend_test.py @@ -13,35 +13,32 @@ # limitations under the License. import pytest + from pytket import Circuit from pytket.backends import ResultHandle -from pytket.extensions.aqt.backends.aqt_multi_zone import AQTMultiZoneBackend from pytket.extensions.aqt.backends.aqt_multi_zone import ( + AQTMultiZoneBackend, get_aqt_json_syntax_for_compiled_circuit, ) from pytket.extensions.aqt.multi_zone_architecture.circuit.multizone_circuit import ( MultiZoneCircuit, ) -from pytket.extensions.aqt.multi_zone_architecture.named_architectures import ( - four_zones_in_a_line, +from pytket.extensions.aqt.multi_zone_architecture.circuit_routing.settings import ( + RoutingAlg, + RoutingSettings, ) - from pytket.extensions.aqt.multi_zone_architecture.compilation_settings import ( CompilationSettings, ) - -from pytket.extensions.aqt.multi_zone_architecture.initial_placement.settings import ( - InitialPlacementSettings, - InitialPlacementAlg, -) - from pytket.extensions.aqt.multi_zone_architecture.graph_algs.mt_kahypar_check import ( MT_KAHYPAR_INSTALLED, ) - -from pytket.extensions.aqt.multi_zone_architecture.circuit_routing.settings import ( - RoutingSettings, - RoutingAlg, +from pytket.extensions.aqt.multi_zone_architecture.initial_placement.settings import ( + InitialPlacementAlg, + InitialPlacementSettings, +) +from pytket.extensions.aqt.multi_zone_architecture.named_architectures import ( + four_zones_in_a_line, ) diff --git a/tests/multi_zone/multi_zone_circuit_test.py b/tests/multi_zone/multi_zone_circuit_test.py index e80f087..a3a06cd 100644 --- a/tests/multi_zone/multi_zone_circuit_test.py +++ b/tests/multi_zone/multi_zone_circuit_test.py @@ -13,17 +13,12 @@ # limitations under the License. import pytest + from pytket.circuit import Circuit, OpType from pytket.extensions.aqt.multi_zone_architecture.circuit.multizone_circuit import ( AcrossZoneOperationError, -) -from pytket.extensions.aqt.multi_zone_architecture.circuit.multizone_circuit import ( MoveError, -) -from pytket.extensions.aqt.multi_zone_architecture.circuit.multizone_circuit import ( MultiZoneCircuit, -) -from pytket.extensions.aqt.multi_zone_architecture.circuit.multizone_circuit import ( QubitPlacementError, ) from pytket.extensions.aqt.multi_zone_architecture.named_architectures import ( @@ -109,7 +104,7 @@ def test_add_barrier_throws_value_error(fix_circuit: MultiZoneCircuit) -> None: def test_validation_of_circuit_with_operation_across_zones_throws( - initial_placement: dict[int, list[int]] + initial_placement: dict[int, list[int]], ) -> None: circuit = MultiZoneCircuit(four_zones_in_a_line, initial_placement, 8) circuit.CX(0, 4)