645850b00c397339ed658b306abcacb680967eb6
[sbp.git] / src / edu / berkeley / sbp / Forest.java
1 package edu.berkeley.sbp;
2 import edu.berkeley.sbp.*;
3 import edu.berkeley.sbp.Sequence.Position;
4 import edu.berkeley.sbp.util.*;
5 import java.io.*;
6 import java.util.*;
7 import java.lang.reflect.*;
8
9 /**
10  *   An efficient representation of a collection of trees (Tomita's
11  *   shared packed parse forest).
12  */
13 public abstract class Forest<T> implements GraphViz.ToGraphViz {
14
15     /** assume that this forest contains exactly one tree and return it; otherwise throw an exception */
16     public abstract Tree<T> expand1() throws Ambiguous;
17
18     /** expand this forest into a set of trees */
19     public void expand(HashSet<Tree<T>> ht) { expand(ht, new HashSet<Forest<T>>(), null); }
20
21     /** create a new forest */
22     public static <T> Forest<T> create(Input.Region loc, T head, Forest<T>[] children, boolean lift) {
23         return new One<T>(loc, head, children, lift);
24     }
25
26     // Package-Private //////////////////////////////////////////////////////////////////////////////
27
28     abstract void expand(HashSet<Tree<T>> ht, HashSet<Forest<T>> ignore, Tree<T> bogus);
29     abstract void gather(HashSet<Forest<T>> ignore);
30     boolean ambiguous() { return false; }
31
32     public abstract void edges(GraphViz.Node n);
33
34
35     // One //////////////////////////////////////////////////////////////////////////////
36
37     /** A "single" forest with a head and child subforests */    
38     private static class One<T> extends Forest<T> {
39
40         private final Input.Region      location;
41         private final T                 head;
42         private final Forest<T>[]       children;
43
44         /** if true, the last child's children are considered children of this node */
45         private final boolean           lift;
46
47         private One(Input.Region loc, T head, Forest<T>[] children, boolean lift) {
48             this.location = loc;
49             this.head = head;
50             this.children = children==null ? emptyForestArray : new Forest[children.length];
51             if (children != null) System.arraycopy(children, 0, this.children, 0, children.length);
52             if (children != null) for(int i=0; i<children.length; i++) if (children[i]==null) throw new Error(i+"");
53             this.lift = lift;
54         }
55
56         public Tree<T> expand1() throws Ambiguous {
57             Tree<T>[] ret = new Tree[children.length];
58             for(int i=0; i<children.length; i++) ret[i] = children[i].expand1();
59             return new Tree<T>(location, head, ret, lift);
60         }
61
62         void gather(HashSet<Forest<T>> hf) {
63             hf.add(this);
64             for(Forest<T> f : children) f.gather(hf);
65         }
66         void expand(HashSet<Tree<T>> ht, HashSet<Forest<T>> ignore, Tree<T> bogus) {
67             if (ignore.contains(this)) { ht.add(bogus); return; }
68             expand(0, new Tree[children.length], ht, ignore, bogus);
69         }
70         private void expand(final int i, Tree<T>[] ta, HashSet<Tree<T>> ht, HashSet<Forest<T>> ignore, Tree<T> bogus) {
71             if (i==children.length) {
72                 ht.add(new Tree<T>(location, head, ta, lift));
73             } else {
74                 HashSet<Tree<T>> ht2 = new HashSet<Tree<T>>();
75                 children[i].expand(ht2, ignore, bogus);
76                 for(Tree<T> tc : ht2) {
77                     ta[i] = tc;
78                     expand(i+1, ta, ht, ignore, bogus);
79                     ta[i] = null;
80                 }
81             }
82         }
83
84         // GraphViz, ToInt //////////////////////////////////////////////////////////////////////////////
85
86         public boolean isTransparent() { return false; }
87         public boolean isHidden() { return false; }
88         public GraphViz.Node toGraphViz(GraphViz gv) {
89             if (gv.hasNode(this)) return gv.createNode(this);
90             GraphViz.Node n = gv.createNode(this);
91             n.label = headToString()==null?"":headToString();
92             n.directed = true;
93             edges(n);
94             return n;
95         }
96         boolean edges = false; // FIXME ??
97         public void edges(GraphViz.Node n) {
98             if (edges) return;
99             edges = true;
100             for(int i=0; i<children.length; i++) {
101                 if (i==children.length-1 && lift && !children[i].ambiguous()) {
102                     children[i].edges(n);
103                 } else {
104                     n.edge(children[i], null);
105                 }
106             }
107         }
108
109         protected String  headToString()         { return head==null?null:head.toString(); }
110         protected String  headToJava()           { return "null"; }
111         protected String  left()                 { return "{"; }
112         protected String  right()                { return "}"; }
113         protected boolean ignoreSingleton()      { return false; }
114     }
115
116
117     // Many //////////////////////////////////////////////////////////////////////////////
118
119     /** An "ambiguity node"; this is immutable once it has been "looked at" */
120     static class Many<T> extends Forest<T> {
121
122         HashSet<GSS.Phase.Node> parents = new HashSet<GSS.Phase.Node>();
123         private FastSet<Forest<T>> hp = new FastSet<Forest<T>>();
124         private boolean touched = false;
125
126         public Many() { }
127
128         public Tree<T> expand1() throws Ambiguous {
129             touched();
130             if (hp.size() > 1) {
131                 HashSet<Forest<T>> hf0 = new HashSet<Forest<T>>();
132                 Iterator<Forest<T>> ih = hp.iterator();
133                 ih.next().gather(hf0);
134                 for(Forest<T> f : hp) {
135                     HashSet<Forest<T>> hf1 = new HashSet<Forest<T>>();
136                     f.gather(hf1);
137                     hf0.retainAll(hf1);
138                 }
139                 HashSet<Tree<T>> ht = new HashSet<Tree<T>>();
140                 expand(ht, hf0, new Tree(null, "*"));
141                 throw new Ambiguous((Forest<?>)this,
142                                     (HashSet<Tree<?>>)(Object)ht);
143             }
144             return hp.iterator().next().expand1();
145         }
146         
147         void gather(HashSet<Forest<T>> ht) {
148             touched();
149             ht.add(this);
150             for(Forest<T> f : hp) f.gather(ht);
151         }
152
153         private void touched() {
154             if (touched) return;
155             touched = true;
156             /*
157             FastSet<Forest<T>> f2 = new FastSet<Forest<T>>();
158             for(Forest f : hp)
159                 if (f instanceof Forest.One) f2.add(f);
160                 else for(Forest ff : ((Forest.Many<T>)f))
161                     f2.add(ff);
162             hp = f2;
163             */
164         }
165         public boolean contains(Forest f) {
166             touched();
167             return hp.contains(f);
168         }
169         public void merge(Forest p) { 
170             if (touched) throw new RuntimeException("attempt to merge() on a Forest.Many that has already been examined");
171             if (p==this) throw new RuntimeException("attempt to merge() a Forest.Many to itself!");
172             hp.add(p, true);
173         }
174         boolean ambiguous() {
175             touched();
176             if (hp.size()==0) return false;
177             if (hp.size()==1) return hp.iterator().next().ambiguous();
178             return true;
179         }
180
181         void expand(HashSet<Tree<T>> ht, HashSet<Forest<T>> ignore, Tree<T> bogus) {
182             touched();
183             if (ignore.contains(this)) { ht.add(bogus); return; }
184             for (Forest<T> f : hp) f.expand(ht, ignore, bogus);
185         }
186
187
188         // GraphViz, ToInt //////////////////////////////////////////////////////////////////////////////
189
190         public boolean isTransparent() { return hp.size()==1; }
191         public boolean isHidden() { return hp.size()==0; }
192         public void edges(GraphViz.Node n) {
193             if (hp.size()==1) { hp.iterator().next().edges(n); return; }
194             for(Forest f : hp) f.edges(n);
195         }
196         public GraphViz.Node toGraphViz(GraphViz gv) {
197             if (hp.size()==1) return hp.iterator().next().toGraphViz(gv);
198             if (gv.hasNode(this)) return gv.createNode(this);
199             GraphViz.Node n = gv.createNode(this);
200             n.label = "?";
201             n.color = "red";
202             for(Forest f : hp) n.edge(f, null);
203             return n;
204         }
205     }
206
207     // Statics //////////////////////////////////////////////////////////////////////////////
208
209     private static Tree[] tree_hint = new Tree[0];
210     private static String[] string_hint = new String[0];
211     private static final Forest[] emptyForestArray = new Forest[0];
212
213     protected String  headToString()    { return null; }
214     protected String  headToJava()      { return "null"; }
215     protected String  left()            { return "<?"; }
216     protected String  right()           { return "?>"; }
217     protected boolean ignoreSingleton() { return true; }
218 }