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

Last change on this file since 351 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
RevLine 
[13]1package de.ugoe.cs.eventbench.models;
[1]2
[86]3import java.io.Serializable;
[1]4import java.security.InvalidParameterException;
[102]5import java.util.Collection;
[1]6import java.util.LinkedList;
7import java.util.List;
[129]8import java.util.Set;
[1]9
[13]10import de.ugoe.cs.eventbench.models.Trie.Edge;
11import de.ugoe.cs.eventbench.models.Trie.TrieVertex;
[1]12import de.ugoe.cs.util.StringTools;
[5]13import edu.uci.ics.jung.graph.DelegateTree;
[106]14import edu.uci.ics.jung.graph.Tree;
[1]15
[106]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 {
[1]30
[86]31        /**
[106]32         * <p>
[86]33         * Id for object serialization.
[106]34         * </p>
[86]35         */
36        private static final long serialVersionUID = 1L;
[106]37
38        /**
39         * <p>
40         * Counter for the number of occurences of the sequence.
41         * </p>
42         */
[1]43        private int count;
[106]44
45        /**
46         * <p>
47         * Symbol associated with the node.
48         * </p>
49         */
[1]50        private final T symbol;
[106]51
52        /**
53         * <p>
54         * Child nodes of this node. If the node is a leaf this collection is empty.
55         * </p>
56         */
[102]57        private Collection<TrieNode<T>> children;
[106]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         */
[6]66        TrieNode() {
67                this.symbol = null;
68                count = 0;
69                children = new LinkedList<TrieNode<T>>();
70        }
[106]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         */
[1]80        public TrieNode(T symbol) {
[106]81                if (symbol == null) {
82                        throw new InvalidParameterException(
83                                        "symbol must not be null. null is reserved for root node!");
[1]84                }
85                this.symbol = symbol;
86                count = 0;
87                children = new LinkedList<TrieNode<T>>();
88        }
89
[106]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         */
[1]100        public void add(List<T> subsequence) {
[106]101                if (!subsequence.isEmpty()) {
102                        if (!symbol.equals(subsequence.get(0))) { // should be guaranteed by
103                                                                                                                // the
104                                                                                                                // recursion/TrieRoot!
[1]105                                throw new AssertionError("Invalid trie operation!");
106                        }
107                        count++;
108                        subsequence.remove(0);
[106]109                        if (!subsequence.isEmpty()) {
[1]110                                T nextSymbol = subsequence.get(0);
111                                getChildCreate(nextSymbol).add(subsequence);
112                        }
113                }
114        }
[106]115
116        /**
117         * <p>
118         * Returns the symbol associated with the node.
119         * </p>
120         *
121         * @return symbol associated with the node
122         */
[1]123        public T getSymbol() {
124                return symbol;
125        }
[106]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         */
[1]134        public int getCount() {
135                return count;
136        }
[106]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) {
[1]150                TrieNode<T> node = getChild(symbol);
[106]151                if (node == null) {
[1]152                        node = new TrieNode<T>(symbol);
153                        children.add(node);
154                }
155                return node;
156        }
[106]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         */
[1]169        protected TrieNode<T> getChild(T symbol) {
[106]170                for (TrieNode<T> child : children) {
171                        if (child.getSymbol().equals(symbol)) {
[1]172                                return child;
173                        }
174                }
175                return null;
176        }
177
[106]178        /**
179         * <p>
[258]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>
[106]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         */
[1]200        public TrieNode<T> find(List<T> subsequence) {
201                TrieNode<T> result = null;
[106]202                if (subsequence.isEmpty()) {
[1]203                        result = this;
204                } else {
205                        TrieNode<T> node = getChild(subsequence.get(0));
[106]206                        if (node != null) {
[1]207                                subsequence.remove(0);
208                                result = node.find(subsequence);
209                        }
210                }
211                return result;
212        }
[106]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         */
[102]223        public Collection<T> getFollowingSymbols() {
224                Collection<T> followingSymbols = new LinkedList<T>();
[106]225                for (TrieNode<T> child : children) {
[1]226                        followingSymbols.add(child.getSymbol());
227                }
228                return followingSymbols;
229        }
[106]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         */
[1]238        @Override
239        public String toString() {
[106]240                String str = symbol.toString() + " #" + count;
241                if (!children.isEmpty()) {
[1]242                        str += StringTools.ENDLINE + children.toString();
243                }
[106]244                return str;
[1]245        }
246
[106]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) {
[6]258                TrieVertex currentVertex;
[251]259                if (isRoot()) {
[6]260                        currentVertex = new TrieVertex("root");
261                        graph.addVertex(currentVertex);
262                } else {
[106]263                        currentVertex = new TrieVertex(getSymbol().toString() + "#"
264                                        + getCount());
265                        graph.addChild(new Edge(), parent, currentVertex);
[6]266                }
[106]267                for (TrieNode<T> node : children) {
[6]268                        node.getGraph(currentVertex, graph);
[106]269                }
[5]270        }
[106]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         */
[30]281        void appendDotRepresentation(StringBuilder stringBuilder) {
282                String thisSaneId;
[251]283                if (isRoot()) {
[30]284                        thisSaneId = "root";
285                } else {
[106]286                        thisSaneId = symbol.toString().replace("\"", "\\\"")
287                                        .replaceAll("[\r\n]", "")
288                                        + "#" + count;
[30]289                }
[106]290                stringBuilder.append(" " + hashCode() + " [label=\"" + thisSaneId
291                                + "\"];" + StringTools.ENDLINE);
292                for (TrieNode<T> childNode : children) {
293                        stringBuilder.append(" " + hashCode() + " -> "
294                                        + childNode.hashCode() + ";" + StringTools.ENDLINE);
[30]295                }
[106]296                for (TrieNode<T> childNode : children) {
[30]297                        childNode.appendDotRepresentation(stringBuilder);
298                }
299        }
[129]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        }
[258]311
[251]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() {
[258]320                return symbol == null;
[251]321        }
[129]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        }
[258]342
[248]343        /**
[258]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.
[248]348         * </p>
[258]349         *
350         * @return number of leafs in this sub-trie
[248]351         */
352        protected int getNumLeafs() {
353                int numLeafs = 0;
[258]354                for (TrieNode<T> child : children) {
355                        if (child.isLeaf()) {
[248]356                                numLeafs++;
357                        } else {
358                                numLeafs += child.getNumLeafs();
359                        }
360                }
361                return numLeafs;
362        }
[258]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        }
[1]379}
Note: See TracBrowser for help on using the repository browser.