diff --git a/qiskit/synthesis/unitary/aqc/approximate.py b/qiskit/synthesis/unitary/aqc/approximate.py index 6294196b13c..be834ba4202 100644 --- a/qiskit/synthesis/unitary/aqc/approximate.py +++ b/qiskit/synthesis/unitary/aqc/approximate.py @@ -12,7 +12,7 @@ """Base classes for an approximate circuit definition.""" from __future__ import annotations from abc import ABC, abstractmethod -from typing import Optional, SupportsFloat +from typing import SupportsFloat import numpy as np from qiskit.circuit.quantumcircuit import QuantumCircuit @@ -21,7 +21,7 @@ class ApproximateCircuit(QuantumCircuit, ABC): """A base class that represents an approximate circuit.""" - def __init__(self, num_qubits: int, name: Optional[str] = None) -> None: + def __init__(self, num_qubits: int, name: str | None = None) -> None: """ Args: num_qubits: number of qubit this circuit will span. diff --git a/qiskit/synthesis/unitary/aqc/cnot_unit_circuit.py b/qiskit/synthesis/unitary/aqc/cnot_unit_circuit.py index 6973ae55d72..add5dcd27e5 100644 --- a/qiskit/synthesis/unitary/aqc/cnot_unit_circuit.py +++ b/qiskit/synthesis/unitary/aqc/cnot_unit_circuit.py @@ -14,7 +14,6 @@ to be parametrized and used for approximate compiling optimization. """ from __future__ import annotations -from typing import Optional import numpy as np @@ -28,8 +27,8 @@ def __init__( self, num_qubits: int, cnots: np.ndarray, - tol: Optional[float] = 0.0, - name: Optional[str] = None, + tol: float | None = 0.0, + name: str | None = None, ) -> None: """ Args: diff --git a/qiskit/synthesis/unitary/aqc/fast_gradient/fast_grad_utils.py b/qiskit/synthesis/unitary/aqc/fast_gradient/fast_grad_utils.py index b13c96ea3fe..5dbb39345a5 100644 --- a/qiskit/synthesis/unitary/aqc/fast_gradient/fast_grad_utils.py +++ b/qiskit/synthesis/unitary/aqc/fast_gradient/fast_grad_utils.py @@ -14,7 +14,6 @@ Utility functions in the fast gradient implementation. """ from __future__ import annotations -from typing import Union import numpy as np @@ -36,7 +35,7 @@ def is_permutation(x: np.ndarray) -> bool: ) -def reverse_bits(x: Union[int, np.ndarray], nbits: int, enable: bool) -> Union[int, np.ndarray]: +def reverse_bits(x: int | np.ndarray, nbits: int, enable: bool) -> int | np.ndarray: """ Reverses the bit order in a number of ``nbits`` length. If ``x`` is an array, then operation is applied to every entry. diff --git a/qiskit/synthesis/unitary/aqc/fast_gradient/layer.py b/qiskit/synthesis/unitary/aqc/fast_gradient/layer.py index 6cb763afbc4..7091171f888 100644 --- a/qiskit/synthesis/unitary/aqc/fast_gradient/layer.py +++ b/qiskit/synthesis/unitary/aqc/fast_gradient/layer.py @@ -15,7 +15,6 @@ """ from __future__ import annotations from abc import abstractmethod, ABC -from typing import Optional import numpy as np from .fast_grad_utils import ( bit_permutation_1q, @@ -62,7 +61,7 @@ class Layer1Q(LayerBase): interleaves with the identity ones. """ - def __init__(self, num_qubits: int, k: int, g2x2: Optional[np.ndarray] = None): + def __init__(self, num_qubits: int, k: int, g2x2: np.ndarray | None = None): """ Args: num_qubits: number of qubits. @@ -102,7 +101,7 @@ class Layer2Q(LayerBase): interleaves with the identity ones. """ - def __init__(self, num_qubits: int, j: int, k: int, g4x4: Optional[np.ndarray] = None): + def __init__(self, num_qubits: int, j: int, k: int, g4x4: np.ndarray | None = None): """ Args: num_qubits: number of qubits. diff --git a/qiskit/transpiler/basepasses.py b/qiskit/transpiler/basepasses.py index 396f5cf4934..57f5c91c0b3 100644 --- a/qiskit/transpiler/basepasses.py +++ b/qiskit/transpiler/basepasses.py @@ -190,7 +190,7 @@ def execute( self, passmanager_ir: PassManagerIR, state: PassManagerState, - callback: Callable = None, + callback: Callable | None = None, ) -> tuple[PassManagerIR, PassManagerState]: new_dag, state = super().execute( passmanager_ir=passmanager_ir, diff --git a/qiskit/transpiler/coupling.py b/qiskit/transpiler/coupling.py index 27f98da68e7..3d73f2e42cc 100644 --- a/qiskit/transpiler/coupling.py +++ b/qiskit/transpiler/coupling.py @@ -18,10 +18,12 @@ CNOT gates. The object has a distance function that can be used to map quantum circuits onto a device with this coupling. """ +from __future__ import annotations import math -from typing import List +from collections.abc import Sequence +import numpy as np import rustworkx as rx from rustworkx.visualization import graphviz_draw @@ -46,7 +48,9 @@ class CouplingMap: "_is_symmetric", ) - def __init__(self, couplinglist=None, description=None): + def __init__( + self, couplinglist: Sequence[Sequence[int]] | None = None, description: str | None = None + ): """ Create coupling graph. By default, the generated coupling has no nodes. @@ -61,23 +65,23 @@ def __init__(self, couplinglist=None, description=None): # the coupling map graph self.graph = rx.PyDiGraph() # a dict of dicts from node pairs to distances - self._dist_matrix = None + self._dist_matrix: np.ndarray | None = None # a sorted list of physical qubits (integers) in this coupling map self._qubit_list = None # number of qubits in the graph - self._size = None + self._size: int | None = None self._is_symmetric = None if couplinglist is not None: self.graph.extend_from_edge_list([tuple(x) for x in couplinglist]) - def size(self): + def size(self) -> int: """Return the number of physical qubits in this graph.""" if self._size is None: self._size = len(self.graph) return self._size - def get_edges(self): + def get_edges(self) -> list[tuple[int, int]]: """ Gets the list of edges in the coupling graph. @@ -108,7 +112,7 @@ def add_physical_qubit(self, physical_qubit): self._qubit_list = None # invalidate self._size = None # invalidate - def add_edge(self, src, dst): + def add_edge(self, src: int, dst: int): """ Add directed edge to coupling graph. @@ -130,7 +134,7 @@ def physical_qubits(self): self._qubit_list = self.graph.node_indexes() return self._qubit_list - def is_connected(self): + def is_connected(self) -> bool: """ Test if the graph is connected. @@ -150,7 +154,7 @@ def neighbors(self, physical_qubit): return self.graph.neighbors(physical_qubit) @property - def distance_matrix(self): + def distance_matrix(self) -> np.ndarray: """Return the distance matrix for the coupling map. For any qubits where there isn't a path available between them the value @@ -174,7 +178,7 @@ def compute_distance_matrix(self): self.graph, as_undirected=True, null_value=math.inf ) - def distance(self, physical_qubit1, physical_qubit2): + def distance(self, physical_qubit1: int, physical_qubit2: int) -> int: """Returns the undirected distance between physical_qubit1 and physical_qubit2. Args: @@ -251,7 +255,7 @@ def _check_symmetry(self): """ return self.graph.is_symmetric() - def reduce(self, mapping, check_if_connected=True): + def reduce(self, mapping: list[int], check_if_connected=True): """Returns a reduced coupling map that corresponds to the subgraph of qubits selected in the mapping. @@ -269,7 +273,7 @@ def reduce(self, mapping, check_if_connected=True): CouplingError: Reduced coupling map must be connected. """ - inv_map = [None] * (max(mapping) + 1) + inv_map: list[int] = [None] * (max(mapping) + 1) for idx, val in enumerate(mapping): inv_map[val] = idx @@ -401,7 +405,7 @@ def largest_connected_component(self): """Return a set of qubits in the largest connected component.""" return max(rx.weakly_connected_components(self.graph), key=len) - def connected_components(self) -> List["CouplingMap"]: + def connected_components(self) -> list["CouplingMap"]: """Separate a :Class:`~.CouplingMap` into subgraph :class:`~.CouplingMap` for each connected component. diff --git a/qiskit/transpiler/instruction_durations.py b/qiskit/transpiler/instruction_durations.py index a34b7e787f3..f74d47007f7 100644 --- a/qiskit/transpiler/instruction_durations.py +++ b/qiskit/transpiler/instruction_durations.py @@ -12,7 +12,8 @@ """Durations of instructions, one of transpiler configurations.""" from __future__ import annotations -from typing import Optional, List, Tuple, Union, Iterable + +from typing import Iterable, Optional, Tuple, List, Union import qiskit.circuit from qiskit.circuit import Barrier, Delay @@ -36,7 +37,9 @@ class InstructionDurations: """ def __init__( - self, instruction_durations: "InstructionDurationsType" | None = None, dt: float = None + self, + instruction_durations: "InstructionDurationsType" | None = None, + dt: float | None = None, ): self.duration_by_name: dict[str, tuple[float, str]] = {} self.duration_by_name_qubits: dict[tuple[str, tuple[int, ...]], tuple[float, str]] = {} @@ -96,7 +99,7 @@ def from_backend(cls, backend: Backend): return cls(instruction_durations, dt=dt) - def update(self, inst_durations: "InstructionDurationsType" | None, dt: float = None): + def update(self, inst_durations: "InstructionDurationsType" | None, dt: float | None = None): """Update self with inst_durations (inst_durations overwrite self). Args: @@ -165,7 +168,7 @@ def update(self, inst_durations: "InstructionDurationsType" | None, dt: float = def get( self, inst: str | qiskit.circuit.Instruction, - qubits: int | list[int], + qubits: int | Iterable[int], unit: str = "dt", parameters: list[float] | None = None, ) -> float: @@ -208,7 +211,7 @@ def get( def _get( self, name: str, - qubits: list[int], + qubits: Iterable[int], to_unit: str, parameters: Iterable[float] | None = None, ) -> float: diff --git a/qiskit/transpiler/layout.py b/qiskit/transpiler/layout.py index bece1967179..057183ca831 100644 --- a/qiskit/transpiler/layout.py +++ b/qiskit/transpiler/layout.py @@ -18,7 +18,6 @@ Physical (qu)bits are integers. """ from __future__ import annotations -from typing import List from dataclasses import dataclass from qiskit import circuit @@ -36,8 +35,8 @@ def __init__(self, input_dict=None): """construct a Layout from a bijective dictionary, mapping virtual qubits to physical qubits""" self._regs = [] - self._p2v = {} - self._v2p = {} + self._p2v: dict[int, circuit.Qubit] = {} + self._v2p: dict[circuit.Qubit, int] = {} if input_dict is not None: if not isinstance(input_dict, dict): raise LayoutError("Layout constructor takes a dict") @@ -202,14 +201,14 @@ def get_registers(self): """ return set(self._regs) - def get_virtual_bits(self): + def get_virtual_bits(self) -> dict[circuit.Qubit, int]: """ Returns the dictionary where the keys are virtual (qu)bits and the values are physical (qu)bits. """ return self._v2p - def get_physical_bits(self): + def get_physical_bits(self) -> dict[int, circuit.Qubit]: """ Returns the dictionary where the keys are physical (qu)bits and the values are virtual (qu)bits. @@ -368,7 +367,7 @@ def from_qubit_list(qubit_list, *qregs): out.add_register(qreg) return out - def compose(self, other: Layout, qubits: List[Qubit]) -> Layout: + def compose(self, other: Layout, qubits: list[Qubit]) -> Layout: """Compose this layout with another layout. If this layout represents a mapping from the P-qubits to the positions of the Q-qubits, @@ -388,7 +387,7 @@ def compose(self, other: Layout, qubits: List[Qubit]) -> Layout: other_v2p = other.get_virtual_bits() return Layout({virt: other_v2p[qubits[phys]] for virt, phys in self._v2p.items()}) - def inverse(self, source_qubits: List[Qubit], target_qubits: List[Qubit]): + def inverse(self, source_qubits: list[Qubit], target_qubits: list[Qubit]): """Finds the inverse of this layout. This is possible when the layout is a bijective mapping, however the input @@ -415,7 +414,7 @@ def inverse(self, source_qubits: List[Qubit], target_qubits: List[Qubit]): } ) - def to_permutation(self, qubits: List[Qubit]): + def to_permutation(self, qubits: list[Qubit]): """Creates a permutation corresponding to this layout. This is possible when the layout is a bijective mapping with the same @@ -551,7 +550,7 @@ class TranspileLayout: input_qubit_mapping: dict[circuit.Qubit, int] final_layout: Layout | None = None _input_qubit_count: int | None = None - _output_qubit_list: List[Qubit] | None = None + _output_qubit_list: list[Qubit] | None = None def initial_virtual_layout(self, filter_ancillas: bool = False) -> Layout: """Return a :class:`.Layout` object for the initial layout. @@ -578,7 +577,7 @@ def initial_virtual_layout(self, filter_ancillas: bool = False) -> Layout: } ) - def initial_index_layout(self, filter_ancillas: bool = False) -> List[int]: + def initial_index_layout(self, filter_ancillas: bool = False) -> list[int]: """Generate an initial layout as an array of integers. Args: @@ -592,7 +591,7 @@ def initial_index_layout(self, filter_ancillas: bool = False) -> List[int]: virtual_map = self.initial_layout.get_virtual_bits() if filter_ancillas: - output = [None] * self._input_qubit_count + output: list[int | None] = [None] * self._input_qubit_count else: output = [None] * len(virtual_map) for index, (virt, phys) in enumerate(virtual_map.items()): @@ -602,7 +601,7 @@ def initial_index_layout(self, filter_ancillas: bool = False) -> List[int]: output[pos] = phys return output - def routing_permutation(self) -> List[int]: + def routing_permutation(self) -> list[int]: """Generate a final layout as an array of integers. If there is no :attr:`.final_layout` attribute present then that indicates @@ -618,7 +617,7 @@ def routing_permutation(self) -> List[int]: virtual_map = self.final_layout.get_virtual_bits() return [virtual_map[virt] for virt in self._output_qubit_list] - def final_index_layout(self, filter_ancillas: bool = True) -> List[int]: + def final_index_layout(self, filter_ancillas: bool = True) -> list[int]: """Generate the final layout as an array of integers. This method will generate an array of final positions for each qubit in the input circuit. diff --git a/qiskit/transpiler/passes/basis/basis_translator.py b/qiskit/transpiler/passes/basis/basis_translator.py index e69887a3b94..f76b22c8f58 100644 --- a/qiskit/transpiler/passes/basis/basis_translator.py +++ b/qiskit/transpiler/passes/basis/basis_translator.py @@ -12,6 +12,7 @@ """Translates gates to a target basis using a given equivalence library.""" +from __future__ import annotations import time import logging @@ -21,6 +22,7 @@ from collections import defaultdict import rustworkx +from qiskit.transpiler import Target from qiskit.circuit import ( Gate, @@ -104,7 +106,13 @@ class BasisTranslator(TransformationPass): :ref:`custom_basis_gates` for details on adding custom equivalence rules. """ - def __init__(self, equivalence_library, target_basis, target=None, min_qubits=0): + def __init__( + self, + equivalence_library, + target_basis: list[str], + target: Target | None = None, + min_qubits=0, + ): """Initialize a BasisTranslator instance. Args: @@ -122,7 +130,7 @@ def __init__(self, equivalence_library, target_basis, target=None, min_qubits=0) self._target_basis = target_basis self._target = target self._non_global_operations = None - self._qargs_with_non_global_operation = {} + self._qargs_with_non_global_operation: dict[tuple, set[str]] = {} self._min_qubits = min_qubits if target is not None: self._non_global_operations = self._target.get_non_global_operation_names() diff --git a/qiskit/transpiler/passes/basis/decompose.py b/qiskit/transpiler/passes/basis/decompose.py index 73d3cd54c6e..5b8c46b08ae 100644 --- a/qiskit/transpiler/passes/basis/decompose.py +++ b/qiskit/transpiler/passes/basis/decompose.py @@ -11,7 +11,9 @@ # that they have been altered from the originals. """Expand a gate in a circuit using its decomposition rules.""" -from typing import Type, Union, List, Optional +from __future__ import annotations + +from collections.abc import Sequence from fnmatch import fnmatch from qiskit.transpiler.basepasses import TransformationPass @@ -25,7 +27,7 @@ class Decompose(TransformationPass): def __init__( self, - gates_to_decompose: Optional[Union[Type[Gate], List[Type[Gate]], List[str], str]] = None, + gates_to_decompose: type[Gate] | Sequence[type[Gate]] | Sequence[str] | str | None = None, ) -> None: """Decompose initializer. diff --git a/qiskit/transpiler/passes/calibration/pulse_gate.py b/qiskit/transpiler/passes/calibration/pulse_gate.py index eacabbe8905..ef1ac26a038 100644 --- a/qiskit/transpiler/passes/calibration/pulse_gate.py +++ b/qiskit/transpiler/passes/calibration/pulse_gate.py @@ -11,8 +11,7 @@ # that they have been altered from the originals. """Instruction schedule map reference pass.""" - -from typing import List, Union +from __future__ import annotations from qiskit.circuit import Instruction as CircuitInst from qiskit.pulse import Schedule, ScheduleBlock @@ -49,8 +48,8 @@ class PulseGates(CalibrationBuilder): def __init__( self, - inst_map: InstructionScheduleMap = None, - target: Target = None, + inst_map: InstructionScheduleMap | None = None, + target: Target | None = None, ): """Create new pass. @@ -70,7 +69,7 @@ def __init__( target.update_from_instruction_schedule_map(inst_map) self.target = target - def supported(self, node_op: CircuitInst, qubits: List) -> bool: + def supported(self, node_op: CircuitInst, qubits: list) -> bool: """Determine if a given node supports the calibration. Args: @@ -82,7 +81,7 @@ def supported(self, node_op: CircuitInst, qubits: List) -> bool: """ return self.target.has_calibration(node_op.name, tuple(qubits)) - def get_calibration(self, node_op: CircuitInst, qubits: List) -> Union[Schedule, ScheduleBlock]: + def get_calibration(self, node_op: CircuitInst, qubits: list) -> Schedule | ScheduleBlock: """Gets the calibrated schedule for the given instruction and qubits. Args: diff --git a/qiskit/transpiler/passes/calibration/rx_builder.py b/qiskit/transpiler/passes/calibration/rx_builder.py index 7cf9c8a1b63..a8824890c7e 100644 --- a/qiskit/transpiler/passes/calibration/rx_builder.py +++ b/qiskit/transpiler/passes/calibration/rx_builder.py @@ -11,8 +11,8 @@ # that they have been altered from the originals. """Add single-pulse RX calibrations that are bootstrapped from the SX calibration.""" +from __future__ import annotations -from typing import Union from functools import lru_cache import numpy as np @@ -77,7 +77,7 @@ class RXCalibrationBuilder(CalibrationBuilder): def __init__( self, - target: Target = None, + target: Target | None = None, ): """Bootstrap single-pulse RX gate calibrations from the (hardware-calibrated) SX gate calibration. @@ -90,7 +90,6 @@ def __init__( super().__init__() self.target = target - self.already_generated = {} self.requires = [NormalizeRXAngle(self.target)] def supported(self, node_op: Instruction, qubits: list) -> bool: @@ -109,7 +108,7 @@ def supported(self, node_op: Instruction, qubits: list) -> bool: == "Drag" ) - def get_calibration(self, node_op: Instruction, qubits: list) -> Union[Schedule, ScheduleBlock]: + def get_calibration(self, node_op: Instruction, qubits: list) -> Schedule | ScheduleBlock: """ Generate RX calibration for the rotation angle specified in node_op. """ diff --git a/qiskit/transpiler/passes/calibration/rzx_builder.py b/qiskit/transpiler/passes/calibration/rzx_builder.py index c153c3eeef3..d169a474019 100644 --- a/qiskit/transpiler/passes/calibration/rzx_builder.py +++ b/qiskit/transpiler/passes/calibration/rzx_builder.py @@ -67,9 +67,9 @@ class RZXCalibrationBuilder(CalibrationBuilder): def __init__( self, - instruction_schedule_map: InstructionScheduleMap = None, + instruction_schedule_map: InstructionScheduleMap | None = None, verbose: bool = True, - target: Target = None, + target: Target | None = None, ): """ Initializes a RZXGate calibration builder. diff --git a/qiskit/transpiler/passes/calibration/rzx_templates.py b/qiskit/transpiler/passes/calibration/rzx_templates.py index 406e5e75de0..80f32ea2856 100644 --- a/qiskit/transpiler/passes/calibration/rzx_templates.py +++ b/qiskit/transpiler/passes/calibration/rzx_templates.py @@ -13,9 +13,9 @@ """ Convenience function to load RZXGate based templates. """ +from __future__ import annotations from enum import Enum -from typing import List, Dict from qiskit.circuit.library.templates import rzx @@ -31,7 +31,7 @@ class RZXTemplateMap(Enum): CY = rzx.rzx_cy() -def rzx_templates(template_list: List[str] = None) -> Dict: +def rzx_templates(template_list: list[str] | None = None) -> dict[str, list | dict[str, int]]: """Convenience function to get the cost_dict and templates for template matching. Args: diff --git a/qiskit/transpiler/passes/layout/disjoint_utils.py b/qiskit/transpiler/passes/layout/disjoint_utils.py index 42f665c473a..6ec24267544 100644 --- a/qiskit/transpiler/passes/layout/disjoint_utils.py +++ b/qiskit/transpiler/passes/layout/disjoint_utils.py @@ -13,7 +13,8 @@ """This module contains common utils for disjoint coupling maps.""" from __future__ import annotations from collections import defaultdict -from typing import List, Callable, TypeVar, Dict, Union +from collections.abc import Callable +from typing import TypeVar import uuid import rustworkx as rx @@ -32,9 +33,9 @@ def run_pass_over_connected_components( dag: DAGCircuit, - components_source: Union[Target, CouplingMap], + components_source: Target | CouplingMap, run_func: Callable[[DAGCircuit, CouplingMap], T], -) -> List[T]: +) -> list[T]: """Run a transpiler pass inner function over mapped components.""" if isinstance(components_source, Target): coupling_map = components_source.build_coupling_map(filter_idle_qubits=True) @@ -74,8 +75,8 @@ def run_pass_over_connected_components( def map_components( - dag_components: List[DAGCircuit], cmap_components: List[CouplingMap] -) -> Dict[int, List[int]]: + dag_components: list[DAGCircuit], cmap_components: list[CouplingMap] +) -> dict[int, list[int]]: """Returns a map where the key is the index of each connected component in cmap_components and the value is a list of indices from dag_components which should be placed onto it.""" free_qubits = {index: len(cmap.graph) for index, cmap in enumerate(cmap_components)} @@ -149,9 +150,7 @@ def combine_barriers(dag: DAGCircuit, retain_uuid: bool = True): node.op.label = original_label -def require_layout_isolated_to_component( - dag: DAGCircuit, components_source: Union[Target, CouplingMap] -): +def require_layout_isolated_to_component(dag: DAGCircuit, components_source: Target | CouplingMap): """ Check that the layout of the dag does not require connectivity across connected components in the CouplingMap @@ -183,7 +182,7 @@ def require_layout_isolated_to_component( ) -def separate_dag(dag: DAGCircuit) -> List[DAGCircuit]: +def separate_dag(dag: DAGCircuit) -> list[DAGCircuit]: """Separate a dag circuit into it's connected components.""" # Split barriers into single qubit barriers before splitting connected components split_barriers(dag) diff --git a/qiskit/transpiler/passes/layout/sabre_layout.py b/qiskit/transpiler/passes/layout/sabre_layout.py index 2fb9a1890bd..bf1395ac08d 100644 --- a/qiskit/transpiler/passes/layout/sabre_layout.py +++ b/qiskit/transpiler/passes/layout/sabre_layout.py @@ -12,12 +12,14 @@ """Layout selection using the SABRE bidirectional search approach from Li et al. """ +from __future__ import annotations import copy import dataclasses import logging import functools import time +from collections.abc import Sequence import numpy as np import rustworkx as rx @@ -39,6 +41,7 @@ sabre_layout_and_routing, Heuristic, NeighborTable, + SwapMap, ) from qiskit.transpiler.passes.routing.sabre_swap import _build_sabre_dag, _apply_sabre_result from qiskit.transpiler.target import Target @@ -475,6 +478,6 @@ class _DisjointComponent: dag: DAGCircuit coupling_map: CouplingMap initial_layout: NLayout - final_permutation: "list[int]" - sabre_result: "tuple[SwapMap, Sequence[int], NodeBlockResults]" - circuit_to_dag_dict: "dict[int, DAGCircuit]" + final_permutation: list[int] + sabre_result: tuple[SwapMap, Sequence[int], "NodeBlockResults"] + circuit_to_dag_dict: dict[int, DAGCircuit] diff --git a/qiskit/transpiler/passes/layout/sabre_pre_layout.py b/qiskit/transpiler/passes/layout/sabre_pre_layout.py index 9e68fd77b01..b8b945a1b72 100644 --- a/qiskit/transpiler/passes/layout/sabre_pre_layout.py +++ b/qiskit/transpiler/passes/layout/sabre_pre_layout.py @@ -11,10 +11,13 @@ # that they have been altered from the originals. """Creating Sabre starting layouts.""" +from __future__ import annotations import itertools -from qiskit.transpiler import CouplingMap, Target, AnalysisPass, TranspilerError +from qiskit.dagcircuit import DAGCircuit + +from qiskit.transpiler import CouplingMap, Target, AnalysisPass, TranspilerError, Layout from qiskit.transpiler.passes.layout.vf2_layout import VF2Layout from qiskit._accelerate.error_map import ErrorMap @@ -152,7 +155,7 @@ def _add_extra_edges(self, distance): return augmented_coupling_map, augmented_error_map - def _get_extra_edges_used(self, dag, layout): + def _get_extra_edges_used(self, dag: DAGCircuit, layout: Layout) -> set[tuple[int, int]]: """Returns the set of extra edges involved in the layout.""" extra_edges_used = set() virtual_bits = layout.get_virtual_bits() @@ -188,7 +191,7 @@ def _minimize_extra_edges(self, dag, starting_layout): # keeps the set of "necessary" extra edges: without a necessary edge # a layout no longer exists - extra_edges_necessary = [] + extra_edges_necessary: list[tuple[int, int]] = [] extra_edges_unprocessed_set = self._get_extra_edges_used(dag, starting_layout) diff --git a/qiskit/transpiler/passes/layout/set_layout.py b/qiskit/transpiler/passes/layout/set_layout.py index c4e5faa91fb..289898e0b2d 100644 --- a/qiskit/transpiler/passes/layout/set_layout.py +++ b/qiskit/transpiler/passes/layout/set_layout.py @@ -11,6 +11,8 @@ # that they have been altered from the originals. """Set the ``layout`` property to the given layout.""" +from __future__ import annotations + from qiskit.transpiler import Layout from qiskit.transpiler.exceptions import InvalidLayoutError from qiskit.transpiler.basepasses import AnalysisPass @@ -23,7 +25,7 @@ class SetLayout(AnalysisPass): of the circuit (Qubit) in increasing order. """ - def __init__(self, layout): + def __init__(self, layout: Layout | list[int]): """SetLayout initializer. Args: diff --git a/qiskit/transpiler/passes/layout/vf2_post_layout.py b/qiskit/transpiler/passes/layout/vf2_post_layout.py index 1a29b0cb450..1a76d9681ab 100644 --- a/qiskit/transpiler/passes/layout/vf2_post_layout.py +++ b/qiskit/transpiler/passes/layout/vf2_post_layout.py @@ -12,6 +12,8 @@ """VF2PostLayout pass to find a layout after transpile using subgraph isomorphism""" +from __future__ import annotations + from enum import Enum import logging import inspect @@ -185,7 +187,7 @@ def run(self, dag): # we should add these to all entries based on the number of qubits, so we # treat that as a valid operation even if there is no scoring for the # strict direction case - global_ops = None + global_ops: dict[int, list] | None = None if None in self.target.qargs: global_ops = {1: [], 2: []} for op in self.target.operation_names_for_qargs(None): diff --git a/qiskit/transpiler/passes/layout/vf2_utils.py b/qiskit/transpiler/passes/layout/vf2_utils.py index c5d420127f8..c877815e005 100644 --- a/qiskit/transpiler/passes/layout/vf2_utils.py +++ b/qiskit/transpiler/passes/layout/vf2_utils.py @@ -11,6 +11,7 @@ # that they have been altered from the originals. """This module contains common utils for vf2 layout passes.""" +from __future__ import annotations from collections import defaultdict import statistics @@ -52,7 +53,7 @@ def _visit(dag, weight, wire_map): qargs = [wire_map[q] for q in node.qargs] if len_args == 1: if qargs[0] not in im_graph_node_map: - weights = defaultdict(int) + weights: dict[str, int] = defaultdict(int) weights[node.name] += weight im_graph_node_map[qargs[0]] = im_graph.add_node(weights) reverse_im_graph_node_map[im_graph_node_map[qargs[0]]] = qargs[0] diff --git a/qiskit/transpiler/passes/optimization/collect_multiqubit_blocks.py b/qiskit/transpiler/passes/optimization/collect_multiqubit_blocks.py index e0dd61ff6cf..e8bc2bd5aba 100644 --- a/qiskit/transpiler/passes/optimization/collect_multiqubit_blocks.py +++ b/qiskit/transpiler/passes/optimization/collect_multiqubit_blocks.py @@ -11,10 +11,11 @@ # that they have been altered from the originals. """Collect sequences of uninterrupted gates acting on a number of qubits.""" +from __future__ import annotations from qiskit.transpiler.basepasses import AnalysisPass -from qiskit.circuit import Gate -from qiskit.dagcircuit import DAGOpNode, DAGInNode +from qiskit.circuit import Gate, Qubit +from qiskit.dagcircuit import DAGOpNode, DAGInNode, DAGCircuit class CollectMultiQBlocks(AnalysisPass): @@ -39,18 +40,20 @@ class CollectMultiQBlocks(AnalysisPass): and the data structure allows these changes to be done quickly. """ - def __init__(self, max_block_size=2): + def __init__(self, max_block_size: int = 2): super().__init__() - self.parent = {} # parent array for the union + self.parent: dict[Qubit, Qubit] = {} # parent array for the union - # the dicts belowed are keyed by a qubit signifying the root of a + # the dicts below are keyed by a qubit signifying the root of a # set in the DSU data structure - self.bit_groups = {} # current groups of bits stored at top of trees - self.gate_groups = {} # current gate lists for the groups + self.bit_groups: dict[Qubit, list[Qubit]] = ( + {} + ) # current groups of bits stored at top of trees + self.gate_groups: dict[Qubit, list[Qubit]] = {} # current gate lists for the groups self.max_block_size = max_block_size # maximum block size - def find_set(self, index): + def find_set(self, index: Qubit) -> Qubit: """DSU function for finding root of set of items If my parent is myself, I am the root. Otherwise we recursively find the root for my parent. After that, we assign my parent to be @@ -66,7 +69,7 @@ def find_set(self, index): self.parent[index] = self.find_set(self.parent[index]) return self.parent[index] - def union_set(self, set1, set2): + def union_set(self, set1: Qubit, set2: Qubit): """DSU function for unioning two sets together Find the roots of each set. Then assign one to have the other as its parent, thus liking the sets. @@ -85,7 +88,7 @@ def union_set(self, set1, set2): self.gate_groups[set2].clear() self.bit_groups[set2].clear() - def run(self, dag): + def run(self, dag: DAGCircuit): """Run the CollectMultiQBlocks pass on `dag`. The blocks contain "op" nodes in topological sort order @@ -105,7 +108,7 @@ def run(self, dag): block_list = [] - def collect_key(x): + def collect_key(x: DAGInNode | DAGOpNode) -> str: """special key function for topological ordering. Heuristic for this is to push all gates involving measurement or barriers, etc. as far back as possible (because they force @@ -172,7 +175,7 @@ def collect_key(x): # adding in all of the new qubits would make the group too big # we must block off sub portions of the groups until the new # group would no longer be too big - savings = {} + savings: dict[Qubit, int] = {} tot_size = 0 for bit in cur_qubits: top = self.find_set(bit) diff --git a/qiskit/transpiler/passes/optimization/commutative_inverse_cancellation.py b/qiskit/transpiler/passes/optimization/commutative_inverse_cancellation.py index 5f9744fc860..d9021964791 100644 --- a/qiskit/transpiler/passes/optimization/commutative_inverse_cancellation.py +++ b/qiskit/transpiler/passes/optimization/commutative_inverse_cancellation.py @@ -36,7 +36,7 @@ def __init__(self, matrix_based: bool = False, max_qubits: int = 4): self._max_qubits = max_qubits super().__init__() - def _skip_node(self, node): + def _skip_node(self, node) -> bool: """Returns True if we should skip this node for the analysis.""" if not isinstance(node, DAGOpNode): return True diff --git a/qiskit/transpiler/passes/optimization/echo_rzx_weyl_decomposition.py b/qiskit/transpiler/passes/optimization/echo_rzx_weyl_decomposition.py index 482891a5ca4..2d7b6b26b5b 100644 --- a/qiskit/transpiler/passes/optimization/echo_rzx_weyl_decomposition.py +++ b/qiskit/transpiler/passes/optimization/echo_rzx_weyl_decomposition.py @@ -11,8 +11,7 @@ # that they have been altered from the originals. """Weyl decomposition of two-qubit gates in terms of echoed cross-resonance gates.""" - -from typing import Tuple +from __future__ import annotations from qiskit.circuit import QuantumRegister from qiskit.circuit.library.standard_gates import RZXGate, HGate, XGate @@ -49,7 +48,7 @@ def __init__(self, instruction_schedule_map=None, target=None): if target is not None: self._inst_map = target.instruction_schedule_map() - def _is_native(self, qubit_pair: Tuple) -> bool: + def _is_native(self, qubit_pair: tuple) -> bool: """Return the direction of the qubit pair that is native.""" cal_type, _, _ = _check_calibration_type(self._inst_map, qubit_pair) return cal_type in [ diff --git a/qiskit/transpiler/passes/optimization/inverse_cancellation.py b/qiskit/transpiler/passes/optimization/inverse_cancellation.py index f5523432c26..90d533df4ab 100644 --- a/qiskit/transpiler/passes/optimization/inverse_cancellation.py +++ b/qiskit/transpiler/passes/optimization/inverse_cancellation.py @@ -13,7 +13,7 @@ """ A generic InverseCancellation pass for any set of gate-inverse pairs. """ -from typing import List, Tuple, Union +from __future__ import annotations from qiskit.circuit import Gate from qiskit.dagcircuit import DAGCircuit @@ -25,7 +25,7 @@ class InverseCancellation(TransformationPass): """Cancel specific Gates which are inverses of each other when they occur back-to- back.""" - def __init__(self, gates_to_cancel: List[Union[Gate, Tuple[Gate, Gate]]]): + def __init__(self, gates_to_cancel: list[Gate | tuple[Gate, Gate]]): """Initialize InverseCancellation pass. Args: @@ -60,7 +60,7 @@ def __init__(self, gates_to_cancel: List[Union[Gate, Tuple[Gate, Gate]]]): self.self_inverse_gates = [] self.inverse_gate_pairs = [] self.self_inverse_gate_names = set() - self.inverse_gate_pairs_names = set() + self.inverse_gate_pairs_names: set[str] = set() for gates in gates_to_cancel: if isinstance(gates, Gate): @@ -72,7 +72,7 @@ def __init__(self, gates_to_cancel: List[Union[Gate, Tuple[Gate, Gate]]]): super().__init__() - def run(self, dag: DAGCircuit): + def run(self, dag: DAGCircuit) -> DAGCircuit: """Run the InverseCancellation pass on `dag`. Args: @@ -87,7 +87,7 @@ def run(self, dag: DAGCircuit): dag = self._run_on_inverse_pairs(dag) return dag - def _run_on_self_inverse(self, dag: DAGCircuit): + def _run_on_self_inverse(self, dag: DAGCircuit) -> DAGCircuit: """ Run self-inverse gates on `dag`. @@ -131,7 +131,7 @@ def _run_on_self_inverse(self, dag: DAGCircuit): dag.remove_op_node(node) return dag - def _run_on_inverse_pairs(self, dag: DAGCircuit): + def _run_on_inverse_pairs(self, dag: DAGCircuit) -> DAGCircuit: """ Run inverse gate pairs on `dag`. diff --git a/qiskit/transpiler/passes/optimization/optimize_1q_commutation.py b/qiskit/transpiler/passes/optimization/optimize_1q_commutation.py index 450490734e4..5f839a72f51 100644 --- a/qiskit/transpiler/passes/optimization/optimize_1q_commutation.py +++ b/qiskit/transpiler/passes/optimization/optimize_1q_commutation.py @@ -11,6 +11,7 @@ # that they have been altered from the originals. """Reduce 1Q gate complexity by commuting through 2Q gates and resynthesizing.""" +from __future__ import annotations from copy import copy import logging @@ -78,7 +79,9 @@ def __init__(self, basis=None, run_to_completion=False, target=None): self._run_to_completion = run_to_completion @staticmethod - def _find_adjoining_run(dag, runs, run, front=True): + def _find_adjoining_run( + dag: DAGCircuit, runs: list[list[DAGOpNode]], run: list[DAGOpNode], front=True + ) -> tuple[DAGOpNode, list[DAGOpNode]]: """ Finds the run which abuts `run` from the front (or the rear if `front == False`), separated by a blocking node. @@ -90,7 +93,7 @@ def _find_adjoining_run(dag, runs, run, front=True): blocker = next(dag.predecessors(edge_node) if front else dag.successors(edge_node)) possibilities = dag.predecessors(blocker) if front else dag.successors(blocker) - adjoining_run = [] + adjoining_run: list[DAGOpNode] = [] for possibility in possibilities: if isinstance(possibility, DAGOpNode) and possibility.qargs == edge_node.qargs: adjoining_run = [] @@ -105,7 +108,7 @@ def _find_adjoining_run(dag, runs, run, front=True): return (blocker, adjoining_run) @staticmethod - def _commute_through(blocker, run, front=True): + def _commute_through(blocker: DAGOpNode, run: list[DAGOpNode], front: bool = True): """ Pulls `DAGOpNode`s from the front of `run` (or the back, if `front == False`) until it encounters a gate which does not commute with `blocker`. @@ -120,7 +123,7 @@ def _commute_through(blocker, run, front=True): # time run_clone = deque(run) - commuted = deque([]) + commuted: deque[DAGOpNode] = deque([]) preindex, commutation_rule = None, None if isinstance(blocker, DAGOpNode): preindex = None @@ -184,7 +187,7 @@ def _replace_subdag(dag, old_run, new_dag): spliced_run = [node_map[node._node_id] for node in new_dag.topological_op_nodes()] mov_list(old_run, spliced_run) - def _step(self, dag): + def _step(self, dag: DAGCircuit): """ Performs one full pass of optimization work. diff --git a/qiskit/transpiler/passes/optimization/optimize_1q_decomposition.py b/qiskit/transpiler/passes/optimization/optimize_1q_decomposition.py index 04d95312aa6..499b724fb4c 100644 --- a/qiskit/transpiler/passes/optimization/optimize_1q_decomposition.py +++ b/qiskit/transpiler/passes/optimization/optimize_1q_decomposition.py @@ -11,9 +11,11 @@ # that they have been altered from the originals. """Optimize chains of single-qubit gates using Euler 1q decomposer""" +from __future__ import annotations import logging import math +from collections.abc import Sequence from qiskit.transpiler.basepasses import TransformationPass from qiskit.transpiler.passes.utils import control_flow @@ -253,11 +255,13 @@ def run(self, dag): return dag - def _error(self, circuit, qubit): + def _error( + self, circuit: euler_one_qubit_decomposer.OneQubitGateSequence | Sequence[DAGOpNode], qubit + ) -> tuple[float, int]: """ Calculate a rough error for a `circuit` that runs on a specific `qubit` of `target` (`circuit` can either be an OneQubitGateSequence - from Rust or a list of DAGOPNodes). + from Rust or a list of DAGOpNode). Use basis errors from target if available, otherwise use length of circuit as a weak proxy for error. diff --git a/qiskit/transpiler/passes/optimization/optimize_1q_gates.py b/qiskit/transpiler/passes/optimization/optimize_1q_gates.py index f8302b9232c..a45762008b0 100644 --- a/qiskit/transpiler/passes/optimization/optimize_1q_gates.py +++ b/qiskit/transpiler/passes/optimization/optimize_1q_gates.py @@ -11,6 +11,7 @@ # that they have been altered from the originals. """Optimize chains of single-qubit u1, u2, u3 gates by combining them into a single gate.""" +from __future__ import annotations from itertools import groupby @@ -81,8 +82,8 @@ def run(self, dag): right_name = "p" else: right_name = "u1" - right_parameters = (0, 0, 0) # (theta, phi, lambda) - right_global_phase = 0 + right_parameters = (0.0, 0.0, 0.0) # (theta, phi, lambda) + right_global_phase = 0.0 for current_node in run: left_name = current_node.name if ( @@ -92,7 +93,7 @@ def run(self, dag): ): raise TranspilerError("internal error") if left_name in ("u1", "p"): - left_parameters = (0, 0, current_node.op.params[0]) + left_parameters = (0.0, 0.0, current_node.op.params[0]) elif left_name == "u2": left_parameters = ( np.pi / 2, diff --git a/qiskit/transpiler/passes/optimization/optimize_cliffords.py b/qiskit/transpiler/passes/optimization/optimize_cliffords.py index 88024532789..41ca3881d49 100644 --- a/qiskit/transpiler/passes/optimization/optimize_cliffords.py +++ b/qiskit/transpiler/passes/optimization/optimize_cliffords.py @@ -11,6 +11,9 @@ # that they have been altered from the originals. """Combine consecutive Cliffords over the same qubits.""" +from __future__ import annotations + +from qiskit.dagcircuit import DAGCircuit, DAGOpNode from qiskit.transpiler.basepasses import TransformationPass from qiskit.transpiler.passes.utils import control_flow @@ -24,7 +27,7 @@ class OptimizeCliffords(TransformationPass): """ @control_flow.trivial_recurse - def run(self, dag): + def run(self, dag: DAGCircuit) -> DAGCircuit: """Run the OptimizeCliffords pass on `dag`. Args: @@ -34,9 +37,9 @@ def run(self, dag): DAGCircuit: the optimized DAG. """ - blocks = [] + blocks: list[list[DAGOpNode]] = [] prev_node = None - cur_block = [] + cur_block: list[DAGOpNode] = [] # Iterate over all nodes and collect consecutive Cliffords over the # same qubits. In this very first proof-of-concept implementation diff --git a/qiskit/transpiler/passes/optimization/template_matching/backward_match.py b/qiskit/transpiler/passes/optimization/template_matching/backward_match.py index d194d1cbbdd..2909d4ed698 100644 --- a/qiskit/transpiler/passes/optimization/template_matching/backward_match.py +++ b/qiskit/transpiler/passes/optimization/template_matching/backward_match.py @@ -24,8 +24,12 @@ `arXiv:1909.05270 `_ """ +from __future__ import annotations + import heapq +from qiskit.dagcircuit import DAGDependency + from qiskit.circuit.controlledgate import ControlledGate @@ -34,7 +38,7 @@ class Match: Object to represent a match and its qubit configurations. """ - def __init__(self, match, qubit, clbit): + def __init__(self, match: list[list[int]], qubit: list[int], clbit: list[int]): """ Create a Match class with necessary arguments. Args: @@ -57,7 +61,13 @@ class MatchingScenarios: """ def __init__( - self, circuit_matched, circuit_blocked, template_matched, template_blocked, matches, counter + self, + circuit_matched: list[list[int]], + circuit_blocked: list[bool], + template_matched: list[list[int]], + template_blocked: list[bool], + matches: list[list[int]], + counter: int, ): """ Create a MatchingScenarios class with necessary arguments. @@ -87,9 +97,9 @@ def __init__(self): """ Create an empty MatchingScenariosList. """ - self.matching_scenarios_list = [] + self.matching_scenarios_list: list[MatchingScenarios] = [] - def append_scenario(self, matching): + def append_scenario(self, matching: MatchingScenarios): """ Append a scenario to the list. Args: @@ -97,7 +107,7 @@ def append_scenario(self, matching): """ self.matching_scenarios_list.append(matching) - def pop_scenario(self): + def pop_scenario(self) -> MatchingScenarios: """ Pop the first scenario of the list. Returns: @@ -117,13 +127,13 @@ class BackwardMatch: def __init__( self, - circuit_dag_dep, - template_dag_dep, - forward_matches, - node_id_c, - node_id_t, - qubits, - clbits=None, + circuit_dag_dep: DAGDependency, + template_dag_dep: DAGDependency, + forward_matches: list[list[int]], + node_id_c: int, + node_id_t: int, + qubits: list[int], + clbits: list[int] | None = None, heuristics_backward_param=None, ): """ @@ -146,7 +156,7 @@ def __init__( self.node_id_c = node_id_c self.node_id_t = node_id_t self.forward_matches = forward_matches - self.match_final = [] + self.match_final: list[Match] = [] self.heuristics_backward_param = ( heuristics_backward_param if heuristics_backward_param is not None else [] ) @@ -317,7 +327,9 @@ def _is_same_c_conf(self, node_circuit, node_template, carg_circuit): return False return True - def _init_matched_blocked_list(self): + def _init_matched_blocked_list( + self, + ) -> tuple[list[list[int]], list[bool], list[list[int]], list[bool]]: """ Initialize the list of blocked and matchedwith attributes. Returns: @@ -390,7 +402,7 @@ def run_backward_match(self): and a circuit qubits configuration. """ - match_store_list = [] + match_store_list: list[Match] = [] counter = 1 @@ -742,8 +754,8 @@ def run_backward_match(self): length = max(len(m.match) for m in match_store_list) # Store the matches with maximal length. - for scenario in match_store_list: - if (len(scenario.match) == length) and not any( - scenario.match == x.match for x in self.match_final + for match_scenario in match_store_list: + if (len(match_scenario.match) == length) and not any( + match_scenario.match == x.match for x in self.match_final ): - self.match_final.append(scenario) + self.match_final.append(match_scenario) diff --git a/qiskit/transpiler/passes/optimization/template_matching/forward_match.py b/qiskit/transpiler/passes/optimization/template_matching/forward_match.py index d8dd5bb2b9a..baad199198e 100644 --- a/qiskit/transpiler/passes/optimization/template_matching/forward_match.py +++ b/qiskit/transpiler/passes/optimization/template_matching/forward_match.py @@ -23,6 +23,9 @@ `arXiv:1909.05270 `_ """ +from __future__ import annotations + +from qiskit.dagcircuit import DAGDependency, DAGDepNode, DAGOpNode, DAGOutNode from qiskit.circuit.controlledgate import ControlledGate @@ -33,7 +36,13 @@ class ForwardMatch: """ def __init__( - self, circuit_dag_dep, template_dag_dep, node_id_c, node_id_t, qubits, clbits=None + self, + circuit_dag_dep: DAGDependency, + template_dag_dep: DAGDependency, + node_id_c: int, + node_id_t: int, + qubits: list[int], + clbits: list[int] | None = None, ): """ Create a ForwardMatch class with necessary arguments. @@ -65,19 +74,19 @@ def __init__( self.node_id_t = node_id_t # List of match - self.match = [] + self.match: list[list[int]] = [] # List of candidates for the forward match - self.candidates = [] + self.candidates: list[set[int]] = [] # List of nodes in circuit which are matched - self.matched_nodes_list = [] + self.matched_nodes_list: list[list[int | DAGDepNode]] = [] # Transformation of the qarg indices of the circuit to be adapted to the template indices - self.qarg_indices = [] + self.qarg_indices: list[int] = [] # Transformation of the carg indices of the circuit to be adapted to the template indices - self.carg_indices = [] + self.carg_indices: list[int] = [] def _init_successors_to_visit(self): """ @@ -150,7 +159,7 @@ def _find_forward_candidates(self, node_id_t): maximal_index = self.template_dag_dep.direct_successors(node_id_t)[-1] pred = [elem for elem in pred if elem <= maximal_index] - block = [] + block: list[int] = [] for node_id in pred: for dir_succ in self.template_dag_dep.direct_successors(node_id): if dir_succ not in matches: @@ -202,7 +211,7 @@ def _update_successor(self, node, successor_id): node_update.successorstovisit.pop(successor_id) return node_update - def _get_successors_to_visit(self, node, list_id): + def _get_successors_to_visit(self, node: DAGOpNode | DAGOutNode, list_id: int) -> int: """ Return the successor for a given node and id. Args: diff --git a/qiskit/transpiler/passes/optimization/template_matching/maximal_matches.py b/qiskit/transpiler/passes/optimization/template_matching/maximal_matches.py index 24268784e24..6a3f58ba216 100644 --- a/qiskit/transpiler/passes/optimization/template_matching/maximal_matches.py +++ b/qiskit/transpiler/passes/optimization/template_matching/maximal_matches.py @@ -14,6 +14,7 @@ It stores all maximal matches from the given matches obtained by the template matching algorithm. """ +from __future__ import annotations class Match: @@ -42,7 +43,7 @@ class MaximalMatches: of matches obtained with the template matching algorithm. """ - def __init__(self, template_matches): + def __init__(self, template_matches: list[Match]): """ Initialize MaximalMatches with the necessary arguments. Args: @@ -50,7 +51,7 @@ def __init__(self, template_matches): """ self.template_matches = template_matches - self.max_match_list = [] + self.max_match_list: list[Match] = [] def run_maximal_matches(self): """ diff --git a/qiskit/transpiler/passes/optimization/template_matching/template_matching.py b/qiskit/transpiler/passes/optimization/template_matching/template_matching.py index 29b65f8e738..0e5539f61d1 100644 --- a/qiskit/transpiler/passes/optimization/template_matching/template_matching.py +++ b/qiskit/transpiler/passes/optimization/template_matching/template_matching.py @@ -22,12 +22,18 @@ `arXiv:1909.05270 `_ """ +from __future__ import annotations import itertools +from qiskit.dagcircuit import DAGDependency + from qiskit.circuit.controlledgate import ControlledGate from qiskit.transpiler.passes.optimization.template_matching.forward_match import ForwardMatch -from qiskit.transpiler.passes.optimization.template_matching.backward_match import BackwardMatch +from qiskit.transpiler.passes.optimization.template_matching.backward_match import ( + BackwardMatch, + Match, +) class TemplateMatching: @@ -37,22 +43,22 @@ class TemplateMatching: def __init__( self, - circuit_dag_dep, - template_dag_dep, - heuristics_qubits_param=None, - heuristics_backward_param=None, + circuit_dag_dep: DAGDependency, + template_dag_dep: DAGDependency, + heuristics_qubits_param: list[int] | None = None, + heuristics_backward_param: list[int] | None = None, ): """ Create a TemplateMatching object with necessary arguments. Args: - circuit_dag_dep (QuantumCircuit): circuit. - template_dag_dep (QuantumCircuit): template. + circuit_dag_dep (DAGDependency): circuit. + template_dag_dep (DAGDependency): template. heuristics_backward_param (list[int]): [length, survivor] heuristics_qubits_param (list[int]): [length] """ self.circuit_dag_dep = circuit_dag_dep self.template_dag_dep = template_dag_dep - self.match_list = [] + self.match_list: list[Match] = [] self.heuristics_qubits_param = ( heuristics_qubits_param if heuristics_qubits_param is not None else [] ) @@ -60,7 +66,9 @@ def __init__( heuristics_backward_param if heuristics_backward_param is not None else [] ) - def _list_first_match_new(self, node_circuit, node_template, n_qubits_t, n_clbits_t): + def _list_first_match_new( + self, node_circuit, node_template, n_qubits_t: int, n_clbits_t: int + ) -> tuple[list[list[int]], list[int]]: """ Returns the list of qubit for circuit given the first match, the unknown qubit are replaced by -1. @@ -141,7 +149,7 @@ def _sublist(self, lst, exclude, length): for sublist in itertools.combinations([e for e in lst if e not in exclude], length): yield list(sublist) - def _list_qubit_clbit_circuit(self, list_first_match, permutation): + def _list_qubit_clbit_circuit(self, list_first_match: list[int], permutation) -> list[int]: """ Function that returns the list of the circuit qubits and clbits give a permutation and an initial match. @@ -164,7 +172,7 @@ def _list_qubit_clbit_circuit(self, list_first_match, permutation): return list_circuit - def _add_match(self, backward_match_list): + def _add_match(self, backward_match_list: list[Match]): """ Method to add a match in list only if it is not already in it. If the match is already in the list, the qubit configuration @@ -186,7 +194,7 @@ def _add_match(self, backward_match_list): if not already_in: self.match_list.append(b_match) - def _explore_circuit(self, node_id_c, node_id_t, n_qubits_t, length): + def _explore_circuit(self, node_id_c: int, node_id_t: int, n_qubits_t: int, length: int): """ Explore the successors of the node_id_c (up to the given length). Args: diff --git a/qiskit/transpiler/passes/optimization/template_matching/template_substitution.py b/qiskit/transpiler/passes/optimization/template_matching/template_substitution.py index 44689894176..c89ed91eb10 100644 --- a/qiskit/transpiler/passes/optimization/template_matching/template_substitution.py +++ b/qiskit/transpiler/passes/optimization/template_matching/template_substitution.py @@ -14,9 +14,15 @@ Template matching substitution, given a list of maximal matches it substitutes them in circuit and creates a new optimized dag version of the circuit. """ +from __future__ import annotations + import collections import copy import itertools +from collections.abc import Sequence + +from qiskit.transpiler.passes.optimization.template_matching import maximal_matches + from qiskit.circuit import Parameter, ParameterExpression from qiskit.dagcircuit.dagcircuit import DAGCircuit @@ -34,9 +40,9 @@ class SubstitutionConfig: def __init__( self, - circuit_config, - template_config, - pred_block, + circuit_config: list[int], + template_config: list[int], + pred_block: list[int], qubit_config, template_dag_dep, clbit_config=None, @@ -63,7 +69,13 @@ class TemplateSubstitution: Class to run the substitution algorithm from the list of maximal matches. """ - def __init__(self, max_matches, circuit_dag_dep, template_dag_dep, user_cost_dict=None): + def __init__( + self, + max_matches: list[maximal_matches.Match], + circuit_dag_dep: DAGDependency, + template_dag_dep: DAGDependency, + user_cost_dict: dict | None = None, + ): """ Initialize TemplateSubstitution with necessary arguments. Args: @@ -79,8 +91,8 @@ def __init__(self, max_matches, circuit_dag_dep, template_dag_dep, user_cost_dic self.circuit_dag_dep = circuit_dag_dep self.template_dag_dep = template_dag_dep - self.substitution_list = [] - self.unmatched_list = [] + self.substitution_list: list[SubstitutionConfig] = [] + self.unmatched_list: list[int] = [] self.dag_dep_optimized = DAGDependency() self.dag_optimized = DAGCircuit() @@ -127,7 +139,7 @@ def __init__(self, max_matches, circuit_dag_dep, template_dag_dep, user_cost_dic "p": 1, } - def _pred_block(self, circuit_sublist, index): + def _pred_block(self, circuit_sublist: list, index: int) -> list[int]: """ It returns the predecessors of a given part of the circuit. Args: @@ -136,11 +148,11 @@ def _pred_block(self, circuit_sublist, index): Returns: list: List of predecessors of the current match circuit configuration. """ - predecessors = set() + predecessors: set[int] = set() for node_id in circuit_sublist: predecessors = predecessors | set(self.circuit_dag_dep.get_node(node_id).predecessors) - exclude = set() + exclude: set[int] = set() for elem in self.substitution_list[:index]: exclude = exclude | set(elem.circuit_config) | set(elem.pred_block) @@ -187,7 +199,9 @@ def _rules(self, circuit_sublist, template_sublist, template_complement): else: return False - def _template_inverse(self, template_list, template_sublist, template_complement): + def _template_inverse( + self, template_list: Sequence, template_sublist, template_complement: list[int] + ) -> list[int]: """ The template circuit realizes the identity operator, then given the list of matches in the template, it returns the inverse part of the template that @@ -203,12 +217,12 @@ def _template_inverse(self, template_list, template_sublist, template_complement left = [] right = [] - pred = set() + pred: set[int] = set() for index in template_sublist: pred = pred | set(self.template_dag_dep.get_node(index).predecessors) pred = list(pred - set(template_sublist)) - succ = set() + succ: set[int] = set() for index in template_sublist: succ = succ | set(self.template_dag_dep.get_node(index).successors) succ = list(succ - set(template_sublist)) @@ -247,7 +261,7 @@ def _permutation(self): bool: True if the matches groups are in the right order, False otherwise. """ for scenario in self.substitution_list: - predecessors = set() + predecessors: set[int] = set() for match in scenario.circuit_config: predecessors = predecessors | set(self.circuit_dag_dep.get_node(match).predecessors) predecessors = predecessors - set(scenario.circuit_config) @@ -273,7 +287,7 @@ def _remove_impossible(self): # Initialize predecessors for each group of matches. for scenario in self.substitution_list: - predecessors = set() + predecessors: set[int] = set() for index in scenario.circuit_config: predecessors = predecessors | set(self.circuit_dag_dep.get_node(index).predecessors) list_predecessors.append(predecessors) @@ -356,7 +370,7 @@ def _substitution(self): index = self.substitution_list.index(scenario) scenario.pred_block = self._pred_block(scenario.circuit_config, index) - circuit_list = [] + circuit_list: list[int] = [] for elem in self.substitution_list: circuit_list = circuit_list + elem.circuit_config + elem.pred_block @@ -508,7 +522,7 @@ def _attempt_bind(self, template_sublist, circuit_sublist): circuit_params, template_params = [], [] # Set of all parameter names that are present in the circuits to be optimized. - circuit_params_set = set() + circuit_params_set: set[str] = set() template_dag_dep = copy.deepcopy(self.template_dag_dep) @@ -530,7 +544,9 @@ def dummy_parameter(): # Substitutions for parameters that have clashing names between the input circuits and the # defined templates. - template_clash_substitutions = collections.defaultdict(dummy_parameter) + template_clash_substitutions: dict[str, Parameter] = collections.defaultdict( + dummy_parameter + ) # add parameters from template to template_params, replacing parameters with names that # clash with those in the circuit. diff --git a/qiskit/transpiler/passes/optimization/template_optimization.py b/qiskit/transpiler/passes/optimization/template_optimization.py index f4274d2331e..7584e1248cb 100644 --- a/qiskit/transpiler/passes/optimization/template_optimization.py +++ b/qiskit/transpiler/passes/optimization/template_optimization.py @@ -20,10 +20,12 @@ Exact and practical pattern matching for quantum circuit optimization. `arXiv:1909.05270 `_ """ +from __future__ import annotations + import numpy as np from qiskit.circuit.quantumcircuit import QuantumCircuit -from qiskit.dagcircuit import DAGDependency +from qiskit.dagcircuit import DAGDependency, DAGCircuit from qiskit.converters.circuit_to_dagdependency import circuit_to_dagdependency from qiskit.converters.dagdependency_to_circuit import dagdependency_to_circuit from qiskit.converters.dag_to_dagdependency import dag_to_dagdependency @@ -86,7 +88,7 @@ def __init__( self.user_cost_dict = user_cost_dict - def run(self, dag): + def run(self, dag: DAGCircuit) -> DAGCircuit: """ Args: dag(DAGCircuit): DAG circuit. diff --git a/qiskit/transpiler/passes/routing/algorithms/util.py b/qiskit/transpiler/passes/routing/algorithms/util.py index d18d22a0db9..9a59a6bf7b7 100644 --- a/qiskit/transpiler/passes/routing/algorithms/util.py +++ b/qiskit/transpiler/passes/routing/algorithms/util.py @@ -31,7 +31,7 @@ from collections.abc import Iterable from typing import TypeVar, MutableMapping -from qiskit.circuit import QuantumRegister +from qiskit.circuit import QuantumRegister, Qubit from qiskit.dagcircuit import DAGCircuit from qiskit.circuit.library.standard_gates import SwapGate @@ -85,7 +85,7 @@ def permutation_circuit(swaps: Iterable[list[Swap[_V]]]) -> PermutationCircuit: swap_list = list(swaps) # Set of unique nodes used in the swaps. - nodes = { + nodes: set[_V] = { swap_node for swap_step in swap_list for swap_nodes in swap_step for swap_node in swap_nodes } @@ -93,7 +93,7 @@ def permutation_circuit(swaps: Iterable[list[Swap[_V]]]) -> PermutationCircuit: for qubit in node_qargs.values(): dag.add_qreg(qubit) - inputmap = {node: q[0] for node, q in node_qargs.items()} + inputmap: dict[_V, Qubit] = {node: q[0] for node, q in node_qargs.items()} # Apply swaps to the circuit. for swap_step in swap_list: diff --git a/qiskit/transpiler/passes/routing/commuting_2q_gate_routing/pauli_2q_evolution_commutation.py b/qiskit/transpiler/passes/routing/commuting_2q_gate_routing/pauli_2q_evolution_commutation.py index beadc884465..eda95e0c674 100644 --- a/qiskit/transpiler/passes/routing/commuting_2q_gate_routing/pauli_2q_evolution_commutation.py +++ b/qiskit/transpiler/passes/routing/commuting_2q_gate_routing/pauli_2q_evolution_commutation.py @@ -11,8 +11,7 @@ # that they have been altered from the originals. """An analysis pass to find evolution gates in which the Paulis commute.""" - -from typing import Tuple +from __future__ import annotations import numpy as np @@ -95,7 +94,7 @@ def summands_commute(operator: SparsePauliOp) -> bool: return len(commuting_subparts) == 1 @staticmethod - def _pauli_to_edge(pauli: Pauli) -> Tuple[int, ...]: + def _pauli_to_edge(pauli: Pauli) -> tuple[int, ...]: """Convert a pauli to an edge. Args: diff --git a/qiskit/transpiler/passes/routing/lookahead_swap.py b/qiskit/transpiler/passes/routing/lookahead_swap.py index 4c6462c04a8..6c1dabc9977 100644 --- a/qiskit/transpiler/passes/routing/lookahead_swap.py +++ b/qiskit/transpiler/passes/routing/lookahead_swap.py @@ -11,12 +11,15 @@ # that they have been altered from the originals. """Map input circuit onto a backend topology via insertion of SWAPs.""" +from __future__ import annotations import collections import copy import logging import math +from qiskit.circuit import Qubit + from qiskit.circuit.library.standard_gates import SwapGate from qiskit.transpiler.basepasses import TransformationPass from qiskit.transpiler.exceptions import TranspilerError @@ -284,7 +287,7 @@ def _map_free_gates(state, gates): mapped_gates (list): ops for gates that can be executed, mapped onto layout. remaining_gates (list): gates that cannot be executed on the layout. """ - blocked_qubits = set() + blocked_qubits: set[Qubit] = set() mapped_gates = [] remaining_gates = [] diff --git a/qiskit/transpiler/passes/routing/sabre_swap.py b/qiskit/transpiler/passes/routing/sabre_swap.py index acb23f39ab0..b046a6a94fa 100644 --- a/qiskit/transpiler/passes/routing/sabre_swap.py +++ b/qiskit/transpiler/passes/routing/sabre_swap.py @@ -11,6 +11,7 @@ # that they have been altered from the originals. """Routing via SWAP insertion using the SABRE method from Li et al.""" +from __future__ import annotations import logging from copy import deepcopy @@ -273,7 +274,7 @@ def _build_sabre_dag(dag, num_physical_qubits, qubit_indices): from qiskit.converters import circuit_to_dag # Maps id(block): circuit_to_dag(block) for all descendant blocks - circuit_to_dag_dict = {} + circuit_to_dag_dict: dict[int, DAGCircuit] = {} def recurse(block, block_qubit_indices): block_id = id(block) diff --git a/qiskit/transpiler/passes/scheduling/base_scheduler.py b/qiskit/transpiler/passes/scheduling/base_scheduler.py index e9076c5c637..0a9e3b4b504 100644 --- a/qiskit/transpiler/passes/scheduling/base_scheduler.py +++ b/qiskit/transpiler/passes/scheduling/base_scheduler.py @@ -11,6 +11,7 @@ # that they have been altered from the originals. """Base circuit scheduling pass.""" +from __future__ import annotations import warnings from qiskit.transpiler import InstructionDurations @@ -218,10 +219,10 @@ class BaseSchedulerTransform(TransformationPass): def __init__( self, - durations: InstructionDurations = None, + durations: InstructionDurations | None = None, clbit_write_latency: int = 0, conditional_latency: int = 0, - target: Target = None, + target: Target | None = None, ): """Scheduler initializer. diff --git a/qiskit/transpiler/passes/scheduling/padding/base_padding.py b/qiskit/transpiler/passes/scheduling/padding/base_padding.py index 4ce17e7bc26..91859ba34b2 100644 --- a/qiskit/transpiler/passes/scheduling/padding/base_padding.py +++ b/qiskit/transpiler/passes/scheduling/padding/base_padding.py @@ -56,7 +56,7 @@ class BasePadding(TransformationPass): def __init__( self, - target: Target = None, + target: Target | None = None, ): """BasePadding initializer. diff --git a/qiskit/transpiler/passes/scheduling/padding/dynamical_decoupling.py b/qiskit/transpiler/passes/scheduling/padding/dynamical_decoupling.py index 45333de009b..6e9be08b0b8 100644 --- a/qiskit/transpiler/passes/scheduling/padding/dynamical_decoupling.py +++ b/qiskit/transpiler/passes/scheduling/padding/dynamical_decoupling.py @@ -105,14 +105,14 @@ def uhrig_pulse_location(k): def __init__( self, - durations: InstructionDurations = None, - dd_sequence: list[Gate] = None, + durations: InstructionDurations | None = None, + dd_sequence: list[Gate] | None = None, qubits: list[int] | None = None, spacing: list[float] | None = None, skip_reset_qubits: bool = True, pulse_alignment: int = 1, extra_slack_distribution: str = "middle", - target: Target = None, + target: Target | None = None, ): """Dynamical decoupling initializer. diff --git a/qiskit/transpiler/passes/scheduling/padding/pad_delay.py b/qiskit/transpiler/passes/scheduling/padding/pad_delay.py index 886bb6a3797..c475a295423 100644 --- a/qiskit/transpiler/passes/scheduling/padding/pad_delay.py +++ b/qiskit/transpiler/passes/scheduling/padding/pad_delay.py @@ -11,6 +11,7 @@ # that they have been altered from the originals. """Padding pass to insert Delay to the empty slots.""" +from __future__ import annotations from qiskit.circuit import Qubit from qiskit.circuit.delay import Delay @@ -51,7 +52,7 @@ class PadDelay(BasePadding): See :class:`BasePadding` pass for details. """ - def __init__(self, fill_very_end: bool = True, target: Target = None): + def __init__(self, fill_very_end: bool = True, target: Target | None = None): """Create new padding delay pass. Args: diff --git a/qiskit/transpiler/passes/scheduling/scheduling/base_scheduler.py b/qiskit/transpiler/passes/scheduling/scheduling/base_scheduler.py index 69bea32acca..82c91b93cc9 100644 --- a/qiskit/transpiler/passes/scheduling/scheduling/base_scheduler.py +++ b/qiskit/transpiler/passes/scheduling/scheduling/base_scheduler.py @@ -11,6 +11,7 @@ # that they have been altered from the originals. """Base circuit scheduling pass.""" +from __future__ import annotations import warnings @@ -29,7 +30,7 @@ class BaseScheduler(AnalysisPass): CONDITIONAL_SUPPORTED = (Gate, Delay) - def __init__(self, durations: InstructionDurations = None, target: Target = None): + def __init__(self, durations: InstructionDurations | None = None, target: Target | None = None): """Scheduler initializer. Args: diff --git a/qiskit/transpiler/passes/scheduling/time_unit_conversion.py b/qiskit/transpiler/passes/scheduling/time_unit_conversion.py index 08ac932d8ae..103881a1653 100644 --- a/qiskit/transpiler/passes/scheduling/time_unit_conversion.py +++ b/qiskit/transpiler/passes/scheduling/time_unit_conversion.py @@ -11,7 +11,7 @@ # that they have been altered from the originals. """Unify time unit in circuit for scheduling and following passes.""" -from typing import Set +from __future__ import annotations from qiskit.circuit import Delay from qiskit.dagcircuit import DAGCircuit @@ -36,7 +36,9 @@ class TimeUnitConversion(TransformationPass): * raise error: if they are a mix of SI units and ``'dt'``. """ - def __init__(self, inst_durations: InstructionDurations = None, target: Target = None): + def __init__( + self, inst_durations: InstructionDurations | None = None, target: Target | None = None + ): """TimeUnitAnalysis initializer. Args: @@ -134,14 +136,14 @@ def _update_inst_durations(self, dag): return circ_durations @staticmethod - def _units_used_in_delays(dag: DAGCircuit) -> Set[str]: + def _units_used_in_delays(dag: DAGCircuit) -> set[str]: units_used = set() for node in dag.op_nodes(op=Delay): units_used.add(node.op.unit) return units_used @staticmethod - def _unified(unit_set: Set[str]) -> str: + def _unified(unit_set: set[str]) -> str: if not unit_set: return "dt" diff --git a/qiskit/transpiler/passes/synthesis/aqc_plugin.py b/qiskit/transpiler/passes/synthesis/aqc_plugin.py index 35987671f9c..b12014b41da 100644 --- a/qiskit/transpiler/passes/synthesis/aqc_plugin.py +++ b/qiskit/transpiler/passes/synthesis/aqc_plugin.py @@ -62,17 +62,17 @@ class AQCSynthesisPlugin(UnitarySynthesisPlugin): """ @property - def max_qubits(self): + def max_qubits(self) -> int: """Maximum number of supported qubits is ``14``.""" return 14 @property - def min_qubits(self): + def min_qubits(self) -> int: """Minimum number of supported qubits is ``3``.""" return 3 @property - def supports_natural_direction(self): + def supports_natural_direction(self) -> bool: """The plugin does not support natural direction, it assumes bidirectional two qubit gates.""" return False @@ -98,13 +98,13 @@ def supported_bases(self): return None @property - def supports_basis_gates(self): + def supports_basis_gates(self) -> bool: """The plugin does not support basis gates and by default it synthesizes a circuit using ``["rx", "ry", "rz", "cx"]`` gate basis.""" return False @property - def supports_coupling_map(self): + def supports_coupling_map(self) -> bool: """The plugin does not support coupling maps.""" return False diff --git a/qiskit/transpiler/passes/synthesis/high_level_synthesis.py b/qiskit/transpiler/passes/synthesis/high_level_synthesis.py index f1de2b8f213..3a58124802c 100644 --- a/qiskit/transpiler/passes/synthesis/high_level_synthesis.py +++ b/qiskit/transpiler/passes/synthesis/high_level_synthesis.py @@ -158,9 +158,8 @@ QFTSynthesisFull QFTSynthesisLine """ - -from typing import Optional, Union, List, Tuple, Callable - +from __future__ import annotations +from typing import Optional, Callable import numpy as np import rustworkx as rx @@ -343,12 +342,12 @@ class HighLevelSynthesis(TransformationPass): def __init__( self, - hls_config: Optional[HLSConfig] = None, - coupling_map: Optional[CouplingMap] = None, - target: Optional[Target] = None, + hls_config: HLSConfig | None = None, + coupling_map: CouplingMap | None = None, + target: Target | None = None, use_qubit_indices: bool = False, - equivalence_library: Optional[EquivalenceLibrary] = None, - basis_gates: Optional[List[str]] = None, + equivalence_library: EquivalenceLibrary | None = None, + basis_gates: list[str] | None = None, min_qubits: int = 0, ): """ @@ -446,8 +445,8 @@ def run(self, dag: DAGCircuit) -> DAGCircuit: return dag def _recursively_handle_op( - self, op: Operation, qubits: Optional[List] = None - ) -> Tuple[Union[QuantumCircuit, DAGCircuit, Operation], bool]: + self, op: Operation, qubits: list | None = None + ) -> tuple[QuantumCircuit | DAGCircuit | Operation, bool]: """Recursively synthesizes a single operation. Note: the reason that this function accepts an operation and not a dag node @@ -521,9 +520,7 @@ def _recursively_handle_op( dag = self.run(dag) return dag, True - def _synthesize_op_using_plugins( - self, op: Operation, qubits: List - ) -> Union[QuantumCircuit, None]: + def _synthesize_op_using_plugins(self, op: Operation, qubits: list) -> QuantumCircuit | None: """ Attempts to synthesize op using plugin mechanism. Returns either the synthesized circuit or None (which occurs when no @@ -604,7 +601,7 @@ def _synthesize_op_using_plugins( return best_decomposition - def _synthesize_annotated_op(self, op: Operation) -> Union[Operation, None]: + def _synthesize_annotated_op(self, op: Operation) -> Operation | None: """ Recursively synthesizes annotated operations. Returns either the synthesized operation or None (which occurs when the operation diff --git a/qiskit/transpiler/passes/synthesis/plugin.py b/qiskit/transpiler/passes/synthesis/plugin.py index c57c6d76f9f..a187d00c723 100644 --- a/qiskit/transpiler/passes/synthesis/plugin.py +++ b/qiskit/transpiler/passes/synthesis/plugin.py @@ -383,9 +383,9 @@ def run(self, high_level_object, coupling_map=None, target=None, qubits=None, ** :no-inherited-members: :no-special-members: """ +from __future__ import annotations import abc -from typing import List import stevedore @@ -695,27 +695,27 @@ def __init__(self): # The registered plugin names should be of the form . # Create a dict, mapping to the list of its s. - self.plugins_by_op = {} + self.plugins_by_op: dict[str, list[str]] = {} for plugin_name in self.plugins.names(): op_name, method_name = plugin_name.split(".") if op_name not in self.plugins_by_op: self.plugins_by_op[op_name] = [] self.plugins_by_op[op_name].append(method_name) - def method_names(self, op_name): + def method_names(self, op_name: str) -> list[str]: """Returns plugin methods for op_name.""" if op_name in self.plugins_by_op: return self.plugins_by_op[op_name] else: return [] - def method(self, op_name, method_name): + def method(self, op_name: str, method_name: str): """Returns the plugin for ``op_name`` and ``method_name``.""" plugin_name = op_name + "." + method_name return self.plugins[plugin_name].obj -def high_level_synthesis_plugin_names(op_name: str) -> List[str]: +def high_level_synthesis_plugin_names(op_name: str) -> list[str]: """Return a list of plugin names installed for a given high level object name Args: diff --git a/qiskit/transpiler/passes/synthesis/solovay_kitaev_synthesis.py b/qiskit/transpiler/passes/synthesis/solovay_kitaev_synthesis.py index c3c51353d03..bf9423bb998 100644 --- a/qiskit/transpiler/passes/synthesis/solovay_kitaev_synthesis.py +++ b/qiskit/transpiler/passes/synthesis/solovay_kitaev_synthesis.py @@ -221,7 +221,7 @@ class SolovayKitaevSynthesis(UnitarySynthesisPlugin): # we cache an instance of the Solovay-Kitaev class to generate the # computationally expensive basis approximation of single qubit gates only once - _sk = None + _sk: SolovayKitaevDecomposition | None = None @property def max_qubits(self): diff --git a/qiskit/transpiler/passes/synthesis/unitary_synthesis.py b/qiskit/transpiler/passes/synthesis/unitary_synthesis.py index ab7c5e04649..0591a8013af 100644 --- a/qiskit/transpiler/passes/synthesis/unitary_synthesis.py +++ b/qiskit/transpiler/passes/synthesis/unitary_synthesis.py @@ -313,17 +313,17 @@ class UnitarySynthesis(TransformationPass): def __init__( self, - basis_gates: list[str] = None, + basis_gates: list[str] | None = None, approximation_degree: float | None = 1.0, - coupling_map: CouplingMap = None, - backend_props: BackendProperties = None, + coupling_map: CouplingMap | None = None, + backend_props: BackendProperties | None = None, pulse_optimize: bool | None = None, natural_direction: bool | None = None, synth_gates: list[str] | None = None, method: str = "default", min_qubits: int = 0, - plugin_config: dict = None, - target: Target = None, + plugin_config: dict | None = None, + target: Target | None = None, ): """Synthesize unitaries over some basis gates. @@ -586,14 +586,14 @@ def _run_main_loop( return out_dag -def _build_gate_lengths(props=None, target=None): +def _build_gate_lengths(props: BackendProperties | None = None, target: Target | None = None): """Builds a ``gate_lengths`` dictionary from either ``props`` (BackendV1) or ``target`` (BackendV2). The dictionary has the form: {gate_name: {(qubits,): duration}} """ - gate_lengths = {} + gate_lengths: dict[str, dict[tuple, float]] = {} if target is not None: for gate, prop_dict in target.items(): gate_lengths[gate] = {} @@ -612,14 +612,16 @@ def _build_gate_lengths(props=None, target=None): return gate_lengths -def _build_gate_errors(props=None, target=None): +def _build_gate_errors( + props: BackendProperties | None = None, target: Target | None = None +) -> dict[str, dict[tuple, float]]: """Builds a ``gate_error`` dictionary from either ``props`` (BackendV1) or ``target`` (BackendV2). The dictionary has the form: {gate_name: {(qubits,): error_rate}} """ - gate_errors = {} + gate_errors: dict[str, dict[tuple, float]] = {} if target is not None: for gate, prop_dict in target.items(): gate_errors[gate] = {} @@ -638,7 +640,9 @@ def _build_gate_errors(props=None, target=None): return gate_errors -def _build_gate_lengths_by_qubit(props=None, target=None): +def _build_gate_lengths_by_qubit( + props: BackendProperties | None = None, target: Target | None = None +): """ Builds a `gate_lengths` dictionary from either `props` (BackendV1) or `target (BackendV2)`. @@ -671,7 +675,9 @@ def _build_gate_lengths_by_qubit(props=None, target=None): return gate_lengths -def _build_gate_errors_by_qubit(props=None, target=None): +def _build_gate_errors_by_qubit( + props: BackendProperties | None = None, target: Target | None = None +): """ Builds a `gate_error` dictionary from either `props` (BackendV1) or `target (BackendV2)`. diff --git a/qiskit/transpiler/passes/utils/control_flow.py b/qiskit/transpiler/passes/utils/control_flow.py index 3739852b4c7..ee3c0f9d634 100644 --- a/qiskit/transpiler/passes/utils/control_flow.py +++ b/qiskit/transpiler/passes/utils/control_flow.py @@ -11,9 +11,10 @@ # that they have been altered from the originals. """Internal utilities for working with control-flow operations.""" +from __future__ import annotations import functools -from typing import Callable +from collections.abc import Callable from qiskit.circuit import ControlFlowOp from qiskit.converters import circuit_to_dag, dag_to_circuit diff --git a/qiskit/transpiler/passes/utils/filter_op_nodes.py b/qiskit/transpiler/passes/utils/filter_op_nodes.py index 344d2280e3f..7fd07f051e2 100644 --- a/qiskit/transpiler/passes/utils/filter_op_nodes.py +++ b/qiskit/transpiler/passes/utils/filter_op_nodes.py @@ -11,8 +11,9 @@ # that they have been altered from the originals. """Filter ops from a circuit""" +from __future__ import annotations -from typing import Callable +from collections.abc import Callable from qiskit.dagcircuit import DAGCircuit, DAGOpNode from qiskit.transpiler.basepasses import TransformationPass diff --git a/qiskit/transpiler/passes/utils/minimum_point.py b/qiskit/transpiler/passes/utils/minimum_point.py index 1dcef0db218..1eed5c26b79 100644 --- a/qiskit/transpiler/passes/utils/minimum_point.py +++ b/qiskit/transpiler/passes/utils/minimum_point.py @@ -11,11 +11,11 @@ # that they have been altered from the originals. """Check if the DAG has reached a relative semi-stable point over previous runs.""" +from __future__ import annotations from copy import deepcopy from dataclasses import dataclass import math -from typing import Tuple from qiskit.dagcircuit.dagcircuit import DAGCircuit from qiskit.transpiler.basepasses import TransformationPass @@ -50,7 +50,7 @@ class MinimumPoint(TransformationPass): and an earlier minimum is restored. """ - def __init__(self, property_set_list, prefix, backtrack_depth=5): + def __init__(self, property_set_list: list, prefix: str, backtrack_depth: int = 5): """Initialize an instance of this pass Args: @@ -72,7 +72,7 @@ def __init__(self, property_set_list, prefix, backtrack_depth=5): self.minimum_reached = f"{prefix}_minimum_point" self.backtrack_depth = backtrack_depth - def run(self, dag): + def run(self, dag: DAGCircuit) -> DAGCircuit: """Run the MinimumPoint pass on `dag`.""" score = tuple(self.property_set[x] for x in self.property_set_list) state = self.property_set[self.backtrack_name] @@ -114,5 +114,5 @@ class _MinimumPointState: __slots__ = ("dag", "score", "since") dag: DAGCircuit - score: Tuple[float, ...] + score: tuple[float, ...] since: int diff --git a/qiskit/transpiler/passmanager.py b/qiskit/transpiler/passmanager.py index c905d614214..1ed8051db8f 100644 --- a/qiskit/transpiler/passmanager.py +++ b/qiskit/transpiler/passmanager.py @@ -16,9 +16,9 @@ import inspect import io import re -from collections.abc import Iterator, Iterable, Callable +from collections.abc import Iterator, Iterable, Callable, Sequence from functools import wraps -from typing import Union, List, Any, TypeVar +from typing import Any, List, Union, TypeVar from qiskit.circuit import QuantumCircuit from qiskit.converters import circuit_to_dag, dag_to_circuit @@ -39,7 +39,7 @@ class PassManager(BasePassManager): def __init__( self, - passes: Task | list[Task] = (), + passes: Task | Sequence[Task] = (), max_iteration: int = 1000, ): """Initialize an empty pass manager object. @@ -172,7 +172,7 @@ def run( # pylint:disable=arguments-renamed self, circuits: _CircuitsT, output_name: str | None = None, - callback: Callable = None, + callback: Callable[..., Any] | None = None, num_processes: int = None, ) -> _CircuitsT: """Run all the passes on the specified ``circuits``. @@ -434,7 +434,7 @@ def run( self, circuits: _CircuitsT, output_name: str | None = None, - callback: Callable | None = None, + callback: Callable[..., Any] | None = None, num_processes: int = None, ) -> _CircuitsT: self._update_passmanager() diff --git a/qiskit/transpiler/preset_passmanagers/builtin_plugins.py b/qiskit/transpiler/preset_passmanagers/builtin_plugins.py index f85b4d113c1..b5c99994e66 100644 --- a/qiskit/transpiler/preset_passmanagers/builtin_plugins.py +++ b/qiskit/transpiler/preset_passmanagers/builtin_plugins.py @@ -11,7 +11,9 @@ # that they have been altered from the originals. """Built-in transpiler stage plugins for preset pass managers.""" +from __future__ import annotations +from qiskit.transpiler.basepasses import BasePass from qiskit.transpiler.passmanager import PassManager from qiskit.transpiler.exceptions import TranspilerError from qiskit.transpiler.passes import BasicSwap @@ -519,7 +521,7 @@ def _opt_control(property_set): ) if optimization_level == 1: # Steps for optimization level 1 - _opt = [ + _opt: list[BasePass] = [ Optimize1qGatesDecomposition( basis=pass_manager_config.basis_gates, target=pass_manager_config.target ), diff --git a/qiskit/transpiler/preset_passmanagers/common.py b/qiskit/transpiler/preset_passmanagers/common.py index ec479f9e006..f5ec2b7b99d 100644 --- a/qiskit/transpiler/preset_passmanagers/common.py +++ b/qiskit/transpiler/preset_passmanagers/common.py @@ -12,14 +12,16 @@ """Common preset passmanager generators.""" +from __future__ import annotations import collections -from typing import Optional +from collections.abc import Sequence from qiskit.circuit.equivalence_library import SessionEquivalenceLibrary as sel from qiskit.circuit.controlflow import CONTROL_FLOW_OP_NAMES from qiskit.passmanager.flow_controllers import ConditionalController +from qiskit.transpiler.basepasses import BasePass from qiskit.transpiler.passmanager import PassManager from qiskit.transpiler.passes import Error from qiskit.transpiler.passes import BasisTranslator @@ -449,6 +451,7 @@ def generate_translation_passmanager( Raises: TranspilerError: If the ``method`` kwarg is not a valid value """ + unroll: Sequence[BasePass] if method == "translator": unroll = [ # Use unitary synthesis for basis aware decomposition of @@ -616,8 +619,8 @@ def _require_alignment(property_set): def get_vf2_limits( optimization_level: int, - layout_method: Optional[str] = None, - initial_layout: Optional[Layout] = None, + layout_method: str | None = None, + initial_layout: Layout | None = None, ) -> VF2Limits: """Get the VF2 limits for VF2-based layout passes. diff --git a/qiskit/transpiler/target.py b/qiskit/transpiler/target.py index 8805deece50..e7442bd21b6 100644 --- a/qiskit/transpiler/target.py +++ b/qiskit/transpiler/target.py @@ -438,7 +438,7 @@ def add_instruction(self, instruction, properties=None, name=None): self._non_global_basis = None self._non_global_strict_basis = None - def update_instruction_properties(self, instruction, qargs, properties): + def update_instruction_properties(self, instruction, qargs: tuple, properties): """Update the property object for an instruction qarg pair already in the Target Args: @@ -1095,7 +1095,7 @@ def physical_qubits(self): """Returns a sorted list of physical_qubits""" return list(range(self.num_qubits)) - def get_non_global_operation_names(self, strict_direction=False): + def get_non_global_operation_names(self, strict_direction: bool = False) -> list[str]: """Return the non-global operation names for the target The non-global operations are those in the target which don't apply