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 PySide2.QtCore import Qt
from qtpy.QtWidgets import QVBoxLayout, QHBoxLayout, QWidget, QDialog, QLabel, QFrame, QScrollArea
from qtpy.QtCore import Qt
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,\
QHBoxLayout, QDockWidget, QToolBar, QMenu, QLayout, QSizePolicy, QListWidget, QListWidgetItem,\
QGraphicsLineItem, QGraphicsWidget
from PySide2.QtCore import Qt, QSize, QLineF, QPoint, QRectF
from PySide2.QtGui import QIcon, QFont, QPainter, QPen
from qtpy.QtCore import Qt, QSize, QLineF, QPoint, QRectF
from qtpy.QtGui import QIcon, QFont, QPainter, QPen
from b_asic.signal import Signal
......
......@@ -8,9 +8,9 @@ import os.path
from b_asic.GUI.properties_window import PropertiesWindow
from b_asic.GUI.utils import decorate_class, handle_error
from PySide2.QtWidgets import QPushButton, QMenu, QAction
from PySide2.QtCore import Qt, QSize, Signal
from PySide2.QtGui import QIcon
from qtpy.QtWidgets import QPushButton, QMenu, QAction
from qtpy.QtCore import Qt, QSize, Signal
from qtpy.QtGui import QIcon
@decorate_class(handle_error)
......
......@@ -7,7 +7,7 @@
# 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):
......
......@@ -32,13 +32,13 @@ from b_asic.save_load_structure import *
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,\
QHBoxLayout, QDockWidget, QToolBar, QMenu, QLayout, QSizePolicy, QListWidget,\
QListWidgetItem, QGraphicsView, QGraphicsScene, QShortcut, QGraphicsTextItem,\
QGraphicsProxyWidget, QInputDialog, QTextEdit, QFileDialog
from PySide2.QtCore import Qt, QSize, QFileInfo
from PySide2.QtGui import QIcon, QFont, QPainter, QPen, QBrush, QKeySequence
from qtpy.QtCore import Qt, QSize, QFileInfo
from qtpy.QtGui import QIcon, QFont, QPainter, QPen, QBrush, QKeySequence
MIN_WIDTH_SCENE = 600
......
import sys
from PySide2.QtWidgets import QPushButton, QMenu
from PySide2.QtCore import Qt, Signal
from qtpy.QtWidgets import QPushButton, QMenu
from qtpy.QtCore import Qt, Signal
class PortButton(QPushButton):
......
from PySide2.QtWidgets import QDialog, QLineEdit, QPushButton, QVBoxLayout, QHBoxLayout,\
from qtpy.QtWidgets import QDialog, QLineEdit, QPushButton, QVBoxLayout, QHBoxLayout,\
QLabel, QCheckBox, QGridLayout
from PySide2.QtCore import Qt
from PySide2.QtGui import QDoubleValidator
from qtpy.QtCore import Qt
from qtpy.QtGui import QDoubleValidator
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
from PySide2.QtCore import Qt, Signal
from PySide2.QtGui import QIntValidator, QKeySequence
from qtpy.QtCore import Qt, Signal
from qtpy.QtGui import QIntValidator, QKeySequence
from matplotlib.backends import qt_compat
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
......
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
from PySide2.QtCore import Qt, Signal
from qtpy.QtCore import Qt, Signal
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
from PySide2.QtCore import Qt, Signal
from PySide2.QtGui import QDoubleValidator, QKeySequence
from qtpy.QtCore import Qt, Signal
from qtpy.QtGui import QDoubleValidator, QKeySequence
from matplotlib.backends import qt_compat
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
......
from PySide2.QtWidgets import QErrorMessage
from qtpy.QtWidgets import QErrorMessage
from traceback import format_exc
def handle_error(fn):
......
......@@ -10,9 +10,10 @@ from io import StringIO
from queue import PriorityQueue
import itertools as it
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.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.graph_component import GraphID, GraphIDNumber, GraphComponent, Name, TypeName
from b_asic.special_operations import Input, Output, Delay
......@@ -452,7 +453,7 @@ class SFG(AbstractOperation):
def remove_operation(self, operation_id: GraphID) -> "SFG":
"""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."""
sfg_copy = self()
operation = sfg_copy.find_by_id(operation_id)
......@@ -504,6 +505,9 @@ class SFG(AbstractOperation):
return self._precedence_list
def show_precedence_graph(self) -> None:
self.precedence_graph().view()
def precedence_graph(self) -> Digraph:
p_list = self.get_precedence_list()
pg = Digraph()
pg.attr(rankdir='LR')
......@@ -514,21 +518,33 @@ class SFG(AbstractOperation):
with pg.subgraph(name='cluster_' + str(i)) as sub:
sub.attr(label='N' + str(i + 1))
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
for i in range(len(p_list)):
ports = p_list[i]
for port in ports:
for signal in port.signals:
pg.edge(port.operation.graph_id + '.' + str(port.index),
signal.destination.operation.graph_id)
pg.node(signal.destination.operation.graph_id,
shape='square')
pg.edge(port.operation.graph_id,
port.operation.graph_id + '.' + str(port.index))
pg.node(port.operation.graph_id, shape='square')
if signal.destination.operation.type_name() == Delay.type_name():
dest_node = signal.destination.operation.graph_id + "In"
else:
dest_node = signal.destination.operation.graph_id
dest_label = signal.destination.operation.graph_id
node_node = port.operation.graph_id + '.' + str(port.index)
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:
"""Prints a representation of the SFG's precedence list to the standard out.
......@@ -561,7 +577,7 @@ class SFG(AbstractOperation):
def get_operations_topological_order(self) -> Iterable[Operation]:
"""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."""
if self._operations_topological_order:
return self._operations_topological_order
......@@ -831,3 +847,71 @@ class SFG(AbstractOperation):
src.index, input_values, results, delays, key_base, bits_override, truncate)
results[key] = 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):
setuptools.setup(
name="b-asic",
version="1.0.0",
author="Adam Jakobsson, Angus Lothian, Arvid Westerlund, Felix Goding, Ivar Härnqvist, Jacob Wahlman, Kevin Scott, Rasmus Karlsson",
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",
version="1.0.1-beta",
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, oscar.gustafsson@liu.se",
description="Better ASIC Toolbox",
long_description=open("README.md", "r").read(),
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",
classifiers=[
"Programming Language :: Python :: 3",
......@@ -76,9 +76,10 @@ setuptools.setup(
],
python_requires=">=3.6",
install_requires=[
"pybind11>=2.3.0",
"numpy",
"pybind11>=2.3.0",
"pyside2",
"qtpy",
"graphviz",
"matplotlib"
],
......
......@@ -1016,3 +1016,49 @@ class TestGetComponentsOfType:
assert [op.name for op in sfg_two_inputs_two_outputs.find_by_type_name(Output.type_name())] \
== ["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")