6 public class GraphNode {
7 /* NodeStatus enumeration pattern ***********/
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");
13 public static class NodeStatus {
14 private static String name;
15 private NodeStatus(String name) {
18 public String toString() {
23 int discoverytime = -1;
24 int finishingtime = -1; /* used for searches */
26 protected Vector edges = new Vector();
27 protected Vector inedges = new Vector();
29 NodeStatus status = UNVISITED;
30 String dotnodeparams = new String();
31 public boolean merge=false;
33 public void setMerge() {
37 public static void computeclosure(Collection nodes, Collection removed) {
38 Stack tovisit=new Stack();
39 tovisit.addAll(nodes);
40 while(!tovisit.isEmpty()) {
41 GraphNode gn=(GraphNode)tovisit.pop();
42 for(Iterator it=gn.edges(); it.hasNext();) {
43 Edge edge=(Edge)it.next();
44 GraphNode target=edge.getTarget();
45 if (!nodes.contains(target)) {
47 (!removed.contains(target))) {
56 public static void boundedcomputeclosure(Collection nodes, Collection removed,int depth) {
57 Stack tovisit=new Stack();
58 Stack newvisit=new Stack();
59 tovisit.addAll(nodes);
60 for(int i=0; i<depth&&!tovisit.isEmpty(); i++) {
61 while(!tovisit.isEmpty()) {
62 GraphNode gn=(GraphNode)tovisit.pop();
63 for(Iterator it=gn.edges(); it.hasNext();) {
64 Edge edge=(Edge)it.next();
65 GraphNode target=edge.getTarget();
66 if (!nodes.contains(target)) {
68 (!removed.contains(target))) {
70 newvisit.push(target);
80 public void setDotNodeParameters(String param) {
82 throw new NullPointerException();
84 if (dotnodeparams.length() > 0) {
85 dotnodeparams += "," + param;
87 dotnodeparams = param;
91 public void setStatus(NodeStatus status) {
93 throw new NullPointerException();
98 public String getLabel() {
102 public String getTextLabel() {
106 public String getName() {
110 public NodeStatus getStatus() {
114 public int numedges() {
118 public int numinedges() {
119 return inedges.size();
122 public Edge getedge(int i) {
123 return (Edge) edges.get(i);
126 public Edge getinedge(int i) {
127 return (Edge) inedges.get(i);
130 public Vector getEdgeVector() {
134 public Vector getInedgeVector() {
138 public Iterator edges() {
139 return edges.iterator();
142 public Iterator inedges() {
143 return inedges.iterator();
146 public void addEdge(Edge newedge) {
147 newedge.setSource(this);
148 edges.addElement(newedge);
149 GraphNode tonode=newedge.getTarget();
150 tonode.inedges.addElement(newedge);
153 public boolean containsEdge(Edge e) {
154 return edges.contains(e);
157 public void addEdge(Vector v) {
158 for (Iterator it = v.iterator(); it.hasNext();)
159 addEdge((Edge)it.next());
162 public void removeEdge(Edge edge) {
166 public void removeInedge(Edge edge) {
167 inedges.remove(edge);
170 public void removeAllEdges() {
171 edges.removeAllElements();
174 public void removeAllInedges() {
175 inedges.removeAllElements();
187 void discover(int time) {
188 discoverytime = time;
192 void finish(int time) {
193 assert status == PROCESSING;
194 finishingtime = time;
198 /** Returns finishing time for dfs */
200 public int getFinishingTime() {
201 return finishingtime;
205 public static class DOTVisitor {
207 java.io.PrintWriter output;
212 private DOTVisitor(java.io.OutputStream output, Vector namers) {
215 this.output = new java.io.PrintWriter(output, true);
219 private String getNewID(String name) {
220 tokennumber = tokennumber + 1;
221 return new String(name+tokennumber);
227 public static void visit(java.io.OutputStream output, Collection nodes, Vector namers) {
228 DOTVisitor visitor = new DOTVisitor(output, namers);
229 visitor.nodes = nodes;
233 public static void visit(java.io.OutputStream output, Collection nodes) {
234 Vector v=new Vector();
236 DOTVisitor visitor = new DOTVisitor(output, v);
237 visitor.nodes = nodes;
241 private void make() {
242 output.println("digraph dotvisitor {");
243 /* output.println("\tpage=\"8.5,11\";");
244 output.println("\tnslimit=1000.0;");
245 output.println("\tnslimit1=1000.0;");
246 output.println("\tmclimit=1000.0;");
247 output.println("\tremincross=true;");*/
248 output.println("\tnode [fontsize=10,height=\"0.1\", width=\"0.1\"];");
249 output.println("\tedge [fontsize=6];");
251 output.println("}\n");
256 private void traverse() {
257 Set cycleset=GraphNode.findcycles(nodes);
259 Iterator it = nodes.iterator();
260 while (it.hasNext()) {
261 GraphNode gn = (GraphNode) it.next();
262 Iterator edges = gn.edges();
264 String dotnodeparams="";
266 for(int i=0; i<namers.size(); i++) {
267 Namer name=(Namer) namers.get(i);
268 String newlabel=name.nodeLabel(gn);
269 String newparams=name.nodeOption(gn);
271 if (!newlabel.equals("") && !label.equals("")) {
274 if (!newparams.equals("")) {
275 dotnodeparams+=", " + name.nodeOption(gn);
277 label+=name.nodeLabel(gn);
281 output.println("\t" + gn.getLabel() + " [label=\"" + label + "\"" + dotnodeparams + "];");
284 while (edges.hasNext()) {
285 Edge edge = (Edge) edges.next();
286 GraphNode node = edge.getTarget();
287 if (nodes.contains(node)) {
288 for(Iterator nodeit=nonmerge(node).iterator(); nodeit.hasNext();) {
289 GraphNode node2=(GraphNode)nodeit.next();
290 String edgelabel = "";
291 String edgedotnodeparams="";
293 for(int i=0; i<namers.size(); i++) {
294 Namer name=(Namer) namers.get(i);
295 String newlabel=name.edgeLabel(edge);
296 String newoption=name.edgeOption(edge);
297 if (!newlabel.equals("")&& !edgelabel.equals(""))
300 if (!newoption.equals(""))
301 edgedotnodeparams+=", "+newoption;
304 output.println("\t" + gn.getLabel() + " -> " + node2.getLabel() + " [" + "label=\"" + edgelabel + "\"" + edgedotnodeparams + "];");
311 Set nonmerge(GraphNode gn) {
312 HashSet newset=new HashSet();
313 HashSet toprocess=new HashSet();
315 while(!toprocess.isEmpty()) {
316 GraphNode gn2=(GraphNode)toprocess.iterator().next();
317 toprocess.remove(gn2);
321 Iterator edges = gn2.edges();
322 while (edges.hasNext()) {
323 Edge edge = (Edge) edges.next();
324 GraphNode node = edge.getTarget();
325 if (!newset.contains(node)&&nodes.contains(node))
335 /** This function returns the set of nodes involved in cycles.
336 * It only considers cycles containing nodes in the set 'nodes'.
338 public static Set findcycles(Collection nodes) {
339 HashSet cycleset=new HashSet();
340 SCC scc=DFS.computeSCC(nodes);
341 if (!scc.hasCycles())
343 for(int i=0; i<scc.numSCC(); i++) {
345 cycleset.addAll(scc.getSCC(i));
350 public static class SCC {
354 public SCC(boolean acyclic, HashMap map,HashMap revmap,int numscc) {
355 this.acyclic=acyclic;
361 /** Returns whether the graph has any cycles */
362 public boolean hasCycles() {
366 /** Returns the number of Strongly Connected Components */
367 public int numSCC() {
371 /** Returns the strongly connected component number for the GraphNode gn*/
372 public int getComponent(GraphNode gn) {
373 return ((Integer)revmap.get(gn)).intValue();
376 /** Returns the set of nodes in the strongly connected component i*/
377 public Set getSCC(int i) {
378 Integer scc=new Integer(i);
379 return (Set)map.get(scc);
382 /** Returns whether the strongly connected component i contains a cycle */
383 boolean hasCycle(int i) {
384 Integer scc=new Integer(i);
385 Set s=(Set)map.get(scc);
388 Object [] array=s.toArray();
389 GraphNode gn=(GraphNode)array[0];
390 for(Iterator it=gn.edges(); it.hasNext();) {
391 Edge e=(Edge)it.next();
392 if (e.getTarget()==gn)
393 return true; /* Self Cycle */
400 * DFS encapsulates the depth first search algorithm
402 public static class DFS {
407 Vector finishingorder=null;
408 Vector finishingorder_edge = null;
413 private DFS(Collection nodes) {
416 /** Calculates the strong connected components for the graph composed
417 * of the set of nodes 'nodes'*/
418 public static SCC computeSCC(Collection nodes) {
420 throw new NullPointerException();
422 DFS dfs=new DFS(nodes);
423 dfs.sccmap=new HashMap();
424 dfs.sccmaprev=new HashMap();
425 dfs.finishingorder=new Vector();
426 boolean acyclic=dfs.go();
427 for (Iterator it = nodes.iterator(); it.hasNext();) {
428 GraphNode gn = (GraphNode) it.next();
431 for(int i=dfs.finishingorder.size()-1; i>=0; i--) {
432 GraphNode gn=(GraphNode)dfs.finishingorder.get(i);
433 if (gn.getStatus() == UNVISITED) {
435 dfs.sccindex++; /* Increment scc index */
438 return new SCC(acyclic,dfs.sccmap,dfs.sccmaprev,dfs.sccindex);
441 void dfsprev(GraphNode gn) {
442 if (gn.getStatus()==FINISHED||!nodes.contains(gn))
444 gn.setStatus(FINISHED);
445 Integer i=new Integer(sccindex);
446 if (!sccmap.containsKey(i))
447 sccmap.put(i,new HashSet());
448 ((Set)sccmap.get(i)).add(gn);
450 for(Iterator edgeit=gn.inedges(); edgeit.hasNext();) {
451 Edge e=(Edge)edgeit.next();
452 GraphNode gn2=e.getSource();
457 public static boolean depthFirstSearch(Collection nodes) {
459 throw new NullPointerException();
462 DFS dfs = new DFS(nodes);
466 private boolean go() {
470 boolean acyclic=true;
471 i = nodes.iterator();
472 while (i.hasNext()) {
473 GraphNode gn = (GraphNode) i.next();
477 i = nodes.iterator();
478 while (i.hasNext()) {
479 GraphNode gn = (GraphNode) i.next();
480 assert gn.getStatus() != PROCESSING;
481 if (gn.getStatus() == UNVISITED) {
489 private boolean dfs(GraphNode gn) {
490 boolean acyclic=true;
492 Iterator edges = gn.edges();
494 while (edges.hasNext()) {
495 Edge edge = (Edge) edges.next();
496 edge.discover(edgetime++);
497 GraphNode node = edge.getTarget();
498 if (!nodes.contains(node)) { /* Skip nodes which aren't in the set */
499 if(finishingorder_edge != null)
500 finishingorder_edge.add(edge);
501 edge.finish(edgetime++);
504 if (node.getStatus() == UNVISITED) {
507 } else if (node.getStatus()==PROCESSING) {
510 if(finishingorder_edge != null)
511 finishingorder_edge.add(edge);
512 edge.finish(edgetime++);
514 if (finishingorder!=null)
515 finishingorder.add(gn);
520 public static Vector topology(Collection nodes, Vector finishingorder_edge) {
522 throw new NullPointerException();
524 DFS dfs=new DFS(nodes);
525 dfs.finishingorder=new Vector();
526 if(finishingorder_edge != null) {
527 dfs.finishingorder_edge = new Vector();
529 boolean acyclic=dfs.go();
530 Vector topology = new Vector();
531 for(int i=dfs.finishingorder.size()-1; i>=0; i--) {
532 GraphNode gn=(GraphNode)dfs.finishingorder.get(i);
535 if(finishingorder_edge != null) {
536 for(int i=dfs.finishingorder_edge.size()-1; i>=0; i--) {
537 Edge gn=(Edge)dfs.finishingorder_edge.get(i);
538 finishingorder_edge.add(gn);