diff --git a/b_asic/signal_flow_graph.py b/b_asic/signal_flow_graph.py index 04c43d7f43cba59d1c528fc30bf48e7cf7675577..2bce1e0ce17a5a3a032bbb750201a02a1b86711d 100644 --- a/b_asic/signal_flow_graph.py +++ b/b_asic/signal_flow_graph.py @@ -234,31 +234,36 @@ class SFG(AbstractOperation): results[self.key(index, prefix)] = value return value - def replace_self(self) -> None: - """ Iterates over the SFG's (self) Input- and OutputSignals to reconnect them to each necessary operation inside the SFG, - so that the inner operations of the SFG can function on their own, effectively replacing the SFG. """ - - assert len(self.inputs) == len(self.input_operations), "Number of inputs does not match the number of input_operations in SFG." - assert len(self.outputs) == len(self.output_operations), "Number of outputs does not match the number of output_operations SFG." - - # Does this function need a check for if the user wants call this on an SFG which is not a component of another SFG - - # For each input_signal, connect it to the corresponding operation - for port, input_operation in zip(self.inputs, self.input_operations): - # Disconnect the previous signal to the destination - dest = input_operation.output(0).signals[0].destination - dest.clear() - # Connect the signal to the new destination - port.signals[0].set_destination(dest) - - # For each output_signal, connect it to the corresponding operation - for port, output_operation in zip(self.outputs, self.output_operations): - # Disconnect the previous signal to the source - src = output_operation.input(0).signals[0].source - src.clear() - # Connect the signal to the new source - port.signals[0].set_source(src) - + def replace_sfg_with_inner_components(self) -> bool: + """ Replace this SFG with its component operations if itself is a component of another SFG. This SFG becomes unconnected + to the SFG it is a component off. Returns True if succesful, False otherwise. """ + + if len(self.inputs) != len(self.input_operations): + raise IndexError(f"Number of inputs does not match the number of input_operations in SFG.") + if len(self.outputs) != len(self.output_operations): + raise IndexError(f"Number of outputs does not match the number of output_operations SFG.") + + try: + # For each input_signal, connect it to the corresponding operation + for port, input_operation in zip(self.inputs, self.input_operations): + # Disconnect the previous signal to the destination + dest = input_operation.output(0).signals[0].destination + dest.clear() + # Connect the signal to the new destination + port.signals[0].set_destination(dest) + + # For each output_signal, connect it to the corresponding operation + for port, output_operation in zip(self.outputs, self.output_operations): + # Disconnect the previous signal to the source + src = output_operation.input(0).signals[0].source + src.clear() + # Connect the signal to the new source + port.signals[0].set_source(src) + + return True + except IndexError: + # This SFG is not a component of another SFG + return False @property def input_operations(self) -> Sequence[Operation]: diff --git a/test/test_sfg.py b/test/test_sfg.py index 38d7f27f9321b6a480ba03b85345e2324170fa91..26bf32119eb3352fe3fc8516882157144f4d5571 100644 --- a/test/test_sfg.py +++ b/test/test_sfg.py @@ -257,7 +257,7 @@ class TestReplaceComponents: class TestReplaceSelfSoloComp: - def test_replace_self_mac(self): + def test_replace_sfg_with_inner_components_mac(self): """ Replace a MAC with inner components in an SFG """ inp1 = Input("INP1") @@ -282,19 +282,21 @@ class TestReplaceSelfSoloComp: inp5 = Input("INP5") out2 = Output(None, "OUT2") - mac_sfg.inputs[0].connect(inp4, "S8") - mac_sfg.inputs[1].connect(inp5, "S9") + mac_sfg.input(0).connect(inp4, "S8") + mac_sfg.input(1).connect(inp5, "S9") out2.input(0).connect(mac_sfg.outputs[0], "S10") test_sfg = SFG(inputs = [inp4, inp5], outputs = [out2]) assert test_sfg.evaluate(1,2) == 9 - mac_sfg.replace_self() + mac_sfg.replace_sfg_with_inner_components() assert test_sfg.evaluate(1,2) == 9 - def test_replace_self_operation_tree(self, operation_tree): + assert test_sfg.replace_sfg_with_inner_components() == False + + def test_replace_sfg_with_inner_components_operation_tree(self, operation_tree): """ Replaces an SFG with only a operation_tree component with its inner components """ sfg1 = SFG(outputs = [Output(operation_tree)]) @@ -307,11 +309,13 @@ class TestReplaceSelfSoloComp: assert test_sfg.evaluate_output(0, []) == 5 - sfg1.replace_self() + sfg1.replace_sfg_with_inner_components() assert test_sfg.evaluate_output(0, []) == 5 - def test_replace_self_large_operation_tree(self, large_operation_tree): + assert test_sfg.replace_sfg_with_inner_components() == False + + def test_replace_sfg_with_inner_components_large_operation_tree(self, large_operation_tree): """ Replaces an SFG with only a large_operation_tree component with its inner components """ sfg1 = SFG(outputs = [Output(large_operation_tree)]) @@ -324,13 +328,15 @@ class TestReplaceSelfSoloComp: assert test_sfg.evaluate_output(0, []) == 14 - sfg1.replace_self() + sfg1.replace_sfg_with_inner_components() assert test_sfg.evaluate_output(0, []) == 14 + assert test_sfg.replace_sfg_with_inner_components() == False + class TestReplaceSelfMultipleComp: - def test_replace_self_operation_tree(self, operation_tree): + def test_replace_sfg_with_inner_components_operation_tree(self, operation_tree): """ Replaces a operation_tree in an SFG with other components """ sfg1 = SFG(outputs = [Output(operation_tree)]) @@ -353,11 +359,13 @@ class TestReplaceSelfMultipleComp: assert test_sfg.evaluate(1, 2) == 8 - sfg1.replace_self() + sfg1.replace_sfg_with_inner_components() assert test_sfg.evaluate(1, 2) == 8 - def test_replace_self_large_operation_tree(self, large_operation_tree): + assert test_sfg.replace_sfg_with_inner_components() == False + + def test_replace_sfg_with_inner_components_large_operation_tree(self, large_operation_tree): """ Replaces a large_operation_tree in an SFG with other components """ sfg1 = SFG(outputs = [Output(large_operation_tree)]) @@ -380,10 +388,12 @@ class TestReplaceSelfMultipleComp: assert test_sfg.evaluate(1, 2) == 17 - sfg1.replace_self() + sfg1.replace_sfg_with_inner_components() assert test_sfg.evaluate(1, 2) == 17 + assert test_sfg.replace_sfg_with_inner_components() == False + def create_sfg(self, op_tree): """ Create a simple SFG with either operation_tree or large_operation_tree """ @@ -406,7 +416,7 @@ class TestReplaceSelfMultipleComp: return SFG(inputs = [inp1, inp2], outputs = [out1]) - def test_replace_self_many_op(self, large_operation_tree): + def test_replace_sfg_with_inner_components_many_op(self, large_operation_tree): """ Replaces an sfg component in a larger SFG with several component operations """ inp1 = Input("INP1") @@ -424,8 +434,8 @@ class TestReplaceSelfMultipleComp: sfg1 = self.create_sfg(large_operation_tree) - sfg1.inputs[0].connect(add1, "S3") - sfg1.inputs[1].connect(inp3, "S4") + sfg1.input(0).connect(add1, "S3") + sfg1.input(1).connect(inp3, "S4") sub1.input(0).connect(sfg1.outputs[0], "S5") @@ -437,6 +447,8 @@ class TestReplaceSelfMultipleComp: assert test_sfg.evaluate(1, 2, 3, 4) == 16 - sfg1.replace_self() + sfg1.replace_sfg_with_inner_components() + + assert test_sfg.evaluate(1, 2, 3, 4) == 16 - assert test_sfg.evaluate(1, 2, 3, 4) == 16 \ No newline at end of file + assert test_sfg.replace_sfg_with_inner_components() == False \ No newline at end of file