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

Last change on this file since 129 was 129, checked in by sherbold, 13 years ago
  • renamed de.ugoe.cs.eventbench.models.IStochasticProcess.getNumStates() to getNumSymbols()
  • renamed de.ugoe.cs.eventbench.models.IStochasticProcess.getStateStrings() to getSymbolStrings()

+ added de.ugoe.cs.eventbench.models.IStochasticProcess.getNumFOMStates(); this function returns the number states an equivalent first-order Markov model would have
+ added methods that count the ancestors of trie leaves, which is in turn used to determine the FOM-equivalent

File size: 7.7 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         * Searches the sub-trie of this trie node for a given sequence and returns
181         * the node associated with the sequence or null if no such node is found.
182         * </p>
183         *
184         * @param sequence
185         *            sequence that is searched for
186         * @return node associated with the sequence
187         * @see Trie#find(List)
188         */
189        public TrieNode<T> find(List<T> subsequence) {
190                TrieNode<T> result = null;
191                if (subsequence.isEmpty()) {
192                        result = this;
193                } else {
194                        TrieNode<T> node = getChild(subsequence.get(0));
195                        if (node != null) {
196                                subsequence.remove(0);
197                                result = node.find(subsequence);
198                        }
199                }
200                return result;
201        }
202
203        /**
204         * <p>
205         * Returns a collection of all symbols that follow a this node, i.e., the
206         * symbols associated with the children of this node.
207         * </p>
208         *
209         * @return symbols follow this node
210         * @see TrieNode#getFollowingSymbols()
211         */
212        public Collection<T> getFollowingSymbols() {
213                Collection<T> followingSymbols = new LinkedList<T>();
214                for (TrieNode<T> child : children) {
215                        followingSymbols.add(child.getSymbol());
216                }
217                return followingSymbols;
218        }
219
220        /**
221         * <p>
222         * The string representation of a node is {@code symbol.toString()#count}
223         * </p>
224         *
225         * @see java.lang.Object#toString()
226         */
227        @Override
228        public String toString() {
229                String str = symbol.toString() + " #" + count;
230                if (!children.isEmpty()) {
231                        str += StringTools.ENDLINE + children.toString();
232                }
233                return str;
234        }
235
236        /**
237         * <p>
238         * Generates a {@link Tree} represenation of the trie.
239         * </p>
240         *
241         * @param parent
242         *            parent vertex in the generated tree
243         * @param graph
244         *            complete tree
245         */
246        void getGraph(TrieVertex parent, DelegateTree<TrieVertex, Edge> graph) {
247                TrieVertex currentVertex;
248                if (symbol == null) {
249                        currentVertex = new TrieVertex("root");
250                        graph.addVertex(currentVertex);
251                } else {
252                        currentVertex = new TrieVertex(getSymbol().toString() + "#"
253                                        + getCount());
254                        graph.addChild(new Edge(), parent, currentVertex);
255                }
256                for (TrieNode<T> node : children) {
257                        node.getGraph(currentVertex, graph);
258                }
259        }
260
261        /**
262         * <p>
263         * Appends the current node to the dot representation of the trie.
264         * </p>
265         *
266         * @param stringBuilder
267         *            {@link StringBuilder} to which the dot representation is
268         *            appended
269         */
270        void appendDotRepresentation(StringBuilder stringBuilder) {
271                String thisSaneId;
272                if (symbol == null) {
273                        thisSaneId = "root";
274                } else {
275                        thisSaneId = symbol.toString().replace("\"", "\\\"")
276                                        .replaceAll("[\r\n]", "")
277                                        + "#" + count;
278                }
279                stringBuilder.append(" " + hashCode() + " [label=\"" + thisSaneId
280                                + "\"];" + StringTools.ENDLINE);
281                for (TrieNode<T> childNode : children) {
282                        stringBuilder.append(" " + hashCode() + " -> "
283                                        + childNode.hashCode() + ";" + StringTools.ENDLINE);
284                }
285                for (TrieNode<T> childNode : children) {
286                        childNode.appendDotRepresentation(stringBuilder);
287                }
288        }
289
290        /**
291         * <p>
292         * Checks if the node is a leaf.
293         * </p>
294         *
295         * @return true if the node is a leaf, false otherwise.
296         */
297        protected boolean isLeaf() {
298                return children.isEmpty();
299        }
300
301        /**
302         * <p>
303         * Recursive methods that collects all nodes that are ancestors of leafs and
304         * stores them in the set.
305         * </p>
306         *
307         * @param ancestors
308         *            set of all ancestors of leafs
309         */
310        protected void getLeafAncestors(Set<TrieNode<T>> ancestors) {
311                boolean isAncestor = false;
312                for (TrieNode<T> child : children) {
313                        child.getLeafAncestors(ancestors);
314                        isAncestor |= child.isLeaf();
315                }
316                if (isAncestor) {
317                        ancestors.add(this);
318                }
319        }
320}
Note: See TracBrowser for help on using the repository browser.