This commit was manufactured by cvs2svn to create tag 'buildscript'.
[IRC.git] /
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 (dotnodeparams.length() > 0) {
81             dotnodeparams += "," + param;
82         } else {
83             dotnodeparams = param;
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 String getName(){
103                 return "";
104         }
105
106     public NodeStatus getStatus() {
107         return this.status;
108     }
109
110     public int numedges() {
111         return edges.size();
112     }
113
114     public int numinedges() {
115         return inedges.size();
116     }
117
118     public Edge getedge(int i) {
119         return (Edge) edges.get(i);
120     }
121
122     public Edge getinedge(int i) {
123         return (Edge) inedges.get(i);
124     }
125
126     public Vector getEdgeVector() {
127         return edges;
128     }
129
130     public Vector getInedgeVector() {
131         return inedges;
132     }
133
134     public Iterator edges() {
135         return edges.iterator();
136     }
137
138     public Iterator inedges() {
139         return inedges.iterator();
140     }
141     
142     public void addEdge(Edge newedge) {
143         newedge.setSource(this);
144         edges.addElement(newedge);
145         GraphNode tonode=newedge.getTarget();
146         tonode.inedges.addElement(newedge);
147     }
148
149     public void addEdge(Vector v) {
150         for (Iterator it = v.iterator(); it.hasNext();)
151             addEdge((Edge)it.next());
152     }
153
154     public void removeEdge(Edge edge) {
155         edges.remove(edge);
156     }
157
158     public void removeInedge(Edge edge) {
159         inedges.remove(edge);
160     }
161
162     public void removeAllEdges() {
163         edges.removeAllElements();
164     }
165
166     public void removeAllInedges() {
167         inedges.removeAllElements();
168     }
169     void reset() {
170             discoverytime = -1;
171             finishingtime = -1;
172             status = UNVISITED;
173     }
174
175     void resetscc() {
176         status = UNVISITED;
177     }
178
179     void discover(int time) {
180         discoverytime = time;
181         status = PROCESSING;
182     }
183
184     void finish(int time) {
185         assert status == PROCESSING;
186         finishingtime = time;
187         status = FINISHED;
188     }
189
190     /** Returns finishing time for dfs */
191
192     public int getFinishingTime() {
193         return finishingtime;
194     }
195
196
197     public static class DOTVisitor {
198
199         java.io.PrintWriter output;
200         int tokennumber;
201         int color;
202         Vector namers;
203
204         private DOTVisitor(java.io.OutputStream output, Vector namers) {
205             tokennumber = 0;
206             color = 0;
207             this.output = new java.io.PrintWriter(output, true);
208             this.namers=namers;
209         }
210
211         private String getNewID(String name) {
212             tokennumber = tokennumber + 1;
213             return new String (name+tokennumber);
214         }
215
216         Collection nodes;
217
218
219         public static void visit(java.io.OutputStream output, Collection nodes, Vector namers) {
220             DOTVisitor visitor = new DOTVisitor(output, namers);
221             visitor.nodes = nodes;
222             visitor.make();
223         }
224
225         public static void visit(java.io.OutputStream output, Collection nodes) {
226             Vector v=new Vector();
227             v.add(new Namer());
228             DOTVisitor visitor = new DOTVisitor(output, v);
229             visitor.nodes = nodes;
230             visitor.make();
231         }
232
233         private void make() {
234             output.println("digraph dotvisitor {");
235             /*            output.println("\tpage=\"8.5,11\";");
236                           output.println("\tnslimit=1000.0;");
237                           output.println("\tnslimit1=1000.0;");
238                           output.println("\tmclimit=1000.0;");
239                           output.println("\tremincross=true;");*/
240             output.println("\tnode [fontsize=10,height=\"0.1\", width=\"0.1\"];");
241             output.println("\tedge [fontsize=6];");
242             traverse();
243             output.println("}\n");
244         }
245
246
247
248         private void traverse() {
249             Set cycleset=GraphNode.findcycles(nodes);
250
251             Iterator it = nodes.iterator();
252             while (it.hasNext()) {
253                 GraphNode gn = (GraphNode) it.next();
254                 Iterator edges = gn.edges();
255                 String label = "";
256                 String dotnodeparams="";
257
258                 for(int i=0;i<namers.size();i++) {
259                     Namer name=(Namer) namers.get(i);
260                     String newlabel=name.nodeLabel(gn);
261                     String newparams=name.nodeOption(gn);
262
263                     if (!newlabel.equals("") && !label.equals("")) {
264                         label+=", ";
265                     }
266                     if (!newparams.equals("")) {
267                         dotnodeparams+=", " + name.nodeOption(gn);
268                     }
269                     label+=name.nodeLabel(gn);
270                 }
271
272                 if (!gn.merge)
273                     output.println("\t" + gn.getLabel() + " [label=\"" + label + "\"" + dotnodeparams + "];");
274
275                 if (!gn.merge)
276                 while (edges.hasNext()) {
277                     Edge edge = (Edge) edges.next();
278                     GraphNode node = edge.getTarget();
279                     if (nodes.contains(node)) {
280                         for(Iterator nodeit=nonmerge(node).iterator();nodeit.hasNext();) {
281                             GraphNode node2=(GraphNode)nodeit.next();
282                             String edgelabel = "";
283                             String edgedotnodeparams="";
284
285                             for(int i=0;i<namers.size();i++) {
286                                 Namer name=(Namer) namers.get(i);
287                                 String newlabel=name.edgeLabel(edge);
288                                 String newoption=name.edgeOption(edge);
289                                 if (!newlabel.equals("")&& ! edgelabel.equals(""))
290                                     edgelabel+=", ";
291                                 edgelabel+=newlabel;
292                                 if (!newoption.equals(""))
293                                     edgedotnodeparams+=", "+newoption;
294                             }
295                             
296                             output.println("\t" + gn.getLabel() + " -> " + node2.getLabel() + " [" + "label=\"" + edgelabel + "\"" + edgedotnodeparams + "];");
297                         }
298                     }
299                 }
300             }
301         }
302
303         Set nonmerge(GraphNode gn) {
304             HashSet newset=new HashSet();
305             HashSet toprocess=new HashSet();
306             toprocess.add(gn);
307             while(!toprocess.isEmpty()) {
308                 GraphNode gn2=(GraphNode)toprocess.iterator().next();
309                 toprocess.remove(gn2);
310                 if (!gn2.merge)
311                     newset.add(gn2);
312                 else {
313                     Iterator edges = gn2.edges();
314                     while (edges.hasNext()) {
315                         Edge edge = (Edge) edges.next();
316                         GraphNode node = edge.getTarget();
317                         if (!newset.contains(node)&&nodes.contains(node))
318                             toprocess.add(node);
319                     }
320                 }
321             }
322             return newset;
323         }
324
325     }
326
327     /** This function returns the set of nodes involved in cycles.
328      *  It only considers cycles containing nodes in the set 'nodes'.
329     */
330     public static Set findcycles(Collection nodes) {
331         HashSet cycleset=new HashSet();
332         SCC scc=DFS.computeSCC(nodes);
333         if (!scc.hasCycles())
334             return cycleset;
335         for(int i=0;i<scc.numSCC();i++) {
336             if (scc.hasCycle(i))
337                 cycleset.addAll(scc.getSCC(i));
338         }
339         return cycleset;
340     }
341
342     public static class SCC {
343         boolean acyclic;
344         HashMap map,revmap;
345         int numscc;
346         public SCC(boolean acyclic, HashMap map,HashMap revmap,int numscc) {
347             this.acyclic=acyclic;
348             this.map=map;
349             this.revmap=revmap;
350             this.numscc=numscc;
351         }
352
353         /** Returns whether the graph has any cycles */
354         public boolean hasCycles() {
355             return !acyclic;
356         }
357
358         /** Returns the number of Strongly Connected Components */
359         public int numSCC() {
360             return numscc;
361         }
362
363         /** Returns the strongly connected component number for the GraphNode gn*/
364         public int getComponent(GraphNode gn) {
365             return ((Integer)revmap.get(gn)).intValue();
366         }
367
368         /** Returns the set of nodes in the strongly connected component i*/
369         public Set getSCC(int i) {
370             Integer scc=new Integer(i);
371             return (Set)map.get(scc);
372         }
373
374         /** Returns whether the strongly connected component i contains a cycle */
375         boolean hasCycle(int i) {
376             Integer scc=new Integer(i);
377             Set s=(Set)map.get(scc);
378             if (s.size()>1)
379                 return true;
380             Object [] array=s.toArray();
381             GraphNode gn=(GraphNode)array[0];
382             for(Iterator it=gn.edges();it.hasNext();) {
383                 Edge e=(Edge)it.next();
384                 if (e.getTarget()==gn)
385                     return true; /* Self Cycle */
386             }
387             return false;
388         }
389     }
390
391     /**
392      * DFS encapsulates the depth first search algorithm
393      */
394     public static class DFS {
395
396         int time = 0;
397         int sccindex = 0;
398         Collection nodes;
399         Vector finishingorder=null;
400         HashMap sccmap;
401         HashMap sccmaprev;
402
403         private DFS(Collection nodes) {
404             this.nodes = nodes;
405         }
406         /** Calculates the strong connected components for the graph composed
407          *  of the set of nodes 'nodes'*/
408         public static SCC computeSCC(Collection nodes) {
409             if (nodes==null) {
410                 throw new NullPointerException();
411             }
412             DFS dfs=new DFS(nodes);
413             dfs.sccmap=new HashMap();
414             dfs.sccmaprev=new HashMap();
415             dfs.finishingorder=new Vector();
416             boolean acyclic=dfs.go();
417             for (Iterator it = nodes.iterator();it.hasNext();) {
418                 GraphNode gn = (GraphNode) it.next();
419                 gn.resetscc();
420             }
421             for(int i=dfs.finishingorder.size()-1;i>=0;i--) {
422                 GraphNode gn=(GraphNode)dfs.finishingorder.get(i);
423                 if (gn.getStatus() == UNVISITED) {
424                     dfs.dfsprev(gn);
425                     dfs.sccindex++; /* Increment scc index */
426                 }
427             }
428             return new SCC(acyclic,dfs.sccmap,dfs.sccmaprev,dfs.sccindex);
429         }
430
431         void dfsprev(GraphNode gn) {
432             if (gn.getStatus()==FINISHED||!nodes.contains(gn))
433                 return;
434             gn.setStatus(FINISHED);
435             Integer i=new Integer(sccindex);
436             if (!sccmap.containsKey(i))
437                 sccmap.put(i,new HashSet());
438             ((Set)sccmap.get(i)).add(gn);
439             sccmaprev.put(gn,i);
440             for(Iterator edgeit=gn.inedges();edgeit.hasNext();) {
441                 Edge e=(Edge)edgeit.next();
442                 GraphNode gn2=e.getSource();
443                 dfsprev(gn2);
444             }
445         }
446
447         public static boolean depthFirstSearch(Collection nodes) {
448             if (nodes == null) {
449                 throw new NullPointerException();
450             }
451
452             DFS dfs = new DFS(nodes);
453             return dfs.go();
454         }
455
456         private boolean go() {
457             Iterator i;
458             time = 0;
459             boolean acyclic=true;
460             i = nodes.iterator();
461             while (i.hasNext()) {
462                 GraphNode gn = (GraphNode) i.next();
463                 gn.reset();
464             }
465
466             i = nodes.iterator();
467             while (i.hasNext()) {
468                 GraphNode gn = (GraphNode) i.next();
469                 assert gn.getStatus() != PROCESSING;
470                 if (gn.getStatus() == UNVISITED) {
471                     if (!dfs(gn))
472                         acyclic=false;
473                 }
474             }
475             return acyclic;
476         }
477
478         private boolean dfs(GraphNode gn) {
479             boolean acyclic=true;
480             gn.discover(time++);
481             Iterator edges = gn.edges();
482
483             while (edges.hasNext()) {
484                 Edge edge = (Edge) edges.next();
485                 GraphNode node = edge.getTarget();
486                 if (!nodes.contains(node)) /* Skip nodes which aren't in the set */
487                     continue;
488                 if (node.getStatus() == UNVISITED) {
489                     if (!dfs(node))
490                         acyclic=false;
491                 } else if (node.getStatus()==PROCESSING) {
492                     acyclic=false;
493                 }
494             }
495             if (finishingorder!=null)
496                 finishingorder.add(gn);
497             gn.finish(time++);
498             return acyclic;
499         }
500
501     } /* end DFS */
502
503 }