diff --git a/legacy/simulation_oop/core_operations.h b/legacy/simulation_oop/core_operations.h
deleted file mode 100644
index 0926572905053cdf5c762f73545642f1ffe3d4f8..0000000000000000000000000000000000000000
--- a/legacy/simulation_oop/core_operations.h
+++ /dev/null
@@ -1,236 +0,0 @@
-#ifndef ASIC_SIMULATION_CORE_OPERATIONS_H
-#define ASIC_SIMULATION_CORE_OPERATIONS_H
-
-#define NOMINMAX
-#include "../debug.h"
-#include "../number.h"
-#include "operation.h"
-
-#include <algorithm>
-#include <cmath>
-#include <cstddef>
-#include <stdexcept>
-#include <utility>
-
-namespace asic {
-
-class constant_operation final : public abstract_operation {
-public:
-	constant_operation(result_key key, number value)
-		: abstract_operation(std::move(key))
-		, m_value(value) {}
-
-	[[nodiscard]] std::size_t output_count() const noexcept final {
-		return 1;
-	}
-
-private:
-	[[nodiscard]] number evaluate_output_impl(std::size_t, evaluation_context const&) const final {
-		ASIC_DEBUG_MSG("Evaluating constant.");
-		return m_value;
-	}
-
-	number m_value;
-};
-
-class addition_operation final : public binary_operation {
-public:
-	explicit addition_operation(result_key key)
-		: binary_operation(std::move(key)) {}
-
-	[[nodiscard]] std::size_t output_count() const noexcept final {
-		return 1;
-	}
-
-private:
-	[[nodiscard]] number evaluate_output_impl(std::size_t, evaluation_context const& context) const final {
-		ASIC_DEBUG_MSG("Evaluating addition.");
-		return this->evaluate_lhs(context) + this->evaluate_rhs(context);
-	}
-};
-
-class subtraction_operation final : public binary_operation {
-public:
-	explicit subtraction_operation(result_key key)
-		: binary_operation(std::move(key)) {}
-
-	[[nodiscard]] std::size_t output_count() const noexcept final {
-		return 1;
-	}
-
-private:
-	[[nodiscard]] number evaluate_output_impl(std::size_t, evaluation_context const& context) const final {
-		ASIC_DEBUG_MSG("Evaluating subtraction.");
-		return this->evaluate_lhs(context) - this->evaluate_rhs(context);
-	}
-};
-
-class multiplication_operation final : public binary_operation {
-public:
-	explicit multiplication_operation(result_key key)
-		: binary_operation(std::move(key)) {}
-
-	[[nodiscard]] std::size_t output_count() const noexcept final {
-		return 1;
-	}
-
-private:
-	[[nodiscard]] number evaluate_output_impl(std::size_t, evaluation_context const& context) const final {
-		ASIC_DEBUG_MSG("Evaluating multiplication.");
-		return this->evaluate_lhs(context) * this->evaluate_rhs(context);
-	}
-};
-
-class division_operation final : public binary_operation {
-public:
-	explicit division_operation(result_key key)
-		: binary_operation(std::move(key)) {}
-
-	[[nodiscard]] std::size_t output_count() const noexcept final {
-		return 1;
-	}
-
-private:
-	[[nodiscard]] number evaluate_output_impl(std::size_t, evaluation_context const& context) const final {
-		ASIC_DEBUG_MSG("Evaluating division.");
-		return this->evaluate_lhs(context) / this->evaluate_rhs(context);
-	}
-};
-
-class min_operation final : public binary_operation {
-public:
-	explicit min_operation(result_key key)
-		: binary_operation(std::move(key)) {}
-
-	[[nodiscard]] std::size_t output_count() const noexcept final {
-		return 1;
-	}
-
-private:
-	[[nodiscard]] number evaluate_output_impl(std::size_t, evaluation_context const& context) const final {
-		ASIC_DEBUG_MSG("Evaluating min.");
-		auto const lhs = this->evaluate_lhs(context);
-		if (lhs.imag() != 0) {
-			throw std::runtime_error{"Min does not support complex numbers."};
-		}
-		auto const rhs = this->evaluate_rhs(context);
-		if (rhs.imag() != 0) {
-			throw std::runtime_error{"Min does not support complex numbers."};
-		}
-		return std::min(lhs.real(), rhs.real());
-	}
-};
-
-class max_operation final : public binary_operation {
-public:
-	explicit max_operation(result_key key)
-		: binary_operation(std::move(key)) {}
-
-	[[nodiscard]] std::size_t output_count() const noexcept final {
-		return 1;
-	}
-
-private:
-	[[nodiscard]] number evaluate_output_impl(std::size_t, evaluation_context const& context) const final {
-		ASIC_DEBUG_MSG("Evaluating max.");
-		auto const lhs = this->evaluate_lhs(context);
-		if (lhs.imag() != 0) {
-			throw std::runtime_error{"Max does not support complex numbers."};
-		}
-		auto const rhs = this->evaluate_rhs(context);
-		if (rhs.imag() != 0) {
-			throw std::runtime_error{"Max does not support complex numbers."};
-		}
-		return std::max(lhs.real(), rhs.real());
-	}
-};
-
-class square_root_operation final : public unary_operation {
-public:
-	explicit square_root_operation(result_key key)
-		: unary_operation(std::move(key)) {}
-
-	[[nodiscard]] std::size_t output_count() const noexcept final {
-		return 1;
-	}
-
-private:
-	[[nodiscard]] number evaluate_output_impl(std::size_t, evaluation_context const& context) const final {
-		ASIC_DEBUG_MSG("Evaluating sqrt.");
-		return std::sqrt(this->evaluate_input(context));
-	}
-};
-
-class complex_conjugate_operation final : public unary_operation {
-public:
-	explicit complex_conjugate_operation(result_key key)
-		: unary_operation(std::move(key)) {}
-
-	[[nodiscard]] std::size_t output_count() const noexcept final {
-		return 1;
-	}
-
-private:
-	[[nodiscard]] number evaluate_output_impl(std::size_t, evaluation_context const& context) const final {
-		ASIC_DEBUG_MSG("Evaluating conj.");
-		return std::conj(this->evaluate_input(context));
-	}
-};
-
-class absolute_operation final : public unary_operation {
-public:
-	explicit absolute_operation(result_key key)
-		: unary_operation(std::move(key)) {}
-
-	[[nodiscard]] std::size_t output_count() const noexcept final {
-		return 1;
-	}
-
-private:
-	[[nodiscard]] number evaluate_output_impl(std::size_t, evaluation_context const& context) const final {
-		ASIC_DEBUG_MSG("Evaluating abs.");
-		return std::abs(this->evaluate_input(context));
-	}
-};
-
-class constant_multiplication_operation final : public unary_operation {
-public:
-	constant_multiplication_operation(result_key key, number value)
-		: unary_operation(std::move(key))
-		, m_value(value) {}
-
-	[[nodiscard]] std::size_t output_count() const noexcept final {
-		return 1;
-	}
-
-private:
-	[[nodiscard]] number evaluate_output_impl(std::size_t, evaluation_context const& context) const final {
-		ASIC_DEBUG_MSG("Evaluating cmul.");
-		return this->evaluate_input(context) * m_value;
-	}
-
-	number m_value;
-};
-
-class butterfly_operation final : public binary_operation {
-public:
-	explicit butterfly_operation(result_key key)
-		: binary_operation(std::move(key)) {}
-
-	[[nodiscard]] std::size_t output_count() const noexcept final {
-		return 2;
-	}
-
-private:
-	[[nodiscard]] number evaluate_output_impl(std::size_t index, evaluation_context const& context) const final {
-		ASIC_DEBUG_MSG("Evaluating bfly.");
-		if (index == 0) {
-			return this->evaluate_lhs(context) + this->evaluate_rhs(context);
-		}
-		return this->evaluate_lhs(context) - this->evaluate_rhs(context);
-	}
-};
-
-} // namespace asic
-
-#endif // ASIC_SIMULATION_CORE_OPERATIONS_H
\ No newline at end of file
diff --git a/legacy/simulation_oop/custom_operation.h b/legacy/simulation_oop/custom_operation.h
deleted file mode 100644
index 8a11aaacbc8c17500069522d9d8f56d9c416d804..0000000000000000000000000000000000000000
--- a/legacy/simulation_oop/custom_operation.h
+++ /dev/null
@@ -1,35 +0,0 @@
-#ifndef ASIC_SIMULATION_CUSTOM_OPERATION_H
-#define ASIC_SIMULATION_CUSTOM_OPERATION_H
-
-#include "../algorithm.h"
-#include "../debug.h"
-#include "../number.h"
-#include "operation.h"
-
-#include <cstddef>
-#include <fmt/format.h>
-#include <functional>
-#include <pybind11/pybind11.h>
-#include <stdexcept>
-#include <utility>
-
-namespace asic {
-
-class custom_operation final : public nary_operation {
-public:
-	custom_operation(result_key key, pybind11::object evaluate_output, pybind11::object truncate_input, std::size_t output_count);
-
-	[[nodiscard]] std::size_t output_count() const noexcept final;
-
-private:
-	[[nodiscard]] number evaluate_output_impl(std::size_t index, evaluation_context const& context) const final;
-	[[nodiscard]] number truncate_input(std::size_t index, number value, std::size_t bits) const final;
-
-	pybind11::object m_evaluate_output;
-	pybind11::object m_truncate_input;
-	std::size_t m_output_count;
-};
-
-} // namespace asic
-
-#endif // ASIC_SIMULATION_CUSTOM_OPERATION_H
\ No newline at end of file
diff --git a/legacy/simulation_oop/operation.h b/legacy/simulation_oop/operation.h
deleted file mode 100644
index 344eacc1482c40021b3d0ff686cbef5c71085f58..0000000000000000000000000000000000000000
--- a/legacy/simulation_oop/operation.h
+++ /dev/null
@@ -1,132 +0,0 @@
-#ifndef ASIC_SIMULATION_OPERATION_H
-#define ASIC_SIMULATION_OPERATION_H
-
-#include "../number.h"
-#include "../span.h"
-
-#include <cstddef>
-#include <cstdint>
-#include <fmt/format.h>
-#include <memory>
-#include <optional>
-#include <stdexcept>
-#include <string>
-#include <unordered_map>
-#include <utility>
-#include <vector>
-
-namespace asic {
-
-class operation;
-class signal_source;
-
-using result_key = std::string;
-using result_map = std::unordered_map<result_key, std::optional<number>>;
-using delay_map = std::unordered_map<result_key, number>;
-using delay_queue = std::vector<std::pair<result_key, signal_source const*>>;
-
-struct evaluation_context final {
-	result_map* results;
-	delay_map* delays;
-	delay_queue* deferred_delays;
-	std::optional<std::size_t> bits_override;
-	bool truncate;
-};
-
-class signal_source final {
-public:
-	signal_source() noexcept = default;
-	signal_source(std::shared_ptr<const operation> op, std::size_t index, std::optional<std::size_t> bits);
-
-	[[nodiscard]] explicit operator bool() const noexcept;
-
-	[[nodiscard]] std::optional<number> current_output(delay_map const& delays) const;
-	[[nodiscard]] number evaluate_output(evaluation_context const& context) const;
-
-	[[nodiscard]] std::optional<std::size_t> bits() const noexcept;
-
-private:
-	std::shared_ptr<const operation> m_operation;
-	std::size_t m_index = 0;
-	std::optional<std::size_t> m_bits;
-};
-
-class operation {
-public:
-	virtual ~operation() = default;
-	[[nodiscard]] virtual std::size_t output_count() const noexcept = 0;
-	[[nodiscard]] virtual std::optional<number> current_output(std::size_t index, delay_map const& delays) const = 0;
-	[[nodiscard]] virtual number evaluate_output(std::size_t index, evaluation_context const& context) const = 0;
-};
-
-class abstract_operation : public operation {
-public:
-	explicit abstract_operation(result_key key);
-	virtual ~abstract_operation() = default;
-
-	[[nodiscard]] std::optional<number> current_output(std::size_t, delay_map const&) const override;
-	[[nodiscard]] number evaluate_output(std::size_t index, evaluation_context const& context) const override;
-
-protected:
-	[[nodiscard]] virtual number evaluate_output_impl(std::size_t index, evaluation_context const& context) const = 0;
-	[[nodiscard]] virtual number truncate_input(std::size_t index, number value, std::size_t bits) const;
-
-	[[nodiscard]] result_key const& key_base() const;
-	[[nodiscard]] result_key key_of_output(std::size_t index) const;
-
-private:
-	result_key m_key;
-};
-
-class unary_operation : public abstract_operation {
-public:
-	explicit unary_operation(result_key key);
-	virtual ~unary_operation() = default;
-
-	void connect(signal_source in);
-
-protected:
-	[[nodiscard]] bool connected() const noexcept;
-	[[nodiscard]] signal_source const& input() const noexcept;
-	[[nodiscard]] number evaluate_input(evaluation_context const& context) const;
-
-private:
-	signal_source m_in;
-};
-
-class binary_operation : public abstract_operation {
-public:
-	explicit binary_operation(result_key key);
-	virtual ~binary_operation() = default;
-
-	void connect(signal_source lhs, signal_source rhs);
-
-protected:
-	[[nodiscard]] signal_source const& lhs() const noexcept;
-	[[nodiscard]] signal_source const& rhs() const noexcept;
-	[[nodiscard]] number evaluate_lhs(evaluation_context const& context) const;
-	[[nodiscard]] number evaluate_rhs(evaluation_context const& context) const;
-
-private:
-	signal_source m_lhs;
-	signal_source m_rhs;
-};
-
-class nary_operation : public abstract_operation {
-public:
-	explicit nary_operation(result_key key);
-	virtual ~nary_operation() = default;
-
-	void connect(std::vector<signal_source> inputs);
-
-protected:
-	[[nodiscard]] span<signal_source const> inputs() const noexcept;
-	[[nodiscard]] std::vector<number> evaluate_inputs(evaluation_context const& context) const;
-
-private:
-	std::vector<signal_source> m_inputs;
-};
-
-} // namespace asic
-
-#endif // ASIC_SIMULATION_OPERATION_H
\ No newline at end of file
diff --git a/legacy/simulation_oop/signal_flow_graph.h b/legacy/simulation_oop/signal_flow_graph.h
deleted file mode 100644
index f06788249e367d3e8e0602f04c6dcf91c71b7a96..0000000000000000000000000000000000000000
--- a/legacy/simulation_oop/signal_flow_graph.h
+++ /dev/null
@@ -1,82 +0,0 @@
-#ifndef ASIC_SIMULATION_SIGNAL_FLOW_GRAPH_H
-#define ASIC_SIMULATION_SIGNAL_FLOW_GRAPH_H
-
-#include "../algorithm.h"
-#include "../debug.h"
-#include "../number.h"
-#include "core_operations.h"
-#include "custom_operation.h"
-#include "operation.h"
-#include "special_operations.h"
-
-#include <Python.h>
-#include <cstddef>
-#include <fmt/format.h>
-#include <functional>
-#include <memory>
-#include <pybind11/pybind11.h>
-#include <stdexcept>
-#include <string_view>
-#include <unordered_map>
-#include <utility>
-#include <vector>
-
-namespace asic {
-
-class signal_flow_graph_operation final : public abstract_operation {
-public:
-	using added_operation_cache = std::unordered_map<PyObject const*, std::shared_ptr<operation>>;
-
-	signal_flow_graph_operation(result_key key);
-
-	void create(pybind11::handle sfg, added_operation_cache& added);
-
-	[[nodiscard]] std::vector<std::shared_ptr<input_operation>> const& inputs() noexcept;
-	[[nodiscard]] std::size_t output_count() const noexcept final;
-
-	[[nodiscard]] number evaluate_output(std::size_t index, evaluation_context const& context) const final;
-
-private:
-	[[nodiscard]] number evaluate_output_impl(std::size_t index, evaluation_context const& context) const final;
-
-	[[nodiscard]] static signal_source make_source(pybind11::handle op, std::size_t input_index, added_operation_cache& added,
-												   std::string_view prefix);
-
-	template <typename Operation, typename... Args>
-	[[nodiscard]] static std::shared_ptr<Operation> add_operation(pybind11::handle op, added_operation_cache& added, Args&&... args) {
-		return std::static_pointer_cast<Operation>(
-			added.try_emplace(op.ptr(), std::make_shared<Operation>(std::forward<Args>(args)...)).first->second);
-	}
-
-	template <typename Operation, typename... Args>
-	[[nodiscard]] static std::shared_ptr<Operation> add_unary_operation(pybind11::handle op, added_operation_cache& added,
-																		std::string_view prefix, Args&&... args) {
-		auto const new_op = add_operation<Operation>(op, added, std::forward<Args>(args)...);
-		new_op->connect(make_source(op, 0, added, prefix));
-		return new_op;
-	}
-
-	template <typename Operation, typename... Args>
-	[[nodiscard]] static std::shared_ptr<Operation> add_binary_operation(pybind11::handle op, added_operation_cache& added,
-																		 std::string_view prefix, Args&&... args) {
-		auto const new_op = add_operation<Operation>(op, added, std::forward<Args>(args)...);
-		new_op->connect(make_source(op, 0, added, prefix), make_source(op, 1, added, prefix));
-		return new_op;
-	}
-
-	[[nodiscard]] static std::shared_ptr<operation> add_signal_flow_graph_operation(pybind11::handle sfg, added_operation_cache& added,
-																					std::string_view prefix, result_key key);
-
-	[[nodiscard]] static std::shared_ptr<custom_operation> add_custom_operation(pybind11::handle op, added_operation_cache& added,
-																				std::string_view prefix, result_key key);
-
-	[[nodiscard]] static std::shared_ptr<operation> make_operation(pybind11::handle op, added_operation_cache& added,
-																   std::string_view prefix);
-
-	std::vector<output_operation> m_output_operations;
-	std::vector<std::shared_ptr<input_operation>> m_input_operations;
-};
-
-} // namespace asic
-
-#endif // ASIC_SIMULATION_SIGNAL_FLOW_GRAPH_H
\ No newline at end of file
diff --git a/legacy/simulation_oop/simulation.h b/legacy/simulation_oop/simulation.h
deleted file mode 100644
index 38e2771b877772bd28048cae16d791bb4e0b45e3..0000000000000000000000000000000000000000
--- a/legacy/simulation_oop/simulation.h
+++ /dev/null
@@ -1,66 +0,0 @@
-#ifndef ASIC_SIMULATION_OOP_H
-#define ASIC_SIMULATION_OOP_H
-
-#include "../number.h"
-#include "core_operations.h"
-#include "custom_operation.h"
-#include "operation.h"
-#include "signal_flow_graph.h"
-#include "special_operations.h"
-
-#include <cstddef>
-#include <cstdint>
-#include <fmt/format.h>
-#include <functional>
-#include <limits>
-#include <memory>
-#include <optional>
-#include <pybind11/functional.h>
-#include <pybind11/numpy.h>
-#include <pybind11/pybind11.h>
-#include <pybind11/stl.h>
-#include <string_view>
-#include <unordered_map>
-#include <utility>
-#include <variant>
-#include <vector>
-
-namespace asic {
-
-using iteration_t = std::uint32_t;
-using result_array_map = std::unordered_map<std::string, std::vector<number>>;
-using input_function_t = std::function<number(iteration_t)>;
-using input_provider_t = std::variant<number, std::vector<number>, input_function_t>;
-
-class simulation final {
-public:
-	simulation(pybind11::handle sfg, std::optional<std::vector<std::optional<input_provider_t>>> input_providers = std::nullopt);
-
-	void set_input(std::size_t index, input_provider_t input_provider);
-	void set_inputs(std::vector<std::optional<input_provider_t>> input_providers);
-
-	[[nodiscard]] std::vector<number> step(bool save_results, std::optional<std::size_t> bits_override, bool truncate);
-	[[nodiscard]] std::vector<number> run_until(iteration_t iteration, bool save_results, std::optional<std::size_t> bits_override,
-												bool truncate);
-	[[nodiscard]] std::vector<number> run_for(iteration_t iterations, bool save_results, std::optional<std::size_t> bits_override,
-											  bool truncate);
-	[[nodiscard]] std::vector<number> run(bool save_results, std::optional<std::size_t> bits_override, bool truncate);
-
-	[[nodiscard]] iteration_t iteration() const noexcept;
-	[[nodiscard]] pybind11::dict results() const noexcept;
-
-	void clear_results() noexcept;
-	void clear_state() noexcept;
-
-private:
-	signal_flow_graph_operation m_sfg;
-	result_array_map m_results;
-	delay_map m_delays;
-	iteration_t m_iteration = 0;
-	std::vector<input_function_t> m_input_functions;
-	std::optional<iteration_t> m_input_length;
-};
-
-} // namespace asic
-
-#endif // ASIC_SIMULATION_OOP_H
\ No newline at end of file
diff --git a/legacy/simulation_oop/special_operations.h b/legacy/simulation_oop/special_operations.h
deleted file mode 100644
index 88fb087e84378e36f423364d2c7d83a083828784..0000000000000000000000000000000000000000
--- a/legacy/simulation_oop/special_operations.h
+++ /dev/null
@@ -1,55 +0,0 @@
-#ifndef ASIC_SIMULATION_SPECIAL_OPERATIONS_H
-#define ASIC_SIMULATION_SPECIAL_OPERATIONS_H
-
-#include "../debug.h"
-#include "../number.h"
-#include "operation.h"
-
-#include <cassert>
-#include <cstddef>
-#include <utility>
-
-namespace asic {
-
-class input_operation final : public unary_operation {
-public:
-	explicit input_operation(result_key key);
-
-	[[nodiscard]] std::size_t output_count() const noexcept final;
-	[[nodiscard]] number value() const noexcept;
-	void value(number value) noexcept;
-
-private:
-	[[nodiscard]] number evaluate_output_impl(std::size_t index, evaluation_context const& context) const final;
-
-	number m_value{};
-};
-
-class output_operation final : public unary_operation {
-public:
-	explicit output_operation(result_key key);
-
-	[[nodiscard]] std::size_t output_count() const noexcept final;
-
-private:
-	[[nodiscard]] number evaluate_output_impl(std::size_t index, evaluation_context const& context) const final;
-};
-
-class delay_operation final : public unary_operation {
-public:
-	delay_operation(result_key key, number initial_value);
-
-	[[nodiscard]] std::size_t output_count() const noexcept final;
-
-	[[nodiscard]] std::optional<number> current_output(std::size_t index, delay_map const& delays) const final;
-	[[nodiscard]] number evaluate_output(std::size_t index, evaluation_context const& context) const final;
-
-private:
-	[[nodiscard]] number evaluate_output_impl(std::size_t index, evaluation_context const& context) const final;
-
-	number m_initial_value;
-};
-
-} // namespace asic
-
-#endif // ASIC_SIMULATION_SPECIAL_OPERATIONS_H
\ No newline at end of file
diff --git a/src/algorithm.h b/src/algorithm.h
deleted file mode 100644
index c86275d1c4ef09a525372d38a4c07a0beb11e8c4..0000000000000000000000000000000000000000
--- a/src/algorithm.h
+++ /dev/null
@@ -1,325 +0,0 @@
-#ifndef ASIC_ALGORITHM_H
-#define ASIC_ALGORITHM_H
-
-#include <cstddef>
-#include <iterator>
-#include <memory>
-#include <type_traits>
-#include <utility>
-
-namespace asic {
-namespace detail {
-
-template <typename Reference>
-class arrow_proxy final {
-public:
-	template <typename Ref>
-	constexpr explicit arrow_proxy(Ref&& r) : m_r(std::forward<Ref>(r)) {}
-
-	Reference* operator->() {
-		return std::addressof(m_r);
-	}
-
-private:
-	Reference m_r;
-};
-
-template <typename T>
-struct range_view final {
-	class iterator final {
-	public:
-		using difference_type = std::ptrdiff_t;
-		using value_type = T const;
-		using reference = value_type&;
-		using pointer = value_type*;
-		using iterator_category = std::random_access_iterator_tag;
-
-		constexpr iterator() noexcept = default;
-		constexpr explicit iterator(T value) noexcept : m_value(value) {}
-
-		[[nodiscard]] constexpr bool operator==(iterator const& other) const noexcept {
-			return m_value == other.m_value;
-		}
-
-		[[nodiscard]] constexpr bool operator!=(iterator const& other) const noexcept {
-			return m_value != other.m_value;
-		}
-
-		[[nodiscard]] constexpr bool operator<(iterator const& other) const noexcept {
-			return m_value < other.m_value;
-		}
-
-		[[nodiscard]] constexpr bool operator>(iterator const& other) const noexcept {
-			return m_value > other.m_value;
-		}
-
-		[[nodiscard]] constexpr bool operator<=(iterator const& other) const noexcept {
-			return m_value <= other.m_value;
-		}
-
-		[[nodiscard]] constexpr bool operator>=(iterator const& other) const noexcept {
-			return m_value >= other.m_value;
-		}
-
-		[[nodiscard]] constexpr reference operator*() const noexcept {
-			return m_value;
-		}
-
-		[[nodiscard]] constexpr pointer operator->() const noexcept {
-			return std::addressof(**this);
-		}
-
-		constexpr iterator& operator++() noexcept {
-			++m_value;
-			return *this;
-		}
-
-		constexpr iterator operator++(int) noexcept {
-			return iterator{m_value++};
-		}
-
-		constexpr iterator& operator--() noexcept {
-			--m_value;
-			return *this;
-		}
-
-		constexpr iterator operator--(int) noexcept {
-			return iterator{m_value--};
-		}
-
-		constexpr iterator& operator+=(difference_type n) noexcept {
-			m_value += n;
-			return *this;
-		}
-
-		constexpr iterator& operator-=(difference_type n) noexcept {
-			m_value -= n;
-			return *this;
-		}
-
-		[[nodiscard]] constexpr T operator[](difference_type n) noexcept {
-			return m_value + static_cast<T>(n);
-		}
-
-		[[nodiscard]] constexpr friend iterator operator+(iterator const& lhs, difference_type rhs) noexcept {
-			return iterator{lhs.m_value + rhs};
-		}
-
-		[[nodiscard]] constexpr friend iterator operator+(difference_type lhs, iterator const& rhs) noexcept {
-			return iterator{lhs + rhs.m_value};
-		}
-
-		[[nodiscard]] constexpr friend iterator operator-(iterator const& lhs, difference_type rhs) noexcept {
-			return iterator{lhs.m_value - rhs};
-		}
-
-		[[nodiscard]] constexpr friend difference_type operator-(iterator const& lhs, iterator const& rhs) noexcept {
-			return static_cast<difference_type>(lhs.m_value - rhs.m_value);
-		}
-
-	private:
-		T m_value{};
-	};
-
-	using sentinel = iterator;
-
-	template <typename First, typename Last>
-	constexpr range_view(First&& first, Last&& last) noexcept : m_begin(std::forward<First>(first)), m_end(std::forward<Last>(last)) {}
-
-	[[nodiscard]] constexpr iterator begin() const noexcept {
-		return m_begin;
-	}
-	[[nodiscard]] constexpr sentinel end() const noexcept {
-		return m_end;
-	}
-
-	iterator m_begin;
-	sentinel m_end;
-};
-
-template <typename Range, typename Iterator, typename Sentinel>
-struct enumerate_view final {
-	using sentinel = Sentinel;
-
-	class iterator final {
-	public:
-		using difference_type = typename std::iterator_traits<Iterator>::difference_type;
-		using value_type = typename std::iterator_traits<Iterator>::value_type;
-		using reference = std::pair<std::size_t const&, decltype(*std::declval<Iterator const>())>;
-		using pointer = arrow_proxy<reference>;
-		using iterator_category =
-			std::common_type_t<typename std::iterator_traits<Iterator>::iterator_category, std::bidirectional_iterator_tag>;
-
-		constexpr iterator() = default;
-
-		constexpr iterator(Iterator it, std::size_t index) : m_it(std::move(it)), m_index(index) {}
-
-		[[nodiscard]] constexpr bool operator==(iterator const& other) const {
-			return m_it == other.m_it;
-		}
-
-		[[nodiscard]] constexpr bool operator!=(iterator const& other) const {
-			return m_it != other.m_it;
-		}
-
-		[[nodiscard]] constexpr bool operator==(sentinel const& other) const {
-			return m_it == other;
-		}
-
-		[[nodiscard]] constexpr bool operator!=(sentinel const& other) const {
-			return m_it != other;
-		}
-
-		[[nodiscard]] constexpr reference operator*() const {
-			return reference{m_index, *m_it};
-		}
-
-		[[nodiscard]] constexpr pointer operator->() const {
-			return pointer{**this};
-		}
-
-		constexpr iterator& operator++() {
-			++m_it;
-			++m_index;
-			return *this;
-		}
-
-		constexpr iterator operator++(int) {
-			return iterator{m_it++, m_index++};
-		}
-
-		constexpr iterator& operator--() {
-			--m_it;
-			--m_index;
-			return *this;
-		}
-
-		constexpr iterator operator--(int) {
-			return iterator{m_it--, m_index--};
-		}
-
-	private:
-		Iterator m_it;
-		std::size_t m_index = 0;
-	};
-
-	constexpr iterator begin() const {
-		return iterator{std::begin(m_range), 0};
-	}
-
-	constexpr sentinel end() const {
-		return std::end(m_range);
-	}
-
-	Range m_range;
-};
-
-template <typename Range1, typename Range2, typename Iterator1, typename Iterator2, typename Sentinel1, typename Sentinel2>
-struct zip_view final {
-	using sentinel = std::pair<Sentinel1, Sentinel2>;
-
-	class iterator final {
-	public:
-		using difference_type = std::common_type_t<typename std::iterator_traits<Iterator1>::difference_type,
-			typename std::iterator_traits<Iterator2>::difference_type>;
-		using value_type =
-			std::pair<typename std::iterator_traits<Iterator1>::value_type, typename std::iterator_traits<Iterator2>::value_type>;
-		using reference = std::pair<decltype(*std::declval<Iterator1 const>()), decltype(*std::declval<Iterator2 const>())>;
-		using pointer = arrow_proxy<reference>;
-		using iterator_category = std::common_type_t<typename std::iterator_traits<Iterator1>::iterator_category,
-			typename std::iterator_traits<Iterator2>::iterator_category, std::bidirectional_iterator_tag>;
-
-		constexpr iterator() = default;
-
-		constexpr iterator(Iterator1 it1, Iterator2 it2) : m_it1(std::move(it1)), m_it2(std::move(it2)) {}
-
-		[[nodiscard]] constexpr bool operator==(iterator const& other) const {
-			return m_it1 == other.m_it1 && m_it2 == other.m_it2;
-		}
-
-		[[nodiscard]] constexpr bool operator!=(iterator const& other) const {
-			return !(*this == other);
-		}
-
-		[[nodiscard]] constexpr bool operator==(sentinel const& other) const {
-			return m_it1 == other.first || m_it2 == other.second;
-		}
-
-		[[nodiscard]] constexpr bool operator!=(sentinel const& other) const {
-			return !(*this == other);
-		}
-
-		[[nodiscard]] constexpr reference operator*() const {
-			return reference{*m_it1, *m_it2};
-		}
-
-		[[nodiscard]] constexpr pointer operator->() const {
-			return pointer{**this};
-		}
-
-		constexpr iterator& operator++() {
-			++m_it1;
-			++m_it2;
-			return *this;
-		}
-
-		constexpr iterator operator++(int) {
-			return iterator{m_it1++, m_it2++};
-		}
-
-		constexpr iterator& operator--() {
-			--m_it1;
-			--m_it2;
-			return *this;
-		}
-
-		constexpr iterator operator--(int) {
-			return iterator{m_it1--, m_it2--};
-		}
-
-	private:
-		Iterator1 m_it1;
-		Iterator2 m_it2;
-	};
-
-	constexpr iterator begin() const {
-		return iterator{std::begin(m_range1), std::begin(m_range2)};
-	}
-
-	constexpr sentinel end() const {
-		return sentinel{std::end(m_range1), std::end(m_range2)};
-	}
-
-	Range1 m_range1;
-	Range2 m_range2;
-};
-
-} // namespace detail
-
-template <typename First, typename Last, typename T = std::remove_cv_t<std::remove_reference_t<First>>>
-[[nodiscard]] constexpr auto range(First&& first, Last&& last) {
-	return detail::range_view<T>{std::forward<First>(first), std::forward<Last>(last)};
-}
-
-template <typename Last, typename T = std::remove_cv_t<std::remove_reference_t<Last>>>
-[[nodiscard]] constexpr auto range(Last&& last) {
-	return detail::range_view<T>{T{}, std::forward<Last>(last)};
-}
-
-template <typename Range, typename Iterator = decltype(std::begin(std::declval<Range>())),
-	typename Sentinel = decltype(std::end(std::declval<Range>()))>
-[[nodiscard]] constexpr auto enumerate(Range&& range) {
-	return detail::enumerate_view<Range, Iterator, Sentinel>{std::forward<Range>(range)};
-}
-
-template <typename Range1, typename Range2, typename Iterator1 = decltype(std::begin(std::declval<Range1>())),
-	typename Iterator2 = decltype(std::begin(std::declval<Range2>())), typename Sentinel1 = decltype(std::end(std::declval<Range1>())),
-	typename Sentinel2 = decltype(std::end(std::declval<Range2>()))>
-[[nodiscard]] constexpr auto zip(Range1&& range1, Range2&& range2) {
-	return detail::zip_view<Range1, Range2, Iterator1, Iterator2, Sentinel1, Sentinel2>{
-		std::forward<Range1>(range1), std::forward<Range2>(range2)};
-}
-
-} // namespace asic
-
-#endif // ASIC_ALGORITHM_H
\ No newline at end of file
diff --git a/src/debug.h b/src/debug.h
deleted file mode 100644
index a11aa057db644dbe2d29399398a1f48ca599876f..0000000000000000000000000000000000000000
--- a/src/debug.h
+++ /dev/null
@@ -1,80 +0,0 @@
-#ifndef ASIC_DEBUG_H
-#define ASIC_DEBUG_H
-
-#ifndef NDEBUG
-#define ASIC_ENABLE_DEBUG_LOGGING 1
-#define ASIC_ENABLE_ASSERTS 1
-#else
-#define ASIC_ENABLE_DEBUG_LOGGING 0
-#define ASIC_ENABLE_ASSERTS 0
-#endif // NDEBUG
-
-#if ASIC_ENABLE_DEBUG_LOGGING
-#include <filesystem>
-#include <fmt/format.h>
-#include <fstream>
-#include <ostream>
-#include <string_view>
-#include <utility>
-#endif // ASIC_ENABLE_DEBUG_LOGGING
-
-#if ASIC_ENABLE_ASSERTS
-#include <filesystem>
-#include <cstdlib>
-#include <cstdio>
-#include <string_view>
-#include <fmt/format.h>
-#endif // ASIC_ENABLE_ASSERTS
-
-namespace asic {
-
-constexpr auto debug_log_filename = "_b_asic_debug_log.txt";
-
-namespace detail {
-
-#if ASIC_ENABLE_DEBUG_LOGGING
-inline void log_debug_msg_string(std::string_view file, int line, std::string_view string) {
-	static auto log_file = std::ofstream{debug_log_filename, std::ios::trunc};
-	log_file << fmt::format("{:<40}: {}", fmt::format("{}:{}", std::filesystem::path{file}.filename().generic_string(), line), string)
-			 << std::endl;
-}
-
-template <typename Format, typename... Args>
-inline void log_debug_msg(std::string_view file, int line, Format&& format, Args&&... args) {
-	log_debug_msg_string(file, line, fmt::format(std::forward<Format>(format), std::forward<Args>(args)...));
-}
-#endif // ASIC_ENABLE_DEBUG_LOGGING
-
-#if ASIC_ENABLE_ASSERTS
-inline void fail_assert(std::string_view file, int line, std::string_view condition_string) {
-#if ASIC_ENABLE_DEBUG_LOGGING
-	log_debug_msg(file, line, "Assertion failed: {}", condition_string);
-#endif // ASIC_ENABLE_DEBUG_LOGGING
-	fmt::print(stderr, "{}:{}: Assertion failed: {}\n", std::filesystem::path{file}.filename().generic_string(), line, condition_string);
-	std::abort();
-}
-
-template <typename BoolConvertible>
-inline void check_assert(std::string_view file, int line, std::string_view condition_string, BoolConvertible&& condition) {
-	if (!static_cast<bool>(condition)) {
-		fail_assert(file, line, condition_string);
-	}
-}
-#endif // ASIC_ENABLE_ASSERTS
-
-} // namespace detail
-} // namespace asic
-
-#if ASIC_ENABLE_DEBUG_LOGGING
-#define ASIC_DEBUG_MSG(...) (asic::detail::log_debug_msg(__FILE__, __LINE__, __VA_ARGS__))
-#else
-#define ASIC_DEBUG_MSG(...) ((void)0)
-#endif // ASIC_ENABLE_DEBUG_LOGGING
-
-#if ASIC_ENABLE_ASSERTS
-#define ASIC_ASSERT(condition) (asic::detail::check_assert(__FILE__, __LINE__, #condition, (condition)))
-#else
-#define ASIC_ASSERT(condition) ((void)0)
-#endif
-
-#endif // ASIC_DEBUG_H
\ No newline at end of file
diff --git a/src/number.h b/src/number.h
deleted file mode 100644
index 9cb5b42f53be4eb0cfcc86d00be65005147384e2..0000000000000000000000000000000000000000
--- a/src/number.h
+++ /dev/null
@@ -1,13 +0,0 @@
-#ifndef ASIC_NUMBER_H
-#define ASIC_NUMBER_H
-
-#include <complex>
-#include <pybind11/complex.h>
-
-namespace asic {
-
-using number = std::complex<double>;
-
-} // namespace asic
-
-#endif // ASIC_NUMBER_H
\ No newline at end of file
diff --git a/src/simulation.h b/src/simulation.h
deleted file mode 100644
index aefa3a4e92b861b9c7b795c7301f900dc54ace6f..0000000000000000000000000000000000000000
--- a/src/simulation.h
+++ /dev/null
@@ -1,12 +0,0 @@
-#ifndef ASIC_SIMULATION_H
-#define ASIC_SIMULATION_H
-
-#include <pybind11/pybind11.h>
-
-namespace asic {
-
-void define_simulation_class(pybind11::module& module);
-
-} // namespace asic
-
-#endif // ASIC_SIMULATION_H
\ No newline at end of file
diff --git a/src/simulation/compile.h b/src/simulation/compile.h
deleted file mode 100644
index 883f4c5832978ea1bfd33c767fc947c1efde718e..0000000000000000000000000000000000000000
--- a/src/simulation/compile.h
+++ /dev/null
@@ -1,61 +0,0 @@
-#ifndef ASIC_SIMULATION_COMPILE_H
-#define ASIC_SIMULATION_COMPILE_H
-
-#include "instruction.h"
-
-#include <cstddef>
-#include <pybind11/pybind11.h>
-#include <string>
-#include <vector>
-
-namespace asic {
-
-using result_key = std::string;
-
-struct simulation_code final {
-	struct custom_operation final {
-		// Python function used to evaluate the custom operation.
-		pybind11::object evaluate_output;
-		// Number of inputs that the custom operation takes.
-		std::size_t input_count;
-		// Number of outputs that the custom operation gives.
-		std::size_t output_count;
-	};
-
-	struct custom_source final {
-		// Index into custom_operations where the custom_operation corresponding to this custom_source is located.
-		std::size_t custom_operation_index;
-		// Output index of the custom_operation that this source gets it value from.
-		std::size_t output_index;
-	};
-
-	struct delay_info final {
-		// Initial value to set at the start of the simulation.
-		number initial_value;
-		// The result index where the current value should be stored at the start of each iteration.
-		result_index_t result_index;
-	};
-
-	// Instructions to execute for one full iteration of the simulation.
-	std::vector<instruction> instructions;
-	// Custom operations used by the simulation.
-	std::vector<custom_operation> custom_operations;
-	// Signal sources that use custom operations.
-	std::vector<custom_source> custom_sources;
-	// Info about the delay operations used in the simulation.
-	std::vector<delay_info> delays;
-	// Keys for each result produced by the simulation. The index of the key matches the index of the result in the simulation state.
-	std::vector<result_key> result_keys;
-	// Number of values expected as input to the simulation.
-	std::size_t input_count;
-	// Number of values given as output from the simulation. This will be the number of values left on the stack after a full iteration of the simulation has been run.
-	std::size_t output_count;
-	// Maximum number of values that need to be able to fit on the stack in order to run a full iteration of the simulation.
-	std::size_t required_stack_size;
-};
-
-[[nodiscard]] simulation_code compile_simulation(pybind11::handle sfg);
-
-} // namespace asic
-
-#endif // ASIC_SIMULATION_COMPILE_H
\ No newline at end of file
diff --git a/src/simulation/format_code.h b/src/simulation/format_code.h
deleted file mode 100644
index 5ebbb95d1f11eb18b915dbab9fbccbb82d83304c..0000000000000000000000000000000000000000
--- a/src/simulation/format_code.h
+++ /dev/null
@@ -1,129 +0,0 @@
-#ifndef ASIC_SIMULATION_FORMAT_CODE_H
-#define ASIC_SIMULATION_FORMAT_CODE_H
-
-#include "../algorithm.h"
-#include "../debug.h"
-#include "../number.h"
-#include "compile.h"
-#include "instruction.h"
-
-#include <fmt/format.h>
-#include <string>
-
-namespace asic {
-
-[[nodiscard]] inline std::string format_number(number const& value) {
-	if (value.imag() == 0) {
-		return fmt::to_string(value.real());
-	}
-	if (value.real() == 0) {
-		return fmt::format("{}j", value.imag());
-	}
-	if (value.imag() < 0) {
-		return fmt::format("{}-{}j", value.real(), -value.imag());
-	}
-	return fmt::format("{}+{}j", value.real(), value.imag());
-}
-
-[[nodiscard]] inline std::string format_compiled_simulation_code_result_keys(simulation_code const& code) {
-	auto result = std::string{};
-	for (auto const& [i, result_key] : enumerate(code.result_keys)) {
-		result += fmt::format("{:>2}: \"{}\"\n", i, result_key);
-	}
-	return result;
-}
-
-[[nodiscard]] inline std::string format_compiled_simulation_code_delays(simulation_code const& code) {
-	auto result = std::string{};
-	for (auto const& [i, delay] : enumerate(code.delays)) {
-		ASIC_ASSERT(delay.result_index < code.result_keys.size());
-		result += fmt::format("{:>2}: Initial value: {}, Result: {}: \"{}\"\n",
-							  i,
-							  format_number(delay.initial_value),
-							  delay.result_index,
-							  code.result_keys[delay.result_index]);
-	}
-	return result;
-}
-
-[[nodiscard]] inline std::string format_compiled_simulation_code_instruction(instruction const& instruction) {
-	switch (instruction.type) {
-		// clang-format off
-		case instruction_type::push_input:              return fmt::format("push_input inputs[{}]", instruction.index);
-		case instruction_type::push_result:             return fmt::format("push_result results[{}]", instruction.index);
-		case instruction_type::push_delay:              return fmt::format("push_delay delays[{}]", instruction.index);
-		case instruction_type::push_constant:           return fmt::format("push_constant {}", format_number(instruction.value));
-		case instruction_type::truncate:                return fmt::format("truncate {:#018x}", instruction.bit_mask);
-		case instruction_type::addition:                return "addition";
-		case instruction_type::subtraction:             return "subtraction";
-		case instruction_type::multiplication:          return "multiplication";
-		case instruction_type::division:                return "division";
-		case instruction_type::min:                     return "min";
-		case instruction_type::max:                     return "max";
-		case instruction_type::square_root:             return "square_root";
-		case instruction_type::complex_conjugate:       return "complex_conjugate";
-		case instruction_type::absolute:                return "absolute";
-		case instruction_type::constant_multiplication: return fmt::format("constant_multiplication {}", format_number(instruction.value));
-		case instruction_type::update_delay:            return fmt::format("update_delay delays[{}]", instruction.index);
-		case instruction_type::custom:                  return fmt::format("custom custom_sources[{}]", instruction.index);
-		case instruction_type::forward_value:           return "forward_value";
-		// clang-format on
-	}
-	return std::string{};
-}
-
-[[nodiscard]] inline std::string format_compiled_simulation_code_instructions(simulation_code const& code) {
-	auto result = std::string{};
-	for (auto const& [i, instruction] : enumerate(code.instructions)) {
-		auto instruction_string = format_compiled_simulation_code_instruction(instruction);
-		if (instruction.result_index < code.result_keys.size()) {
-			instruction_string = fmt::format(
-				"{:<26} -> {}: \"{}\"", instruction_string, instruction.result_index, code.result_keys[instruction.result_index]);
-		}
-		result += fmt::format("{:>2}: {}\n", i, instruction_string);
-	}
-	return result;
-}
-
-[[nodiscard]] inline std::string format_compiled_simulation_code(simulation_code const& code) {
-	return fmt::format(
-		"==============================================\n"
-		"> Code stats\n"
-		"==============================================\n"
-		"Input count: {}\n"
-		"Output count: {}\n"
-		"Instruction count: {}\n"
-		"Required stack size: {}\n"
-		"Delay count: {}\n"
-		"Result count: {}\n"
-		"Custom operation count: {}\n"
-		"Custom source count: {}\n"
-		"==============================================\n"
-		"> Delays\n"
-		"==============================================\n"
-		"{}"
-		"==============================================\n"
-		"> Result keys\n"
-		"==============================================\n"
-		"{}"
-		"==============================================\n"
-		"> Instructions\n"
-		"==============================================\n"
-		"{}"
-		"==============================================",
-		code.input_count,
-		code.output_count,
-		code.instructions.size(),
-		code.required_stack_size,
-		code.delays.size(),
-		code.result_keys.size(),
-		code.custom_operations.size(),
-		code.custom_sources.size(),
-		format_compiled_simulation_code_delays(code),
-		format_compiled_simulation_code_result_keys(code),
-		format_compiled_simulation_code_instructions(code));
-}
-
-} // namespace asic
-
-#endif // ASIC_SIMULATION_FORMAT_CODE
\ No newline at end of file
diff --git a/src/simulation/instruction.h b/src/simulation/instruction.h
deleted file mode 100644
index d650c651394a243c52eee7e5ad2fe463f96bdad7..0000000000000000000000000000000000000000
--- a/src/simulation/instruction.h
+++ /dev/null
@@ -1,57 +0,0 @@
-#ifndef ASIC_SIMULATION_INSTRUCTION_H
-#define ASIC_SIMULATION_INSTRUCTION_H
-
-#include "../number.h"
-
-#include <cstddef>
-#include <cstdint>
-#include <optional>
-
-namespace asic {
-
-enum class instruction_type : std::uint8_t {
-	push_input,              // push(inputs[index])
-	push_result,             // push(results[index])
-	push_delay,              // push(delays[index])
-	push_constant,           // push(value)
-	truncate,                // push(trunc(pop(), bit_mask))
-	addition,                // push(pop() + pop())
-	subtraction,             // push(pop() - pop())
-	multiplication,          // push(pop() * pop())
-	division,                // push(pop() / pop())
-	min,                     // push(min(pop(), pop()))
-	max,                     // push(max(pop(), pop()))
-	square_root,             // push(sqrt(pop()))
-	complex_conjugate,       // push(conj(pop()))
-	absolute,                // push(abs(pop()))
-	constant_multiplication, // push(pop() * value)
-	update_delay,            // delays[index] = pop()
-	custom,                  // Custom operation. Uses custom_source[index].
-	forward_value            // Forward the current value on the stack (push(pop()), i.e. do nothing).
-};
-
-using result_index_t = std::uint16_t;
-
-struct instruction final {
-	constexpr instruction() noexcept
-		: index(0)
-		, result_index(0)
-		, type(instruction_type::forward_value) {}
-
-	union {
-		// Index used by push_input, push_result, delay and custom.
-		std::size_t index;
-		// Bit mask used by truncate.
-		std::int64_t bit_mask;
-		// Constant value used by push_constant and constant_multiplication.
-		number value;
-	};
-	// Index into where the result of the instruction will be stored. If the result should be ignored, this index will be one past the last valid result index.
-	result_index_t result_index;
-	// Specifies what kind of operation the instruction should execute.
-	instruction_type type;
-};
-
-} // namespace asic
-
-#endif // ASIC_SIMULATION_INSTRUCTION_H
\ No newline at end of file
diff --git a/src/simulation/run.h b/src/simulation/run.h
deleted file mode 100644
index 2174c571ef59f3e12236471e3e064f2619c38a60..0000000000000000000000000000000000000000
--- a/src/simulation/run.h
+++ /dev/null
@@ -1,23 +0,0 @@
-#ifndef ASIC_SIMULATION_RUN_H
-#define ASIC_SIMULATION_RUN_H
-
-#include "../number.h"
-#include "../span.h"
-#include "compile.h"
-
-#include <cstdint>
-#include <vector>
-
-namespace asic {
-
-struct simulation_state final {
-	std::vector<number> stack;
-	std::vector<number> results;
-};
-
-simulation_state run_simulation(simulation_code const& code, span<number const> inputs, span<number> delays,
-								std::optional<std::uint8_t> bits_override, bool truncate);
-
-} // namespace asic
-
-#endif // ASIC_SIMULATION_RUN_H
\ No newline at end of file
diff --git a/src/simulation/simulation.h b/src/simulation/simulation.h
deleted file mode 100644
index c1a36cbc93492494af14a198c970a6a534477794..0000000000000000000000000000000000000000
--- a/src/simulation/simulation.h
+++ /dev/null
@@ -1,54 +0,0 @@
-#ifndef ASIC_SIMULATION_DOD_H
-#define ASIC_SIMULATION_DOD_H
-
-#include "../number.h"
-#include "compile.h"
-
-#include <cstddef>
-#include <cstdint>
-#include <functional>
-#include <optional>
-#include <pybind11/functional.h>
-#include <pybind11/pybind11.h>
-#include <pybind11/stl.h>
-#include <variant>
-#include <vector>
-
-namespace asic {
-
-using iteration_t = std::uint32_t;
-using input_function_t = std::function<number(iteration_t)>;
-using input_provider_t = std::variant<number, std::vector<number>, input_function_t>;
-
-class simulation final {
-public:
-	simulation(pybind11::handle sfg, std::optional<std::vector<std::optional<input_provider_t>>> input_providers = std::nullopt);
-
-	void set_input(std::size_t index, input_provider_t input_provider);
-	void set_inputs(std::vector<std::optional<input_provider_t>> input_providers);
-
-	[[nodiscard]] std::vector<number> step(bool save_results, std::optional<std::uint8_t> bits_override, bool truncate);
-	[[nodiscard]] std::vector<number> run_until(iteration_t iteration, bool save_results, std::optional<std::uint8_t> bits_override,
-												bool truncate);
-	[[nodiscard]] std::vector<number> run_for(iteration_t iterations, bool save_results, std::optional<std::uint8_t> bits_override,
-											  bool truncate);
-	[[nodiscard]] std::vector<number> run(bool save_results, std::optional<std::uint8_t> bits_override, bool truncate);
-
-	[[nodiscard]] iteration_t iteration() const noexcept;
-	[[nodiscard]] pybind11::dict results() const noexcept;
-
-	void clear_results() noexcept;
-	void clear_state() noexcept;
-
-private:
-	simulation_code m_code;
-	std::vector<number> m_delays;
-	std::vector<input_function_t> m_input_functions;
-	std::optional<iteration_t> m_input_length;
-	iteration_t m_iteration = 0;
-	std::vector<std::vector<number>> m_results;
-};
-
-} // namespace asic
-
-#endif // ASIC_SIMULATION_DOD_H
\ No newline at end of file
diff --git a/src/span.h b/src/span.h
deleted file mode 100644
index 2ad454e13e3978c74355ae3ca0f955fad1bb9753..0000000000000000000000000000000000000000
--- a/src/span.h
+++ /dev/null
@@ -1,314 +0,0 @@
-#ifndef ASIC_SPAN_H
-#define ASIC_SPAN_H
-
-#include <cstddef>
-#include <type_traits>
-#include <utility>
-#include <iterator>
-#include <limits>
-#include <array>
-#include <algorithm>
-#include <cassert>
-
-namespace asic {
-
-constexpr auto dynamic_size = static_cast<std::size_t>(-1);
-
-// C++17-compatible std::span substitute.
-template <typename T, std::size_t Size = dynamic_size>
-class span;
-
-namespace detail {
-
-template <typename T>
-struct is_span_impl : std::false_type {};
-
-template <typename T, std::size_t Size>
-struct is_span_impl<span<T, Size>> : std::true_type {};
-
-template <typename T>
-struct is_span : is_span_impl<std::remove_cv_t<T>> {};
-
-template <typename T>
-constexpr auto is_span_v = is_span<T>::value;
-
-template <typename T>
-struct is_std_array_impl : std::false_type {};
-
-template <typename T, std::size_t Size>
-struct is_std_array_impl<std::array<T, Size>> : std::true_type {};
-
-template <typename T>
-struct is_std_array : is_std_array_impl<std::remove_cv_t<T>> {};
-
-template <typename T>
-constexpr auto is_std_array_v = is_std_array<T>::value;
-
-template <std::size_t From, std::size_t To>
-struct is_size_convertible : std::bool_constant<From == To || From == dynamic_size || To == dynamic_size> {};
-
-template <std::size_t From, std::size_t To>
-constexpr auto is_size_convertible_v = is_size_convertible<From, To>::value;
-
-template <typename From, typename To>
-struct is_element_type_convertible : std::bool_constant<std::is_convertible_v<From(*)[], To(*)[]>> {};
-
-template <typename From, typename To>
-constexpr auto is_element_type_convertible_v = is_element_type_convertible<From, To>::value;
-
-template <typename T, std::size_t Size>
-struct span_base {
-	using element_type	= T;
-	using pointer		= element_type*;
-	using size_type		= std::size_t;
-
-	constexpr span_base() noexcept = default;
-	constexpr span_base(pointer data, [[maybe_unused]] size_type size) : m_data(data) { assert(size == Size); }
-
-	template <size_type N>
-	constexpr span_base(span_base<T, N> other) : m_data(other.data()) {
-		static_assert(N == Size || N == dynamic_size);
-		assert(other.size() == Size);
-	}
-
-	[[nodiscard]] constexpr pointer data() const noexcept	{ return m_data; }
-	[[nodiscard]] constexpr size_type size() const noexcept	{ return Size; }
-
-private:
-	pointer m_data = nullptr;
-};
-
-template <typename T>
-struct span_base<T, dynamic_size> {
-	using element_type	= T;
-	using pointer		= element_type*;
-	using size_type		= std::size_t;
-
-	constexpr span_base() noexcept = default;
-	constexpr span_base(pointer data, size_type size) : m_data(data), m_size(size) {}
-
-	template <size_type N>
-	explicit constexpr span_base(span_base<T, N> other) : m_data(other.data()), m_size(other.size()) {}
-
-	[[nodiscard]] constexpr pointer data() const noexcept	{ return m_data; }
-	[[nodiscard]] constexpr size_type size() const noexcept	{ return m_size; }
-
-private:
-	pointer		m_data = nullptr;
-	size_type	m_size = 0;
-};
-
-template <typename T, std::size_t Size, std::size_t Offset, std::size_t N>
-struct subspan_type {
-	using type = span<
-		T,
-		(N != dynamic_size) ?
-			N :
-			(Size != dynamic_size) ?
-				Size - Offset :
-				Size
-	>;
-};
-
-template <typename T, std::size_t Size, std::size_t Offset, std::size_t Count>
-using subspan_type_t = typename subspan_type<T, Size, Offset, Count>::type;
-
-} // namespace detail
-
-template <typename T, std::size_t Size>
-class span final : public detail::span_base<T, Size> {
-public:
-	using element_type				= typename detail::span_base<T, Size>::element_type;
-	using pointer					= typename detail::span_base<T, Size>::pointer;
-	using size_type					= typename detail::span_base<T, Size>::size_type;
-	using value_type				= std::remove_cv_t<element_type>;
-	using reference					= element_type&;
-	using iterator					= element_type*;
-	using const_iterator			= const element_type*;
-	using reverse_iterator			= std::reverse_iterator<iterator>;
-	using const_reverse_iterator	= std::reverse_iterator<const_iterator>;
-
-	// Default constructor.
-	constexpr span() noexcept = default;
-
-	// Construct from pointer, size.
-	constexpr span(pointer data, size_type size) : detail::span_base<T, Size>(data, size) {}
-
-	// Copy constructor.
-	template <
-		typename U, std::size_t N,
-		typename = std::enable_if_t<detail::is_size_convertible_v<N, Size>>,
-		typename = std::enable_if_t<detail::is_element_type_convertible_v<U, T>>
-	>
-	constexpr span(span<U, N> const& other) : span(other.data(), other.size()) {}
-
-	// Copy assignment.
-	constexpr span& operator=(span const&) noexcept = default;
-
-	// Destructor.
-	~span() = default;
-
-	// Construct from begin, end.
-	constexpr span(pointer begin, pointer end) : span(begin, end - begin) {}
-
-	// Construct from C array.
-	template <std::size_t N>
-	constexpr span(element_type(&arr)[N]) noexcept : span(std::data(arr), N) {}
-
-	// Construct from std::array.
-	template <
-		std::size_t N,
-		typename = std::enable_if_t<N != 0>
-	>
-	constexpr span(std::array<value_type, N>& arr) noexcept : span(std::data(arr), N) {}
-
-	// Construct from empty std::array.
-	constexpr span(std::array<value_type, 0>&) noexcept : span() {}
-
-	// Construct from const std::array.
-	template <
-		std::size_t N,
-		typename = std::enable_if_t<N != 0>
-	>
-	constexpr span(std::array<value_type, N> const& arr) noexcept : span(std::data(arr), N) {}
-
-	// Construct from empty const std::array.
-	constexpr span(std::array<value_type, 0> const&) noexcept : span() {}
-
-	// Construct from other container.
-	template <
-		typename Container,
-		typename = std::enable_if_t<!detail::is_span_v<Container>>,
-		typename = std::enable_if_t<!detail::is_std_array_v<Container>>,
-		typename = decltype(std::data(std::declval<Container>())),
-		typename = decltype(std::size(std::declval<Container>())),
-		typename = std::enable_if_t<std::is_convertible_v<typename Container::pointer, pointer>>,
-		typename = std::enable_if_t<std::is_convertible_v<typename Container::pointer, decltype(std::data(std::declval<Container>()))>>
-	>
-	constexpr span(Container& container) : span(std::data(container), std::size(container)) {}
-
-	// Construct from other const container.
-	template <
-		typename Container,
-		typename Element = element_type,
-		typename = std::enable_if_t<std::is_const_v<Element>>,
-		typename = std::enable_if_t<!detail::is_span_v<Container>>,
-		typename = std::enable_if_t<!detail::is_std_array_v<Container>>,
-		typename = decltype(std::data(std::declval<Container>())),
-		typename = decltype(std::size(std::declval<Container>())),
-		typename = std::enable_if_t<std::is_convertible_v<typename Container::pointer, pointer>>,
-		typename = std::enable_if_t<std::is_convertible_v<typename Container::pointer, decltype(std::data(std::declval<Container>()))>>
-	>
-	constexpr span(Container const& container) : span(std::data(container), std::size(container)) {}
-
-	[[nodiscard]] constexpr iterator begin() const noexcept						{ return this->data(); }
-	[[nodiscard]] constexpr const_iterator cbegin() const noexcept				{ return this->data(); }
-	[[nodiscard]] constexpr iterator end() const noexcept						{ return this->data() + this->size(); }
-	[[nodiscard]] constexpr const_iterator cend() const noexcept				{ return this->data() + this->size(); }
-	[[nodiscard]] constexpr reverse_iterator rbegin() const noexcept			{ return std::make_reverse_iterator(this->end()); }
-	[[nodiscard]] constexpr const_reverse_iterator crbegin() const noexcept		{ return std::make_reverse_iterator(this->cend()); }
-	[[nodiscard]] constexpr reverse_iterator rend() const noexcept				{ return std::make_reverse_iterator(this->begin()); }
-	[[nodiscard]] constexpr const_reverse_iterator crend() const noexcept		{ return std::make_reverse_iterator(this->cbegin()); }
-
-	[[nodiscard]] constexpr reference operator[](size_type i) const noexcept	{ assert(i < this->size()); return this->data()[i]; }
-	[[nodiscard]] constexpr reference operator()(size_type i) const noexcept	{ assert(i < this->size()); return this->data()[i]; }
-
-	[[nodiscard]] constexpr size_type size_bytes() const noexcept				{ return this->size() * sizeof(element_type); }
-	[[nodiscard]] constexpr bool empty() const noexcept							{ return this->size() == 0; }
-
-	[[nodiscard]] constexpr reference front() const noexcept					{ assert(!this->empty()); return this->data()[0]; }
-	[[nodiscard]] constexpr reference back() const noexcept						{ assert(!this->empty()); return this->data()[this->size() - 1]; }
-
-	template <std::size_t N>
-	[[nodiscard]] constexpr span<T, N> first() const {
-		static_assert(N != dynamic_size && N <= Size);
-		return {this->data(), N};
-	}
-
-	template <std::size_t N>
-	[[nodiscard]] constexpr span<T, N> last() const {
-		static_assert(N != dynamic_size && N <= Size);
-		return {this->data() + (Size - N), N};
-	}
-
-	template <std::size_t Offset, std::size_t N = dynamic_size>
-	[[nodiscard]] constexpr auto subspan() const -> detail::subspan_type_t<T, Size, Offset, N> {
-		static_assert(Offset <= Size);
-		return {this->data() + Offset, (N == dynamic_size) ? this->size() - Offset : N};
-	}
-
-	[[nodiscard]] constexpr span<T, dynamic_size> first(size_type n) const {
-		assert(n <= this->size());
-		return { this->data(), n };
-	}
-
-	[[nodiscard]] constexpr span<T, dynamic_size> last(size_type n) const {
-		return this->subspan(this->size() - n);
-	}
-
-	[[nodiscard]] constexpr span<T, dynamic_size> subspan(size_type offset, size_type n = dynamic_size) const {
-		if constexpr (Size == dynamic_size) {
-			assert(offset <= this->size());
-			if (n == dynamic_size) {
-				return { this->data() + offset, this->size() - offset };
-			}
-			assert(n <= this->size());
-			assert(offset + n <= this->size());
-			return {this->data() + offset, n};
-		} else {
-			return span<T, dynamic_size>{*this}.subspan(offset, n);
-		}
-	}
-};
-
-template <typename T, std::size_t LhsSize, std::size_t RhsSize>
-[[nodiscard]] constexpr bool operator==(span<T, LhsSize> lhs, span<T, RhsSize> rhs) {
-	return std::equal(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
-}
-
-template <typename T, std::size_t LhsSize, std::size_t RhsSize>
-[[nodiscard]] constexpr bool operator!=(span<T, LhsSize> lhs, span<T, RhsSize> rhs) {
-	return !(lhs == rhs);
-}
-
-template <typename T, std::size_t LhsSize, std::size_t RhsSize>
-[[nodiscard]] constexpr bool operator<(span<T, LhsSize> lhs, span<T, RhsSize> rhs) {
-	return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
-}
-
-template <typename T, std::size_t LhsSize, std::size_t RhsSize>
-[[nodiscard]] constexpr bool operator<=(span<T, LhsSize> lhs, span<T, RhsSize> rhs) {
-	return !(lhs > rhs);
-}
-
-template <typename T, std::size_t LhsSize, std::size_t RhsSize>
-[[nodiscard]] constexpr bool operator>(span<T, LhsSize> lhs, span<T, RhsSize> rhs) {
-	return rhs < lhs;
-}
-
-template <typename T, std::size_t LhsSize, std::size_t RhsSize>
-[[nodiscard]] constexpr bool operator>=(span<T, LhsSize> lhs, span<T, RhsSize> rhs) {
-	return !(lhs < rhs);
-}
-
-template <typename Container>
-span(Container&) -> span<typename Container::value_type>;
-
-template <typename Container>
-span(Container const&) -> span<typename Container::value_type const>;
-
-template <typename T, std::size_t N>
-span(T(&)[N]) -> span<T, N>;
-
-template <typename T, std::size_t N>
-span(std::array<T, N>&) -> span<T, N>;
-
-template <typename T, std::size_t N>
-span(std::array<T, N> const&) -> span<T const, N>;
-
-template <typename T, typename Dummy>
-span(T, Dummy&&) -> span<std::remove_reference_t<decltype(std::declval<T>()[0])>>;
-
-} // namespace asic
-
-#endif // ASIC_SPAN_H
\ No newline at end of file