From a5069646bea7bb132ada81ddec26334be6410915 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ivar=20H=C3=A4rnqvist?= <ivaha717@student.liu.se>
Date: Tue, 25 Feb 2020 01:05:00 +0100
Subject: [PATCH] fix circular module import

---
 CMakeLists.txt                          |   8 +-
 README.md                               |   2 +
 b_asic/__init__.py                      |   7 +-
 b_asic/basic_operation.py               | 114 ++++++++++++++++++++++
 b_asic/{ops.py => core_operations.py}   |   4 +-
 b_asic/operation.py                     | 124 +++---------------------
 b_asic/{pc.py => precedence_chart.py}   |   2 +-
 b_asic/schema.py                        |   2 +-
 b_asic/{sfg.py => signal_flow_graph.py} |   3 +-
 setup.py                                |   6 +-
 10 files changed, 152 insertions(+), 120 deletions(-)
 create mode 100644 b_asic/basic_operation.py
 rename b_asic/{ops.py => core_operations.py} (91%)
 rename b_asic/{pc.py => precedence_chart.py} (89%)
 rename b_asic/{sfg.py => signal_flow_graph.py} (89%)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 8ba064fd..433d2746 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 b36a5d82..bcd09857 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 8bbc17ab..8a84a945 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 00000000..e87860c6
--- /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 6b370725..553d7cff 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 4bea5047..310491bc 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 cc18d6af..76a22c9f 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 a7642f49..c7a72526 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 d39cc524..8fbbebff 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 aa6d7a6c..71ae4e4a 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},
-- 
GitLab