601123eaf0257b66a11281a29ca57754c357c7b5
[repair.git] / Repair / RepairCompiler / MCC / IR / GraphNode.java
1 package MCC.IR;
2
3 import java.util.*;
4 import java.io.*;
5
6 public class GraphNode {
7
8     public static boolean useEdgeLabels;
9
10     /* NodeStatus enumeration pattern ***********/
11     
12     public static final NodeStatus UNVISITED = new NodeStatus("UNVISITED");
13     public static final NodeStatus PROCESSING = new NodeStatus("PROCESSING");
14     public static final NodeStatus FINISHED = new NodeStatus("FINISHED");
15
16     public static class NodeStatus {
17         private static String name;
18         private NodeStatus(String name) { this.name = name; }
19         public String toString() { return name; }
20     }
21
22     /* Edge *****************/
23
24     public static class Edge {
25         
26         private String label;
27         private GraphNode target;
28         private GraphNode source;
29         private String dotnodeparams = new String();
30
31         public Edge(String label, GraphNode target) {
32             this.label = label;
33             this.target = target;
34         }
35
36         public String getLabel() {
37             return label;
38         }
39
40         public void setSource(GraphNode s) {
41             this.source=s;
42         }
43
44         public GraphNode getSource() {
45             return source;
46         }
47
48         public GraphNode getTarget() {
49             return target;
50         }
51
52         public void setDotNodeParameters(String param) {
53             if (param == null) {
54                 throw new NullPointerException();
55             }
56             if (param.length() > 0) {
57                 dotnodeparams = "," + param;
58             } else {
59                 dotnodeparams = new String();
60             }
61         }
62
63     }
64
65     int discoverytime = -1;
66     int finishingtime = -1; /* used for searches */
67
68     Vector edges = new Vector();  
69     Vector inedges = new Vector();
70     String nodelabel;
71     String textlabel;
72     NodeStatus status = UNVISITED;    
73     String dotnodeparams = new String();
74     Object owner = null;
75
76     public GraphNode(String label) {
77         this.nodelabel = label;
78         this.textlabel = label;
79     }
80
81     public GraphNode(String label, Object owner) {
82         this.nodelabel = label;
83         this.textlabel = label;
84         this.owner = owner;
85     }
86
87     public GraphNode(String label, String textlabel, Object owner) {
88         this.nodelabel = label;
89         this.textlabel = textlabel;
90         this.owner = owner;
91     }
92
93     public Object getOwner() {
94         return owner;
95     }
96
97     public static void computeclosure(Collection nodes, Collection removed) {
98         Stack tovisit=new Stack();
99         tovisit.addAll(nodes);
100         while(!tovisit.isEmpty()) {
101             GraphNode gn=(GraphNode)tovisit.pop();
102             for(Iterator it=gn.edges();it.hasNext();) {
103                 Edge edge=(Edge)it.next();
104                 GraphNode target=edge.getTarget();
105                 if (!nodes.contains(target)) {
106                     if ((removed==null)||
107                         (!removed.contains(target))) {
108                         nodes.add(target);
109                         tovisit.push(target);
110                     }
111                 }
112             }
113         }
114     }
115
116     public static void boundedcomputeclosure(Collection nodes, Collection removed,int depth) {
117         Stack tovisit=new Stack();
118         tovisit.addAll(nodes);
119         for(int i=0;i<depth&&!tovisit.isEmpty();i++) {
120             GraphNode gn=(GraphNode)tovisit.pop();
121             for(Iterator it=gn.edges();it.hasNext();) {
122                 Edge edge=(Edge)it.next();
123                 GraphNode target=edge.getTarget();
124                 if (!nodes.contains(target)) {
125                     if ((removed==null)||
126                         (!removed.contains(target))) {
127                         nodes.add(target);
128                         tovisit.push(target);
129                     }
130                 }
131             }
132         }
133     }
134
135     public void setDotNodeParameters(String param) {
136         if (param == null) {
137             throw new NullPointerException();
138         }
139         if (param.length() > 0) {
140             dotnodeparams = "," + param;
141         } else {
142             dotnodeparams = new String();
143         }
144     }
145     
146     public void setStatus(NodeStatus status) {
147         if (status == null) {
148             throw new NullPointerException();
149         }
150         this.status = status;
151     }
152
153     public String getLabel() {
154         return nodelabel;
155     }
156
157     public String getTextLabel() {
158         return textlabel;
159     }
160     
161     public NodeStatus getStatus() {
162         return this.status;
163     }
164
165     public Iterator edges() {
166         return edges.iterator();
167     }
168
169     public Iterator inedges() {
170         return inedges.iterator();
171     }
172
173     public void addEdge(Edge newedge) {
174         newedge.setSource(this);
175         edges.addElement(newedge);
176         GraphNode tonode=newedge.getTarget();
177         tonode.inedges.addElement(newedge);
178     }
179
180     void reset() {
181             discoverytime = -1;
182             finishingtime = -1;
183             status = UNVISITED;
184     }
185
186     void resetscc() {
187         status = UNVISITED;
188     }
189
190     void discover(int time) {
191         discoverytime = time;
192         status = PROCESSING;
193     }
194
195     void finish(int time) {
196         assert status == PROCESSING;
197         finishingtime = time;
198         status = FINISHED;
199     }
200
201     /** Returns finishing time for dfs */
202
203     public int getFinishingTime() {
204         return finishingtime;
205     }
206
207
208     public static class DOTVisitor {
209         
210         java.io.PrintWriter output;
211         int tokennumber;
212         int color;
213       
214         private DOTVisitor(java.io.OutputStream output) {
215             tokennumber = 0;
216             color = 0;
217             this.output = new java.io.PrintWriter(output, true);
218         }
219         
220         private String getNewID(String name) {
221             tokennumber = tokennumber + 1;
222             return new String (name+tokennumber);
223         }
224
225         Collection nodes;
226         Collection special;
227         
228         public static void visit(java.io.OutputStream output, Collection nodes) {
229             visit(output,nodes,null);
230         }
231
232         public static void visit(java.io.OutputStream output, Collection nodes, Collection special) {
233             DOTVisitor visitor = new DOTVisitor(output);
234             visitor.special=special;
235             visitor.nodes = nodes;
236             visitor.make();
237         }
238         
239         private void make() {
240             output.println("digraph dotvisitor {");
241             output.println("\trotate=90;");
242             /*            output.println("\tpage=\"8.5,11\";");
243                           output.println("\tnslimit=1000.0;");
244                           output.println("\tnslimit1=1000.0;");
245                           output.println("\tmclimit=1000.0;");
246                           output.println("\tremincross=true;");*/
247             output.println("\tnode [fontsize=10,height=\"0.1\", width=\"0.1\"];");
248             output.println("\tedge [fontsize=6];");
249             traverse();
250             output.println("}\n");
251         }
252                 
253         private void traverse() {            
254             Set cycleset=GraphNode.findcycles(nodes);
255
256             Iterator i = nodes.iterator();
257             while (i.hasNext()) {
258                 GraphNode gn = (GraphNode) i.next();
259                 Iterator edges = gn.edges();
260                 String label = gn.getTextLabel(); // + " [" + gn.discoverytime + "," + gn.finishingtime + "];";
261                 String option="";
262                 if (cycleset.contains(gn))
263                     option=",style=bold";
264                 if (special!=null&&special.contains(gn))
265                     option+=",shape=box";
266                 output.println("\t" + gn.getLabel() + " [label=\"" + label + "\"" + gn.dotnodeparams + option+"];");
267
268                 while (edges.hasNext()) {
269                     Edge edge = (Edge) edges.next();
270                     GraphNode node = edge.getTarget();
271                     if (nodes.contains(node)) {
272                         String edgelabel = useEdgeLabels ? "label=\"" + edge.getLabel() + "\"" : "label=\"\"";
273                         output.println("\t" + gn.getLabel() + " -> " + node.getLabel() + " [" + edgelabel + edge.dotnodeparams + "];");
274                     }
275                 }
276             }
277         }
278     }
279
280     /** This function returns the set of nodes involved in cycles. 
281      *  It only considers cycles containing nodes in the set 'nodes'.
282     */
283     public static Set findcycles(Collection nodes) {
284         HashSet cycleset=new HashSet();
285         SCC scc=DFS.computeSCC(nodes);
286         if (!scc.hasCycles())
287             return cycleset;
288         for(int i=0;i<scc.numSCC();i++) {
289             if (scc.hasCycle(i))
290                 cycleset.addAll(scc.getSCC(i));
291         }
292         return cycleset;
293     }
294
295     public static class SCC {
296         boolean acyclic;
297         HashMap map,revmap;
298         int numscc;
299         public SCC(boolean acyclic, HashMap map,HashMap revmap,int numscc) {
300             this.acyclic=acyclic;
301             this.map=map;
302             this.revmap=revmap;
303             this.numscc=numscc;
304         }
305
306         /** Returns whether the graph has any cycles */
307         public boolean hasCycles() {
308             return !acyclic;
309         }
310
311         /** Returns the number of Strongly Connected Components */
312         public int numSCC() {
313             return numscc;
314         }
315
316         /** Returns the strongly connected component number for the GraphNode gn*/
317         public int getComponent(GraphNode gn) {
318             return ((Integer)revmap.get(gn)).intValue();
319         }
320
321         /** Returns the set of nodes in the strongly connected component i*/
322         public Set getSCC(int i) {
323             Integer scc=new Integer(i);
324             return (Set)map.get(scc);
325         }
326
327         /** Returns whether the strongly connected component i contains a cycle */
328         boolean hasCycle(int i) {
329             Integer scc=new Integer(i);
330             Set s=(Set)map.get(scc);
331             if (s.size()>1)
332                 return true;
333             Object [] array=s.toArray();
334             GraphNode gn=(GraphNode)array[0];
335             for(Iterator it=gn.edges();it.hasNext();) {
336                 Edge e=(Edge)it.next();
337                 if (e.getTarget()==gn)
338                     return true; /* Self Cycle */
339             }
340             return false;
341         }
342     }
343
344     /**
345      * DFS encapsulates the depth first search algorithm 
346      */
347     public static class DFS {
348
349         int time = 0;
350         int sccindex = 0;
351         Collection nodes;
352         Vector finishingorder=null;
353         HashMap sccmap;
354         HashMap sccmaprev;
355
356         private DFS(Collection nodes) { 
357             this.nodes = nodes;
358         }
359         /** Calculates the strong connected components for the graph composed
360          *  of the set of nodes 'nodes'*/
361         public static SCC computeSCC(Collection nodes) {
362             if (nodes==null) {
363                 throw new NullPointerException();
364             }
365             DFS dfs=new DFS(nodes);
366             dfs.sccmap=new HashMap();
367             dfs.sccmaprev=new HashMap();
368             dfs.finishingorder=new Vector();
369             boolean acyclic=dfs.go();
370             for (Iterator it = nodes.iterator();it.hasNext();) {
371                 GraphNode gn = (GraphNode) it.next();
372                 gn.resetscc();
373             }
374             for(int i=dfs.finishingorder.size()-1;i>=0;i--) {
375                 GraphNode gn=(GraphNode)dfs.finishingorder.get(i);
376                 if (gn.getStatus() == UNVISITED) {
377                     dfs.dfsprev(gn);
378                     dfs.sccindex++; /* Increment scc index */
379                 }
380             }
381             return new SCC(acyclic,dfs.sccmap,dfs.sccmaprev,dfs.sccindex);
382         }
383
384         void dfsprev(GraphNode gn) {
385             if (gn.getStatus()==FINISHED||!nodes.contains(gn))
386                 return;
387             gn.setStatus(FINISHED);
388             Integer i=new Integer(sccindex);
389             if (!sccmap.containsKey(i))
390                 sccmap.put(i,new HashSet());
391             ((Set)sccmap.get(i)).add(gn);
392             sccmaprev.put(gn,i);
393             for(Iterator edgeit=gn.inedges();edgeit.hasNext();) {
394                 Edge e=(Edge)edgeit.next();
395                 GraphNode gn2=e.getSource();
396                 dfsprev(gn2);
397             }
398         }
399
400         public static boolean depthFirstSearch(Collection nodes) {
401             if (nodes == null) {
402                 throw new NullPointerException();
403             }
404             
405             DFS dfs = new DFS(nodes);
406             return dfs.go();
407         }
408
409         private boolean go() {           
410             Iterator i;
411             time = 0;
412             boolean acyclic=true;
413             i = nodes.iterator();
414             while (i.hasNext()) {
415                 GraphNode gn = (GraphNode) i.next();
416                 gn.reset();            
417             }            
418
419             i = nodes.iterator();
420             while (i.hasNext()) {
421                 GraphNode gn = (GraphNode) i.next();
422                 assert gn.getStatus() != PROCESSING;                    
423                 if (gn.getStatus() == UNVISITED) {
424                     if (!dfs(gn))
425                         acyclic=false;
426                 } 
427             }
428             return acyclic;
429         }
430
431         private boolean dfs(GraphNode gn) {
432             boolean acyclic=true;
433             gn.discover(time++);
434             Iterator edges = gn.edges();
435
436             while (edges.hasNext()) {
437                 Edge edge = (Edge) edges.next();
438                 GraphNode node = edge.getTarget();
439                 if (!nodes.contains(node)) /* Skip nodes which aren't in the set */
440                     continue;
441                 if (node.getStatus() == UNVISITED) {
442                     if (!dfs(node))
443                         acyclic=false;
444                 } else if (node.getStatus()==PROCESSING) {
445                     acyclic=false;
446                 }
447             }
448             if (finishingorder!=null)
449                 finishingorder.add(gn);
450             gn.finish(time++);
451             return acyclic;
452         }
453
454     } /* end DFS */
455
456 }