diff --git a/b_asic/GUI/arrow.py b/b_asic/GUI/arrow.py index d2bdfe0af04a3e5f0d7ab63ec21528687ca26c4e..8ead6587611ab9e06e07dac38e33c1614ae92c83 100644 --- a/b_asic/GUI/arrow.py +++ b/b_asic/GUI/arrow.py @@ -78,7 +78,8 @@ class Arrow(QGraphicsPathItem): def moveLine(self): """ - Draw a line connecting ``self.source`` with ``self.destination``. Used as callback when moving operations. + Draw a line connecting ``self.source`` with ``self.destination``. + Used as callback when moving operations. """ ORTHOGONAL = True OFFSET = 2 * PORTWIDTH diff --git a/b_asic/GUI/drag_button.py b/b_asic/GUI/drag_button.py index d2ee6015b713f37d73c56b910e365209e445f101..432477eb42c7ff1dcb6984ba996f9b1a9253fe99 100644 --- a/b_asic/GUI/drag_button.py +++ b/b_asic/GUI/drag_button.py @@ -162,7 +162,8 @@ class DragButton(QPushButton): path_to_image = os.path.join( os.path.dirname(__file__), "operation_icons", - f"{self.operation.type_name().lower()}{'_grey.png' if self.pressed else '.png'}", + f"{self.operation.type_name().lower()}" + f"{'_grey.png' if self.pressed else '.png'}", ) self.setIcon(QIcon(path_to_image)) self.setIconSize(QSize(MINBUTTONSIZE, MINBUTTONSIZE)) diff --git a/b_asic/GUI/main_window.py b/b_asic/GUI/main_window.py index 942bcd5b2eab169464158a91c828ebcd2da4fdec..16c807085329315a7ecaa98ff622419e535fae56 100644 --- a/b_asic/GUI/main_window.py +++ b/b_asic/GUI/main_window.py @@ -519,8 +519,7 @@ class MainWindow(QMainWindow): attr_button.setIconSize(QSize(MINBUTTONSIZE, MINBUTTONSIZE)) attr_button.setToolTip("No SFG") attr_button.setStyleSheet( - """ QToolTip { background-color: white; - color: black }""" + "QToolTip { background-color: white; color: black }" ) attr_button.setParent(None) attr_button_scene = self.scene.addWidget(attr_button) @@ -545,7 +544,7 @@ class MainWindow(QMainWindow): ) def _create_operation_item(self, item): - self.logger.info("Creating operation of type: " + str(item.text())) + self.logger.info("Creating operation of type: %s" % str(item.text())) try: attr_oper = self._operations_from_name[item.text()]() self.create_operation(attr_oper) @@ -601,7 +600,7 @@ class MainWindow(QMainWindow): self.logger.warning("Cannot connect to the same port") continue - if type(source.port) == type(destination.port): + if isinstance(source.port, type(destination.port)): self.logger.warning( "Cannot connect port of type: %s to port of type: %s." % ( @@ -623,8 +622,11 @@ class MainWindow(QMainWindow): if signal.destination is destination.port ) self.logger.info( - f"Connecting: {source.operation.operation.type_name()} " - f"-> {destination.operation.operation.type_name()}." + "Connecting: %s -> %s." + % ( + source.operation.operation.type_name(), + destination.operation.operation.type_name(), + ) ) try: line = Arrow(source, destination, self, signal=next(signal_exists)) @@ -657,7 +659,7 @@ class MainWindow(QMainWindow): def _simulate_sfg(self): for sfg, properties in self.dialog.properties.items(): - self.logger.info(f"Simulating SFG with name: " + str(sfg.name)) + self.logger.info("Simulating SFG with name: %s" % str(sfg.name)) simulation = FastSimulation( sfg, input_providers=properties["input_values"] ) diff --git a/b_asic/graph_component.py b/b_asic/graph_component.py index 1e76ce02938edcbc8c1d67d61795c1fe92c6c789..86018c8d85ca52afca764e6e9b604ce7fb3ae4f5 100644 --- a/b_asic/graph_component.py +++ b/b_asic/graph_component.py @@ -16,7 +16,8 @@ GraphIDNumber = NewType("GraphIDNumber", int) class GraphComponent(ABC): - """Graph component interface. + """ + Graph component interface. Each graph component has a type name, a name and a unique ID. Graph components also contain parameters and provide an interface for @@ -54,9 +55,12 @@ class GraphComponent(ABC): @graph_id.setter @abstractmethod def graph_id(self, graph_id: GraphID) -> None: - """Set the graph id of this graph component to the given id. - Note that this id will be ignored if this component is used to create a new graph, - and that a new local id will be generated for it instead.""" + """ + Set the graph id of this graph component to the given id. + + Note that this id will be ignored if this component is used to create a new + graph, and that a new local id will be generated for it instead. + """ raise NotImplementedError @property @@ -84,7 +88,8 @@ class GraphComponent(ABC): @abstractmethod def copy_component(self, *args, **kwargs) -> "GraphComponent": """ - Get a new instance of this graph component type with the same name, id and parameters. + Get a new instance of this graph component type with the same name, id and + parameters. """ raise NotImplementedError @@ -96,14 +101,17 @@ class GraphComponent(ABC): @abstractmethod def traverse(self) -> Generator["GraphComponent", None, None]: - """Get a generator that recursively iterates through all components that are connected to this operation, + """ + Get a generator that recursively iterates through all components that + are connected to this operation, as well as the ones that they are connected to. """ raise NotImplementedError class AbstractGraphComponent(GraphComponent): - """Generic abstract graph component base class. + """ + Generic abstract graph component base class. Concrete graph components should normally derive from this to get the default behavior. diff --git a/b_asic/operation.py b/b_asic/operation.py index 23c5cd99468526c02b649b180bc02a32ebe95d78..78f70ca2ddc39ede2c4e2fc0d794b95565212445 100644 --- a/b_asic/operation.py +++ b/b_asic/operation.py @@ -86,8 +86,8 @@ class Operation(GraphComponent, SignalSourceProvider): self, src: Union[SignalSourceProvider, Number] ) -> "Subtraction": """ - Overloads the subtraction operator to make it return a new Subtraction operation - object that is connected to the self and other objects. + Overloads the subtraction operator to make it return a new Subtraction + operation object that is connected to the self and other objects. """ raise NotImplementedError @@ -96,8 +96,8 @@ class Operation(GraphComponent, SignalSourceProvider): self, src: Union[SignalSourceProvider, Number] ) -> "Subtraction": """ - Overloads the subtraction operator to make it return a new Subtraction operation - object that is connected to the self and other objects. + Overloads the subtraction operator to make it return a new Subtraction + operation object that is connected to the self and other objects. """ raise NotImplementedError @@ -106,9 +106,11 @@ class Operation(GraphComponent, SignalSourceProvider): self, src: Union[SignalSourceProvider, Number] ) -> Union["Multiplication", "ConstantMultiplication"]: """ - Overloads the multiplication operator to make it return a new Multiplication operation - object that is connected to the self and other objects. If *src* is a number, then - returns a ConstantMultiplication operation object instead. + Overloads the multiplication operator to make it return a new Multiplication + operation object that is connected to the self and other objects. + + If *src* is a number, then returns a ConstantMultiplication operation object + instead. """ raise NotImplementedError @@ -117,9 +119,11 @@ class Operation(GraphComponent, SignalSourceProvider): self, src: Union[SignalSourceProvider, Number] ) -> Union["Multiplication", "ConstantMultiplication"]: """ - Overloads the multiplication operator to make it return a new Multiplication operation - object that is connected to the self and other objects. If *src* is a number, then - returns a ConstantMultiplication operation object instead. + Overloads the multiplication operator to make it return a new Multiplication + operation object that is connected to the self and other objects. + + If *src* is a number, then returns a ConstantMultiplication operation object + instead. """ raise NotImplementedError @@ -218,8 +222,10 @@ class Operation(GraphComponent, SignalSourceProvider): ) -> Optional[Number]: """ Get the current output at the given index of this operation, if available. + The *delays* parameter will be used for lookup. - The *prefix* parameter will be used as a prefix for the key string when looking for delays. + The *prefix* parameter will be used as a prefix for the key string when looking + for delays. See also ======== @@ -240,7 +246,8 @@ class Operation(GraphComponent, SignalSourceProvider): truncate: bool = True, ) -> Number: """ - Evaluate the output at the given index of this operation with the given input values. + Evaluate the output at the given index of this operation with the given input + values. Parameters ---------- @@ -261,7 +268,8 @@ class Operation(GraphComponent, SignalSourceProvider): which ignores the word length specified by the input signal. truncate : bool, default: True Specifies whether input truncation should be enabled in the first - place. If set to False, input values will be used directly without any bit truncation. + place. If set to False, input values will be used directly without any + bit truncation. See also ======== @@ -303,7 +311,9 @@ class Operation(GraphComponent, SignalSourceProvider): def split(self) -> Iterable["Operation"]: """ Split the operation into multiple operations. - If splitting is not possible, this may return a list containing only the operation itself. + + If splitting is not possible, this may return a list containing only the + operation itself. """ raise NotImplementedError @@ -311,7 +321,9 @@ class Operation(GraphComponent, SignalSourceProvider): def to_sfg(self) -> "SFG": """ Convert the operation into its corresponding SFG. - If the operation is composed by multiple operations, the operation will be split. + + If the operation is composed by multiple operations, the operation will be + split. """ raise NotImplementedError @@ -326,7 +338,8 @@ class Operation(GraphComponent, SignalSourceProvider): @abstractmethod def truncate_input(self, index: int, value: Number, bits: int) -> Number: """ - Truncate the value to be used as input at the given index to a certain bit length. + Truncate the value to be used as input at the given index to a certain bit + length. """ raise NotImplementedError @@ -350,18 +363,24 @@ class Operation(GraphComponent, SignalSourceProvider): @abstractmethod def set_latency(self, latency: int) -> None: """ - Sets the latency of the operation to the specified integer value by setting the - latency-offsets of operations input ports to 0 and the latency-offsets of the operations - output ports to the specified value. The latency cannot be a negative integers. + Sets the latency of the operation to the specified integer value. + + This is done by setting the latency-offsets of operations input ports to 0 + and the latency-offsets of the operations output ports to the specified value. + + The latency cannot be a negative integer. """ raise NotImplementedError @abstractmethod def set_latency_offsets(self, latency_offsets: Dict[str, int]) -> None: """ - Sets the latency-offsets for the operations ports specified in the latency_offsets dictionary. - The latency offsets dictionary should be {'in0': 2, 'out1': 4} if you want to set the latency offset - for the inport port with index 0 to 2, and the latency offset of the output port with index 1 to 4. + Sets the latency-offsets for the operations ports specified in the + latency_offsets dictionary. + + The latency offsets dictionary should be {'in0': 2, 'out1': 4} if you want to + set the latency offset for the inport port with index 0 to 2, and the latency + offset of the output port with index 1 to 4. """ raise NotImplementedError @@ -369,8 +388,10 @@ class Operation(GraphComponent, SignalSourceProvider): @abstractmethod def execution_time(self) -> Optional[int]: """ - Get the execution time of the operation, which is the time it takes before the - processing element implementing the operation can be reused for starting another operation. + Get the execution time of the operation. + + This is the time it takes before the processing element implementing the + operation can be reused for starting another operation. """ raise NotImplementedError diff --git a/b_asic/save_load_structure.py b/b_asic/save_load_structure.py index b3970dc5f4822d25fbaa772e7fac570138a337dd..5f26b43ce5951da614babaf0fc1952de1d4f6d7b 100644 --- a/b_asic/save_load_structure.py +++ b/b_asic/save_load_structure.py @@ -98,8 +98,10 @@ def sfg_to_python( destination = cast(InputPort, signal.destination) dest_op = destination.operation connection = ( - f"\nSignal(source={op.graph_id}.output({op.outputs.index(signal.source)})," - f" destination={dest_op.graph_id}.input({dest_op.inputs.index(destination)}))" + f"\nSignal(source={op.graph_id}." + f"output({op.outputs.index(signal.source)})," + f" destination={dest_op.graph_id}." + f"input({dest_op.inputs.index(destination)}))" ) if connection in connections: continue diff --git a/b_asic/schedule.py b/b_asic/schedule.py index 280615606b31b3b98ae42d2380e5cc4efc394807..c64831e5fdef76625fa62ca0a74d86cfef64b46c 100644 --- a/b_asic/schedule.py +++ b/b_asic/schedule.py @@ -50,7 +50,8 @@ class Schedule: sfg : SFG The signal flow graph to schedule. schedule_time : int, optional - The schedule time. If not provided, it will be determined by the scheduling algorithm. + The schedule time. If not provided, it will be determined by the scheduling + algorithm. cyclic : bool, default: False If the schedule is cyclic. scheduling_algorithm : {'ASAP'}, optional @@ -128,7 +129,8 @@ class Schedule: Returns ------- - The number of time steps the operation with *graph_id* can ba moved forward in time. + The number of time steps the operation with *graph_id* can ba moved + forward in time. See also -------- @@ -179,10 +181,11 @@ class Schedule: Returns ------- - The number of time steps the operation with *graph_id* can ba moved backward in time. + The number of time steps the operation with *graph_id* can ba moved + backward in time. - .. note:: The backward slack is positive, but a call to :func:`move_operation` should be negative to move - the operation backward. + .. note:: The backward slack is positive, but a call to :func:`move_operation` + should be negative to move the operation backward. See also -------- @@ -224,8 +227,8 @@ class Schedule: def slacks(self, graph_id: GraphID) -> Tuple[int, int]: """ - Return the backward and forward slacks of operation *graph_id*. That is, how much - the operation can be moved backward and forward in time. + Return the backward and forward slacks of operation *graph_id*. That is, how + much the operation can be moved backward and forward in time. Parameters ---------- @@ -236,8 +239,8 @@ class Schedule: ------- A tuple as ``(backward_slack, forward_slack)``. - .. note:: The backward slack is positive, but a call to :func:`move_operation` should be negative to move - the operation backward. + .. note:: The backward slack is positive, but a call to :func:`move_operation` + should be negative to move the operation backward. See also -------- @@ -351,6 +354,10 @@ class Schedule: factor : int The time resolution decrement. + + See also + ======== + get_possible_time_resolution_decrements """ possible_values = self.get_possible_time_resolution_decrements() if factor not in possible_values: @@ -807,7 +814,8 @@ class Schedule: ax : matplotlib.axes.Axes The :class:`matplotlib.axes.Axes` to plot in. operation_gap : float, optional - The vertical distance between operations in the schedule. The height of the operation is always 1. + The vertical distance between operations in the schedule. The height of + the operation is always 1. """ def plot(self, operation_gap: float = None) -> None: @@ -817,7 +825,8 @@ class Schedule: Parameters ---------- operation_gap : float, optional - The vertical distance between operations in the schedule. The height of the operation is always 1. + The vertical distance between operations in the schedule. The height of + the operation is always 1. """ self._get_figure(operation_gap=operation_gap).show() @@ -828,7 +837,8 @@ class Schedule: Parameters ---------- operation_gap : float, optional - The vertical distance between operations in the schedule. The height of the operation is always 1. + The vertical distance between operations in the schedule. The height of + the operation is always 1. Returns ------- @@ -840,7 +850,8 @@ class Schedule: def _repr_svg_(self): """ - Generate an SVG of the schedule. This is automatically displayed in e.g. Jupyter Qt console. + Generate an SVG of the schedule. This is automatically displayed in e.g. + Jupyter Qt console. """ fig, ax = plt.subplots() self._plot_schedule(ax) diff --git a/b_asic/sfg_generator.py b/b_asic/sfg_generator.py index faa6e3b1b2cadc3399076120e13d2ff43568f106..a97f902649d396984702d4424cc5d8dc61ebc7d1 100644 --- a/b_asic/sfg_generator.py +++ b/b_asic/sfg_generator.py @@ -24,7 +24,8 @@ def wdf_allpass( execution_time: Optional[int] = None, ) -> SFG: """ - Generate a signal flow graph of a WDF allpass section based on symmetric two-port adaptors. + Generate a signal flow graph of a WDF allpass section based on symmetric two-port + adaptors. Parameters ---------- diff --git a/b_asic/signal_flow_graph.py b/b_asic/signal_flow_graph.py index d111de970fe77454115b6879de4677291851b749..c4a6545d9b385660218c4134816626e8fac1e563 100644 --- a/b_asic/signal_flow_graph.py +++ b/b_asic/signal_flow_graph.py @@ -474,14 +474,16 @@ class SFG(AbstractOperation): @property def input_operations(self) -> Sequence[Operation]: """ - Get the internal input operations in the same order as their respective input ports. + Get the internal input operations in the same order as their respective input + ports. """ return self._input_operations @property def output_operations(self) -> Sequence[Operation]: """ - Get the internal output operations in the same order as their respective output ports. + Get the internal output operations in the same order as their respective output + ports. """ return self._output_operations @@ -502,7 +504,8 @@ class SFG(AbstractOperation): Returns ------- - A list of inputs that are required to compute the output with the given *output_index*. + A list of inputs that are required to compute the output with the given + *output_index*. """ if output_index < 0 or output_index >= self.output_count: raise IndexError( @@ -678,6 +681,7 @@ class SFG(AbstractOperation): ) -> Optional["SFG"]: """ Insert an operation in the SFG after a given source operation. + The source operation output count must match the input count of the operation as well as the output. Then return a new deepcopy of the sfg with the inserted component. @@ -721,9 +725,12 @@ class SFG(AbstractOperation): def remove_operation(self, operation_id: GraphID) -> Union["SFG", None]: """ - Returns a version of the SFG where the operation with the specified GraphID removed. - The operation has to have the same amount of input- and output ports or a ValueError will - be raised. If no operation with the entered operation_id is found then returns None and does nothing. + Returns a version of the SFG where the operation with the specified GraphID + removed. + + The operation must have the same amount of input- and output ports or a + ValueError is raised. If no operation with the entered operation_id is found + then returns None and does nothing. Parameters ========== @@ -816,7 +823,8 @@ class SFG(AbstractOperation): portstr, label=port.operation.graph_id, ) - # Creates edges for each output port and creates nodes for each operation and edges for them as well + # Creates edges for each output port and creates nodes for each operation + # and edges for them as well for i in range(len(p_list)): ports = p_list[i] for port in ports: @@ -948,7 +956,8 @@ class SFG(AbstractOperation): neighbor_op ) - # Check if have to fetch Operations from somewhere else since p_queue is empty + # Check if have to fetch Operations from somewhere else since p_queue + # is empty if operations_left > 0: # First check if can fetch from Operations with no input ports if no_inputs_queue: @@ -989,7 +998,8 @@ class SFG(AbstractOperation): Parameters ---------- type_name : TypeName - The type name of the operation. For example, obtained as ``Addition.type_name()``. + The type name of the operation. For example, obtained as + ``Addition.type_name()``. latency : int The latency of the operation. @@ -1006,7 +1016,8 @@ class SFG(AbstractOperation): Parameters ---------- type_name : TypeName - The type name of the operation. For example, obtained as ``Addition.type_name()``. + The type name of the operation. For example, obtained as + ``Addition.type_name()``. execution_time : int The execution time of the operation. """ @@ -1022,7 +1033,8 @@ class SFG(AbstractOperation): Parameters ---------- type_name : TypeName - The type name of the operation. For example, obtained as ``Addition.type_name()``. + The type name of the operation. For example, obtained as + ``Addition.type_name()``. latency_offsets : {"in1": int, ...} The latency offsets of the inputs and outputs. """ @@ -1282,7 +1294,8 @@ class SFG(AbstractOperation): self._components_dfs_order.append(new_connected_op) self._operations_dfs_order.append(new_connected_op) - # Add connected operation to the queue of operations to visit. + # Add connected operation to the queue of operations + # to visit. op_stack.append(original_connected_op) def _evaluate_source( @@ -1421,7 +1434,8 @@ class SFG(AbstractOperation): format : string, optional File format of the generated graph. Output formats can be found at https://www.graphviz.org/doc/info/output.html - Most common are "pdf", "eps", "png", and "svg". Default is None which leads to PDF. + Most common are "pdf", "eps", "png", and "svg". Default is None which + leads to PDF. show_id : Boolean, optional If True, the graph_id:s of signals are shown. The default is False. diff --git a/b_asic/signal_generator.py b/b_asic/signal_generator.py index 58782b96c071b41a02321ef9c3d2f2733839508e..11c7097b012e6a2b7b9be159efb0a948ea71815f 100644 --- a/b_asic/signal_generator.py +++ b/b_asic/signal_generator.py @@ -20,7 +20,8 @@ class SignalGenerator: """ Base class for signal generators. - Handles operator overloading and defined the ``__call__`` method that should be overridden. + Handles operator overloading and defined the ``__call__`` method that should + be overridden. """ def __call__(self, time: int) -> complex: diff --git a/b_asic/simulation.py b/b_asic/simulation.py index 2eaa3a6a188290ff2c5f443c21db9fb8571eb736..75bf31afca198ac76b625f7d624668c6bcd6e668 100644 --- a/b_asic/simulation.py +++ b/b_asic/simulation.py @@ -8,9 +8,6 @@ from collections import defaultdict from numbers import Number from typing import ( Callable, - DefaultDict, - Dict, - List, Mapping, MutableMapping, MutableSequence, @@ -21,12 +18,7 @@ from typing import ( import numpy as np -from b_asic.operation import ( - MutableDelayMap, - MutableResultMap, - ResultKey, - ResultMap, -) +from b_asic.operation import MutableDelayMap, ResultKey from b_asic.signal_flow_graph import SFG ResultArrayMap = Mapping[ResultKey, Sequence[Number]] @@ -127,8 +119,8 @@ class Simulation: truncate: bool = True, ) -> Sequence[Number]: """ - Run the simulation until its iteration is greater than or equal to the given iteration - and return the output values of the last iteration. + Run the simulation until its iteration is greater than or equal to the given + iteration and return the output values of the last iteration. """ result: Sequence[Number] = [] while self._iteration < iteration: @@ -191,9 +183,10 @@ class Simulation: def results(self) -> ResultArrayMap: """ Get a mapping from result keys to numpy arrays containing all results, including - intermediate values, calculated for each iteration up until now that was run with - save_results enabled. - The mapping is indexed using the key() method of Operation with the appropriate output index. + intermediate values, calculated for each iteration up until now that was run + with save_results enabled. + The mapping is indexed using the key() method of Operation with the appropriate + output index. Example result after 3 iterations:: {"c1": [3, 6, 7], "c2": [4, 5, 5], "bfly1.0": [7, 0, 0], "bfly1.1": [-1, 0, 2], "0": [7, -2, -1]}