Skip to content
Snippets Groups Projects
Commit 35dfc3ed authored by Kevin Scott's avatar Kevin Scott Committed by Angus Lothian
Browse files

Resolve "Signal Interface"

parent 09e8cc0a
No related branches found
No related tags found
3 merge requests!67WIP: B-ASIC version 1.0.0 hotfix,!65B-ASIC version 1.0.0,!15Add changes from sprint 1 and 2 to master
...@@ -8,7 +8,7 @@ from typing import List, Dict, Optional, Any ...@@ -8,7 +8,7 @@ from typing import List, Dict, Optional, Any
from numbers import Number from numbers import Number
from b_asic.port import InputPort, OutputPort from b_asic.port import InputPort, OutputPort
from b_asic.signal import SignalSource, SignalDestination from b_asic.signal import Signal
from b_asic.operation import Operation from b_asic.operation import Operation
from b_asic.simulation import SimulationState, OperationState from b_asic.simulation import SimulationState, OperationState
...@@ -73,7 +73,7 @@ class BasicOperation(Operation): ...@@ -73,7 +73,7 @@ class BasicOperation(Operation):
while self_state.iteration < state.iteration: while self_state.iteration < state.iteration:
input_values: List[Number] = [0] * input_count input_values: List[Number] = [0] * input_count
for i in range(input_count): for i in range(input_count):
source: SignalSource = self._input_ports[i].signal().source source: Signal = self._input_ports[i].signal
input_values[i] = source.operation.evaluate_outputs(state)[source.port_index] input_values[i] = source.operation.evaluate_outputs(state)[source.port_index]
self_state.output_values = self.evaluate(input_values) self_state.output_values = self.evaluate(input_values)
...@@ -81,7 +81,7 @@ class BasicOperation(Operation): ...@@ -81,7 +81,7 @@ class BasicOperation(Operation):
self_state.iteration += 1 self_state.iteration += 1
for i in range(output_count): for i in range(output_count):
for signal in self._output_ports[i].signals(): for signal in self._output_ports[i].signals():
destination: SignalDestination = signal.destination destination: Signal = signal.destination
destination.evaluate_outputs(state) destination.evaluate_outputs(state)
return self_state.output_values return self_state.output_values
...@@ -96,9 +96,13 @@ class BasicOperation(Operation): ...@@ -96,9 +96,13 @@ class BasicOperation(Operation):
@property @property
def neighbours(self) -> List[Operation]: def neighbours(self) -> List[Operation]:
neighbours: List[Operation] = [] neighbours: List[Operation] = []
for port in self._output_ports + self._input_ports: for port in self._input_ports:
for signal in port.signals(): for signal in port.signals:
neighbours += [signal.source.operation, signal.destination.operation] neighbours.append(signal.source.operation)
for port in self._output_ports:
for signal in port.signals:
neighbours.append(signal.destination.operation)
return neighbours return neighbours
......
...@@ -28,7 +28,7 @@ class Constant(BasicOperation): ...@@ -28,7 +28,7 @@ class Constant(BasicOperation):
def __init__(self, value: Number): def __init__(self, value: Number):
"""Construct a Constant.""" """Construct a Constant."""
super().__init__() super().__init__()
self._output_ports = [OutputPort(1)] # TODO: Generate appropriate ID for ports. self._output_ports = [OutputPort(1, self)] # TODO: Generate appropriate ID for ports.
self._parameters["value"] = value self._parameters["value"] = value
def evaluate(self, inputs: list) -> list: def evaluate(self, inputs: list) -> list:
...@@ -45,8 +45,8 @@ class Addition(BasicOperation): ...@@ -45,8 +45,8 @@ class Addition(BasicOperation):
def __init__(self): def __init__(self):
"""Construct an Addition.""" """Construct an Addition."""
super().__init__() super().__init__()
self._input_ports = [InputPort(1), InputPort(1)] # TODO: Generate appropriate ID for ports. self._input_ports = [InputPort(1, self), InputPort(1, self)] # TODO: Generate appropriate ID for ports.
self._output_ports = [OutputPort(1)] # TODO: Generate appropriate ID for ports. self._output_ports = [OutputPort(1, self)] # TODO: Generate appropriate ID for ports.
def evaluate(self, inputs: list) -> list: def evaluate(self, inputs: list) -> list:
return [inputs[0] + inputs[1]] return [inputs[0] + inputs[1]]
...@@ -63,8 +63,8 @@ class ConstantMultiplication(BasicOperation): ...@@ -63,8 +63,8 @@ class ConstantMultiplication(BasicOperation):
def __init__(self, coefficient: Number): def __init__(self, coefficient: Number):
"""Construct a ConstantMultiplication.""" """Construct a ConstantMultiplication."""
super().__init__() super().__init__()
self._input_ports = [InputPort(1)] # TODO: Generate appropriate ID for ports. self._input_ports = [InputPort(1), self] # TODO: Generate appropriate ID for ports.
self._output_ports = [OutputPort(1)] # TODO: Generate appropriate ID for ports. self._output_ports = [OutputPort(1, self)] # TODO: Generate appropriate ID for ports.
self._parameters["coefficient"] = coefficient self._parameters["coefficient"] = coefficient
def evaluate(self, inputs: list) -> list: def evaluate(self, inputs: list) -> list:
......
...@@ -7,6 +7,7 @@ from abc import ABC, abstractmethod ...@@ -7,6 +7,7 @@ from abc import ABC, abstractmethod
from typing import NewType, Optional, List from typing import NewType, Optional, List
from b_asic.signal import Signal from b_asic.signal import Signal
from b_asic.operation import Operation
PortId = NewType("PortId", int) PortId = NewType("PortId", int)
...@@ -16,29 +17,38 @@ class Port(ABC): ...@@ -16,29 +17,38 @@ class Port(ABC):
TODO: More info. TODO: More info.
""" """
_identifier: PortId _port_id: PortId
_operation: Operation
def __init__(self, identifier: PortId): def __init__(self, port_id: PortId, operation: Operation):
"""Construct a Port.""" self._port_id = port_id
self._identifier = identifier self._operation = operation
@property
def identifier(self) -> PortId: def identifier(self) -> PortId:
"""Get the unique identifier.""" """Get the unique identifier."""
return self._identifier return self._port_id
@property
def operation(self) -> Operation:
"""Get the connected operation."""
return self._operation
@property
@abstractmethod @abstractmethod
def signals(self) -> List[Signal]: def signals(self) -> List[Signal]:
"""Get a list of all connected signals.""" """Get a list of all connected signals."""
pass pass
@property
@abstractmethod @abstractmethod
def signal_count(self) -> int: def signal(self, i: int = 0) -> Signal:
"""Get the number of connected signals.""" """Get the connected signal at index i."""
pass pass
@abstractmethod @abstractmethod
def signal(self, i: int = 0) -> Signal: def signal_count(self) -> int:
"""Get the connected signal at index i.""" """Get the number of connected signals."""
pass pass
@abstractmethod @abstractmethod
...@@ -51,6 +61,7 @@ class Port(ABC): ...@@ -51,6 +61,7 @@ class Port(ABC):
"""Disconnect a signal.""" """Disconnect a signal."""
pass pass
# TODO: More stuff. # TODO: More stuff.
...@@ -60,26 +71,30 @@ class InputPort(Port): ...@@ -60,26 +71,30 @@ class InputPort(Port):
""" """
_source_signal: Optional[Signal] _source_signal: Optional[Signal]
def __init__(self, identifier: PortId): def __init__(self, port_id: PortId, operation: Operation):
super().__init__(identifier) super().__init__(port_id, operation)
self._source_signal = None self._source_signal = None
@property
def signals(self) -> List[Signal]: def signals(self) -> List[Signal]:
return [] if self._source_signal is None else [self._source_signal] return [] if self._source_signal is None else [self._source_signal]
def signal_count(self) -> int: @property
return 0 if self._source_signal is None else 1
def signal(self, i: int = 0) -> Signal: def signal(self, i: int = 0) -> Signal:
assert 0 <= i < self.signal_count() # TODO: Error message. assert 0 <= i < self.signal_count() # TODO: Error message.
assert self._source_signal is not None # TODO: Error message. assert self._source_signal is not None # TODO: Error message.
return self._source_signal return self._source_signal
def signal_count(self) -> int:
return 0 if self._source_signal is None else 1
def connect(self, signal: Signal) -> None: def connect(self, signal: Signal) -> None:
self._source_signal = signal self._source_signal = signal
signal.destination = self
def disconnect(self, i: int = 0) -> None: def disconnect(self, i: int = 0) -> None:
assert 0 <= i < self.signal_count() # TODO: Error message. assert 0 <= i < self.signal_count() # TODO: Error message.
self._source_signal.disconnect_source()
self._source_signal = None self._source_signal = None
# TODO: More stuff. # TODO: More stuff.
...@@ -92,23 +107,26 @@ class OutputPort(Port): ...@@ -92,23 +107,26 @@ class OutputPort(Port):
_destination_signals: List[Signal] _destination_signals: List[Signal]
def __init__(self, identifier: PortId): def __init__(self, port_id: PortId, operation: Operation):
super().__init__(identifier) super().__init__(port_id, operation)
self._destination_signals = [] self._destination_signals = []
@property
def signals(self) -> List[Signal]: def signals(self) -> List[Signal]:
return self._destination_signals.copy() return self._destination_signals.copy()
def signal_count(self) -> int: @property
return len(self._destination_signals)
def signal(self, i: int = 0) -> Signal: def signal(self, i: int = 0) -> Signal:
assert 0 <= i < self.signal_count() # TODO: Error message. assert 0 <= i < self.signal_count() # TODO: Error message.
return self._destination_signals[i] return self._destination_signals[i]
def signal_count(self) -> int:
return len(self._destination_signals)
def connect(self, signal: Signal) -> None: def connect(self, signal: Signal) -> None:
assert signal not in self._destination_signals # TODO: Error message. assert signal not in self._destination_signals # TODO: Error message.
self._destination_signals.append(signal) self._destination_signals.append(signal)
signal.source = self
def disconnect(self, i: int = 0) -> None: def disconnect(self, i: int = 0) -> None:
assert 0 <= i < self.signal_count() # TODO: Error message. assert 0 <= i < self.signal_count() # TODO: Error message.
......
"""@package docstring """@package docstring
B-ASIC Signal Module. B-ASIC Signal Module.
TODO: More info.
""" """
from typing import TYPE_CHECKING, Optional
if TYPE_CHECKING:
from b_asic import OutputPort, InputPort
from b_asic.operation import Operation class Signal:
"""A connection between two ports."""
_source: "OutputPort"
class SignalSource: _destination: "InputPort"
"""Handle to a signal source.
TODO: More info.
"""
operation: Operation
port_index: int
def __init__(self, operation: Operation, port_index: int):
self.operation = operation
self.port_index = port_index
# TODO: More stuff.
def __init__(self, src: Optional["OutputPort"] = None, dest: Optional["InputPort"] = None):
self._source = src
self._destination = dest
class SignalDestination: @property
"""Handle to a signal destination. def source(self) -> "InputPort":
TODO: More info. return self._source
"""
operation: Operation
port_index: int
def __init__(self, operation: Operation, port_index: int): @property
self.operation = operation def destination(self) -> "OutputPort":
self.port_index = port_index return self._destination
# TODO: More stuff. @source.setter
def source(self, src: "Outputport") -> None:
self._source = src
@destination.setter
def destination(self, dest: "InputPort") -> None:
self._destination = dest
class Signal: def disconnect_source(self) -> None:
"""A connection between two operations consisting of a source and destination handle. self._source = None
TODO: More info.
"""
source: SignalSource
destination: SignalDestination
def __init__(self, source: SignalSource, destination: SignalDestination): def disconnect_destination(self) -> None:
self.source = source self._destination = None
self.destination = destination
# TODO: More stuff.
...@@ -7,7 +7,9 @@ from typing import List, Dict, Union, Optional ...@@ -7,7 +7,9 @@ from typing import List, Dict, Union, Optional
from b_asic.operation import Operation from b_asic.operation import Operation
from b_asic.basic_operation import BasicOperation from b_asic.basic_operation import BasicOperation
from b_asic.signal import Signal, SignalSource, SignalDestination from b_asic.signal import Signal
from b_asic.simulation import SimulationState, OperationState
from typing import List
from b_asic.graph_id import GraphIDGenerator, GraphID from b_asic.graph_id import GraphIDGenerator, GraphID
...@@ -19,7 +21,7 @@ class SFG(BasicOperation): ...@@ -19,7 +21,7 @@ class SFG(BasicOperation):
_graph_objects_by_id: Dict[GraphID, Union[Operation, Signal]] _graph_objects_by_id: Dict[GraphID, Union[Operation, Signal]]
_graph_id_generator: GraphIDGenerator _graph_id_generator: GraphIDGenerator
def __init__(self, input_destinations: List[SignalDestination], output_sources: List[SignalSource]): def __init__(self, input_destinations: List[Signal], output_sources: List[Signal]):
super().__init__() super().__init__()
# TODO: Allocate input/output ports with appropriate IDs. # TODO: Allocate input/output ports with appropriate IDs.
......
import pytest import pytest
from b_asic import Signal, SignalSource, SignalDestination, Addition from b_asic import Signal
"""
Use a fixture for initializing objects and pass them as argument to a test function
"""
@pytest.fixture @pytest.fixture
def signal(): def signal():
source = SignalSource(Addition(), 1) return Signal()
dest = SignalDestination(Addition(), 2)
return Signal(source, dest)
@pytest.fixture @pytest.fixture
def signals(): def signals():
ret = [] return [Signal() for _ in range(0,3)]
for _ in range(0,3):
source = SignalSource(Addition(), 1)
dest = SignalDestination(Addition(), 2)
ret.append(Signal(source, dest))
return ret
\ No newline at end of file
...@@ -2,22 +2,19 @@ ...@@ -2,22 +2,19 @@
B-ASIC test suite for Inputport B-ASIC test suite for Inputport
""" """
# import module we are testing
from b_asic import InputPort from b_asic import InputPort
# import dependencies
from b_asic import Signal, SignalSource, SignalDestination, Addition
import pytest import pytest
def test_connect_multiple_signals(signals): def test_connect_multiple_signals(signals):
""" """
test if only one signal can connect to an input port test if only one signal can connect to an input port
""" """
inp_port = InputPort(0) inp_port = InputPort(0, None)
for s in signals: for s in signals:
inp_port.connect(s) inp_port.connect(s)
assert inp_port.signal_count() == 1 assert inp_port.signal_count() == 1
assert inp_port.signals()[0] == signals[-1] assert inp_port.signals[0] == signals[-1]
\ No newline at end of file
...@@ -2,17 +2,17 @@ ...@@ -2,17 +2,17 @@
B-ASIC test suite for InputPort B-ASIC test suite for InputPort
TODO: More info TODO: More info
""" """
from b_asic import OutputPort, Signal, SignalSource, SignalDestination, Addition from b_asic import OutputPort
import pytest import pytest
def test_connect_multiple_signals(signals): def test_connect_multiple_signals(signals):
""" """
test if multiple signals can connect to an output port test if multiple signals can connect to an output port
""" """
outp_port = OutputPort(0) outp_port = OutputPort(0, None)
for s in signals: for s in signals:
outp_port.connect(s) outp_port.connect(s)
assert outp_port.signal_count() == 3 assert outp_port.signal_count() == 3
assert outp_port.signals() == signals assert outp_port.signals == signals
\ No newline at end of file \ No newline at end of file
"""
B-ASIC test suite for Port interface, place all general test cases for abstract class Port here
"""
from b_asic import InputPort, OutputPort, Signal, SignalSource, SignalDestination, Addition
import pytest
def test_connect_one_signal_to_port(signal):
port = InputPort(0)
port.connect(signal)
assert len(port.signals()) == 1
assert port.signal() == signal
def test_change_port_signal():
source = SignalSource(Addition, 1)
dest = SignalDestination(Addition,2)
signal1 = Signal(source, dest)
signal2 = Signal(source, dest)
port = InputPort(0)
port.connect(signal1)
assert port.signal() == signal1
port.connect(signal2)
assert port.signal() == signal2
\ No newline at end of file
...@@ -5,7 +5,7 @@ TODO: ...@@ -5,7 +5,7 @@ TODO:
""" """
from b_asic.core_operations import Constant, Addition from b_asic.core_operations import Constant, Addition
from b_asic.signal import Signal, SignalSource, SignalDestination from b_asic.signal import Signal
from b_asic.port import InputPort, OutputPort from b_asic.port import InputPort, OutputPort
from b_asic.traverse_tree import Traverse from b_asic.traverse_tree import Traverse
...@@ -17,10 +17,9 @@ def operation(): ...@@ -17,10 +17,9 @@ def operation():
def create_operation(_type, dest_oper, index, **kwargs): def create_operation(_type, dest_oper, index, **kwargs):
oper = _type(**kwargs) oper = _type(**kwargs)
oper_signal_source = SignalSource(oper, 0) oper_signal = Signal()
oper_signal_dest = SignalDestination(dest_oper, index)
oper_signal = Signal(oper_signal_source, oper_signal_dest)
oper._output_ports[0].connect(oper_signal) oper._output_ports[0].connect(oper_signal)
dest_oper._input_ports[index].connect(oper_signal) dest_oper._input_ports[index].connect(oper_signal)
return oper return oper
...@@ -45,15 +44,11 @@ def large_operation_tree(): ...@@ -45,15 +44,11 @@ def large_operation_tree():
const_oper_4 = create_operation(Constant, add_oper_2, 1, value=5) const_oper_4 = create_operation(Constant, add_oper_2, 1, value=5)
add_oper_3 = Addition() add_oper_3 = Addition()
add_oper_signal_source = SignalSource(add_oper, 0) add_oper_signal = Signal(add_oper, add_oper_3)
add_oper_signal_dest = SignalDestination(add_oper_3, 0)
add_oper_signal = Signal(add_oper_signal_source, add_oper_signal_dest)
add_oper._output_ports[0].connect(add_oper_signal) add_oper._output_ports[0].connect(add_oper_signal)
add_oper_3._input_ports[0].connect(add_oper_signal) add_oper_3._input_ports[0].connect(add_oper_signal)
add_oper_2_signal_source = SignalSource(add_oper_2, 0) add_oper_2_signal = Signal(add_oper_2, add_oper_3)
add_oper_2_signal_dest = SignalDestination(add_oper_3, 1)
add_oper_2_signal = Signal(add_oper_2_signal_source, add_oper_2_signal_dest)
add_oper_2._output_ports[0].connect(add_oper_2_signal) add_oper_2._output_ports[0].connect(add_oper_2_signal)
add_oper_3._input_ports[1].connect(add_oper_2_signal) add_oper_3._input_ports[1].connect(add_oper_2_signal)
return const_oper return const_oper
...@@ -76,9 +71,7 @@ def test_traverse_type(large_operation_tree): ...@@ -76,9 +71,7 @@ def test_traverse_type(large_operation_tree):
assert len(traverse.traverse(Constant)) == 4 assert len(traverse.traverse(Constant)) == 4
def test_traverse_loop(operation_tree): def test_traverse_loop(operation_tree):
add_oper_signal_source = SignalSource(operation_tree, 0) add_oper_signal = Signal()
add_oper_signal_dest = SignalDestination(operation_tree, 0)
add_oper_signal = Signal(add_oper_signal_source, add_oper_signal_dest)
operation_tree._output_ports[0].connect(add_oper_signal) operation_tree._output_ports[0].connect(add_oper_signal)
operation_tree._input_ports[0].connect(add_oper_signal) operation_tree._input_ports[0].connect(add_oper_signal)
traverse = Traverse(operation_tree) traverse = Traverse(operation_tree)
......
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