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