From 4245c77ffdb458b9352bf1a9467fb6ce6d092201 Mon Sep 17 00:00:00 2001 From: Oscar Gustafsson <oscar.gustafsson@liu.se> Date: Thu, 27 Feb 2025 16:33:31 +0100 Subject: [PATCH] Update code to Python 3.10 --- b_asic/GUI/arrow.py | 4 +- b_asic/GUI/drag_button.py | 6 +- b_asic/GUI/main_window.py | 31 +- b_asic/GUI/simulate_sfg_window.py | 4 +- b_asic/architecture.py | 100 +++---- b_asic/core_operations.py | 366 ++++++++++++------------ b_asic/graph_component.py | 5 +- b_asic/gui_utils/plot_window.py | 6 +- b_asic/logger.py | 5 +- b_asic/operation.py | 113 ++++---- b_asic/port.py | 17 +- b_asic/process.py | 48 ++-- b_asic/research/interleaver.py | 9 +- b_asic/resources.py | 115 ++++---- b_asic/save_load_structure.py | 6 +- b_asic/schedule.py | 57 ++-- b_asic/scheduler.py | 16 +- b_asic/scheduler_gui/axes_item.py | 13 +- b_asic/scheduler_gui/main_window.py | 24 +- b_asic/scheduler_gui/operation_item.py | 12 +- b_asic/scheduler_gui/scheduler_event.py | 10 +- b_asic/scheduler_gui/scheduler_item.py | 18 +- b_asic/scheduler_gui/timeline_item.py | 10 +- b_asic/sfg_generators.py | 35 +-- b_asic/signal.py | 13 +- b_asic/signal_flow_graph.py | 92 +++--- b_asic/signal_generator.py | 22 +- b_asic/simulation.py | 24 +- b_asic/special_operations.py | 28 +- b_asic/utils.py | 10 +- 30 files changed, 597 insertions(+), 622 deletions(-) diff --git a/b_asic/GUI/arrow.py b/b_asic/GUI/arrow.py index 84d52441..02a72bde 100644 --- a/b_asic/GUI/arrow.py +++ b/b_asic/GUI/arrow.py @@ -1,4 +1,4 @@ -from typing import TYPE_CHECKING, Optional, cast +from typing import TYPE_CHECKING, cast from qtpy.QtCore import QPointF from qtpy.QtGui import QPainterPath, QPen @@ -38,7 +38,7 @@ class Arrow(QGraphicsPathItem): source_port_button: "PortButton", destination_port_button: "PortButton", window: "SFGMainWindow", - signal: Optional[Signal] = None, + signal: Signal | None = None, parent=None, ): super().__init__(parent) diff --git a/b_asic/GUI/drag_button.py b/b_asic/GUI/drag_button.py index dc13b756..18308ef7 100644 --- a/b_asic/GUI/drag_button.py +++ b/b_asic/GUI/drag_button.py @@ -5,7 +5,7 @@ Contains a GUI class for drag buttons. """ import os.path -from typing import TYPE_CHECKING, List +from typing import TYPE_CHECKING from qtpy.QtCore import QSize, Qt, Signal from qtpy.QtGui import QIcon @@ -56,7 +56,7 @@ class DragButton(QPushButton): parent=None, ): self.name = operation.name or operation.graph_id - self._ports: List[PortButton] = [] + self._ports: list[PortButton] = [] self.show_name = show_name self._window = window self.operation = operation @@ -115,7 +115,7 @@ class DragButton(QPushButton): super().mousePressEvent(event) @property - def port_list(self) -> List[PortButton]: + def port_list(self) -> list[PortButton]: """Return a list of PortButtons.""" return self._ports diff --git a/b_asic/GUI/main_window.py b/b_asic/GUI/main_window.py index 90146b87..15b5f98c 100644 --- a/b_asic/GUI/main_window.py +++ b/b_asic/GUI/main_window.py @@ -10,8 +10,9 @@ import os import sys import webbrowser from collections import deque +from collections.abc import Sequence from types import ModuleType -from typing import TYPE_CHECKING, Deque, Dict, List, Optional, Sequence, Tuple, cast +from typing import TYPE_CHECKING, Deque, cast from qtpy.QtCore import QCoreApplication, QFileInfo, QSettings, QSize, Qt, QThread, Slot from qtpy.QtGui import QCursor, QIcon, QKeySequence, QPainter @@ -78,20 +79,20 @@ class SFGMainWindow(QMainWindow): self._ui.setupUi(self) self.setWindowIcon(QIcon("small_logo.png")) self._scene = QGraphicsScene(self._ui.splitter) - self._operations_from_name: Dict[str, Operation] = {} + self._operations_from_name: dict[str, Operation] = {} self._zoom = 1 - self._drag_operation_scenes: Dict[DragButton, "QGraphicsProxyWidget"] = {} - self._drag_buttons: Dict[Operation, DragButton] = {} + self._drag_operation_scenes: dict[DragButton, "QGraphicsProxyWidget"] = {} + self._drag_buttons: dict[Operation, DragButton] = {} self._mouse_pressed = False self._mouse_dragging = False self._starting_port = None - self._pressed_operations: List[DragButton] = [] - self._arrow_ports: Dict[Arrow, List[Tuple[PortButton, PortButton]]] = {} - self._operation_to_sfg: Dict[DragButton, SFG] = {} - self._pressed_ports: List[PortButton] = [] - self._sfg_dict: Dict[str, SFG] = {} - self._plot: Dict[Simulation, PlotWindow] = {} - self._ports: Dict[DragButton, List[PortButton]] = {} + self._pressed_operations: list[DragButton] = [] + self._arrow_ports: dict[Arrow, list[tuple[PortButton, PortButton]]] = {} + self._operation_to_sfg: dict[DragButton, SFG] = {} + self._pressed_ports: list[PortButton] = [] + self._sfg_dict: dict[str, SFG] = {} + self._plot: dict[Simulation, PlotWindow] = {} + self._ports: dict[DragButton, list[PortButton]] = {} # Create Graphics View self._graphics_view = QGraphicsView(self._scene, self._ui.splitter) @@ -119,7 +120,7 @@ class SFGMainWindow(QMainWindow): # Add operations self._max_recent_files = 4 - self._recent_files_actions: List[QAction] = [] + self._recent_files_actions: list[QAction] = [] self._recent_files_paths: Deque[str] = deque(maxlen=self._max_recent_files) self.add_operations_from_namespace( @@ -600,7 +601,7 @@ class SFGMainWindow(QMainWindow): """Callback for toggling the status bar.""" self._statusbar.setVisible(self._statusbar_visible.isChecked()) - def get_operations_from_namespace(self, namespace: ModuleType) -> List[str]: + def get_operations_from_namespace(self, namespace: ModuleType) -> list[str]: """ Return a list of all operations defined in a namespace (module). @@ -671,7 +672,7 @@ class SFGMainWindow(QMainWindow): def add_operation( self, op: Operation, - position: Optional[Tuple[float, float]] = None, + position: tuple[float, float] | None = None, is_flipped: bool = False, ) -> None: """ @@ -963,7 +964,7 @@ class SFGMainWindow(QMainWindow): self._keybindings_page.show() -def start_editor(sfg: Optional[SFG] = None) -> Dict[str, SFG]: +def start_editor(sfg: SFG | None = None) -> dict[str, SFG]: """ Start the SFG editor. diff --git a/b_asic/GUI/simulate_sfg_window.py b/b_asic/GUI/simulate_sfg_window.py index 29dc5c8e..6e655242 100644 --- a/b_asic/GUI/simulate_sfg_window.py +++ b/b_asic/GUI/simulate_sfg_window.py @@ -2,7 +2,7 @@ B-ASIC window to simulate an SFG. """ -from typing import TYPE_CHECKING, Dict +from typing import TYPE_CHECKING from qtpy.QtCore import Qt, Signal from qtpy.QtWidgets import ( @@ -181,6 +181,6 @@ class SimulateSFGWindow(QDialog): self.simulate.emit() @property - def properties(self) -> Dict: + def properties(self) -> dict: """Return the simulation properties.""" return self._properties diff --git a/b_asic/architecture.py b/b_asic/architecture.py index 6e10d0f6..03c98379 100644 --- a/b_asic/architecture.py +++ b/b_asic/architecture.py @@ -3,20 +3,12 @@ B-ASIC architecture classes. """ from collections import defaultdict +from collections.abc import Iterable, Iterator from io import TextIOWrapper from itertools import chain from typing import ( DefaultDict, - Dict, - Iterable, - Iterator, - List, Literal, - Optional, - Set, - Tuple, - Type, - Union, cast, ) @@ -55,13 +47,13 @@ class HardwareBlock: """ __slots__ = "_entity_name" - _entity_name: Optional[str] + _entity_name: str | None __slots__ = "_entity_name" - _entity_name: Optional[str] + _entity_name: str | None - def __init__(self, entity_name: Optional[str] = None): - self._entity_name: Optional[str] = None + def __init__(self, entity_name: str | None = None): + self._entity_name: str | None = None if entity_name is not None: self.set_entity_name(entity_name) @@ -161,7 +153,7 @@ class Resource(HardwareBlock): """ def __init__( - self, process_collection: ProcessCollection, entity_name: Optional[str] = None + self, process_collection: ProcessCollection, entity_name: str | None = None ): if not len(process_collection): raise ValueError("Do not create Resource with empty ProcessCollection") @@ -169,7 +161,7 @@ class Resource(HardwareBlock): self._collection = process_collection self._input_count = -1 self._output_count = -1 - self._assignment: Optional[List[ProcessCollection]] = None + self._assignment: list[ProcessCollection] | None = None def __repr__(self): return self.entity_name @@ -311,7 +303,7 @@ class Resource(HardwareBlock): return self._collection @property - def operation_type(self) -> Union[Type[MemoryProcess], Type[Operation]]: + def operation_type(self) -> type[MemoryProcess] | type[Operation]: raise NotImplementedError("ABC Resource does not implement operation_type") def add_process(self, proc: Process, assign=False): @@ -387,12 +379,12 @@ class ProcessingElement(Resource): _color = f"#{''.join(f'{v:0>2X}' for v in PE_COLOR)}" __slots__ = ("_process_collection", "_entity_name") _process_collection: ProcessCollection - _entity_name: Optional[str] + _entity_name: str | None def __init__( self, process_collection: ProcessCollection, - entity_name: Optional[str] = None, + entity_name: str | None = None, assign: bool = True, ): super().__init__(process_collection=process_collection, entity_name=entity_name) @@ -426,7 +418,7 @@ class ProcessingElement(Resource): self.assign() @property - def processes(self) -> List[OperatorProcess]: + def processes(self) -> list[OperatorProcess]: return [cast(OperatorProcess, p) for p in self._collection] def assign( @@ -451,7 +443,7 @@ class ProcessingElement(Resource): raise ValueError("Cannot map ProcessCollection to single ProcessingElement") @property - def operation_type(self) -> Type[Operation]: + def operation_type(self) -> type[Operation]: return self._operation_type @@ -489,20 +481,20 @@ class Memory(Resource): ) _process_collection: ProcessCollection _memory_type: Literal["RAM", "register"] - _entity_name: Optional[str] - _read_ports: Optional[int] - _write_ports: Optional[int] - _total_ports: Optional[int] + _entity_name: str | None + _read_ports: int | None + _write_ports: int | None + _total_ports: int | None _assign: bool def __init__( self, process_collection: ProcessCollection, memory_type: Literal["RAM", "register"] = "RAM", - entity_name: Optional[str] = None, - read_ports: Optional[int] = None, - write_ports: Optional[int] = None, - total_ports: Optional[int] = None, + entity_name: str | None = None, + read_ports: int | None = None, + write_ports: int | None = None, + total_ports: int | None = None, assign: bool = False, ): super().__init__(process_collection=process_collection, entity_name=entity_name) @@ -587,7 +579,7 @@ class Memory(Resource): raise NotImplementedError() @property - def operation_type(self) -> Type[MemoryProcess]: + def operation_type(self) -> type[MemoryProcess]: return self._operation_type @@ -611,10 +603,10 @@ of :class:`~b_asic.architecture.ProcessingElement` def __init__( self, - processing_elements: Union[ProcessingElement, Iterable[ProcessingElement]], - memories: Union[Memory, Iterable[Memory]], + processing_elements: ProcessingElement | Iterable[ProcessingElement], + memories: Memory | Iterable[Memory], entity_name: str = "arch", - direct_interconnects: Optional[ProcessCollection] = None, + direct_interconnects: ProcessCollection | None = None, ): super().__init__(entity_name) self._processing_elements = ( @@ -625,13 +617,13 @@ of :class:`~b_asic.architecture.ProcessingElement` self._memories = [memories] if isinstance(memories, Memory) else list(memories) self._direct_interconnects = direct_interconnects self._variable_input_port_to_resource: DefaultDict[ - InputPort, Set[Tuple[Resource, int]] + InputPort, set[tuple[Resource, int]] ] = defaultdict(set) self._variable_outport_to_resource: DefaultDict[ - OutputPort, Set[Tuple[Resource, int]] + OutputPort, set[tuple[Resource, int]] ] = defaultdict(set) - self._operation_input_port_to_resource: Dict[InputPort, Resource] = {} - self._operation_outport_to_resource: Dict[OutputPort, Resource] = {} + self._operation_input_port_to_resource: dict[InputPort, Resource] = {} + self._operation_outport_to_resource: dict[OutputPort, Resource] = {} self._schedule_time = self._check_and_get_schedule_time() @@ -705,8 +697,8 @@ of :class:`~b_asic.architecture.ProcessingElement` memory_write_ports.add(mv.write_port) memory_read_ports.update(mv.read_ports) - pe_input_ports: Set[InputPort] = set() - pe_output_ports: Set[OutputPort] = set() + pe_input_ports: set[InputPort] = set() + pe_output_ports: set[OutputPort] = set() for pe in self.processing_elements: for operator in pe.processes: pe_input_ports.update(operator.operation.inputs) @@ -727,8 +719,8 @@ of :class:`~b_asic.architecture.ProcessingElement` ) def get_interconnects_for_memory( - self, mem: Union[Memory, str] - ) -> Tuple[Dict[Resource, int], Dict[Resource, int]]: + self, mem: Memory | str + ) -> tuple[dict[Resource, int], dict[Resource, int]]: """ Return a dictionary with interconnect information for a Memory. @@ -756,9 +748,9 @@ of :class:`~b_asic.architecture.ProcessingElement` return dict(d_in), dict(d_out) def get_interconnects_for_pe( - self, pe: Union[str, ProcessingElement] - ) -> Tuple[ - List[Dict[Tuple[Resource, int], int]], List[Dict[Tuple[Resource, int], int]] + self, pe: str | ProcessingElement + ) -> tuple[ + list[dict[tuple[Resource, int], int]], list[dict[tuple[Resource, int], int]] ]: """ Return with interconnect information for a ProcessingElement. @@ -782,10 +774,10 @@ of :class:`~b_asic.architecture.ProcessingElement` if isinstance(pe, str): pe = cast(ProcessingElement, self.resource_from_name(pe)) - d_in: List[DefaultDict[Tuple[Resource, int], int]] = [ + d_in: list[DefaultDict[tuple[Resource, int], int]] = [ defaultdict(_interconnect_dict) for _ in range(pe.input_count) ] - d_out: List[DefaultDict[Tuple[Resource, int], int]] = [ + d_out: list[DefaultDict[tuple[Resource, int], int]] = [ defaultdict(_interconnect_dict) for _ in range(pe.output_count) ] for var in pe.collection: @@ -817,7 +809,7 @@ of :class:`~b_asic.architecture.ProcessingElement` def remove_resource( self, - resource: Union[str, Resource], + resource: str | Resource, ) -> None: """ Remove an empty :class:`Resource` from the architecture. @@ -860,9 +852,9 @@ of :class:`~b_asic.architecture.ProcessingElement` def move_process( self, - proc: Union[str, Process], - source: Union[str, Resource], - destination: Union[str, Resource], + proc: str | Process, + source: str | Resource, + destination: str | Resource, assign: bool = False, ) -> None: """ @@ -1032,8 +1024,8 @@ of :class:`~b_asic.architecture.ProcessingElement` ) # Create list of interconnects - edges: DefaultDict[str, Set[Tuple[str, str]]] = defaultdict(set) - destination_edges: DefaultDict[str, Set[str]] = defaultdict(set) + edges: DefaultDict[str, set[tuple[str, str]]] = defaultdict(set) + destination_edges: DefaultDict[str, set[str]] = defaultdict(set) for pe in self._processing_elements: inputs, outputs = self.get_interconnects_for_pe(pe) for i, inp in enumerate(inputs): @@ -1106,15 +1098,15 @@ of :class:`~b_asic.architecture.ProcessingElement` return dg @property - def memories(self) -> List[Memory]: + def memories(self) -> list[Memory]: return self._memories @property - def processing_elements(self) -> List[ProcessingElement]: + def processing_elements(self) -> list[ProcessingElement]: return self._processing_elements @property - def direct_interconnects(self) -> Optional[ProcessCollection]: + def direct_interconnects(self) -> ProcessCollection | None: return self._direct_interconnects @property diff --git a/b_asic/core_operations.py b/b_asic/core_operations.py index d09e0c62..e16a5ce0 100644 --- a/b_asic/core_operations.py +++ b/b_asic/core_operations.py @@ -4,8 +4,6 @@ B-ASIC Core Operations Module. Contains some of the most commonly used mathematical operations. """ -from typing import Dict, Optional - from numpy import abs as np_abs from numpy import conjugate, sqrt @@ -149,24 +147,24 @@ class Addition(AbstractOperation): "_latency_offsets", "_execution_time", ) - _src0: Optional[SignalSourceProvider] - _src1: Optional[SignalSourceProvider] + _src0: SignalSourceProvider | None + _src1: SignalSourceProvider | None _name: Name - _latency: Optional[int] - _latency_offsets: Optional[Dict[str, int]] - _execution_time: Optional[int] + _latency: int | None + _latency_offsets: dict[str, int] | None + _execution_time: int | None is_linear = True is_swappable = True def __init__( self, - src0: Optional[SignalSourceProvider] = None, - src1: Optional[SignalSourceProvider] = None, + src0: SignalSourceProvider | None = None, + src1: SignalSourceProvider | None = None, name: Name = Name(""), - latency: Optional[int] = None, - latency_offsets: Optional[Dict[str, int]] = None, - execution_time: Optional[int] = None, + latency: int | None = None, + latency_offsets: dict[str, int] | None = None, + execution_time: int | None = None, ): """ Construct an Addition operation. @@ -231,21 +229,21 @@ class Subtraction(AbstractOperation): "_latency_offsets", "_execution_time", ) - _src0: Optional[SignalSourceProvider] - _src1: Optional[SignalSourceProvider] + _src0: SignalSourceProvider | None + _src1: SignalSourceProvider | None _name: Name - _latency: Optional[int] - _latency_offsets: Optional[Dict[str, int]] - _execution_time: Optional[int] + _latency: int | None + _latency_offsets: dict[str, int] | None + _execution_time: int | None def __init__( self, - src0: Optional[SignalSourceProvider] = None, - src1: Optional[SignalSourceProvider] = None, + src0: SignalSourceProvider | None = None, + src1: SignalSourceProvider | None = None, name: Name = Name(""), - latency: Optional[int] = None, - latency_offsets: Optional[Dict[str, int]] = None, - execution_time: Optional[int] = None, + latency: int | None = None, + latency_offsets: dict[str, int] | None = None, + execution_time: int | None = None, ): """Construct a Subtraction operation.""" super().__init__( @@ -317,24 +315,24 @@ class AddSub(AbstractOperation): "_execution_time", ) _is_add: bool - _src0: Optional[SignalSourceProvider] - _src1: Optional[SignalSourceProvider] + _src0: SignalSourceProvider | None + _src1: SignalSourceProvider | None _name: Name - _latency: Optional[int] - _latency_offsets: Optional[Dict[str, int]] - _execution_time: Optional[int] + _latency: int | None + _latency_offsets: dict[str, int] | None + _execution_time: int | None is_linear = True def __init__( self, is_add: bool = True, - src0: Optional[SignalSourceProvider] = None, - src1: Optional[SignalSourceProvider] = None, + src0: SignalSourceProvider | None = None, + src1: SignalSourceProvider | None = None, name: Name = Name(""), - latency: Optional[int] = None, - latency_offsets: Optional[Dict[str, int]] = None, - execution_time: Optional[int] = None, + latency: int | None = None, + latency_offsets: dict[str, int] | None = None, + execution_time: int | None = None, ): """Construct an Addition/Subtraction operation.""" super().__init__( @@ -410,23 +408,23 @@ class Multiplication(AbstractOperation): "_latency_offsets", "_execution_time", ) - _src0: Optional[SignalSourceProvider] - _src1: Optional[SignalSourceProvider] + _src0: SignalSourceProvider | None + _src1: SignalSourceProvider | None _name: Name - _latency: Optional[int] - _latency_offsets: Optional[Dict[str, int]] - _execution_time: Optional[int] + _latency: int | None + _latency_offsets: dict[str, int] | None + _execution_time: int | None is_swappable = True def __init__( self, - src0: Optional[SignalSourceProvider] = None, - src1: Optional[SignalSourceProvider] = None, + src0: SignalSourceProvider | None = None, + src1: SignalSourceProvider | None = None, name: Name = Name(""), - latency: Optional[int] = None, - latency_offsets: Optional[Dict[str, int]] = None, - execution_time: Optional[int] = None, + latency: int | None = None, + latency_offsets: dict[str, int] | None = None, + execution_time: int | None = None, ): """Construct a Multiplication operation.""" super().__init__( @@ -493,21 +491,21 @@ class Division(AbstractOperation): "_latency_offsets", "_execution_time", ) - _src0: Optional[SignalSourceProvider] - _src1: Optional[SignalSourceProvider] + _src0: SignalSourceProvider | None + _src1: SignalSourceProvider | None _name: Name - _latency: Optional[int] - _latency_offsets: Optional[Dict[str, int]] - _execution_time: Optional[int] + _latency: int | None + _latency_offsets: dict[str, int] | None + _execution_time: int | None def __init__( self, - src0: Optional[SignalSourceProvider] = None, - src1: Optional[SignalSourceProvider] = None, + src0: SignalSourceProvider | None = None, + src1: SignalSourceProvider | None = None, name: Name = Name(""), - latency: Optional[int] = None, - latency_offsets: Optional[Dict[str, int]] = None, - execution_time: Optional[int] = None, + latency: int | None = None, + latency_offsets: dict[str, int] | None = None, + execution_time: int | None = None, ): """Construct a Division operation.""" super().__init__( @@ -574,23 +572,23 @@ class Min(AbstractOperation): "_latency_offsets", "_execution_time", ) - _src0: Optional[SignalSourceProvider] - _src1: Optional[SignalSourceProvider] + _src0: SignalSourceProvider | None + _src1: SignalSourceProvider | None _name: Name - _latency: Optional[int] - _latency_offsets: Optional[Dict[str, int]] - _execution_time: Optional[int] + _latency: int | None + _latency_offsets: dict[str, int] | None + _execution_time: int | None is_swappable = True def __init__( self, - src0: Optional[SignalSourceProvider] = None, - src1: Optional[SignalSourceProvider] = None, + src0: SignalSourceProvider | None = None, + src1: SignalSourceProvider | None = None, name: Name = Name(""), - latency: Optional[int] = None, - latency_offsets: Optional[Dict[str, int]] = None, - execution_time: Optional[int] = None, + latency: int | None = None, + latency_offsets: dict[str, int] | None = None, + execution_time: int | None = None, ): """Construct a Min operation.""" super().__init__( @@ -655,23 +653,23 @@ class Max(AbstractOperation): "_latency_offsets", "_execution_time", ) - _src0: Optional[SignalSourceProvider] - _src1: Optional[SignalSourceProvider] + _src0: SignalSourceProvider | None + _src1: SignalSourceProvider | None _name: Name - _latency: Optional[int] - _latency_offsets: Optional[Dict[str, int]] - _execution_time: Optional[int] + _latency: int | None + _latency_offsets: dict[str, int] | None + _execution_time: int | None is_swappable = True def __init__( self, - src0: Optional[SignalSourceProvider] = None, - src1: Optional[SignalSourceProvider] = None, + src0: SignalSourceProvider | None = None, + src1: SignalSourceProvider | None = None, name: Name = Name(""), - latency: Optional[int] = None, - latency_offsets: Optional[Dict[str, int]] = None, - execution_time: Optional[int] = None, + latency: int | None = None, + latency_offsets: dict[str, int] | None = None, + execution_time: int | None = None, ): """Construct a Max operation.""" super().__init__( @@ -719,19 +717,19 @@ class SquareRoot(AbstractOperation): """ __slots__ = ("_src0", "_name", "_latency", "_latency_offsets", "_execution_time") - _src0: Optional[SignalSourceProvider] + _src0: SignalSourceProvider | None _name: Name - _latency: Optional[int] - _latency_offsets: Optional[Dict[str, int]] - _execution_time: Optional[int] + _latency: int | None + _latency_offsets: dict[str, int] | None + _execution_time: int | None def __init__( self, - src0: Optional[SignalSourceProvider] = None, + src0: SignalSourceProvider | None = None, name: Name = Name(""), - latency: Optional[int] = None, - latency_offsets: Optional[Dict[str, int]] = None, - execution_time: Optional[int] = None, + latency: int | None = None, + latency_offsets: dict[str, int] | None = None, + execution_time: int | None = None, ): """Construct a SquareRoot operation.""" super().__init__( @@ -777,19 +775,19 @@ class ComplexConjugate(AbstractOperation): """ __slots__ = ("_src0", "_name", "_latency", "_latency_offsets", "_execution_time") - _src0: Optional[SignalSourceProvider] + _src0: SignalSourceProvider | None _name: Name - _latency: Optional[int] - _latency_offsets: Optional[Dict[str, int]] - _execution_time: Optional[int] + _latency: int | None + _latency_offsets: dict[str, int] | None + _execution_time: int | None def __init__( self, - src0: Optional[SignalSourceProvider] = None, + src0: SignalSourceProvider | None = None, name: Name = Name(""), - latency: Optional[int] = None, - latency_offsets: Optional[Dict[str, int]] = None, - execution_time: Optional[int] = None, + latency: int | None = None, + latency_offsets: dict[str, int] | None = None, + execution_time: int | None = None, ): """Construct a ComplexConjugate operation.""" super().__init__( @@ -835,19 +833,19 @@ class Absolute(AbstractOperation): """ __slots__ = ("_src0", "_name", "_latency", "_latency_offsets", "_execution_time") - _src0: Optional[SignalSourceProvider] + _src0: SignalSourceProvider | None _name: Name - _latency: Optional[int] - _latency_offsets: Optional[Dict[str, int]] - _execution_time: Optional[int] + _latency: int | None + _latency_offsets: dict[str, int] | None + _execution_time: int | None def __init__( self, - src0: Optional[SignalSourceProvider] = None, + src0: SignalSourceProvider | None = None, name: Name = Name(""), - latency: Optional[int] = None, - latency_offsets: Optional[Dict[str, int]] = None, - execution_time: Optional[int] = None, + latency: int | None = None, + latency_offsets: dict[str, int] | None = None, + execution_time: int | None = None, ): """Construct an Absolute operation.""" super().__init__( @@ -907,22 +905,22 @@ class ConstantMultiplication(AbstractOperation): "_execution_time", ) _value: Num - _src0: Optional[SignalSourceProvider] + _src0: SignalSourceProvider | None _name: Name - _latency: Optional[int] - _latency_offsets: Optional[Dict[str, int]] - _execution_time: Optional[int] + _latency: int | None + _latency_offsets: dict[str, int] | None + _execution_time: int | None is_linear = True def __init__( self, value: Num = 0, - src0: Optional[SignalSourceProvider] = None, + src0: SignalSourceProvider | None = None, name: Name = Name(""), - latency: Optional[int] = None, - latency_offsets: Optional[Dict[str, int]] = None, - execution_time: Optional[int] = None, + latency: int | None = None, + latency_offsets: dict[str, int] | None = None, + execution_time: int | None = None, ): """Construct a ConstantMultiplication operation with the given value.""" super().__init__( @@ -995,23 +993,23 @@ class Butterfly(AbstractOperation): "_latency_offsets", "_execution_time", ) - _src0: Optional[SignalSourceProvider] - _src1: Optional[SignalSourceProvider] + _src0: SignalSourceProvider | None + _src1: SignalSourceProvider | None _name: Name - _latency: Optional[int] - _latency_offsets: Optional[Dict[str, int]] - _execution_time: Optional[int] + _latency: int | None + _latency_offsets: dict[str, int] | None + _execution_time: int | None is_linear = True def __init__( self, - src0: Optional[SignalSourceProvider] = None, - src1: Optional[SignalSourceProvider] = None, + src0: SignalSourceProvider | None = None, + src1: SignalSourceProvider | None = None, name: Name = Name(""), - latency: Optional[int] = None, - latency_offsets: Optional[Dict[str, int]] = None, - execution_time: Optional[int] = None, + latency: int | None = None, + latency_offsets: dict[str, int] | None = None, + execution_time: int | None = None, ): """Construct a Butterfly operation.""" super().__init__( @@ -1075,25 +1073,25 @@ class MAD(AbstractOperation): "_latency_offsets", "_execution_time", ) - _src0: Optional[SignalSourceProvider] - _src1: Optional[SignalSourceProvider] - _src2: Optional[SignalSourceProvider] + _src0: SignalSourceProvider | None + _src1: SignalSourceProvider | None + _src2: SignalSourceProvider | None _name: Name - _latency: Optional[int] - _latency_offsets: Optional[Dict[str, int]] - _execution_time: Optional[int] + _latency: int | None + _latency_offsets: dict[str, int] | None + _execution_time: int | None is_swappable = True def __init__( self, - src0: Optional[SignalSourceProvider] = None, - src1: Optional[SignalSourceProvider] = None, - src2: Optional[SignalSourceProvider] = None, + src0: SignalSourceProvider | None = None, + src1: SignalSourceProvider | None = None, + src2: SignalSourceProvider | None = None, name: Name = Name(""), - latency: Optional[int] = None, - latency_offsets: Optional[Dict[str, int]] = None, - execution_time: Optional[int] = None, + latency: int | None = None, + latency_offsets: dict[str, int] | None = None, + execution_time: int | None = None, ): """Construct a MAD operation.""" super().__init__( @@ -1142,29 +1140,29 @@ class MADS(AbstractOperation): "_latency_offsets", "_execution_time", ) - _is_add: Optional[bool] - _override_zero_on_src0: Optional[bool] - _src0: Optional[SignalSourceProvider] - _src1: Optional[SignalSourceProvider] - _src2: Optional[SignalSourceProvider] + _is_add: bool | None + _override_zero_on_src0: bool | None + _src0: SignalSourceProvider | None + _src1: SignalSourceProvider | None + _src2: SignalSourceProvider | None _name: Name - _latency: Optional[int] - _latency_offsets: Optional[Dict[str, int]] - _execution_time: Optional[int] + _latency: int | None + _latency_offsets: dict[str, int] | None + _execution_time: int | None is_swappable = True def __init__( self, - is_add: Optional[bool] = True, - override_zero_on_src0: Optional[bool] = False, - src0: Optional[SignalSourceProvider] = None, - src1: Optional[SignalSourceProvider] = None, - src2: Optional[SignalSourceProvider] = None, + is_add: bool | None = True, + override_zero_on_src0: bool | None = False, + src0: SignalSourceProvider | None = None, + src1: SignalSourceProvider | None = None, + src2: SignalSourceProvider | None = None, name: Name = Name(""), - latency: Optional[int] = None, - latency_offsets: Optional[Dict[str, int]] = None, - execution_time: Optional[int] = None, + latency: int | None = None, + latency_offsets: dict[str, int] | None = None, + execution_time: int | None = None, ): """Construct a MADS operation.""" super().__init__( @@ -1251,12 +1249,12 @@ class SymmetricTwoportAdaptor(AbstractOperation): "_latency_offsets", "_execution_time", ) - _src0: Optional[SignalSourceProvider] - _src1: Optional[SignalSourceProvider] + _src0: SignalSourceProvider | None + _src1: SignalSourceProvider | None _name: Name - _latency: Optional[int] - _latency_offsets: Optional[Dict[str, int]] - _execution_time: Optional[int] + _latency: int | None + _latency_offsets: dict[str, int] | None + _execution_time: int | None is_linear = True is_swappable = True @@ -1264,12 +1262,12 @@ class SymmetricTwoportAdaptor(AbstractOperation): def __init__( self, value: Num = 0, - src0: Optional[SignalSourceProvider] = None, - src1: Optional[SignalSourceProvider] = None, + src0: SignalSourceProvider | None = None, + src1: SignalSourceProvider | None = None, name: Name = Name(""), - latency: Optional[int] = None, - latency_offsets: Optional[Dict[str, int]] = None, - execution_time: Optional[int] = None, + latency: int | None = None, + latency_offsets: dict[str, int] | None = None, + execution_time: int | None = None, ): """Construct a SymmetricTwoportAdaptor operation.""" super().__init__( @@ -1344,19 +1342,19 @@ class Reciprocal(AbstractOperation): """ __slots__ = ("_src0", "_name", "_latency", "_latency_offsets", "_execution_time") - _src0: Optional[SignalSourceProvider] + _src0: SignalSourceProvider | None _name: Name - _latency: Optional[int] - _latency_offsets: Optional[Dict[str, int]] - _execution_time: Optional[int] + _latency: int | None + _latency_offsets: dict[str, int] | None + _execution_time: int | None def __init__( self, - src0: Optional[SignalSourceProvider] = None, + src0: SignalSourceProvider | None = None, name: Name = Name(""), - latency: Optional[int] = None, - latency_offsets: Optional[Dict[str, int]] = None, - execution_time: Optional[int] = None, + latency: int | None = None, + latency_offsets: dict[str, int] | None = None, + execution_time: int | None = None, ): """Construct a Reciprocal operation.""" super().__init__( @@ -1418,22 +1416,22 @@ class RightShift(AbstractOperation): "_execution_time", ) _value: Num - _src0: Optional[SignalSourceProvider] + _src0: SignalSourceProvider | None _name: Name - _latency: Optional[int] - _latency_offsets: Optional[Dict[str, int]] - _execution_time: Optional[int] + _latency: int | None + _latency_offsets: dict[str, int] | None + _execution_time: int | None is_linear = True def __init__( self, value: int = 0, - src0: Optional[SignalSourceProvider] = None, + src0: SignalSourceProvider | None = None, name: Name = Name(""), - latency: Optional[int] = None, - latency_offsets: Optional[Dict[str, int]] = None, - execution_time: Optional[int] = None, + latency: int | None = None, + latency_offsets: dict[str, int] | None = None, + execution_time: int | None = None, ): """Construct a RightShift operation with the given value.""" super().__init__( @@ -1510,22 +1508,22 @@ class LeftShift(AbstractOperation): "_execution_time", ) _value: Num - _src0: Optional[SignalSourceProvider] + _src0: SignalSourceProvider | None _name: Name - _latency: Optional[int] - _latency_offsets: Optional[Dict[str, int]] - _execution_time: Optional[int] + _latency: int | None + _latency_offsets: dict[str, int] | None + _execution_time: int | None is_linear = True def __init__( self, value: int = 0, - src0: Optional[SignalSourceProvider] = None, + src0: SignalSourceProvider | None = None, name: Name = Name(""), - latency: Optional[int] = None, - latency_offsets: Optional[Dict[str, int]] = None, - execution_time: Optional[int] = None, + latency: int | None = None, + latency_offsets: dict[str, int] | None = None, + execution_time: int | None = None, ): """Construct a RightShift operation with the given value.""" super().__init__( @@ -1603,22 +1601,22 @@ class Shift(AbstractOperation): "_execution_time", ) _value: Num - _src0: Optional[SignalSourceProvider] + _src0: SignalSourceProvider | None _name: Name - _latency: Optional[int] - _latency_offsets: Optional[Dict[str, int]] - _execution_time: Optional[int] + _latency: int | None + _latency_offsets: dict[str, int] | None + _execution_time: int | None is_linear = True def __init__( self, value: int = 0, - src0: Optional[SignalSourceProvider] = None, + src0: SignalSourceProvider | None = None, name: Name = Name(""), - latency: Optional[int] = None, - latency_offsets: Optional[Dict[str, int]] = None, - execution_time: Optional[int] = None, + latency: int | None = None, + latency_offsets: dict[str, int] | None = None, + execution_time: int | None = None, ): """Construct a Shift operation with the given value.""" super().__init__( diff --git a/b_asic/graph_component.py b/b_asic/graph_component.py index 238c6ecd..2864904b 100644 --- a/b_asic/graph_component.py +++ b/b_asic/graph_component.py @@ -6,8 +6,9 @@ Contains the base for all components with an ID in a signal flow graph. from abc import ABC, abstractmethod from collections import deque +from collections.abc import Generator, Iterable, Mapping from copy import copy, deepcopy -from typing import Any, Dict, Generator, Iterable, Mapping, cast +from typing import Any, cast from b_asic.types import GraphID, Name, TypeName @@ -121,7 +122,7 @@ class AbstractGraphComponent(GraphComponent): _name: Name _graph_id: GraphID - _parameters: Dict[str, Any] + _parameters: dict[str, Any] def __init__(self, name: Name = Name("")): """Construct a graph component.""" diff --git a/b_asic/gui_utils/plot_window.py b/b_asic/gui_utils/plot_window.py index 96c3bec5..4a9b0d58 100644 --- a/b_asic/gui_utils/plot_window.py +++ b/b_asic/gui_utils/plot_window.py @@ -2,7 +2,7 @@ import re import sys -from typing import Dict, List, Mapping, Optional, Sequence # , Union +from collections.abc import Mapping, Sequence # from numpy import (array, real, imag, real_if_close, absolute, angle) import numpy as np @@ -46,7 +46,7 @@ class PlotWindow(QWidget): def __init__( self, sim_result: Mapping[ResultKey, Sequence[Num]], - sfg_name: Optional[str] = None, + sfg_name: str | None = None, ): super().__init__() self.setWindowFlags( @@ -237,7 +237,7 @@ class PlotWindow(QWidget): def start_simulation_dialog( - sim_results: Dict[str, List[complex]], sfg_name: Optional[str] = None + sim_results: dict[str, list[complex]], sfg_name: str | None = None ): """ Display the simulation results window. diff --git a/b_asic/logger.py b/b_asic/logger.py index 5e18464d..53b510e3 100644 --- a/b_asic/logger.py +++ b/b_asic/logger.py @@ -52,7 +52,6 @@ import os import sys from logging import Logger from types import TracebackType -from typing import Type, Union def getLogger(source: str, filename: str, loglevel: str = "INFO") -> Logger: @@ -124,9 +123,9 @@ def getLogger(source: str, filename: str, loglevel: str = "INFO") -> Logger: # log uncaught exceptions def handle_exceptions( - exc_type: Type[BaseException], + exc_type: type[BaseException], exc_value: BaseException, - exc_traceback: Union[TracebackType, None], + exc_traceback: TracebackType | None, ) -> None: # def log_exceptions(type, value, tb): """This function is a helper function to log uncaught exceptions. Install with: diff --git a/b_asic/operation.py b/b_asic/operation.py index 02995d3f..bc6bb748 100644 --- a/b_asic/operation.py +++ b/b_asic/operation.py @@ -8,19 +8,12 @@ import collections import collections.abc import itertools as it from abc import abstractmethod +from collections.abc import Iterable, Mapping, MutableMapping, Sequence from numbers import Number from typing import ( TYPE_CHECKING, - Dict, - Iterable, - List, - Mapping, - MutableMapping, NewType, Optional, - Sequence, - Tuple, - Union, cast, overload, ) @@ -127,8 +120,8 @@ class Operation(GraphComponent, SignalSourceProvider): @abstractmethod def current_output( - self, index: int, delays: Optional[DelayMap] = None, prefix: str = "" - ) -> Optional[Num]: + self, index: int, delays: DelayMap | None = None, prefix: str = "" + ) -> Num | None: """ Get the current output at the given index of this operation, if available. @@ -147,10 +140,10 @@ class Operation(GraphComponent, SignalSourceProvider): self, index: int, input_values: Sequence[Num], - results: Optional[MutableResultMap] = None, - delays: Optional[MutableDelayMap] = None, + results: MutableResultMap | None = None, + delays: MutableDelayMap | None = None, prefix: str = "", - bits_override: Optional[int] = None, + bits_override: int | None = None, quantize: bool = True, ) -> Num: """ @@ -186,8 +179,8 @@ class Operation(GraphComponent, SignalSourceProvider): @abstractmethod def current_outputs( - self, delays: Optional[DelayMap] = None, prefix: str = "" - ) -> Sequence[Optional[Num]]: + self, delays: DelayMap | None = None, prefix: str = "" + ) -> Sequence[Num | None]: """ Get all current outputs of this operation, if available. @@ -201,10 +194,10 @@ class Operation(GraphComponent, SignalSourceProvider): def evaluate_outputs( self, input_values: Sequence[Num], - results: Optional[MutableResultMap] = None, - delays: Optional[MutableDelayMap] = None, + results: MutableResultMap | None = None, + delays: MutableDelayMap | None = None, prefix: str = "", - bits_override: Optional[int] = None, + bits_override: int | None = None, quantize: bool = True, ) -> Sequence[Num]: """ @@ -265,7 +258,7 @@ class Operation(GraphComponent, SignalSourceProvider): @property @abstractmethod - def latency_offsets(self) -> Dict[str, Optional[int]]: + def latency_offsets(self) -> dict[str, int | None]: """ Get a dictionary with all the operations ports latency-offsets. """ @@ -292,7 +285,7 @@ class Operation(GraphComponent, SignalSourceProvider): raise NotImplementedError @abstractmethod - def set_latency_offsets(self, latency_offsets: Dict[str, int]) -> None: + def set_latency_offsets(self, latency_offsets: dict[str, int]) -> None: """ Set the latency-offsets for the operations port. @@ -304,7 +297,7 @@ class Operation(GraphComponent, SignalSourceProvider): @property @abstractmethod - def execution_time(self) -> Optional[int]: + def execution_time(self) -> int | None: """ Get the execution time of the operation. @@ -315,7 +308,7 @@ class Operation(GraphComponent, SignalSourceProvider): @execution_time.setter @abstractmethod - def execution_time(self, execution_time: Optional[int]) -> None: + def execution_time(self, execution_time: int | None) -> None: """ Set the execution time of the operation. @@ -335,7 +328,7 @@ class Operation(GraphComponent, SignalSourceProvider): @abstractmethod def get_plot_coordinates( self, - ) -> Tuple[Tuple[Tuple[float, float], ...], Tuple[Tuple[float, float], ...]]: + ) -> tuple[tuple[tuple[float, float], ...], tuple[tuple[float, float], ...]]: """ Return coordinates for the latency and execution time polygons. @@ -348,7 +341,7 @@ class Operation(GraphComponent, SignalSourceProvider): @abstractmethod def get_input_coordinates( self, - ) -> Tuple[Tuple[float, float], ...]: + ) -> tuple[tuple[float, float], ...]: """ Return coordinates for inputs. @@ -364,7 +357,7 @@ class Operation(GraphComponent, SignalSourceProvider): @abstractmethod def get_output_coordinates( self, - ) -> Tuple[Tuple[float, float], ...]: + ) -> tuple[tuple[float, float], ...]: """ Return coordinates for outputs. @@ -455,19 +448,19 @@ class AbstractOperation(Operation, AbstractGraphComponent): """ __slots__ = ("_input_ports", "_output_ports", "_execution_time") - _input_ports: List[InputPort] - _output_ports: List[OutputPort] - _execution_time: Optional[int] + _input_ports: list[InputPort] + _output_ports: list[OutputPort] + _execution_time: int | None def __init__( self, input_count: int, output_count: int, name: Name = Name(""), - input_sources: Optional[Sequence[Optional[SignalSourceProvider]]] = None, - latency: Optional[int] = None, - latency_offsets: Optional[Dict[str, int]] = None, - execution_time: Optional[int] = None, + input_sources: Sequence[SignalSourceProvider | None] | None = None, + latency: int | None = None, + latency_offsets: dict[str, int] | None = None, + execution_time: int | None = None, ): """ Construct an operation with the given input/output count. @@ -520,12 +513,12 @@ class AbstractOperation(Operation, AbstractGraphComponent): @abstractmethod def evaluate( self, *inputs: Operation - ) -> List[Operation]: # pylint: disable=arguments-differ + ) -> list[Operation]: # pylint: disable=arguments-differ ... @overload @abstractmethod - def evaluate(self, *inputs: Num) -> List[Num]: # pylint: disable=arguments-differ + def evaluate(self, *inputs: Num) -> list[Num]: # pylint: disable=arguments-differ ... @abstractmethod @@ -552,7 +545,7 @@ class AbstractOperation(Operation, AbstractGraphComponent): def __str__(self) -> str: """Get a string representation of this operation.""" - inputs_dict: Dict[int, Union[List[GraphID], str]] = {} + inputs_dict: dict[int, list[GraphID] | str] = {} for i, current_input in enumerate(self.inputs): if current_input.signal_count == 0: inputs_dict[i] = "-" @@ -571,7 +564,7 @@ class AbstractOperation(Operation, AbstractGraphComponent): dict_ele.append(GraphID("no_id")) inputs_dict[i] = dict_ele - outputs_dict: Dict[int, Union[List[GraphID], str]] = {} + outputs_dict: dict[int, list[GraphID] | str] = {} for i, outport in enumerate(self.outputs): if outport.signal_count == 0: outputs_dict[i] = "-" @@ -644,18 +637,18 @@ class AbstractOperation(Operation, AbstractGraphComponent): return ResultKey(key) def current_output( - self, index: int, delays: Optional[DelayMap] = None, prefix: str = "" - ) -> Optional[Num]: + self, index: int, delays: DelayMap | None = None, prefix: str = "" + ) -> Num | None: return None def evaluate_output( self, index: int, input_values: Sequence[Num], - results: Optional[MutableResultMap] = None, - delays: Optional[MutableDelayMap] = None, + results: MutableResultMap | None = None, + delays: MutableDelayMap | None = None, prefix: str = "", - bits_override: Optional[int] = None, + bits_override: int | None = None, quantize: bool = True, ) -> Num: if index < 0 or index >= self.output_count: @@ -701,8 +694,8 @@ class AbstractOperation(Operation, AbstractGraphComponent): return values[index] def current_outputs( - self, delays: Optional[DelayMap] = None, prefix: str = "" - ) -> Sequence[Optional[Num]]: + self, delays: DelayMap | None = None, prefix: str = "" + ) -> Sequence[Num | None]: return [ self.current_output(i, delays, prefix) for i in range(self.output_count) ] @@ -710,10 +703,10 @@ class AbstractOperation(Operation, AbstractGraphComponent): def evaluate_outputs( self, input_values: Sequence[Num], - results: Optional[MutableResultMap] = None, - delays: Optional[MutableDelayMap] = None, + results: MutableResultMap | None = None, + delays: MutableDelayMap | None = None, prefix: str = "", - bits_override: Optional[int] = None, + bits_override: int | None = None, quantize: bool = True, ) -> Sequence[Num]: return [ @@ -737,7 +730,7 @@ class AbstractOperation(Operation, AbstractGraphComponent): if isinstance(result, collections.abc.Sequence) and all( isinstance(e, Operation) for e in result ): - return cast(List[Operation], result) + return cast(list[Operation], result) return [self] def to_sfg(self) -> "SFG": @@ -838,7 +831,7 @@ class AbstractOperation(Operation, AbstractGraphComponent): def quantize_inputs( self, input_values: Sequence[Num], - bits_override: Optional[int] = None, + bits_override: int | None = None, ) -> Sequence[Num]: """ Quantize the values to be used as inputs. @@ -879,7 +872,7 @@ class AbstractOperation(Operation, AbstractGraphComponent): ) @property - def latency_offsets(self) -> Dict[str, Optional[int]]: + def latency_offsets(self) -> dict[str, int | None]: latency_offsets = {} for i, input_ in enumerate(self.inputs): @@ -897,7 +890,7 @@ class AbstractOperation(Operation, AbstractGraphComponent): self.input_latency_offsets() self.output_latency_offsets() - def input_latency_offsets(self) -> List[int]: + def input_latency_offsets(self) -> list[int]: latency_offsets = [i.latency_offset for i in self.inputs] if any(val is None for val in latency_offsets): @@ -906,9 +899,9 @@ class AbstractOperation(Operation, AbstractGraphComponent): ] raise ValueError(f"Missing latencies for input(s) {missing}") - return cast(List[int], latency_offsets) + return cast(list[int], latency_offsets) - def output_latency_offsets(self) -> List[int]: + def output_latency_offsets(self) -> list[int]: latency_offsets = [i.latency_offset for i in self.outputs] if any(val is None for val in latency_offsets): @@ -917,7 +910,7 @@ class AbstractOperation(Operation, AbstractGraphComponent): ] raise ValueError(f"Missing latencies for output(s) {missing}") - return cast(List[int], latency_offsets) + return cast(list[int], latency_offsets) def set_latency(self, latency: int) -> None: if latency < 0: @@ -927,7 +920,7 @@ class AbstractOperation(Operation, AbstractGraphComponent): for outport in self.outputs: outport.latency_offset = latency - def set_latency_offsets(self, latency_offsets: Dict[str, int]) -> None: + def set_latency_offsets(self, latency_offsets: dict[str, int]) -> None: for port_str, latency_offset in latency_offsets.items(): port_str = port_str.lower() if port_str.startswith("in"): @@ -953,7 +946,7 @@ class AbstractOperation(Operation, AbstractGraphComponent): ) @property - def execution_time(self) -> Optional[int]: + def execution_time(self) -> int | None: """Execution time of operation.""" return self._execution_time @@ -979,7 +972,7 @@ class AbstractOperation(Operation, AbstractGraphComponent): def get_plot_coordinates( self, - ) -> Tuple[Tuple[Tuple[float, float], ...], Tuple[Tuple[float, float], ...]]: + ) -> tuple[tuple[tuple[float, float], ...], tuple[tuple[float, float], ...]]: # Doc-string inherited return ( self._get_plot_coordinates_for_latency(), @@ -988,7 +981,7 @@ class AbstractOperation(Operation, AbstractGraphComponent): def _get_plot_coordinates_for_execution_time( self, - ) -> Tuple[Tuple[float, float], ...]: + ) -> tuple[tuple[float, float], ...]: # Always a rectangle, but easier if coordinates are returned execution_time = self._execution_time # Copy for type checking if execution_time is None: @@ -1003,7 +996,7 @@ class AbstractOperation(Operation, AbstractGraphComponent): def _get_plot_coordinates_for_latency( self, - ) -> Tuple[Tuple[float, float], ...]: + ) -> tuple[tuple[float, float], ...]: # Points for latency polygon latency = [] input_latencies = self.input_latency_offsets() @@ -1028,7 +1021,7 @@ class AbstractOperation(Operation, AbstractGraphComponent): return tuple(latency) - def get_input_coordinates(self) -> Tuple[Tuple[float, float], ...]: + def get_input_coordinates(self) -> tuple[tuple[float, float], ...]: # doc-string inherited num_in = self.input_count return tuple( @@ -1039,7 +1032,7 @@ class AbstractOperation(Operation, AbstractGraphComponent): for k in range(num_in) ) - def get_output_coordinates(self) -> Tuple[Tuple[float, float], ...]: + def get_output_coordinates(self) -> tuple[tuple[float, float], ...]: # doc-string inherited num_out = self.output_count return tuple( diff --git a/b_asic/port.py b/b_asic/port.py index b3b3ccfb..65df10d3 100644 --- a/b_asic/port.py +++ b/b_asic/port.py @@ -5,9 +5,10 @@ Contains classes for managing the ports of operations. """ from abc import ABC, abstractmethod +from collections.abc import Sequence from copy import copy from numbers import Number -from typing import TYPE_CHECKING, List, Optional, Sequence, Union +from typing import TYPE_CHECKING, Optional, Union from b_asic.graph_component import Name from b_asic.signal import Signal @@ -55,7 +56,7 @@ class Port(ABC): @property @abstractmethod - def latency_offset(self) -> Optional[int]: + def latency_offset(self) -> int | None: """Get the latency_offset of the port.""" raise NotImplementedError @@ -133,13 +134,13 @@ class AbstractPort(Port): __slots__ = ("_operation", "_index", "_latency_offset") _operation: "Operation" _index: int - _latency_offset: Optional[int] + _latency_offset: int | None def __init__( self, operation: "Operation", index: int, - latency_offset: Optional[int] = None, + latency_offset: int | None = None, ): """Construct a port of the given operation at the given port index.""" self._operation = operation @@ -155,11 +156,11 @@ class AbstractPort(Port): return self._index @property - def latency_offset(self) -> Optional[int]: + def latency_offset(self) -> int | None: return self._latency_offset @latency_offset.setter - def latency_offset(self, latency_offset: Optional[int]): + def latency_offset(self, latency_offset: int | None): self._latency_offset = latency_offset @property @@ -278,7 +279,7 @@ class InputPort(AbstractPort): """ __slots__ = ("_source_signal",) - _source_signal: Optional[Signal] + _source_signal: Signal | None def __init__(self, operation: "Operation", index: int): """Construct an InputPort.""" @@ -375,7 +376,7 @@ class OutputPort(AbstractPort, SignalSourceProvider): """ __slots__ = ("_destination_signals",) - _destination_signals: List[Signal] + _destination_signals: list[Signal] def __init__(self, operation: "Operation", index: int): """Construct an OutputPort.""" diff --git a/b_asic/process.py b/b_asic/process.py index e51fc31e..0a5d7fa7 100644 --- a/b_asic/process.py +++ b/b_asic/process.py @@ -1,6 +1,6 @@ """B-ASIC classes representing resource usage.""" -from typing import Any, Dict, List, Optional, Tuple, cast +from typing import Any, Optional, cast from b_asic.operation import Operation from b_asic.port import InputPort, OutputPort @@ -69,7 +69,7 @@ class Process: return f"Process({self.start_time}, {self.execution_time}, {self.name!r})" @property - def read_times(self) -> Tuple[int, ...]: + def read_times(self) -> tuple[int, ...]: return (self.start_time + self.execution_time,) @@ -94,7 +94,7 @@ class OperatorProcess(Process): self, start_time: int, operation: Operation, - name: Optional[str] = None, + name: str | None = None, ): execution_time = operation.execution_time if execution_time is None: @@ -140,12 +140,12 @@ class MemoryProcess(Process): """ __slots__ = ("_life_times",) - _life_times: List[int] + _life_times: list[int] def __init__( self, write_time: int, - life_times: List[int], + life_times: list[int], name: str = "", ): pass @@ -157,19 +157,19 @@ class MemoryProcess(Process): ) @property - def read_times(self) -> Tuple[int, ...]: + def read_times(self) -> tuple[int, ...]: return tuple(self.start_time + read for read in self._life_times) @property - def life_times(self) -> List[int]: + def life_times(self) -> list[int]: return self._life_times @property - def reads(self) -> Dict[Any, int]: + def reads(self) -> dict[Any, int]: raise NotImplementedError("MultiReadProcess should be derived from") @property - def read_ports(self) -> List[Any]: + def read_ports(self) -> list[Any]: raise NotImplementedError("MultiReadProcess should be derived from") @property @@ -179,7 +179,7 @@ class MemoryProcess(Process): def split_on_length( self, length: int = 0, - ) -> Tuple[Optional["MemoryProcess"], Optional["MemoryProcess"]]: + ) -> tuple[Optional["MemoryProcess"], Optional["MemoryProcess"]]: """ Split this :class:`MemoryProcess` into two new :class:`MemoryProcess` objects. @@ -286,16 +286,16 @@ class MemoryVariable(MemoryProcess): """ __slots__ = ("_reads", "_read_ports", "_write_port") - _reads: Dict[InputPort, int] - _read_ports: List[InputPort] + _reads: dict[InputPort, int] + _read_ports: list[InputPort] _write_port: OutputPort def __init__( self, write_time: int, write_port: OutputPort, - reads: Dict[InputPort, int], - name: Optional[str] = None, + reads: dict[InputPort, int], + name: str | None = None, ): self._read_ports = list(reads.keys()) self._reads = reads @@ -307,11 +307,11 @@ class MemoryVariable(MemoryProcess): ) @property - def reads(self) -> Dict[InputPort, int]: + def reads(self) -> dict[InputPort, int]: return self._reads @property - def read_ports(self) -> List[InputPort]: + def read_ports(self) -> list[InputPort]: return self._read_ports @property @@ -328,7 +328,7 @@ class MemoryVariable(MemoryProcess): def split_on_length( self, length: int = 0, - ) -> Tuple[Optional["MemoryVariable"], Optional["MemoryVariable"]]: + ) -> tuple[Optional["MemoryVariable"], Optional["MemoryVariable"]]: """ Split this :class:`MemoryVariable` into two new :class:`MemoryVariable` objects, based on lifetimes of read accesses. @@ -376,16 +376,16 @@ class PlainMemoryVariable(MemoryProcess): """ __slots__ = ("_reads", "_read_ports", "_write_port") - _reads: Dict[int, int] - _read_ports: List[int] + _reads: dict[int, int] + _read_ports: list[int] _write_port: OutputPort def __init__( self, write_time: int, write_port: int, - reads: Dict[int, int], - name: Optional[str] = None, + reads: dict[int, int], + name: str | None = None, ): self._read_ports = list(reads.keys()) self._write_port = write_port @@ -401,11 +401,11 @@ class PlainMemoryVariable(MemoryProcess): ) @property - def reads(self) -> Dict[int, int]: + def reads(self) -> dict[int, int]: return self._reads @property - def read_ports(self) -> List[int]: + def read_ports(self) -> list[int]: return self._read_ports @property @@ -422,7 +422,7 @@ class PlainMemoryVariable(MemoryProcess): def split_on_length( self, length: int = 0, - ) -> Tuple[Optional["PlainMemoryVariable"], Optional["PlainMemoryVariable"]]: + ) -> tuple[Optional["PlainMemoryVariable"], Optional["PlainMemoryVariable"]]: """ Split this :class:`PlainMemoryVariable` into two new :class:`PlainMemoryVariable` objects, based on lifetimes of read accesses. diff --git a/b_asic/research/interleaver.py b/b_asic/research/interleaver.py index 3bb7a4ba..86b81491 100644 --- a/b_asic/research/interleaver.py +++ b/b_asic/research/interleaver.py @@ -4,19 +4,18 @@ Functions to generate memory-variable test data that are used for research. import random from itertools import product -from typing import List, Optional, Tuple from b_asic.process import PlainMemoryVariable from b_asic.resources import ProcessCollection def _insert_delays( - inputorder: List[Tuple[int, int]], - outputorder: List[Tuple[int, int]], + inputorder: list[tuple[int, int]], + outputorder: list[tuple[int, int]], min_lifetime: int, cyclic: bool, time: int, -) -> Tuple[List[Tuple[int, int]], List[Tuple[int, int]]]: +) -> tuple[list[tuple[int, int]], list[tuple[int, int]]]: size = len(inputorder) maxdiff = min(outputorder[i][0] - inputorder[i][0] for i in range(size)) outputorder = [(o[0] - maxdiff + min_lifetime, o[1]) for o in outputorder] @@ -71,7 +70,7 @@ def generate_random_interleaver( def generate_matrix_transposer( rows: int, - cols: Optional[int] = None, + cols: int | None = None, min_lifetime: int = 0, cyclic: bool = True, parallelism: int = 1, diff --git a/b_asic/resources.py b/b_asic/resources.py index 597e7f29..e54322bc 100644 --- a/b_asic/resources.py +++ b/b_asic/resources.py @@ -1,9 +1,10 @@ import io import re from collections import Counter, defaultdict +from collections.abc import Iterable from functools import reduce from math import log2 -from typing import Dict, Iterable, List, Literal, Optional, Tuple, TypeVar, Union +from typing import Literal, TypeVar import matplotlib.pyplot as plt import networkx as nx @@ -34,7 +35,7 @@ _WARNING_COLOR = tuple(c / 255 for c in WARNING_COLOR) _T = TypeVar('_T') -def _sorted_nicely(to_be_sorted: Iterable[_T]) -> List[_T]: +def _sorted_nicely(to_be_sorted: Iterable[_T]) -> list[_T]: """Sort the given iterable in the way that humans expect.""" def convert(text): @@ -47,10 +48,10 @@ def _sorted_nicely(to_be_sorted: Iterable[_T]) -> List[_T]: def _sanitize_port_option( - read_ports: Optional[int] = None, - write_ports: Optional[int] = None, - total_ports: Optional[int] = None, -) -> Tuple[int, int, int]: + read_ports: int | None = None, + write_ports: int | None = None, + total_ports: int | None = None, +) -> tuple[int, int, int]: """ General port sanitization function used to test if a port specification makes sense. Raises ValueError if the port specification is in-proper. @@ -95,9 +96,9 @@ def _sanitize_port_option( def draw_exclusion_graph_coloring( exclusion_graph: nx.Graph, - color_dict: Dict[Process, int], - ax: Optional[Axes] = None, - color_list: Optional[Union[List[str], List[Tuple[float, float, float]]]] = None, + color_dict: dict[Process, int], + ax: Axes | None = None, + color_list: list[str] | list[tuple[float, float, float]] | None = None, **kwargs, ) -> None: """ @@ -176,12 +177,12 @@ def draw_exclusion_graph_coloring( class _ForwardBackwardEntry: def __init__( self, - inputs: Optional[List[Process]] = None, - outputs: Optional[List[Process]] = None, - regs: Optional[List[Optional[Process]]] = None, - back_edge_to: Optional[Dict[int, int]] = None, - back_edge_from: Optional[Dict[int, int]] = None, - outputs_from: Optional[int] = None, + inputs: list[Process] | None = None, + outputs: list[Process] | None = None, + regs: list[Process | None] | None = None, + back_edge_to: dict[int, int] | None = None, + back_edge_from: dict[int, int] | None = None, + outputs_from: int | None = None, ): """ Single entry in a _ForwardBackwardTable. @@ -204,11 +205,11 @@ class _ForwardBackwardEntry: this entry. outputs_from : int, optional """ - self.inputs: List[Process] = [] if inputs is None else inputs - self.outputs: List[Process] = [] if outputs is None else outputs - self.regs: List[Optional[Process]] = [] if regs is None else regs - self.back_edge_to: Dict[int, int] = {} if back_edge_to is None else back_edge_to - self.back_edge_from: Dict[int, int] = ( + self.inputs: list[Process] = [] if inputs is None else inputs + self.outputs: list[Process] = [] if outputs is None else outputs + self.regs: list[Process | None] = [] if regs is None else regs + self.back_edge_to: dict[int, int] = {} if back_edge_to is None else back_edge_to + self.back_edge_from: dict[int, int] = ( {} if back_edge_from is None else back_edge_from ) self.outputs_from = outputs_from @@ -229,14 +230,14 @@ class _ForwardBackwardTable: """ # Generate an alive variable list self._collection = set(collection.collection) - self._live_variables: List[int] = [0] * collection.schedule_time + self._live_variables: list[int] = [0] * collection.schedule_time for mv in self._collection: stop_time = mv.start_time + mv.execution_time for alive_time in range(mv.start_time, stop_time): self._live_variables[alive_time % collection.schedule_time] += 1 # First, create an empty forward-backward table with the right dimensions - self.table: List[_ForwardBackwardEntry] = [] + self.table: list[_ForwardBackwardEntry] = [] for _ in range(collection.schedule_time): entry = _ForwardBackwardEntry() # https://github.com/microsoft/pyright/issues/1073 @@ -450,7 +451,7 @@ class ProcessCollection: """ __slots__ = ("_collection", "_schedule_time", "_cyclic") - _collection: List[Process] + _collection: list[Process] _schedule_time: int _cyclic: bool @@ -465,7 +466,7 @@ class ProcessCollection: self._cyclic = cyclic @property - def collection(self) -> List[Process]: + def collection(self) -> list[Process]: return self._collection @property @@ -520,15 +521,15 @@ class ProcessCollection: def plot( self, - ax: Optional[Axes] = None, + ax: Axes | None = None, *, show_name: bool = True, - bar_color: Union[str, Tuple[float, ...]] = _LATENCY_COLOR, - marker_color: Union[str, Tuple[float, ...]] = "black", + bar_color: str | tuple[float, ...] = _LATENCY_COLOR, + marker_color: str | tuple[float, ...] = "black", marker_read: str = "X", marker_write: str = "o", show_markers: bool = True, - row: Optional[int] = None, + row: int | None = None, allow_excessive_lifetimes: bool = False, ): """ @@ -689,13 +690,13 @@ class ProcessCollection: self, *, show_name: bool = True, - bar_color: Union[str, Tuple[float, ...]] = _LATENCY_COLOR, - marker_color: Union[str, Tuple[float, ...]] = "black", + bar_color: str | tuple[float, ...] = _LATENCY_COLOR, + marker_color: str | tuple[float, ...] = "black", marker_read: str = "X", marker_write: str = "o", show_markers: bool = True, allow_excessive_lifetimes: bool = False, - title: Optional[str] = None, + title: str | None = None, ) -> None: """ Display lifetime diagram using the current Matplotlib backend. @@ -740,9 +741,9 @@ class ProcessCollection: def create_exclusion_graph_from_ports( self, - read_ports: Optional[int] = None, - write_ports: Optional[int] = None, - total_ports: Optional[int] = None, + read_ports: int | None = None, + write_ports: int | None = None, + total_ports: int | None = None, ) -> nx.Graph: """ Create an exclusion graph based on concurrent read and write accesses. @@ -871,7 +872,7 @@ class ProcessCollection: self, heuristic: Literal["graph_color", "left_edge"] = "left_edge", coloring_strategy: str = "saturation_largest_first", - ) -> List["ProcessCollection"]: + ) -> list["ProcessCollection"]: """ Split based on overlapping execution time. @@ -908,10 +909,10 @@ class ProcessCollection: def split_on_ports( self, heuristic: str = "left_edge", - read_ports: Optional[int] = None, - write_ports: Optional[int] = None, - total_ports: Optional[int] = None, - ) -> List["ProcessCollection"]: + read_ports: int | None = None, + write_ports: int | None = None, + total_ports: int | None = None, + ) -> list["ProcessCollection"]: """ Split based on concurrent read and write accesses. @@ -962,8 +963,8 @@ class ProcessCollection: read_ports: int, write_ports: int, total_ports: int, - sequence: List[Process], - ) -> List["ProcessCollection"]: + sequence: list[Process], + ) -> list["ProcessCollection"]: """ Split this collection into multiple new collections by sequentially assigning processes in the order of `sequence`. @@ -1027,7 +1028,7 @@ class ProcessCollection: if set(self.collection) != set(sequence): raise KeyError("processes in `sequence` must be equal to processes in self") - collections: List[ProcessCollection] = [] + collections: list[ProcessCollection] = [] for process in sequence: process_added = False for collection in collections: @@ -1053,7 +1054,7 @@ class ProcessCollection: write_ports: int, total_ports: int, coloring_strategy: str = "saturation_largest_first", - ) -> List["ProcessCollection"]: + ) -> list["ProcessCollection"]: """ Parameters ---------- @@ -1089,8 +1090,8 @@ class ProcessCollection: def _split_from_graph_coloring( self, - coloring: Dict[Process, int], - ) -> List["ProcessCollection"]: + coloring: dict[Process, int], + ) -> list["ProcessCollection"]: """ Split :class:`Process` objects into a set of :class:`ProcessesCollection` objects based on a provided graph coloring. @@ -1143,8 +1144,8 @@ class ProcessCollection: self, coloring_strategy: str = "saturation_largest_first", *, - coloring: Optional[Dict[Process, int]] = None, - ) -> List["ProcessCollection"]: + coloring: dict[Process, int] | None = None, + ) -> list["ProcessCollection"]: """ Perform assignment of the processes in this collection using graph coloring. @@ -1172,7 +1173,7 @@ class ProcessCollection: f"{process} has execution time greater than the schedule time" ) - cell_assignment: Dict[int, ProcessCollection] = dict() + cell_assignment: dict[int, ProcessCollection] = dict() exclusion_graph = self.create_exclusion_graph_from_execution_time() if coloring is None: coloring = nx.coloring.greedy_color( @@ -1184,7 +1185,7 @@ class ProcessCollection: cell_assignment[cell].add_process(process) return list(cell_assignment.values()) - def _left_edge_assignment(self) -> List["ProcessCollection"]: + def _left_edge_assignment(self) -> list["ProcessCollection"]: """ Perform assignment of the processes in this collection using the left-edge algorithm. @@ -1199,7 +1200,7 @@ class ProcessCollection: ------- List[ProcessCollection] """ - assignment: List[ProcessCollection] = [] + assignment: list[ProcessCollection] = [] for next_process in sorted(self): if next_process.execution_time > self.schedule_time: # Can not assign process to any cell @@ -1256,14 +1257,14 @@ class ProcessCollection: filename: str, entity_name: str, word_length: int, - assignment: List['ProcessCollection'], + assignment: list['ProcessCollection'], read_ports: int = 1, write_ports: int = 1, total_ports: int = 2, *, input_sync: bool = True, - adr_mux_size: Optional[int] = None, - adr_pipe_depth: Optional[int] = None, + adr_mux_size: int | None = None, + adr_pipe_depth: int | None = None, ): """ Generate VHDL code for memory based storage of processes (MemoryVariables). @@ -1411,7 +1412,7 @@ class ProcessCollection: def split_on_length( self, length: int = 0 - ) -> Tuple["ProcessCollection", "ProcessCollection"]: + ) -> tuple["ProcessCollection", "ProcessCollection"]: """ Split into two ProcessCollections based on execution time length. @@ -1567,7 +1568,7 @@ class ProcessCollection: """ return max(self.read_port_accesses().values()) - def read_port_accesses(self) -> Dict[int, int]: + def read_port_accesses(self) -> dict[int, int]: reads = sum( ( [read_time % self.schedule_time for read_time in process.read_times] @@ -1589,7 +1590,7 @@ class ProcessCollection: """ return max(self.write_port_accesses().values()) - def write_port_accesses(self) -> Dict[int, int]: + def write_port_accesses(self) -> dict[int, int]: writes = [ process.start_time % self.schedule_time for process in self._collection ] @@ -1607,7 +1608,7 @@ class ProcessCollection: """ return max(self.total_port_accesses().values()) - def total_port_accesses(self) -> Dict[int, int]: + def total_port_accesses(self) -> dict[int, int]: accesses = sum( ( list(read_time % self.schedule_time for read_time in process.read_times) diff --git a/b_asic/save_load_structure.py b/b_asic/save_load_structure.py index 8f9622d4..34d84498 100644 --- a/b_asic/save_load_structure.py +++ b/b_asic/save_load_structure.py @@ -7,7 +7,7 @@ stored as files. from datetime import datetime from inspect import signature -from typing import Dict, Optional, Tuple, cast +from typing import cast from b_asic.graph_component import GraphComponent from b_asic.port import InputPort @@ -16,7 +16,7 @@ from b_asic.signal_flow_graph import SFG def sfg_to_python( - sfg: SFG, counter: int = 0, suffix: Optional[str] = None, schedule: bool = False + sfg: SFG, counter: int = 0, suffix: str | None = None, schedule: bool = False ) -> str: """ Given an SFG structure try to serialize it for saving to a file. @@ -141,7 +141,7 @@ def sfg_to_python( return result -def python_to_sfg(path: str) -> Tuple[SFG, Dict[str, Tuple[int, int]]]: +def python_to_sfg(path: str) -> tuple[SFG, dict[str, tuple[int, int]]]: """ Given a serialized file, try to deserialize it and load it to the library. diff --git a/b_asic/schedule.py b/b_asic/schedule.py index c815fdb2..13433612 100644 --- a/b_asic/schedule.py +++ b/b_asic/schedule.py @@ -7,7 +7,8 @@ Contains the schedule class for scheduling operations in an SFG. import io import sys from collections import defaultdict -from typing import Dict, List, Optional, Sequence, Tuple, cast +from collections.abc import Sequence +from typing import cast import matplotlib.pyplot as plt import numpy as np @@ -39,11 +40,11 @@ from b_asic.special_operations import Delay, Input, Output from b_asic.types import TypeName # Need RGB from 0 to 1 -_EXECUTION_TIME_COLOR: Tuple[float, ...] = tuple( +_EXECUTION_TIME_COLOR: tuple[float, ...] = tuple( float(c / 255) for c in EXECUTION_TIME_COLOR ) -_LATENCY_COLOR: Tuple[float, ...] = tuple(float(c / 255) for c in LATENCY_COLOR) -_SIGNAL_COLOR: Tuple[float, ...] = tuple(float(c / 255) for c in SIGNAL_COLOR) +_LATENCY_COLOR: tuple[float, ...] = tuple(float(c / 255) for c in LATENCY_COLOR) +_SIGNAL_COLOR: tuple[float, ...] = tuple(float(c / 255) for c in SIGNAL_COLOR) def _laps_default(): @@ -80,20 +81,20 @@ class Schedule: """ _sfg: SFG - _start_times: Dict[GraphID, int] - _laps: Dict[GraphID, int] + _start_times: dict[GraphID, int] + _laps: dict[GraphID, int] _schedule_time: int _cyclic: bool - _y_locations: Dict[GraphID, Optional[int]] + _y_locations: dict[GraphID, int | None] def __init__( self, sfg: SFG, - scheduler: Optional[Scheduler] = None, - schedule_time: Optional[int] = None, + scheduler: Scheduler | None = None, + schedule_time: int | None = None, cyclic: bool = False, - start_times: Optional[Dict[GraphID, int]] = None, - laps: Optional[Dict[GraphID, int]] = None, + start_times: dict[GraphID, int] | None = None, + laps: dict[GraphID, int] | None = None, ): """Construct a Schedule from an SFG.""" if not isinstance(sfg, SFG): @@ -126,7 +127,7 @@ class Schedule: def __str__(self) -> str: """Return a string representation of this Schedule.""" - res: List[Tuple[GraphID, int, int, int]] = [ + res: list[tuple[GraphID, int, int, int]] = [ ( op.graph_id, self.start_time_of_operation(op.graph_id), @@ -265,7 +266,7 @@ class Schedule: def _forward_slacks( self, graph_id: GraphID - ) -> Dict["OutputPort", Dict["Signal", int]]: + ) -> dict["OutputPort", dict["Signal", int]]: ret = {} start_time = self._start_times[graph_id] operation = cast(Operation, self._sfg.find_by_id(graph_id)) @@ -274,8 +275,8 @@ class Schedule: return ret def _output_slacks( - self, output_port: "OutputPort", start_time: Optional[int] = None - ) -> Dict[Signal, int]: + self, output_port: "OutputPort", start_time: int | None = None + ) -> dict[Signal, int]: if start_time is None: start_time = self._start_times[output_port.operation.graph_id] output_slacks = {} @@ -331,7 +332,7 @@ class Schedule: ), ) - def _backward_slacks(self, graph_id: GraphID) -> Dict[InputPort, Dict[Signal, int]]: + def _backward_slacks(self, graph_id: GraphID) -> dict[InputPort, dict[Signal, int]]: ret = {} start_time = self._start_times[graph_id] operation = cast(Operation, self._sfg.find_by_id(graph_id)) @@ -340,8 +341,8 @@ class Schedule: return ret def _input_slacks( - self, input_port: InputPort, start_time: Optional[int] = None - ) -> Dict[Signal, int]: + self, input_port: InputPort, start_time: int | None = None + ) -> dict[Signal, int]: if start_time is None: start_time = self._start_times[input_port.operation.graph_id] input_slacks = {} @@ -361,7 +362,7 @@ class Schedule: input_slacks[signal] = usage_time - available_time return input_slacks - def slacks(self, graph_id: GraphID) -> Tuple[int, int]: + def slacks(self, graph_id: GraphID) -> tuple[int, int]: """ Return the backward and forward slacks of operation *graph_id*. @@ -401,7 +402,7 @@ class Schedule: * 1: backward slack * 2: forward slack """ - res: List[Tuple[GraphID, int, int]] = [ + res: list[tuple[GraphID, int, int]] = [ ( op.graph_id, cast(int, self.backward_slack(op.graph_id)), @@ -463,7 +464,7 @@ class Schedule: return simplified_sfg @property - def start_times(self) -> Dict[GraphID, int]: + def start_times(self) -> dict[GraphID, int]: """The start times of the operations in the schedule.""" return self._start_times @@ -477,7 +478,7 @@ class Schedule: self._start_times = start_times @property - def laps(self) -> Dict[GraphID, int]: + def laps(self) -> dict[GraphID, int]: """ The number of laps for the start times of the operations in the schedule. """ @@ -529,7 +530,7 @@ class Schedule: self._schedule_time *= factor return self - def _get_all_times(self) -> List[int]: + def _get_all_times(self) -> list[int]: """ Return a list of all times for the schedule. @@ -548,7 +549,7 @@ class Schedule: ret = [v for v in ret if v is not None] return ret - def get_possible_time_resolution_decrements(self) -> List[int]: + def get_possible_time_resolution_decrements(self) -> list[int]: """Return a list with possible factors to reduce time resolution.""" vals = self._get_all_times() max_loop = min(val for val in vals if val) @@ -912,8 +913,8 @@ class Schedule: new_sfg = new_sfg.insert_operation_before(op, Delay(), port) return new_sfg() - def _get_memory_variables_list(self) -> List[MemoryVariable]: - ret: List[MemoryVariable] = [] + def _get_memory_variables_list(self) -> list[MemoryVariable]: + ret: list[MemoryVariable] = [] for graph_id, start_time in self._start_times.items(): slacks = self._forward_slacks(graph_id) for outport, signals in slacks.items(): @@ -963,7 +964,7 @@ class Schedule: self.cyclic, ) - def get_used_type_names(self) -> List[TypeName]: + def get_used_type_names(self) -> list[TypeName]: """Get a list of all TypeNames used in the Schedule.""" return self._sfg.get_used_type_names() @@ -1185,7 +1186,7 @@ class Schedule: self._plot_schedule(ax, operation_gap=operation_gap) def show( - self, operation_gap: float = OPERATION_GAP, title: Optional[str] = None + self, operation_gap: float = OPERATION_GAP, title: str | None = None ) -> None: """ Show the schedule. Will display based on the current Matplotlib backend. diff --git a/b_asic/scheduler.py b/b_asic/scheduler.py index e6b8dfd7..9a40ec02 100644 --- a/b_asic/scheduler.py +++ b/b_asic/scheduler.py @@ -2,7 +2,7 @@ import copy import sys from abc import ABC, abstractmethod from math import ceil -from typing import TYPE_CHECKING, Optional, cast +from typing import TYPE_CHECKING, cast import b_asic.logger as logger from b_asic.core_operations import DontCare @@ -29,7 +29,7 @@ class Scheduler(ABC): raise NotImplementedError def _handle_outputs( - self, schedule: "Schedule", non_schedulable_ops: Optional[list["GraphID"]] = [] + self, schedule: "Schedule", non_schedulable_ops: list["GraphID"] | None = [] ) -> None: for output in schedule.sfg.find_by_type_name(Output.type_name()): output = cast(Output, output) @@ -165,12 +165,12 @@ class ListScheduler(Scheduler, ABC): def __init__( self, - max_resources: Optional[dict[TypeName, int]] = None, - max_concurrent_reads: Optional[int] = None, - max_concurrent_writes: Optional[int] = None, - input_times: Optional[dict["GraphID", int]] = None, - output_delta_times: Optional[dict["GraphID", int]] = None, - cyclic: Optional[bool] = False, + max_resources: dict[TypeName, int] | None = None, + max_concurrent_reads: int | None = None, + max_concurrent_writes: int | None = None, + input_times: dict["GraphID", int] | None = None, + output_delta_times: dict["GraphID", int] | None = None, + cyclic: bool | None = False, ) -> None: super() self._logger = logger.getLogger(__name__, "list_scheduler.log", "DEBUG") diff --git a/b_asic/scheduler_gui/axes_item.py b/b_asic/scheduler_gui/axes_item.py index 65520ea6..f65b11c0 100644 --- a/b_asic/scheduler_gui/axes_item.py +++ b/b_asic/scheduler_gui/axes_item.py @@ -6,7 +6,6 @@ Contains the scheduler-gui AxesItem class for drawing and maintaining the axes in a graph. """ from math import pi, sin -from typing import List, Optional, Union # QGraphics and QPainter imports from qtpy.QtCore import QPointF, Qt @@ -51,12 +50,12 @@ class AxesItem(QGraphicsItemGroup): _x_axis: QGraphicsLineItem _x_label: QGraphicsSimpleTextItem _x_arrow: QGraphicsPolygonItem - _x_scale: List[QGraphicsLineItem] - _x_scale_labels: List[QGraphicsSimpleTextItem] - _x_ledger: List[Union[QGraphicsLineItem, TimelineItem]] + _x_scale: list[QGraphicsLineItem] + _x_scale_labels: list[QGraphicsSimpleTextItem] + _x_ledger: list[QGraphicsLineItem | TimelineItem] _x_label_offset: float _y_axis: QGraphicsLineItem - _event_items: List[QGraphicsItem] + _event_items: list[QGraphicsItem] _base_pen: QPen _ledger_pen: QPen _timeline_pen: QPen @@ -69,7 +68,7 @@ class AxesItem(QGraphicsItemGroup): height_indent: float = SCHEDULE_INDENT, width_padding: float = 0.6, height_padding: float = 0.5, - parent: Optional[QGraphicsItem] = None, + parent: QGraphicsItem | None = None, ): """ Class for an AxesItem. @@ -134,7 +133,7 @@ class AxesItem(QGraphicsItemGroup): return self._height @property - def event_items(self) -> List[QGraphicsItem]: + def event_items(self) -> list[QGraphicsItem]: """Return a list of objects that receives events.""" return [self._x_ledger[-1]] diff --git a/b_asic/scheduler_gui/main_window.py b/b_asic/scheduler_gui/main_window.py index 9d035587..09756521 100644 --- a/b_asic/scheduler_gui/main_window.py +++ b/b_asic/scheduler_gui/main_window.py @@ -14,7 +14,7 @@ import webbrowser from collections import defaultdict, deque from copy import deepcopy from importlib.machinery import SourceFileLoader -from typing import TYPE_CHECKING, Deque, Dict, List, Optional, cast, overload +from typing import TYPE_CHECKING, Deque, cast, overload # Qt/qtpy import qtpy @@ -119,15 +119,15 @@ class ScheduleMainWindow(QMainWindow, Ui_MainWindow): """Schedule of an SFG with scheduled Operations.""" _scene: QGraphicsScene - _schedule: Optional[Schedule] - _graph: Optional[SchedulerItem] + _schedule: Schedule | None + _graph: SchedulerItem | None _scale: float _debug_rectangles: QGraphicsItemGroup _splitter_pos: int _splitter_min: int _zoom: float - _color_per_type: Dict[str, QColor] = dict() - converted_colorPerType: Dict[str, str] = dict() + _color_per_type: dict[str, QColor] = dict() + converted_colorPerType: dict[str, str] = dict() def __init__(self): """Initialize Scheduler-GUI.""" @@ -148,11 +148,11 @@ class ScheduleMainWindow(QMainWindow, Ui_MainWindow): self._execution_time_plot_dialogs = defaultdict(lambda: None) self._ports_accesses_for_storage = None self._color_changed_perType = False - self.changed_operation_colors: Dict[str, QColor] = dict() + self.changed_operation_colors: dict[str, QColor] = dict() # Recent files self._max_recent_files = 4 - self._recent_files_actions: List[QAction] = [] + self._recent_files_actions: list[QAction] = [] self._recent_file_paths: Deque[str] = deque(maxlen=self._max_recent_files) self._create_recent_file_actions_and_menus() @@ -239,7 +239,7 @@ class ScheduleMainWindow(QMainWindow, Ui_MainWindow): self._scene.sceneRectChanged.connect(self.shrink_scene_to_min_size) @property - def schedule(self) -> Optional[Schedule]: + def schedule(self) -> Schedule | None: """The current schedule.""" return self._schedule @@ -1584,7 +1584,7 @@ class ScheduleMainWindow(QMainWindow, Ui_MainWindow): @Slot() @Slot(str) - def _schedule_changed(self, type_name: Optional[str] = None): + def _schedule_changed(self, type_name: str | None = None): self._update_execution_times_for_variables() self._update_ports_accesses_for_storage() for key, dialog in self._execution_time_plot_dialogs.items(): @@ -1666,14 +1666,14 @@ def start_scheduler(schedule: Schedule) -> Schedule: ... @overload -def start_scheduler(schedule: None) -> Optional[Schedule]: ... +def start_scheduler(schedule: None) -> Schedule | None: ... @overload -def start_scheduler() -> Optional[Schedule]: ... +def start_scheduler() -> Schedule | None: ... -def start_scheduler(schedule: Optional[Schedule] = None) -> Optional[Schedule]: +def start_scheduler(schedule: Schedule | None = None) -> Schedule | None: """ Start scheduler GUI. diff --git a/b_asic/scheduler_gui/operation_item.py b/b_asic/scheduler_gui/operation_item.py index 6b9fc774..eab2c317 100644 --- a/b_asic/scheduler_gui/operation_item.py +++ b/b_asic/scheduler_gui/operation_item.py @@ -5,7 +5,7 @@ B-ASIC Scheduler-GUI Operation Item Module. Contains the scheduler_gui OperationItem class for drawing and maintain an operation in the schedule. """ -from typing import TYPE_CHECKING, Dict, List, Union, cast +from typing import TYPE_CHECKING, cast # QGraphics and QPainter imports from qtpy.QtCore import QPointF, Qt @@ -56,13 +56,13 @@ class OperationItem(QGraphicsItemGroup): """Static, changed from MainWindow.""" _operation: Operation _height: float - _ports: Dict[str, Dict[str, Union[float, QPointF]]] # ['port-id']['latency/pos'] + _ports: dict[str, dict[str, float | QPointF]] # ['port-id']['latency/pos'] _end_time: int _latency_item: QGraphicsPathItem _execution_time_item: QGraphicsPathItem _label_item: QGraphicsSimpleTextItem - _port_items: List[QGraphicsEllipseItem] - _port_number_items: List[QGraphicsSimpleTextItem] + _port_items: list[QGraphicsEllipseItem] + _port_number_items: list[QGraphicsSimpleTextItem] _inactive_color: QColor = Latency_Color.DEFAULT def __init__( @@ -80,7 +80,7 @@ class OperationItem(QGraphicsItemGroup): self._operation = operation self._height = height operation._check_all_latencies_set() - latency_offsets = cast(Dict[str, int], operation.latency_offsets) + latency_offsets = cast(dict[str, int], operation.latency_offsets) self._ports = {k: {"latency": float(v)} for k, v in latency_offsets.items()} self._end_time = max(latency_offsets.values()) self._port_items = [] @@ -177,7 +177,7 @@ class OperationItem(QGraphicsItemGroup): self._make_component() @property - def event_items(self) -> List[QGraphicsItem]: + def event_items(self) -> list[QGraphicsItem]: """List of objects that receives events.""" return [self] diff --git a/b_asic/scheduler_gui/scheduler_event.py b/b_asic/scheduler_gui/scheduler_event.py index 617e14cb..872b4511 100644 --- a/b_asic/scheduler_gui/scheduler_event.py +++ b/b_asic/scheduler_gui/scheduler_event.py @@ -6,7 +6,7 @@ Contains the scheduler_ui SchedulerEvent class containing event filters and handlers for SchedulerItem objects. """ import math -from typing import List, Optional, overload +from typing import overload # QGraphics and QPainter imports from qtpy.QtCore import QEvent, QObject, QPointF, Qt, Signal @@ -40,14 +40,14 @@ class SchedulerEvent: execution_time_plot = Signal(str) TextSignal = Signal(str) - _axes: Optional[AxesItem] + _axes: AxesItem | None _current_pos: QPointF _delta_time: int _signals: Signals _schedule: Schedule _old_op_position: int = -1 - def __init__(self, parent: Optional[QGraphicsItem] = None): + def __init__(self, parent: QGraphicsItem | None = None): super().__init__(parent=parent) self._signals = self.Signals() @@ -73,7 +73,7 @@ class SchedulerEvent: def installSceneEventFilters(self, filterItems: QGraphicsItem) -> None: ... @overload - def installSceneEventFilters(self, filterItems: List[QGraphicsItem]) -> None: ... + def installSceneEventFilters(self, filterItems: list[QGraphicsItem]) -> None: ... def installSceneEventFilters(self, filterItems) -> None: """ @@ -90,7 +90,7 @@ class SchedulerEvent: def removeSceneEventFilters(self, filterItems: QGraphicsItem) -> None: ... @overload - def removeSceneEventFilters(self, filterItems: List[QGraphicsItem]) -> None: ... + def removeSceneEventFilters(self, filterItems: list[QGraphicsItem]) -> None: ... def removeSceneEventFilters(self, filterItems) -> None: """ diff --git a/b_asic/scheduler_gui/scheduler_item.py b/b_asic/scheduler_gui/scheduler_item.py index 13af04a9..fbb84fcd 100644 --- a/b_asic/scheduler_gui/scheduler_item.py +++ b/b_asic/scheduler_gui/scheduler_item.py @@ -8,7 +8,7 @@ maintaining a schedule. from collections import defaultdict from math import floor from pprint import pprint -from typing import Dict, List, Optional, Set, cast +from typing import cast # QGraphics and QPainter imports from qtpy.QtCore import Signal @@ -58,18 +58,18 @@ class SchedulerItem(SchedulerEvent, QGraphicsItemGroup): The parent. Passed to the constructor of QGraphicsItemGroup. """ - _axes: Optional[AxesItem] - _operation_items: Dict[str, OperationItem] + _axes: AxesItem | None + _operation_items: dict[str, OperationItem] _x_axis_indent: float - _event_items: List[QGraphicsItem] - _signal_dict: Dict[OperationItem, Set[SignalItem]] + _event_items: list[QGraphicsItem] + _signal_dict: dict[OperationItem, set[SignalItem]] def __init__( self, schedule: Schedule, warnings: bool = True, show_port_numbers: bool = False, - parent: Optional[QGraphicsItem] = None, + parent: QGraphicsItem | None = None, ): """ Construct a SchedulerItem. @@ -292,15 +292,15 @@ class SchedulerItem(SchedulerEvent, QGraphicsItemGroup): return self._schedule @property - def axes(self) -> Optional[AxesItem]: + def axes(self) -> AxesItem | None: return self._axes @property - def components(self) -> List[OperationItem]: + def components(self) -> list[OperationItem]: return list(component for component in self._operation_items.values()) @property - def event_items(self) -> List[QGraphicsItem]: + def event_items(self) -> list[QGraphicsItem]: """Return a list of objects that receives events.""" return self._event_items diff --git a/b_asic/scheduler_gui/timeline_item.py b/b_asic/scheduler_gui/timeline_item.py index b9296cf3..5fd10d07 100644 --- a/b_asic/scheduler_gui/timeline_item.py +++ b/b_asic/scheduler_gui/timeline_item.py @@ -5,7 +5,7 @@ B-ASIC Scheduler-GUI Timeline Item Module. Contains the scheduler_gui TimelineItem class for drawing and maintain the timeline in a schedule. """ -from typing import List, Optional, overload +from typing import overload # QGraphics and QPainter imports from qtpy.QtCore import QLineF, Qt @@ -20,7 +20,7 @@ class TimelineItem(QGraphicsLineItem): _delta_time_label: QGraphicsTextItem @overload - def __init__(self, line: QLineF, parent: Optional[QGraphicsItem] = None) -> None: + def __init__(self, line: QLineF, parent: QGraphicsItem | None = None) -> None: """ Constructs a TimelineItem out of *line*. @@ -28,7 +28,7 @@ class TimelineItem(QGraphicsLineItem): """ @overload - def __init__(self, parent: Optional[QGraphicsItem] = None) -> None: + def __init__(self, parent: QGraphicsItem | None = None) -> None: """Constructs a TimelineItem. *parent* is passed to QGraphicsLineItem's constructor.""" @@ -40,7 +40,7 @@ class TimelineItem(QGraphicsLineItem): y1: float, x2: float, y2: float, - parent: Optional[QGraphicsItem] = None, + parent: QGraphicsItem | None = None, ) -> None: """ Constructs a TimelineItem from (x1, y1) to (x2, y2). @@ -126,6 +126,6 @@ class TimelineItem(QGraphicsLineItem): self._delta_time_label.setScale(scale) @property - def event_items(self) -> List[QGraphicsItem]: + def event_items(self) -> list[QGraphicsItem]: """Return a list of objects that receives events.""" return [self] diff --git a/b_asic/sfg_generators.py b/b_asic/sfg_generators.py index 2d68215c..ceb602bd 100644 --- a/b_asic/sfg_generators.py +++ b/b_asic/sfg_generators.py @@ -4,7 +4,8 @@ B-ASIC signal flow graph generators. This module contains a number of functions generating SFGs for specific functions. """ -from typing import TYPE_CHECKING, Dict, Optional, Sequence, Union +from collections.abc import Sequence +from typing import TYPE_CHECKING import numpy as np @@ -28,10 +29,10 @@ if TYPE_CHECKING: def wdf_allpass( coefficients: Sequence[float], - name: Optional[str] = None, - latency: Optional[int] = None, - latency_offsets: Optional[Dict[str, int]] = None, - execution_time: Optional[int] = None, + name: str | None = None, + latency: int | None = None, + latency_offsets: dict[str, int] | None = None, + execution_time: int | None = None, ) -> SFG: """ Generate a signal flow graph of a WDF allpass section based on symmetric two-port\ @@ -131,9 +132,9 @@ def wdf_allpass( def direct_form_fir( coefficients: Sequence[complex], - name: Optional[str] = None, - mult_properties: Optional[Union[Dict[str, int], Dict[str, Dict[str, int]]]] = None, - add_properties: Optional[Union[Dict[str, int], Dict[str, Dict[str, int]]]] = None, + name: str | None = None, + mult_properties: dict[str, int] | dict[str, dict[str, int]] | None = None, + add_properties: dict[str, int] | dict[str, dict[str, int]] | None = None, ) -> SFG: r""" Generate a signal flow graph of a direct form FIR filter. @@ -199,9 +200,9 @@ def direct_form_fir( def transposed_direct_form_fir( coefficients: Sequence[complex], - name: Optional[str] = None, - mult_properties: Optional[Union[Dict[str, int], Dict[str, Dict[str, int]]]] = None, - add_properties: Optional[Union[Dict[str, int], Dict[str, Dict[str, int]]]] = None, + name: str | None = None, + mult_properties: dict[str, int] | dict[str, dict[str, int]] | None = None, + add_properties: dict[str, int] | dict[str, dict[str, int]] | None = None, ) -> SFG: r""" Generate a signal flow graph of a transposed direct form FIR filter. @@ -267,9 +268,9 @@ def transposed_direct_form_fir( def direct_form_1_iir( b: Sequence[complex], a: Sequence[complex], - name: Optional[str] = None, - mult_properties: Optional[Union[Dict[str, int], Dict[str, Dict[str, int]]]] = None, - add_properties: Optional[Union[Dict[str, int], Dict[str, Dict[str, int]]]] = None, + name: str | None = None, + mult_properties: dict[str, int] | dict[str, dict[str, int]] | None = None, + add_properties: dict[str, int] | dict[str, dict[str, int]] | None = None, ) -> SFG: """Generates a direct-form IIR filter of type I with coefficients a and b.""" if len(a) < 2 or len(b) < 2: @@ -328,9 +329,9 @@ def direct_form_1_iir( def direct_form_2_iir( b: Sequence[complex], a: Sequence[complex], - name: Optional[str] = None, - mult_properties: Optional[Union[Dict[str, int], Dict[str, Dict[str, int]]]] = None, - add_properties: Optional[Union[Dict[str, int], Dict[str, Dict[str, int]]]] = None, + name: str | None = None, + mult_properties: dict[str, int] | dict[str, dict[str, int]] | None = None, + add_properties: dict[str, int] | dict[str, dict[str, int]] | None = None, ) -> SFG: """Generates a direct-form IIR filter of type II with coefficients a and b.""" if len(a) < 2 or len(b) < 2: diff --git a/b_asic/signal.py b/b_asic/signal.py index d755bfd5..ae4bed44 100644 --- a/b_asic/signal.py +++ b/b_asic/signal.py @@ -4,7 +4,8 @@ B-ASIC Signal Module. Contains the class for representing the connections between operations. """ -from typing import TYPE_CHECKING, Iterable, Optional, Union +from collections.abc import Iterable +from typing import TYPE_CHECKING, Optional, Union from b_asic.graph_component import AbstractGraphComponent, GraphComponent from b_asic.types import Name, TypeName @@ -44,9 +45,9 @@ class Signal(AbstractGraphComponent): def __init__( self, - source: Optional[Union["OutputPort", "Signal", "Operation"]] = None, - destination: Optional[Union["InputPort", "Signal", "Operation"]] = None, - bits: Optional[int] = None, + source: Union["OutputPort", "Signal", "Operation"] | None = None, + destination: Union["InputPort", "Signal", "Operation"] | None = None, + bits: int | None = None, name: Name = Name(""), ): """Construct a Signal.""" @@ -186,7 +187,7 @@ class Signal(AbstractGraphComponent): return self._source is None or self._destination is None @property - def bits(self) -> Optional[int]: + def bits(self) -> int | None: """ Get the number of bits that this operation using this signal as an input should quantize received values to. @@ -195,7 +196,7 @@ class Signal(AbstractGraphComponent): return self.param("bits") @bits.setter - def bits(self, bits: Optional[int]) -> None: + def bits(self, bits: int | None) -> None: """ Set the number of bits that operations using this signal as an input should quantize received values to. diff --git a/b_asic/signal_flow_graph.py b/b_asic/signal_flow_graph.py index 903ab2af..abc380ec 100644 --- a/b_asic/signal_flow_graph.py +++ b/b_asic/signal_flow_graph.py @@ -8,20 +8,14 @@ import itertools import re import warnings from collections import defaultdict, deque +from collections.abc import Iterable, MutableSet, Sequence from io import StringIO from numbers import Number from queue import PriorityQueue from typing import ( DefaultDict, Deque, - Dict, - Iterable, - List, - MutableSet, Optional, - Sequence, - Set, - Tuple, Union, cast, ) @@ -42,7 +36,7 @@ from b_asic.signal import Signal from b_asic.special_operations import Delay, Input, Output from b_asic.types import GraphID, GraphIDNumber, Name, Num, TypeName -DelayQueue = List[Tuple[str, ResultKey, OutputPort]] +DelayQueue = list[tuple[str, ResultKey, OutputPort]] _OPERATION_SHAPE: DefaultDict[TypeName, str] = defaultdict(lambda: "ellipse") @@ -115,29 +109,29 @@ class SFG(AbstractOperation): input_sources : """ - _components_by_id: Dict[GraphID, GraphComponent] - _components_by_name: DefaultDict[Name, List[GraphComponent]] - _components_dfs_order: List[GraphComponent] - _operations_dfs_order: List[Operation] - _operations_topological_order: List[Operation] + _components_by_id: dict[GraphID, GraphComponent] + _components_by_name: DefaultDict[Name, list[GraphComponent]] + _components_dfs_order: list[GraphComponent] + _operations_dfs_order: list[Operation] + _operations_topological_order: list[Operation] _graph_id_generator: GraphIDGenerator - _input_operations: List[Input] - _output_operations: List[Output] - _original_components_to_new: Dict[GraphComponent, GraphComponent] - _original_input_signals_to_indices: Dict[Signal, int] - _original_output_signals_to_indices: Dict[Signal, int] - _precedence_list: Optional[List[List[OutputPort]]] - _used_ids: Set[GraphID] = set() + _input_operations: list[Input] + _output_operations: list[Output] + _original_components_to_new: dict[GraphComponent, GraphComponent] + _original_input_signals_to_indices: dict[Signal, int] + _original_output_signals_to_indices: dict[Signal, int] + _precedence_list: list[list[OutputPort]] | None + _used_ids: set[GraphID] = set() def __init__( self, - inputs: Optional[Sequence[Input]] = None, - outputs: Optional[Sequence[Output]] = None, - input_signals: Optional[Sequence[Signal]] = None, - output_signals: Optional[Sequence[Signal]] = None, + inputs: Sequence[Input] | None = None, + outputs: Sequence[Output] | None = None, + input_signals: Sequence[Signal] | None = None, + output_signals: Sequence[Signal] | None = None, id_number_offset: GraphIDNumber = GraphIDNumber(0), name: Name = Name(""), - input_sources: Optional[Sequence[Optional[SignalSourceProvider]]] = None, + input_sources: Sequence[SignalSourceProvider | None] | None = None, ): input_signal_count = 0 if input_signals is None else len(input_signals) input_operation_count = 0 if inputs is None else len(inputs) @@ -323,7 +317,7 @@ class SFG(AbstractOperation): return string_io.getvalue() def __call__( - self, *src: Optional[SignalSourceProvider], name: Name = Name("") + self, *src: SignalSourceProvider | None, name: Name = Name("") ) -> "SFG": """ Return a new independent SFG instance that is identical to this SFG @@ -351,10 +345,10 @@ class SFG(AbstractOperation): self, index: int, input_values: Sequence[Num], - results: Optional[MutableResultMap] = None, - delays: Optional[MutableDelayMap] = None, + results: MutableResultMap | None = None, + delays: MutableDelayMap | None = None, prefix: str = "", - bits_override: Optional[int] = None, + bits_override: int | None = None, quantize: bool = True, ) -> Number: # doc-string inherited @@ -506,7 +500,7 @@ class SFG(AbstractOperation): } output_op = self._output_operations[output_index] queue: Deque[Operation] = deque([output_op]) - visited: Set[Operation] = {output_op} + visited: set[Operation] = {output_op} while queue: op = queue.popleft() if isinstance(op, Input): @@ -542,12 +536,12 @@ class SFG(AbstractOperation): return self._graph_id_generator.id_number_offset @property - def components(self) -> List[GraphComponent]: + def components(self) -> list[GraphComponent]: """Get all components of this graph in depth-first order.""" return self._components_dfs_order @property - def operations(self) -> List[Operation]: + def operations(self) -> list[Operation]: """Get all operations of this graph in depth-first order.""" return list(self._operations_dfs_order) @@ -569,7 +563,7 @@ class SFG(AbstractOperation): ] return components - def find_by_id(self, graph_id: GraphID) -> Optional[GraphComponent]: + def find_by_id(self, graph_id: GraphID) -> GraphComponent | None: """ Find the graph component with the specified ID. @@ -762,7 +756,7 @@ class SFG(AbstractOperation): self, input_comp_id: GraphID, new_operation: Operation, - port: Optional[int] = None, + port: int | None = None, ) -> Optional["SFG"]: """ Insert an operation in the SFG before a given source operation. @@ -1093,7 +1087,7 @@ class SFG(AbstractOperation): remaining_inports_per_operation = {op: op.input_count for op in self.operations} # Maps number of input counts to a queue of seen objects with such a size. - seen_with_inputs_dict: Dict[int, Deque] = defaultdict(deque) + seen_with_inputs_dict: dict[int, Deque] = defaultdict(deque) seen = set() top_order = [] @@ -1212,7 +1206,7 @@ class SFG(AbstractOperation): cast(Operation, op).execution_time = execution_time def set_latency_offsets_of_type( - self, type_name: TypeName, latency_offsets: Dict[str, int] + self, type_name: TypeName, latency_offsets: dict[str, int] ) -> None: """ Set the latency offsets of all operations with the given type name. @@ -1229,8 +1223,8 @@ class SFG(AbstractOperation): cast(Operation, op).set_latency_offsets(latency_offsets) def _traverse_for_precedence_list( - self, first_iter_ports: List[OutputPort] - ) -> List[List[OutputPort]]: + self, first_iter_ports: list[OutputPort] + ) -> list[list[OutputPort]]: # Find dependencies of output ports and input ports. remaining_inports_per_operation = {op: op.input_count for op in self.operations} @@ -1474,7 +1468,7 @@ class SFG(AbstractOperation): results: MutableResultMap, delays: MutableDelayMap, prefix: str, - bits_override: Optional[int], + bits_override: int | None, quantize: bool, deferred_delays: DelayQueue, ) -> Num: @@ -1519,7 +1513,7 @@ class SFG(AbstractOperation): results: MutableResultMap, delays: MutableDelayMap, prefix: str, - bits_override: Optional[int], + bits_override: int | None, quantize: bool, deferred_delays: DelayQueue, ) -> Num: @@ -1550,7 +1544,7 @@ class SFG(AbstractOperation): def sfg_digraph( self, show_signal_id: bool = False, - engine: Optional[str] = None, + engine: str | None = None, branch_node: bool = True, port_numbering: bool = True, splines: str = "spline", @@ -1661,9 +1655,9 @@ class SFG(AbstractOperation): def show( self, - fmt: Optional[str] = None, + fmt: str | None = None, show_signal_id: bool = False, - engine: Optional[str] = None, + engine: str | None = None, branch_node: bool = True, port_numbering: bool = True, splines: str = "spline", @@ -1755,7 +1749,7 @@ class SFG(AbstractOperation): for input in inputs_used: input_op = self._input_operations[input] queue: Deque[Operation] = deque([input_op]) - visited: Set[Operation] = {input_op} + visited: set[Operation] = {input_op} dict_of_sfg = {} while queue: op = queue.popleft() @@ -1839,7 +1833,7 @@ class SFG(AbstractOperation): for output in output_index_used: output_op = self._output_operations[output] queue: Deque[Operation] = deque([output_op]) - visited: Set[Operation] = {output_op} + visited: set[Operation] = {output_op} while queue: op = queue.popleft() for input_port in op.inputs: @@ -1855,7 +1849,7 @@ class SFG(AbstractOperation): for input in input_index_used: input_op = self._input_operations[input] queue: Deque[Operation] = deque([input_op]) - visited: Set[Operation] = {input_op} + visited: set[Operation] = {input_op} while queue: op = queue.popleft() if isinstance(op, Output): @@ -2020,7 +2014,7 @@ class SFG(AbstractOperation): paths.append(newpath) return paths - def edit(self) -> Dict[str, "SFG"]: + def edit(self) -> dict[str, "SFG"]: """Edit SFG in GUI.""" from b_asic.GUI.main_window import start_editor @@ -2141,13 +2135,13 @@ class SFG(AbstractOperation): def is_constant(self) -> bool: return all(output.is_constant for output in self._output_operations) - def get_used_type_names(self) -> List[TypeName]: + def get_used_type_names(self) -> list[TypeName]: """Get a list of all TypeNames used in the SFG.""" ret = list({op.type_name() for op in self.operations}) ret.sort() return ret - def get_used_graph_ids(self) -> Set[GraphID]: + def get_used_graph_ids(self) -> set[GraphID]: """Get a list of all GraphID:s used in the SFG.""" ret = set({op.graph_id for op in self.operations}) sorted(ret) diff --git a/b_asic/signal_generator.py b/b_asic/signal_generator.py index 45706d81..21381b48 100644 --- a/b_asic/signal_generator.py +++ b/b_asic/signal_generator.py @@ -11,9 +11,9 @@ This is handled by a number of private generator classes. Check out the source c if you want more information. """ +from collections.abc import Sequence from math import pi, sin from numbers import Number -from typing import List, Optional, Sequence, Union import numpy as np @@ -195,12 +195,12 @@ class FromFile(SignalGenerator): __slots__ = ("_data", "_len", "_path") _path: str - _data: List[Num] + _data: list[Num] _len: int def __init__(self, path: str) -> None: self._path = path - data: List[Num] = np.loadtxt(path, dtype=complex).tolist() + data: list[Num] = np.loadtxt(path, dtype=complex).tolist() self._data = data self._len = len(data) @@ -264,12 +264,12 @@ class Gaussian(SignalGenerator): __slots__ = ("_rng", "_seed", "_loc", "_scale") - _seed: Optional[int] + _seed: int | None _loc: float _scale: float def __init__( - self, seed: Optional[int] = None, loc: float = 0.0, scale: float = 1.0 + self, seed: int | None = None, loc: float = 0.0, scale: float = 1.0 ) -> None: self._rng = np.random.default_rng(seed) self._seed = seed @@ -309,12 +309,12 @@ class Uniform(SignalGenerator): __slots__ = ("_rng", "_seed", "_low", "_high") - _seed: Optional[int] + _seed: int | None _low: float _high: float def __init__( - self, seed: Optional[int] = None, low: float = -1.0, high: float = 1.0 + self, seed: int | None = None, low: float = -1.0, high: float = 1.0 ) -> None: self._rng = np.random.default_rng(seed) self._seed = seed @@ -495,13 +495,13 @@ class Upsample(SignalGenerator): __slots__ = ("_generator", "_factor", "_phase") - _generator: Union[SignalGenerator, Sequence[complex]] + _generator: SignalGenerator | Sequence[complex] _factor: int _phase: int def __init__( self, - data: Union[SignalGenerator, Sequence[complex]], + data: SignalGenerator | Sequence[complex], factor: int, phase: int = 0, ) -> None: @@ -540,13 +540,13 @@ class Downsample(SignalGenerator): __slots__ = ("_generator", "_factor", "_phase") - _generator: Union[SignalGenerator, Sequence[complex]] + _generator: SignalGenerator | Sequence[complex] _factor: int _phase: int def __init__( self, - data: Union[SignalGenerator, Sequence[complex]], + data: SignalGenerator | Sequence[complex], factor: int, phase: int = 0, ) -> None: diff --git a/b_asic/simulation.py b/b_asic/simulation.py index 31f25910..4b300433 100644 --- a/b_asic/simulation.py +++ b/b_asic/simulation.py @@ -5,15 +5,9 @@ Contains a class for simulating the result of an SFG given a set of input values """ from collections import defaultdict +from collections.abc import Callable, Mapping, MutableMapping, MutableSequence, Sequence from numbers import Number from typing import ( - Callable, - List, - Mapping, - MutableMapping, - MutableSequence, - Optional, - Sequence, Union, ) @@ -50,13 +44,13 @@ class Simulation: _results: MutableResultArrayMap _delays: MutableDelayMap _iteration: int - _input_functions: List[InputFunction] - _input_length: Optional[int] + _input_functions: list[InputFunction] + _input_length: int | None def __init__( self, sfg: SFG, - input_providers: Optional[Sequence[Optional[InputProvider]]] = None, + input_providers: Sequence[InputProvider | None] | None = None, ): """Construct a Simulation of an SFG.""" if not isinstance(sfg, SFG): @@ -103,7 +97,7 @@ class Simulation: ) self._input_functions[index] = lambda n: input_provider[n] - def set_inputs(self, input_providers: Sequence[Optional[InputProvider]]) -> None: + def set_inputs(self, input_providers: Sequence[InputProvider | None]) -> None: """ Set the input functions used to get values for the inputs to the internal SFG. @@ -123,7 +117,7 @@ class Simulation: def step( self, save_results: bool = True, - bits_override: Optional[int] = None, + bits_override: int | None = None, quantize: bool = True, ) -> Sequence[Num]: """ @@ -141,7 +135,7 @@ class Simulation: self, iteration: int, save_results: bool = True, - bits_override: Optional[int] = None, + bits_override: int | None = None, quantize: bool = True, ) -> Sequence[Num]: """ @@ -184,7 +178,7 @@ class Simulation: self, iterations: int, save_results: bool = True, - bits_override: Optional[int] = None, + bits_override: int | None = None, quantize: bool = True, ) -> Sequence[Num]: """ @@ -207,7 +201,7 @@ class Simulation: def run( self, save_results: bool = True, - bits_override: Optional[int] = None, + bits_override: int | None = None, quantize: bool = True, ) -> Sequence[Num]: """ diff --git a/b_asic/special_operations.py b/b_asic/special_operations.py index f6d0e84c..dbffb2af 100644 --- a/b_asic/special_operations.py +++ b/b_asic/special_operations.py @@ -5,7 +5,7 @@ Contains operations with special purposes that may be treated differently from normal operations in an SFG. """ -from typing import Optional, Sequence, Tuple +from collections.abc import Sequence from b_asic.operation import ( AbstractOperation, @@ -67,7 +67,7 @@ class Input(AbstractOperation): def get_plot_coordinates( self, - ) -> Tuple[Tuple[Tuple[float, float], ...], Tuple[Tuple[float, float], ...]]: + ) -> tuple[tuple[tuple[float, float], ...], tuple[tuple[float, float], ...]]: # Doc-string inherited return ( ( @@ -88,11 +88,11 @@ class Input(AbstractOperation): ), ) - def get_input_coordinates(self) -> Tuple[Tuple[float, float], ...]: + def get_input_coordinates(self) -> tuple[tuple[float, float], ...]: # doc-string inherited return tuple() - def get_output_coordinates(self) -> Tuple[Tuple[float, float], ...]: + def get_output_coordinates(self) -> tuple[tuple[float, float], ...]: # doc-string inherited return ((0, 0.5),) @@ -118,7 +118,7 @@ class Output(AbstractOperation): def __init__( self, - src0: Optional[SignalSourceProvider] = None, + src0: SignalSourceProvider | None = None, name: Name = Name(""), ): """Construct an Output operation.""" @@ -140,18 +140,18 @@ class Output(AbstractOperation): def get_plot_coordinates( self, - ) -> Tuple[Tuple[Tuple[float, float], ...], Tuple[Tuple[float, float], ...]]: + ) -> tuple[tuple[tuple[float, float], ...], tuple[tuple[float, float], ...]]: # Doc-string inherited return ( ((0, 0), (0, 1), (0.25, 1), (0.5, 0.5), (0.25, 0), (0, 0)), ((0, 0), (0, 1), (0.25, 1), (0.5, 0.5), (0.25, 0), (0, 0)), ) - def get_input_coordinates(self) -> Tuple[Tuple[float, float], ...]: + def get_input_coordinates(self) -> tuple[tuple[float, float], ...]: # doc-string inherited return ((0, 0.5),) - def get_output_coordinates(self) -> Tuple[Tuple[float, float], ...]: + def get_output_coordinates(self) -> tuple[tuple[float, float], ...]: # doc-string inherited return tuple() @@ -181,7 +181,7 @@ class Delay(AbstractOperation): def __init__( self, - src0: Optional[SignalSourceProvider] = None, + src0: SignalSourceProvider | None = None, initial_value: Num = 0, name: Name = Name(""), ): @@ -203,8 +203,8 @@ class Delay(AbstractOperation): return self.param("initial_value") def current_output( - self, index: int, delays: Optional[DelayMap] = None, prefix: str = "" - ) -> Optional[Num]: + self, index: int, delays: DelayMap | None = None, prefix: str = "" + ) -> Num | None: if delays is not None: return delays.get(self.key(index, prefix), self.param("initial_value")) return self.param("initial_value") @@ -213,10 +213,10 @@ class Delay(AbstractOperation): self, index: int, input_values: Sequence[Num], - results: Optional[MutableResultMap] = None, - delays: Optional[MutableDelayMap] = None, + results: MutableResultMap | None = None, + delays: MutableDelayMap | None = None, prefix: str = "", - bits_override: Optional[int] = None, + bits_override: int | None = None, quantize: bool = True, ) -> Num: if index != 0: diff --git a/b_asic/utils.py b/b_asic/utils.py index c128a32b..654d86a9 100644 --- a/b_asic/utils.py +++ b/b_asic/utils.py @@ -1,11 +1,11 @@ """B-ASIC Utilities.""" -from typing import List, Sequence +from collections.abc import Sequence from b_asic.types import Num -def interleave(*args) -> List[Num]: +def interleave(*args) -> list[Num]: """ Interleave a number of arrays. @@ -29,7 +29,7 @@ def interleave(*args) -> List[Num]: return [val for tup in zip(*args) for val in tup] -def downsample(a: Sequence[Num], factor: int, phase: int = 0) -> List[Num]: +def downsample(a: Sequence[Num], factor: int, phase: int = 0) -> list[Num]: """ Downsample a sequence with an integer factor. @@ -57,7 +57,7 @@ def downsample(a: Sequence[Num], factor: int, phase: int = 0) -> List[Num]: return a[phase::factor] -def upsample(a: Sequence[Num], factor: int, phase: int = 0) -> List[Num]: +def upsample(a: Sequence[Num], factor: int, phase: int = 0) -> list[Num]: """ Upsample a sequence with an integer factor. @@ -93,7 +93,7 @@ def upsample(a: Sequence[Num], factor: int, phase: int = 0) -> List[Num]: return interleave(*args) -def decompose(a: Sequence[Num], factor: int) -> List[List[Num]]: +def decompose(a: Sequence[Num], factor: int) -> list[list[Num]]: """ Polyphase decompose signal *a* into *factor* parts. -- GitLab