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},