diff --git a/.gitignore b/.gitignore
index 52db8cb9aeab4fa7229202d8e66a8080e81fa27d..c5b2148a43663314ad0317ed1d16a12c0627085e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -120,3 +120,4 @@ result_images/
 .coverage
 Digraph.gv
 Digraph.gv.pdf
+*.pstat
diff --git a/b_asic/__init__.py b/b_asic/__init__.py
index 423e4676d9eda02aed6ec6accff2900743a0a04f..5b365ed17b584f6be96d7ec90d216fa6709306a5 100644
--- a/b_asic/__init__.py
+++ b/b_asic/__init__.py
@@ -4,6 +4,7 @@ ASIC toolbox that simplifies circuit design and optimization.
 
 # Python modules.
 from b_asic.core_operations import *
+from b_asic.core_schedulers import *
 from b_asic.graph_component import *
 from b_asic.operation import *
 from b_asic.port import *
diff --git a/b_asic/core_schedulers.py b/b_asic/core_schedulers.py
new file mode 100644
index 0000000000000000000000000000000000000000..05bcc3f454dc59ab48b776baa3e46281c7da3451
--- /dev/null
+++ b/b_asic/core_schedulers.py
@@ -0,0 +1,124 @@
+import copy
+from typing import TYPE_CHECKING, cast
+
+from b_asic.scheduler import ListScheduler, Scheduler
+from b_asic.special_operations import Delay, Output
+
+if TYPE_CHECKING:
+    from b_asic.schedule import Schedule
+    from b_asic.types import GraphID
+
+
+class ASAPScheduler(Scheduler):
+    """Scheduler that implements the as-soon-as-possible (ASAP) algorithm."""
+
+    def apply_scheduling(self, schedule: "Schedule") -> None:
+        """Applies the scheduling algorithm on the given Schedule.
+
+        Parameters
+        ----------
+        schedule : Schedule
+            Schedule to apply the scheduling algorithm on.
+        """
+        prec_list = schedule.sfg.get_precedence_list()
+        if len(prec_list) < 2:
+            raise ValueError("Empty signal flow graph cannot be scheduled.")
+
+        # handle the first set in precedence graph (input and delays)
+        non_schedulable_ops = []
+        for outport in prec_list[0]:
+            operation = outport.operation
+            if operation.type_name() == Delay.type_name():
+                non_schedulable_ops.append(operation.graph_id)
+            else:
+                schedule.start_times[operation.graph_id] = 0
+
+        # handle second set in precedence graph (first operations)
+        for outport in prec_list[1]:
+            operation = outport.operation
+            schedule.start_times[operation.graph_id] = 0
+
+        # handle the remaining sets
+        for outports in prec_list[2:]:
+            for outport in outports:
+                operation = outport.operation
+                if operation.graph_id not in schedule.start_times:
+                    op_start_time = 0
+                    for current_input in operation.inputs:
+                        source_port = current_input.signals[0].source
+
+                        if source_port.operation.graph_id in non_schedulable_ops:
+                            source_end_time = 0
+                        else:
+                            source_op_time = schedule.start_times[
+                                source_port.operation.graph_id
+                            ]
+
+                            if source_port.latency_offset is None:
+                                raise ValueError(
+                                    f"Output port {source_port.index} of"
+                                    " operation"
+                                    f" {source_port.operation.graph_id} has no"
+                                    " latency-offset."
+                                )
+
+                            source_end_time = (
+                                source_op_time + source_port.latency_offset
+                            )
+
+                        if current_input.latency_offset is None:
+                            raise ValueError(
+                                f"Input port {current_input.index} of operation"
+                                f" {current_input.operation.graph_id} has no"
+                                " latency-offset."
+                            )
+                        op_start_time_from_in = (
+                            source_end_time - current_input.latency_offset
+                        )
+                        op_start_time = max(op_start_time, op_start_time_from_in)
+
+                    schedule.start_times[operation.graph_id] = op_start_time
+
+        self._handle_outputs(schedule, non_schedulable_ops)
+        schedule.remove_delays()
+
+
+class ALAPScheduler(Scheduler):
+    """Scheduler that implements the as-late-as-possible (ALAP) algorithm."""
+
+    def apply_scheduling(self, schedule: "Schedule") -> None:
+        """Applies the scheduling algorithm on the given Schedule.
+
+        Parameters
+        ----------
+        schedule : Schedule
+            Schedule to apply the scheduling algorithm on.
+        """
+        ASAPScheduler().apply_scheduling(schedule)
+        max_end_time = schedule.get_max_end_time()
+
+        if schedule.schedule_time is None:
+            schedule.set_schedule_time(max_end_time)
+        elif schedule.schedule_time < max_end_time:
+            raise ValueError(f"Too short schedule time. Minimum is {max_end_time}.")
+
+        # move all outputs ALAP before operations
+        for output in schedule.sfg.find_by_type_name(Output.type_name()):
+            output = cast(Output, output)
+            schedule.move_operation_alap(output.graph_id)
+
+        # move all operations ALAP
+        for step in reversed(schedule.sfg.get_precedence_list()):
+            for outport in step:
+                if not isinstance(outport.operation, Delay):
+                    schedule.move_operation_alap(outport.operation.graph_id)
+
+
+class EarliestDeadlineScheduler(ListScheduler):
+    """Scheduler that implements the earliest-deadline-first algorithm."""
+
+    @staticmethod
+    def _get_sorted_operations(schedule: "Schedule") -> list["GraphID"]:
+        schedule_copy = copy.deepcopy(schedule)
+        ALAPScheduler().apply_scheduling(schedule_copy)
+        return sorted(schedule_copy.start_times, key=schedule_copy.start_times.get)
diff --git a/b_asic/schedule.py b/b_asic/schedule.py
index 4c7f01b6dea0be070b775e84605c0b0b84363ab8..922f3dbc8d1d21010865124db3eaf228734a6dae 100644
--- a/b_asic/schedule.py
+++ b/b_asic/schedule.py
@@ -793,117 +793,6 @@ class Schedule:
                 new_sfg = new_sfg.insert_operation_before(op, Delay(), port)
         return new_sfg()
 
-    # def _schedule_alap(self) -> None:
-    #     """Schedule the operations using as-late-as-possible scheduling."""
-    #     precedence_list = self._sfg.get_precedence_list()
-    #     self._schedule_asap()
-    #     max_end_time = self.get_max_end_time()
-
-    #     if self.schedule_time is None:
-    #         self._schedule_time = max_end_time
-    #     elif self.schedule_time < max_end_time:
-    #         raise ValueError(f"Too short schedule time. Minimum is {max_end_time}.")
-
-    #     for output in self._sfg.find_by_type_name(Output.type_name()):
-    #         output = cast(Output, output)
-    #         self.move_operation_alap(output.graph_id)
-    #     for step in reversed(precedence_list):
-    #         graph_ids = {
-    #             outport.operation.graph_id
-    #             for outport in step
-    #             if not isinstance(outport.operation, Delay)
-    #         }
-    #         for graph_id in graph_ids:
-    #             self.move_operation_alap(graph_id)
-
-    # def _schedule_asap(self) -> None:
-    #     """Schedule the operations using as-soon-as-possible scheduling."""
-    #     precedence_list = self._sfg.get_precedence_list()
-
-    #     if len(precedence_list) < 2:
-    #         raise ValueError("Empty signal flow graph cannot be scheduled.")
-
-    #     non_schedulable_ops = set()
-    #     for outport in precedence_list[0]:
-    #         operation = outport.operation
-    #         if operation.type_name() not in [Delay.type_name()]:
-    #             if operation.graph_id not in self._start_times:
-    #                 # Set start time of all operations in the first iter to 0
-    #                 self._start_times[operation.graph_id] = 0
-    #         else:
-    #             non_schedulable_ops.add(operation.graph_id)
-
-    #     for outport in precedence_list[1]:
-    #         operation = outport.operation
-    #         if operation.graph_id not in self._start_times:
-    #             # Set start time of all operations in the first iter to 0
-    #             self._start_times[operation.graph_id] = 0
-
-    #     for outports in precedence_list[2:]:
-    #         for outport in outports:
-    #             operation = outport.operation
-    #             if operation.graph_id not in self._start_times:
-    #                 # Schedule the operation if it does not have a start time yet.
-    #                 op_start_time = 0
-    #                 for current_input in operation.inputs:
-    #                     if len(current_input.signals) != 1:
-    #                         raise ValueError(
-    #                             "Error in scheduling, dangling input port detected."
-    #                         )
-    #                     if current_input.signals[0].source is None:
-    #                         raise ValueError(
-    #                             "Error in scheduling, signal with no source detected."
-    #                         )
-    #                     source_port = current_input.signals[0].source
-
-    #                     if source_port.operation.graph_id in non_schedulable_ops:
-    #                         source_end_time = 0
-    #                     else:
-    #                         source_op_time = self._start_times[
-    #                             source_port.operation.graph_id
-    #                         ]
-
-    #                         if source_port.latency_offset is None:
-    #                             raise ValueError(
-    #                                 f"Output port {source_port.index} of"
-    #                                 " operation"
-    #                                 f" {source_port.operation.graph_id} has no"
-    #                                 " latency-offset."
-    #                             )
-
-    #                         source_end_time = (
-    #                             source_op_time + source_port.latency_offset
-    #                         )
-
-    #                     if current_input.latency_offset is None:
-    #                         raise ValueError(
-    #                             f"Input port {current_input.index} of operation"
-    #                             f" {current_input.operation.graph_id} has no"
-    #                             " latency-offset."
-    #                         )
-    #                     op_start_time_from_in = (
-    #                         source_end_time - current_input.latency_offset
-    #                     )
-    #                     op_start_time = max(op_start_time, op_start_time_from_in)
-
-    #                 self._start_times[operation.graph_id] = op_start_time
-    #     for output in self._sfg.find_by_type_name(Output.type_name()):
-    #         output = cast(Output, output)
-    #         source_port = cast(OutputPort, output.inputs[0].signals[0].source)
-    #         if source_port.operation.graph_id in non_schedulable_ops:
-    #             self._start_times[output.graph_id] = 0
-    #         else:
-    #             if source_port.latency_offset is None:
-    #                 raise ValueError(
-    #                     f"Output port {source_port.index} of operation"
-    #                     f" {source_port.operation.graph_id} has no"
-    #                     " latency-offset."
-    #                 )
-    #             self._start_times[output.graph_id] = self._start_times[
-    #                 source_port.operation.graph_id
-    #             ] + cast(int, source_port.latency_offset)
-    #     self._remove_delays()
-
     def _get_memory_variables_list(self) -> List[MemoryVariable]:
         ret: List[MemoryVariable] = []
         for graph_id, start_time in self._start_times.items():
diff --git a/b_asic/scheduler.py b/b_asic/scheduler.py
index e109d01d9de77ed74b7f685ead2982d085def749..cc47294527a31eff720fe2dfb11594436ce19dc8 100644
--- a/b_asic/scheduler.py
+++ b/b_asic/scheduler.py
@@ -1,6 +1,4 @@
-import sys
 from abc import ABC, abstractmethod
-from collections import defaultdict
 from typing import TYPE_CHECKING, Optional, cast
 
 from b_asic.port import OutputPort
@@ -8,7 +6,9 @@ from b_asic.special_operations import Delay, Input, Output
 from b_asic.types import TypeName
 
 if TYPE_CHECKING:
+    from b_asic.operation import Operation
     from b_asic.schedule import Schedule
+    from b_asic.types import GraphID
 
 
 class Scheduler(ABC):
@@ -23,7 +23,9 @@ class Scheduler(ABC):
         """
         raise NotImplementedError
 
-    def _handle_outputs(self, schedule, non_schedulable_ops=set()) -> None:
+    def _handle_outputs(
+        self, schedule: "Schedule", non_schedulable_ops: Optional[list["GraphID"]] = []
+    ) -> None:
         for output in schedule.sfg.find_by_type_name(Output.type_name()):
             output = cast(Output, output)
             source_port = cast(OutputPort, output.inputs[0].signals[0].source)
@@ -41,124 +43,7 @@ class Scheduler(ABC):
                 ] + cast(int, source_port.latency_offset)
 
 
-class ASAPScheduler(Scheduler):
-    """Scheduler that implements the as-soon-as-possible (ASAP) algorithm."""
-
-    def apply_scheduling(self, schedule: "Schedule") -> None:
-        """Applies the scheduling algorithm on the given Schedule.
-
-        Parameters
-        ----------
-        schedule : Schedule
-            Schedule to apply the scheduling algorithm on.
-        """
-        prec_list = schedule.sfg.get_precedence_list()
-        if len(prec_list) < 2:
-            raise ValueError("Empty signal flow graph cannot be scheduled.")
-
-        # handle the first set in precedence graph (input and delays)
-        non_schedulable_ops = set()
-        for outport in prec_list[0]:
-            operation = outport.operation
-            if operation.type_name() == Delay.type_name():
-                non_schedulable_ops.add(operation.graph_id)
-            else:
-                schedule.start_times[operation.graph_id] = 0
-
-        # handle second set in precedence graph (first operations)
-        for outport in prec_list[1]:
-            operation = outport.operation
-            schedule.start_times[operation.graph_id] = 0
-
-        # handle the remaining sets
-        for outports in prec_list[2:]:
-            for outport in outports:
-                operation = outport.operation
-                if operation.graph_id not in schedule.start_times:
-                    op_start_time = 0
-                    for current_input in operation.inputs:
-                        source_port = current_input.signals[0].source
-
-                        if source_port.operation.graph_id in non_schedulable_ops:
-                            source_end_time = 0
-                        else:
-                            source_op_time = schedule.start_times[
-                                source_port.operation.graph_id
-                            ]
-
-                            if source_port.latency_offset is None:
-                                raise ValueError(
-                                    f"Output port {source_port.index} of"
-                                    " operation"
-                                    f" {source_port.operation.graph_id} has no"
-                                    " latency-offset."
-                                )
-
-                            source_end_time = (
-                                source_op_time + source_port.latency_offset
-                            )
-
-                        if current_input.latency_offset is None:
-                            raise ValueError(
-                                f"Input port {current_input.index} of operation"
-                                f" {current_input.operation.graph_id} has no"
-                                " latency-offset."
-                            )
-                        op_start_time_from_in = (
-                            source_end_time - current_input.latency_offset
-                        )
-                        op_start_time = max(op_start_time, op_start_time_from_in)
-
-                    schedule.start_times[operation.graph_id] = op_start_time
-
-        self._handle_outputs(schedule, non_schedulable_ops)
-        schedule.remove_delays()
-
-
-class ALAPScheduler(Scheduler):
-    """Scheduler that implements the as-late-as-possible (ALAP) algorithm."""
-
-    def apply_scheduling(self, schedule: "Schedule") -> None:
-        """Applies the scheduling algorithm on the given Schedule.
-
-        Parameters
-        ----------
-        schedule : Schedule
-            Schedule to apply the scheduling algorithm on.
-        """
-        ASAPScheduler().apply_scheduling(schedule)
-        max_end_time = schedule.get_max_end_time()
-
-        if schedule.schedule_time is None:
-            schedule.set_schedule_time(max_end_time)
-        elif schedule.schedule_time < max_end_time:
-            raise ValueError(f"Too short schedule time. Minimum is {max_end_time}.")
-
-        # move all outputs ALAP before operations
-        for output in schedule.sfg.find_by_type_name(Output.type_name()):
-            output = cast(Output, output)
-            schedule.move_operation_alap(output.graph_id)
-
-        # move all operations ALAP
-        for step in reversed(schedule.sfg.get_precedence_list()):
-            for outport in step:
-                if not isinstance(outport.operation, Delay):
-                    schedule.move_operation_alap(outport.operation.graph_id)
-
-
-class EarliestDeadlineScheduler(Scheduler):
-    """
-    Scheduler that implements the earliest-deadline-first algorithm.
-
-    Parameters
-    ----------
-    max_resources : dict, optional
-        Dictionary like ``{Addition.type_name(): 2}`` denoting the maximum number of
-        resources for a given operation type if the scheduling algorithm considers
-        that. If not provided, or an operation type is not provided, at most one
-        resource is used.
-    """
-
+class ListScheduler(Scheduler, ABC):
     def __init__(self, max_resources: Optional[dict[TypeName, int]] = None) -> None:
         if max_resources:
             self._max_resources = max_resources
@@ -173,97 +58,98 @@ class EarliestDeadlineScheduler(Scheduler):
         schedule : Schedule
             Schedule to apply the scheduling algorithm on.
         """
+        sfg = schedule.sfg
+        start_times = schedule.start_times
 
-        ALAPScheduler().apply_scheduling(schedule)
-
-        # move all inputs ASAP to ensure correct operation
-        for input_op in schedule.sfg.find_by_type_name(Input.type_name()):
-            input_op = cast(Input, input_op)
-            schedule.move_operation_asap(input_op.graph_id)
-
-        # construct the set of remaining operations, excluding inputs
-        remaining_ops = list(schedule.start_times.keys())
-        remaining_ops = [elem for elem in remaining_ops if not elem.startswith("in")]
-
-        # construct a dictionarry for storing how many times until a resource is available again
         used_resources_ready_times = {}
-
-        # iterate through all remaining operations and schedule them
-        # while not exceeding the available resources
         remaining_resources = self._max_resources.copy()
-        current_time = 0
-        while remaining_ops:
-            best_candidate = self._find_best_candidate(
-                schedule, remaining_ops, remaining_resources, current_time
-            )
+        sorted_operations = self._get_sorted_operations(schedule)
 
-            if not best_candidate:
-                current_time += 1
+        # place all inputs at time 0
+        for input_op in sfg.find_by_type_name(Input.type_name()):
+            start_times[input_op.graph_id] = 0
 
-                # update available operators
-                for operation, ready_time in used_resources_ready_times.items():
-                    if ready_time == current_time:
-                        remaining_resources[operation.type_name()] += 1
-                # remaining_resources = self._max_resources.copy()
-                continue
+        current_time = 0
+        while sorted_operations:
+
+            # generate the best schedulable candidate
+            candidate = sfg.find_by_id(sorted_operations[0])
+            counter = 0
+            while not self._candidate_is_schedulable(
+                start_times,
+                candidate,
+                current_time,
+                remaining_resources,
+                sorted_operations,
+            ):
+                if counter == len(sorted_operations):
+                    counter = 0
+                    current_time += 1
+                    # update available operators
+                    for operation, ready_time in used_resources_ready_times.items():
+                        if ready_time == current_time:
+                            remaining_resources[operation.type_name()] += 1
+                else:
+                    candidate = sfg.find_by_id(sorted_operations[counter])
+                    counter += 1
 
             # if the resource is constrained, update remaining resources
-            if best_candidate.type_name() in remaining_resources:
-                remaining_resources[best_candidate.type_name()] -= 1
-                if best_candidate.execution_time:
-                    used_resources_ready_times[best_candidate] = (
-                        current_time + best_candidate.execution_time
+            if candidate.type_name() in remaining_resources:
+                remaining_resources[candidate.type_name()] -= 1
+                if candidate.execution_time:
+                    used_resources_ready_times[candidate] = (
+                        current_time + candidate.execution_time
                     )
                 else:
-                    used_resources_ready_times[best_candidate] = (
-                        current_time + best_candidate.latency
+                    used_resources_ready_times[candidate] = (
+                        current_time + candidate.latency
                     )
 
             # schedule the best candidate to the current time
-            remaining_ops.remove(best_candidate.graph_id)
-            schedule.start_times[best_candidate.graph_id] = current_time
+            sorted_operations.remove(candidate.graph_id)
+            start_times[candidate.graph_id] = current_time
+
+        schedule.set_schedule_time(current_time)
+
+        self._handle_outputs(schedule)
+        schedule.remove_delays()
 
         # move all inputs and outputs ALAP now that operations have moved
         for input_op in schedule.sfg.find_by_type_name(Input.type_name()):
             input_op = cast(Input, input_op)
             schedule.move_operation_alap(input_op.graph_id)
-        self._handle_outputs(schedule)
 
     @staticmethod
-    def _find_best_candidate(
-        schedule, remaining_ops, remaining_resources, current_time
-    ):
-        sfg = schedule.sfg
-        source_end_times = defaultdict(float)
+    def _candidate_is_schedulable(
+        start_times: dict["GraphID"],
+        operation: "Operation",
+        current_time: int,
+        remaining_resources: dict["GraphID", int],
+        remaining_ops: list["GraphID"],
+    ) -> bool:
+        if (
+            operation.type_name() in remaining_resources
+            and remaining_resources[operation.type_name()] == 0
+        ):
+            return False
+
+        earliest_start_time = 0
+        for op_input in operation.inputs:
+            source_op = op_input.signals[0].source.operation
+            source_op_graph_id = source_op.graph_id
+
+            if source_op_graph_id in remaining_ops:
+                return False
+
+            proceeding_op_start_time = start_times.get(source_op_graph_id)
+
+            if not isinstance(source_op, Delay):
+                earliest_start_time = max(
+                    earliest_start_time, proceeding_op_start_time + source_op.latency
+                )
+
+        return earliest_start_time <= current_time
 
-        # find the best candidate
-        best_candidate = None
-        best_deadline = float('inf')
-        for op_id in remaining_ops:
-            operation = sfg.find_by_id(op_id)
-
-            # compute maximum end times of preceding operations
-            for op_input in operation.inputs:
-                source_op = op_input.signals[0].source.operation
-                if not isinstance(source_op, Delay):
-                    source_end_times[op_id] = max(
-                        source_end_times[op_id],
-                        schedule.start_times[source_op.graph_id] + source_op.latency,
-                    )
-                    # ensure that the source is already scheduled
-                    if source_op.graph_id in remaining_ops:
-                        source_end_times[op_id] = sys.maxsize
-
-            # check resource constraints
-            if operation.type_name() in remaining_resources:
-                if remaining_resources[operation.type_name()] == 0:
-                    continue
-
-            # check if all inputs are available
-            if source_end_times[op_id] <= current_time:
-                operation_deadline = schedule.start_times[op_id] + operation.latency
-                if operation_deadline < best_deadline:
-                    best_candidate = operation
-                    best_deadline = operation_deadline
-
-        return best_candidate
+    @abstractmethod
+    def _get_sorted_operations(schedule: "Schedule") -> list["GraphID"]:
+        raise NotImplementedError
diff --git a/b_asic/signal_flow_graph.py b/b_asic/signal_flow_graph.py
index db482e57c93b482ed3990a8b61a219441a676e0c..74f5698fc4bd9ca1720afa65a74a1752cd7a9f6e 100644
--- a/b_asic/signal_flow_graph.py
+++ b/b_asic/signal_flow_graph.py
@@ -29,6 +29,7 @@ from typing import (
 import numpy as np
 from graphviz import Digraph
 
+from b_asic.core_schedulers import ASAPScheduler
 from b_asic.graph_component import GraphComponent
 from b_asic.operation import (
     AbstractOperation,
@@ -38,7 +39,6 @@ from b_asic.operation import (
     ResultKey,
 )
 from b_asic.port import InputPort, OutputPort, SignalSourceProvider
-from b_asic.scheduler import ASAPScheduler
 from b_asic.signal import Signal
 from b_asic.special_operations import Delay, Input, Output
 from b_asic.types import GraphID, GraphIDNumber, Name, Num, TypeName
diff --git a/examples/fivepointwinograddft.py b/examples/fivepointwinograddft.py
index d21561511d5fafa2c9249adf4ffac5e939e91cd4..856dcb6c453ae9ba008fe1ecfdfb65ece1b47a6c 100644
--- a/examples/fivepointwinograddft.py
+++ b/examples/fivepointwinograddft.py
@@ -13,8 +13,8 @@ import networkx as nx
 
 from b_asic.architecture import Architecture, Memory, ProcessingElement
 from b_asic.core_operations import AddSub, Butterfly, ConstantMultiplication
+from b_asic.core_schedulers import ASAPScheduler
 from b_asic.schedule import Schedule
-from b_asic.scheduler import ASAPScheduler
 from b_asic.signal_flow_graph import SFG
 from b_asic.special_operations import Input, Output
 
diff --git a/examples/folding_example_with_architecture.py b/examples/folding_example_with_architecture.py
index 43bdc798e0a24fcd0ce8a10e66cc27c412b0acea..66e40299ef02c31830f14907cf133f09ade5dd16 100644
--- a/examples/folding_example_with_architecture.py
+++ b/examples/folding_example_with_architecture.py
@@ -16,8 +16,8 @@ shorter than the scheduling period.
 
 from b_asic.architecture import Architecture, Memory, ProcessingElement
 from b_asic.core_operations import Addition, ConstantMultiplication
+from b_asic.core_schedulers import ASAPScheduler
 from b_asic.schedule import Schedule
-from b_asic.scheduler import ASAPScheduler
 from b_asic.signal_flow_graph import SFG
 from b_asic.special_operations import Delay, Input, Output
 
diff --git a/examples/lwdfallpass.py b/examples/lwdfallpass.py
index 6bbde6291eca6404efb3a5df66e28633b3ea0a91..7eb78ca7e3024e69848d762025475345e904a113 100644
--- a/examples/lwdfallpass.py
+++ b/examples/lwdfallpass.py
@@ -8,8 +8,8 @@ This has different latency offsets for the different inputs/outputs.
 """
 
 from b_asic.core_operations import SymmetricTwoportAdaptor
+from b_asic.core_schedulers import ASAPScheduler
 from b_asic.schedule import Schedule
-from b_asic.scheduler import ASAPScheduler
 from b_asic.signal_flow_graph import SFG
 from b_asic.special_operations import Delay, Input, Output
 
diff --git a/examples/secondorderdirectformiir.py b/examples/secondorderdirectformiir.py
index aa84c26b532b0304fd012805bb88b1719723e9a7..772d8fb826850c83b75863c442ca8cc3cbdb4179 100644
--- a/examples/secondorderdirectformiir.py
+++ b/examples/secondorderdirectformiir.py
@@ -6,8 +6,8 @@ Second-order IIR Filter with Schedule
 """
 
 from b_asic.core_operations import Addition, ConstantMultiplication
+from b_asic.core_schedulers import ASAPScheduler
 from b_asic.schedule import Schedule
-from b_asic.scheduler import ASAPScheduler
 from b_asic.signal_flow_graph import SFG
 from b_asic.special_operations import Delay, Input, Output
 
diff --git a/examples/secondorderdirectformiir_architecture.py b/examples/secondorderdirectformiir_architecture.py
index a7d72fb36fa631c7a39395597351a9b4c1674930..2147961ffe10ec52e4dcdaad3a9e6d322e3d0c1b 100644
--- a/examples/secondorderdirectformiir_architecture.py
+++ b/examples/secondorderdirectformiir_architecture.py
@@ -7,8 +7,8 @@ Second-order IIR Filter with Architecture
 
 from b_asic.architecture import Architecture, Memory, ProcessingElement
 from b_asic.core_operations import Addition, ConstantMultiplication
+from b_asic.core_schedulers import ASAPScheduler
 from b_asic.schedule import Schedule
-from b_asic.scheduler import ASAPScheduler
 from b_asic.signal_flow_graph import SFG
 from b_asic.special_operations import Delay, Input, Output
 
diff --git a/examples/thirdorderblwdf.py b/examples/thirdorderblwdf.py
index d29fd21566982464ffae9107ba64e79eccf79fce..0b81573104a1a35c14828dda4f45cbf3cb161be8 100644
--- a/examples/thirdorderblwdf.py
+++ b/examples/thirdorderblwdf.py
@@ -10,8 +10,8 @@ import numpy as np
 from mplsignal.freq_plots import freqz_fir
 
 from b_asic.core_operations import Addition, SymmetricTwoportAdaptor
+from b_asic.core_schedulers import ASAPScheduler
 from b_asic.schedule import Schedule
-from b_asic.scheduler import ASAPScheduler
 from b_asic.signal_flow_graph import SFG
 from b_asic.signal_generator import Impulse
 from b_asic.simulation import Simulation
diff --git a/examples/threepointwinograddft.py b/examples/threepointwinograddft.py
index 7e7a58acd5465969142aa85f95883998b0a74689..5dc962e645967e40f77d8c63aecec137d2ee9d39 100644
--- a/examples/threepointwinograddft.py
+++ b/examples/threepointwinograddft.py
@@ -11,8 +11,8 @@ import networkx as nx
 
 from b_asic.architecture import Architecture, Memory, ProcessingElement
 from b_asic.core_operations import AddSub, ConstantMultiplication
+from b_asic.core_schedulers import ASAPScheduler
 from b_asic.schedule import Schedule
-from b_asic.scheduler import ASAPScheduler
 from b_asic.signal_flow_graph import SFG
 from b_asic.special_operations import Input, Output
 
diff --git a/test/fixtures/schedule.py b/test/fixtures/schedule.py
index 39b375ed12eaae2a350ad9f38d1d8dd0273093d3..b5e9d0fbf910cdb153552dc9bfbcf613b6266201 100644
--- a/test/fixtures/schedule.py
+++ b/test/fixtures/schedule.py
@@ -1,8 +1,8 @@
 import pytest
 
 from b_asic.core_operations import Addition, ConstantMultiplication
+from b_asic.core_schedulers import ASAPScheduler
 from b_asic.schedule import Schedule
-from b_asic.scheduler import ASAPScheduler
 from b_asic.signal_flow_graph import SFG
 
 
diff --git a/test/test_architecture.py b/test/test_architecture.py
index 2ab9c539c6e3985e50829a0a4068eb89cfeec459..6b72bbdcbe952a5cbe6a93e1dded67ac029349fd 100644
--- a/test/test_architecture.py
+++ b/test/test_architecture.py
@@ -6,10 +6,10 @@ import pytest
 
 from b_asic.architecture import Architecture, Memory, ProcessingElement
 from b_asic.core_operations import Addition, ConstantMultiplication
+from b_asic.core_schedulers import ASAPScheduler
 from b_asic.process import PlainMemoryVariable
 from b_asic.resources import ProcessCollection
 from b_asic.schedule import Schedule
-from b_asic.scheduler import ASAPScheduler
 from b_asic.special_operations import Input, Output
 
 
diff --git a/test/test_scheduler.py b/test/test_core_schedulers.py
similarity index 51%
rename from test/test_scheduler.py
rename to test/test_core_schedulers.py
index 0959b2cb3fd81422d0de97531c3c004828e6f66e..147d230d2da5bb840e4262315544a94f4b4b5c3c 100644
--- a/test/test_scheduler.py
+++ b/test/test_core_schedulers.py
@@ -1,8 +1,13 @@
 import pytest
 
-from b_asic.core_operations import Addition, ConstantMultiplication
+from b_asic.core_operations import Addition, Butterfly, ConstantMultiplication
+from b_asic.core_schedulers import (
+    ALAPScheduler,
+    ASAPScheduler,
+    EarliestDeadlineScheduler,
+)
 from b_asic.schedule import Schedule
-from b_asic.scheduler import ALAPScheduler, ASAPScheduler, EarliestDeadlineScheduler
+from b_asic.sfg_generators import direct_form_1_iir, radix_2_dif_fft
 
 
 class TestASAPScheduler:
@@ -12,6 +17,31 @@ class TestASAPScheduler:
         ):
             Schedule(sfg_empty, scheduler=ASAPScheduler())
 
+    def test_direct_form_1_iir(self):
+        sfg = direct_form_1_iir([1, 2, 3], [4, 5, 6])
+
+        sfg.set_latency_of_type(ConstantMultiplication.type_name(), 2)
+        sfg.set_execution_time_of_type(ConstantMultiplication.type_name(), 1)
+        sfg.set_latency_of_type(Addition.type_name(), 3)
+        sfg.set_execution_time_of_type(Addition.type_name(), 1)
+
+        schedule = Schedule(sfg, scheduler=ASAPScheduler())
+
+        assert schedule.start_times == {
+            "in0": 0,
+            "cmul0": 0,
+            "cmul1": 0,
+            "cmul2": 0,
+            "cmul3": 0,
+            "cmul4": 0,
+            "add3": 2,
+            "add1": 2,
+            "add0": 5,
+            "add2": 8,
+            "out0": 11,
+        }
+        assert schedule.schedule_time == 11
+
     def test_direct_form_2_iir(self, sfg_direct_form_iir_lp_filter):
         sfg_direct_form_iir_lp_filter.set_latency_of_type(Addition.type_name(), 5)
         sfg_direct_form_iir_lp_filter.set_latency_of_type(
@@ -20,7 +50,7 @@ class TestASAPScheduler:
 
         schedule = Schedule(sfg_direct_form_iir_lp_filter, scheduler=ASAPScheduler())
 
-        assert schedule._start_times == {
+        assert schedule.start_times == {
             "in0": 0,
             "cmul1": 0,
             "cmul4": 0,
@@ -47,7 +77,7 @@ class TestASAPScheduler:
             sfg_direct_form_iir_lp_filter, scheduler=ASAPScheduler(), schedule_time=30
         )
 
-        assert schedule._start_times == {
+        assert schedule.start_times == {
             "in0": 0,
             "cmul1": 0,
             "cmul4": 0,
@@ -62,6 +92,53 @@ class TestASAPScheduler:
         }
         assert schedule.schedule_time == 30
 
+    def test_radix_2_fft_8_points(self):
+        sfg = radix_2_dif_fft(points=8)
+
+        sfg.set_latency_of_type(ConstantMultiplication.type_name(), 2)
+        sfg.set_execution_time_of_type(ConstantMultiplication.type_name(), 1)
+        sfg.set_latency_of_type(Butterfly.type_name(), 1)
+        sfg.set_execution_time_of_type(Butterfly.type_name(), 1)
+
+        schedule = Schedule(sfg, scheduler=ASAPScheduler())
+
+        assert schedule.start_times == {
+            "in0": 0,
+            "in1": 0,
+            "in2": 0,
+            "in3": 0,
+            "in4": 0,
+            "in5": 0,
+            "in6": 0,
+            "in7": 0,
+            "bfly0": 0,
+            "bfly6": 0,
+            "bfly8": 0,
+            "bfly11": 0,
+            "cmul3": 1,
+            "bfly7": 1,
+            "cmul2": 1,
+            "bfly1": 1,
+            "cmul0": 1,
+            "cmul4": 2,
+            "bfly9": 2,
+            "bfly5": 3,
+            "bfly2": 3,
+            "out0": 3,
+            "out4": 3,
+            "bfly10": 4,
+            "cmul1": 4,
+            "bfly3": 4,
+            "out1": 5,
+            "out2": 5,
+            "out5": 5,
+            "out6": 5,
+            "bfly4": 6,
+            "out3": 7,
+            "out7": 7,
+        }
+        assert schedule.schedule_time == 7
+
 
 class TestALAPScheduler:
     def test_empty_sfg(self, sfg_empty):
@@ -70,6 +147,31 @@ class TestALAPScheduler:
         ):
             Schedule(sfg_empty, scheduler=ALAPScheduler())
 
+    def test_direct_form_1_iir(self):
+        sfg = direct_form_1_iir([1, 2, 3], [4, 5, 6])
+
+        sfg.set_latency_of_type(ConstantMultiplication.type_name(), 2)
+        sfg.set_execution_time_of_type(ConstantMultiplication.type_name(), 1)
+        sfg.set_latency_of_type(Addition.type_name(), 3)
+        sfg.set_execution_time_of_type(Addition.type_name(), 1)
+
+        schedule = Schedule(sfg, scheduler=ALAPScheduler())
+
+        assert schedule.start_times == {
+            "cmul3": 0,
+            "cmul4": 0,
+            "add1": 2,
+            "in0": 3,
+            "cmul0": 3,
+            "cmul1": 3,
+            "cmul2": 3,
+            "add3": 5,
+            "add0": 5,
+            "add2": 8,
+            "out0": 11,
+        }
+        assert schedule.schedule_time == 11
+
     def test_direct_form_2_iir(self, sfg_direct_form_iir_lp_filter):
         sfg_direct_form_iir_lp_filter.set_latency_of_type(Addition.type_name(), 5)
         sfg_direct_form_iir_lp_filter.set_latency_of_type(
@@ -78,7 +180,7 @@ class TestALAPScheduler:
 
         schedule = Schedule(sfg_direct_form_iir_lp_filter, scheduler=ALAPScheduler())
 
-        assert schedule._start_times == {
+        assert schedule.start_times == {
             "cmul3": 0,
             "cmul4": 0,
             "add1": 4,
@@ -105,7 +207,7 @@ class TestALAPScheduler:
             sfg_direct_form_iir_lp_filter, scheduler=ALAPScheduler(), schedule_time=30
         )
 
-        assert schedule._start_times == {
+        assert schedule.start_times == {
             "cmul3": 7,
             "cmul4": 7,
             "add1": 11,
@@ -120,6 +222,53 @@ class TestALAPScheduler:
         }
         assert schedule.schedule_time == 30
 
+    def test_radix_2_fft_8_points(self):
+        sfg = radix_2_dif_fft(points=8)
+
+        sfg.set_latency_of_type(ConstantMultiplication.type_name(), 2)
+        sfg.set_execution_time_of_type(ConstantMultiplication.type_name(), 1)
+        sfg.set_latency_of_type(Butterfly.type_name(), 1)
+        sfg.set_execution_time_of_type(Butterfly.type_name(), 1)
+
+        schedule = Schedule(sfg, scheduler=ALAPScheduler())
+
+        assert schedule.start_times == {
+            "in3": 0,
+            "in7": 0,
+            "in1": 0,
+            "in5": 0,
+            "bfly6": 0,
+            "bfly8": 0,
+            "cmul2": 1,
+            "cmul3": 1,
+            "in2": 2,
+            "in6": 2,
+            "bfly11": 2,
+            "bfly7": 3,
+            "cmul0": 3,
+            "bfly5": 3,
+            "in0": 4,
+            "in4": 4,
+            "cmul4": 4,
+            "cmul1": 4,
+            "bfly0": 4,
+            "bfly1": 5,
+            "bfly2": 5,
+            "bfly9": 6,
+            "bfly10": 6,
+            "bfly3": 6,
+            "bfly4": 6,
+            "out0": 7,
+            "out1": 7,
+            "out2": 7,
+            "out3": 7,
+            "out4": 7,
+            "out5": 7,
+            "out6": 7,
+            "out7": 7,
+        }
+        assert schedule.schedule_time == 7
+
 
 class TestEarliestDeadlineScheduler:
     def test_empty_sfg(self, sfg_empty):
@@ -128,6 +277,34 @@ class TestEarliestDeadlineScheduler:
         ):
             Schedule(sfg_empty, scheduler=EarliestDeadlineScheduler())
 
+    def test_direct_form_1_iir(self):
+        sfg = direct_form_1_iir([1, 2, 3], [4, 5, 6])
+
+        sfg.set_latency_of_type(ConstantMultiplication.type_name(), 2)
+        sfg.set_execution_time_of_type(ConstantMultiplication.type_name(), 1)
+        sfg.set_latency_of_type(Addition.type_name(), 3)
+        sfg.set_execution_time_of_type(Addition.type_name(), 1)
+
+        resources = {Addition.type_name(): 1, ConstantMultiplication.type_name(): 1}
+        schedule = Schedule(
+            sfg, scheduler=EarliestDeadlineScheduler(max_resources=resources)
+        )
+
+        assert schedule.start_times == {
+            "cmul4": 0,
+            "cmul3": 1,
+            "in0": 2,
+            "cmul0": 2,
+            "add1": 3,
+            "cmul1": 3,
+            "cmul2": 4,
+            "add3": 6,
+            "add0": 7,
+            "add2": 10,
+            "out0": 13,
+        }
+        assert schedule.schedule_time == 13
+
     def test_direct_form_2_iir_inf_resources_no_exec_time(
         self, sfg_direct_form_iir_lp_filter
     ):
@@ -141,7 +318,7 @@ class TestEarliestDeadlineScheduler:
         )
 
         # should be the same as for ASAP due to infinite resources, except for input
-        assert schedule._start_times == {
+        assert schedule.start_times == {
             "in0": 9,
             "cmul1": 0,
             "cmul4": 0,
@@ -170,7 +347,7 @@ class TestEarliestDeadlineScheduler:
             sfg_direct_form_iir_lp_filter,
             scheduler=EarliestDeadlineScheduler(max_resources),
         )
-        assert schedule._start_times == {
+        assert schedule.start_times == {
             "cmul4": 0,
             "cmul3": 4,
             "cmul1": 8,
@@ -206,7 +383,7 @@ class TestEarliestDeadlineScheduler:
             sfg_direct_form_iir_lp_filter,
             scheduler=EarliestDeadlineScheduler(max_resources),
         )
-        assert schedule._start_times == {
+        assert schedule.start_times == {
             "cmul4": 0,
             "cmul3": 1,
             "cmul1": 2,
@@ -242,7 +419,7 @@ class TestEarliestDeadlineScheduler:
             sfg_direct_form_iir_lp_filter,
             scheduler=EarliestDeadlineScheduler(max_resources),
         )
-        assert schedule._start_times == {
+        assert schedule.start_times == {
             "cmul1": 0,
             "cmul4": 0,
             "cmul3": 0,
@@ -257,3 +434,53 @@ class TestEarliestDeadlineScheduler:
         }
 
         assert schedule.schedule_time == 12
+
+    def test_radix_2_fft_8_points(self):
+        sfg = radix_2_dif_fft(points=8)
+
+        sfg.set_latency_of_type(ConstantMultiplication.type_name(), 2)
+        sfg.set_execution_time_of_type(ConstantMultiplication.type_name(), 1)
+        sfg.set_latency_of_type(Butterfly.type_name(), 1)
+        sfg.set_execution_time_of_type(Butterfly.type_name(), 1)
+
+        resources = {Butterfly.type_name(): 2, ConstantMultiplication.type_name(): 2}
+        schedule = Schedule(
+            sfg, scheduler=EarliestDeadlineScheduler(max_resources=resources)
+        )
+
+        assert schedule.start_times == {
+            "in1": 0,
+            "in3": 0,
+            "in5": 0,
+            "in7": 0,
+            "bfly6": 0,
+            "bfly8": 0,
+            "in2": 1,
+            "in6": 1,
+            "cmul2": 1,
+            "cmul3": 1,
+            "bfly11": 1,
+            "bfly7": 1,
+            "in0": 2,
+            "in4": 2,
+            "cmul0": 2,
+            "bfly0": 2,
+            "cmul4": 2,
+            "bfly5": 3,
+            "bfly1": 3,
+            "cmul1": 4,
+            "bfly2": 4,
+            "bfly9": 4,
+            "bfly10": 5,
+            "bfly3": 5,
+            "out0": 5,
+            "out4": 5,
+            "bfly4": 6,
+            "out1": 6,
+            "out2": 6,
+            "out5": 6,
+            "out6": 6,
+            "out7": 7,
+            "out3": 7,
+        }
+        assert schedule.schedule_time == 7
diff --git a/test/test_schedule.py b/test/test_schedule.py
index bbd98c3622e99526a59663dd08394997de2d57d1..456d53f470bf87296aae5f50731f673cfe4882e0 100644
--- a/test/test_schedule.py
+++ b/test/test_schedule.py
@@ -8,9 +8,9 @@ import matplotlib.testing.decorators
 import pytest
 
 from b_asic.core_operations import Addition, Butterfly, ConstantMultiplication
+from b_asic.core_schedulers import ALAPScheduler, ASAPScheduler
 from b_asic.process import OperatorProcess
 from b_asic.schedule import Schedule
-from b_asic.scheduler import ALAPScheduler, ASAPScheduler
 from b_asic.sfg_generators import direct_form_fir
 from b_asic.signal_flow_graph import SFG
 from b_asic.special_operations import Delay, Input, Output
diff --git a/test/test_scheduler_gui.py b/test/test_scheduler_gui.py
index 02e9d36e475d32c2db5d8a37a22c9e828c2b8ddf..99e8485002139c2aa2fd0a09f9121e88078fb220 100644
--- a/test/test_scheduler_gui.py
+++ b/test/test_scheduler_gui.py
@@ -1,8 +1,8 @@
 import pytest
 
 from b_asic.core_operations import Addition, ConstantMultiplication
+from b_asic.core_schedulers import ASAPScheduler
 from b_asic.schedule import Schedule
-from b_asic.scheduler import ASAPScheduler
 
 try:
     from b_asic.scheduler_gui.main_window import ScheduleMainWindow