-- Implements directed graph ADT

pragma assertion_policy(Check);
-- Check pre and post conditions

with lists;
generic
   type Node_Type (<>) is private;  -- Stored in the graph, via type NODE, below

   with function Equal (Left, Right : access Node_Type) return Boolean is <>;
   with function Less  (Left, Right : access Node_Type) return Boolean is <>;

   with procedure Print_Node_Type (N : Node_Type);
   Max_Nodes : Positive;

package graphs is
   type Graph is limited private;

   type Node is access Node_Type;

   type Nodes_Array is array (Positive range <>) of Node;
   -- A bunch of Nodes

   subtype Node_Count_Type is Natural range 0 .. Max_Nodes;
   subtype Node_Index_Type is Natural range 1 .. Max_Nodes;

   type Add_Order is (Alpha, As_Entered);
   -- Add parents and children alphabetical using Less, or as entered

   -----------------------------------
   -- Insert Nodes and Edges
   -----------------------------------
   procedure Add_Node (G : in out Graph; A_Node  : Node)
      with pre => not Contains (G, A_Node);

   procedure Connect (G : in out Graph; Parent : Node; Child : Node;
      Order : Add_Order := Alpha)
      with pre => not (Contains (G, Parent) and Contains (G, Child))
                or else not Is_Child (G, Parent, Child);

   -----------------------------------
   -- Does the graph contain a node or node_type?
      -- If so, find the node that goes with a node_type
   -----------------------------------
   function Contains (G : Graph; A_Node : Node     ) return Boolean;
   function Contains (G : Graph; A_Node : Node_Type) return Boolean;

   function Find (G : Graph; A_Node : Node_Type) return Node
      with pre => Contains (G, A_Node);

   -----------------------------------
   -- Extract and Print
   -----------------------------------
   function Get_Nodes (G : Graph) return Nodes_Array;
   function Get_Node_Count (G : Graph) return Node_Count_Type;

   procedure Print (G : Graph);
   -- Print each node and its parents and children

   procedure Print_Node (N : Node);

   -----------------------------------
   -- Children Routines
   -----------------------------------
   function Is_Child (G : Graph; Parent : Node; Child : Node) return Boolean
      with pre => Contains (G, Parent) and Contains (G, Child);

   function Get_Children (G : Graph; Parent : Node) return Nodes_Array
      with pre => Contains (G, Parent),
           post => Get_Children'result'last in 0 .. Max_Nodes;

   function Get_Children_Count (G : Graph; Parent : Node) return Node_Count_Type
      with pre => Contains (G, Parent),
           post => Get_Children_Count'result = Get_Children (G, Parent)'length;

   function Find_Child (G : Graph; Parent : Node; Child : Node) return Node_Index_Type
      with pre => Contains (G, Parent) and Contains (G, Child)
                  and (Is_Child (G, Parent, Child));

   function Get_Child (G : Graph; Parent : Node; Child : Node_Index_Type) return Node
      with pre => Contains (G, Parent)
                  and Child in 1 .. Get_Children_Count (G, Parent);

   -----------------------------------
   -- Parent Routines
   -----------------------------------
   function Is_Parent (G : Graph; Parent : Node; Child : Node) return Boolean
      with pre => Contains (G, Parent) and Contains (G, Child);

   function Get_Parents (G : Graph; Child : Node) return Nodes_Array
      with pre => contains (G, Child),
           post => Get_Parents'result'last in 0 .. Max_Nodes;

   function Get_Parents_Count (G : Graph; Child : Node) return Node_Count_Type
      with pre => Contains (G, child);

   function Find_Parent (G : Graph; Child : Node; Parent : Node) return Node_Index_Type
      with pre => Contains (G, Child) and Contains (G, Parent)
                  and (Is_Child (G, Parent, Child));

   function Get_Parent (G : Graph; Child : Node; Parent : Node_Index_Type) return Node
      with pre => Contains (G, Child)
                  and then Parent <= Get_Parents_Count (G, Child);

   -----------------------------------
   -- Relation Routines
   -----------------------------------
   function Is_Sibling (G : Graph; Left, Right : Node) return Boolean
      with pre => contains (G, Left) and contains (G, Right);

   function Related (G : Graph; Parent : Node; Child : Node) return Boolean
      with pre => contains (g, child) and contains (G, Parent);

private
   ...
end graphs;