Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • da/B-ASIC
  • lukja239/B-ASIC
  • robal695/B-ASIC
3 results
Show changes
Commits on Source (6)
from PySide2.QtWidgets import QVBoxLayout, QHBoxLayout, QWidget, QDialog, QLabel, QFrame, QScrollArea from qtpy.QtWidgets import QVBoxLayout, QHBoxLayout, QWidget, QDialog, QLabel, QFrame, QScrollArea
from PySide2.QtCore import Qt from qtpy.QtCore import Qt
QUESTIONS = { QUESTIONS = {
......
from PySide2.QtWidgets import QApplication, QWidget, QMainWindow, QLabel, QAction,\ from qtpy.QtWidgets import QApplication, QWidget, QMainWindow, QLabel, QAction,\
QStatusBar, QMenuBar, QLineEdit, QPushButton, QSlider, QScrollArea, QVBoxLayout,\ QStatusBar, QMenuBar, QLineEdit, QPushButton, QSlider, QScrollArea, QVBoxLayout,\
QHBoxLayout, QDockWidget, QToolBar, QMenu, QLayout, QSizePolicy, QListWidget, QListWidgetItem,\ QHBoxLayout, QDockWidget, QToolBar, QMenu, QLayout, QSizePolicy, QListWidget, QListWidgetItem,\
QGraphicsLineItem, QGraphicsWidget QGraphicsLineItem, QGraphicsWidget
from PySide2.QtCore import Qt, QSize, QLineF, QPoint, QRectF from qtpy.QtCore import Qt, QSize, QLineF, QPoint, QRectF
from PySide2.QtGui import QIcon, QFont, QPainter, QPen from qtpy.QtGui import QIcon, QFont, QPainter, QPen
from b_asic.signal import Signal from b_asic.signal import Signal
......
...@@ -8,9 +8,9 @@ import os.path ...@@ -8,9 +8,9 @@ import os.path
from b_asic.GUI.properties_window import PropertiesWindow from b_asic.GUI.properties_window import PropertiesWindow
from b_asic.GUI.utils import decorate_class, handle_error from b_asic.GUI.utils import decorate_class, handle_error
from PySide2.QtWidgets import QPushButton, QMenu, QAction from qtpy.QtWidgets import QPushButton, QMenu, QAction
from PySide2.QtCore import Qt, QSize, Signal from qtpy.QtCore import Qt, QSize, Signal
from PySide2.QtGui import QIcon from qtpy.QtGui import QIcon
@decorate_class(handle_error) @decorate_class(handle_error)
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
# WARNING! All changes made in this file will be lost! # WARNING! All changes made in this file will be lost!
from PySide2 import QtCore, QtGui, QtWidgets from qtpy import QtCore, QtGui, QtWidgets
class Ui_main_window(object): class Ui_main_window(object):
......
...@@ -32,13 +32,13 @@ from b_asic.save_load_structure import * ...@@ -32,13 +32,13 @@ from b_asic.save_load_structure import *
from numpy import linspace from numpy import linspace
from PySide2.QtWidgets import QApplication, QWidget, QMainWindow, QLabel, QAction,\ from qtpy.QtWidgets import QApplication, QWidget, QMainWindow, QLabel, QAction,\
QStatusBar, QMenuBar, QLineEdit, QPushButton, QSlider, QScrollArea, QVBoxLayout,\ QStatusBar, QMenuBar, QLineEdit, QPushButton, QSlider, QScrollArea, QVBoxLayout,\
QHBoxLayout, QDockWidget, QToolBar, QMenu, QLayout, QSizePolicy, QListWidget,\ QHBoxLayout, QDockWidget, QToolBar, QMenu, QLayout, QSizePolicy, QListWidget,\
QListWidgetItem, QGraphicsView, QGraphicsScene, QShortcut, QGraphicsTextItem,\ QListWidgetItem, QGraphicsView, QGraphicsScene, QShortcut, QGraphicsTextItem,\
QGraphicsProxyWidget, QInputDialog, QTextEdit, QFileDialog QGraphicsProxyWidget, QInputDialog, QTextEdit, QFileDialog
from PySide2.QtCore import Qt, QSize, QFileInfo from qtpy.QtCore import Qt, QSize, QFileInfo
from PySide2.QtGui import QIcon, QFont, QPainter, QPen, QBrush, QKeySequence from qtpy.QtGui import QIcon, QFont, QPainter, QPen, QBrush, QKeySequence
MIN_WIDTH_SCENE = 600 MIN_WIDTH_SCENE = 600
......
import sys import sys
from PySide2.QtWidgets import QPushButton, QMenu from qtpy.QtWidgets import QPushButton, QMenu
from PySide2.QtCore import Qt, Signal from qtpy.QtCore import Qt, Signal
class PortButton(QPushButton): class PortButton(QPushButton):
......
from PySide2.QtWidgets import QDialog, QLineEdit, QPushButton, QVBoxLayout, QHBoxLayout,\ from qtpy.QtWidgets import QDialog, QLineEdit, QPushButton, QVBoxLayout, QHBoxLayout,\
QLabel, QCheckBox, QGridLayout QLabel, QCheckBox, QGridLayout
from PySide2.QtCore import Qt from qtpy.QtCore import Qt
from PySide2.QtGui import QDoubleValidator from qtpy.QtGui import QDoubleValidator
class PropertiesWindow(QDialog): class PropertiesWindow(QDialog):
......
from PySide2.QtWidgets import QDialog, QLineEdit, QPushButton, QVBoxLayout, QHBoxLayout,\ from qtpy.QtWidgets import QDialog, QLineEdit, QPushButton, QVBoxLayout, QHBoxLayout,\
QLabel, QCheckBox, QSpinBox, QGroupBox, QFrame, QFormLayout, QGridLayout, QSizePolicy, QFileDialog, QShortcut, QComboBox QLabel, QCheckBox, QSpinBox, QGroupBox, QFrame, QFormLayout, QGridLayout, QSizePolicy, QFileDialog, QShortcut, QComboBox
from PySide2.QtCore import Qt, Signal from qtpy.QtCore import Qt, Signal
from PySide2.QtGui import QIntValidator, QKeySequence from qtpy.QtGui import QIntValidator, QKeySequence
from matplotlib.backends import qt_compat from matplotlib.backends import qt_compat
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
......
from b_asic.signal_flow_graph import SFG from b_asic.signal_flow_graph import SFG
from PySide2.QtWidgets import QDialog, QPushButton, QVBoxLayout, QCheckBox,\ from qtpy.QtWidgets import QDialog, QPushButton, QVBoxLayout, QCheckBox,\
QFrame, QFormLayout QFrame, QFormLayout
from PySide2.QtCore import Qt, Signal from qtpy.QtCore import Qt, Signal
class ShowPCWindow(QDialog): class ShowPCWindow(QDialog):
......
from PySide2.QtWidgets import QDialog, QLineEdit, QPushButton, QVBoxLayout, QHBoxLayout,\ from qtpy.QtWidgets import QDialog, QLineEdit, QPushButton, QVBoxLayout, QHBoxLayout,\
QLabel, QCheckBox, QSpinBox, QGroupBox, QFrame, QFormLayout, QGridLayout, QSizePolicy, QFileDialog, QShortcut QLabel, QCheckBox, QSpinBox, QGroupBox, QFrame, QFormLayout, QGridLayout, QSizePolicy, QFileDialog, QShortcut
from PySide2.QtCore import Qt, Signal from qtpy.QtCore import Qt, Signal
from PySide2.QtGui import QDoubleValidator, QKeySequence from qtpy.QtGui import QDoubleValidator, QKeySequence
from matplotlib.backends import qt_compat from matplotlib.backends import qt_compat
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
......
from PySide2.QtWidgets import QErrorMessage from qtpy.QtWidgets import QErrorMessage
from traceback import format_exc from traceback import format_exc
def handle_error(fn): def handle_error(fn):
......
...@@ -10,9 +10,10 @@ from io import StringIO ...@@ -10,9 +10,10 @@ from io import StringIO
from queue import PriorityQueue from queue import PriorityQueue
import itertools as it import itertools as it
from graphviz import Digraph from graphviz import Digraph
from graphviz.backend import FORMATS as GRAPHVIZ_FORMATS, ENGINES as GRAPHVIZ_ENGINES
from b_asic.port import SignalSourceProvider, OutputPort from b_asic.port import SignalSourceProvider, OutputPort
from b_asic.operation import Operation, AbstractOperation, ResultKey, DelayMap, MutableResultMap, MutableDelayMap from b_asic.operation import Operation, AbstractOperation, ResultKey, MutableResultMap, MutableDelayMap
from b_asic.signal import Signal from b_asic.signal import Signal
from b_asic.graph_component import GraphID, GraphIDNumber, GraphComponent, Name, TypeName from b_asic.graph_component import GraphID, GraphIDNumber, GraphComponent, Name, TypeName
from b_asic.special_operations import Input, Output, Delay from b_asic.special_operations import Input, Output, Delay
...@@ -452,7 +453,7 @@ class SFG(AbstractOperation): ...@@ -452,7 +453,7 @@ class SFG(AbstractOperation):
def remove_operation(self, operation_id: GraphID) -> "SFG": def remove_operation(self, operation_id: GraphID) -> "SFG":
"""Returns a version of the SFG where the operation with the specified GraphID removed. """Returns a version of the SFG where the operation with the specified GraphID removed.
The operation has to have the same amount of input- and output ports or a ValueError will The operation has to have the same amount of input- and output ports or a ValueError will
be raised. If no operation with the entered operation_id is found then returns None and does nothing.""" be raised. If no operation with the entered operation_id is found then returns None and does nothing."""
sfg_copy = self() sfg_copy = self()
operation = sfg_copy.find_by_id(operation_id) operation = sfg_copy.find_by_id(operation_id)
...@@ -504,6 +505,9 @@ class SFG(AbstractOperation): ...@@ -504,6 +505,9 @@ class SFG(AbstractOperation):
return self._precedence_list return self._precedence_list
def show_precedence_graph(self) -> None: def show_precedence_graph(self) -> None:
self.precedence_graph().view()
def precedence_graph(self) -> Digraph:
p_list = self.get_precedence_list() p_list = self.get_precedence_list()
pg = Digraph() pg = Digraph()
pg.attr(rankdir='LR') pg.attr(rankdir='LR')
...@@ -514,21 +518,33 @@ class SFG(AbstractOperation): ...@@ -514,21 +518,33 @@ class SFG(AbstractOperation):
with pg.subgraph(name='cluster_' + str(i)) as sub: with pg.subgraph(name='cluster_' + str(i)) as sub:
sub.attr(label='N' + str(i + 1)) sub.attr(label='N' + str(i + 1))
for port in ports: for port in ports:
sub.node(port.operation.graph_id + '.' + str(port.index)) if port.operation.output_count > 1:
sub.node(port.operation.graph_id + '.' + str(port.index))
else:
sub.node(port.operation.graph_id + '.' + str(port.index), label=port.operation.graph_id)
# Creates edges for each output port and creates nodes for each operation and edges for them as well # Creates edges for each output port and creates nodes for each operation and edges for them as well
for i in range(len(p_list)): for i in range(len(p_list)):
ports = p_list[i] ports = p_list[i]
for port in ports: for port in ports:
for signal in port.signals: for signal in port.signals:
pg.edge(port.operation.graph_id + '.' + str(port.index), if signal.destination.operation.type_name() == Delay.type_name():
signal.destination.operation.graph_id) dest_node = signal.destination.operation.graph_id + "In"
pg.node(signal.destination.operation.graph_id, else:
shape='square') dest_node = signal.destination.operation.graph_id
pg.edge(port.operation.graph_id, dest_label = signal.destination.operation.graph_id
port.operation.graph_id + '.' + str(port.index)) node_node = port.operation.graph_id + '.' + str(port.index)
pg.node(port.operation.graph_id, shape='square') pg.edge(node_node, dest_node)
pg.node(dest_node, label=dest_label, shape='square')
if port.operation.type_name() == Delay.type_name():
source_node = port.operation.graph_id + "Out"
else:
source_node = port.operation.graph_id
source_label = port.operation.graph_id
node_node = port.operation.graph_id + '.' + str(port.index)
pg.edge(source_node, node_node)
pg.node(source_node, label=source_label, shape='square')
pg.view() return pg
def print_precedence_graph(self) -> None: def print_precedence_graph(self) -> None:
"""Prints a representation of the SFG's precedence list to the standard out. """Prints a representation of the SFG's precedence list to the standard out.
...@@ -561,7 +577,7 @@ class SFG(AbstractOperation): ...@@ -561,7 +577,7 @@ class SFG(AbstractOperation):
def get_operations_topological_order(self) -> Iterable[Operation]: def get_operations_topological_order(self) -> Iterable[Operation]:
"""Returns an Iterable of the Operations in the SFG in Topological Order. """Returns an Iterable of the Operations in the SFG in Topological Order.
Feedback loops makes an absolutely correct Topological order impossible, so an Feedback loops makes an absolutely correct Topological order impossible, so an
approximative Topological Order is returned in such cases in this implementation.""" approximative Topological Order is returned in such cases in this implementation."""
if self._operations_topological_order: if self._operations_topological_order:
return self._operations_topological_order return self._operations_topological_order
...@@ -831,3 +847,71 @@ class SFG(AbstractOperation): ...@@ -831,3 +847,71 @@ class SFG(AbstractOperation):
src.index, input_values, results, delays, key_base, bits_override, truncate) src.index, input_values, results, delays, key_base, bits_override, truncate)
results[key] = value results[key] = value
return value return value
def sfg(self, show_id=False, engine=None) -> Digraph:
"""
Returns a Digraph of the SFG. Can be directly displayed in IPython.
Parameters
----------
show_id : Boolean, optional
If True, the graph_id:s of signals are shown. The default is False.
engine: string, optional
Graphviz layout engine to be used, see https://graphviz.org/documentation/.
Most common are "dot" and "neato". Default is None leading to dot.
Returns
-------
Digraph
Digraph of the SFG.
"""
dg = Digraph()
dg.attr(rankdir='LR')
if engine:
assert engine in GRAPHVIZ_ENGINES, "Unknown layout engine"
dg.engine = engine
for op in self._components_by_id.values():
if isinstance(op, Signal):
if show_id:
dg.edge(op.source.operation.graph_id, op.destination.operation.graph_id, label=op.graph_id)
else:
dg.edge(op.source.operation.graph_id, op.destination.operation.graph_id)
else:
if op.type_name() == Delay.type_name():
dg.node(op.graph_id, shape='square')
else:
dg.node(op.graph_id)
return dg
def _repr_svg_(self):
return self.sfg()._repr_svg_()
def show_sfg(self, format=None, show_id=False, engine=None) -> None:
"""
Shows a visual representation of the SFG using the default system viewer.
Parameters
----------
format : string, optional
File format of the generated graph. Output formats can be found at https://www.graphviz.org/doc/info/output.html
Most common are "pdf", "eps", "png", and "svg". Default is None which leads to PDF.
show_id : Boolean, optional
If True, the graph_id:s of signals are shown. The default is False.
engine: string, optional
Graphviz layout engine to be used, see https://graphviz.org/documentation/.
Most common are "dot" and "neato". Default is None leading to dot.
"""
dg = self.sfg(show_id=show_id)
if format:
assert format in GRAPHVIZ_FORMATS, "Unknown file format"
dg.format = format
if engine:
assert engine in GRAPHVIZ_ENGINES, "Unknown layout engine"
dg.engine = engine
dg.view()
...@@ -61,13 +61,13 @@ class CMakeBuild(build_ext): ...@@ -61,13 +61,13 @@ class CMakeBuild(build_ext):
setuptools.setup( setuptools.setup(
name="b-asic", name="b-asic",
version="1.0.0", version="1.0.1-beta",
author="Adam Jakobsson, Angus Lothian, Arvid Westerlund, Felix Goding, Ivar Härnqvist, Jacob Wahlman, Kevin Scott, Rasmus Karlsson", author="Adam Jakobsson, Angus Lothian, Arvid Westerlund, Felix Goding, Ivar Härnqvist, Jacob Wahlman, Kevin Scott, Rasmus Karlsson, Oscar Gustafsson",
author_email="adaja901@student.liu.se, anglo547@student.liu.se, arvwe160@student.liu.se, felgo673@student.liu.se, ivaha717@student.liu.se, jacwa448@student.liu.se, kevsc634@student.liu.se, raska119@student.liu.se", author_email="adaja901@student.liu.se, anglo547@student.liu.se, arvwe160@student.liu.se, felgo673@student.liu.se, ivaha717@student.liu.se, jacwa448@student.liu.se, kevsc634@student.liu.se, raska119@student.liu.se, oscar.gustafsson@liu.se",
description="Better ASIC Toolbox", description="Better ASIC Toolbox",
long_description=open("README.md", "r").read(), long_description=open("README.md", "r").read(),
long_description_content_type="text/markdown", long_description_content_type="text/markdown",
url="https://gitlab.liu.se/PUM_TDDD96/B-ASIC", url="https://gitlab.liu.se/da/B-ASIC",
license="MIT", license="MIT",
classifiers=[ classifiers=[
"Programming Language :: Python :: 3", "Programming Language :: Python :: 3",
...@@ -76,9 +76,10 @@ setuptools.setup( ...@@ -76,9 +76,10 @@ setuptools.setup(
], ],
python_requires=">=3.6", python_requires=">=3.6",
install_requires=[ install_requires=[
"pybind11>=2.3.0",
"numpy", "numpy",
"pybind11>=2.3.0",
"pyside2", "pyside2",
"qtpy",
"graphviz", "graphviz",
"matplotlib" "matplotlib"
], ],
......
...@@ -1016,3 +1016,49 @@ class TestGetComponentsOfType: ...@@ -1016,3 +1016,49 @@ class TestGetComponentsOfType:
assert [op.name for op in sfg_two_inputs_two_outputs.find_by_type_name(Output.type_name())] \ assert [op.name for op in sfg_two_inputs_two_outputs.find_by_type_name(Output.type_name())] \
== ["OUT1", "OUT2"] == ["OUT1", "OUT2"]
class TestPrecedenceGraph:
def test_precedence_graph(self, sfg_simple_filter):
res = 'digraph {\n\trankdir=LR\n\tsubgraph cluster_0 ' \
'{\n\t\tlabel=N1\n\t\t"in1.0" [label=in1]\n\t\t"t1.0" [label=t1]' \
'\n\t}\n\tsubgraph cluster_1 {\n\t\tlabel=N2\n\t\t"cmul1.0" ' \
'[label=cmul1]\n\t}\n\tsubgraph cluster_2 ' \
'{\n\t\tlabel=N3\n\t\t"add1.0" [label=add1]\n\t}\n\t"in1.0" ' \
'-> add1\n\tadd1 [label=add1 shape=square]\n\tin1 -> "in1.0"' \
'\n\tin1 [label=in1 shape=square]\n\t"t1.0" -> cmul1\n\tcmul1 ' \
'[label=cmul1 shape=square]\n\t"t1.0" -> out1\n\tout1 ' \
'[label=out1 shape=square]\n\tt1Out -> "t1.0"\n\tt1Out ' \
'[label=t1 shape=square]\n\t"cmul1.0" -> add1\n\tadd1 ' \
'[label=add1 shape=square]\n\tcmul1 -> "cmul1.0"\n\tcmul1 ' \
'[label=cmul1 shape=square]\n\t"add1.0" -> t1In\n\tt1In ' \
'[label=t1 shape=square]\n\tadd1 -> "add1.0"\n\tadd1 ' \
'[label=add1 shape=square]\n}'
assert sfg_simple_filter.precedence_graph().source == res
class TestSFGGraph:
def test_sfg(self, sfg_simple_filter):
res = 'digraph {\n\trankdir=LR\n\tin1\n\tin1 -> ' \
'add1\n\tout1\n\tt1 -> out1\n\tadd1\n\tcmul1 -> ' \
'add1\n\tcmul1\n\tadd1 -> t1\n\tt1 [shape=square]\n\tt1 ' \
'-> cmul1\n}'
assert sfg_simple_filter.sfg().source == res
def test_sfg_show_id(self, sfg_simple_filter):
res = 'digraph {\n\trankdir=LR\n\tin1\n\tin1 -> add1 ' \
'[label=s1]\n\tout1\n\tt1 -> out1 [label=s2]\n\tadd1' \
'\n\tcmul1 -> add1 [label=s3]\n\tcmul1\n\tadd1 -> t1 ' \
'[label=s4]\n\tt1 [shape=square]\n\tt1 -> cmul1 [label=s5]\n}'
assert sfg_simple_filter.sfg(show_id=True).source == res
def test_show_sfg_invalid_format(self, sfg_simple_filter):
with pytest.raises(AssertionError):
sfg_simple_filter.show_sfg(format="ppddff")
def test_show_sfg_invalid_engine(self, sfg_simple_filter):
with pytest.raises(AssertionError):
sfg_simple_filter.show_sfg(engine="ppddff")