copyright notices/updates
[sbp.git] / src / edu / berkeley / sbp / util / GraphViz.java
index 13899bb..07213e5 100644 (file)
@@ -1,3 +1,5 @@
+// Copyright 2006 all rights reserved; see LICENSE file for BSD-style license
+
 package edu.berkeley.sbp.util;
 import edu.berkeley.sbp.util.*;
 import edu.berkeley.sbp.*;
@@ -11,34 +13,67 @@ public class GraphViz {
     IdentityHashMap<ToGraphViz,Node> ihm = new IdentityHashMap<ToGraphViz,Node>();
     HashMap<Node,Group> groups = new HashMap<Node,Group>();
 
-    public class Group {
+    public class Group extends Node {
+        private final int idx = master_idx++;
+        public boolean cluster = false;
+        public boolean primary = true;
         public Group() { }
         public void add(Node n) { groups.put(n, this); }
+        public String name() { return cluster?("cluster_"+idx):("subgraph_"+idx); }
+        public boolean simple() { return false; }
+        public void dump(PrintWriter pw, IdentityHashMap<Node,Node> done) {
+            Group g = this;
+            if (done.get(g)!=null) return;
+            done.put(g,g);
+            pw.println("  subgraph "+name()+" { rank=same;\n");
+            pw.println("  label=\""+StringUtil.escapify(label.toString(), "\\\"\r\n")+"\";\n");
+            pw.println("  color="+g.color+";\n");
+            pw.println("  shape="+g.shape+";\n");
+            for(Node n : groups.keySet())
+                if (groups.get(n)==g)
+                    n.dump(pw, done);
+            pw.println("  }\n");
+        }
     }
 
     private static int master_idx=0;
+
     public class Node {
         private final int idx = master_idx++;
         public String label;
+        public String comment;
         public boolean directed = false;
         public String color="black";
+        public String fill="white";
+        public String shape="ellipse";
         public ArrayList<Node> edges = new ArrayList<Node>();
+        public ArrayList<Object> labels = new ArrayList<Object>();
         public ArrayList<Node> inbound = new ArrayList<Node>();
-        public void edge(ToGraphViz o) {
+        public void edge(ToGraphViz o, Object label) {
             Node n = o.toGraphViz(GraphViz.this);
             if (n==null) return;
             edges.add(n);
+            labels.add(label);
             n.inbound.add(this);
         }
+        public String getParentName() {
+            if (inbound.size()==1 && inbound.get(0).simple())
+                return inbound.get(0).getParentName();
+            return name();
+        }
         public String name() {
             if (inbound.size()==1 && inbound.get(0).simple())
-                return inbound.get(0).name()+":node_"+idx;
+                return inbound.get(0).getParentName()+":node_"+idx;
             return "node_"+idx;
         }
         public void edges(PrintWriter pw) {
             if (simple()) return;
-            for(Node n : edges)
-                pw.println("    "+name()+" -> " + n.name() + " [color="+color+"];\n");
+            for(int i=0; i<edges.size(); i++) {
+                Node n = edges.get(i);
+                Object label = labels.get(i);
+                pw.println("    "+name()+" -> " + n.name() + " [color="+color+" "
+                           +(label==null?"":("label=\""+StringUtil.escapify(label.toString(), "\\\"\r\n")+"\""))+ "];\n");
+            }
         }
         public int numEdges() { return edges.size(); }
         public boolean simple() {
@@ -50,7 +85,9 @@ public class GraphViz {
                     if (n.inbound.size() > 1) { simple = false; break; }
             return simple;
         }
-        public void dump(PrintWriter pw) {
+        public void dump(PrintWriter pw, IdentityHashMap<Node,Node> done) {
+            if (done.get(this)!=null) return;
+            done.put(this, this);
             if (inbound.size() > 0) {
                 boolean good = false;
                 for(Node n : inbound)
@@ -74,16 +111,17 @@ public class GraphViz {
                     if (!first) pw.print("|");
                     first = false;
                     pw.print("<node_"+n.idx+">");
-                    pw.print(StringUtil.escapify(n.label,"\\\""));
+                    pw.print(StringUtil.escapify(n.label,"\\\"\r\n"));
                 }
                 if (!complex) pw.print("}");
-                pw.print("\"");
+                pw.print("\" ");
             } else {
                 pw.print(" label=\"");
-                pw.print(StringUtil.escapify(label,"\\\""));
-                pw.print("\"");
+                pw.print(StringUtil.escapify(label,"\\\"\r\n"));
+                pw.print("\" ");
             }
             pw.print("color="+color);
+            if (comment!=null) pw.print(" comment=\""+StringUtil.escapify(comment,"\\\"\r\n")+"\" ");
             pw.print("];\n");
         }
     }
@@ -100,30 +138,39 @@ public class GraphViz {
         return n;
     }
 
+    public Group createGroup(ToGraphViz o) {
+        Group n = (Group)ihm.get(o);
+        if (n!=null) return n;
+        n = new Group();
+        ihm.put(o, n);
+        return n;
+    }
+
     public static interface ToGraphViz {
-        public Node    toGraphViz(GraphViz gv);
-        public boolean isTransparent();
-        public boolean isHidden();
+        Node    toGraphViz(GraphViz gv);
+        boolean isTransparent();
+        boolean isHidden();
+    }
+
+    public void show() throws IOException {
+        Runtime.getRuntime().exec(new String[] { "dot", "-Tsvg" });
     }
 
+    public void dump(OutputStream os) { dump(new PrintWriter(new OutputStreamWriter(os))); }
     public void dump(PrintWriter pw) {
         IdentityHashMap<Node,Node> done = new IdentityHashMap<Node,Node>();
-        pw.println("digraph G { rankdir=LR; \n");
-        for(Group g : groups.values()) {
-            pw.println("  { rank=same;\n");
-            for(Node n : groups.keySet())
-                if (groups.get(n)==g) {
-                    done.put(n,n);
-                    n.dump(pw);
-                }
-            pw.println("  }\n");
-        }
+        pw.println("digraph G { rankdir=LR; ordering=out; compound=true; \n");
+        for(Group g : groups.values())
+            if (g.primary)
+                g.dump(pw, done);
         for(Node n : ihm.values()) {
             if (done.get(n)!=null) continue;
-            n.dump(pw);
+            if (n instanceof Group) continue;
+            n.dump(pw, done);
         }
         for(Node n : ihm.values()) n.edges(pw);
         pw.println("}\n");
+        pw.flush();
     }
 
 }