From d7649bf570a86da31da9353eee6faf6b12e7e96a Mon Sep 17 00:00:00 2001
From: Simon Bjurek <simbj106@student.liu.se>
Date: Wed, 22 Jan 2025 15:04:53 +0100
Subject: [PATCH 01/21] bumped to qtpy6

---
 b_asic/scheduler_gui/main_window.py    |  16 +-
 b_asic/scheduler_gui/ui_main_window.py | 796 ++++++++-----------------
 2 files changed, 268 insertions(+), 544 deletions(-)

diff --git a/b_asic/scheduler_gui/main_window.py b/b_asic/scheduler_gui/main_window.py
index bd03b5f2..4de6e4cd 100644
--- a/b_asic/scheduler_gui/main_window.py
+++ b/b_asic/scheduler_gui/main_window.py
@@ -31,7 +31,7 @@ from qtpy.QtCore import (
     Qt,
     Slot,
 )
-from qtpy.QtGui import QCloseEvent, QColor, QFont, QIcon, QIntValidator
+from qtpy.QtGui import QCloseEvent, QColor, QFont, QIcon, QIntValidator, QPalette
 from qtpy.QtWidgets import (
     QAbstractButton,
     QAction,
@@ -98,9 +98,9 @@ if __debug__:
     log.debug(f"Qt version (compile time): {QtCore.__version__}")
     log.debug(f"QT_API:                    {QT_API}")
     if QT_API.lower().startswith("pyside"):
-        import PySide2
+        import PySide6
 
-        log.debug(f"PySide version:           {PySide2.__version__}")
+        log.debug(f"PySide version:           {PySide6.__version__}")
     if QT_API.lower().startswith("pyqt"):
         from qtpy.QtCore import PYQT_VERSION_STR
 
@@ -1688,8 +1688,16 @@ def start_scheduler(schedule: Optional[Schedule] = None) -> Optional[Schedule]:
         The edited schedule.
     """
     if not QApplication.instance():
-        QApplication.setAttribute(Qt.AA_EnableHighDpiScaling)
         app = QApplication(sys.argv)
+        # Enforce a light palette regardless of laptop theme
+        palette = QPalette()
+        palette.setColor(QPalette.ColorRole.Window, QtCore.Qt.white)
+        palette.setColor(QPalette.ColorRole.WindowText, QtCore.Qt.black)
+        palette.setColor(QPalette.ColorRole.ButtonText, QtCore.Qt.black)
+        palette.setColor(QPalette.ColorRole.Base, QtCore.Qt.white) 
+        palette.setColor(QPalette.ColorRole.AlternateBase, QtCore.Qt.lightGray) 
+        palette.setColor(QPalette.ColorRole.Text, QtCore.Qt.black)
+        app.setPalette(palette)
     else:
         app = QApplication.instance()
     window = ScheduleMainWindow()
diff --git a/b_asic/scheduler_gui/ui_main_window.py b/b_asic/scheduler_gui/ui_main_window.py
index ec174369..7def5879 100644
--- a/b_asic/scheduler_gui/ui_main_window.py
+++ b/b_asic/scheduler_gui/ui_main_window.py
@@ -1,293 +1,220 @@
-################################################################################
-## Form generated from reading UI file 'main_window.ui'
-##
-## Created by: Qt User Interface Compiler version 5.15.8
-##
-## WARNING! All changes made in this file will be lost when recompiling UI file!
-################################################################################
+# Form implementation generated from reading ui file '.\B-ASIC\b_asic\scheduler_gui\main_window.ui'
+#
+# Created by: PyQt6 UI code generator 6.8.0
+#
+# WARNING: Any manual changes made to this file will be lost when pyuic6 is
+# run again.  Do not edit this file unless you know what you are doing.
 
-from qtpy.QtCore import QSize, QCoreApplication, QRect, QMetaObject
-from qtpy.QtGui import QIcon, QColor, QFont, QBrush, Qt, QPainter
-from qtpy.QtWidgets import (
-    QSizePolicy,
-    QAction,
-    QMenu,
-    QMenuBar,
-    QToolBar,
-    QHBoxLayout,
-    QWidget,
-    QGraphicsView,
-    QSplitter,
-    QTableWidgetItem,
-    QTableWidget,
-    QAbstractItemView,
-    QStatusBar,
-)
 
+from qtpy import QtCore, QtGui, QtWidgets
 
-class Ui_MainWindow:
+
+class Ui_MainWindow(object):
     def setupUi(self, MainWindow):
-        if not MainWindow.objectName():
-            MainWindow.setObjectName("MainWindow")
+        MainWindow.setObjectName("MainWindow")
         MainWindow.resize(800, 600)
-        sizePolicy = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred)
+        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Preferred, QtWidgets.QSizePolicy.Policy.Preferred)
         sizePolicy.setHorizontalStretch(0)
         sizePolicy.setVerticalStretch(0)
         sizePolicy.setHeightForWidth(MainWindow.sizePolicy().hasHeightForWidth())
         MainWindow.setSizePolicy(sizePolicy)
-        icon = QIcon()
-        icon.addFile(":/icons/basic/small_logo.png", QSize(), QIcon.Normal, QIcon.Off)
+        icon = QtGui.QIcon()
+        icon.addPixmap(QtGui.QPixmap(":/icons/basic/small_logo.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)
         MainWindow.setWindowIcon(icon)
-        self.menu_load_from_file = QAction(MainWindow)
+        self.centralwidget = QtWidgets.QWidget(parent=MainWindow)
+        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Preferred, QtWidgets.QSizePolicy.Policy.Preferred)
+        sizePolicy.setHorizontalStretch(0)
+        sizePolicy.setVerticalStretch(0)
+        sizePolicy.setHeightForWidth(self.centralwidget.sizePolicy().hasHeightForWidth())
+        self.centralwidget.setSizePolicy(sizePolicy)
+        self.centralwidget.setObjectName("centralwidget")
+        self.horizontalLayout = QtWidgets.QHBoxLayout(self.centralwidget)
+        self.horizontalLayout.setContentsMargins(0, 0, 0, 0)
+        self.horizontalLayout.setSpacing(0)
+        self.horizontalLayout.setObjectName("horizontalLayout")
+        self.splitter = QtWidgets.QSplitter(parent=self.centralwidget)
+        self.splitter.setOrientation(QtCore.Qt.Orientation.Horizontal)
+        self.splitter.setHandleWidth(0)
+        self.splitter.setObjectName("splitter")
+        self.view = QtWidgets.QGraphicsView(parent=self.splitter)
+        self.view.setAlignment(QtCore.Qt.AlignmentFlag.AlignLeading|QtCore.Qt.AlignmentFlag.AlignLeft|QtCore.Qt.AlignmentFlag.AlignTop)
+        self.view.setRenderHints(QtGui.QPainter.RenderHint.Antialiasing|QtGui.QPainter.RenderHint.TextAntialiasing)
+        self.view.setViewportUpdateMode(QtWidgets.QGraphicsView.ViewportUpdateMode.FullViewportUpdate)
+        self.view.setObjectName("view")
+        self.info_table = QtWidgets.QTableWidget(parent=self.splitter)
+        self.info_table.setStyleSheet("alternate-background-color: #fadefb;background-color: #ebebeb;")
+        self.info_table.setEditTriggers(QtWidgets.QAbstractItemView.EditTrigger.NoEditTriggers)
+        self.info_table.setAlternatingRowColors(True)
+        self.info_table.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectionBehavior.SelectRows)
+        self.info_table.setRowCount(2)
+        self.info_table.setColumnCount(2)
+        self.info_table.setObjectName("info_table")
+        item = QtWidgets.QTableWidgetItem()
+        self.info_table.setVerticalHeaderItem(0, item)
+        item = QtWidgets.QTableWidgetItem()
+        self.info_table.setVerticalHeaderItem(1, item)
+        item = QtWidgets.QTableWidgetItem()
+        item.setTextAlignment(QtCore.Qt.AlignmentFlag.AlignLeading|QtCore.Qt.AlignmentFlag.AlignVCenter)
+        font = QtGui.QFont()
+        font.setBold(False)
+        font.setWeight(50)
+        item.setFont(font)
+        self.info_table.setHorizontalHeaderItem(0, item)
+        item = QtWidgets.QTableWidgetItem()
+        item.setTextAlignment(QtCore.Qt.AlignmentFlag.AlignLeading|QtCore.Qt.AlignmentFlag.AlignVCenter)
+        self.info_table.setHorizontalHeaderItem(1, item)
+        item = QtWidgets.QTableWidgetItem()
+        font = QtGui.QFont()
+        font.setBold(False)
+        font.setWeight(50)
+        font.setKerning(True)
+        item.setFont(font)
+        brush = QtGui.QBrush(QtGui.QColor(160, 160, 164))
+        brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern)
+        item.setBackground(brush)
+        brush = QtGui.QBrush(QtGui.QColor(255, 255, 255))
+        brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern)
+        item.setForeground(brush)
+        item.setFlags(QtCore.Qt.ItemFlag.ItemIsSelectable|QtCore.Qt.ItemFlag.ItemIsEditable|QtCore.Qt.ItemFlag.ItemIsDragEnabled|QtCore.Qt.ItemFlag.ItemIsDropEnabled|QtCore.Qt.ItemFlag.ItemIsUserCheckable)
+        self.info_table.setItem(0, 0, item)
+        item = QtWidgets.QTableWidgetItem()
+        font = QtGui.QFont()
+        font.setBold(False)
+        font.setWeight(50)
+        item.setFont(font)
+        brush = QtGui.QBrush(QtGui.QColor(160, 160, 164))
+        brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern)
+        item.setBackground(brush)
+        brush = QtGui.QBrush(QtGui.QColor(255, 255, 255))
+        brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern)
+        item.setForeground(brush)
+        item.setFlags(QtCore.Qt.ItemFlag.ItemIsSelectable|QtCore.Qt.ItemFlag.ItemIsEditable|QtCore.Qt.ItemFlag.ItemIsDragEnabled|QtCore.Qt.ItemFlag.ItemIsDropEnabled|QtCore.Qt.ItemFlag.ItemIsUserCheckable)
+        self.info_table.setItem(1, 0, item)
+        self.info_table.horizontalHeader().setHighlightSections(False)
+        self.info_table.horizontalHeader().setStretchLastSection(True)
+        self.info_table.verticalHeader().setVisible(False)
+        self.info_table.verticalHeader().setDefaultSectionSize(24)
+        self.horizontalLayout.addWidget(self.splitter)
+        MainWindow.setCentralWidget(self.centralwidget)
+        self.menubar = QtWidgets.QMenuBar(parent=MainWindow)
+        self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 20))
+        self.menubar.setObjectName("menubar")
+        self.menuFile = QtWidgets.QMenu(parent=self.menubar)
+        self.menuFile.setObjectName("menuFile")
+        self.menu_Recent_Schedule = QtWidgets.QMenu(parent=self.menuFile)
+        self.menu_Recent_Schedule.setObjectName("menu_Recent_Schedule")
+        self.menuView = QtWidgets.QMenu(parent=self.menubar)
+        self.menuView.setObjectName("menuView")
+        self.menu_view_execution_times = QtWidgets.QMenu(parent=self.menuView)
+        self.menu_view_execution_times.setEnabled(False)
+        self.menu_view_execution_times.setObjectName("menu_view_execution_times")
+        self.menu_Edit = QtWidgets.QMenu(parent=self.menubar)
+        self.menu_Edit.setObjectName("menu_Edit")
+        self.menuWindow = QtWidgets.QMenu(parent=self.menubar)
+        self.menuWindow.setObjectName("menuWindow")
+        self.menuHelp = QtWidgets.QMenu(parent=self.menubar)
+        self.menuHelp.setObjectName("menuHelp")
+        MainWindow.setMenuBar(self.menubar)
+        self.statusbar = QtWidgets.QStatusBar(parent=MainWindow)
+        self.statusbar.setObjectName("statusbar")
+        MainWindow.setStatusBar(self.statusbar)
+        self.toolBar = QtWidgets.QToolBar(parent=MainWindow)
+        self.toolBar.setObjectName("toolBar")
+        MainWindow.addToolBar(QtCore.Qt.ToolBarArea.TopToolBarArea, self.toolBar)
+        self.menu_load_from_file = QtGui.QAction(parent=MainWindow)
+        icon = QtGui.QIcon.fromTheme("document-open-folder")
+        self.menu_load_from_file.setIcon(icon)
+        self.menu_load_from_file.setStatusTip("")
         self.menu_load_from_file.setObjectName("menu_load_from_file")
-        icon1 = QIcon()
-        iconThemeName = "document-open-folder"
-        if QIcon.hasThemeIcon(iconThemeName):
-            icon1 = QIcon.fromTheme(iconThemeName)
-        else:
-            icon1.addFile("../../../.designer/backup", QSize(), QIcon.Normal, QIcon.Off)
-
-        self.menu_load_from_file.setIcon(icon1)
-        self.menu_save = QAction(MainWindow)
-        self.menu_save.setObjectName("menu_save")
+        self.menu_save = QtGui.QAction(parent=MainWindow)
         self.menu_save.setEnabled(False)
-        icon2 = QIcon()
-        iconThemeName = "document-save"
-        if QIcon.hasThemeIcon(iconThemeName):
-            icon2 = QIcon.fromTheme(iconThemeName)
-        else:
-            icon2.addFile("../../../.designer/backup", QSize(), QIcon.Normal, QIcon.Off)
-
-        self.menu_save.setIcon(icon2)
-        self.menu_node_info = QAction(MainWindow)
-        self.menu_node_info.setObjectName("menu_node_info")
+        icon = QtGui.QIcon.fromTheme("document-save")
+        self.menu_save.setIcon(icon)
+        self.menu_save.setObjectName("menu_save")
+        self.menu_node_info = QtGui.QAction(parent=MainWindow)
         self.menu_node_info.setCheckable(True)
         self.menu_node_info.setChecked(True)
-        icon3 = QIcon()
-        icon3.addFile(":/icons/misc/right_panel.svg", QSize(), QIcon.Normal, QIcon.Off)
-        icon3.addFile(
-            ":/icons/misc/right_filled_panel.svg", QSize(), QIcon.Normal, QIcon.On
-        )
-        self.menu_node_info.setIcon(icon3)
+        icon1 = QtGui.QIcon()
+        icon1.addPixmap(QtGui.QPixmap(":/icons/misc/right_panel.svg"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)
+        icon1.addPixmap(QtGui.QPixmap(":/icons/misc/right_filled_panel.svg"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.On)
+        self.menu_node_info.setIcon(icon1)
         self.menu_node_info.setIconVisibleInMenu(False)
-        self.menu_quit = QAction(MainWindow)
+        self.menu_node_info.setObjectName("menu_node_info")
+        self.menu_quit = QtGui.QAction(parent=MainWindow)
+        icon = QtGui.QIcon.fromTheme("application-exit")
+        self.menu_quit.setIcon(icon)
         self.menu_quit.setObjectName("menu_quit")
-        icon4 = QIcon()
-        iconThemeName = "application-exit"
-        if QIcon.hasThemeIcon(iconThemeName):
-            icon4 = QIcon.fromTheme(iconThemeName)
-        else:
-            icon4.addFile("../../../.designer/backup", QSize(), QIcon.Normal, QIcon.Off)
-
-        self.menu_quit.setIcon(icon4)
-        self.menu_save_as = QAction(MainWindow)
-        self.menu_save_as.setObjectName("menu_save_as")
+        self.menu_save_as = QtGui.QAction(parent=MainWindow)
         self.menu_save_as.setEnabled(False)
-        icon5 = QIcon()
-        iconThemeName = "document-save-as"
-        if QIcon.hasThemeIcon(iconThemeName):
-            icon5 = QIcon.fromTheme(iconThemeName)
-        else:
-            icon5.addFile("../../../.designer/backup", QSize(), QIcon.Normal, QIcon.Off)
-
-        self.menu_save_as.setIcon(icon5)
-        self.menu_exit_dialog = QAction(MainWindow)
-        self.menu_exit_dialog.setObjectName("menu_exit_dialog")
+        icon = QtGui.QIcon.fromTheme("document-save-as")
+        self.menu_save_as.setIcon(icon)
+        self.menu_save_as.setObjectName("menu_save_as")
+        self.menu_exit_dialog = QtGui.QAction(parent=MainWindow)
         self.menu_exit_dialog.setCheckable(True)
         self.menu_exit_dialog.setChecked(True)
-        icon6 = QIcon()
-        iconThemeName = "view-close"
-        if QIcon.hasThemeIcon(iconThemeName):
-            icon6 = QIcon.fromTheme(iconThemeName)
-        else:
-            icon6.addFile("../../../.designer/backup", QSize(), QIcon.Normal, QIcon.Off)
-
-        self.menu_exit_dialog.setIcon(icon6)
-        self.menu_close_schedule = QAction(MainWindow)
-        self.menu_close_schedule.setObjectName("menu_close_schedule")
+        icon = QtGui.QIcon.fromTheme("view-close")
+        self.menu_exit_dialog.setIcon(icon)
+        self.menu_exit_dialog.setObjectName("menu_exit_dialog")
+        self.menu_close_schedule = QtGui.QAction(parent=MainWindow)
         self.menu_close_schedule.setEnabled(False)
-        self.menu_close_schedule.setIcon(icon6)
-        self.actionAbout = QAction(MainWindow)
+        icon = QtGui.QIcon.fromTheme("view-close")
+        self.menu_close_schedule.setIcon(icon)
+        self.menu_close_schedule.setObjectName("menu_close_schedule")
+        self.actionAbout = QtGui.QAction(parent=MainWindow)
         self.actionAbout.setObjectName("actionAbout")
-        self.actionDocumentation = QAction(MainWindow)
+        self.actionDocumentation = QtGui.QAction(parent=MainWindow)
         self.actionDocumentation.setObjectName("actionDocumentation")
-        self.actionReorder = QAction(MainWindow)
+        self.actionReorder = QtGui.QAction(parent=MainWindow)
         self.actionReorder.setObjectName("actionReorder")
-        self.actionPlot_schedule = QAction(MainWindow)
+        self.actionPlot_schedule = QtGui.QAction(parent=MainWindow)
         self.actionPlot_schedule.setObjectName("actionPlot_schedule")
-        self.action_view_variables = QAction(MainWindow)
-        self.action_view_variables.setObjectName("action_view_variables")
+        self.action_view_variables = QtGui.QAction(parent=MainWindow)
         self.action_view_variables.setEnabled(False)
-        self.action_view_port_accesses = QAction(MainWindow)
-        self.action_view_port_accesses.setObjectName("action_view_port_accesses")
+        self.action_view_variables.setObjectName("action_view_variables")
+        self.action_view_port_accesses = QtGui.QAction(parent=MainWindow)
         self.action_view_port_accesses.setEnabled(False)
-        self.actionUndo = QAction(MainWindow)
-        self.actionUndo.setObjectName("actionUndo")
+        self.action_view_port_accesses.setObjectName("action_view_port_accesses")
+        self.actionUndo = QtGui.QAction(parent=MainWindow)
         self.actionUndo.setEnabled(False)
-        self.actionRedo = QAction(MainWindow)
-        self.actionRedo.setObjectName("actionRedo")
+        self.actionUndo.setObjectName("actionUndo")
+        self.actionRedo = QtGui.QAction(parent=MainWindow)
         self.actionRedo.setEnabled(False)
-        self.actionIncrease_time_resolution = QAction(MainWindow)
-        self.actionIncrease_time_resolution.setObjectName(
-            "actionIncrease_time_resolution"
-        )
-        self.actionDecrease_time_resolution = QAction(MainWindow)
-        self.actionDecrease_time_resolution.setObjectName(
-            "actionDecrease_time_resolution"
-        )
-        self.actionZoom_to_fit = QAction(MainWindow)
+        self.actionRedo.setObjectName("actionRedo")
+        self.actionIncrease_time_resolution = QtGui.QAction(parent=MainWindow)
+        self.actionIncrease_time_resolution.setObjectName("actionIncrease_time_resolution")
+        self.actionDecrease_time_resolution = QtGui.QAction(parent=MainWindow)
+        self.actionDecrease_time_resolution.setObjectName("actionDecrease_time_resolution")
+        self.actionZoom_to_fit = QtGui.QAction(parent=MainWindow)
         self.actionZoom_to_fit.setObjectName("actionZoom_to_fit")
-        self.actionStatus_bar = QAction(MainWindow)
-        self.actionStatus_bar.setObjectName("actionStatus_bar")
+        self.actionStatus_bar = QtGui.QAction(parent=MainWindow)
         self.actionStatus_bar.setCheckable(True)
         self.actionStatus_bar.setChecked(True)
-        self.actionToolbar = QAction(MainWindow)
-        self.actionToolbar.setObjectName("actionToolbar")
+        self.actionStatus_bar.setObjectName("actionStatus_bar")
+        self.actionToolbar = QtGui.QAction(parent=MainWindow)
         self.actionToolbar.setCheckable(True)
         self.actionToolbar.setChecked(True)
-        self.action_show_port_numbers = QAction(MainWindow)
-        self.action_show_port_numbers.setObjectName("action_show_port_numbers")
+        self.actionToolbar.setObjectName("actionToolbar")
+        self.action_show_port_numbers = QtGui.QAction(parent=MainWindow)
         self.action_show_port_numbers.setCheckable(True)
         self.action_show_port_numbers.setChecked(False)
         self.action_show_port_numbers.setIconVisibleInMenu(False)
-        self.action_incorrect_execution_time = QAction(MainWindow)
-        self.action_incorrect_execution_time.setObjectName(
-            "action_incorrect_execution_time"
-        )
+        self.action_show_port_numbers.setObjectName("action_show_port_numbers")
+        self.action_incorrect_execution_time = QtGui.QAction(parent=MainWindow)
         self.action_incorrect_execution_time.setCheckable(True)
         self.action_incorrect_execution_time.setChecked(True)
         self.action_incorrect_execution_time.setIconVisibleInMenu(False)
-        self.menu_open = QAction(MainWindow)
+        self.action_incorrect_execution_time.setObjectName("action_incorrect_execution_time")
+        self.menu_open = QtGui.QAction(parent=MainWindow)
+        icon = QtGui.QIcon.fromTheme("personal")
+        self.menu_open.setIcon(icon)
         self.menu_open.setObjectName("menu_open")
-        icon7 = QIcon(QIcon.fromTheme("personal"))
-        self.menu_open.setIcon(icon7)
-        self.actionToggle_full_screen = QAction(MainWindow)
-        self.actionToggle_full_screen.setObjectName("actionToggle_full_screen")
+        self.actionToggle_full_screen = QtGui.QAction(parent=MainWindow)
         self.actionToggle_full_screen.setCheckable(True)
-        self.actionPreferences = QAction(MainWindow)
+        self.actionToggle_full_screen.setObjectName("actionToggle_full_screen")
+        self.actionPreferences = QtGui.QAction(parent=MainWindow)
+        icon = QtGui.QIcon.fromTheme("preferences-desktop-personal")
+        self.actionPreferences.setIcon(icon)
         self.actionPreferences.setObjectName("actionPreferences")
-        icon8 = QIcon(QIcon.fromTheme("preferences-desktop-personal"))
-        self.actionPreferences.setIcon(icon8)
-        self.centralwidget = QWidget(MainWindow)
-        self.centralwidget.setObjectName("centralwidget")
-        sizePolicy.setHeightForWidth(
-            self.centralwidget.sizePolicy().hasHeightForWidth()
-        )
-        self.centralwidget.setSizePolicy(sizePolicy)
-        self.horizontalLayout = QHBoxLayout(self.centralwidget)
-        self.horizontalLayout.setSpacing(0)
-        self.horizontalLayout.setObjectName("horizontalLayout")
-        self.horizontalLayout.setContentsMargins(0, 0, 0, 0)
-        self.splitter = QSplitter(self.centralwidget)
-        self.splitter.setObjectName("splitter")
-        self.splitter.setOrientation(Qt.Horizontal)
-        self.splitter.setHandleWidth(0)
-        self.view = QGraphicsView(self.splitter)
-        self.view.setObjectName("view")
-        self.view.setAlignment(Qt.AlignLeading | Qt.AlignLeft | Qt.AlignTop)
-        self.view.setRenderHints(QPainter.Antialiasing | QPainter.TextAntialiasing)
-        self.view.setViewportUpdateMode(QGraphicsView.FullViewportUpdate)
-        self.splitter.addWidget(self.view)
-        self.info_table = QTableWidget(self.splitter)
-        if self.info_table.columnCount() < 2:
-            self.info_table.setColumnCount(2)
-        font = QFont()
-        font.setBold(False)
-        font.setWeight(50)
-        __qtablewidgetitem = QTableWidgetItem()
-        __qtablewidgetitem.setTextAlignment(Qt.AlignLeading | Qt.AlignVCenter)
-        __qtablewidgetitem.setFont(font)
-        self.info_table.setHorizontalHeaderItem(0, __qtablewidgetitem)
-        __qtablewidgetitem1 = QTableWidgetItem()
-        __qtablewidgetitem1.setTextAlignment(Qt.AlignLeading | Qt.AlignVCenter)
-        self.info_table.setHorizontalHeaderItem(1, __qtablewidgetitem1)
-        if self.info_table.rowCount() < 2:
-            self.info_table.setRowCount(2)
-        __qtablewidgetitem2 = QTableWidgetItem()
-        self.info_table.setVerticalHeaderItem(0, __qtablewidgetitem2)
-        __qtablewidgetitem3 = QTableWidgetItem()
-        self.info_table.setVerticalHeaderItem(1, __qtablewidgetitem3)
-        brush = QBrush(QColor(255, 255, 255, 255))
-        brush.setStyle(Qt.SolidPattern)
-        brush1 = QBrush(QColor(160, 160, 164, 255))
-        brush1.setStyle(Qt.SolidPattern)
-        font1 = QFont()
-        font1.setBold(False)
-        font1.setWeight(50)
-        font1.setKerning(True)
-        __qtablewidgetitem4 = QTableWidgetItem()
-        __qtablewidgetitem4.setFont(font1)
-        __qtablewidgetitem4.setBackground(brush1)
-        __qtablewidgetitem4.setForeground(brush)
-        __qtablewidgetitem4.setFlags(
-            Qt.ItemIsSelectable
-            | Qt.ItemIsEditable
-            | Qt.ItemIsDragEnabled
-            | Qt.ItemIsDropEnabled
-            | Qt.ItemIsUserCheckable
-        )
-        self.info_table.setItem(0, 0, __qtablewidgetitem4)
-        __qtablewidgetitem5 = QTableWidgetItem()
-        __qtablewidgetitem5.setFont(font)
-        __qtablewidgetitem5.setBackground(brush1)
-        __qtablewidgetitem5.setForeground(brush)
-        __qtablewidgetitem5.setFlags(
-            Qt.ItemIsSelectable
-            | Qt.ItemIsEditable
-            | Qt.ItemIsDragEnabled
-            | Qt.ItemIsDropEnabled
-            | Qt.ItemIsUserCheckable
-        )
-        self.info_table.setItem(1, 0, __qtablewidgetitem5)
-        self.info_table.setObjectName("info_table")
-        self.info_table.setStyleSheet(
-            "alternate-background-color: #fadefb;background-color: #ebebeb;"
-        )
-        self.info_table.setEditTriggers(QAbstractItemView.NoEditTriggers)
-        self.info_table.setAlternatingRowColors(True)
-        self.info_table.setSelectionBehavior(QAbstractItemView.SelectRows)
-        self.info_table.setRowCount(2)
-        self.info_table.setColumnCount(2)
-        self.splitter.addWidget(self.info_table)
-        self.info_table.horizontalHeader().setHighlightSections(False)
-        self.info_table.horizontalHeader().setStretchLastSection(True)
-        self.info_table.verticalHeader().setVisible(False)
-        self.info_table.verticalHeader().setDefaultSectionSize(24)
-
-        self.horizontalLayout.addWidget(self.splitter)
-
-        MainWindow.setCentralWidget(self.centralwidget)
-        self.menubar = QMenuBar(MainWindow)
-        self.menubar.setObjectName("menubar")
-        self.menubar.setGeometry(QRect(0, 0, 800, 20))
-        self.menuFile = QMenu(self.menubar)
-        self.menuFile.setObjectName("menuFile")
-        self.menu_Recent_Schedule = QMenu(self.menuFile)
-        self.menu_Recent_Schedule.setObjectName("menu_Recent_Schedule")
-        self.menuView = QMenu(self.menubar)
-        self.menuView.setObjectName("menuView")
-        self.menu_view_execution_times = QMenu(self.menuView)
-        self.menu_view_execution_times.setObjectName("menu_view_execution_times")
-        self.menu_view_execution_times.setEnabled(False)
-        self.menu_Edit = QMenu(self.menubar)
-        self.menu_Edit.setObjectName("menu_Edit")
-        self.menuWindow = QMenu(self.menubar)
-        self.menuWindow.setObjectName("menuWindow")
-        self.menuHelp = QMenu(self.menubar)
-        self.menuHelp.setObjectName("menuHelp")
-        MainWindow.setMenuBar(self.menubar)
-        self.statusbar = QStatusBar(MainWindow)
-        self.statusbar.setObjectName("statusbar")
-        MainWindow.setStatusBar(self.statusbar)
-        self.toolBar = QToolBar(MainWindow)
-        self.toolBar.setObjectName("toolBar")
-        MainWindow.addToolBar(Qt.TopToolBarArea, self.toolBar)
-
-        self.menubar.addAction(self.menuFile.menuAction())
-        self.menubar.addAction(self.menu_Edit.menuAction())
-        self.menubar.addAction(self.menuView.menuAction())
-        self.menubar.addAction(self.menuWindow.menuAction())
-        self.menubar.addAction(self.menuHelp.menuAction())
         self.menuFile.addAction(self.menu_open)
         self.menuFile.addAction(self.menu_Recent_Schedule.menuAction())
         self.menuFile.addAction(self.menu_load_from_file)
@@ -322,6 +249,11 @@ class Ui_MainWindow:
         self.menuHelp.addAction(self.actionDocumentation)
         self.menuHelp.addSeparator()
         self.menuHelp.addAction(self.actionAbout)
+        self.menubar.addAction(self.menuFile.menuAction())
+        self.menubar.addAction(self.menu_Edit.menuAction())
+        self.menubar.addAction(self.menuView.menuAction())
+        self.menubar.addAction(self.menuWindow.menuAction())
+        self.menubar.addAction(self.menuHelp.menuAction())
         self.toolBar.addAction(self.menu_open)
         self.toolBar.addAction(self.menu_save)
         self.toolBar.addAction(self.menu_save_as)
@@ -335,300 +267,84 @@ class Ui_MainWindow:
         self.toolBar.addAction(self.actionReorder)
 
         self.retranslateUi(MainWindow)
-
-        QMetaObject.connectSlotsByName(MainWindow)
-
-    # setupUi
+        QtCore.QMetaObject.connectSlotsByName(MainWindow)
 
     def retranslateUi(self, MainWindow):
-        self.menu_load_from_file.setText(
-            QCoreApplication.translate(
-                "MainWindow", "&Import schedule from file...", None
-            )
-        )
-        # if QT_CONFIG(tooltip)
-        self.menu_load_from_file.setToolTip(
-            QCoreApplication.translate(
-                "MainWindow", "Import schedule from python script", None
-            )
-        )
-        # endif // QT_CONFIG(tooltip)
-        # if QT_CONFIG(statustip)
-        self.menu_load_from_file.setStatusTip("")
-        # endif // QT_CONFIG(statustip)
-        # if QT_CONFIG(shortcut)
-        self.menu_load_from_file.setShortcut(
-            QCoreApplication.translate("MainWindow", "Ctrl+I", None)
-        )
-        # endif // QT_CONFIG(shortcut)
-        self.menu_save.setText(QCoreApplication.translate("MainWindow", "&Save", None))
-        # if QT_CONFIG(tooltip)
-        self.menu_save.setToolTip(
-            QCoreApplication.translate("MainWindow", "Save schedule", None)
-        )
-        # endif // QT_CONFIG(tooltip)
-        # if QT_CONFIG(shortcut)
-        self.menu_save.setShortcut(
-            QCoreApplication.translate("MainWindow", "Ctrl+S", None)
-        )
-        # endif // QT_CONFIG(shortcut)
-        self.menu_node_info.setText(
-            QCoreApplication.translate("MainWindow", "&Node info", None)
-        )
-        # if QT_CONFIG(tooltip)
-        self.menu_node_info.setToolTip(
-            QCoreApplication.translate("MainWindow", "Show/hide node information", None)
-        )
-        # endif // QT_CONFIG(tooltip)
-        # if QT_CONFIG(shortcut)
-        self.menu_node_info.setShortcut(
-            QCoreApplication.translate("MainWindow", "Ctrl+N", None)
-        )
-        # endif // QT_CONFIG(shortcut)
-        self.menu_quit.setText(QCoreApplication.translate("MainWindow", "&Quit", None))
-        # if QT_CONFIG(shortcut)
-        self.menu_quit.setShortcut(
-            QCoreApplication.translate("MainWindow", "Ctrl+Q", None)
-        )
-        # endif // QT_CONFIG(shortcut)
-        self.menu_save_as.setText(
-            QCoreApplication.translate("MainWindow", "Save &as...", None)
-        )
-        # if QT_CONFIG(tooltip)
-        self.menu_save_as.setToolTip(
-            QCoreApplication.translate(
-                "MainWindow", "Save schedule with new file name", None
-            )
-        )
-        # endif // QT_CONFIG(tooltip)
-        # if QT_CONFIG(shortcut)
-        self.menu_save_as.setShortcut(
-            QCoreApplication.translate("MainWindow", "Ctrl+Shift+S", None)
-        )
-        # endif // QT_CONFIG(shortcut)
-        self.menu_exit_dialog.setText(
-            QCoreApplication.translate("MainWindow", "&Hide exit dialog", None)
-        )
-        # if QT_CONFIG(tooltip)
-        self.menu_exit_dialog.setToolTip(
-            QCoreApplication.translate("MainWindow", "Hide exit dialog", None)
-        )
-        # endif // QT_CONFIG(tooltip)
-        self.menu_close_schedule.setText(
-            QCoreApplication.translate("MainWindow", "&Close schedule", None)
-        )
-        # if QT_CONFIG(shortcut)
-        self.menu_close_schedule.setShortcut(
-            QCoreApplication.translate("MainWindow", "Ctrl+W", None)
-        )
-        # endif // QT_CONFIG(shortcut)
-        self.actionAbout.setText(
-            QCoreApplication.translate("MainWindow", "&About", None)
-        )
-        # if QT_CONFIG(tooltip)
-        self.actionAbout.setToolTip(
-            QCoreApplication.translate("MainWindow", "Open about window", None)
-        )
-        # endif // QT_CONFIG(tooltip)
-        self.actionDocumentation.setText(
-            QCoreApplication.translate("MainWindow", "&Documentation", None)
-        )
-        # if QT_CONFIG(tooltip)
-        self.actionDocumentation.setToolTip(
-            QCoreApplication.translate("MainWindow", "Open documentation", None)
-        )
-        # endif // QT_CONFIG(tooltip)
-        self.actionReorder.setText(
-            QCoreApplication.translate("MainWindow", "Reorder", None)
-        )
-        # if QT_CONFIG(tooltip)
-        self.actionReorder.setToolTip(
-            QCoreApplication.translate(
-                "MainWindow", "Reorder schedule based on start time", None
-            )
-        )
-        # endif // QT_CONFIG(tooltip)
-        # if QT_CONFIG(shortcut)
-        self.actionReorder.setShortcut(
-            QCoreApplication.translate("MainWindow", "Ctrl+R", None)
-        )
-        # endif // QT_CONFIG(shortcut)
-        self.actionPlot_schedule.setText(
-            QCoreApplication.translate("MainWindow", "&Plot schedule", None)
-        )
-        # if QT_CONFIG(tooltip)
-        self.actionPlot_schedule.setToolTip(
-            QCoreApplication.translate("MainWindow", "Plot schedule", None)
-        )
-        # endif // QT_CONFIG(tooltip)
-        self.action_view_variables.setText(
-            QCoreApplication.translate(
-                "MainWindow", "View execution times of variables", None
-            )
-        )
-        # if QT_CONFIG(tooltip)
-        self.action_view_variables.setToolTip(
-            QCoreApplication.translate("MainWindow", "View all variables", None)
-        )
-        # endif // QT_CONFIG(tooltip)
-        self.action_view_port_accesses.setText(
-            QCoreApplication.translate(
-                "MainWindow", "View port access statistics", None
-            )
-        )
-        # if QT_CONFIG(tooltip)
-        self.action_view_port_accesses.setToolTip(
-            QCoreApplication.translate(
-                "MainWindow", "View port access statistics for storage", None
-            )
-        )
-        # endif // QT_CONFIG(tooltip)
-        self.actionUndo.setText(QCoreApplication.translate("MainWindow", "Undo", None))
-        # if QT_CONFIG(shortcut)
-        self.actionUndo.setShortcut(
-            QCoreApplication.translate("MainWindow", "Ctrl+Z", None)
-        )
-        # endif // QT_CONFIG(shortcut)
-        self.actionRedo.setText(QCoreApplication.translate("MainWindow", "Redo", None))
-        # if QT_CONFIG(shortcut)
-        self.actionRedo.setShortcut(
-            QCoreApplication.translate("MainWindow", "Ctrl+Y, Ctrl+Shift+Z", None)
-        )
-        # endif // QT_CONFIG(shortcut)
-        self.actionIncrease_time_resolution.setText(
-            QCoreApplication.translate(
-                "MainWindow", "Increase time resolution...", None
-            )
-        )
-        self.actionDecrease_time_resolution.setText(
-            QCoreApplication.translate(
-                "MainWindow", "Decrease time resolution...", None
-            )
-        )
-        self.actionZoom_to_fit.setText(
-            QCoreApplication.translate("MainWindow", "Zoom to &fit", None)
-        )
-        self.actionStatus_bar.setText(
-            QCoreApplication.translate("MainWindow", "&Status bar", None)
-        )
-        # if QT_CONFIG(tooltip)
-        self.actionStatus_bar.setToolTip(
-            QCoreApplication.translate("MainWindow", "Show/hide status bar", None)
-        )
-        # endif // QT_CONFIG(tooltip)
-        self.actionToolbar.setText(
-            QCoreApplication.translate("MainWindow", "&Toolbar", None)
-        )
-        # if QT_CONFIG(tooltip)
-        self.actionToolbar.setToolTip(
-            QCoreApplication.translate("MainWindow", "Show/hide toolbar", None)
-        )
-        # endif // QT_CONFIG(tooltip)
-        self.action_show_port_numbers.setText(
-            QCoreApplication.translate("MainWindow", "S&how port numbers", None)
-        )
-        # if QT_CONFIG(tooltip)
-        self.action_show_port_numbers.setToolTip(
-            QCoreApplication.translate(
-                "MainWindow", "Show port numbers of operation", None
-            )
-        )
-        # endif // QT_CONFIG(tooltip)
-        self.action_incorrect_execution_time.setText(
-            QCoreApplication.translate("MainWindow", "&Incorrect execution time", None)
-        )
-        # if QT_CONFIG(tooltip)
-        self.action_incorrect_execution_time.setToolTip(
-            QCoreApplication.translate(
-                "MainWindow",
-                "Highlight processes with execution time longer than schedule time",
-                None,
-            )
-        )
-        # endif // QT_CONFIG(tooltip)
-        self.menu_open.setText(
-            QCoreApplication.translate("MainWindow", "&Open...", None)
-        )
-        # if QT_CONFIG(tooltip)
-        self.menu_open.setToolTip(
-            QCoreApplication.translate(
-                "MainWindow", "Open previously saved schedule", None
-            )
-        )
-        # endif // QT_CONFIG(tooltip)
-        # if QT_CONFIG(shortcut)
-        self.menu_open.setShortcut(
-            QCoreApplication.translate("MainWindow", "Ctrl+O", None)
-        )
-        # endif // QT_CONFIG(shortcut)
-        self.actionToggle_full_screen.setText(
-            QCoreApplication.translate("MainWindow", "Toggle f&ull screen", None)
-        )
-        # if QT_CONFIG(shortcut)
-        self.actionToggle_full_screen.setShortcut(
-            QCoreApplication.translate("MainWindow", "F11", None)
-        )
-        # endif // QT_CONFIG(shortcut)
-        self.actionPreferences.setText(
-            QCoreApplication.translate("MainWindow", "Preferences", None)
-        )
-        # if QT_CONFIG(tooltip)
-        self.actionPreferences.setToolTip(
-            QCoreApplication.translate("MainWindow", "Color and Fonts", None)
-        )
-        # endif // QT_CONFIG(tooltip)
-        # if QT_CONFIG(shortcut)
-        self.actionPreferences.setShortcut(
-            QCoreApplication.translate("MainWindow", "Ctrl+M", None)
-        )
-        # endif // QT_CONFIG(shortcut)
-        ___qtablewidgetitem = self.info_table.horizontalHeaderItem(0)
-        ___qtablewidgetitem.setText(
-            QCoreApplication.translate("MainWindow", "Property", None)
-        )
-        ___qtablewidgetitem1 = self.info_table.horizontalHeaderItem(1)
-        ___qtablewidgetitem1.setText(
-            QCoreApplication.translate("MainWindow", "Value", None)
-        )
-        ___qtablewidgetitem2 = self.info_table.verticalHeaderItem(0)
-        ___qtablewidgetitem2.setText(
-            QCoreApplication.translate("MainWindow", "1", None)
-        )
-        ___qtablewidgetitem3 = self.info_table.verticalHeaderItem(1)
-        ___qtablewidgetitem3.setText(
-            QCoreApplication.translate("MainWindow", "2", None)
-        )
-
+        _translate = QtCore.QCoreApplication.translate
+        item = self.info_table.verticalHeaderItem(0)
+        item.setText(_translate("MainWindow", "1"))
+        item = self.info_table.verticalHeaderItem(1)
+        item.setText(_translate("MainWindow", "2"))
+        item = self.info_table.horizontalHeaderItem(0)
+        item.setText(_translate("MainWindow", "Property"))
+        item = self.info_table.horizontalHeaderItem(1)
+        item.setText(_translate("MainWindow", "Value"))
         __sortingEnabled = self.info_table.isSortingEnabled()
         self.info_table.setSortingEnabled(False)
-        ___qtablewidgetitem4 = self.info_table.item(0, 0)
-        ___qtablewidgetitem4.setText(
-            QCoreApplication.translate("MainWindow", "Schedule", None)
-        )
-        ___qtablewidgetitem5 = self.info_table.item(1, 0)
-        ___qtablewidgetitem5.setText(
-            QCoreApplication.translate("MainWindow", "Operator", None)
-        )
+        item = self.info_table.item(0, 0)
+        item.setText(_translate("MainWindow", "Schedule"))
+        item = self.info_table.item(1, 0)
+        item.setText(_translate("MainWindow", "Operator"))
         self.info_table.setSortingEnabled(__sortingEnabled)
-
-        self.menuFile.setTitle(QCoreApplication.translate("MainWindow", "&File", None))
-        self.menu_Recent_Schedule.setTitle(
-            QCoreApplication.translate("MainWindow", "Open &recent", None)
-        )
-        self.menuView.setTitle(QCoreApplication.translate("MainWindow", "&View", None))
-        self.menu_view_execution_times.setTitle(
-            QCoreApplication.translate(
-                "MainWindow", "View execution times of type", None
-            )
-        )
-        self.menu_Edit.setTitle(QCoreApplication.translate("MainWindow", "&Edit", None))
-        self.menuWindow.setTitle(
-            QCoreApplication.translate("MainWindow", "&Window", None)
-        )
-        self.menuHelp.setTitle(QCoreApplication.translate("MainWindow", "&Help", None))
-        self.toolBar.setWindowTitle(
-            QCoreApplication.translate("MainWindow", "toolBar", None)
-        )
-        pass
-
-    # retranslateUi
+        self.menuFile.setTitle(_translate("MainWindow", "&File"))
+        self.menu_Recent_Schedule.setTitle(_translate("MainWindow", "Open &recent"))
+        self.menuView.setTitle(_translate("MainWindow", "&View"))
+        self.menu_view_execution_times.setTitle(_translate("MainWindow", "View execution times of type"))
+        self.menu_Edit.setTitle(_translate("MainWindow", "&Edit"))
+        self.menuWindow.setTitle(_translate("MainWindow", "&Window"))
+        self.menuHelp.setTitle(_translate("MainWindow", "&Help"))
+        self.toolBar.setWindowTitle(_translate("MainWindow", "toolBar"))
+        self.menu_load_from_file.setText(_translate("MainWindow", "&Import schedule from file..."))
+        self.menu_load_from_file.setToolTip(_translate("MainWindow", "Import schedule from python script"))
+        self.menu_load_from_file.setShortcut(_translate("MainWindow", "Ctrl+I"))
+        self.menu_save.setText(_translate("MainWindow", "&Save"))
+        self.menu_save.setToolTip(_translate("MainWindow", "Save schedule"))
+        self.menu_save.setShortcut(_translate("MainWindow", "Ctrl+S"))
+        self.menu_node_info.setText(_translate("MainWindow", "&Node info"))
+        self.menu_node_info.setToolTip(_translate("MainWindow", "Show/hide node information"))
+        self.menu_node_info.setShortcut(_translate("MainWindow", "Ctrl+N"))
+        self.menu_quit.setText(_translate("MainWindow", "&Quit"))
+        self.menu_quit.setShortcut(_translate("MainWindow", "Ctrl+Q"))
+        self.menu_save_as.setText(_translate("MainWindow", "Save &as..."))
+        self.menu_save_as.setToolTip(_translate("MainWindow", "Save schedule with new file name"))
+        self.menu_save_as.setShortcut(_translate("MainWindow", "Ctrl+Shift+S"))
+        self.menu_exit_dialog.setText(_translate("MainWindow", "&Hide exit dialog"))
+        self.menu_exit_dialog.setToolTip(_translate("MainWindow", "Hide exit dialog"))
+        self.menu_close_schedule.setText(_translate("MainWindow", "&Close schedule"))
+        self.menu_close_schedule.setShortcut(_translate("MainWindow", "Ctrl+W"))
+        self.actionAbout.setText(_translate("MainWindow", "&About"))
+        self.actionAbout.setToolTip(_translate("MainWindow", "Open about window"))
+        self.actionDocumentation.setText(_translate("MainWindow", "&Documentation"))
+        self.actionDocumentation.setToolTip(_translate("MainWindow", "Open documentation"))
+        self.actionReorder.setText(_translate("MainWindow", "Reorder"))
+        self.actionReorder.setToolTip(_translate("MainWindow", "Reorder schedule based on start time"))
+        self.actionReorder.setShortcut(_translate("MainWindow", "Ctrl+R"))
+        self.actionPlot_schedule.setText(_translate("MainWindow", "&Plot schedule"))
+        self.actionPlot_schedule.setToolTip(_translate("MainWindow", "Plot schedule"))
+        self.action_view_variables.setText(_translate("MainWindow", "View execution times of variables"))
+        self.action_view_variables.setToolTip(_translate("MainWindow", "View all variables"))
+        self.action_view_port_accesses.setText(_translate("MainWindow", "View port access statistics"))
+        self.action_view_port_accesses.setToolTip(_translate("MainWindow", "View port access statistics for storage"))
+        self.actionUndo.setText(_translate("MainWindow", "Undo"))
+        self.actionUndo.setShortcut(_translate("MainWindow", "Ctrl+Z"))
+        self.actionRedo.setText(_translate("MainWindow", "Redo"))
+        self.actionRedo.setShortcut(_translate("MainWindow", "Ctrl+Y, Ctrl+Shift+Z"))
+        self.actionIncrease_time_resolution.setText(_translate("MainWindow", "Increase time resolution..."))
+        self.actionDecrease_time_resolution.setText(_translate("MainWindow", "Decrease time resolution..."))
+        self.actionZoom_to_fit.setText(_translate("MainWindow", "Zoom to &fit"))
+        self.actionStatus_bar.setText(_translate("MainWindow", "&Status bar"))
+        self.actionStatus_bar.setToolTip(_translate("MainWindow", "Show/hide status bar"))
+        self.actionToolbar.setText(_translate("MainWindow", "&Toolbar"))
+        self.actionToolbar.setToolTip(_translate("MainWindow", "Show/hide toolbar"))
+        self.action_show_port_numbers.setText(_translate("MainWindow", "S&how port numbers"))
+        self.action_show_port_numbers.setToolTip(_translate("MainWindow", "Show port numbers of operation"))
+        self.action_incorrect_execution_time.setText(_translate("MainWindow", "&Incorrect execution time"))
+        self.action_incorrect_execution_time.setToolTip(_translate("MainWindow", "Highlight processes with execution time longer than schedule time"))
+        self.menu_open.setText(_translate("MainWindow", "&Open..."))
+        self.menu_open.setToolTip(_translate("MainWindow", "Open previously saved schedule"))
+        self.menu_open.setShortcut(_translate("MainWindow", "Ctrl+O"))
+        self.actionToggle_full_screen.setText(_translate("MainWindow", "Toggle f&ull screen"))
+        self.actionToggle_full_screen.setShortcut(_translate("MainWindow", "F11"))
+        self.actionPreferences.setText(_translate("MainWindow", "Preferences"))
+        self.actionPreferences.setToolTip(_translate("MainWindow", "Color and Fonts"))
+        self.actionPreferences.setShortcut(_translate("MainWindow", "Ctrl+M"))
-- 
GitLab


From bf03b089c551e8177ccc78bc45e39cc8cd96f4ed Mon Sep 17 00:00:00 2001
From: Simon Bjurek <simbj106@student.liu.se>
Date: Wed, 22 Jan 2025 15:53:13 +0100
Subject: [PATCH 02/21] fixes from last time, also ran post-commit on all files

---
 b_asic/scheduler_gui/main_window.py    |   8 +-
 b_asic/scheduler_gui/ui_main_window.py | 180 +++++++++++++++++++------
 2 files changed, 144 insertions(+), 44 deletions(-)

diff --git a/b_asic/scheduler_gui/main_window.py b/b_asic/scheduler_gui/main_window.py
index 4de6e4cd..f4502f99 100644
--- a/b_asic/scheduler_gui/main_window.py
+++ b/b_asic/scheduler_gui/main_window.py
@@ -98,9 +98,9 @@ if __debug__:
     log.debug(f"Qt version (compile time): {QtCore.__version__}")
     log.debug(f"QT_API:                    {QT_API}")
     if QT_API.lower().startswith("pyside"):
-        import PySide6
+        import PySide2
 
-        log.debug(f"PySide version:           {PySide6.__version__}")
+        log.debug(f"PySide version:           {PySide2.__version__}")
     if QT_API.lower().startswith("pyqt"):
         from qtpy.QtCore import PYQT_VERSION_STR
 
@@ -1694,8 +1694,8 @@ def start_scheduler(schedule: Optional[Schedule] = None) -> Optional[Schedule]:
         palette.setColor(QPalette.ColorRole.Window, QtCore.Qt.white)
         palette.setColor(QPalette.ColorRole.WindowText, QtCore.Qt.black)
         palette.setColor(QPalette.ColorRole.ButtonText, QtCore.Qt.black)
-        palette.setColor(QPalette.ColorRole.Base, QtCore.Qt.white) 
-        palette.setColor(QPalette.ColorRole.AlternateBase, QtCore.Qt.lightGray) 
+        palette.setColor(QPalette.ColorRole.Base, QtCore.Qt.white)
+        palette.setColor(QPalette.ColorRole.AlternateBase, QtCore.Qt.lightGray)
         palette.setColor(QPalette.ColorRole.Text, QtCore.Qt.black)
         app.setPalette(palette)
     else:
diff --git a/b_asic/scheduler_gui/ui_main_window.py b/b_asic/scheduler_gui/ui_main_window.py
index 7def5879..ad3fa898 100644
--- a/b_asic/scheduler_gui/ui_main_window.py
+++ b/b_asic/scheduler_gui/ui_main_window.py
@@ -9,23 +9,35 @@
 from qtpy import QtCore, QtGui, QtWidgets
 
 
-class Ui_MainWindow(object):
+class Ui_MainWindow:
     def setupUi(self, MainWindow):
         MainWindow.setObjectName("MainWindow")
         MainWindow.resize(800, 600)
-        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Preferred, QtWidgets.QSizePolicy.Policy.Preferred)
+        sizePolicy = QtWidgets.QSizePolicy(
+            QtWidgets.QSizePolicy.Policy.Preferred,
+            QtWidgets.QSizePolicy.Policy.Preferred,
+        )
         sizePolicy.setHorizontalStretch(0)
         sizePolicy.setVerticalStretch(0)
         sizePolicy.setHeightForWidth(MainWindow.sizePolicy().hasHeightForWidth())
         MainWindow.setSizePolicy(sizePolicy)
         icon = QtGui.QIcon()
-        icon.addPixmap(QtGui.QPixmap(":/icons/basic/small_logo.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)
+        icon.addPixmap(
+            QtGui.QPixmap(":/icons/basic/small_logo.png"),
+            QtGui.QIcon.Mode.Normal,
+            QtGui.QIcon.State.Off,
+        )
         MainWindow.setWindowIcon(icon)
         self.centralwidget = QtWidgets.QWidget(parent=MainWindow)
-        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Preferred, QtWidgets.QSizePolicy.Policy.Preferred)
+        sizePolicy = QtWidgets.QSizePolicy(
+            QtWidgets.QSizePolicy.Policy.Preferred,
+            QtWidgets.QSizePolicy.Policy.Preferred,
+        )
         sizePolicy.setHorizontalStretch(0)
         sizePolicy.setVerticalStretch(0)
-        sizePolicy.setHeightForWidth(self.centralwidget.sizePolicy().hasHeightForWidth())
+        sizePolicy.setHeightForWidth(
+            self.centralwidget.sizePolicy().hasHeightForWidth()
+        )
         self.centralwidget.setSizePolicy(sizePolicy)
         self.centralwidget.setObjectName("centralwidget")
         self.horizontalLayout = QtWidgets.QHBoxLayout(self.centralwidget)
@@ -37,15 +49,30 @@ class Ui_MainWindow(object):
         self.splitter.setHandleWidth(0)
         self.splitter.setObjectName("splitter")
         self.view = QtWidgets.QGraphicsView(parent=self.splitter)
-        self.view.setAlignment(QtCore.Qt.AlignmentFlag.AlignLeading|QtCore.Qt.AlignmentFlag.AlignLeft|QtCore.Qt.AlignmentFlag.AlignTop)
-        self.view.setRenderHints(QtGui.QPainter.RenderHint.Antialiasing|QtGui.QPainter.RenderHint.TextAntialiasing)
-        self.view.setViewportUpdateMode(QtWidgets.QGraphicsView.ViewportUpdateMode.FullViewportUpdate)
+        self.view.setAlignment(
+            QtCore.Qt.AlignmentFlag.AlignLeading
+            | QtCore.Qt.AlignmentFlag.AlignLeft
+            | QtCore.Qt.AlignmentFlag.AlignTop
+        )
+        self.view.setRenderHints(
+            QtGui.QPainter.RenderHint.Antialiasing
+            | QtGui.QPainter.RenderHint.TextAntialiasing
+        )
+        self.view.setViewportUpdateMode(
+            QtWidgets.QGraphicsView.ViewportUpdateMode.FullViewportUpdate
+        )
         self.view.setObjectName("view")
         self.info_table = QtWidgets.QTableWidget(parent=self.splitter)
-        self.info_table.setStyleSheet("alternate-background-color: #fadefb;background-color: #ebebeb;")
-        self.info_table.setEditTriggers(QtWidgets.QAbstractItemView.EditTrigger.NoEditTriggers)
+        self.info_table.setStyleSheet(
+            "alternate-background-color: #fadefb;background-color: #ebebeb;"
+        )
+        self.info_table.setEditTriggers(
+            QtWidgets.QAbstractItemView.EditTrigger.NoEditTriggers
+        )
         self.info_table.setAlternatingRowColors(True)
-        self.info_table.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectionBehavior.SelectRows)
+        self.info_table.setSelectionBehavior(
+            QtWidgets.QAbstractItemView.SelectionBehavior.SelectRows
+        )
         self.info_table.setRowCount(2)
         self.info_table.setColumnCount(2)
         self.info_table.setObjectName("info_table")
@@ -54,14 +81,18 @@ class Ui_MainWindow(object):
         item = QtWidgets.QTableWidgetItem()
         self.info_table.setVerticalHeaderItem(1, item)
         item = QtWidgets.QTableWidgetItem()
-        item.setTextAlignment(QtCore.Qt.AlignmentFlag.AlignLeading|QtCore.Qt.AlignmentFlag.AlignVCenter)
+        item.setTextAlignment(
+            QtCore.Qt.AlignmentFlag.AlignLeading | QtCore.Qt.AlignmentFlag.AlignVCenter
+        )
         font = QtGui.QFont()
         font.setBold(False)
         font.setWeight(50)
         item.setFont(font)
         self.info_table.setHorizontalHeaderItem(0, item)
         item = QtWidgets.QTableWidgetItem()
-        item.setTextAlignment(QtCore.Qt.AlignmentFlag.AlignLeading|QtCore.Qt.AlignmentFlag.AlignVCenter)
+        item.setTextAlignment(
+            QtCore.Qt.AlignmentFlag.AlignLeading | QtCore.Qt.AlignmentFlag.AlignVCenter
+        )
         self.info_table.setHorizontalHeaderItem(1, item)
         item = QtWidgets.QTableWidgetItem()
         font = QtGui.QFont()
@@ -75,7 +106,13 @@ class Ui_MainWindow(object):
         brush = QtGui.QBrush(QtGui.QColor(255, 255, 255))
         brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern)
         item.setForeground(brush)
-        item.setFlags(QtCore.Qt.ItemFlag.ItemIsSelectable|QtCore.Qt.ItemFlag.ItemIsEditable|QtCore.Qt.ItemFlag.ItemIsDragEnabled|QtCore.Qt.ItemFlag.ItemIsDropEnabled|QtCore.Qt.ItemFlag.ItemIsUserCheckable)
+        item.setFlags(
+            QtCore.Qt.ItemFlag.ItemIsSelectable
+            | QtCore.Qt.ItemFlag.ItemIsEditable
+            | QtCore.Qt.ItemFlag.ItemIsDragEnabled
+            | QtCore.Qt.ItemFlag.ItemIsDropEnabled
+            | QtCore.Qt.ItemFlag.ItemIsUserCheckable
+        )
         self.info_table.setItem(0, 0, item)
         item = QtWidgets.QTableWidgetItem()
         font = QtGui.QFont()
@@ -88,7 +125,13 @@ class Ui_MainWindow(object):
         brush = QtGui.QBrush(QtGui.QColor(255, 255, 255))
         brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern)
         item.setForeground(brush)
-        item.setFlags(QtCore.Qt.ItemFlag.ItemIsSelectable|QtCore.Qt.ItemFlag.ItemIsEditable|QtCore.Qt.ItemFlag.ItemIsDragEnabled|QtCore.Qt.ItemFlag.ItemIsDropEnabled|QtCore.Qt.ItemFlag.ItemIsUserCheckable)
+        item.setFlags(
+            QtCore.Qt.ItemFlag.ItemIsSelectable
+            | QtCore.Qt.ItemFlag.ItemIsEditable
+            | QtCore.Qt.ItemFlag.ItemIsDragEnabled
+            | QtCore.Qt.ItemFlag.ItemIsDropEnabled
+            | QtCore.Qt.ItemFlag.ItemIsUserCheckable
+        )
         self.info_table.setItem(1, 0, item)
         self.info_table.horizontalHeader().setHighlightSections(False)
         self.info_table.horizontalHeader().setStretchLastSection(True)
@@ -135,8 +178,16 @@ class Ui_MainWindow(object):
         self.menu_node_info.setCheckable(True)
         self.menu_node_info.setChecked(True)
         icon1 = QtGui.QIcon()
-        icon1.addPixmap(QtGui.QPixmap(":/icons/misc/right_panel.svg"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)
-        icon1.addPixmap(QtGui.QPixmap(":/icons/misc/right_filled_panel.svg"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.On)
+        icon1.addPixmap(
+            QtGui.QPixmap(":/icons/misc/right_panel.svg"),
+            QtGui.QIcon.Mode.Normal,
+            QtGui.QIcon.State.Off,
+        )
+        icon1.addPixmap(
+            QtGui.QPixmap(":/icons/misc/right_filled_panel.svg"),
+            QtGui.QIcon.Mode.Normal,
+            QtGui.QIcon.State.On,
+        )
         self.menu_node_info.setIcon(icon1)
         self.menu_node_info.setIconVisibleInMenu(False)
         self.menu_node_info.setObjectName("menu_node_info")
@@ -181,9 +232,13 @@ class Ui_MainWindow(object):
         self.actionRedo.setEnabled(False)
         self.actionRedo.setObjectName("actionRedo")
         self.actionIncrease_time_resolution = QtGui.QAction(parent=MainWindow)
-        self.actionIncrease_time_resolution.setObjectName("actionIncrease_time_resolution")
+        self.actionIncrease_time_resolution.setObjectName(
+            "actionIncrease_time_resolution"
+        )
         self.actionDecrease_time_resolution = QtGui.QAction(parent=MainWindow)
-        self.actionDecrease_time_resolution.setObjectName("actionDecrease_time_resolution")
+        self.actionDecrease_time_resolution.setObjectName(
+            "actionDecrease_time_resolution"
+        )
         self.actionZoom_to_fit = QtGui.QAction(parent=MainWindow)
         self.actionZoom_to_fit.setObjectName("actionZoom_to_fit")
         self.actionStatus_bar = QtGui.QAction(parent=MainWindow)
@@ -203,7 +258,9 @@ class Ui_MainWindow(object):
         self.action_incorrect_execution_time.setCheckable(True)
         self.action_incorrect_execution_time.setChecked(True)
         self.action_incorrect_execution_time.setIconVisibleInMenu(False)
-        self.action_incorrect_execution_time.setObjectName("action_incorrect_execution_time")
+        self.action_incorrect_execution_time.setObjectName(
+            "action_incorrect_execution_time"
+        )
         self.menu_open = QtGui.QAction(parent=MainWindow)
         icon = QtGui.QIcon.fromTheme("personal")
         self.menu_open.setIcon(icon)
@@ -289,24 +346,34 @@ class Ui_MainWindow(object):
         self.menuFile.setTitle(_translate("MainWindow", "&File"))
         self.menu_Recent_Schedule.setTitle(_translate("MainWindow", "Open &recent"))
         self.menuView.setTitle(_translate("MainWindow", "&View"))
-        self.menu_view_execution_times.setTitle(_translate("MainWindow", "View execution times of type"))
+        self.menu_view_execution_times.setTitle(
+            _translate("MainWindow", "View execution times of type")
+        )
         self.menu_Edit.setTitle(_translate("MainWindow", "&Edit"))
         self.menuWindow.setTitle(_translate("MainWindow", "&Window"))
         self.menuHelp.setTitle(_translate("MainWindow", "&Help"))
         self.toolBar.setWindowTitle(_translate("MainWindow", "toolBar"))
-        self.menu_load_from_file.setText(_translate("MainWindow", "&Import schedule from file..."))
-        self.menu_load_from_file.setToolTip(_translate("MainWindow", "Import schedule from python script"))
+        self.menu_load_from_file.setText(
+            _translate("MainWindow", "&Import schedule from file...")
+        )
+        self.menu_load_from_file.setToolTip(
+            _translate("MainWindow", "Import schedule from python script")
+        )
         self.menu_load_from_file.setShortcut(_translate("MainWindow", "Ctrl+I"))
         self.menu_save.setText(_translate("MainWindow", "&Save"))
         self.menu_save.setToolTip(_translate("MainWindow", "Save schedule"))
         self.menu_save.setShortcut(_translate("MainWindow", "Ctrl+S"))
         self.menu_node_info.setText(_translate("MainWindow", "&Node info"))
-        self.menu_node_info.setToolTip(_translate("MainWindow", "Show/hide node information"))
+        self.menu_node_info.setToolTip(
+            _translate("MainWindow", "Show/hide node information")
+        )
         self.menu_node_info.setShortcut(_translate("MainWindow", "Ctrl+N"))
         self.menu_quit.setText(_translate("MainWindow", "&Quit"))
         self.menu_quit.setShortcut(_translate("MainWindow", "Ctrl+Q"))
         self.menu_save_as.setText(_translate("MainWindow", "Save &as..."))
-        self.menu_save_as.setToolTip(_translate("MainWindow", "Save schedule with new file name"))
+        self.menu_save_as.setToolTip(
+            _translate("MainWindow", "Save schedule with new file name")
+        )
         self.menu_save_as.setShortcut(_translate("MainWindow", "Ctrl+Shift+S"))
         self.menu_exit_dialog.setText(_translate("MainWindow", "&Hide exit dialog"))
         self.menu_exit_dialog.setToolTip(_translate("MainWindow", "Hide exit dialog"))
@@ -315,35 +382,68 @@ class Ui_MainWindow(object):
         self.actionAbout.setText(_translate("MainWindow", "&About"))
         self.actionAbout.setToolTip(_translate("MainWindow", "Open about window"))
         self.actionDocumentation.setText(_translate("MainWindow", "&Documentation"))
-        self.actionDocumentation.setToolTip(_translate("MainWindow", "Open documentation"))
+        self.actionDocumentation.setToolTip(
+            _translate("MainWindow", "Open documentation")
+        )
         self.actionReorder.setText(_translate("MainWindow", "Reorder"))
-        self.actionReorder.setToolTip(_translate("MainWindow", "Reorder schedule based on start time"))
+        self.actionReorder.setToolTip(
+            _translate("MainWindow", "Reorder schedule based on start time")
+        )
         self.actionReorder.setShortcut(_translate("MainWindow", "Ctrl+R"))
         self.actionPlot_schedule.setText(_translate("MainWindow", "&Plot schedule"))
         self.actionPlot_schedule.setToolTip(_translate("MainWindow", "Plot schedule"))
-        self.action_view_variables.setText(_translate("MainWindow", "View execution times of variables"))
-        self.action_view_variables.setToolTip(_translate("MainWindow", "View all variables"))
-        self.action_view_port_accesses.setText(_translate("MainWindow", "View port access statistics"))
-        self.action_view_port_accesses.setToolTip(_translate("MainWindow", "View port access statistics for storage"))
+        self.action_view_variables.setText(
+            _translate("MainWindow", "View execution times of variables")
+        )
+        self.action_view_variables.setToolTip(
+            _translate("MainWindow", "View all variables")
+        )
+        self.action_view_port_accesses.setText(
+            _translate("MainWindow", "View port access statistics")
+        )
+        self.action_view_port_accesses.setToolTip(
+            _translate("MainWindow", "View port access statistics for storage")
+        )
         self.actionUndo.setText(_translate("MainWindow", "Undo"))
         self.actionUndo.setShortcut(_translate("MainWindow", "Ctrl+Z"))
         self.actionRedo.setText(_translate("MainWindow", "Redo"))
         self.actionRedo.setShortcut(_translate("MainWindow", "Ctrl+Y, Ctrl+Shift+Z"))
-        self.actionIncrease_time_resolution.setText(_translate("MainWindow", "Increase time resolution..."))
-        self.actionDecrease_time_resolution.setText(_translate("MainWindow", "Decrease time resolution..."))
+        self.actionIncrease_time_resolution.setText(
+            _translate("MainWindow", "Increase time resolution...")
+        )
+        self.actionDecrease_time_resolution.setText(
+            _translate("MainWindow", "Decrease time resolution...")
+        )
         self.actionZoom_to_fit.setText(_translate("MainWindow", "Zoom to &fit"))
         self.actionStatus_bar.setText(_translate("MainWindow", "&Status bar"))
-        self.actionStatus_bar.setToolTip(_translate("MainWindow", "Show/hide status bar"))
+        self.actionStatus_bar.setToolTip(
+            _translate("MainWindow", "Show/hide status bar")
+        )
         self.actionToolbar.setText(_translate("MainWindow", "&Toolbar"))
         self.actionToolbar.setToolTip(_translate("MainWindow", "Show/hide toolbar"))
-        self.action_show_port_numbers.setText(_translate("MainWindow", "S&how port numbers"))
-        self.action_show_port_numbers.setToolTip(_translate("MainWindow", "Show port numbers of operation"))
-        self.action_incorrect_execution_time.setText(_translate("MainWindow", "&Incorrect execution time"))
-        self.action_incorrect_execution_time.setToolTip(_translate("MainWindow", "Highlight processes with execution time longer than schedule time"))
+        self.action_show_port_numbers.setText(
+            _translate("MainWindow", "S&how port numbers")
+        )
+        self.action_show_port_numbers.setToolTip(
+            _translate("MainWindow", "Show port numbers of operation")
+        )
+        self.action_incorrect_execution_time.setText(
+            _translate("MainWindow", "&Incorrect execution time")
+        )
+        self.action_incorrect_execution_time.setToolTip(
+            _translate(
+                "MainWindow",
+                "Highlight processes with execution time longer than schedule time",
+            )
+        )
         self.menu_open.setText(_translate("MainWindow", "&Open..."))
-        self.menu_open.setToolTip(_translate("MainWindow", "Open previously saved schedule"))
+        self.menu_open.setToolTip(
+            _translate("MainWindow", "Open previously saved schedule")
+        )
         self.menu_open.setShortcut(_translate("MainWindow", "Ctrl+O"))
-        self.actionToggle_full_screen.setText(_translate("MainWindow", "Toggle f&ull screen"))
+        self.actionToggle_full_screen.setText(
+            _translate("MainWindow", "Toggle f&ull screen")
+        )
         self.actionToggle_full_screen.setShortcut(_translate("MainWindow", "F11"))
         self.actionPreferences.setText(_translate("MainWindow", "Preferences"))
         self.actionPreferences.setToolTip(_translate("MainWindow", "Color and Fonts"))
-- 
GitLab


From 6fd1f5f987fc6c190e7ce40c6822d080c26d8e3f Mon Sep 17 00:00:00 2001
From: Simon Bjurek <simbj106@student.liu.se>
Date: Wed, 22 Jan 2025 15:03:18 +0000
Subject: [PATCH 03/21] Update .gitlab-ci.yml file

---
 .gitlab-ci.yml | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 32946f44..2e59a32d 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -91,6 +91,12 @@ run-test-3.12-pyqt5:
   image: python:3.12
   extends: ".run-test"
 
+run-test-3.12-pyqt6:
+  variables:
+    QT_API: pyqt6
+  image: python:3.12
+  extends: ".run-test"
+
 # Seemingly works with Qt6, but tests stall on closing scheduler GUI due to modal dialog(?)
 #run-test-3.10-pyside6:
 #  variables:
-- 
GitLab


From 97342c36a63c7917c270d18ef84e071fbedb4585 Mon Sep 17 00:00:00 2001
From: Simon Bjurek <simbj106@student.liu.se>
Date: Thu, 23 Jan 2025 16:11:05 +0100
Subject: [PATCH 04/21] moved alap and asap to seperate class and changed some
 of the code

---
 b_asic/schedule.py             | 386 +++++++++++++++++++++++----------
 b_asic/scheduling_algorithm.py |   8 +
 2 files changed, 274 insertions(+), 120 deletions(-)
 create mode 100644 b_asic/scheduling_algorithm.py

diff --git a/b_asic/schedule.py b/b_asic/schedule.py
index 4b34d580..3f8a0592 100644
--- a/b_asic/schedule.py
+++ b/b_asic/schedule.py
@@ -36,6 +36,7 @@ from b_asic.resources import ProcessCollection
 from b_asic.signal_flow_graph import SFG
 from b_asic.special_operations import Delay, Input, Output
 from b_asic.types import TypeName
+from b_asic.scheduling_algorithm import SchedAlg
 
 # Need RGB from 0 to 1
 _EXECUTION_TIME_COLOR: Tuple[float, ...] = tuple(
@@ -68,13 +69,8 @@ class Schedule:
         algorithm.
     cyclic : bool, default: False
         If the schedule is cyclic.
-    algorithm : {'ASAP', 'ALAP', 'provided'}, default: 'ASAP'
-        The scheduling algorithm to use. The following algorithm are available:
-
-        * ``'ASAP'``: As-soon-as-possible scheduling.
-        * ``'ALAP'``: As-late-as-possible scheduling.
-
-        If 'provided', use provided *start_times*  and *laps* dictionaries.
+    algorithm : SchedulingAlgorithm, default: 'ASAP'
+        The scheduling algorithm to use.
     start_times : dict, optional
         Dictionary with GraphIDs as keys and start times as values.
         Used when *algorithm* is 'provided'.
@@ -100,7 +96,7 @@ class Schedule:
         sfg: SFG,
         schedule_time: Optional[int] = None,
         cyclic: bool = False,
-        algorithm: Literal["ASAP", "ALAP", "provided"] = "ASAP",
+        algorithm: SchedAlg = "ASAP",
         start_times: Optional[Dict[GraphID, int]] = None,
         laps: Optional[Dict[GraphID, int]] = None,
         max_resources: Optional[Dict[TypeName, int]] = None,
@@ -115,10 +111,14 @@ class Schedule:
         self._cyclic = cyclic
         self._y_locations = defaultdict(_y_locations_default)
         self._schedule_time = schedule_time
+
+        self.scheduler = Scheduler(self)
         if algorithm == "ASAP":
-            self._schedule_asap()
+            self.scheduler.schedule_asap()
         elif algorithm == "ALAP":
-            self._schedule_alap()
+            self.scheduler.schedule_alap()
+        elif algorithm == "earliest_deadline":
+            self.scheduler.schedule_earliest_deadline()
         elif algorithm == "provided":
             if start_times is None:
                 raise ValueError("Must provide start_times when using 'provided'")
@@ -797,116 +797,116 @@ class Schedule:
                 new_sfg = new_sfg.insert_operation_before(op, Delay(), port)
         return new_sfg()
 
-    def _schedule_alap(self) -> None:
-        """Schedule the operations using as-late-as-possible scheduling."""
-        precedence_list = self._sfg.get_precedence_list()
-        self._schedule_asap()
-        max_end_time = self.get_max_end_time()
-
-        if self.schedule_time is None:
-            self._schedule_time = max_end_time
-        elif self.schedule_time < max_end_time:
-            raise ValueError(f"Too short schedule time. Minimum is {max_end_time}.")
-
-        for output in self._sfg.find_by_type_name(Output.type_name()):
-            output = cast(Output, output)
-            self.move_operation_alap(output.graph_id)
-        for step in reversed(precedence_list):
-            graph_ids = {
-                outport.operation.graph_id
-                for outport in step
-                if not isinstance(outport.operation, Delay)
-            }
-            for graph_id in graph_ids:
-                self.move_operation_alap(graph_id)
-
-    def _schedule_asap(self) -> None:
-        """Schedule the operations using as-soon-as-possible scheduling."""
-        precedence_list = self._sfg.get_precedence_list()
-
-        if len(precedence_list) < 2:
-            raise ValueError("Empty signal flow graph cannot be scheduled.")
-
-        non_schedulable_ops = set()
-        for outport in precedence_list[0]:
-            operation = outport.operation
-            if operation.type_name() not in [Delay.type_name()]:
-                if operation.graph_id not in self._start_times:
-                    # Set start time of all operations in the first iter to 0
-                    self._start_times[operation.graph_id] = 0
-            else:
-                non_schedulable_ops.add(operation.graph_id)
-
-        for outport in precedence_list[1]:
-            operation = outport.operation
-            if operation.graph_id not in self._start_times:
-                # Set start time of all operations in the first iter to 0
-                self._start_times[operation.graph_id] = 0
-
-        for outports in precedence_list[2:]:
-            for outport in outports:
-                operation = outport.operation
-                if operation.graph_id not in self._start_times:
-                    # Schedule the operation if it does not have a start time yet.
-                    op_start_time = 0
-                    for current_input in operation.inputs:
-                        if len(current_input.signals) != 1:
-                            raise ValueError(
-                                "Error in scheduling, dangling input port detected."
-                            )
-                        if current_input.signals[0].source is None:
-                            raise ValueError(
-                                "Error in scheduling, signal with no source detected."
-                            )
-                        source_port = current_input.signals[0].source
-
-                        if source_port.operation.graph_id in non_schedulable_ops:
-                            source_end_time = 0
-                        else:
-                            source_op_time = self._start_times[
-                                source_port.operation.graph_id
-                            ]
-
-                            if source_port.latency_offset is None:
-                                raise ValueError(
-                                    f"Output port {source_port.index} of"
-                                    " operation"
-                                    f" {source_port.operation.graph_id} has no"
-                                    " latency-offset."
-                                )
-
-                            source_end_time = (
-                                source_op_time + source_port.latency_offset
-                            )
-
-                        if current_input.latency_offset is None:
-                            raise ValueError(
-                                f"Input port {current_input.index} of operation"
-                                f" {current_input.operation.graph_id} has no"
-                                " latency-offset."
-                            )
-                        op_start_time_from_in = (
-                            source_end_time - current_input.latency_offset
-                        )
-                        op_start_time = max(op_start_time, op_start_time_from_in)
-
-                    self._start_times[operation.graph_id] = op_start_time
-        for output in self._sfg.find_by_type_name(Output.type_name()):
-            output = cast(Output, output)
-            source_port = cast(OutputPort, output.inputs[0].signals[0].source)
-            if source_port.operation.graph_id in non_schedulable_ops:
-                self._start_times[output.graph_id] = 0
-            else:
-                if source_port.latency_offset is None:
-                    raise ValueError(
-                        f"Output port {source_port.index} of operation"
-                        f" {source_port.operation.graph_id} has no"
-                        " latency-offset."
-                    )
-                self._start_times[output.graph_id] = self._start_times[
-                    source_port.operation.graph_id
-                ] + cast(int, source_port.latency_offset)
-        self._remove_delays()
+    # def _schedule_alap(self) -> None:
+    #     """Schedule the operations using as-late-as-possible scheduling."""
+    #     precedence_list = self._sfg.get_precedence_list()
+    #     self._schedule_asap()
+    #     max_end_time = self.get_max_end_time()
+
+    #     if self.schedule_time is None:
+    #         self._schedule_time = max_end_time
+    #     elif self.schedule_time < max_end_time:
+    #         raise ValueError(f"Too short schedule time. Minimum is {max_end_time}.")
+
+    #     for output in self._sfg.find_by_type_name(Output.type_name()):
+    #         output = cast(Output, output)
+    #         self.move_operation_alap(output.graph_id)
+    #     for step in reversed(precedence_list):
+    #         graph_ids = {
+    #             outport.operation.graph_id
+    #             for outport in step
+    #             if not isinstance(outport.operation, Delay)
+    #         }
+    #         for graph_id in graph_ids:
+    #             self.move_operation_alap(graph_id)
+
+    # def _schedule_asap(self) -> None:
+    #     """Schedule the operations using as-soon-as-possible scheduling."""
+    #     precedence_list = self._sfg.get_precedence_list()
+
+    #     if len(precedence_list) < 2:
+    #         raise ValueError("Empty signal flow graph cannot be scheduled.")
+
+    #     non_schedulable_ops = set()
+    #     for outport in precedence_list[0]:
+    #         operation = outport.operation
+    #         if operation.type_name() not in [Delay.type_name()]:
+    #             if operation.graph_id not in self._start_times:
+    #                 # Set start time of all operations in the first iter to 0
+    #                 self._start_times[operation.graph_id] = 0
+    #         else:
+    #             non_schedulable_ops.add(operation.graph_id)
+
+    #     for outport in precedence_list[1]:
+    #         operation = outport.operation
+    #         if operation.graph_id not in self._start_times:
+    #             # Set start time of all operations in the first iter to 0
+    #             self._start_times[operation.graph_id] = 0
+
+    #     for outports in precedence_list[2:]:
+    #         for outport in outports:
+    #             operation = outport.operation
+    #             if operation.graph_id not in self._start_times:
+    #                 # Schedule the operation if it does not have a start time yet.
+    #                 op_start_time = 0
+    #                 for current_input in operation.inputs:
+    #                     if len(current_input.signals) != 1:
+    #                         raise ValueError(
+    #                             "Error in scheduling, dangling input port detected."
+    #                         )
+    #                     if current_input.signals[0].source is None:
+    #                         raise ValueError(
+    #                             "Error in scheduling, signal with no source detected."
+    #                         )
+    #                     source_port = current_input.signals[0].source
+
+    #                     if source_port.operation.graph_id in non_schedulable_ops:
+    #                         source_end_time = 0
+    #                     else:
+    #                         source_op_time = self._start_times[
+    #                             source_port.operation.graph_id
+    #                         ]
+
+    #                         if source_port.latency_offset is None:
+    #                             raise ValueError(
+    #                                 f"Output port {source_port.index} of"
+    #                                 " operation"
+    #                                 f" {source_port.operation.graph_id} has no"
+    #                                 " latency-offset."
+    #                             )
+
+    #                         source_end_time = (
+    #                             source_op_time + source_port.latency_offset
+    #                         )
+
+    #                     if current_input.latency_offset is None:
+    #                         raise ValueError(
+    #                             f"Input port {current_input.index} of operation"
+    #                             f" {current_input.operation.graph_id} has no"
+    #                             " latency-offset."
+    #                         )
+    #                     op_start_time_from_in = (
+    #                         source_end_time - current_input.latency_offset
+    #                     )
+    #                     op_start_time = max(op_start_time, op_start_time_from_in)
+
+    #                 self._start_times[operation.graph_id] = op_start_time
+    #     for output in self._sfg.find_by_type_name(Output.type_name()):
+    #         output = cast(Output, output)
+    #         source_port = cast(OutputPort, output.inputs[0].signals[0].source)
+    #         if source_port.operation.graph_id in non_schedulable_ops:
+    #             self._start_times[output.graph_id] = 0
+    #         else:
+    #             if source_port.latency_offset is None:
+    #                 raise ValueError(
+    #                     f"Output port {source_port.index} of operation"
+    #                     f" {source_port.operation.graph_id} has no"
+    #                     " latency-offset."
+    #                 )
+    #             self._start_times[output.graph_id] = self._start_times[
+    #                 source_port.operation.graph_id
+    #             ] + cast(int, source_port.latency_offset)
+    #     self._remove_delays()
 
     def _get_memory_variables_list(self) -> List[MemoryVariable]:
         ret: List[MemoryVariable] = []
@@ -1227,3 +1227,149 @@ class Schedule:
 
     # SVG is valid HTML. This is useful for e.g. sphinx-gallery
     _repr_html_ = _repr_svg_
+
+
+class Scheduler():
+    def __init__(self, schedule: Schedule) -> None:
+        self.schedule = schedule
+    
+    def schedule_asap(self) -> None:
+        """Schedule the operations using as-soon-as-possible scheduling."""
+        sched = self.schedule
+        prec_list = sched.sfg.get_precedence_list()
+        if len(prec_list) < 2:
+            raise ValueError("Empty signal flow graph cannot be scheduled.")
+
+        # handle the first set in precedence graph (input and delays)
+        non_schedulable_ops = set()
+        for outport in prec_list[0]:
+            operation = outport.operation
+            if operation.type_name() == Delay.type_name():
+                non_schedulable_ops.add(operation.graph_id)
+            elif operation.graph_id not in sched._start_times:
+                sched._start_times[operation.graph_id] = 0
+
+        # handle second set in precedence graph (first operations)
+        for outport in prec_list[1]:
+            operation = outport.operation
+            if operation.graph_id not in sched._start_times:
+                sched._start_times[operation.graph_id] = 0
+
+        # handle the remaining sets
+        for outports in prec_list[2:]:
+            for outport in outports:
+                operation = outport.operation
+                if operation.graph_id not in sched._start_times:
+                    op_start_time = 0
+                    for current_input in operation.inputs:
+                        if len(current_input.signals) != 1:
+                            raise ValueError(
+                                "Error in scheduling, dangling input port detected."
+                            )
+                        if current_input.signals[0].source is None:
+                            raise ValueError(
+                                "Error in scheduling, signal with no source detected."
+                            )
+                        source_port = current_input.signals[0].source
+
+                        if source_port.operation.graph_id in non_schedulable_ops:
+                            source_end_time = 0
+                        else:
+                            source_op_time = sched._start_times[
+                                source_port.operation.graph_id
+                            ]
+
+                            if source_port.latency_offset is None:
+                                raise ValueError(
+                                    f"Output port {source_port.index} of"
+                                    " operation"
+                                    f" {source_port.operation.graph_id} has no"
+                                    " latency-offset."
+                                )
+
+                            source_end_time = (
+                                source_op_time + source_port.latency_offset
+                            )
+
+                        if current_input.latency_offset is None:
+                            raise ValueError(
+                                f"Input port {current_input.index} of operation"
+                                f" {current_input.operation.graph_id} has no"
+                                " latency-offset."
+                            )
+                        op_start_time_from_in = (
+                            source_end_time - current_input.latency_offset
+                        )
+                        op_start_time = max(op_start_time, op_start_time_from_in)
+
+                    sched._start_times[operation.graph_id] = op_start_time
+        
+        # handle output and remove delays
+        for output in sched._sfg.find_by_type_name(Output.type_name()):
+            output = cast(Output, output)
+            source_port = cast(OutputPort, output.inputs[0].signals[0].source)
+            if source_port.operation.graph_id in non_schedulable_ops:
+                sched._start_times[output.graph_id] = 0
+            else:
+                if source_port.latency_offset is None:
+                    raise ValueError(
+                        f"Output port {source_port.index} of operation"
+                        f" {source_port.operation.graph_id} has no"
+                        " latency-offset."
+                    )
+                sched._start_times[output.graph_id] = sched._start_times[
+                    source_port.operation.graph_id
+                ] + cast(int, source_port.latency_offset)
+        sched._remove_delays()
+
+    def schedule_alap(self) -> None:
+        """Schedule the operations using as-late-as-possible scheduling."""
+        self.schedule_asap()
+        sched = self.schedule
+        max_end_time = sched.get_max_end_time()
+
+        if sched.schedule_time is None:
+            sched.set_schedule_time(max_end_time)
+        elif sched.schedule_time < max_end_time:
+            raise ValueError(f"Too short schedule time. Minimum is {max_end_time}.")
+
+        # move all outputs ALAP before operations
+        for output in sched.sfg.find_by_type_name(Output.type_name()):
+            output = cast(Output, output)
+            sched.move_operation_alap(output.graph_id)
+        
+        # move all operations ALAP
+        for step in reversed(sched.sfg.get_precedence_list()):
+            for outport in step:
+                if not isinstance(outport.operation, Delay):
+                    sched.move_operation_alap(outport.operation.graph_id)
+
+    def schedule_earliest_deadline(self) -> None:
+        """Schedule the operations using earliest deadline scheduling."""
+        pass
+        # sched = self.schedule
+        # prec_list = sched.sfg.get_precedence_list()
+        # if len(prec_list) < 2:
+        #     raise ValueError("Empty signal flow graph cannot be scheduled.")
+
+        # # handle the first set in precedence graph (input and delays)
+        # non_schedulable_ops = set()
+        # for outport in prec_list[0]:
+        #     operation = outport.operation
+        #     if operation.type_name() == Delay.type_name():
+        #         non_schedulable_ops.add(operation.graph_id)
+        #     elif operation.graph_id not in sched._start_times:
+        #         sched._start_times[operation.graph_id] = 0
+
+        # # handle second set in precedence graph (first operations)
+        # for outport in prec_list[1]:
+        #     operation = outport.operation
+        #     if operation.graph_id not in sched._start_times:
+        #         sched._start_times[operation.graph_id] = 0
+        
+        # # handle the remaining sets
+        # for outports in prec_list[2:]:
+        #     for outport in outports:
+        #         operation = outport.operation
+        #         if operation.graph_id not in sched._start_times:
+        #             pass
\ No newline at end of file
diff --git a/b_asic/scheduling_algorithm.py b/b_asic/scheduling_algorithm.py
new file mode 100644
index 00000000..8a1dbcd3
--- /dev/null
+++ b/b_asic/scheduling_algorithm.py
@@ -0,0 +1,8 @@
+from enum import Enum
+
+class SchedAlg(Enum):
+    ASAP = "ASAP"
+    ALAP = "ALAP"
+    EARLIEST_DEADLINE = "earliest_deadline"
+    LEAST_SLACK = "least_slack"
+    PROVIDED = "provided"
-- 
GitLab


From eb4a5de84b262910184d0c9dcda83f119612667d Mon Sep 17 00:00:00 2001
From: Simon Bjurek <simbj106@student.liu.se>
Date: Thu, 23 Jan 2025 16:26:43 +0100
Subject: [PATCH 05/21] linting fixes

---
 b_asic/schedule.py             | 16 ++++++++--------
 b_asic/scheduling_algorithm.py |  1 +
 2 files changed, 9 insertions(+), 8 deletions(-)

diff --git a/b_asic/schedule.py b/b_asic/schedule.py
index 3f8a0592..86eaba91 100644
--- a/b_asic/schedule.py
+++ b/b_asic/schedule.py
@@ -7,7 +7,7 @@ Contains the schedule class for scheduling operations in an SFG.
 import io
 import sys
 from collections import defaultdict
-from typing import Dict, List, Literal, Optional, Sequence, Tuple, cast
+from typing import Dict, List, Optional, Sequence, Tuple, cast
 
 import matplotlib.pyplot as plt
 import numpy as np
@@ -33,10 +33,10 @@ from b_asic.operation import Operation
 from b_asic.port import InputPort, OutputPort
 from b_asic.process import MemoryVariable, OperatorProcess
 from b_asic.resources import ProcessCollection
+from b_asic.scheduling_algorithm import SchedAlg
 from b_asic.signal_flow_graph import SFG
 from b_asic.special_operations import Delay, Input, Output
 from b_asic.types import TypeName
-from b_asic.scheduling_algorithm import SchedAlg
 
 # Need RGB from 0 to 1
 _EXECUTION_TIME_COLOR: Tuple[float, ...] = tuple(
@@ -1229,10 +1229,10 @@ class Schedule:
     _repr_html_ = _repr_svg_
 
 
-class Scheduler():
+class Scheduler:
     def __init__(self, schedule: Schedule) -> None:
         self.schedule = schedule
-    
+
     def schedule_asap(self) -> None:
         """Schedule the operations using as-soon-as-possible scheduling."""
         sched = self.schedule
@@ -1303,7 +1303,7 @@ class Scheduler():
                         op_start_time = max(op_start_time, op_start_time_from_in)
 
                     sched._start_times[operation.graph_id] = op_start_time
-        
+
         # handle output and remove delays
         for output in sched._sfg.find_by_type_name(Output.type_name()):
             output = cast(Output, output)
@@ -1337,7 +1337,7 @@ class Scheduler():
         for output in sched.sfg.find_by_type_name(Output.type_name()):
             output = cast(Output, output)
             sched.move_operation_alap(output.graph_id)
-        
+
         # move all operations ALAP
         for step in reversed(sched.sfg.get_precedence_list()):
             for outport in step:
@@ -1366,10 +1366,10 @@ class Scheduler():
         #     operation = outport.operation
         #     if operation.graph_id not in sched._start_times:
         #         sched._start_times[operation.graph_id] = 0
-        
+
         # # handle the remaining sets
         # for outports in prec_list[2:]:
         #     for outport in outports:
         #         operation = outport.operation
         #         if operation.graph_id not in sched._start_times:
-        #             pass
\ No newline at end of file
+        #             pass
diff --git a/b_asic/scheduling_algorithm.py b/b_asic/scheduling_algorithm.py
index 8a1dbcd3..c6787a73 100644
--- a/b_asic/scheduling_algorithm.py
+++ b/b_asic/scheduling_algorithm.py
@@ -1,5 +1,6 @@
 from enum import Enum
 
+
 class SchedAlg(Enum):
     ASAP = "ASAP"
     ALAP = "ALAP"
-- 
GitLab


From c6c95908ada00ba951ceab486ce2d17cabfa69c8 Mon Sep 17 00:00:00 2001
From: Simon Bjurek <simbj106@student.liu.se>
Date: Fri, 24 Jan 2025 16:50:52 +0100
Subject: [PATCH 06/21] post commit

---
 b_asic/schedule.py | 126 +++++++++++++++++++++++++++------------------
 1 file changed, 77 insertions(+), 49 deletions(-)

diff --git a/b_asic/schedule.py b/b_asic/schedule.py
index 86eaba91..c0d998cc 100644
--- a/b_asic/schedule.py
+++ b/b_asic/schedule.py
@@ -118,7 +118,7 @@ class Schedule:
         elif algorithm == "ALAP":
             self.scheduler.schedule_alap()
         elif algorithm == "earliest_deadline":
-            self.scheduler.schedule_earliest_deadline()
+            self.scheduler.schedule_earliest_deadline([])
         elif algorithm == "provided":
             if start_times is None:
                 raise ValueError("Must provide start_times when using 'provided'")
@@ -1246,14 +1246,15 @@ class Scheduler:
             operation = outport.operation
             if operation.type_name() == Delay.type_name():
                 non_schedulable_ops.add(operation.graph_id)
-            elif operation.graph_id not in sched._start_times:
+            # elif operation.graph_id not in sched._start_times:
+            else:
                 sched._start_times[operation.graph_id] = 0
 
         # handle second set in precedence graph (first operations)
         for outport in prec_list[1]:
             operation = outport.operation
-            if operation.graph_id not in sched._start_times:
-                sched._start_times[operation.graph_id] = 0
+            # if operation.graph_id not in sched._start_times:
+            sched._start_times[operation.graph_id] = 0
 
         # handle the remaining sets
         for outports in prec_list[2:]:
@@ -1304,23 +1305,7 @@ class Scheduler:
 
                     sched._start_times[operation.graph_id] = op_start_time
 
-        # handle output and remove delays
-        for output in sched._sfg.find_by_type_name(Output.type_name()):
-            output = cast(Output, output)
-            source_port = cast(OutputPort, output.inputs[0].signals[0].source)
-            if source_port.operation.graph_id in non_schedulable_ops:
-                sched._start_times[output.graph_id] = 0
-            else:
-                if source_port.latency_offset is None:
-                    raise ValueError(
-                        f"Output port {source_port.index} of operation"
-                        f" {source_port.operation.graph_id} has no"
-                        " latency-offset."
-                    )
-                sched._start_times[output.graph_id] = sched._start_times[
-                    source_port.operation.graph_id
-                ] + cast(int, source_port.latency_offset)
-        sched._remove_delays()
+        self._handle_outputs_and_delays(non_schedulable_ops)
 
     def schedule_alap(self) -> None:
         """Schedule the operations using as-late-as-possible scheduling."""
@@ -1344,32 +1329,75 @@ class Scheduler:
                 if not isinstance(outport.operation, Delay):
                     sched.move_operation_alap(outport.operation.graph_id)
 
-    def schedule_earliest_deadline(self) -> None:
+    def schedule_earliest_deadline(self, process_elements: list[Operation]) -> None:
         """Schedule the operations using earliest deadline scheduling."""
-        pass
-        # sched = self.schedule
-        # prec_list = sched.sfg.get_precedence_list()
-        # if len(prec_list) < 2:
-        #     raise ValueError("Empty signal flow graph cannot be scheduled.")
-
-        # # handle the first set in precedence graph (input and delays)
-        # non_schedulable_ops = set()
-        # for outport in prec_list[0]:
-        #     operation = outport.operation
-        #     if operation.type_name() == Delay.type_name():
-        #         non_schedulable_ops.add(operation.graph_id)
-        #     elif operation.graph_id not in sched._start_times:
-        #         sched._start_times[operation.graph_id] = 0
-
-        # # handle second set in precedence graph (first operations)
-        # for outport in prec_list[1]:
-        #     operation = outport.operation
-        #     if operation.graph_id not in sched._start_times:
-        #         sched._start_times[operation.graph_id] = 0
-
-        # # handle the remaining sets
-        # for outports in prec_list[2:]:
-        #     for outport in outports:
-        #         operation = outport.operation
-        #         if operation.graph_id not in sched._start_times:
-        #             pass
+
+        # ACT BASED ON THE NUMBER OF PEs!
+
+        sched = self.schedule
+        prec_list = sched.sfg.get_precedence_list()
+        if len(prec_list) < 2:
+            raise ValueError("Empty signal flow graph cannot be scheduled.")
+
+        # handle the first set in precedence graph (input and delays)
+        non_schedulable_ops = set()
+        for outport in prec_list[0]:
+            operation = outport.operation
+            if operation.type_name() == Delay.type_name():
+                non_schedulable_ops.add(operation.graph_id)
+            elif operation.graph_id not in sched._start_times:
+                sched._start_times[operation.graph_id] = 0
+
+        # latencies = [outport.operation.latency for outport in prec_list[1]]
+        current_time = 0
+        sorted_outports = sorted(
+            prec_list[1], key=lambda outport: outport.operation.latency
+        )
+        for outport in sorted_outports:
+            op = outport.operation
+            sched._start_times[op.graph_id] = current_time
+            current_time += 1
+
+        for outports in prec_list[2:]:
+            # try all remaining operations for one time step
+            candidates = []
+            while len(candidates) == 0:
+                for outport in outports:
+                    remaining_op = outport.operation
+                    op_is_ready_to_be_scheduled = True
+                    for op_input in remaining_op.inputs:
+                        source_op = op_input.signals[0].source.operation
+                        source_op_time = sched.start_times[source_op.graph_id]
+                        source_end_time = source_op_time + source_op.latency
+                        if source_end_time > current_time:
+                            op_is_ready_to_be_scheduled = False
+                    if op_is_ready_to_be_scheduled:
+                        candidates.append(remaining_op)
+                        # sched._start_times[remaining_op.graph_id] = current_time
+                current_time += 1
+            sorted_candidates = sorted(
+                candidates, key=lambda candidate: candidate.latency
+            )
+            # schedule the best candidate to current time
+            sched._start_times[sorted_candidates[0].graph_id] = current_time
+
+        self._handle_outputs_and_delays(non_schedulable_ops)
+
+    def _handle_outputs_and_delays(self, non_schedulable_ops) -> None:
+        sched = self.schedule
+        for output in sched._sfg.find_by_type_name(Output.type_name()):
+            output = cast(Output, output)
+            source_port = cast(OutputPort, output.inputs[0].signals[0].source)
+            if source_port.operation.graph_id in non_schedulable_ops:
+                sched._start_times[output.graph_id] = 0
+            else:
+                if source_port.latency_offset is None:
+                    raise ValueError(
+                        f"Output port {source_port.index} of operation"
+                        f" {source_port.operation.graph_id} has no"
+                        " latency-offset."
+                    )
+                sched._start_times[output.graph_id] = sched._start_times[
+                    source_port.operation.graph_id
+                ] + cast(int, source_port.latency_offset)
+        sched._remove_delays()
-- 
GitLab


From 980170f1f54558cfd7c27e71f51879d83ad7ea78 Mon Sep 17 00:00:00 2001
From: Simon Bjurek <simbj106@student.liu.se>
Date: Fri, 24 Jan 2025 17:03:53 +0100
Subject: [PATCH 07/21] earliest deadline, first version working, needs testing

---
 b_asic/schedule.py | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/b_asic/schedule.py b/b_asic/schedule.py
index c0d998cc..58fa572a 100644
--- a/b_asic/schedule.py
+++ b/b_asic/schedule.py
@@ -1361,7 +1361,9 @@ class Scheduler:
         for outports in prec_list[2:]:
             # try all remaining operations for one time step
             candidates = []
+            current_time -= 1
             while len(candidates) == 0:
+                current_time += 1
                 for outport in outports:
                     remaining_op = outport.operation
                     op_is_ready_to_be_scheduled = True
@@ -1374,7 +1376,6 @@ class Scheduler:
                     if op_is_ready_to_be_scheduled:
                         candidates.append(remaining_op)
                         # sched._start_times[remaining_op.graph_id] = current_time
-                current_time += 1
             sorted_candidates = sorted(
                 candidates, key=lambda candidate: candidate.latency
             )
-- 
GitLab


From 831687a8776d95d32501a73fe255b9d881b58ce7 Mon Sep 17 00:00:00 2001
From: Simon Bjurek <simbj106@student.liu.se>
Date: Mon, 27 Jan 2025 08:38:14 +0100
Subject: [PATCH 08/21] removed end-of-life py version 3.8

---
 .gitlab-ci.yml | 12 ------------
 1 file changed, 12 deletions(-)

diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 2e59a32d..96ca283e 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -35,18 +35,6 @@ before_script:
         path: cov.xml
   coverage: /(?i)total.*? (100(?:\.0+)?\%|[1-9]?\d(?:\.\d+)?\%)$/
 
-run-test-3.8-pyside2:
-  variables:
-    QT_API: pyside2
-  image: python:3.8
-  extends: ".run-test"
-
-run-test-3.8-pyqt5:
-  variables:
-    QT_API: pyqt5
-  image: python:3.8
-  extends: ".run-test"
-
 run-test-3.9-pyside2:
   variables:
     QT_API: pyside2
-- 
GitLab


From 8c2e1053f977c33ef116fe346525690b7499cc18 Mon Sep 17 00:00:00 2001
From: Simon Bjurek <simbj106@student.liu.se>
Date: Mon, 27 Jan 2025 08:40:42 +0100
Subject: [PATCH 09/21] removed py version 3.9 since it will reach end-of-life
 this year

---
 .gitlab-ci.yml | 12 ------------
 1 file changed, 12 deletions(-)

diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 96ca283e..873cea6c 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -35,18 +35,6 @@ before_script:
         path: cov.xml
   coverage: /(?i)total.*? (100(?:\.0+)?\%|[1-9]?\d(?:\.\d+)?\%)$/
 
-run-test-3.9-pyside2:
-  variables:
-    QT_API: pyside2
-  image: python:3.9
-  extends: ".run-test"
-
-run-test-3.9-pyqt5:
-  variables:
-    QT_API: pyqt5
-  image: python:3.9
-  extends: ".run-test"
-
 run-test-3.10-pyside2:
   variables:
     QT_API: pyside2
-- 
GitLab


From 9f512f7cd59d72f9443f5926f9e5d182faab3569 Mon Sep 17 00:00:00 2001
From: Simon Bjurek <simbj106@student.liu.se>
Date: Mon, 27 Jan 2025 08:41:11 +0100
Subject: [PATCH 10/21] updated toml file with new py version

---
 pyproject.toml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/pyproject.toml b/pyproject.toml
index c0d7de2f..ff1ea7b2 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -4,7 +4,7 @@ description = "Better ASIC Toolbox"
 readme = "README.md"
 maintainers = [{ name = "Oscar Gustafsson", email = "oscar.gustafsson@liu.se" }]
 license = { file = "LICENSE" }
-requires-python = ">=3.8"
+requires-python = ">=3.10"
 dependencies = [
   "numpy",
   "qtpy",
-- 
GitLab


From 40eb2980980dad07d536e74c5b1e44682add922c Mon Sep 17 00:00:00 2001
From: Simon Bjurek <simbj106@student.liu.se>
Date: Mon, 27 Jan 2025 08:45:29 +0100
Subject: [PATCH 11/21] updated ci file with pyqt6 tests for python 3.10 and
 3.11

---
 .gitlab-ci.yml | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 873cea6c..aeb235f0 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -47,6 +47,12 @@ run-test-3.10-pyqt5:
   image: python:3.10
   extends: ".run-test"
 
+run-test-3.10-pyqt6:
+  variables:
+    QT_API: pyqt6
+  image: python:3.10
+  extends: ".run-test"
+
 # PySide2 does not seem to have support for 3.11, "almost works" though
 #run-test-3.11-pyside2:
 #  variables:
@@ -61,6 +67,12 @@ run-test-3.11-pyqt5:
   image: python:3.11
   extends: ".run-test"
 
+run-test-3.11-pyqt6:
+  variables:
+    QT_API: pyqt6
+  image: python:3.11
+  extends: ".run-test"
+
 run-test-3.12-pyqt5:
   variables:
     QT_API: pyqt5
-- 
GitLab


From 7bc3424f7a7322d2b8f05cc9ed6556cfa2db0cd6 Mon Sep 17 00:00:00 2001
From: Simon Bjurek <simbj106@student.liu.se>
Date: Mon, 27 Jan 2025 08:46:47 +0100
Subject: [PATCH 12/21] updated ci file with python 3.13

---
 .gitlab-ci.yml | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index aeb235f0..1bb8d867 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -85,6 +85,12 @@ run-test-3.12-pyqt6:
   image: python:3.12
   extends: ".run-test"
 
+run-test-3.13-pyqt6:
+  variables:
+    QT_API: pyqt6
+  image: python:3.13
+  extends: ".run-test"
+
 # Seemingly works with Qt6, but tests stall on closing scheduler GUI due to modal dialog(?)
 #run-test-3.10-pyside6:
 #  variables:
-- 
GitLab


From c32e17ee379c60165c8f790d8c8270bb989f5d24 Mon Sep 17 00:00:00 2001
From: Simon Bjurek <simbj106@student.liu.se>
Date: Mon, 27 Jan 2025 08:01:17 +0000
Subject: [PATCH 13/21] Update .gitlab-ci.yml file

---
 .gitlab-ci.yml | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 1bb8d867..275368b0 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -49,7 +49,7 @@ run-test-3.10-pyqt5:
 
 run-test-3.10-pyqt6:
   variables:
-    QT_API: pyqt6
+    QT_API: PyQt6
   image: python:3.10
   extends: ".run-test"
 
@@ -69,7 +69,7 @@ run-test-3.11-pyqt5:
 
 run-test-3.11-pyqt6:
   variables:
-    QT_API: pyqt6
+    QT_API: PyQt6
   image: python:3.11
   extends: ".run-test"
 
@@ -81,13 +81,13 @@ run-test-3.12-pyqt5:
 
 run-test-3.12-pyqt6:
   variables:
-    QT_API: pyqt6
+    QT_API: PyQt6
   image: python:3.12
   extends: ".run-test"
 
 run-test-3.13-pyqt6:
   variables:
-    QT_API: pyqt6
+    QT_API: PyQt6
   image: python:3.13
   extends: ".run-test"
 
-- 
GitLab


From 2e41421589db056bce9473775c87b4d102c1781c Mon Sep 17 00:00:00 2001
From: Simon Bjurek <simbj106@student.liu.se>
Date: Mon, 27 Jan 2025 08:13:02 +0000
Subject: [PATCH 14/21] Update .gitlab-ci.yml file

---
 .gitlab-ci.yml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 275368b0..88a2d4be 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -19,6 +19,7 @@ before_script:
   # Install test dependencies
   - pip install -r requirements_test.txt
   - export PYTEST_QT_API=$QT_API
+  - export MPLBACKEND=qtagg
 
 .run-test:
   stage: test
-- 
GitLab


From 450b1e86d267471a8ec78c17d91b38af4aec156d Mon Sep 17 00:00:00 2001
From: Simon Bjurek <simbj106@student.liu.se>
Date: Mon, 27 Jan 2025 08:26:48 +0000
Subject: [PATCH 15/21] Update .gitlab-ci.yml file

---
 .gitlab-ci.yml | 9 ++++-----
 1 file changed, 4 insertions(+), 5 deletions(-)

diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 88a2d4be..1bb8d867 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -19,7 +19,6 @@ before_script:
   # Install test dependencies
   - pip install -r requirements_test.txt
   - export PYTEST_QT_API=$QT_API
-  - export MPLBACKEND=qtagg
 
 .run-test:
   stage: test
@@ -50,7 +49,7 @@ run-test-3.10-pyqt5:
 
 run-test-3.10-pyqt6:
   variables:
-    QT_API: PyQt6
+    QT_API: pyqt6
   image: python:3.10
   extends: ".run-test"
 
@@ -70,7 +69,7 @@ run-test-3.11-pyqt5:
 
 run-test-3.11-pyqt6:
   variables:
-    QT_API: PyQt6
+    QT_API: pyqt6
   image: python:3.11
   extends: ".run-test"
 
@@ -82,13 +81,13 @@ run-test-3.12-pyqt5:
 
 run-test-3.12-pyqt6:
   variables:
-    QT_API: PyQt6
+    QT_API: pyqt6
   image: python:3.12
   extends: ".run-test"
 
 run-test-3.13-pyqt6:
   variables:
-    QT_API: PyQt6
+    QT_API: pyqt6
   image: python:3.13
   extends: ".run-test"
 
-- 
GitLab


From 54d614eb4df4cd6a11c05c3d129ab7cf68a7c81f Mon Sep 17 00:00:00 2001
From: Simon Bjurek <simbj106@student.liu.se>
Date: Mon, 27 Jan 2025 09:15:30 +0000
Subject: [PATCH 16/21] debugging ci file

---
 .gitlab-ci.yml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 1bb8d867..1fa2fb74 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -84,6 +84,7 @@ run-test-3.12-pyqt6:
     QT_API: pyqt6
   image: python:3.12
   extends: ".run-test"
+  allow_failure: true
 
 run-test-3.13-pyqt6:
   variables:
-- 
GitLab


From 7ef91215bd9f3aece99901e627dfab2980fe89d8 Mon Sep 17 00:00:00 2001
From: Simon Bjurek <simbj106@student.liu.se>
Date: Mon, 27 Jan 2025 09:35:51 +0000
Subject: [PATCH 17/21] debugging (adding -s to pytest command)

---
 .gitlab-ci.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 1fa2fb74..7001d19d 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -23,7 +23,7 @@ before_script:
 .run-test:
   stage: test
   script:
-    - pytest --cov=b_asic --cov-report=xml:cov.xml --cov-report=term --cov-branch --color=yes test --timeout=20 --durations=10
+    - pytest -s --cov=b_asic --cov-report=xml:cov.xml --cov-report=term --cov-branch --color=yes test --timeout=20 --durations=10
     # - lcov --capture --directory . --output-file coverage.info
     # - lcov --output-file coverage.info --extract coverage.info $PWD/src/'*' $PWD/b_asic/'*'
     # - lcov --list coverage.info
-- 
GitLab


From 7167a5b2f6501039a8c5f8cb23b6b026282ae783 Mon Sep 17 00:00:00 2001
From: Simon Bjurek <simbj106@student.liu.se>
Date: Mon, 27 Jan 2025 09:41:50 +0000
Subject: [PATCH 18/21] attempting fix by adding libxcb-cursor-dev

---
 .gitlab-ci.yml | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 7001d19d..f95d4f67 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -6,6 +6,7 @@ before_script:
   - apt-get update --yes
   # - apt-get install --yes build-essential cmake graphviz python3-pyqt5 xvfb xdg-utils lcov
   - apt-get install --yes graphviz python3-pyqt5 xvfb xdg-utils
+  - apt-get install -y libxcb-cursor-dev
   - python -m pip install --upgrade pip
   - python --version
   - pip install -r requirements.txt
@@ -23,7 +24,7 @@ before_script:
 .run-test:
   stage: test
   script:
-    - pytest -s --cov=b_asic --cov-report=xml:cov.xml --cov-report=term --cov-branch --color=yes test --timeout=20 --durations=10
+    - pytest --cov=b_asic --cov-report=xml:cov.xml --cov-report=term --cov-branch --color=yes test --timeout=20 --durations=10
     # - lcov --capture --directory . --output-file coverage.info
     # - lcov --output-file coverage.info --extract coverage.info $PWD/src/'*' $PWD/b_asic/'*'
     # - lcov --list coverage.info
-- 
GitLab


From c23e613e89b4fb8639b3702c427ed0b6786446b3 Mon Sep 17 00:00:00 2001
From: Simon Bjurek <simbj106@student.liu.se>
Date: Mon, 27 Jan 2025 11:01:17 +0100
Subject: [PATCH 19/21] CI fixes, hopefully working now

---
 .gitlab-ci.yml | 30 ------------------------------
 1 file changed, 30 deletions(-)

diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index f95d4f67..5f4c6f59 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -54,14 +54,6 @@ run-test-3.10-pyqt6:
   image: python:3.10
   extends: ".run-test"
 
-# PySide2 does not seem to have support for 3.11, "almost works" though
-#run-test-3.11-pyside2:
-#  variables:
-#    QT_API: pyside2
-#  image: python:3.11
-#  extends: ".run-test"
-#  allow_failure: true
-
 run-test-3.11-pyqt5:
   variables:
     QT_API: pyqt5
@@ -85,28 +77,6 @@ run-test-3.12-pyqt6:
     QT_API: pyqt6
   image: python:3.12
   extends: ".run-test"
-  allow_failure: true
-
-run-test-3.13-pyqt6:
-  variables:
-    QT_API: pyqt6
-  image: python:3.13
-  extends: ".run-test"
-
-# Seemingly works with Qt6, but tests stall on closing scheduler GUI due to modal dialog(?)
-#run-test-3.10-pyside6:
-#  variables:
-#    QT_API: pyside6
-#  image: python:3.10
-#  extends: ".run-test"
-#  allow_failure: true
-#
-#run-test-3.10-pyqt6:
-#  variables:
-#    QT_API: pyqt6
-#  image: python:3.10
-#  extends: ".run-test"
-#  allow_failure: true
 
 run-vhdl-tests:
   variables:
-- 
GitLab


From 2a7a7305c79f9eb587cf1e4e68e2b013f9bdc945 Mon Sep 17 00:00:00 2001
From: Simon Bjurek <simbj106@student.liu.se>
Date: Mon, 27 Jan 2025 16:00:09 +0100
Subject: [PATCH 20/21] fixes from mr comments

---
 b_asic/schedule.py             | 179 +-----------------------------
 b_asic/scheduler.py            | 193 +++++++++++++++++++++++++++++++++
 b_asic/scheduling_algorithm.py |   9 --
 pyproject.toml                 |   7 +-
 4 files changed, 199 insertions(+), 189 deletions(-)
 create mode 100644 b_asic/scheduler.py
 delete mode 100644 b_asic/scheduling_algorithm.py

diff --git a/b_asic/schedule.py b/b_asic/schedule.py
index 58fa572a..a708fe1a 100644
--- a/b_asic/schedule.py
+++ b/b_asic/schedule.py
@@ -33,7 +33,7 @@ from b_asic.operation import Operation
 from b_asic.port import InputPort, OutputPort
 from b_asic.process import MemoryVariable, OperatorProcess
 from b_asic.resources import ProcessCollection
-from b_asic.scheduling_algorithm import SchedAlg
+from b_asic.scheduler import Scheduler, SchedulingAlgorithm
 from b_asic.signal_flow_graph import SFG
 from b_asic.special_operations import Delay, Input, Output
 from b_asic.types import TypeName
@@ -96,7 +96,7 @@ class Schedule:
         sfg: SFG,
         schedule_time: Optional[int] = None,
         cyclic: bool = False,
-        algorithm: SchedAlg = "ASAP",
+        algorithm: SchedulingAlgorithm = "ASAP",
         start_times: Optional[Dict[GraphID, int]] = None,
         laps: Optional[Dict[GraphID, int]] = None,
         max_resources: Optional[Dict[TypeName, int]] = None,
@@ -1227,178 +1227,3 @@ class Schedule:
 
     # SVG is valid HTML. This is useful for e.g. sphinx-gallery
     _repr_html_ = _repr_svg_
-
-
-class Scheduler:
-    def __init__(self, schedule: Schedule) -> None:
-        self.schedule = schedule
-
-    def schedule_asap(self) -> None:
-        """Schedule the operations using as-soon-as-possible scheduling."""
-        sched = self.schedule
-        prec_list = sched.sfg.get_precedence_list()
-        if len(prec_list) < 2:
-            raise ValueError("Empty signal flow graph cannot be scheduled.")
-
-        # handle the first set in precedence graph (input and delays)
-        non_schedulable_ops = set()
-        for outport in prec_list[0]:
-            operation = outport.operation
-            if operation.type_name() == Delay.type_name():
-                non_schedulable_ops.add(operation.graph_id)
-            # elif operation.graph_id not in sched._start_times:
-            else:
-                sched._start_times[operation.graph_id] = 0
-
-        # handle second set in precedence graph (first operations)
-        for outport in prec_list[1]:
-            operation = outport.operation
-            # if operation.graph_id not in sched._start_times:
-            sched._start_times[operation.graph_id] = 0
-
-        # handle the remaining sets
-        for outports in prec_list[2:]:
-            for outport in outports:
-                operation = outport.operation
-                if operation.graph_id not in sched._start_times:
-                    op_start_time = 0
-                    for current_input in operation.inputs:
-                        if len(current_input.signals) != 1:
-                            raise ValueError(
-                                "Error in scheduling, dangling input port detected."
-                            )
-                        if current_input.signals[0].source is None:
-                            raise ValueError(
-                                "Error in scheduling, signal with no source detected."
-                            )
-                        source_port = current_input.signals[0].source
-
-                        if source_port.operation.graph_id in non_schedulable_ops:
-                            source_end_time = 0
-                        else:
-                            source_op_time = sched._start_times[
-                                source_port.operation.graph_id
-                            ]
-
-                            if source_port.latency_offset is None:
-                                raise ValueError(
-                                    f"Output port {source_port.index} of"
-                                    " operation"
-                                    f" {source_port.operation.graph_id} has no"
-                                    " latency-offset."
-                                )
-
-                            source_end_time = (
-                                source_op_time + source_port.latency_offset
-                            )
-
-                        if current_input.latency_offset is None:
-                            raise ValueError(
-                                f"Input port {current_input.index} of operation"
-                                f" {current_input.operation.graph_id} has no"
-                                " latency-offset."
-                            )
-                        op_start_time_from_in = (
-                            source_end_time - current_input.latency_offset
-                        )
-                        op_start_time = max(op_start_time, op_start_time_from_in)
-
-                    sched._start_times[operation.graph_id] = op_start_time
-
-        self._handle_outputs_and_delays(non_schedulable_ops)
-
-    def schedule_alap(self) -> None:
-        """Schedule the operations using as-late-as-possible scheduling."""
-        self.schedule_asap()
-        sched = self.schedule
-        max_end_time = sched.get_max_end_time()
-
-        if sched.schedule_time is None:
-            sched.set_schedule_time(max_end_time)
-        elif sched.schedule_time < max_end_time:
-            raise ValueError(f"Too short schedule time. Minimum is {max_end_time}.")
-
-        # move all outputs ALAP before operations
-        for output in sched.sfg.find_by_type_name(Output.type_name()):
-            output = cast(Output, output)
-            sched.move_operation_alap(output.graph_id)
-
-        # move all operations ALAP
-        for step in reversed(sched.sfg.get_precedence_list()):
-            for outport in step:
-                if not isinstance(outport.operation, Delay):
-                    sched.move_operation_alap(outport.operation.graph_id)
-
-    def schedule_earliest_deadline(self, process_elements: list[Operation]) -> None:
-        """Schedule the operations using earliest deadline scheduling."""
-
-        # ACT BASED ON THE NUMBER OF PEs!
-
-        sched = self.schedule
-        prec_list = sched.sfg.get_precedence_list()
-        if len(prec_list) < 2:
-            raise ValueError("Empty signal flow graph cannot be scheduled.")
-
-        # handle the first set in precedence graph (input and delays)
-        non_schedulable_ops = set()
-        for outport in prec_list[0]:
-            operation = outport.operation
-            if operation.type_name() == Delay.type_name():
-                non_schedulable_ops.add(operation.graph_id)
-            elif operation.graph_id not in sched._start_times:
-                sched._start_times[operation.graph_id] = 0
-
-        # latencies = [outport.operation.latency for outport in prec_list[1]]
-        current_time = 0
-        sorted_outports = sorted(
-            prec_list[1], key=lambda outport: outport.operation.latency
-        )
-        for outport in sorted_outports:
-            op = outport.operation
-            sched._start_times[op.graph_id] = current_time
-            current_time += 1
-
-        for outports in prec_list[2:]:
-            # try all remaining operations for one time step
-            candidates = []
-            current_time -= 1
-            while len(candidates) == 0:
-                current_time += 1
-                for outport in outports:
-                    remaining_op = outport.operation
-                    op_is_ready_to_be_scheduled = True
-                    for op_input in remaining_op.inputs:
-                        source_op = op_input.signals[0].source.operation
-                        source_op_time = sched.start_times[source_op.graph_id]
-                        source_end_time = source_op_time + source_op.latency
-                        if source_end_time > current_time:
-                            op_is_ready_to_be_scheduled = False
-                    if op_is_ready_to_be_scheduled:
-                        candidates.append(remaining_op)
-                        # sched._start_times[remaining_op.graph_id] = current_time
-            sorted_candidates = sorted(
-                candidates, key=lambda candidate: candidate.latency
-            )
-            # schedule the best candidate to current time
-            sched._start_times[sorted_candidates[0].graph_id] = current_time
-
-        self._handle_outputs_and_delays(non_schedulable_ops)
-
-    def _handle_outputs_and_delays(self, non_schedulable_ops) -> None:
-        sched = self.schedule
-        for output in sched._sfg.find_by_type_name(Output.type_name()):
-            output = cast(Output, output)
-            source_port = cast(OutputPort, output.inputs[0].signals[0].source)
-            if source_port.operation.graph_id in non_schedulable_ops:
-                sched._start_times[output.graph_id] = 0
-            else:
-                if source_port.latency_offset is None:
-                    raise ValueError(
-                        f"Output port {source_port.index} of operation"
-                        f" {source_port.operation.graph_id} has no"
-                        " latency-offset."
-                    )
-                sched._start_times[output.graph_id] = sched._start_times[
-                    source_port.operation.graph_id
-                ] + cast(int, source_port.latency_offset)
-        sched._remove_delays()
diff --git a/b_asic/scheduler.py b/b_asic/scheduler.py
new file mode 100644
index 00000000..845859c9
--- /dev/null
+++ b/b_asic/scheduler.py
@@ -0,0 +1,193 @@
+from enum import Enum
+from typing import TYPE_CHECKING, cast
+
+from b_asic.operation import Operation
+from b_asic.port import OutputPort
+from b_asic.special_operations import Delay, Output
+
+if TYPE_CHECKING:
+    from b_asic.schedule import Schedule
+
+
+class SchedulingAlgorithm(Enum):
+    ASAP = "ASAP"
+    ALAP = "ALAP"
+    EARLIEST_DEADLINE = "earliest_deadline"
+    # LEAST_SLACK = "least_slack" # to be implemented
+    PROVIDED = "provided"
+
+
+class Scheduler:
+    def __init__(self, schedule: "Schedule") -> None:
+        self.schedule = schedule
+
+    def schedule_asap(self) -> None:
+        """Schedule the operations using as-soon-as-possible scheduling."""
+        sched = self.schedule
+        prec_list = sched.sfg.get_precedence_list()
+        if len(prec_list) < 2:
+            raise ValueError("Empty signal flow graph cannot be scheduled.")
+
+        # handle the first set in precedence graph (input and delays)
+        non_schedulable_ops = set()
+        for outport in prec_list[0]:
+            operation = outport.operation
+            if operation.type_name() == Delay.type_name():
+                non_schedulable_ops.add(operation.graph_id)
+            # elif operation.graph_id not in sched._start_times:
+            else:
+                sched._start_times[operation.graph_id] = 0
+
+        # handle second set in precedence graph (first operations)
+        for outport in prec_list[1]:
+            operation = outport.operation
+            # if operation.graph_id not in sched._start_times:
+            sched._start_times[operation.graph_id] = 0
+
+        # handle the remaining sets
+        for outports in prec_list[2:]:
+            for outport in outports:
+                operation = outport.operation
+                if operation.graph_id not in sched._start_times:
+                    op_start_time = 0
+                    for current_input in operation.inputs:
+                        if len(current_input.signals) != 1:
+                            raise ValueError(
+                                "Error in scheduling, dangling input port detected."
+                            )
+                        if current_input.signals[0].source is None:
+                            raise ValueError(
+                                "Error in scheduling, signal with no source detected."
+                            )
+                        source_port = current_input.signals[0].source
+
+                        if source_port.operation.graph_id in non_schedulable_ops:
+                            source_end_time = 0
+                        else:
+                            source_op_time = sched._start_times[
+                                source_port.operation.graph_id
+                            ]
+
+                            if source_port.latency_offset is None:
+                                raise ValueError(
+                                    f"Output port {source_port.index} of"
+                                    " operation"
+                                    f" {source_port.operation.graph_id} has no"
+                                    " latency-offset."
+                                )
+
+                            source_end_time = (
+                                source_op_time + source_port.latency_offset
+                            )
+
+                        if current_input.latency_offset is None:
+                            raise ValueError(
+                                f"Input port {current_input.index} of operation"
+                                f" {current_input.operation.graph_id} has no"
+                                " latency-offset."
+                            )
+                        op_start_time_from_in = (
+                            source_end_time - current_input.latency_offset
+                        )
+                        op_start_time = max(op_start_time, op_start_time_from_in)
+
+                    sched._start_times[operation.graph_id] = op_start_time
+
+        self._handle_outputs_and_delays(non_schedulable_ops)
+
+    def schedule_alap(self) -> None:
+        """Schedule the operations using as-late-as-possible scheduling."""
+        self.schedule_asap()
+        sched = self.schedule
+        max_end_time = sched.get_max_end_time()
+
+        if sched.schedule_time is None:
+            sched.set_schedule_time(max_end_time)
+        elif sched.schedule_time < max_end_time:
+            raise ValueError(f"Too short schedule time. Minimum is {max_end_time}.")
+
+        # move all outputs ALAP before operations
+        for output in sched.sfg.find_by_type_name(Output.type_name()):
+            output = cast(Output, output)
+            sched.move_operation_alap(output.graph_id)
+
+        # move all operations ALAP
+        for step in reversed(sched.sfg.get_precedence_list()):
+            for outport in step:
+                if not isinstance(outport.operation, Delay):
+                    sched.move_operation_alap(outport.operation.graph_id)
+
+    def schedule_earliest_deadline(
+        self, process_elements: dict[Operation, int]
+    ) -> None:
+        """Schedule the operations using earliest deadline scheduling."""
+
+        # ACT BASED ON THE NUMBER OF PEs!
+
+        sched = self.schedule
+        prec_list = sched.sfg.get_precedence_list()
+        if len(prec_list) < 2:
+            raise ValueError("Empty signal flow graph cannot be scheduled.")
+
+        # handle the first set in precedence graph (input and delays)
+        non_schedulable_ops = set()
+        for outport in prec_list[0]:
+            operation = outport.operation
+            if operation.type_name() == Delay.type_name():
+                non_schedulable_ops.add(operation.graph_id)
+            elif operation.graph_id not in sched._start_times:
+                sched._start_times[operation.graph_id] = 0
+
+        current_time = 0
+        sorted_outports = sorted(
+            prec_list[1], key=lambda outport: outport.operation.latency
+        )
+        for outport in sorted_outports:
+            op = outport.operation
+            sched._start_times[op.graph_id] = current_time
+            current_time += 1
+
+        for outports in prec_list[2:]:
+            # try all remaining operations for one time step
+            candidates = []
+            current_time -= 1
+            while len(candidates) == 0:
+                current_time += 1
+                for outport in outports:
+                    remaining_op = outport.operation
+                    op_is_ready_to_be_scheduled = True
+                    for op_input in remaining_op.inputs:
+                        source_op = op_input.signals[0].source.operation
+                        source_op_time = sched.start_times[source_op.graph_id]
+                        source_end_time = source_op_time + source_op.latency
+                        if source_end_time > current_time:
+                            op_is_ready_to_be_scheduled = False
+                    if op_is_ready_to_be_scheduled:
+                        candidates.append(remaining_op)
+                        # sched._start_times[remaining_op.graph_id] = current_time
+            sorted_candidates = sorted(
+                candidates, key=lambda candidate: candidate.latency
+            )
+            # schedule the best candidate to current time
+            sched._start_times[sorted_candidates[0].graph_id] = current_time
+
+        self._handle_outputs_and_delays(non_schedulable_ops)
+
+    def _handle_outputs_and_delays(self, non_schedulable_ops) -> None:
+        sched = self.schedule
+        for output in sched._sfg.find_by_type_name(Output.type_name()):
+            output = cast(Output, output)
+            source_port = cast(OutputPort, output.inputs[0].signals[0].source)
+            if source_port.operation.graph_id in non_schedulable_ops:
+                sched._start_times[output.graph_id] = 0
+            else:
+                if source_port.latency_offset is None:
+                    raise ValueError(
+                        f"Output port {source_port.index} of operation"
+                        f" {source_port.operation.graph_id} has no"
+                        " latency-offset."
+                    )
+                sched._start_times[output.graph_id] = sched._start_times[
+                    source_port.operation.graph_id
+                ] + cast(int, source_port.latency_offset)
+        sched._remove_delays()
diff --git a/b_asic/scheduling_algorithm.py b/b_asic/scheduling_algorithm.py
deleted file mode 100644
index c6787a73..00000000
--- a/b_asic/scheduling_algorithm.py
+++ /dev/null
@@ -1,9 +0,0 @@
-from enum import Enum
-
-
-class SchedAlg(Enum):
-    ASAP = "ASAP"
-    ALAP = "ALAP"
-    EARLIEST_DEADLINE = "earliest_deadline"
-    LEAST_SLACK = "least_slack"
-    PROVIDED = "provided"
diff --git a/pyproject.toml b/pyproject.toml
index ff1ea7b2..21ece32f 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -12,16 +12,17 @@ dependencies = [
   "matplotlib>=3.7",
   "setuptools_scm[toml]>=6.2",
   "networkx>=3",
-  "qtawesome"
+  "qtawesome",
+  "pyqt6",
 ]
 classifiers = [
   "Intended Audience :: Education",
   "Intended Audience :: Science/Research",
   "Programming Language :: Python :: 3",
-  "Programming Language :: Python :: 3.8",
-  "Programming Language :: Python :: 3.9",
   "Programming Language :: Python :: 3.10",
   "Programming Language :: Python :: 3.11",
+  "Programming Language :: Python :: 3.12",
+  "Programming Language :: Python :: 3.13",
   "Programming Language :: C++",
   "License :: OSI Approved :: MIT License",
   "Operating System :: OS Independent",
-- 
GitLab


From 720336ddda37470237b57937d0ee95912b7001f7 Mon Sep 17 00:00:00 2001
From: Simon Bjurek <simbj106@student.liu.se>
Date: Mon, 27 Jan 2025 16:01:21 +0100
Subject: [PATCH 21/21] fixes from mr comments

---
 pyproject.toml | 1 -
 1 file changed, 1 deletion(-)

diff --git a/pyproject.toml b/pyproject.toml
index 21ece32f..a9074708 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -13,7 +13,6 @@ dependencies = [
   "setuptools_scm[toml]>=6.2",
   "networkx>=3",
   "qtawesome",
-  "pyqt6",
 ]
 classifiers = [
   "Intended Audience :: Education",
-- 
GitLab