From e0aa4e17afebde6a9201ee2c4fe4deebbd5b1f62 Mon Sep 17 00:00:00 2001
From: Oscar Gustafsson <oscar.gustafsson@liu.se>
Date: Wed, 16 Apr 2025 10:20:32 +0000
Subject: [PATCH] Docs and typing

---
 b_asic/__init__.py                         |  6 +-
 b_asic/architecture.py                     | 12 +++-
 b_asic/core_operations.py                  | 33 ++++++++--
 b_asic/logger.py                           | 10 +--
 b_asic/operation.py                        | 12 +++-
 b_asic/process.py                          |  4 +-
 b_asic/resources.py                        | 76 +++++++++++++++-------
 b_asic/schedule.py                         | 14 ++--
 b_asic/scheduler.py                        | 76 ++++++++++++++++++----
 b_asic/scheduler_gui/preferences_dialog.py | 13 ++--
 b_asic/sfg_generators.py                   | 13 ++--
 b_asic/signal_flow_graph.py                |  4 +-
 docs_sphinx/api/scheduler.rst              |  6 ++
 docs_sphinx/scheduler_gui.rst              |  2 +-
 14 files changed, 201 insertions(+), 80 deletions(-)

diff --git a/b_asic/__init__.py b/b_asic/__init__.py
index 1d0af5f6..fe6b1cb0 100644
--- a/b_asic/__init__.py
+++ b/b_asic/__init__.py
@@ -1,5 +1,7 @@
-"""B-ASIC - Better ASIC Toolbox.
-ASIC toolbox that simplifies circuit design and optimization.
+"""
+B-ASIC - Better ASIC Toolbox.
+
+A Python toolbox that simplifies implementation and optimization of static algorithms.
 """
 
 # Python modules.
diff --git a/b_asic/architecture.py b/b_asic/architecture.py
index 9ceaacc7..a843a903 100644
--- a/b_asic/architecture.py
+++ b/b_asic/architecture.py
@@ -110,7 +110,9 @@ class HardwareBlock:
 
     @property
     def schedule_time(self) -> int:
-        """The schedule time for hardware block."""
+        """
+        The schedule time for hardware block.
+        """
         raise NotImplementedError()
 
     def write_component_declaration(self, f: TextIOWrapper, indent: int = 1) -> None:
@@ -182,12 +184,16 @@ class Resource(HardwareBlock):
 
     @property
     def input_count(self) -> int:
-        """Number of input ports."""
+        """
+        Number of input ports.
+        """
         return self._input_count
 
     @property
     def output_count(self) -> int:
-        """Number of output ports."""
+        """
+        Number of output ports.
+        """
         return self._output_count
 
     def _struct_def(self) -> str:
diff --git a/b_asic/core_operations.py b/b_asic/core_operations.py
index e5d9dc02..0b39ba9d 100644
--- a/b_asic/core_operations.py
+++ b/b_asic/core_operations.py
@@ -39,7 +39,9 @@ class Constant(AbstractOperation):
     is_constant = True
 
     def __init__(self, value: Num = 0, name: Name = ""):
-        """Construct a Constant operation with the given value."""
+        """
+        Construct a Constant operation with the given value.
+        """
         super().__init__(
             input_count=0,
             output_count=1,
@@ -57,12 +59,16 @@ class Constant(AbstractOperation):
 
     @property
     def value(self) -> Num:
-        """Get the constant value of this operation."""
+        """
+        Get the constant value of this operation.
+        """
         return self.param("value")
 
     @value.setter
     def value(self, value: Num) -> None:
-        """Set the constant value of this operation."""
+        """
+        Set the constant value of this operation.
+        """
         self.set_param("value", value)
 
     @property
@@ -245,7 +251,9 @@ class Subtraction(AbstractOperation):
         latency_offsets: dict[str, int] | None = None,
         execution_time: int | None = None,
     ):
-        """Construct a Subtraction operation."""
+        """
+        Construct a Subtraction operation.
+        """
         super().__init__(
             input_count=2,
             output_count=1,
@@ -334,7 +342,9 @@ class AddSub(AbstractOperation):
         latency_offsets: dict[str, int] | None = None,
         execution_time: int | None = None,
     ):
-        """Construct an Addition/Subtraction operation."""
+        """
+        Construct an Addition/Subtraction operation.
+        """
         super().__init__(
             input_count=2,
             output_count=1,
@@ -355,12 +365,21 @@ class AddSub(AbstractOperation):
 
     @property
     def is_add(self) -> bool:
-        """Get if operation is an addition."""
+        """
+        Get if operation is an addition.
+        """
         return self.param("is_add")
 
     @is_add.setter
     def is_add(self, is_add: bool) -> None:
-        """Set if operation is an addition."""
+        """
+        Set if operation is an addition.
+
+        Parameters
+        ----------
+        is_add : bool
+            If True, operation is an addition. If False, operation is a subtraction.
+        """
         self.set_param("is_add", is_add)
 
     @property
diff --git a/b_asic/logger.py b/b_asic/logger.py
index 96f89df6..d279388f 100644
--- a/b_asic/logger.py
+++ b/b_asic/logger.py
@@ -59,8 +59,7 @@ def getLogger(
     name: str, filename: str | None = "", console_log_level: str = "warning"
 ) -> Logger:
     """
-    This function creates console- and filehandler and from those, creates a logger
-    object.
+    Create console- and filehandler and from those, create a logger object.
 
     Parameters
     ----------
@@ -125,8 +124,11 @@ def handle_exceptions(
     exc_value: BaseException,
     exc_traceback: TracebackType | None,
 ) -> None:
-    """This function is a helper function to log uncaught exceptions. Install with:
-    `sys.excepthook = <module>.handle_exceptions`"""
+    """
+    Helper function to log uncaught exceptions.
+
+    Install with: `sys.excepthook = <module>.handle_exceptions`
+    """
     if issubclass(exc_type, KeyboardInterrupt):
         sys.__excepthook__(exc_type, exc_value, exc_traceback)
         return
diff --git a/b_asic/operation.py b/b_asic/operation.py
index 955ce168..2ca298e9 100644
--- a/b_asic/operation.py
+++ b/b_asic/operation.py
@@ -56,18 +56,24 @@ class Operation(GraphComponent, SignalSourceProvider):
     @property
     @abstractmethod
     def input_count(self) -> int:
-        """Get the number of input ports."""
+        """
+        Get the number of input ports.
+        """
         raise NotImplementedError
 
     @property
     @abstractmethod
     def output_count(self) -> int:
-        """Get the number of output ports."""
+        """
+        Get the number of output ports.
+        """
         raise NotImplementedError
 
     @abstractmethod
     def input(self, index: int) -> InputPort:
-        """Get the input port at the given index."""
+        """
+        Get the input port at the given index.
+        """
         raise NotImplementedError
 
     @abstractmethod
diff --git a/b_asic/process.py b/b_asic/process.py
index be4ccbe2..cb5d77ff 100644
--- a/b_asic/process.py
+++ b/b_asic/process.py
@@ -303,7 +303,7 @@ class MemoryVariable(MemoryProcess):
         super().__init__(
             write_time=write_time,
             life_times=list(reads.values()),
-            name=name,
+            name=name or write_port.name,
         )
 
     @property
@@ -378,7 +378,7 @@ class PlainMemoryVariable(MemoryProcess):
     __slots__ = ("_reads", "_read_ports", "_write_port")
     _reads: dict[int, int]
     _read_ports: list[int]
-    _write_port: OutputPort
+    _write_port: int
 
     def __init__(
         self,
diff --git a/b_asic/resources.py b/b_asic/resources.py
index 95b42d82..26a36336 100644
--- a/b_asic/resources.py
+++ b/b_asic/resources.py
@@ -918,7 +918,17 @@ class ProcessCollection:
             "greedy_graph_color",
             "ilp_graph_color",
         ] = "left_edge",
-        coloring_strategy: str = "saturation_largest_first",
+        coloring_strategy: Literal[
+            'largest_first',
+            'random_sequential',
+            'smallest_last',
+            'independent_set',
+            'connected_sequential_bfs',
+            'connected_sequential_dfs',
+            'connected_sequential',
+            'saturation_largest_first',
+            'DSATUR',
+        ] = "saturation_largest_first",
         max_colors: int | None = None,
         solver: PULP_CBC_CMD | GUROBI | None = None,
     ) -> list["ProcessCollection"]:
@@ -950,9 +960,10 @@ class ProcessCollection:
 
         solver : PuLP MIP solver object, optional
             Only used if strategy is an ILP method.
-            Valid options are:
-                * PULP_CBC_CMD() - preinstalled with the package
-                * GUROBI() - required licence but likely faster
+            Valid options are
+
+            * PULP_CBC_CMD() - preinstalled
+            * GUROBI() - license required, but likely faster
 
         Returns
         -------
@@ -969,7 +980,15 @@ class ProcessCollection:
 
     def split_on_ports(
         self,
-        strategy: str = "left_edge",
+        strategy: Literal[
+            "ilp_graph_color",
+            "ilp_min_input_mux",
+            "greedy_graph_color",
+            "equitable_graph_color",
+            "left_edge",
+            "left_edge_min_pe_to_mem",
+            "left_edge_min_mem_to_pe",
+        ] = "left_edge",
         read_ports: int | None = None,
         write_ports: int | None = None,
         total_ports: int | None = None,
@@ -986,35 +1005,43 @@ class ProcessCollection:
         ----------
         strategy : str, default: "left_edge"
             The strategy used when splitting this :class:`ProcessCollection`.
-            Valid options are:
-                * "ilp_graph_color"
-                * "ilp_min_input_mux"
-                * "greedy_graph_color"
-                * "equitable_graph_color"
-                * "left_edge"
-                * "left_edge_min_pe_to_mem"
-                * "left_edge_min_mem_to_pe"
+            Valid options are
+
+            * "ilp_graph_color" - ILP-based optimal graph coloring
+            * "ilp_min_input_mux" - ILP-based optimal graph coloring minimizing the number of input multiplexers
+            * "greedy_graph_color"
+            * "equitable_graph_color"
+            * "left_edge"
+            * "left_edge_min_pe_to_mem"
+            * "left_edge_min_mem_to_pe"
+
         read_ports : int, optional
             The number of read ports used when splitting process collection based on
             memory variable access.
+
         write_ports : int, optional
             The number of write ports used when splitting process collection based on
             memory variable access.
+
         total_ports : int, optional
             The total number of ports used when splitting process collection based on
             memory variable access.
-        processing_elements : list of ProcessingElement, optional
+
+        processing_elements : list of :class:`ProcessingElement`, optional
             The currently used PEs,
-            only required if strategy = "left_edge_min_mem_to_pe",
+            only required if *strategy* is "left_edge_min_mem_to_pe",
             "ilp_graph_color" or "ilp_min_input_mux".
+
         max_colors : int, optional
             The maximum amount of colors to split based on,
             only required if strategy is an ILP method.
+
         solver : PuLP MIP solver object, optional
             Only used if strategy is an ILP method.
-            Valid options are:
-                * PULP_CBC_CMD() - preinstalled with the package
-                * GUROBI() - required licence but likely faster
+            Valid options are
+
+            * PULP_CBC_CMD() - preinstalled with the package
+            * GUROBI() - required licence but likely faster
 
         Returns
         -------
@@ -1128,13 +1155,12 @@ class ProcessCollection:
         sequence: list[Process],
     ) -> list["ProcessCollection"]:
         """
-        Split this collection into multiple new collections by sequentially assigning
-        processes in the order of `sequence`.
+        Split this collection by sequentially assigning processes in the order of `sequence`.
 
         This method takes the processes from `sequence`, in order, and assigns them to
         to multiple new `ProcessCollection` based on port collisions in a first-come
-        first-served manner. The first `Process` in `sequence` is assigned first, and
-        the last `Process` in `sequence is assigned last.
+        first-served manner. The first :class:`Process` in `sequence` is assigned first, and
+        the last :class:`Process` in `sequence is assigned last.
 
         Parameters
         ----------
@@ -1147,14 +1173,14 @@ class ProcessCollection:
         total_ports : int
             The total number of ports used when splitting process collection based on
             memory variable access.
-        sequence : list of `Process`
+        sequence : list of :class:`Process`
             A list of the processes used to determine the order in which processes are
             assigned.
 
         Returns
         -------
-        list of `ProcessCollection`
-            A set of new ProcessCollection objects with the process splitting.
+        list of :class:`ProcessCollection`
+            A list of new :class:`ProcessCollection` objects with the process splitting.
         """
 
         if set(self.collection) != set(sequence):
diff --git a/b_asic/schedule.py b/b_asic/schedule.py
index 368a20f2..a3d8aaa1 100644
--- a/b_asic/schedule.py
+++ b/b_asic/schedule.py
@@ -655,21 +655,23 @@ class Schedule:
         """
         self._sfg.set_execution_time_of_type_name(type_name, execution_time)
 
-    def set_latency_of_type_name(self, type_name: TypeName, latency: int) -> None:
+    def set_latency_of_type_name(
+        self, type_name: TypeName | GraphID, latency: int
+    ) -> None:
         """
         Set the latency of all operations with the given type name.
 
         Parameters
         ----------
-        type_name : TypeName
-            The type name of the operation. For example, obtained as
-            ``Addition.type_name()``.
+        type_name : TypeName or GraphID
+            The type name of the operation, e.g., obtained as
+            ``Addition.type_name()`` or a specific GraphID of an operation.
         latency : int
             The latency of the operation.
         """
         passed = True
         for op in self._sfg.operations:
-            if type_name == op.type_name() or type_name == op.graph_id:
+            if type_name in (op.type_name(), op.graph_id):
                 change_in_latency = latency - op.latency
                 if change_in_latency > (self.forward_slack(op.graph_id)):
                     passed = False
@@ -680,7 +682,7 @@ class Schedule:
                     break
         if change_in_latency < 0 or passed:
             for op in self._sfg.operations:
-                if type_name == op.type_name() or type_name == op.graph_id:
+                if type_name in (op.type_name(), op.graph_id):
                     cast(Operation, op).set_latency(latency)
 
     def move_y_location(
diff --git a/b_asic/scheduler.py b/b_asic/scheduler.py
index a50e390d..0bae94f3 100644
--- a/b_asic/scheduler.py
+++ b/b_asic/scheduler.py
@@ -29,7 +29,7 @@ class Scheduler(ABC):
     input_times : dict(GraphID, int), optional
         The times when inputs arrive.
     output_delta_times : dict(GraphID, int), optional
-        The relative time when outputs should be produced
+        The relative times when outputs should be produced.
     sort_y_location : bool, default: True
         If the y-position should be sorted based on start time of operations.
     """
@@ -223,7 +223,18 @@ class Scheduler(ABC):
 
 
 class ASAPScheduler(Scheduler):
-    """Scheduler that implements the as-soon-as-possible (ASAP) algorithm."""
+    """
+    Scheduler that implements the as-soon-as-possible (ASAP) algorithm.
+
+    Parameters
+    ----------
+    input_times : dict(GraphID, int), optional
+        The times when inputs arrive.
+    output_delta_times : dict(GraphID, int), optional
+        The relative times when outputs should be produced.
+    sort_y_location : bool, default: True
+        If the y-position should be sorted based on start time of operations.
+    """
 
     def apply_scheduling(self, schedule: "Schedule") -> None:
         # Doc-string inherited
@@ -307,7 +318,18 @@ class ASAPScheduler(Scheduler):
 
 
 class ALAPScheduler(Scheduler):
-    """Scheduler that implements the as-late-as-possible (ALAP) algorithm."""
+    """
+    Scheduler that implements the as-late-as-possible (ALAP) algorithm.
+
+    Parameters
+    ----------
+    input_times : dict(GraphID, int), optional
+        The times when inputs arrive.
+    output_delta_times : dict(GraphID, int), optional
+        The relative times when outputs should be produced.
+    sort_y_location : bool, default: True
+        If the y-position should be sorted based on start time of operations.
+    """
 
     def apply_scheduling(self, schedule: "Schedule") -> None:
         # Doc-string inherited
@@ -363,7 +385,7 @@ class ALAPScheduler(Scheduler):
 
 class ListScheduler(Scheduler):
     """
-    List-based scheduler that schedules the operations with constraints.
+    List-based scheduler with optional constraints.
 
     .. admonition:: Important
 
@@ -372,19 +394,21 @@ class ListScheduler(Scheduler):
 
     Parameters
     ----------
-    sort_order : tuple[tuple[int, bool]]
+    sort_order : tuple(tuple(int, bool))
         Specifies which columns in the priority table to sort on and in
         which order, where True is ascending order.
     max_resources : dict[TypeName, int] | None, optional
-        Max resources available to realize the schedule, by default None
+        Max resources available to realize the schedule.
     max_concurrent_reads : int | None, optional
-        Max number of conccurent reads, by default None
+        Max number of conccurent reads.
     max_concurrent_writes : int | None, optional
-        Max number of conccurent writes, by default None
-    input_times : dict["GraphID", int] | None, optional
-        Specified input times, by default None
-    output_delta_times : dict["GraphID", int] | None, optional
-        Specified output delta times, by default None
+        Max number of conccurent writes.
+    input_times : dict(GraphID, int) | None, optional
+        The times when inputs arrive.
+    output_delta_times : dict(GraphID, int) | None, optional
+        The relative times when outputs should be produced.
+    sort_y_location : bool, default: True
+        If the y-position should be sorted based on start time of operations.
     """
 
     __slots__ = (
@@ -426,9 +450,9 @@ class ListScheduler(Scheduler):
         max_concurrent_writes: int | None = None,
         input_times: dict["GraphID", int] | None = None,
         output_delta_times: dict["GraphID", int] | None = None,
-        sort_y_locations: bool = True,
+        sort_y_location: bool = True,
     ) -> None:
-        super().__init__(input_times, output_delta_times, sort_y_locations)
+        super().__init__(input_times, output_delta_times, sort_y_location)
         self._sort_order = sort_order
 
         if max_resources is not None:
@@ -886,6 +910,28 @@ class ListScheduler(Scheduler):
 
 
 class RecursiveListScheduler(ListScheduler):
+    """
+    List-based scheduler for recursive algorithms with optional constraints.
+
+    .. admonition:: Info
+
+       If the SFG does not have any recursive parts, use :class:`ListScheduler` instead.
+
+    Parameters
+    ----------
+    sort_order : tuple(tuple(int, bool))
+        Specifies which columns in the priority table to sort on and in
+        which order, where True is ascending order.
+    max_resources : dict[TypeName, int] | None, optional
+        Max resources available to realize the schedule.
+    input_times : dict(GraphID, int) | None, optional
+        The times when inputs arrive.
+    output_delta_times : dict(GraphID, int) | None, optional
+        The relative times when outputs should be produced.
+    sort_y_location : bool, default: True
+        If the y-position should be sorted based on start time of operations.
+    """
+
     __slots__ = ('_recursive_ops', '_recursive_ops_set', '_remaining_recursive_ops')
 
     def __init__(
@@ -894,12 +940,14 @@ class RecursiveListScheduler(ListScheduler):
         max_resources: dict[TypeName, int] | None = None,
         input_times: dict["GraphID", int] | None = None,
         output_delta_times: dict["GraphID", int] | None = None,
+        sort_y_location: bool = True,
     ) -> None:
         super().__init__(
             sort_order=sort_order,
             max_resources=max_resources,
             input_times=input_times,
             output_delta_times=output_delta_times,
+            sort_y_location=sort_y_location,
         )
 
     def apply_scheduling(self, schedule: "Schedule") -> None:
diff --git a/b_asic/scheduler_gui/preferences_dialog.py b/b_asic/scheduler_gui/preferences_dialog.py
index 45d4eff9..3e671b4e 100644
--- a/b_asic/scheduler_gui/preferences_dialog.py
+++ b/b_asic/scheduler_gui/preferences_dialog.py
@@ -169,7 +169,7 @@ class PreferencesDialog(QWidget):
         layout.addWidget(groupbox)
 
         reset_font_button = ColorButton(QColor("silver"))
-        reset_font_button.setText("Reset All Font Settings")
+        reset_font_button.setText("Reset all font Settings")
         reset_font_button.pressed.connect(lambda: self.reset_font_clicked())
         layout.addWidget(reset_font_button)
 
@@ -216,7 +216,8 @@ class PreferencesDialog(QWidget):
         self.update_font()
 
     def create_color_button(self, color: ColorDataType) -> ColorButton:
-        """Create a colored button to be used to modify a certain color
+        """
+        Create a colored button to be used to modify a certain color.
 
         Parameters
         ----------
@@ -308,7 +309,7 @@ class PreferencesDialog(QWidget):
 
     def color_button_clicked(self, color_type: ColorDataType) -> None:
         """
-        Open a color dialog to select a color based on the specified color type
+        Open a color dialog to select a color based on the specified color type.
 
         Parameters
         ----------
@@ -379,7 +380,7 @@ class PreferencesDialog(QWidget):
             self._boldbutton.set_color(QColor("snow"))
 
     def update_font(self):
-        """Update font preferences based on current Font settings"""
+        """Update font preferences based on current Font settings."""
         settings = QSettings()
         FONT.changed = not (
             FONT.current_font == FONT.DEFAULT
@@ -395,7 +396,7 @@ class PreferencesDialog(QWidget):
         self._parent.load_preferences()
 
     def font_color_clicked(self):
-        """Select a font color and update preferences"""
+        """Select a font color and update preferences."""
         settings = QSettings()
         color = QColorDialog.getColor(FONT.color, self, "Select font color")
         if color.isValid():
@@ -406,7 +407,7 @@ class PreferencesDialog(QWidget):
         self._parent._graph._font_color_change(FONT.color)
 
     def reset_color_clicked(self):
-        """Reset the color settings"""
+        """Reset the color settings."""
         settings = QSettings()
         reset_color_settings(settings)
         self._parent._color_changed_per_type = False
diff --git a/b_asic/sfg_generators.py b/b_asic/sfg_generators.py
index b7e21aaa..bd5eec42 100644
--- a/b_asic/sfg_generators.py
+++ b/b_asic/sfg_generators.py
@@ -271,7 +271,8 @@ def symmetric_fir(
     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 symmetric FIR filter.
+    r"""
+    Generate a signal flow graph of a symmetric FIR filter.
 
     The *coefficients* parameter is a sequence of impulse response values of even length::
 
@@ -351,7 +352,7 @@ def direct_form_1_iir(
     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."""
+    """Generate a direct-form IIR filter of type I with coefficients a and b."""
     if len(a) < 2 or len(b) < 2:
         raise ValueError(
             "Size of coefficient lists a and b needs to contain at least 2 element."
@@ -425,7 +426,7 @@ def direct_form_2_iir(
     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."""
+    """Generate a direct-form IIR filter of type II with coefficients a and b."""
     if len(a) < 2 or len(b) < 2:
         raise ValueError(
             "Size of coefficient lists a and b needs to contain at least 2 element."
@@ -503,7 +504,8 @@ def direct_form_2_iir(
 
 
 def radix_2_dif_fft(points: int) -> SFG:
-    """Generates a radix-2 decimation-in-frequency FFT structure.
+    """
+    Generate a radix-2 decimation-in-frequency FFT structure.
 
     Parameters
     ----------
@@ -548,7 +550,8 @@ def ldlt_matrix_inverse(
     mads_properties: dict[str, int] | dict[str, dict[str, int]] | None = None,
     reciprocal_properties: dict[str, int] | dict[str, dict[str, int]] | None = None,
 ) -> SFG:
-    """Generates an SFG for the LDLT matrix inverse algorithm.
+    """
+    Generate an SFG for the LDLT matrix inverse algorithm.
 
     Parameters
     ----------
diff --git a/b_asic/signal_flow_graph.py b/b_asic/signal_flow_graph.py
index 859e3647..349e0e8e 100644
--- a/b_asic/signal_flow_graph.py
+++ b/b_asic/signal_flow_graph.py
@@ -13,7 +13,7 @@ from fractions import Fraction
 from io import StringIO
 from math import ceil
 from queue import PriorityQueue
-from typing import ClassVar, Literal, Union, cast
+from typing import Literal, Union, cast
 
 import numpy as np
 from graphviz import Digraph
@@ -797,7 +797,7 @@ class SFG(AbstractOperation):
             The source operation GraphID to connect to.
         new_operation : Operation
             The new operation, e.g. Multiplication.
-        port : Optional[int]
+        port : int, optional
             The number of the InputPort before which the new operation shall be
             inserted.
         """
diff --git a/docs_sphinx/api/scheduler.rst b/docs_sphinx/api/scheduler.rst
index 8d3c52dd..a81c19a4 100644
--- a/docs_sphinx/api/scheduler.rst
+++ b/docs_sphinx/api/scheduler.rst
@@ -3,6 +3,12 @@
 ********************
 :mod:`.scheduler`
 
+
+.. inheritance-diagram:: b_asic.operation
+   :parts: 1
+   :top-classes: b_asic.scheduler.scheduler
+
+
 .. automodule:: b_asic.scheduler
    :members:
    :undoc-members:
diff --git a/docs_sphinx/scheduler_gui.rst b/docs_sphinx/scheduler_gui.rst
index 03ead85c..fed5c453 100644
--- a/docs_sphinx/scheduler_gui.rst
+++ b/docs_sphinx/scheduler_gui.rst
@@ -38,7 +38,7 @@ scheduler\_gui.operation\_item module
    :show-inheritance:
 
 scheduler\_gui.preferences\_dialog module
--------------------------------------
+-----------------------------------------
 
 .. automodule:: b_asic.scheduler_gui.preferences_dialog
    :members:
-- 
GitLab