1 { Version 991025 experimental (minor changes 050625).
2   Adaptation for AGraph: Alexey A.Chernobaev }
3 
4 unit CTrick;
5 (*
6  * The author of this software is Michael Trick. Copyright (c) 1994 by
7  * Michael Trick.
8  *
9  * Permission to use, copy, modify, and distribute this software for any
10  * purpose without fee is hereby granted, provided that this entire notice
11  * is included in all copies of any software which is or includes a copy
12  * or modification of this software and in all copies of the supporting
13  * documentation for such software.
14  * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
15  * WARRANTY. IN PARTICULAR, NEITHER THE AUTHOR DOES NOT MAKE ANY
16  * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
17  * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
18 *)
19 (*
20    COLOR.C: Easy code for graph coloring
21    Author: Michael A. Trick, Carnegie Mellon University, trick+@cmu.edu
22    Last Modified: November 2, 1994
23 
24    Code is probably insufficiently debugged, but may be useful to some people.
25 
26    For more information on this code, see Anuj Mehrotra and Michael A. Trick,
27    "A column generation approach to graph coloring", GSIA Technical report series.
28 *)
29 
30 interface
31 
32 {$I VCheck.inc}
33 
34 uses
35   ExtType, Aliasv, Int16g, Int16v, Aliasm, Int16m, Boolv, Boolm, Graphs,
36   VectErr, GraphErr;
37 
ColorConnectedGraphnull38 function ColorConnectedGraph(G: TGraph; Colors: TGenericIntegerVector): Integer;
39 
40 implementation
41 
ColorConnectedGraphnull42 function ColorConnectedGraph(G: TGraph; Colors: TGenericIntegerVector): Integer;
43 var
44   BestColoring, NumNode, LowerBound, BestClique: Integer;
45   ColorClass, Order, ColorCount: TIntegerVector;
46   Handled: TBoolVector;
47   Adj: TBoolMatrix;
48   ColorAdj: TIntegerMatrix;
49 
Greedy_Cliquenull50   function Greedy_Clique(Valid, Clique: TBoolVector): Integer;
51   var
52     I, J, K, Max, Place: Integer;
53     Done: Bool;
54     Order, Weight: TIntegerVector;
55   begin
56     Order:=TIntegerVector.Create(NumNode + 1, 0);
57     Weight:=nil;
58     try
59       Weight:=TIntegerVector.Create(NumNode, 0);
60       Clique.SetToDefault;
61       Place:=0;
62       for I:=0 to NumNode - 1 do
63         if Valid[I] then begin
64           Order[Place]:=I;
65           Inc(Place);
66         end;
67       for I:=0 to NumNode - 1 do
68         if Valid[I] then
69           for J:=0 to NumNode - 1 do
70             if Valid[J] and Adj[I, J] then
71               Weight.IncItem(I, 1);
72       repeat
73         Done:=True;
74         for I:=0 to Place - 2 do begin
75           J:=Order[I];
76           K:=Order[I + 1];
77           if Weight[J] < Weight[K] then begin
78             Order[I]:=K;
79             Order[I + 1]:=J;
80             Done:=False;
81           end;
82         end;
83       until Done;
84       Clique[Order[0]]:=True;
85       for I:=1 to Place - 1 do begin
86         J:=Order[I];
87         for K:=0 to I - 1 do
88           if Clique[Order[K]] and not Adj[J, Order[K]] then
89             Break;
90         Clique[J]:=K = I;
91       end;
92       Max:=0;
93       for I:=0 to Place - 1 do
94         if Clique[Order[I]] then Inc(Max);
95     finally
96       Order.Free;
97       Weight.Free;
98     end;
99     Result:=Max;
100   end; {Greedy_Clique}
101 
Max_W_Cliquenull102   function Max_W_Clique(Valid, Clique: TBoolVector; Lower, Target: Integer): Integer;
103   (*
104     Target is a goal value: once a Clique is found with value Target
105     it is possible to return.
106 
107     Lower is a bound representing an already found Clique: once it is
108     determined that no Clique exists with value better than Lower, it
109     is permitted to return with a suboptimal Clique.
110 
111     Note, to find a Clique of value 1, it is not permitted to just set
112     the Lower to 1: the recursion will not work. Lower represents a
113     value that is the goal for the recursion.
114   *)
115   var
116     I, J, K, Incumb, NewWeight, Place, Place1, Start, Finish, TotalLeft: Integer;
117     Done: Bool;
118     Order, Value: TIntegerVector;
119     Valid1, Clique1: TBoolVector;
120   begin {Max_W_Clique}
121     { entered with 'Lower', 'Target' }
122     Clique.SetToDefault;
123     TotalLeft:=Valid.NumTrue;
124     if TotalLeft < Lower then begin
125       Result:=0;
126       Exit;
127     end;
128     Order:=TIntegerVector.Create(NumNode + 1, 0);
129     try
130       Value:=TIntegerVector.Create(NumNode, 0);
131       try
132         Incumb:=Greedy_Clique(Valid, Clique);
133         if Incumb >= Target then begin
134           Result:=Incumb;
135           Exit;
136         end;
137         if Incumb > BestClique then { Clique of size 'Incumb' found }
138           BestClique:=Incumb;
139         { greedy gave 'Incumb' }
140         Place:=0;
141         for I:=0 to NumNode - 1 do begin
142           if Clique[I] then begin
143             Order[Place]:=I;
144             Dec(TotalLeft);
145             Inc(Place);
146           end;
147         end;
148         Start:=Place;
149         for I:=0 to NumNode - 1 do begin
150           if not Clique[I] and Valid[I] then begin
151             Order[Place]:=I;
152             Inc(Place);
153           end;
154         end;
155         Finish:=Place;
156         for Place:=Start to Finish - 1 do begin
157           I:=Order[Place];
158           Value[I]:=0;
159           for J:=0 to NumNode - 1 do
160             if Valid[J] and Adj[I, J] then
161               Value.IncItem(I, 1);
162         end;
163         repeat
164           Done:=True;
165           for Place:=Start to Finish - 2 do begin
166             I:=Order[Place];
167             J:=Order[Place + 1];
168             if Value[I] < Value[J] then begin
169               Order[Place]:=J;
170               Order[Place + 1]:=I;
171               Done:=False;
172             end;
173           end;
174         until Done;
175       finally
176         Value.Free;
177       end;
178       Valid1:=TBoolVector.Create(NumNode, False);
179       Clique1:=nil;
180       try
181         Clique1:=TBoolVector.Create(NumNode, False);
182         for Place:=Start to Finish - 1 do begin
183           if Incumb + TotalLeft < Lower then begin
184             Result:=0;
185             Exit;
186           end;
187           J:=Order[Place];
188           Dec(TotalLeft);
189           if not Clique[J] then begin
190             Valid1.SetToDefault;
191             Place1:=0;
192             while Place1 < Place do begin
193               K:=Order[Place1];
194               Valid1[K]:=Valid[K] and Adj[J, K];
195               Inc(Place1);
196             end;
197             NewWeight:=Max_W_Clique(Valid1, Clique1, Incumb - 1, Target - 1);
198             if NewWeight + 1 > Incumb then begin { taking new }
199               Incumb:=NewWeight + 1;
200               Clique.Assign(Clique1);
201               Clique[J]:=True;
202               if Incumb > BestClique then { Clique of size 'Incumb' found }
203                 BestClique:=Incumb;
204             end;
205             { taking 'Incumb' }
206             if Incumb >=Target then
207               Break;
208           end;
209         end; {for}
210       finally
211         Valid1.Free;
212         Clique1.Free;
213       end;
214     finally
215       Order.Free;
216     end;
217     Result:=Incumb;
218   end; {Max_W_Clique}
219 
220   procedure AssignColor(Node, Color: Integer);
221   { 'Node' Color + 'Color' }
222   var
223     Node1: Integer;
224   begin
225     ColorClass[Node]:=Color;
226     for Node1:=0 to NumNode - 1 do
227       if (Node <> Node1) and Adj[Node, Node1] then begin
228         if ColorAdj[Node1, Color] = 0 then ColorCount.IncItem(Node1, 1);
229         ColorAdj.IncItem(Node1, Color, 1);
230         ColorAdj.DecItem(Node1, 0, 1);
231        {$IFDEF CHECK_GRAPHS}
232         if ColorAdj[Node1, 0] < 0 then
233           TGraph.Error(SAlgorithmFailure)
234        {$ENDIF};
235       end;
236   end; {AssignColor}
237 
238   procedure RemoveColor(Node, Color: Integer);
239   { 'Node' Color - 'Color' }
240   var
241     Node1: Integer;
242   begin
243     ColorClass[Node]:=0;
244     for Node1:=0 to NumNode - 1 do
245       if (Node <> Node1) and Adj[Node, Node1] then begin
246         if ColorAdj.DecItem(Node1, Color, 1) = 0 then
247           ColorCount.DecItem(Node1, 1);
248        {$IFDEF CHECK_GRAPHS}
249         if ColorAdj[Node1, Color] < 0 then
250           TGraph.Error(SAlgorithmFailure)
251        {$ENDIF};
252         ColorAdj.IncItem(Node1, 0, 1);
253       end;
254   end; {RemoveColor}
255 
Colornull256   function Color(I, CurrentColor: Integer): Integer;
257   var
258     J, Max, Place, NewVal: Integer;
259   begin
260     if CurrentColor >= BestColoring then begin
261       Result:=CurrentColor;
262       Exit;
263     end;
264     if BestColoring <= LowerBound then begin
265       Result:=BestColoring;
266       Exit;
267     end;
268     if I >= NumNode then begin
269       Result:=CurrentColor;
270       Exit;
271     end;
272     { Node 'I' color 'CurrentColor' }
273     { find Node with maximum ColorAdj }
274     Max:=-1;
275     Place:=-1;
276     for J:=0 to NumNode - 1 do
277       if not Handled[J] then begin
278         if (ColorCount[J] > Max) or
279           (ColorCount[J] = Max) and (ColorAdj[J, 0] > ColorAdj[Place, 0]) then
280         begin { best now at 'J' }
281           Max:=ColorCount[J];
282           Place:=J;
283         end;
284       end;
285     Order[I]:=Place;
286     Handled[Place]:=True;
287     { using Node 'Place' at level 'I' }
288     for J:=1 to CurrentColor do begin
289       if ColorAdj[Place, J] = 0 then begin
290         ColorClass[Place]:=J;
291         AssignColor(Place, J);
292         NewVal:=Color(I + 1, CurrentColor);
293         if NewVal < BestColoring then begin
294           BestColoring:=NewVal;
295           if Colors <> nil then Colors.Assign(ColorClass);
296         end;
297         RemoveColor(Place, J);
298         if BestColoring <= CurrentColor then begin
299           Handled[Place]:=False;
300           Result:=BestColoring;
301           Exit;
302         end;
303       end;
304     end;
305     if CurrentColor + 1 < BestColoring then begin
306       ColorClass[Place]:=CurrentColor + 1;
307       AssignColor(Place, CurrentColor + 1);
308       NewVal:=Color(I + 1, CurrentColor + 1);
309       if NewVal < BestColoring then begin
310         BestColoring:=NewVal;
311         if Colors <> nil then Colors.Assign(ColorClass);
312       end;
313       RemoveColor(Place, CurrentColor + 1);
314     end;
315     Handled[Place]:=False;
316     Result:=BestColoring;
317   end; {Color}
318 
319 var
320   I, J, Place: Integer;
321   Valid, Clique: TBoolVector;
322 begin { ColorConnectedGraph }
323   {$IFDEF CHECK_GRAPHS}
324   if (Directed in G.Features) or not G.Connected then
325     TGraph.Error(SErrorInParameters);
326   {$ENDIF}
327   BestColoring:=0;
328   NumNode:=G.VertexCount;
329   LowerBound:=0;
330   BestClique:=0;
331   Adj:=G.CreateConnectionMatrix;
332   ColorAdj:=nil;
333   ColorClass:=nil;
334   Order:=nil;
335   ColorCount:=nil;
336   Handled:=nil;
337   try
338     ColorAdj:=TIntegerMatrix.Create(NumNode, NumNode + 1, 0);
339     ColorClass:=TIntegerVector.Create(NumNode, 0);
340     Order:=TIntegerVector.Create(NumNode, 0);
341     ColorCount:=TIntegerVector.Create(NumNode, 0);
342     Handled:=TBoolVector.Create(NumNode, False);
343     for I:=0 to NumNode - 1 do
344       for J:=0 to NumNode - 1 do
345         if Adj[I, J] then ColorAdj.IncItem(I, 0, 1);
346     BestColoring:=NumNode + 1;
347     Valid:=TBoolVector.Create(NumNode, True);
348     Clique:=nil;
349     try
350       Clique:=TBoolVector.Create(NumNode, False);
351       BestClique:=0;
352       LowerBound:=Max_W_Clique(Valid, Clique, 0, NumNode);
353       Place:=0;
354       for I:=0 to NumNode - 1 do
355         if Clique[I] then begin
356           Order[Place]:=I;
357           Handled[I]:=True;
358           Inc(Place);
359           AssignColor(I, Place);
360         end;
361     finally
362       Valid.Free;
363       Clique.Free;
364     end;
365     if Colors <> nil then Colors.Assign(ColorClass); { for trivial graph }
366     Result:=Color(Place, Place);
367     if Colors <> nil then Colors.SubScalar(1);
368   finally
369     Adj.Free;
370     ColorAdj.Free;
371     ColorClass.Free;
372     Order.Free;
373     ColorCount.Free;
374     Handled.Free;
375   end;
376 end; { ColorConnectedGraph }
377 
378 end.
379