diff --git a/b_asic/schedule.py b/b_asic/schedule.py index d6289cff221da2f1a0157790fd6a923d46183271..a842a8b3e531977cfd0377e3df125d04aee4d524 100644 --- a/b_asic/schedule.py +++ b/b_asic/schedule.py @@ -190,14 +190,17 @@ class Schedule: if graph_id not in self._start_times: raise ValueError(f"No operation with graph_id {graph_id} in schedule") output_slacks = self._forward_slacks(graph_id) - return min( - sum( - ( - list(signal_slacks.values()) - for signal_slacks in output_slacks.values() - ), - [sys.maxsize], - ) + return cast( + int, + min( + sum( + ( + list(signal_slacks.values()) + for signal_slacks in output_slacks.values() + ), + [sys.maxsize], + ) + ), ) def _forward_slacks( @@ -255,14 +258,17 @@ class Schedule: if graph_id not in self._start_times: raise ValueError(f"No operation with graph_id {graph_id} in schedule") input_slacks = self._backward_slacks(graph_id) - return min( - sum( - ( - list(signal_slacks.values()) - for signal_slacks in input_slacks.values() - ), - [sys.maxsize], - ) + return cast( + int, + min( + sum( + ( + list(signal_slacks.values()) + for signal_slacks in input_slacks.values() + ), + [sys.maxsize], + ) + ), ) def _backward_slacks(self, graph_id: GraphID) -> Dict[InputPort, Dict[Signal, int]]: @@ -332,15 +338,16 @@ class Schedule: * 1: backward slack * 2: forward slack """ - res = [ + res: List[Tuple[GraphID, int, int]] = [ ( op.graph_id, - self.backward_slack(op.graph_id), + cast(int, self.backward_slack(op.graph_id)), self.forward_slack(op.graph_id), ) for op in self._sfg.operations ] - res = [ + res.sort(key=lambda tup: tup[order]) + res_str = [ ( r[0], f"{r[1]}".rjust(8) if r[1] < sys.maxsize else "oo".rjust(8), @@ -348,10 +355,9 @@ class Schedule: ) for r in res ] - res.sort(key=lambda tup: tup[order]) print("Graph ID | Backward | Forward") print("---------|----------|---------") - for r in res: + for r in res_str: print(f"{r[0]:8} | {r[1]} | {r[2]}") def set_schedule_time(self, time: int) -> "Schedule": @@ -590,6 +596,12 @@ class Schedule: """ self._y_locations[graph_id] = y_location + def _get_minimum_height( + self, operation_height: float = 1.0, operation_gap: float = OPERATION_GAP + ): + max_pos_graph_id = max(self._y_locations, key=self._y_locations.get) + return self._get_y_position(max_pos_graph_id, operation_height, operation_gap) + def move_operation(self, graph_id: GraphID, time: int) -> "Schedule": """ Move an operation in the schedule. @@ -917,10 +929,8 @@ class Schedule: return self._sfg.get_used_type_names() def _get_y_position( - self, graph_id, operation_height=1.0, operation_gap=None + self, graph_id, operation_height=1.0, operation_gap=OPERATION_GAP ) -> float: - if operation_gap is None: - operation_gap = OPERATION_GAP y_location = self._y_locations[graph_id] if y_location is None: # Assign the lowest row number not yet in use @@ -930,7 +940,7 @@ class Schedule: self._y_locations[graph_id] = y_location return operation_gap + y_location * (operation_height + operation_gap) - def _plot_schedule(self, ax: Axes, operation_gap: Optional[float] = None) -> None: + def _plot_schedule(self, ax: Axes, operation_gap: float = OPERATION_GAP) -> None: """Draw the schedule.""" line_cache = [] @@ -969,45 +979,30 @@ class Schedule: ) line_cache.append(start) - elif end[0] == start[0]: - path = Path( - [ - start, - [start[0] + SPLINE_OFFSET, start[1]], - [start[0] + SPLINE_OFFSET, (start[1] + end[1]) / 2], - [start[0], (start[1] + end[1]) / 2], - [start[0] - SPLINE_OFFSET, (start[1] + end[1]) / 2], - [start[0] - SPLINE_OFFSET, end[1]], - end, - ], - [ - Path.MOVETO, - Path.CURVE4, - Path.CURVE4, - Path.CURVE4, - Path.CURVE4, - Path.CURVE4, - Path.CURVE4, - ], - ) - path_patch = PathPatch( - path, - fc='none', - ec=_SIGNAL_COLOR, - lw=SIGNAL_LINEWIDTH, - zorder=10, - ) - ax.add_patch(path_patch) else: - path = Path( - [ - start, - [(start[0] + end[0]) / 2, start[1]], - [(start[0] + end[0]) / 2, end[1]], - end, - ], - [Path.MOVETO, Path.CURVE4, Path.CURVE4, Path.CURVE4], - ) + if end[0] == start[0]: + path = Path( + [ + start, + [start[0] + SPLINE_OFFSET, start[1]], + [start[0] + SPLINE_OFFSET, (start[1] + end[1]) / 2], + [start[0], (start[1] + end[1]) / 2], + [start[0] - SPLINE_OFFSET, (start[1] + end[1]) / 2], + [start[0] - SPLINE_OFFSET, end[1]], + end, + ], + [Path.MOVETO] + [Path.CURVE4] * 6, + ) + else: + path = Path( + [ + start, + [(start[0] + end[0]) / 2, start[1]], + [(start[0] + end[0]) / 2, end[1]], + end, + ], + [Path.MOVETO] + [Path.CURVE4] * 3, + ) path_patch = PathPatch( path, fc='none', @@ -1115,7 +1110,7 @@ class Schedule: """Reset all the y-locations in the schedule to None""" self._y_locations = defaultdict(_y_locations_default) - def plot(self, ax: Axes, operation_gap: Optional[float] = None) -> None: + def plot(self, ax: Axes, operation_gap: OPERATION_GAP) -> None: """ Plot the schedule in a :class:`matplotlib.axes.Axes` or subclass. @@ -1130,7 +1125,7 @@ class Schedule: self._plot_schedule(ax, operation_gap=operation_gap) def show( - self, operation_gap: Optional[float] = None, title: Optional[str] = None + self, operation_gap: float = OPERATION_GAP, title: Optional[str] = None ) -> None: """ Show the schedule. Will display based on the current Matplotlib backend. @@ -1148,7 +1143,7 @@ class Schedule: fig.suptitle(title) fig.show() - def _get_figure(self, operation_gap: Optional[float] = None) -> Figure: + def _get_figure(self, operation_gap: float = OPERATION_GAP) -> Figure: """ Create a Figure and an Axes and plot schedule in the Axes. diff --git a/b_asic/scheduler_gui/operation_item.py b/b_asic/scheduler_gui/operation_item.py index 6f75542d7deb261e29a7f839694f3110689b32f6..f488689fc07d07de3c73e51af21a985ab70850fb 100644 --- a/b_asic/scheduler_gui/operation_item.py +++ b/b_asic/scheduler_gui/operation_item.py @@ -269,24 +269,17 @@ class OperationItem(QGraphicsItemGroup): new_port.setBrush(self._port_filling_brush) new_port.setPos(port_pos.x(), port_pos.y()) self._ports[key]["item"] = new_port + # Add port numbers + port_item = QGraphicsSimpleTextItem(str(i)) + port_item.setScale(port_item.scale() / self._scale) + center = port_item.boundingRect().center() / self._scale + x_offset = center.x() if prefix == "in" else -3 * center.x() + port_item.setPos(QPointF(x + x_offset, y * self._height - center.y())) + self._port_number_items.append(port_item) create_ports(self._operation.get_input_coordinates(), "in") create_ports(self._operation.get_output_coordinates(), "out") - for i, (x, y) in enumerate(self._operation.get_input_coordinates()): - port_item = QGraphicsSimpleTextItem(str(i)) - port_item.setScale(port_item.scale() / self._scale) - center = port_item.boundingRect().center() / self._scale - port_item.setPos(QPointF(x + center.x(), y * self._height - center.y())) - self._port_number_items.append(port_item) - - for i, (x, y) in enumerate(self._operation.get_output_coordinates()): - port_item = QGraphicsSimpleTextItem(str(i)) - port_item.setScale(port_item.scale() / self._scale) - center = port_item.boundingRect().center() / self._scale - port_item.setPos(QPointF(x - 3 * center.x(), y * self._height - center.y())) - self._port_number_items.append(port_item) - # op-id/label self._label_item = QGraphicsSimpleTextItem(self._operation.graph_id) self._label_item.setScale(self._label_item.scale() / self._scale) @@ -312,7 +305,7 @@ class OperationItem(QGraphicsItemGroup): menu.addAction(swap) swap.setEnabled(self._operation.is_swappable) swap.triggered.connect(self._swap_io) - slacks = self._parent._schedule.slacks(self._operation.graph_id) + slacks = self._parent.schedule.slacks(self._operation.graph_id) asap = QAction(get_icon('asap'), "Move as soon as possible") asap.triggered.connect(self._move_asap) asap.setEnabled(slacks[0] > 0) @@ -336,7 +329,7 @@ class OperationItem(QGraphicsItemGroup): self._parent._execution_time_plot(self._operation.type_name()) def _move_asap(self, event=None): - self._parent._schedule.move_operation_asap(self._operation.graph_id) + self._parent.schedule.move_operation_asap(self._operation.graph_id) def _move_alap(self, event=None): - self._parent._schedule.move_operation_alap(self._operation.graph_id) + self._parent.schedule.move_operation_alap(self._operation.graph_id) diff --git a/b_asic/scheduler_gui/scheduler_item.py b/b_asic/scheduler_gui/scheduler_item.py index 4042beb9d08a986e74664884ae101ddd14d89b12..63cae2433380545488696264b05a4bc42b42285e 100644 --- a/b_asic/scheduler_gui/scheduler_item.py +++ b/b_asic/scheduler_gui/scheduler_item.py @@ -27,6 +27,7 @@ from b_asic.scheduler_gui.axes_item import AxesItem from b_asic.scheduler_gui.operation_item import OperationItem from b_asic.scheduler_gui.scheduler_event import SchedulerEvent from b_asic.scheduler_gui.signal_item import SignalItem +from b_asic.types import GraphID class SchedulerItem(SchedulerEvent, QGraphicsItemGroup): # PySide2 / PyQt5 @@ -310,13 +311,7 @@ class SchedulerItem(SchedulerEvent, QGraphicsItemGroup): # PySide2 / PyQt5 def _update_axes(self, build=False) -> None: # build axes schedule_time = self.schedule.schedule_time - max_pos_graph_id = max( - self.schedule._y_locations, key=self.schedule._y_locations.get - ) - y_pos_min = self.schedule._get_y_position( - max_pos_graph_id, OPERATION_HEIGHT, OPERATION_GAP - ) - + y_pos_min = self.schedule._get_minimum_height(OPERATION_HEIGHT, OPERATION_GAP) if self._axes is None or build: self._axes = AxesItem(schedule_time, y_pos_min + 0.5) self._event_items += self._axes.event_items @@ -357,7 +352,7 @@ class SchedulerItem(SchedulerEvent, QGraphicsItemGroup): # PySide2 / PyQt5 self._signal_dict[component].add(gui_signal) self._signal_dict[destination_component].add(gui_signal) - def _swap_io_of_operation(self, graph_id: str) -> None: + def _swap_io_of_operation(self, graph_id: GraphID) -> None: self._schedule.swap_io_of_operation(graph_id) print(f"schedule.swap_io_of_operation({graph_id!r})") self._signals.reopen.emit()