diff --git a/CMakeLists.txt b/CMakeLists.txt index 8ba064fd854be1f2d984db7949aa6080ddf6200a..433d2746392261a745573dc457bbb579cdc96dcb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -67,9 +67,15 @@ target_link_libraries( ) add_custom_target( - copy_python_files ALL + remove_old_python_dir ALL + COMMAND ${CMAKE_COMMAND} -E remove_directory "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/${LIBRARY_NAME}" + COMMENT "Removing old python directory ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/${LIBRARY_NAME}" +) +add_custom_target( + copy_python_dir ALL COMMAND ${CMAKE_COMMAND} -E copy_directory "${CMAKE_CURRENT_LIST_DIR}/${LIBRARY_NAME}" "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/${LIBRARY_NAME}" COMMENT "Copying python files to ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/${LIBRARY_NAME}" + DEPENDS remove_old_python_dir ) add_custom_target( copy_misc_files ALL diff --git a/README.md b/README.md index b36a5d82421b3c31455a2b69d8d9fc303e4c116e..bcd09857e6f6c320c32c56f5182de4e1469370f3 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,8 @@ The following packages are required in order to build the library: * setuptools * wheel * pybind11 + * numpy + * pyside2/pyqt5 ## Development How to build and debug the library during development. diff --git a/b_asic/__init__.py b/b_asic/__init__.py index 8bbc17ab50204e26db7dcaf0569cbfe316b3dc3a..8a84a9456c668da32c055f8ef1af13098422925e 100644 --- a/b_asic/__init__.py +++ b/b_asic/__init__.py @@ -3,11 +3,12 @@ Better ASIC Toolbox. TODO: More info. """ from _b_asic import * +from b_asic.basic_operation import * +from b_asic.core_operations import * from b_asic.operation import * -from b_asic.ops import * -from b_asic.pc import * +from b_asic.precedence_chart import * from b_asic.port import * from b_asic.schema import * -from b_asic.sfg import * +from b_asic.signal_flow_graph import * from b_asic.signal import * from b_asic.simulation import * \ No newline at end of file diff --git a/b_asic/basic_operation.py b/b_asic/basic_operation.py new file mode 100644 index 0000000000000000000000000000000000000000..e87860c6a226484afd6d3ba6c28811cd7b545b66 --- /dev/null +++ b/b_asic/basic_operation.py @@ -0,0 +1,114 @@ +""" +B-ASIC Basic Operation Module. +TODO: More info. +""" + +from b_asic.port import InputPort, OutputPort +from b_asic.signal import SignalSource, SignalDestination +from b_asic.operation import OperationId, Operation +from b_asic.simulation import SimulationState, OperationState +from abc import ABC, abstractmethod +from typing import List, Dict, Optional, Any, final +from numbers import Number + +class BasicOperation(Operation): + """ + Generic abstract operation class which most implementations will derive from. + TODO: More info. + """ + + _identifier: OperationId + _input_ports: List[InputPort] + _output_ports: List[OutputPort] + _parameters: Dict[str, Optional[Any]] + + def __init__(self, identifier: OperationId): + """ + Construct a BasicOperation. + """ + self._identifier = identifier + self._input_ports = [] + self._output_ports = [] + self._parameters = {} + + @abstractmethod + def evaluate(self, inputs: list) -> list: + """ + Evaluate the operation and generate a list of output values given a list of input values. + """ + pass + + @final + def id(self) -> OperationId: + return self._identifier + + @final + def inputs(self) -> List[InputPort]: + return self._input_ports.copy() + + @final + def outputs(self) -> List[OutputPort]: + return self._output_ports.copy() + + @final + def input_count(self) -> int: + return len(self._input_ports) + + @final + def output_count(self) -> int: + return len(self._output_ports) + + @final + def input(self, i: int) -> InputPort: + return self._input_ports[i] + + @final + def output(self, i: int) -> OutputPort: + return self._output_ports[i] + + @final + def params(self) -> Dict[str, Optional[Any]]: + return self._parameters.copy() + + @final + def param(self, name: str) -> Optional[Any]: + return self._parameters.get(name) + + @final + def set_param(self, name: str, value: Any) -> None: + assert name in self._parameters # TODO: Error message. + self._parameters[name] = value + + def evaluate_outputs(self, state: SimulationState) -> List[Number]: + # TODO: Check implementation. + input_count: int = self.input_count() + output_count: int = self.output_count() + assert input_count == len(self._input_ports) # TODO: Error message. + assert output_count == len(self._output_ports) # TODO: Error message. + + self_state: OperationState = state.operation_states[self.identifier()] + + while self_state.iteration < state.iteration: + input_values: List[Number] = [0] * input_count + for i in range(input_count): + source: SignalSource = self._input_ports[i].signal().source + input_values[i] = source.operation.evaluate_outputs(state)[source.port_index] + + self_state.output_values = self.evaluate(input_values) + assert len(self_state.output_values) == output_count # TODO: Error message. + self_state.iteration += 1 + for i in range(output_count): + for signal in self._output_ports[i].signals(): + destination: SignalDestination = signal.destination + destination.evaluate_outputs(state) + + return self_state.output_values + + def split(self) -> List[Operation]: + # TODO: Check implementation. + results = self.evaluate(self._input_ports) + if all(isinstance(e, Operation) for e in results): + return results + return [self] + + # TODO: More stuff. \ No newline at end of file diff --git a/b_asic/ops.py b/b_asic/core_operations.py similarity index 91% rename from b_asic/ops.py rename to b_asic/core_operations.py index 6b3707254e8faceed0727da1ff93b9ad2582c35a..553d7cff4d7b06cfdc79704773e0d1a3e4edf390 100644 --- a/b_asic/ops.py +++ b/b_asic/core_operations.py @@ -3,7 +3,9 @@ B-ASIC Core Operations Module. TODO: More info. """ -from b_asic.operation import OperationId, Operation, BasicOperation +from b_asic.port import InputPort, OutputPort +from b_asic.operation import OperationId, Operation +from b_asic.basic_operation import BasicOperation from numbers import Number from typing import final diff --git a/b_asic/operation.py b/b_asic/operation.py index 4bea5047775df99993f9bf2dedfdd1fb4209834b..310491bce3ea18e206d087c298d67d23655bc709 100644 --- a/b_asic/operation.py +++ b/b_asic/operation.py @@ -2,12 +2,14 @@ B-ASIC Operation Module. TODO: More info. """ -from b_asic.port import InputPort, OutputPort -from b_asic.signal import SignalSource, SignalDestination -from b_asic.simulation import SimulationState, OperationState + from abc import ABC, abstractmethod from numbers import Number -from typing import NewType, List, Dict, Optional, final +from typing import NewType, List, Dict, Optional, Any, TYPE_CHECKING + +if TYPE_CHECKING: + from b_asic.port import InputPort, OutputPort + from b_asic.simulation import SimulationState OperationId = NewType("OperationId", int) @@ -21,18 +23,19 @@ class Operation(ABC): def identifier(self) -> OperationId: """ Get the unique identifier. + TODO: Move id info to SFG, remove id class members. """ pass @abstractmethod - def inputs(self) -> List[InputPort]: + def inputs(self) -> "List[InputPort]": """ Get a list of all input ports. """ pass @abstractmethod - def outputs(self) -> List[OutputPort]: + def outputs(self) -> "List[OutputPort]": """ Get a list of all output ports. """ @@ -53,14 +56,14 @@ class Operation(ABC): pass @abstractmethod - def input(self, i: int) -> InputPort: + def input(self, i: int) -> "InputPort": """ Get the input port at index i. """ pass @abstractmethod - def output(self, i: int) -> OutputPort: + def output(self, i: int) -> "OutputPort": """ Get the output port at index i. """ @@ -90,7 +93,7 @@ class Operation(ABC): pass @abstractmethod - def evaluate_outputs(self, state: SimulationState) -> List[Number]: + def evaluate_outputs(self, state: "SimulationState") -> List[Number]: """ Simulate the circuit until its iteration count matches that of the simulation state, then return the resulting output vector. @@ -98,7 +101,7 @@ class Operation(ABC): pass @abstractmethod - def split(self) -> List[Operation]: + def split(self) -> "List[Operation]": """ Split the operation into multiple operations. If splitting is not possible, this may return a list containing only the operation itself. @@ -107,104 +110,3 @@ class Operation(ABC): # TODO: More stuff. -class BasicOperation(ABC, Operation): - """ - Generic abstract operation class which most implementations will derive from. - TODO: More info. - """ - - _identifier: OperationId - _input_ports: List[InputPort] - _output_ports: List[OutputPort] - _parameters: Dict[str, Optional[Any]] - - def __init__(self, identifier: OperationId): - """ - Construct a BasicOperation. - """ - self._identifier = identifier - self._input_ports = [] - self._output_ports = [] - self._parameters = {} - - @abstractmethod - def evaluate(self, inputs: list) -> list: - """ - Evaluate the operation and generate a list of output values given a list of input values. - """ - pass - - @final - def id(self) -> OperationId: - return self._identifier - - @final - def inputs(self) -> List[InputPort]: - return self._input_ports.copy() - - @final - def outputs(self) -> List[OutputPort]: - return self._output_ports.copy() - - @final - def input_count(self) -> int: - return len(self._input_ports) - - @final - def output_count(self) -> int: - return len(self._output_ports) - - @final - def input(self, i: int) -> InputPort: - return self._input_ports[i] - - @final - def output(self, i: int) -> OutputPort: - return self._output_ports[i] - - @final - def params(self) -> Dict[str, Optional[Any]]: - return self._parameters.copy() - - @final - def param(self, name: str) -> Optional[Any]: - return self._parameters.get(name) - - @final - def set_param(self, name: str, value: Any) -> None: - assert name in self._parameters # TODO: Error message. - self._parameters[name] = value - - def evaluate_outputs(self, state: SimulationState) -> List[Number]: - # TODO: Check implementation. - input_count: int = self.input_count() - output_count: int = self.output_count() - assert input_count == len(self._input_ports) # TODO: Error message. - assert output_count == len(self._output_ports) # TODO: Error message. - - self_state: OperationState = state.operation_states[self.identifier()] - - while self_state.iteration < state.iteration: - input_values: List[Number] = [0] * input_count - for i in range(input_count): - source: SignalSource = self._input_ports[i].signal().source - input_values[i] = source.operation.evaluate_outputs(state)[source.port_index] - - self_state.output_values = self.evaluate(input_values) - assert len(self_state.output_values) == output_count # TODO: Error message. - self_state.iteration += 1 - for i in range(output_count): - for signal in self._output_ports[i].signals(): - destination: SignalDestination = signal.destination - destination.evaluate_outputs(state) - - return self_state.output_values - - def split(self) -> List[Operation]: - # TODO: Check implementation. - results = self.evaluate(self._input_ports) - if all(isinstance(e, Operation) for e in results): - return results - return [self] - - # TODO: More stuff. \ No newline at end of file diff --git a/b_asic/pc.py b/b_asic/precedence_chart.py similarity index 89% rename from b_asic/pc.py rename to b_asic/precedence_chart.py index cc18d6af1dea2843257d53f9b3008d1decde3604..76a22c9fe0b006192b3755268ceecdef0f1174eb 100644 --- a/b_asic/pc.py +++ b/b_asic/precedence_chart.py @@ -3,7 +3,7 @@ B-ASIC Precedence Chart Module. TODO: More info. """ -from b_asic.sfg import SFG +from b_asic.signal_flow_graph import SFG class PrecedenceChart: """ diff --git a/b_asic/schema.py b/b_asic/schema.py index a7642f49fcca42459b5ee04f069781e13605f517..c7a72526fc9a00f7bf573f98f17b68f6bd8c3003 100644 --- a/b_asic/schema.py +++ b/b_asic/schema.py @@ -3,7 +3,7 @@ B-ASIC Schema Module. TODO: More info. """ -from b_asic.pc import PrecedenceChart +from b_asic.precedence_chart import PrecedenceChart class Schema: """ diff --git a/b_asic/sfg.py b/b_asic/signal_flow_graph.py similarity index 89% rename from b_asic/sfg.py rename to b_asic/signal_flow_graph.py index d39cc5245131f9815c8e495f1e9faebc024a190f..8fbbebff824dd3a82e8ba4c10f86286d6d4b828a 100644 --- a/b_asic/sfg.py +++ b/b_asic/signal_flow_graph.py @@ -3,7 +3,8 @@ B-ASIC Signal Flow Graph Module. TODO: More info. """ -from b_asic.operation import OperationId, Operation, BasicOperation +from b_asic.operation import OperationId, Operation +from b_asic.basic_operation import BasicOperation from b_asic.signal import SignalSource, SignalDestination from b_asic.simulation import SimulationState, OperationState from typing import List, final diff --git a/setup.py b/setup.py index aa6d7a6c41247b4a4151d27d2e221c6d328851c6..71ae4e4a222ca26c5c0e75cafe10e2012a9518d9 100644 --- a/setup.py +++ b/setup.py @@ -67,7 +67,11 @@ setuptools.setup( "Operating System :: OS Independent", ], python_requires = ">=3.6", - install_requires = ["pybind11>=2.3.0"], + install_requires = [ + "pybind11>=2.3.0", + "numpy", + "install_qt_binding" + ], packages = ["b_asic"], ext_modules = [CMakeExtension("b_asic")], cmdclass = {"build_ext": CMakeBuild},