Skip to content
Snippets Groups Projects
Commit 49b856f8 authored by Angus Lothian's avatar Angus Lothian :dark_sunglasses: Committed by Adam Jakobsson
Browse files

Add code to remove_operation so that if an operation is missing an output...

Add code to remove_operation so that if an operation is missing an output signals but has input signals then the input signal is disconnected from the operation
parent 7b732af1
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
......@@ -193,6 +193,7 @@ class Operation(GraphComponent, SignalSourceProvider):
"""
raise NotImplementedError
class AbstractOperation(Operation, AbstractGraphComponent):
"""Generic abstract operation class which most implementations will derive from.
TODO: More info.
......
......@@ -128,7 +128,7 @@ class InputPort(AbstractPort):
signal.set_destination(self)
def remove_signal(self, signal: Signal) -> None:
assert signal is self._source_signal, "Attempted to remove already removed signal."
assert signal is self._source_signal, "Attempted to remove signal that is not connected."
self._source_signal = None
signal.remove_destination()
......@@ -177,7 +177,7 @@ class OutputPort(AbstractPort, SignalSourceProvider):
signal.set_source(self)
def remove_signal(self, signal: Signal) -> None:
assert signal in self._destination_signals, "Attempted to remove already removed signal."
assert signal in self._destination_signals, "Attempted to remove signal that is not connected."
self._destination_signals.remove(signal)
signal.remove_source()
......
......@@ -258,7 +258,7 @@ class SFG(AbstractOperation):
def split(self) -> Iterable[Operation]:
return self.operations
def to_sfg(self) -> 'SFG':
return self
......@@ -480,7 +480,7 @@ class SFG(AbstractOperation):
# The old SFG will be deleted by Python GC
return _sfg_copy()
def insert_operation(self, component: Operation, output_comp_id: GraphID):
def insert_operation(self, component: Operation, output_comp_id: GraphID) -> Optional["SFG"]:
"""Insert an operation in the SFG after a given source operation.
The source operation output count must match the input count of the operation as well as the output
Then return a new deepcopy of the sfg with the inserted component.
......@@ -511,6 +511,37 @@ class SFG(AbstractOperation):
# Recreate the newly coupled SFG so that all attributes are correct.
return sfg_copy()
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
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)
if operation is None:
return None
if operation.input_count != operation.output_count:
raise ValueError("Different number of input and output ports of operation with the specified id")
for i, outport in enumerate(operation.outputs):
if outport.signal_count > 0:
if operation.input(i).signal_count > 0 and operation.input(i).signals[0].source is not None:
in_sig = operation.input(i).signals[0]
source_port = in_sig.source
source_port.remove_signal(in_sig)
operation.input(i).remove_signal(in_sig)
for out_sig in outport.signals.copy():
out_sig.set_source(source_port)
else:
for out_sig in outport.signals.copy():
out_sig.remove_source()
else:
if operation.input(i).signal_count > 0:
in_sig = operation.input(i).signals[0]
operation.input(i).remove_signal(in_sig)
return sfg_copy()
def _evaluate_source(self, src: OutputPort, results: MutableOutputMap, registers: MutableRegisterMap, prefix: str) -> Number:
src_prefix = prefix
if src_prefix:
......
......@@ -113,8 +113,9 @@ def simple_filter():
in1 = Input("IN1")
constmul1 = ConstantMultiplication(0.5, name="CMUL1")
add1 = Addition(in1, constmul1, "ADD1")
add1.input(1).signals[0].name = "S2"
reg = Register(add1, name="REG1")
constmul1.input(0).connect(reg)
constmul1.input(0).connect(reg, "S1")
out1 = Output(reg, "OUT1")
return SFG(inputs=[in1], outputs=[out1], name="simple_filter")
......
......@@ -707,3 +707,72 @@ class TestTopologicalOrderOperations:
topological_order = sfg_two_inputs_two_outputs_independent.get_operations_topological_order()
assert [comp.name for comp in topological_order] == ["IN1", "OUT1", "IN2", "C1", "ADD1", "OUT2"]
class TestRemove:
def test_remove_single_input_outputs(self, simple_filter):
new_sfg = simple_filter.remove_operation("cmul1")
assert set(op.name for op in simple_filter.find_by_name("REG1")[0].subsequent_operations) == {"CMUL1", "OUT1"}
assert set(op.name for op in new_sfg.find_by_name("REG1")[0].subsequent_operations) == {"ADD1", "OUT1"}
assert set(op.name for op in simple_filter.find_by_name("ADD1")[0].preceding_operations) == {"CMUL1", "IN1"}
assert set(op.name for op in new_sfg.find_by_name("ADD1")[0].preceding_operations) == {"REG1", "IN1"}
assert "S1" in set([sig.name for sig in simple_filter.find_by_name("REG1")[0].output(0).signals])
assert "S2" in set([sig.name for sig in new_sfg.find_by_name("REG1")[0].output(0).signals])
def test_remove_multiple_inputs_outputs(self, butterfly_operation_tree):
out1 = Output(butterfly_operation_tree.output(0), "OUT1")
out2 = Output(butterfly_operation_tree.output(1), "OUT2")
sfg = SFG(outputs=[out1, out2])
new_sfg = sfg.remove_operation(sfg.find_by_name("bfly2")[0].graph_id)
assert sfg.find_by_name("bfly3")[0].output(0).signal_count == 1
assert new_sfg.find_by_name("bfly3")[0].output(0).signal_count == 1
sfg_dest_0 = sfg.find_by_name("bfly3")[0].output(0).signals[0].destination
new_sfg_dest_0 = new_sfg.find_by_name("bfly3")[0].output(0).signals[0].destination
assert sfg_dest_0.index == 0
assert new_sfg_dest_0.index == 0
assert sfg_dest_0.operation.name == "bfly2"
assert new_sfg_dest_0.operation.name == "bfly1"
assert sfg.find_by_name("bfly3")[0].output(1).signal_count == 1
assert new_sfg.find_by_name("bfly3")[0].output(1).signal_count == 1
sfg_dest_1 = sfg.find_by_name("bfly3")[0].output(1).signals[0].destination
new_sfg_dest_1 = new_sfg.find_by_name("bfly3")[0].output(1).signals[0].destination
assert sfg_dest_1.index == 1
assert new_sfg_dest_1.index == 1
assert sfg_dest_1.operation.name == "bfly2"
assert new_sfg_dest_1.operation.name == "bfly1"
assert sfg.find_by_name("bfly1")[0].input(0).signal_count == 1
assert new_sfg.find_by_name("bfly1")[0].input(0).signal_count == 1
sfg_source_0 = sfg.find_by_name("bfly1")[0].input(0).signals[0].source
new_sfg_source_0 = new_sfg.find_by_name("bfly1")[0].input(0).signals[0].source
assert sfg_source_0.index == 0
assert new_sfg_source_0.index == 0
assert sfg_source_0.operation.name == "bfly2"
assert new_sfg_source_0.operation.name == "bfly3"
sfg_source_1 = sfg.find_by_name("bfly1")[0].input(1).signals[0].source
new_sfg_source_1 = new_sfg.find_by_name("bfly1")[0].input(1).signals[0].source
assert sfg_source_1.index == 1
assert new_sfg_source_1.index == 1
assert sfg_source_1.operation.name == "bfly2"
assert new_sfg_source_1.operation.name == "bfly3"
assert "bfly2" not in set(op.name for op in new_sfg.operations)
def remove_different_number_inputs_outputs(self, simple_filter):
with pytest.raises(ValueError):
simple_filter.remove_operation("add1")
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