package body Partitions_of_Sets_of_Unknowns is -- CREATORS : procedure Create ( p : in out Partition; n : in natural ) is begin for i in p'range loop p(i) := Create(n); end loop; end Create; function Create ( p : Partition ) return Partition is res : Partition(p'range); begin for i in p'range loop res(i) := Create(p(i)); end loop; return res; end Create; -- CONSTRUCTOR : procedure Generate_Partitions ( s : in Set ) is -- NOTE : -- The algorithm below is a rather unelegant construction. -- The VADS compiler for IBM RS/6000 had problems with the nested -- generics, so the generation of all subsets is repeated here in full. n : constant natural := Dimension(s); continue : boolean := true; p : Partition(1..n); cnt : natural := 0; procedure Generate ( v : in Set; cont : out boolean ); -- DESCRIPTION : -- Generation of all partitions makes use of a double recursive process. procedure Empty_Subsets ( w : in Set; cont : out boolean ) is rest : Set := Difference(w,p(cnt)); begin if Extent_of(rest) = 0 then Process(p(1..cnt),cont); else Generate(rest,cont); end if; Clear(rest); end Empty_Subsets; procedure All_Subsets ( w : in Set; cont : out boolean ) is sb : Set := Create(n); procedure Create_Partition ( sub : in Set; cont : out boolean ) is rest : Set; back : Set := Create(p(cnt)); -- back up copy needed to restore begin Union(p(cnt),sub); rest := Difference(w,p(cnt)); if Extent_Of(rest) = 0 then Process(p(1..cnt),cont); else Generate(rest,cont); end if; Clear(p(cnt)); p(cnt) := Create(back); Clear(rest); Clear(back); end Create_Partition; procedure Generate_Subset ( level,start : in natural ) is begin if level > 0 then for i in start..n loop if Is_In(w,i) then Add(sb,i); Create_Partition(sb,continue); if continue then Generate_Subset(level-1,i+1); Remove(sb,i); end if; end if; exit when not continue; end loop; cont := continue; end if; end Generate_Subset; begin Generate_Subset(n,1); Clear(sb); end All_Subsets; procedure Generate ( v : in Set; cont : out boolean ) is begin for i in 1..n loop if Is_In(v,i) then cnt := cnt + 1; p(cnt) := Create(n); Add(p(cnt),i); Empty_Subsets(v,continue); if continue then declare w : Set := Create(v); begin Remove(w,i); All_Subsets(w,cont); Clear(w); end; end if; Clear(p(cnt)); cnt := cnt - 1; cont := continue; end if; exit when Is_In(v,i); end loop; end Generate; begin Generate(s,continue); end Generate_Partitions; -- SELECTOR : function Number_of_Partitions ( n : natural ) return natural is sum : natural; function comb ( n,i : natural ) return natural is n1,n2 : natural := 1; begin if (i = 0) or (i = n) then return 1; else for k in 1..i loop n1 := n1 * (n - k + 1); n2 := n2 * k; end loop; return (n1/n2); end if; end comb; begin if (n = 0) or (n = 1) then return 1; else sum := 0; for k in 0..(n-1) loop sum := sum + comb(n-1,k) * Number_Of_Partitions(n-1-k); end loop; return sum; end if; end Number_of_Partitions; -- DESTRUCTOR : procedure Clear ( p : in out Partition ) is begin for i in p'range loop Clear(p(i)); end loop; end Clear; end Partitions_of_Sets_of_Unknowns;