diff --git a/b_asic/schedule.py b/b_asic/schedule.py
index a4655e076b73193af06817cb75cdb3116bc520b5..c80466a29f1bfe2070f72f35009c8559c81c4e0d 100644
--- a/b_asic/schedule.py
+++ b/b_asic/schedule.py
@@ -72,15 +72,22 @@ class Schedule:
         algorithm.
     cyclic : bool, default: False
         If the schedule is cyclic.
-    scheduling_algorithm : {'ASAP', 'provided'}, optional
-        The scheduling algorithm to use. Currently, only "ASAP" is supported.
+    algorithm : {'ASAP', 'ALAP', 'provided'}, optional
+        The scheduling algorithm to use. The following algorithm are available:
+           * ``'ASAP'``: As-soon-as-possible scheduling.
+           * ``'ALAP'``: As-late-as-possible scheduling.
         If 'provided', use provided *start_times*  and *laps* dictionaries.
     start_times : dict, optional
         Dictionary with GraphIDs as keys and start times as values.
-        Used when *scheduling_algorithm* is 'provided'.
+        Used when *algorithm* is 'provided'.
     laps : dict, optional
         Dictionary with GraphIDs as keys and laps as values.
-        Used when *scheduling_algorithm* is 'provided'.
+        Used when *algorithm* is 'provided'.
+    max_resources : dict, optional
+        Dictionary like ``{'cmul': 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.
     """
 
     _sfg: SFG
@@ -95,9 +102,10 @@ class Schedule:
         sfg: SFG,
         schedule_time: Optional[int] = None,
         cyclic: bool = False,
-        scheduling_algorithm: str = "ASAP",
+        algorithm: str = "ASAP",
         start_times: Optional[Dict[GraphID, int]] = None,
         laps: Optional[Dict[GraphID, int]] = None,
+        max_resources: Optional[Dict[TypeName, int]] = None,
     ):
         """Construct a Schedule from an SFG."""
         if not isinstance(sfg, SFG):
@@ -109,9 +117,12 @@ class Schedule:
         self._laps = defaultdict(_laps_default)
         self._cyclic = cyclic
         self._y_locations = defaultdict(_y_locations_default)
-        if scheduling_algorithm == "ASAP":
+        self._schedule_time = schedule_time
+        if algorithm == "ASAP":
             self._schedule_asap()
-        elif scheduling_algorithm == "provided":
+        elif algorithm == "ALAP":
+            self._schedule_alap()
+        elif algorithm == "provided":
             if start_times is None:
                 raise ValueError("Must provide start_times when using 'provided'")
             if laps is None:
@@ -120,9 +131,7 @@ class Schedule:
             self._laps.update(laps)
             self._remove_delays_no_laps()
         else:
-            raise NotImplementedError(
-                f"No algorithm with name: {scheduling_algorithm} defined."
-            )
+            raise NotImplementedError(f"No algorithm with name: {algorithm} defined.")
 
         max_end_time = self.get_max_end_time()
 
@@ -130,8 +139,6 @@ class Schedule:
             self._schedule_time = max_end_time
         elif schedule_time < max_end_time:
             raise ValueError(f"Too short schedule time. Minimum is {max_end_time}.")
-        else:
-            self._schedule_time = schedule_time
 
     def start_time_of_operation(self, graph_id: GraphID) -> int:
         """
@@ -636,10 +643,24 @@ class Schedule:
                 # schedule period
                 if new_available == 0 and (new_slack > 0 or next_usage == 0):
                     new_available = self._schedule_time
-                if next_usage < new_available:
+                if (
+                    next_usage < new_available
+                    and self._start_times[signal.destination_operation.graph_id]
+                    != self.schedule_time
+                ):
                     laps += 1
                 self._laps[signal.graph_id] = laps
 
+        # Outputs should not start at 0, but at schedule time
+        op = self._sfg.find_by_id(graph_id)
+        if (
+            new_start == 0
+            and isinstance(op, Output)
+            and self._laps[op.input(0).signals[0].graph_id] != 0
+        ):
+            new_start = self._schedule_time
+            self._laps[op.input(0).signals[0].graph_id] -= 1
+            print(f"Moved {graph_id}")
         # Set new start time
         self._start_times[graph_id] = new_start
         return self
@@ -715,6 +736,29 @@ class Schedule:
             del self._laps[delay_input_id]
             delay_list = self._sfg.find_by_type_name(Delay.type_name())
 
+    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()
diff --git a/b_asic/signal_flow_graph.py b/b_asic/signal_flow_graph.py
index 7bcb273ea369611eec98e3568c59b8f18efb7518..464513bbc2f6b67f1cf2ccdbfe4511518a395095 100644
--- a/b_asic/signal_flow_graph.py
+++ b/b_asic/signal_flow_graph.py
@@ -1548,7 +1548,7 @@ class SFG(AbstractOperation):
         # Import here needed to avoid circular imports
         from b_asic.schedule import Schedule
 
-        return Schedule(self, scheduling_algorithm="ASAP").schedule_time
+        return Schedule(self, algorithm="ASAP").schedule_time
 
     def iteration_period_bound(self) -> int:
         """
diff --git a/test/fixtures/schedule.py b/test/fixtures/schedule.py
index 4091bd4047750996e84b87af3c7dcae0ab1ab51d..f6ec65bf677825bdb06b61aa426ba3f893c315a1 100644
--- a/test/fixtures/schedule.py
+++ b/test/fixtures/schedule.py
@@ -10,7 +10,7 @@ def secondorder_iir_schedule(precedence_sfg_delays):
     precedence_sfg_delays.set_latency_of_type(Addition.type_name(), 4)
     precedence_sfg_delays.set_latency_of_type(ConstantMultiplication.type_name(), 3)
 
-    schedule = Schedule(precedence_sfg_delays, scheduling_algorithm="ASAP")
+    schedule = Schedule(precedence_sfg_delays, algorithm="ASAP")
     return schedule
 
 
@@ -23,7 +23,7 @@ def secondorder_iir_schedule_with_execution_times(precedence_sfg_delays):
         ConstantMultiplication.type_name(), 1
     )
 
-    schedule = Schedule(precedence_sfg_delays, scheduling_algorithm="ASAP")
+    schedule = Schedule(precedence_sfg_delays, algorithm="ASAP")
     return schedule
 
 
@@ -37,9 +37,7 @@ def schedule_direct_form_iir_lp_filter(sfg_direct_form_iir_lp_filter: SFG):
     sfg_direct_form_iir_lp_filter.set_execution_time_of_type(
         ConstantMultiplication.type_name(), 1
     )
-    schedule = Schedule(
-        sfg_direct_form_iir_lp_filter, scheduling_algorithm="ASAP", cyclic=True
-    )
+    schedule = Schedule(sfg_direct_form_iir_lp_filter, algorithm="ASAP", cyclic=True)
     schedule.move_operation('cmul4', -1)
     schedule.move_operation('cmul3', -1)
     schedule.move_operation('cmul4', -10)
diff --git a/test/test_schedule.py b/test/test_schedule.py
index e5fc64b375ee55da016372bbffc8a4261ee3b09c..14ba916a9dd0d7baba24eafb6c870d6bdaba7c7f 100644
--- a/test/test_schedule.py
+++ b/test/test_schedule.py
@@ -31,7 +31,7 @@ class TestInit:
         precedence_sfg_delays.set_latency_of_type(Addition.type_name(), 4)
         precedence_sfg_delays.set_latency_of_type(ConstantMultiplication.type_name(), 3)
 
-        schedule = Schedule(precedence_sfg_delays, scheduling_algorithm="ASAP")
+        schedule = Schedule(precedence_sfg_delays, algorithm="ASAP")
 
         for op in schedule._sfg.get_operations_topological_order():
             print(op.latency_offsets)
@@ -58,6 +58,39 @@ class TestInit:
         }
         assert schedule.schedule_time == 21
 
+    def test_complicated_single_outputs_normal_latency_alap(
+        self, precedence_sfg_delays
+    ):
+        precedence_sfg_delays.set_latency_of_type(Addition.type_name(), 4)
+        precedence_sfg_delays.set_latency_of_type(ConstantMultiplication.type_name(), 3)
+
+        schedule = Schedule(precedence_sfg_delays, algorithm="ALAP")
+
+        for op in schedule._sfg.get_operations_topological_order():
+            print(op.latency_offsets)
+
+        start_times_names = {}
+        for op_id, start_time in schedule._start_times.items():
+            op_name = precedence_sfg_delays.find_by_id(op_id).name
+            start_times_names[op_name] = start_time
+
+        assert start_times_names == {
+            "IN1": 4,
+            "C0": 4,
+            "B1": 0,
+            "B2": 0,
+            "ADD2": 3,
+            "ADD1": 7,
+            "Q1": 11,
+            "A0": 14,
+            "A1": 10,
+            "A2": 10,
+            "ADD3": 13,
+            "ADD4": 17,
+            "OUT1": 21,
+        }
+        assert schedule.schedule_time == 21
+
     def test_complicated_single_outputs_normal_latency_from_fixture(
         self, secondorder_iir_schedule
     ):
@@ -120,7 +153,7 @@ class TestInit:
             {"in0": 6, "in1": 7, "out0": 9}
         )
 
-        schedule = Schedule(precedence_sfg_delays, scheduling_algorithm="ASAP")
+        schedule = Schedule(precedence_sfg_delays, algorithm="ASAP")
 
         start_times_names = {}
         for op_id, start_time in schedule._start_times.items():
@@ -148,7 +181,7 @@ class TestInit:
     def test_independent_sfg(self, sfg_two_inputs_two_outputs_independent_with_cmul):
         schedule = Schedule(
             sfg_two_inputs_two_outputs_independent_with_cmul,
-            scheduling_algorithm="ASAP",
+            algorithm="ASAP",
         )
 
         start_times_names = {}
@@ -177,7 +210,7 @@ class TestSlacks:
         precedence_sfg_delays.set_latency_of_type(Addition.type_name(), 1)
         precedence_sfg_delays.set_latency_of_type(ConstantMultiplication.type_name(), 3)
 
-        schedule = Schedule(precedence_sfg_delays, scheduling_algorithm="ASAP")
+        schedule = Schedule(precedence_sfg_delays, algorithm="ASAP")
         assert (
             schedule.forward_slack(
                 precedence_sfg_delays.find_by_name("ADD3")[0].graph_id
@@ -206,7 +239,7 @@ class TestSlacks:
         precedence_sfg_delays.set_latency_of_type(Addition.type_name(), 1)
         precedence_sfg_delays.set_latency_of_type(ConstantMultiplication.type_name(), 3)
 
-        schedule = Schedule(precedence_sfg_delays, scheduling_algorithm="ASAP")
+        schedule = Schedule(precedence_sfg_delays, algorithm="ASAP")
         assert schedule.slacks(
             precedence_sfg_delays.find_by_name("ADD3")[0].graph_id
         ) == (0, 7)
@@ -220,7 +253,7 @@ class TestRescheduling:
         precedence_sfg_delays.set_latency_of_type(Addition.type_name(), 4)
         precedence_sfg_delays.set_latency_of_type(ConstantMultiplication.type_name(), 3)
 
-        schedule = Schedule(precedence_sfg_delays, scheduling_algorithm="ASAP")
+        schedule = Schedule(precedence_sfg_delays, algorithm="ASAP")
 
         schedule.move_operation(
             precedence_sfg_delays.find_by_name("ADD3")[0].graph_id, 4
@@ -252,7 +285,7 @@ class TestRescheduling:
         precedence_sfg_delays.set_latency_of_type(Addition.type_name(), 1)
         precedence_sfg_delays.set_latency_of_type(ConstantMultiplication.type_name(), 3)
 
-        schedule = Schedule(precedence_sfg_delays, scheduling_algorithm="ASAP")
+        schedule = Schedule(precedence_sfg_delays, algorithm="ASAP")
         add3_id = precedence_sfg_delays.find_by_name("ADD3")[0].graph_id
         schedule.move_operation(add3_id, 4)
         assert schedule.forward_slack(add3_id) == 3
@@ -274,7 +307,7 @@ class TestRescheduling:
         precedence_sfg_delays.set_latency_of_type(Addition.type_name(), 1)
         precedence_sfg_delays.set_latency_of_type(ConstantMultiplication.type_name(), 3)
 
-        schedule = Schedule(precedence_sfg_delays, scheduling_algorithm="ASAP")
+        schedule = Schedule(precedence_sfg_delays, algorithm="ASAP")
         with pytest.raises(
             ValueError,
             match="Operation add4 got incorrect move: -4. Must be between 0 and 7.",
@@ -287,7 +320,7 @@ class TestRescheduling:
         precedence_sfg_delays.set_latency_of_type(Addition.type_name(), 1)
         precedence_sfg_delays.set_latency_of_type(ConstantMultiplication.type_name(), 3)
 
-        schedule = Schedule(precedence_sfg_delays, scheduling_algorithm="ASAP")
+        schedule = Schedule(precedence_sfg_delays, algorithm="ASAP")
         with pytest.raises(
             ValueError,
             match="Operation add4 got incorrect move: 10. Must be between 0 and 7.",
@@ -315,51 +348,43 @@ class TestRescheduling:
 
         # Move and scheduling algorithm behaves differently
         schedule.move_operation("out1", 0)
-        assert schedule.laps[sfg.find_by_id("out1").input(0).signals[0].graph_id] == 1
+        assert schedule.laps[sfg.find_by_id("out1").input(0).signals[0].graph_id] == 0
         assert schedule.laps[sfg.find_by_id("add1").input(0).signals[0].graph_id] == 1
         assert schedule.laps[sfg.find_by_id("add1").input(1).signals[0].graph_id] == 0
-        assert schedule._start_times["out1"] == 0
+        assert schedule._start_times["out1"] == 1
         assert schedule._start_times["add1"] == 0
 
         # Increase schedule time
         schedule.set_schedule_time(2)
-        assert schedule.laps[sfg.find_by_id("out1").input(0).signals[0].graph_id] == 1
+        assert schedule.laps[sfg.find_by_id("out1").input(0).signals[0].graph_id] == 0
         assert schedule.laps[sfg.find_by_id("add1").input(0).signals[0].graph_id] == 1
         assert schedule.laps[sfg.find_by_id("add1").input(1).signals[0].graph_id] == 0
-        assert schedule._start_times["out1"] == 0
+        assert schedule._start_times["out1"] == 1
         assert schedule._start_times["add1"] == 0
 
         # Move out one time unit
         schedule.move_operation("out1", 1)
-        assert schedule.laps[sfg.find_by_id("out1").input(0).signals[0].graph_id] == 1
+        assert schedule.laps[sfg.find_by_id("out1").input(0).signals[0].graph_id] == 0
         assert schedule.laps[sfg.find_by_id("add1").input(0).signals[0].graph_id] == 1
         assert schedule.laps[sfg.find_by_id("add1").input(1).signals[0].graph_id] == 0
-        assert schedule._start_times["out1"] == 1
+        assert schedule._start_times["out1"] == 2
         assert schedule._start_times["add1"] == 0
 
         # Move add one time unit
         schedule.move_operation("add1", 1)
         assert schedule.laps[sfg.find_by_id("add1").input(0).signals[0].graph_id] == 1
         assert schedule.laps[sfg.find_by_id("add1").input(1).signals[0].graph_id] == 0
-        assert schedule.laps[sfg.find_by_id("out1").input(0).signals[0].graph_id] == 1
-        assert schedule._start_times["add1"] == 1
-        assert schedule._start_times["out1"] == 1
-
-        # Move out back one time unit
-        schedule.move_operation("out1", -1)
-        assert schedule.laps[sfg.find_by_id("out1").input(0).signals[0].graph_id] == 1
-        assert schedule._start_times["out1"] == 0
-        assert schedule.laps[sfg.find_by_id("add1").input(0).signals[0].graph_id] == 1
-        assert schedule.laps[sfg.find_by_id("add1").input(1).signals[0].graph_id] == 0
+        assert schedule.laps[sfg.find_by_id("out1").input(0).signals[0].graph_id] == 0
         assert schedule._start_times["add1"] == 1
+        assert schedule._start_times["out1"] == 2
 
         # Move add back one time unit
         schedule.move_operation("add1", -1)
         assert schedule.laps[sfg.find_by_id("add1").input(0).signals[0].graph_id] == 1
         assert schedule.laps[sfg.find_by_id("add1").input(1).signals[0].graph_id] == 0
-        assert schedule.laps[sfg.find_by_id("out1").input(0).signals[0].graph_id] == 1
+        assert schedule.laps[sfg.find_by_id("out1").input(0).signals[0].graph_id] == 0
         assert schedule._start_times["add1"] == 0
-        assert schedule._start_times["out1"] == 0
+        assert schedule._start_times["out1"] == 2
 
 
 class TestTimeResolution:
@@ -368,7 +393,7 @@ class TestTimeResolution:
     ):
         schedule = Schedule(
             sfg_two_inputs_two_outputs_independent_with_cmul,
-            scheduling_algorithm="ASAP",
+            algorithm="ASAP",
         )
         old_schedule_time = schedule.schedule_time
         assert schedule.get_possible_time_resolution_decrements() == [1]
@@ -402,7 +427,7 @@ class TestTimeResolution:
     ):
         schedule = Schedule(
             sfg_two_inputs_two_outputs_independent_with_cmul,
-            scheduling_algorithm="ASAP",
+            algorithm="ASAP",
         )
         old_schedule_time = schedule.schedule_time
 
@@ -439,7 +464,7 @@ class TestTimeResolution:
     ):
         schedule = Schedule(
             sfg_two_inputs_two_outputs_independent_with_cmul,
-            scheduling_algorithm="ASAP",
+            algorithm="ASAP",
         )
         old_schedule_time = schedule.schedule_time
         assert schedule.get_possible_time_resolution_decrements() == [1]
@@ -567,7 +592,7 @@ class TestErrors:
         with pytest.raises(
             NotImplementedError, match="No algorithm with name: foo defined."
         ):
-            Schedule(sfg_simple_filter, scheduling_algorithm="foo")
+            Schedule(sfg_simple_filter, algorithm="foo")
 
 
 class TestGetUsedTypeNames: