1 ovy 1.1 package harpoon.Analysis.MemOpt; 2 ovy 1.1 3 ovy 1.1 /* This colors a graph with as few colors as possible, returning 4 ovy 1.1 the resulting color classes (similar to GraphColoring.UnboundedGraphColorer, 5 ovy 1.1 qbut with much better results). 6 ovy 1.1 7 ovy 1.1 It does not currently implement GraphColoring, instead gets the graph as 8 ovy 1.1 a collection of nodes and a "contains edge" relation (MultiMap) and 9 ovy 1.1 returns the classes not the colors. We use it in IncompatibilityAnalysis 10 ovy 1.1 on what is conceptually a symmetric relation, not a graph. IMHO, it 11 ovy 1.1 should stay this way since we really don't need the extra complication 12 ovy 1.1 of ColorableGraph and friends in IncompatibilityAnalysis. But I could 13 ovy 1.1 change it if needed. 14 ovy 1.1 15 ovy 1.1 Uses a Most-saturated-node heuristic, with O(E + N log N) complexity. 16 ovy 1.1 17 ovy 1.1 FIXME: add comments 18 ovy 1.1 FIXME: maybe change to GraphColoring semantics. 19 ovy 1.1 */ 20 ovy 1.1 21 ovy 1.1 import harpoon.Util.MaxPriorityQueue; 22 ovy 1.1 import harpoon.Util.BinHeapPriorityQueue; 23 cananian 1.3 import net.cscott.jutil.MultiMap; 24 ovy 1.1 25 ovy 1.1 import java.util.Collection; 26 ovy 1.1 import java.util.Iterator; 27 ovy 1.1 import java.util.LinkedList; 28 ovy 1.1 29 ovy 1.1 30 ovy 1.1 public final class MyGraphColorer { 31 ovy 1.1 32 ovy 1.1 public static Collection colorGraph(Collection nodes, 33 ovy 1.1 MultiMap edges) { 34 ovy 1.1 35 ovy 1.1 MaxPriorityQueue pqueue = new BinHeapPriorityQueue(nodes.size()); 36 ovy 1.1 37 ovy 1.1 // this could be optimized by implementing a custom addAll in pqueue 38 ovy 1.1 // then building would take O(n) instead of O(n log n) 39 ovy 1.1 // but this is really too insignificant to matter 40 ovy 1.1 for (Iterator it = nodes.iterator(); it.hasNext(); ) { 41 ovy 1.1 Object node = it.next(); 42 ovy 1.1 pqueue.insert(node, edges.getValues(node).size()); 43 ovy 1.1 } 44 ovy 1.1 45 ovy 1.1 Collection classes = new LinkedList(); 46 ovy 1.1 47 ovy 1.1 while (!pqueue.isEmpty()) { 48 ovy 1.1 Object candidate = pqueue.deleteMax(); 49 ovy 1.1 50 ovy 1.1 boolean assigned = false; 51 ovy 1.1 52 ovy 1.1 for (Iterator it = classes.iterator(); 53 ovy 1.1 it.hasNext() && !assigned; ) { 54 ovy 1.1 Collection members = (Collection) it.next(); 55 salcianu 1.2 56 ovy 1.1 boolean compatible = true; 57 ovy 1.1 for (Iterator it2 = members.iterator(); 58 ovy 1.1 it2.hasNext() && compatible; ) { 59 ovy 1.1 Object member = it2.next(); 60 ovy 1.1 61 ovy 1.1 compatible &= !edges.contains(candidate, member); 62 ovy 1.1 } 63 ovy 1.1 64 ovy 1.1 if (compatible) { 65 ovy 1.1 members.add(candidate); 66 ovy 1.1 assigned = true; 67 ovy 1.1 } 68 ovy 1.1 } 69 ovy 1.1 70 ovy 1.1 if (!assigned) { 71 ovy 1.1 Collection newClass = new LinkedList(); 72 ovy 1.1 newClass.add(candidate); 73 ovy 1.1 74 ovy 1.1 classes.add(newClass); 75 ovy 1.1 } 76 ovy 1.1 77 ovy 1.1 // now decrease priorities for this guys neighbours 78 ovy 1.1 for (Iterator it = edges.getValues(candidate).iterator(); 79 ovy 1.1 it.hasNext(); ) { 80 ovy 1.1 Object neighbour = it.next(); 81 ovy 1.1 if (pqueue.contains(neighbour)) { 82 ovy 1.1 pqueue.changePriority(neighbour, -1); 83 ovy 1.1 } 84 ovy 1.1 } 85 ovy 1.1 } 86 ovy 1.1 return classes; 87 ovy 1.1 } 88 ovy 1.1 }