Skip to content
Snippets Groups Projects
Commit 99ad18fc authored by Jacob Wahlman's avatar Jacob Wahlman :ok_hand:
Browse files

Fixed save/load, sfg creating, simulation, bug fixes

parent 3e1b411d
No related branches found
No related tags found
2 merge requests!67WIP: B-ASIC version 1.0.0 hotfix,!65B-ASIC version 1.0.0
......@@ -9,12 +9,10 @@ from b_asic import Signal
class Arrow(QGraphicsLineItem):
def __init__(self, source, destination, window, create_signal=True, parent=None):
def __init__(self, source, destination, window, signal=None, parent=None):
super(Arrow, self).__init__(parent)
self.source = source
# if an signal does not exist create one
if create_signal:
self.signal = Signal(source.port, destination.port)
self.signal = Signal(source.port, destination.port) if signal is None else signal
self.destination = destination
self._window = window
self.moveLine()
......@@ -30,7 +28,18 @@ class Arrow(QGraphicsLineItem):
self.signal.remove_destination()
self.signal.remove_source()
self._window.scene.removeItem(self)
self._window.signalList.remove(self)
if self in self._window.signalList:
self._window.signalList.remove(self)
if self in self._window.signalPortDict:
for port1, port2 in self._window.signalPortDict[self]:
for operation, operation_ports in self._window.portDict.items():
if (port1 in operation_ports or port2 in operation_ports) and operation in self._window.opToSFG:
self._window.logger.info(f"Operation detected in existing sfg, removing sfg with name: {self._window.opToSFG[operation].name}.")
del self._window.sfg_dict[self._window.opToSFG[operation].name]
self._window.opToSFG = {op: self._window.opToSFG[op] for op in self._window.opToSFG if self._window.opToSFG[op] is not self._window.opToSFG[operation]}
del self._window.signalPortDict[self]
def moveLine(self):
self.setPen(QPen(Qt.black, 3))
......
......@@ -123,16 +123,15 @@ class DragButton(QPushButton):
for signal, ports in self._window.signalPortDict.items():
if any(map(lambda port: set(port).intersection(set(self._window.portDict[self])), ports)):
self._window.logger.info(f"Removed signal with name: {signal.signal.name} to/from operation: {self.operation.name}.")
signal.remove()
_signals.append(signal)
for signal in _signals:
signal.remove()
if self in self._window.opToSFG:
self._window.logger.info(f"Operation detected in existing sfg, removing sfg with name: {self._window.opToSFG[self].name}.")
self._window.opToSFG = {op: self._window.opToSFG[op] for op in self._window.opToSFG if self._window.opToSFG[op] is self._window.opToSFG[self]}
del self._window.sfg_dict[self._window.opToSFG[self].name]
for signal in _signals:
del self._window.signalPortDict[signal]
self._window.opToSFG = {op: self._window.opToSFG[op] for op in self._window.opToSFG if self._window.opToSFG[op] is not self._window.opToSFG[self]}
for port in self._window.portDict[self]:
if port in self._window.pressed_ports:
......
......@@ -101,6 +101,8 @@ class MainWindow(QMainWindow):
self.shortcut_save.activated.connect(self.save_work)
self.shortcut_help = QShortcut(QKeySequence("Ctrl+?"), self)
self.shortcut_help.activated.connect(self.display_faq_page)
self.shortcut_signal = QShortcut(QKeySequence(Qt.Key_Space), self)
self.shortcut_signal.activated.connect(self._connect_button)
self.logger.info("Finished setting up GUI")
self.logger.info("For questions please refer to 'Ctrl+?', or visit the 'Help' section on the toolbar.")
......@@ -212,6 +214,7 @@ class MainWindow(QMainWindow):
for op in sfg.split():
self.operationDragDict[op].setToolTip(sfg.name)
self.opToSFG[self.operationDragDict[op]] = sfg
self.sfg_dict[sfg.name] = sfg
self.logger.info(f"Loaded sfg from path: {module}.")
......@@ -257,11 +260,55 @@ class MainWindow(QMainWindow):
sfg = SFG(inputs=inputs, outputs=outputs, name=name)
self.logger.info(f"Created SFG with name: {name} from selected operations.")
sfg_operations = sfg.operations.copy()
for op in self.pressed_operations:
operation = [op_ for op_ in sfg_operations if op_.type_name() == op.operation.type_name()][0]
op.operation = operation
sfg_operations.remove(operation)
def check_equality(signal, signal_2):
if not (signal.source.operation.type_name() == signal_2.source.operation.type_name() \
and signal.destination.operation.type_name() == signal_2.destination.operation.type_name()):
return False
if hasattr(signal.source.operation, "value") and hasattr(signal_2.source.operation, "value") \
and hasattr(signal.destination.operation, "value") and hasattr(signal_2.destination.operation, "value"):
if not (signal.source.operation.value == signal_2.source.operation.value \
and signal.destination.operation.value == signal_2.destination.operation.value):
return False
if hasattr(signal.source.operation, "name") and hasattr(signal_2.source.operation, "name") \
and hasattr(signal.destination.operation, "name") and hasattr(signal_2.destination.operation, "name"):
if not (signal.source.operation.name == signal_2.source.operation.name \
and signal.destination.operation.name == signal_2.destination.operation.name):
return False
try:
_signal_source_index = [signal.source.operation.outputs.index(port) for port in signal.source.operation.outputs if signal in port.signals]
_signal_2_source_index = [signal_2.source.operation.outputs.index(port) for port in signal_2.source.operation.outputs if signal_2 in port.signals]
except ValueError:
return False # Signal output connections not matching
try:
_signal_destination_index = [signal.destination.operation.inputs.index(port) for port in signal.destination.operation.inputs if signal in port.signals]
_signal_2_destination_index = [signal_2.destination.operation.inputs.index(port) for port in signal_2.destination.operation.inputs if signal_2 in port.signals]
except ValueError:
return False # Signal input connections not matching
if not (_signal_source_index == _signal_2_source_index and _signal_destination_index == _signal_2_destination_index):
return False
return True
for pressed_op in self.pressed_operations:
for operation in sfg.operations:
for input_ in operation.inputs:
for signal in input_.signals:
for line in self.signalPortDict:
if check_equality(line.signal, signal):
line.source.operation.operation = signal.source.operation
line.destination.operation.operation = signal.destination.operation
for output_ in operation.outputs:
for signal in output_.signals:
for line in self.signalPortDict:
if check_equality(line.signal, signal):
line.source.operation.operation = signal.source.operation
line.destination.operation.operation = signal.destination.operation
for op in self.pressed_operations:
op.setToolTip(sfg.name)
......@@ -328,7 +375,6 @@ class MainWindow(QMainWindow):
self.add_operations_from_namespace(namespace, self.ui.custom_operations_list)
def create_operation(self, op, position=None):
self.logger.info(f"Creating operation of type: {op.type_name()}.")
try:
attr_button = DragButton(op.graph_id, op, op.type_name().lower(), True, window = self)
if position is None:
......@@ -352,10 +398,9 @@ class MainWindow(QMainWindow):
attr_button.setParent(None)
attr_button_scene = self.scene.addWidget(attr_button)
if position is None:
attr_button_scene.moveBy(self.move_button_index * 100, 0)
attr_button_scene.moveBy(int(self.scene.width() / 2), int(self.scene.height() / 2))
attr_button_scene.setFlag(attr_button_scene.ItemIsSelectable, True)
self.move_button_index += 1
operation_label = QGraphicsTextItem(op.type_name(), attr_button_scene)
operation_label = QGraphicsTextItem(op.name, attr_button_scene)
if not self.is_show_names:
operation_label.setOpacity(0)
operation_label.setTransformOriginPoint(operation_label.boundingRect().center())
......@@ -394,7 +439,7 @@ class MainWindow(QMainWindow):
self.pressed_operations.clear()
super().keyPressEvent(event)
def _connect_button(self, event):
def _connect_button(self, *event):
if len(self.pressed_ports) < 2:
self.logger.warning("Can't connect less than two ports. Please select more.")
return
......@@ -403,6 +448,11 @@ class MainWindow(QMainWindow):
source = self.pressed_ports[i] if isinstance(self.pressed_ports[i].port, OutputPort) else self.pressed_ports[i + 1]
destination = self.pressed_ports[i + 1] if source is not self.pressed_ports[i + 1] else self.pressed_ports[i]
if source.port.operation is destination.port.operation:
self.logger.warning("Can't connect to the same port")
continue
if type(source.port) == type(destination.port):
self.logger.warning(f"Can't connect port of type: {type(source.port).__name__} to port of type: {type(destination.port).__name__}.")
continue
self.connect_button(source, destination)
......@@ -411,9 +461,13 @@ class MainWindow(QMainWindow):
port.select_port()
def connect_button(self, source, destination):
signal_exists = any([signal.destination is destination.port for signal in source.port.signals])
signal_exists = (signal for signal in source.port.signals if signal.destination is destination.port)
self.logger.info(f"Connecting: {source.operation.operation.type_name()} -> {destination.operation.operation.type_name()}.")
line = Arrow(source, destination, self, create_signal=not signal_exists)
try:
line = Arrow(source, destination, self, signal=next(signal_exists))
except StopIteration:
line = Arrow(source, destination, self)
if line not in self.signalPortDict:
self.signalPortDict[line] = []
......
File moved
from PySide2.QtWidgets import QDialog, QLineEdit, QPushButton, QVBoxLayout, QHBoxLayout,\
QLabel, QCheckBox, QGridLayout
from PySide2.QtCore import Qt
from PySide2.QtGui import QIntValidator
from PySide2.QtGui import QDoubleValidator
class PropertiesWindow(QDialog):
def __init__(self, operation, main_window):
......@@ -22,13 +22,17 @@ class PropertiesWindow(QDialog):
self.vertical_layout = QVBoxLayout()
self.vertical_layout.addLayout(self.name_layout)
if self.operation.operation_path_name == "c":
if hasattr(self.operation.operation, "value") or hasattr(self.operation.operation, "initial_value"):
self.constant_layout = QHBoxLayout()
self.constant_layout.setSpacing(50)
self.constant_value = QLabel("Constant:")
self.edit_constant = QLineEdit(str(self.operation.operation.value))
self.only_accept_int = QIntValidator()
self.edit_constant.setValidator(self.only_accept_int)
self.constant_value = QLabel("Value:")
if hasattr(self.operation.operation, "value"):
self.edit_constant = QLineEdit(str(self.operation.operation.value))
else:
self.edit_constant = QLineEdit(str(self.operation.operation.initial_value))
self.only_accept_float = QDoubleValidator()
self.edit_constant.setValidator(self.only_accept_float)
self.constant_layout.addWidget(self.constant_value)
self.constant_layout.addWidget(self.edit_constant)
self.vertical_layout.addLayout(self.constant_layout)
......@@ -66,7 +70,7 @@ class PropertiesWindow(QDialog):
input_value.setPlaceholderText(str(self.operation.operation.latency))
except ValueError:
input_value.setPlaceholderText("-1")
int_valid = QIntValidator()
int_valid = QDoubleValidator()
int_valid.setBottom(-1)
input_value.setValidator(int_valid)
input_value.setFixedWidth(50)
......@@ -101,7 +105,7 @@ class PropertiesWindow(QDialog):
input_value.setPlaceholderText(str(self.operation.operation.latency))
except ValueError:
input_value.setPlaceholderText("-1")
int_valid = QIntValidator()
int_valid = QDoubleValidator()
int_valid.setBottom(-1)
input_value.setValidator(int_valid)
input_value.setFixedWidth(50)
......@@ -122,9 +126,13 @@ class PropertiesWindow(QDialog):
def save_properties(self):
self._window.logger.info(f"Saving properties of operation: {self.operation.name}.")
self.operation.name = self.edit_name.text()
self.operation.operation.name = self.edit_name.text()
self.operation.label.setPlainText(self.operation.name)
if self.operation.operation_path_name == "c":
self.operation.operation.value = int(self.edit_constant.text())
if hasattr(self.operation.operation, "value"):
self.operation.operation.value = float(self.edit_constant.text().replace(",", "."))
elif hasattr(self.operation.operation, "initial_value"):
self.operation.operation.initial_value = float(self.edit_constant.text().replace(",", "."))
if self.check_show_name.isChecked():
self.operation.label.setOpacity(1)
self.operation.is_show_name = True
......@@ -132,6 +140,6 @@ class PropertiesWindow(QDialog):
self.operation.label.setOpacity(0)
self.operation.is_show_name = False
self.operation.operation.set_latency_offsets({port: int(self.latency_fields[port].text()) if self.latency_fields[port].text() and int(self.latency_fields[port].text()) > 0 else None for port in self.latency_fields})
self.operation.operation.set_latency_offsets({port: float(self.latency_fields[port].text().replace(",", ".")) if self.latency_fields[port].text() and float(self.latency_fields[port].text().replace(",", ".")) > 0 else None for port in self.latency_fields})
self.reject()
\ No newline at end of file
from PySide2.QtWidgets import QDialog, QLineEdit, QPushButton, QVBoxLayout, QHBoxLayout,\
QLabel, QCheckBox, QSpinBox, QGroupBox, QFrame, QFormLayout, QGridLayout, QSizePolicy, QFileDialog, QShortcut
from PySide2.QtCore import Qt, Signal
from PySide2.QtGui import QIntValidator, QKeySequence
from PySide2.QtGui import QDoubleValidator, QKeySequence
from matplotlib.backends import qt_compat
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
......@@ -69,9 +69,8 @@ class SimulateSFGWindow(QDialog):
input_label = QLabel("in" + str(i))
input_layout.addWidget(input_label)
input_value = QLineEdit()
input_value.setPlaceholderText("0")
input_value.setValidator(QIntValidator())
input_value.setFixedWidth(50)
input_value.setPlaceholderText("e.g 0, 0, 0")
input_value.setFixedWidth(100)
input_layout.addWidget(input_value)
input_layout.addStretch()
input_layout.setSpacing(10)
......@@ -90,19 +89,47 @@ class SimulateSFGWindow(QDialog):
self.sfg_to_layout[sfg] = sfg_layout
self.dialog_layout.addLayout(sfg_layout)
def save_properties(self):
for sfg, properties in self.input_fields.items():
def parse_input_values(self, input_values):
_input_values = []
for _list in list(input_values):
_list_values = []
for val in _list:
val = val.strip()
try:
if not val:
val = 0
_list_values.append(complex(val))
except ValueError:
self._window.logger.warning(f"Skipping value: {val}, not a digit.")
continue
self.properties[sfg] = {
"iteration_count": self.input_fields[sfg]["iteration_count"].value(),
"show_plot": self.input_fields[sfg]["show_plot"].isChecked(),
"all_results": self.input_fields[sfg]["all_results"].isChecked(),
"input_values": [int(widget.text()) if widget.text() else 0 for widget in self.input_fields[sfg]["input_values"]]
}
_input_values.append(_list_values)
# If we plot we should also print the entire data, since you can't really interact with the graph.
if self.properties[sfg]["show_plot"]:
self.properties[sfg]["all_results"] = True
return _input_values
def save_properties(self):
for sfg, properties in self.input_fields.items():
input_values = self.parse_input_values(widget.text().split(",") if widget.text() else [0] for widget in self.input_fields[sfg]["input_values"])
if max(len(list_) for list_ in input_values) != min(len(list_) for list_ in input_values):
self._window.logger.error(f"Minimum length of input lists are not equal to maximum length of input lists: {max(len(list_) for list_ in input_values)} != {min(len(list_) for list_ in input_values)}.")
elif self.input_fields[sfg]["iteration_count"].value() > min(len(list_) for list_ in input_values):
self._window.logger.error(f"Minimum length of input lists are less than the iteration count: {self.input_fields[sfg]['iteration_count'].value()} > {min(len(list_) for list_ in input_values)}.")
else:
self.properties[sfg] = {
"iteration_count": self.input_fields[sfg]["iteration_count"].value(),
"show_plot": self.input_fields[sfg]["show_plot"].isChecked(),
"all_results": self.input_fields[sfg]["all_results"].isChecked(),
"input_values": input_values
}
# If we plot we should also print the entire data, since you can't really interact with the graph.
if self.properties[sfg]["show_plot"]:
self.properties[sfg]["all_results"] = True
continue
self._window.logger.info(f"Skipping simulation of sfg with name: {sfg.name}, due to previous errors.")
self.accept()
self.simulate.emit()
......
......@@ -62,8 +62,9 @@ def sfg_to_python(sfg: SFG, counter: int = 0, suffix: str = None) -> str:
inputs = "[" + ", ".join(op.graph_id for op in sfg.input_operations) + "]"
outputs = "[" + ", ".join(op.graph_id for op in sfg.output_operations) + "]"
sfg_name = sfg.name if sfg.name else "sfg" + str(counter) if counter > 0 else 'sfg'
result += f"\n{sfg_name} = SFG(inputs={inputs}, outputs={outputs}, name='{sfg_name}')\n"
result += "\n# SFG Properties:\n" + "prop = {'name':" + f"{sfg_name}" + "}"
sfg_name_var = sfg_name.replace(" ", "_")
result += f"\n{sfg_name_var} = SFG(inputs={inputs}, outputs={outputs}, name='{sfg_name}')\n"
result += "\n# SFG Properties:\n" + "prop = {'name':" + f"{sfg_name_var}" + "}"
if suffix is not None:
result += "\n" + suffix + "\n"
......@@ -75,4 +76,4 @@ def python_to_sfg(path: str) -> SFG:
code = compile(f.read(), path, 'exec')
exec(code, globals(), locals())
return locals()["prop"]["name"], locals()["positions"] if "positions" in locals() else None
\ No newline at end of file
return locals()["prop"]["name"], locals()["positions"] if "positions" in locals() else {}
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment