1 pnkfelix 1.1.2.1  // OptimisticGraphColorer.java, created Fri Jul 28 18:45:20 2000 by pnkfelix
  2 cananian 1.1.2.11 // Copyright (C) 2000 Felix S. Klock II <pnkfelix@mit.edu>
  3 pnkfelix 1.1.2.1  // Licensed under the terms of the GNU GPL; see COPYING for details.
  4 pnkfelix 1.1.2.1  package harpoon.Analysis.GraphColoring;
  5 pnkfelix 1.1.2.1  
  6 pnkfelix 1.1.2.10 import harpoon.Analysis.GraphColoring.ColorableGraph.IllegalColor;
  7 pnkfelix 1.1.2.10 
  8 pnkfelix 1.1.2.1  import java.util.List;
  9 pnkfelix 1.1.2.1  import java.util.Iterator;
 10 pnkfelix 1.1.2.1  import java.util.Collection;
 11 pnkfelix 1.1.2.1  import java.util.ArrayList;
 12 pnkfelix 1.1.2.1  import java.util.Set;
 13 pnkfelix 1.1.2.1  import java.util.HashSet;
 14 pnkfelix 1.1.2.1  import java.util.Vector;
 15 pnkfelix 1.1.2.1  import java.util.Stack;
 16 pnkfelix 1.1.2.1  import java.util.Enumeration;
 17 pnkfelix 1.1.2.1  
 18 pnkfelix 1.1.2.1  import harpoon.Util.Util;
 19 cananian 1.5      import net.cscott.jutil.LinearSet;
 20 pnkfelix 1.1.2.1  
 21 pnkfelix 1.1.2.1  /**
 22 pnkfelix 1.1.2.1   * <code>OptimisticGraphColorer</code> uses a strategy similar to that
 23 pnkfelix 1.1.2.1   * of <code>SimpleGraphColorer</code>, except after removing
 24 pnkfelix 1.1.2.1   * all nodes with degree < K (where K is the number of colors
 25 pnkfelix 1.1.2.2   * provided), it begins optimistically removing nodes in the hopes
 26 pnkfelix 1.1.2.2   * that they will not actually need to be spilled.  By default it
 27 pnkfelix 1.1.2.2   * selects the nodes with the largest degree for removal in this
 28 pnkfelix 1.1.2.2   * second stage, but this is parameterizable.
 29 pnkfelix 1.1.2.1   * 
 30 cananian 1.1.2.11  * @author  Felix S. Klock II <pnkfelix@mit.edu>
 31 cananian 1.6       * @version $Id: OptimisticGraphColorer.java,v 1.6 2004/02/08 03:19:33 cananian Exp $
 32 pnkfelix 1.1.2.1   */
 33 pnkfelix 1.1.2.1  public class OptimisticGraphColorer extends GraphColorer {
 34 pnkfelix 1.1.2.2  
 35 pnkfelix 1.1.2.8      public static boolean MONITOR = false;
 36 pnkfelix 1.1.2.7      private static void MONITOR(String s) {
 37 pnkfelix 1.1.2.7          if (MONITOR) System.out.print(s);
 38 pnkfelix 1.1.2.7      }
 39 pnkfelix 1.1.2.7      
 40 pnkfelix 1.1.2.2      private final NodeSelector selector;
 41 pnkfelix 1.1.2.1      
 42 pnkfelix 1.1.2.2      public static abstract class NodeSelector {
 43 pnkfelix 1.1.2.2          /** Returns a element of <code>g.nodeSet()</code>, in the
 44 pnkfelix 1.1.2.2              intent that it be removed from <code>g</code>.
 45 pnkfelix 1.1.2.2              <BR> <B>requires:</B> g.nodeSet() is not empty.
 46 pnkfelix 1.1.2.2              <BR> <B>effects:</B> returns some element of g.nodeSet().
 47 pnkfelix 1.1.2.6          */
 48 pnkfelix 1.1.2.8          public abstract Object chooseNodeForRemoval(ColorableGraph g);
 49 pnkfelix 1.1.2.8  
 50 pnkfelix 1.1.2.8          /** Returns a element of <code>g.nodeSet()</code>, in the
 51 pnkfelix 1.1.2.9              intent that it be hidden in <code>g</code>.
 52 pnkfelix 1.1.2.8              <BR> <B>requires:</B> g.nodeSet() is not empty.
 53 pnkfelix 1.1.2.9              <BR> <B>effects:</B> 
 54 pnkfelix 1.1.2.9                   returns some uncolored element of g.nodeSet(), or
 55 pnkfelix 1.1.2.9                   null if all the elements of g.nodeSet() are colored.
 56 pnkfelix 1.1.2.8          */
 57 pnkfelix 1.1.2.8          public abstract Object chooseNodeForHiding(ColorableGraph g);
 58 pnkfelix 1.1.2.8  
 59 pnkfelix 1.1.2.10         /** Checks if node can be removed from graph to improve
 60 pnkfelix 1.1.2.10             colorability.
 61 pnkfelix 1.1.2.10             <BR> <B>requires:</B> n is in g
 62 pnkfelix 1.1.2.10             <BR> <B>effects:</B> returns True if n could ever be
 63 pnkfelix 1.1.2.10                  returned from chooseNodeForRemoval(g), False
 64 pnkfelix 1.1.2.10                  otherwise. 
 65 pnkfelix 1.1.2.10         */
 66 pnkfelix 1.1.2.10         public abstract boolean allowedToRemove(Object n,ColorableGraph g);
 67 pnkfelix 1.1.2.10 
 68 pnkfelix 1.1.2.2      }
 69 pnkfelix 1.1.2.2  
 70 pnkfelix 1.1.2.8      private static NodeSelector DEFAULT_SELECTOR = new SimpleSelector();
 71 pnkfelix 1.1.2.8  
 72 pnkfelix 1.1.2.8      public static class SimpleSelector extends NodeSelector {
 73 pnkfelix 1.1.2.8          protected SimpleSelector() { }
 74 pnkfelix 1.1.2.10         public boolean allowedToRemove(Object n, ColorableGraph g) {
 75 pnkfelix 1.1.2.10             return true;
 76 pnkfelix 1.1.2.10         }
 77 pnkfelix 1.1.2.8          public Object chooseNodeForRemoval(ColorableGraph g) {
 78 pnkfelix 1.1.2.9              Object o = chooseNode(g);
 79 cananian 1.3.2.1              assert o != null;
 80 pnkfelix 1.1.2.9              return o;
 81 pnkfelix 1.1.2.8          }
 82 pnkfelix 1.1.2.8          public Object chooseNodeForHiding(ColorableGraph g) {
 83 pnkfelix 1.1.2.9              Object o = chooseNode(g);
 84 pnkfelix 1.1.2.9              return o;
 85 pnkfelix 1.1.2.8          }
 86 pnkfelix 1.1.2.8          private Object chooseNode(ColorableGraph g) {
 87 pnkfelix 1.1.2.8              Object spillChoice = null; 
 88 pnkfelix 1.1.2.8              Set nset = g.nodeSet();
 89 pnkfelix 1.1.2.8              int maxDegree = -1;
 90 pnkfelix 1.1.2.8              for(Iterator ns = nset.iterator(); ns.hasNext();){
 91 pnkfelix 1.1.2.8                  Object n = ns.next();
 92 pnkfelix 1.1.2.8                  if (g.getColor(n) == null && 
 93 pnkfelix 1.1.2.8                      g.getDegree(n) > maxDegree) {
 94 pnkfelix 1.1.2.8                      spillChoice = n;
 95 pnkfelix 1.1.2.8                      maxDegree = g.getDegree(n);
 96 pnkfelix 1.1.2.2                  }
 97 pnkfelix 1.1.2.2              }
 98 pnkfelix 1.1.2.8              return spillChoice;
 99 pnkfelix 1.1.2.8          }
100 pnkfelix 1.1.2.8      }   
101 pnkfelix 1.1.2.8      
102 pnkfelix 1.1.2.2      /** Creates a <code>OptimisticGraphColorer</code> with the default
103 pnkfelix 1.1.2.2          second stage selection strategy. */
104 pnkfelix 1.1.2.2      public OptimisticGraphColorer() { 
105 pnkfelix 1.1.2.2          this.selector = DEFAULT_SELECTOR;
106 pnkfelix 1.1.2.2      }
107 pnkfelix 1.1.2.2  
108 pnkfelix 1.1.2.2      /** Creates a <code>OptimisticGraphColorer</code> with
109 pnkfelix 1.1.2.2          <code>selector</code> as its second stage selection
110 pnkfelix 1.1.2.2          strategy. */ 
111 pnkfelix 1.1.2.2      public OptimisticGraphColorer(NodeSelector selector) {
112 pnkfelix 1.1.2.2          this.selector = selector;
113 pnkfelix 1.1.2.2      }
114 pnkfelix 1.1.2.1  
115 pnkfelix 1.1.2.5      private boolean uncoloredNodesRemain(ColorableGraph g) {
116 pnkfelix 1.1.2.5          Iterator nodes = g.nodeSet().iterator();
117 pnkfelix 1.1.2.5          while(nodes.hasNext()) {
118 pnkfelix 1.1.2.5              if (g.getColor(nodes.next()) == null) 
119 pnkfelix 1.1.2.5                  return true;
120 pnkfelix 1.1.2.5          }
121 pnkfelix 1.1.2.5          return false;
122 pnkfelix 1.1.2.5      }
123 pnkfelix 1.1.2.5  
124 pnkfelix 1.1.2.1      public final void color(ColorableGraph graph, List colors)
125 pnkfelix 1.1.2.1          throws UnableToColorGraph {
126 pnkfelix 1.1.2.1          boolean moreNodesToHide;
127 pnkfelix 1.1.2.1          
128 pnkfelix 1.1.2.1          HashSet spills = new HashSet();
129 pnkfelix 1.1.2.1          for(;;) {
130 pnkfelix 1.1.2.1              do {
131 pnkfelix 1.1.2.1                  moreNodesToHide = false;
132 pnkfelix 1.1.2.5                  LinearSet nodeSet = new LinearSet(graph.nodeSet());
133 pnkfelix 1.1.2.1                  for(Iterator ns = nodeSet.iterator(); ns.hasNext();){ 
134 pnkfelix 1.1.2.1                      Object n = ns.next();
135 pnkfelix 1.1.2.5                      if (graph.getDegree(n) < colors.size() &&
136 pnkfelix 1.1.2.5                          graph.getColor(n) == null) {
137 pnkfelix 1.1.2.1                          graph.hide(n);
138 pnkfelix 1.1.2.1                          moreNodesToHide = true;
139 pnkfelix 1.1.2.7  
140 pnkfelix 1.1.2.7                          // MONITOR("conservative hide: "+n+"\n");
141 pnkfelix 1.1.2.1                      } 
142 pnkfelix 1.1.2.1                  }
143 pnkfelix 1.1.2.1              } while (moreNodesToHide);
144 pnkfelix 1.1.2.5  
145 pnkfelix 1.1.2.5              // Either the graph is finished (no uncolored nodes
146 pnkfelix 1.1.2.5              // remain) or all nodes present have degree >= K, in which
147 pnkfelix 1.1.2.5              // case we optimistically remove the node chosen by
148 pnkfelix 1.1.2.5              // this.selector. 
149 pnkfelix 1.1.2.1              
150 pnkfelix 1.1.2.5              if (!uncoloredNodesRemain(graph)) {
151 pnkfelix 1.1.2.1                  break;
152 pnkfelix 1.1.2.1              } else {
153 pnkfelix 1.1.2.8                  Object choice = this.selector.chooseNodeForHiding(graph);
154 pnkfelix 1.1.2.2                  graph.hide(choice);
155 pnkfelix 1.1.2.2                  spills.add(choice);
156 pnkfelix 1.1.2.7  
157 pnkfelix 1.1.2.7                  MONITOR("optimistic hide: "+choice+"\n");
158 pnkfelix 1.1.2.1                  continue;
159 pnkfelix 1.1.2.1              }
160 pnkfelix 1.1.2.1          }
161 pnkfelix 1.1.2.5  
162 pnkfelix 1.1.2.8          HashSet allSpills = new HashSet(spills);
163 pnkfelix 1.1.2.6          boolean unableToColor = false;
164 pnkfelix 1.1.2.8          
165 pnkfelix 1.1.2.3          nextNode:
166 pnkfelix 1.1.2.1          for(Object n=graph.replace(); n!=null; n=graph.replace()){
167 pnkfelix 1.1.2.1              // find color that none of n's neighbors is set to
168 pnkfelix 1.1.2.1              
169 pnkfelix 1.1.2.1              if (graph.getColor(n) != null) {
170 pnkfelix 1.1.2.5                  // precolored, die
171 cananian 1.3.2.1                  assert false;
172 pnkfelix 1.1.2.1              }
173 pnkfelix 1.1.2.1              
174 pnkfelix 1.1.2.1              Collection nborsC = graph.neighborsOf(n);
175 pnkfelix 1.1.2.1              HashSet nColors = new HashSet(nborsC.size());
176 pnkfelix 1.1.2.1              for(Iterator nbors = nborsC.iterator(); nbors.hasNext();){
177 pnkfelix 1.1.2.1                  Object nb = nbors.next();
178 pnkfelix 1.1.2.9                  if (spills.contains(nb)) continue;
179 pnkfelix 1.1.2.9                  
180 pnkfelix 1.1.2.3                  Color col = graph.getColor(nb);
181 pnkfelix 1.1.2.6                  
182 pnkfelix 1.1.2.6                  // nb can have no color, if it was a failed optimistic
183 pnkfelix 1.1.2.6                  // spill.  treat it as not needing a color.
184 pnkfelix 1.1.2.6                  if (col != null) nColors.add(col);
185 pnkfelix 1.1.2.1              }
186 pnkfelix 1.1.2.1              
187 pnkfelix 1.1.2.6          nextColor:
188 cananian 1.6                  for(Object colO : colors){
189 cananian 1.6                      Color col = (Color) colO;
190 pnkfelix 1.1.2.1                  if (!nColors.contains(col)) {
191 pnkfelix 1.1.2.3                      try {
192 pnkfelix 1.1.2.8                          // MONITOR("trying "+col+" with "+n+"\n");
193 pnkfelix 1.1.2.3                          graph.setColor(n, col);
194 pnkfelix 1.1.2.6                          spills.remove(n);
195 pnkfelix 1.1.2.7  
196 pnkfelix 1.1.2.7                          // MONITOR("set color of "+n+ " to "+col+"\n");
197 pnkfelix 1.1.2.3                          continue nextNode;
198 pnkfelix 1.1.2.10                     } catch (IllegalColor ic) {
199 pnkfelix 1.1.2.3                          // col was not legal for n
200 pnkfelix 1.1.2.3                          // try another color...  
201 pnkfelix 1.1.2.9                          if (false) MONITOR(col + " not legal for " + n + 
202 pnkfelix 1.1.2.8                                  "b/c of conflict between "+
203 pnkfelix 1.1.2.8                                  ic.color + " and " + ic.node+"\n");
204 pnkfelix 1.1.2.6                          continue nextColor;
205 pnkfelix 1.1.2.3                      }
206 pnkfelix 1.1.2.1                  }
207 pnkfelix 1.1.2.1              }
208 pnkfelix 1.1.2.3              
209 pnkfelix 1.1.2.3              // if we ever reach this point, we failed to color n
210 pnkfelix 1.1.2.7              MONITOR("failed to color "+n+"\n");
211 pnkfelix 1.1.2.9              // MONITOR("nbors(n): "+graph.neighborsOf(n));
212 pnkfelix 1.1.2.10             
213 pnkfelix 1.1.2.10             Object choice = null; int max = -1;
214 pnkfelix 1.1.2.10             for(Iterator ns=graph.neighborsOf(n).iterator();ns.hasNext();){
215 pnkfelix 1.1.2.10                 Object nde = ns.next();
216 pnkfelix 1.1.2.10                 if (graph.getDegree(nde) > max &&
217 pnkfelix 1.1.2.10                     selector.allowedToRemove(nde,graph)) {
218 pnkfelix 1.1.2.10                     choice = nde;
219 pnkfelix 1.1.2.10                     max = graph.getDegree(nde);
220 pnkfelix 1.1.2.10                 }
221 pnkfelix 1.1.2.10             }
222 pnkfelix 1.1.2.10             if (choice == null)
223 pnkfelix 1.1.2.10                 choice = this.selector.chooseNodeForRemoval(graph);
224 pnkfelix 1.1.2.9              if (choice != null) {
225 pnkfelix 1.1.2.9                  spills.add(choice); 
226 pnkfelix 1.1.2.9                  allSpills.add(choice);
227 pnkfelix 1.1.2.10                 graph.unsetColor(choice);
228 pnkfelix 1.1.2.9              }
229 pnkfelix 1.1.2.6              unableToColor = true;
230 pnkfelix 1.1.2.6          }
231 pnkfelix 1.1.2.6          
232 pnkfelix 1.1.2.6          if (unableToColor) {
233 pnkfelix 1.1.2.3              UnableToColorGraph u = new UnableToColorGraph();
234 pnkfelix 1.1.2.3              u.rmvSuggs = spills;
235 pnkfelix 1.1.2.8              u.rmvSuggsLarge = allSpills;
236 pnkfelix 1.1.2.3              throw u;
237 pnkfelix 1.1.2.1          }
238 pnkfelix 1.1.2.1      }
239 pnkfelix 1.1.2.1      
240 cananian 1.2      }