source: trunk/EventBenchCore/src/de/ugoe/cs/eventbench/models/TrieNode.java @ 258

Last change on this file since 258 was 258, checked in by sherbold, 13 years ago
  • added methods getChildren() and setCount() to de.ugoe.cs.eventbench.models.TrieNode?
  • added method updateKnownSymbols() to de.ugoe.cs.eventbench.models.Trie
  • changed the visibility of some members of de.ugoe.cs.eventbench.models.PredictionByPartionMatch?
  • added class de.ugoe.cs.eventbench.models.ModelFlattener? to generate FirstOrderMarkovModel? from higher-order models through state splitting
  • tweaked entropy calculation of de.ugoe.cs.eventbench.models.FirstOrderMarkovModel? to work with flattened models (locating of START and END was a problem)
File size: 8.9 KB
Line 
1package de.ugoe.cs.eventbench.models;
2
3import java.io.Serializable;
4import java.security.InvalidParameterException;
5import java.util.Collection;
6import java.util.LinkedList;
7import java.util.List;
8import java.util.Set;
9
10import de.ugoe.cs.eventbench.models.Trie.Edge;
11import de.ugoe.cs.eventbench.models.Trie.TrieVertex;
12import de.ugoe.cs.util.StringTools;
13import edu.uci.ics.jung.graph.DelegateTree;
14import edu.uci.ics.jung.graph.Tree;
15
16/**
17 * <p>
18 * This class implements a node of a trie. Each node is associated with a symbol
19 * and has a counter. The counter marks the number of occurences of the sequence
20 * defined by the path from the root of the trie to this node.
21 * </p>
22 *
23 * @author Steffen Herbold
24 *
25 * @param <T>
26 *            Type of the symbols that are stored in the trie.
27 * @see Trie
28 */
29class TrieNode<T> implements Serializable {
30
31        /**
32         * <p>
33         * Id for object serialization.
34         * </p>
35         */
36        private static final long serialVersionUID = 1L;
37
38        /**
39         * <p>
40         * Counter for the number of occurences of the sequence.
41         * </p>
42         */
43        private int count;
44
45        /**
46         * <p>
47         * Symbol associated with the node.
48         * </p>
49         */
50        private final T symbol;
51
52        /**
53         * <p>
54         * Child nodes of this node. If the node is a leaf this collection is empty.
55         * </p>
56         */
57        private Collection<TrieNode<T>> children;
58
59        /**
60         * <p>
61         * Constructor. Creates a new TrieNode without a symbol associated.<br>
62         * <b>This constructor should only be used to create the root node of the
63         * trie!</b>
64         * </p>
65         */
66        TrieNode() {
67                this.symbol = null;
68                count = 0;
69                children = new LinkedList<TrieNode<T>>();
70        }
71
72        /**
73         * <p>
74         * Constructor. Creates a new TrieNode. The symbol must not be null.
75         * </p>
76         *
77         * @param symbol
78         *            symbol associated with the trie node
79         */
80        public TrieNode(T symbol) {
81                if (symbol == null) {
82                        throw new InvalidParameterException(
83                                        "symbol must not be null. null is reserved for root node!");
84                }
85                this.symbol = symbol;
86                count = 0;
87                children = new LinkedList<TrieNode<T>>();
88        }
89
90        /**
91         * <p>
92         * Adds a given subsequence to the trie and increases the counters
93         * accordingly.
94         * </p>
95         *
96         * @param subsequence
97         *            subsequence whose counters are increased
98         * @see Trie#add(List)
99         */
100        public void add(List<T> subsequence) {
101                if (!subsequence.isEmpty()) {
102                        if (!symbol.equals(subsequence.get(0))) { // should be guaranteed by
103                                                                                                                // the
104                                                                                                                // recursion/TrieRoot!
105                                throw new AssertionError("Invalid trie operation!");
106                        }
107                        count++;
108                        subsequence.remove(0);
109                        if (!subsequence.isEmpty()) {
110                                T nextSymbol = subsequence.get(0);
111                                getChildCreate(nextSymbol).add(subsequence);
112                        }
113                }
114        }
115
116        /**
117         * <p>
118         * Returns the symbol associated with the node.
119         * </p>
120         *
121         * @return symbol associated with the node
122         */
123        public T getSymbol() {
124                return symbol;
125        }
126
127        /**
128         * <p>
129         * Returns the number of occurences of the sequence represented by the node.
130         * </p>
131         *
132         * @return number of occurences of the sequence represented by the node
133         */
134        public int getCount() {
135                return count;
136        }
137
138        /**
139         * <p>
140         * Returns the child of the node associated with the given symbol or creates
141         * it if it does not exist yet.
142         * </p>
143         *
144         * @param symbol
145         *            symbol whose node is required
146         * @return node associated with the symbol
147         * @see Trie#getChildCreate(Object)
148         */
149        protected TrieNode<T> getChildCreate(T symbol) {
150                TrieNode<T> node = getChild(symbol);
151                if (node == null) {
152                        node = new TrieNode<T>(symbol);
153                        children.add(node);
154                }
155                return node;
156        }
157
158        /**
159         * <p>
160         * Returns the child of the node associated with the given symbol or null if
161         * it does not exist.
162         * </p>
163         *
164         * @param symbol
165         *            symbol whose node is required
166         * @return node associated with the symbol; null if no such node exists
167         * @see Trie#getChild(Object)
168         */
169        protected TrieNode<T> getChild(T symbol) {
170                for (TrieNode<T> child : children) {
171                        if (child.getSymbol().equals(symbol)) {
172                                return child;
173                        }
174                }
175                return null;
176        }
177
178        /**
179         * <p>
180         * Returns all children of this node.
181         * </p>
182         *
183         * @return children of this node
184         */
185        protected Collection<TrieNode<T>> getChildren() {
186                return children;
187        }
188
189        /**
190         * <p>
191         * Searches the sub-trie of this trie node for a given sequence and returns
192         * the node associated with the sequence or null if no such node is found.
193         * </p>
194         *
195         * @param sequence
196         *            sequence that is searched for
197         * @return node associated with the sequence
198         * @see Trie#find(List)
199         */
200        public TrieNode<T> find(List<T> subsequence) {
201                TrieNode<T> result = null;
202                if (subsequence.isEmpty()) {
203                        result = this;
204                } else {
205                        TrieNode<T> node = getChild(subsequence.get(0));
206                        if (node != null) {
207                                subsequence.remove(0);
208                                result = node.find(subsequence);
209                        }
210                }
211                return result;
212        }
213
214        /**
215         * <p>
216         * Returns a collection of all symbols that follow a this node, i.e., the
217         * symbols associated with the children of this node.
218         * </p>
219         *
220         * @return symbols follow this node
221         * @see TrieNode#getFollowingSymbols()
222         */
223        public Collection<T> getFollowingSymbols() {
224                Collection<T> followingSymbols = new LinkedList<T>();
225                for (TrieNode<T> child : children) {
226                        followingSymbols.add(child.getSymbol());
227                }
228                return followingSymbols;
229        }
230
231        /**
232         * <p>
233         * The string representation of a node is {@code symbol.toString()#count}
234         * </p>
235         *
236         * @see java.lang.Object#toString()
237         */
238        @Override
239        public String toString() {
240                String str = symbol.toString() + " #" + count;
241                if (!children.isEmpty()) {
242                        str += StringTools.ENDLINE + children.toString();
243                }
244                return str;
245        }
246
247        /**
248         * <p>
249         * Generates a {@link Tree} represenation of the trie.
250         * </p>
251         *
252         * @param parent
253         *            parent vertex in the generated tree
254         * @param graph
255         *            complete tree
256         */
257        void getGraph(TrieVertex parent, DelegateTree<TrieVertex, Edge> graph) {
258                TrieVertex currentVertex;
259                if (isRoot()) {
260                        currentVertex = new TrieVertex("root");
261                        graph.addVertex(currentVertex);
262                } else {
263                        currentVertex = new TrieVertex(getSymbol().toString() + "#"
264                                        + getCount());
265                        graph.addChild(new Edge(), parent, currentVertex);
266                }
267                for (TrieNode<T> node : children) {
268                        node.getGraph(currentVertex, graph);
269                }
270        }
271
272        /**
273         * <p>
274         * Appends the current node to the dot representation of the trie.
275         * </p>
276         *
277         * @param stringBuilder
278         *            {@link StringBuilder} to which the dot representation is
279         *            appended
280         */
281        void appendDotRepresentation(StringBuilder stringBuilder) {
282                String thisSaneId;
283                if (isRoot()) {
284                        thisSaneId = "root";
285                } else {
286                        thisSaneId = symbol.toString().replace("\"", "\\\"")
287                                        .replaceAll("[\r\n]", "")
288                                        + "#" + count;
289                }
290                stringBuilder.append(" " + hashCode() + " [label=\"" + thisSaneId
291                                + "\"];" + StringTools.ENDLINE);
292                for (TrieNode<T> childNode : children) {
293                        stringBuilder.append(" " + hashCode() + " -> "
294                                        + childNode.hashCode() + ";" + StringTools.ENDLINE);
295                }
296                for (TrieNode<T> childNode : children) {
297                        childNode.appendDotRepresentation(stringBuilder);
298                }
299        }
300
301        /**
302         * <p>
303         * Checks if the node is a leaf.
304         * </p>
305         *
306         * @return true if the node is a leaf, false otherwise.
307         */
308        protected boolean isLeaf() {
309                return children.isEmpty();
310        }
311
312        /**
313         * <p>
314         * Checks if the node is the root.
315         * </p>
316         *
317         * @return true if the node is the root of the trie, false otherwise
318         */
319        protected boolean isRoot() {
320                return symbol == null;
321        }
322
323        /**
324         * <p>
325         * Recursive methods that collects all nodes that are ancestors of leafs and
326         * stores them in the set.
327         * </p>
328         *
329         * @param ancestors
330         *            set of all ancestors of leafs
331         */
332        protected void getLeafAncestors(Set<TrieNode<T>> ancestors) {
333                boolean isAncestor = false;
334                for (TrieNode<T> child : children) {
335                        child.getLeafAncestors(ancestors);
336                        isAncestor |= child.isLeaf();
337                }
338                if (isAncestor) {
339                        ancestors.add(this);
340                }
341        }
342
343        /**
344         * <p>
345         * Returns the number of descendants of this node that are leafs. This does
346         * not only include direct children of this node, but all leafs in the
347         * sub-trie with this node as root.
348         * </p>
349         *
350         * @return number of leafs in this sub-trie
351         */
352        protected int getNumLeafs() {
353                int numLeafs = 0;
354                for (TrieNode<T> child : children) {
355                        if (child.isLeaf()) {
356                                numLeafs++;
357                        } else {
358                                numLeafs += child.getNumLeafs();
359                        }
360                }
361                return numLeafs;
362        }
363
364        /**
365         * <p>
366         * Sets the {@link #count} of this node.
367         * </p>
368         * <p>
369         * This function should only be used sparingly and very carefully! The count
370         * is usually maintained automatically by the training procedures.
371         * </p>
372         *
373         * @param count
374         *            new count
375         */
376        protected void setCount(int count) {
377                this.count = count;
378        }
379}
Note: See TracBrowser for help on using the repository browser.