diff --git a/b_asic/signal_flow_graph.py b/b_asic/signal_flow_graph.py index 3be91ad3a77cb8a3f1feeb7d2631ec30a6ae2206..fb7849134d1a34c60295de7e797c02cd56801404 100644 --- a/b_asic/signal_flow_graph.py +++ b/b_asic/signal_flow_graph.py @@ -1242,7 +1242,16 @@ class SFG(AbstractOperation): self, original_component: GraphComponent ) -> GraphComponent: if original_component in self._original_components_to_new: - raise ValueError("Tried to add duplicate SFG component") + id = ( + original_component.name + if original_component.name + else ( + original_component.graph_id + if original_component.graph_id + else original_component.type_name() + ) + ) + raise ValueError(f"Tried to add duplicate SFG component: {id}") new_component = original_component.copy() self._original_components_to_new[original_component] = new_component if not new_component.graph_id or new_component.graph_id in self._used_ids: @@ -1273,7 +1282,16 @@ class SFG(AbstractOperation): # Connect input ports to new signals. for original_input_port in original_op.inputs: if original_input_port.signal_count < 1: - raise ValueError("Unconnected input port in SFG") + id = ( + original_op.name + if original_op.name + else ( + original_op.graph_id + if original_op.graph_id + else original_op.type_name() + ) + ) + raise ValueError(f"Unconnected input port in SFG. Operation: {id}") for original_signal in original_input_port.signals: # Check if the signal is one of the SFG's input signals. @@ -1509,7 +1527,7 @@ class SFG(AbstractOperation): def sfg_digraph( self, - show_id: bool = False, + show_signal_id: bool = False, engine: Optional[str] = None, branch_node: bool = True, port_numbering: bool = True, @@ -1522,7 +1540,7 @@ class SFG(AbstractOperation): Parameters ---------- - show_id : bool, default: False + show_signal_id : bool, default: False If True, the graph_id:s of signals are shown. engine : str, optional Graphviz layout engine to be used, see https://graphviz.org/documentation/. @@ -1554,7 +1572,7 @@ class SFG(AbstractOperation): if branch_node and source.signal_count > 1 else source.operation.graph_id ) - label = op.graph_id if show_id else None + label = op.graph_id if show_signal_id else None taillabel = ( str(source.index) if source.operation.output_count > 1 @@ -1593,7 +1611,11 @@ class SFG(AbstractOperation): taillabel=taillabel, ) else: - dg.node(op.graph_id, shape=_OPERATION_SHAPE[op.type_name()]) + dg.node( + op.graph_id, + shape=_OPERATION_SHAPE[op.type_name()], + label=f"{op.name}\n({op.graph_id})" if op.name else None, + ) return dg def _repr_mimebundle_(self, include=None, exclude=None): @@ -1618,7 +1640,7 @@ class SFG(AbstractOperation): def show( self, fmt: Optional[str] = None, - show_id: bool = False, + show_signal_id: bool = False, engine: Optional[str] = None, branch_node: bool = True, port_numbering: bool = True, @@ -1634,7 +1656,7 @@ class SFG(AbstractOperation): 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 : bool, default: False + show_signal_id : bool, default: False If True, the graph_id:s of signals are shown. engine : str, optional Graphviz layout engine to be used, see https://graphviz.org/documentation/. @@ -1649,7 +1671,7 @@ class SFG(AbstractOperation): """ dg = self.sfg_digraph( - show_id=show_id, + show_signal_id=show_signal_id, engine=engine, branch_node=branch_node, port_numbering=port_numbering, diff --git a/test/fixtures/signal_flow_graph.py b/test/fixtures/signal_flow_graph.py index 173c495318cf5fd2e9f6d6032a382c2aa889aed3..21c07d0f77e495a2c647839b3d9718352953838c 100644 --- a/test/fixtures/signal_flow_graph.py +++ b/test/fixtures/signal_flow_graph.py @@ -180,13 +180,13 @@ def sfg_simple_filter(): in1---->add1----->t1+---->out1 . . """ - in1 = Input("IN1") - cmul1 = ConstantMultiplication(0.5, name="CMUL1") - add1 = Addition(in1, cmul1, "ADD1") + in1 = Input("IN") + cmul1 = ConstantMultiplication(0.5, name="CMUL") + add1 = Addition(in1, cmul1, "ADD") add1.input(1).signals[0].name = "S2" - t1 = Delay(add1, name="T1") + t1 = Delay(add1, name="T") cmul1.input(0).connect(t1, "S1") - out1 = Output(t1, "OUT1") + out1 = Output(t1, "OUT") return SFG(inputs=[in1], outputs=[out1], name="simple_filter") diff --git a/test/test_sfg.py b/test/test_sfg.py index 44cba8247e84098e26f75292eb5019e6767900ce..ab38f328dcf32e6f54c3dfc1bae9f39166be1005 100644 --- a/test/test_sfg.py +++ b/test/test_sfg.py @@ -163,15 +163,15 @@ class TestPrintSfg: + "Internal Operations:\n" + "--------------------------------------------------------------------" + "--------------------------------\n" - + str(sfg_simple_filter.find_by_name("IN1")[0]) + + str(sfg_simple_filter.find_by_name("IN")[0]) + "\n" - + str(sfg_simple_filter.find_by_name("ADD1")[0]) + + str(sfg_simple_filter.find_by_name("ADD")[0]) + "\n" - + str(sfg_simple_filter.find_by_name("T1")[0]) + + str(sfg_simple_filter.find_by_name("T")[0]) + "\n" - + str(sfg_simple_filter.find_by_name("CMUL1")[0]) + + str(sfg_simple_filter.find_by_name("CMUL")[0]) + "\n" - + str(sfg_simple_filter.find_by_name("OUT1")[0]) + + str(sfg_simple_filter.find_by_name("OUT")[0]) + "\n" + "--------------------------------------------------------------------" + "--------------------------------\n" @@ -958,11 +958,11 @@ class TestTopologicalOrderOperations: topological_order = sfg_simple_filter.get_operations_topological_order() assert [comp.name for comp in topological_order] == [ - "IN1", - "ADD1", - "T1", - "CMUL1", - "OUT1", + "IN", + "ADD", + "T", + "CMUL", + "OUT", ] def test_multiple_independent_inputs(self, sfg_two_inputs_two_outputs_independent): @@ -1007,26 +1007,25 @@ class TestRemove: assert { op.name - for op in sfg_simple_filter.find_by_name("T1")[0].subsequent_operations - } == {"CMUL1", "OUT1"} + for op in sfg_simple_filter.find_by_name("T")[0].subsequent_operations + } == {"CMUL", "OUT"} assert { - op.name for op in new_sfg.find_by_name("T1")[0].subsequent_operations - } == {"ADD1", "OUT1"} + op.name for op in new_sfg.find_by_name("T")[0].subsequent_operations + } == {"ADD", "OUT"} assert { op.name - for op in sfg_simple_filter.find_by_name("ADD1")[0].preceding_operations - } == {"CMUL1", "IN1"} + for op in sfg_simple_filter.find_by_name("ADD")[0].preceding_operations + } == {"CMUL", "IN"} assert { - op.name for op in new_sfg.find_by_name("ADD1")[0].preceding_operations - } == {"T1", "IN1"} + op.name for op in new_sfg.find_by_name("ADD")[0].preceding_operations + } == {"T", "IN"} assert "S1" in { - sig.name - for sig in sfg_simple_filter.find_by_name("T1")[0].output(0).signals + sig.name for sig in sfg_simple_filter.find_by_name("T")[0].output(0).signals } assert "S2" in { - sig.name for sig in new_sfg.find_by_name("T1")[0].output(0).signals + sig.name for sig in new_sfg.find_by_name("T")[0].output(0).signals } def test_remove_multiple_inputs_outputs(self, butterfly_operation_tree): @@ -1217,59 +1216,105 @@ class TestPrecedenceGraph: class TestSFGGraph: def test_sfg(self, sfg_simple_filter): - res = ( - 'digraph {\n\trankdir=LR splines=spline\n\tin0 [shape=cds]\n\tin0 -> add0' - ' [headlabel=0]\n\tout0 [shape=cds]\n\tt0 -> out0\n\tadd0' - ' [shape=ellipse]\n\tcmul0 -> add0 [headlabel=1]\n\tcmul0' - ' [shape=ellipse]\n\tadd0 -> t0\n\tt0 [shape=square]\n\tt0 -> cmul0\n}' - ) - assert sfg_simple_filter.sfg_digraph(branch_node=False).source in ( + res = """digraph { + rankdir=LR splines=spline + in0 [label="IN +(in0)" shape=cds] + in0 -> add0 [headlabel=0] + out0 [label="OUT +(out0)" shape=cds] + "t0.0" -> out0 + "t0.0" [shape=point] + t0 -> "t0.0" [arrowhead=none] + add0 [label="ADD +(add0)" shape=ellipse] + cmul0 -> add0 [headlabel=1] + cmul0 [label="CMUL +(cmul0)" shape=ellipse] + add0 -> t0 + t0 [label="T +(t0)" shape=square] + "t0.0" -> cmul0 +}""" + assert sfg_simple_filter.sfg_digraph().source in ( res, res + "\n", ) - def test_sfg_show_id(self, sfg_simple_filter): - res = ( - 'digraph {\n\trankdir=LR splines=spline\n\tin0 [shape=cds]\n\tin0 -> add0' - ' [label=s0 headlabel=0]\n\tout0 [shape=cds]\n\tt0 -> out0' - ' [label=s1]\n\tadd0 [shape=ellipse]\n\tcmul0 -> add0 [label=s2' - ' headlabel=1]\n\tcmul0 [shape=ellipse]\n\tadd0 -> t0 [label=s3]\n\tt0' - ' [shape=square]\n\tt0 -> cmul0 [label=s4]\n}' - ) - - assert sfg_simple_filter.sfg_digraph( - show_id=True, branch_node=False - ).source in ( + def test_sfg_show_signal_id(self, sfg_simple_filter): + res = """digraph { + rankdir=LR splines=spline + in0 [label="IN +(in0)" shape=cds] + in0 -> add0 [label=s0 headlabel=0] + out0 [label="OUT +(out0)" shape=cds] + "t0.0" -> out0 [label=s1] + "t0.0" [shape=point] + t0 -> "t0.0" [arrowhead=none] + add0 [label="ADD +(add0)" shape=ellipse] + cmul0 -> add0 [label=s2 headlabel=1] + cmul0 [label="CMUL +(cmul0)" shape=ellipse] + add0 -> t0 [label=s3] + t0 [label="T +(t0)" shape=square] + "t0.0" -> cmul0 [label=s4] +}""" + + assert sfg_simple_filter.sfg_digraph(show_signal_id=True).source in ( res, res + "\n", ) - def test_sfg_branch(self, sfg_simple_filter): - res = ( - 'digraph {\n\trankdir=LR splines=spline\n\tin0 [shape=cds]\n\tin0 -> add0' - ' [headlabel=0]\n\tout0 [shape=cds]\n\t"t0.0" -> out0\n\t"t0.0"' - ' [shape=point]\n\tt0 -> "t0.0" [arrowhead=none]\n\tadd0' - ' [shape=ellipse]\n\tcmul0 -> add0 [headlabel=1]\n\tcmul0' - ' [shape=ellipse]\n\tadd0 -> t0\n\tt0 [shape=square]\n\t"t0.0" ->' - ' cmul0\n}' - ) - - assert sfg_simple_filter.sfg_digraph().source in ( + def test_sfg_no_branch(self, sfg_simple_filter): + res = """digraph { + rankdir=LR splines=spline + in0 [label="IN +(in0)" shape=cds] + in0 -> add0 [headlabel=0] + out0 [label="OUT +(out0)" shape=cds] + t0 -> out0 + add0 [label="ADD +(add0)" shape=ellipse] + cmul0 -> add0 [headlabel=1] + cmul0 [label="CMUL +(cmul0)" shape=ellipse] + add0 -> t0 + t0 [label="T +(t0)" shape=square] + t0 -> cmul0 +}""" + assert sfg_simple_filter.sfg_digraph(branch_node=False).source in ( res, res + "\n", ) def test_sfg_no_port_numbering(self, sfg_simple_filter): - res = ( - 'digraph {\n\trankdir=LR splines=spline\n\tin0 [shape=cds]\n\tin0 ->' - ' add0\n\tout0 [shape=cds]\n\tt0 -> out0\n\tadd0 [shape=ellipse]\n\tcmul0' - ' -> add0\n\tcmul0 [shape=ellipse]\n\tadd0 -> t0\n\tt0 [shape=square]\n\tt0' - ' -> cmul0\n}' - ) - - assert sfg_simple_filter.sfg_digraph( - port_numbering=False, branch_node=False - ).source in ( + res = """digraph { + rankdir=LR splines=spline + in0 [label="IN +(in0)" shape=cds] + in0 -> add0 + out0 [label="OUT +(out0)" shape=cds] + "t0.0" -> out0 + "t0.0" [shape=point] + t0 -> "t0.0" [arrowhead=none] + add0 [label="ADD +(add0)" shape=ellipse] + cmul0 -> add0 + cmul0 [label="CMUL +(cmul0)" shape=ellipse] + add0 -> t0 + t0 [label="T +(t0)" shape=square] + "t0.0" -> cmul0 +}""" + + assert sfg_simple_filter.sfg_digraph(port_numbering=False).source in ( res, res + "\n", )