Reducibility
Glossary Contents
← Ch XVIII
Chapter XIX Job Sequencing
Ch XX →
  1. 55 — Deadlines on a single machine
  2. 56 — Moore–Hodgson in Ada
  3. 57 — Avionics task scheduling
56

Moore–Hodgson in Ada

Ada's strong typing and ranges fit naturally to scheduling — every quantity has a unit, and the compiler catches arithmetic mismatches.

  1. 01
    Define types with semantic ranges. Ada's subtypes catch off-by-one and unit confusions at compile time — the kind of thing you really want when scheduling avionics tasks.
    with Ada.Containers.Vectors;
    procedure Job_Schedule is
       subtype Time     is Natural range 0 .. 1_000_000;
       subtype Penalty  is Natural;
    
       type Job is record
          Id          : Positive;
          Length      : Time;
          Deadline    : Time;
          Late_Cost   : Penalty;
       end record;
    
       package Job_Vectors is new Ada.Containers.Vectors
          (Index_Type => Positive, Element_Type => Job);
       use Job_Vectors;
  2. 02
    Moore–Hodgson algorithm for minimizing the count of late jobs (a special case): sort by deadline, scan; whenever a job pushes you past its deadline, drop the longest scheduled-so-far. The algorithm is provably optimal for this objective.
    function Moore_Hodgson (Jobs : Vector) return Vector is
       Sorted : Vector := Jobs;
       Out_J  : Vector;
       T      : Time := 0;
    begin
       --  Sort by deadline (insertion sort, fine for small n)
       --  ... (sort code elided for space) ...
       for J of Sorted loop
          Out_J.Append (J);
          T := T + J.Length;
          if T > J.Deadline then
             declare
                Worst_Idx : Positive := 1;
             begin
                for K in Out_J.First_Index .. Out_J.Last_Index loop
                   if Out_J (K).Length > Out_J (Worst_Idx).Length then
                      Worst_Idx := K;
                   end if;
                end loop;
                T := T - Out_J (Worst_Idx).Length;
                Out_J.Delete (Worst_Idx);
             end;
          end if;
       end loop;
       return Out_J;
    end Moore_Hodgson;
  3. 03
    Drive it. The result is the largest set of jobs that can all meet their deadlines on a single machine. Ada's compile-time guarantees are the reason it remains the language of choice for safety-critical scheduling — when an avionics scheduler reorders tasks, "off-by-one" is not an option.
       Jobs : Vector;
    begin
       Jobs.Append ((1, 5, 10, 100));
       Jobs.Append ((2, 4, 8,   50));
       Jobs.Append ((3, 6, 12,  20));
       declare
          Sched : constant Vector := Moore_Hodgson (Jobs);
       begin
          for J of Sched loop
             Ada.Text_IO.Put_Line ("scheduled " & Integer'Image (J.Id));
          end loop;
       end;
    end Job_Schedule;
  4. 04
    For the general weighted case (the actually NP-hard Karp version), no greedy works; you fall back to branch-and-bound or branch-and-price. But the Moore–Hodgson kernel is the building block of every industrial scheduler, including those used by Boeing and Airbus.
    --  Weighted variant: branch on each job either scheduled-on-time
    --  or accepted-as-late, prune by lower-bound (sum of penalties for
    --  jobs that *must* be late given the chosen prefix).
Grammar — Ada

Ada is the strict-uncle language of the systems world. Subtypes carry runtime-checked range constraints; types do not implicitly convert; even the plain "=" symbol is reserved for comparison only. The result: scheduling code where a "time" can never accidentally be added to a "count."

with Ada.Text_IO;
import a package. Use `use Ada.Text_IO;` to bring its names into scope without prefixing.
procedure Name is ... begin ... end Name;
procedure — a routine that returns nothing. Declarative parts go before `begin`; executable code after.
subtype T is Natural range 0 .. 1_000;
a constrained subtype. Out-of-range assignments raise Constraint_Error at runtime.
type Job is record F : T; end record;
record type — Ada's name for a struct. Fields declared inside `record ... end record`.
:=
assignment. The plain `=` is reserved for equality comparison; mixing them is a compile error.
declare ... begin ... end;
block statement with local declarations. Blocks can nest anywhere.
'Image
an attribute — `Integer'Image(42)` returns " 42" as a string. Many types come with built-in attributes.
for J of Container loop ... end loop;
iterate over a container. `for I in 1 .. N loop` for index loops.
package P is new Generic (...)
generic instantiation. Generic packages (like Ada.Containers.Vectors) get specialized per use.
Declare scheduling types with hard ranges. Trying to assign 2_000_000 to a value of subtype Time raises Constraint_Error — at runtime if you can't prove it statically. The compiler catches what it can, the runtime catches the rest.
subtype Time     is Natural range 0 .. 1_000_000;
subtype Penalty  is Natural;

type Job is record
   Id        : Positive;
   Length    : Time;
   Deadline  : Time;
   Late_Cost : Penalty;
end record;

J : Job := (Id => 1, Length => 5, Deadline => 10, Late_Cost => 100);
-- J.Length := 2_000_000;  -- runtime: raises Constraint_Error
Learn.AdaCore — Ada in your browser →

Scan to come back to page 56

← 55 Deadlines on a single machine
2/3 · 56/63
57 Avionics task scheduling →