Changeset 1060
- Timestamp:
- 02/07/13 17:57:07 (12 years ago)
- Location:
- trunk
- Files:
-
- 2 added
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/autoquest-core-usageprofiles-test/src/test/java/de/ugoe/cs/autoquest/usageprofiles/TrieTest.java
r927 r1060 75 75 @Test(expected = java.lang.IllegalArgumentException.class) 76 76 public void testTrie_3() throws Exception { 77 new Trie<String>(null); 78 } 77 new Trie<String>((SymbolComparator<String>) null); 78 } 79 80 @Test(expected = java.lang.IllegalArgumentException.class) 81 public void testTrie_4() throws Exception { 82 new Trie<String>((Trie<String>) null); 83 } 79 84 80 85 @Test … … 240 245 assertEquals(0, result.size()); 241 246 } 247 248 @Test 249 public void testGetSequencesWithMostOccurrences_1() throws Exception { 250 Trie<String> fixture = new Trie<String>(); 251 fixture.train(sequence, 3); 252 253 List<String> expected = new ArrayList<String>(); 254 expected.add("a"); 255 256 Collection<List<String>> result = fixture.getSequencesWithMostOccurrences(1); 257 258 assertEquals(1, result.size()); 259 ListAssert.assertEquals(expected, result.iterator().next()); 260 } 261 262 @Test 263 public void testGetSequencesWithMostOccurrences_2() throws Exception { 264 Trie<String> fixture = new Trie<String>(); 265 fixture.train(sequence, 3); 266 267 Collection<List<String>> result = fixture.getSequencesWithMostOccurrences(2); 268 269 assertEquals(5, result.size()); 270 271 List<String> expected = new ArrayList<String>(); 272 expected.add("a"); 273 expected.add("b"); 274 ListAssert.assertContains((List<List<String>>) result, expected); 275 276 expected.add("r"); 277 ListAssert.assertContains((List<List<String>>) result, expected); 278 279 expected.clear(); 280 expected.add("b"); 281 expected.add("r"); 282 ListAssert.assertContains((List<List<String>>) result, expected); 283 284 expected.add("a"); 285 ListAssert.assertContains((List<List<String>>) result, expected); 286 287 expected.clear(); 288 expected.add("r"); 289 expected.add("a"); 290 ListAssert.assertContains((List<List<String>>) result, expected); 291 } 292 293 @Test 294 public void testGetSequencesWithMostOccurrences_3() throws Exception { 295 Trie<String> fixture = new Trie<String>(); 296 fixture.train(sequence, 3); 297 298 Collection<List<String>> result = fixture.getSequencesWithMostOccurrences(3); 299 300 assertEquals(2, result.size()); 301 302 List<String> expected = new ArrayList<String>(); 303 expected.add("a"); 304 expected.add("b"); 305 expected.add("r"); 306 ListAssert.assertContains((List<List<String>>) result, expected); 307 308 expected.clear(); 309 expected.add("b"); 310 expected.add("r"); 311 expected.add("a"); 312 ListAssert.assertContains((List<List<String>>) result, expected); 313 } 314 315 @Test 316 public void testGetSequencesWithMostOccurrences_4() throws Exception { 317 Trie<String> fixture = new Trie<String>(); 318 fixture.train(sequence, 3); 319 320 Collection<List<String>> result = fixture.getSequencesWithMostOccurrences(4); 321 322 assertEquals(0, result.size()); 323 } 242 324 243 325 @Test -
trunk/autoquest-core-usageprofiles/src/main/java/de/ugoe/cs/autoquest/usageprofiles/Trie.java
r927 r1060 34 34 * </p> 35 35 * 36 * @author Steffen Herbold 36 * @author Steffen Herbold, Patrick Harms 37 37 * 38 38 * @param <T> … … 66 66 /** 67 67 * <p> 68 * Contructor. Creates a new Trie. 68 * Comparator to be used for comparing the symbols with each other 69 * </p> 70 */ 71 private SymbolComparator<T> comparator; 72 73 /** 74 * <p> 75 * Contructor. Creates a new Trie with a {@link DefaultSymbolComparator}. 69 76 * </p> 70 77 */ 71 78 public Trie() { 72 rootNode = new TrieNode<T>(); 79 this(new DefaultSymbolComparator<T>()); 80 } 81 82 /** 83 * <p> 84 * Contructor. Creates a new Trie with that uses a specific {@link SymbolComparator}. 85 * </p> 86 */ 87 public Trie(SymbolComparator<T> comparator) { 88 this.comparator = comparator; 89 rootNode = new TrieNode<T>(comparator); 73 90 knownSymbols = new LinkedHashSet<T>(); 74 91 } … … 76 93 /** 77 94 * <p> 78 * Copy-Constructor. Creates a new Trie as the copy of other. The other trie must no chbe null.95 * Copy-Constructor. Creates a new Trie as the copy of other. The other trie must not be null. 79 96 * </p> 80 97 * … … 88 105 rootNode = new TrieNode<T>(other.rootNode); 89 106 knownSymbols = new LinkedHashSet<T>(other.knownSymbols); 107 comparator = other.comparator; 90 108 } 91 109 … … 120 138 for (T currentEvent : sequence) { 121 139 latestActions.add(currentEvent); 122 knownSymbols.add(currentEvent);140 addToKnownSymbols(currentEvent); 123 141 i++; 124 142 if (i >= maxOrder) { … … 143 161 protected void add(List<T> subsequence) { 144 162 if (subsequence != null && !subsequence.isEmpty()) { 145 knownSymbols.addAll(subsequence);163 addToKnownSymbols(subsequence); 146 164 subsequence = new LinkedList<T>(subsequence); // defensive copy! 147 165 T firstSymbol = subsequence.get(0); … … 306 324 /** 307 325 * <p> 326 * returns a list of symbol sequences which have a minimal length and that occurred most often 327 * with the same number of occurrences. The resulting list is empty, if there is no symbol 328 * sequence with the minimal length. 329 * </p> 330 * 331 * @param minimalLength the minimal length of the returned sequences 332 * 333 * @return as described 334 */ 335 public Collection<List<T>> getSequencesWithMostOccurrences(int minimalLength) { 336 LinkedList<TrieNode<T>> context = new LinkedList<TrieNode<T>>(); 337 Collection<List<TrieNode<T>>> paths = new LinkedList<List<TrieNode<T>>>(); 338 339 context.push(rootNode); 340 341 // traverse the trie and determine all sequences, which have the maximum number of 342 // occurrences and a minimal length. 343 344 // minimalLength + 1 because we denote the depth including the root node 345 determineLongPathsWithMostOccurrences(minimalLength + 1, paths, context); 346 347 Collection<List<T>> resultingPaths = new LinkedList<List<T>>(); 348 List<T> resultingPath; 349 350 if (paths.size() > 0) { 351 352 for (List<TrieNode<T>> path : paths) { 353 resultingPath = new LinkedList<T>(); 354 355 for (TrieNode<T> node : path) { 356 if (node.getSymbol() != null) { 357 resultingPath.add(node.getSymbol()); 358 } 359 } 360 361 resultingPaths.add(resultingPath); 362 } 363 } 364 365 return resultingPaths; 366 } 367 368 /** 369 * <p> 370 * Traverses the trie to collect all sequences with a maximum number of occurrences and with 371 * a minimal length. The length is encoded in the provided recursion depth. 372 * </p> 373 * 374 * @param minimalDepth the minimal recursion depth to be done 375 * @param paths the paths through the trie that all occurred with the same amount and 376 * that have the so far found maximum of occurrences (is updated each 377 * time a further path with the same number of occurrences is found; is 378 * replaced if a path with more occurrences is found) 379 * @param context the path through the trie, that is analyzed by the recursive call 380 */ 381 private void determineLongPathsWithMostOccurrences(int minimalDepth, 382 Collection<List<TrieNode<T>>> paths, 383 LinkedList<TrieNode<T>> context) 384 { 385 int maxCount = 0; 386 387 // only if we already reached the depth to be achieved, we check if the paths have the 388 // maximum number of occurrences 389 if (context.size() >= minimalDepth) { 390 391 // try to determine the maximum number of occurrences so far, if any 392 if (paths.size() > 0) { 393 List<TrieNode<T>> path = paths.iterator().next(); 394 maxCount = path.get(path.size() - 1).getCount(); 395 } 396 397 // if the current path has a higher number of occurrences than all so far, clear 398 // the paths collected so far and set the new number of occurrences as new maximum 399 if (context.getLast().getCount() > maxCount) { 400 paths.clear(); 401 maxCount = context.getLast().getCount(); 402 } 403 404 // if the path matches the current maximal number of occurrences, add it to the list 405 // of collected paths with these number of occurrences 406 if (context.getLast().getCount() == maxCount) { 407 paths.add(new LinkedList<TrieNode<T>>(context)); 408 } 409 } 410 411 // perform the trie traversal 412 for (TrieNode<T> child : context.getLast().getChildren()) { 413 if (child.getCount() >= maxCount) { 414 context.add(child); 415 determineLongPathsWithMostOccurrences(minimalDepth, paths, context); 416 context.removeLast(); 417 } 418 } 419 } 420 421 /** 422 * <p> 423 * adds a new symbol to the collection of known symbols if this symbol is not already 424 * contained. The symbols are compared using the comparator. 425 * </p> 426 * 427 * @param symbol the symbol to be added to the known symbols 428 */ 429 private void addToKnownSymbols(T symbol) { 430 for (T knownSymbol : knownSymbols) { 431 if (comparator.equals(knownSymbol, symbol)) { 432 return; 433 } 434 } 435 436 knownSymbols.add(symbol); 437 } 438 439 /** 440 * <p> 441 * adds a list of new symbols to the collection of known symbols. Uses the 442 * {@link #addToKnownSymbols(Object)} method for each element of the provided list. 443 * </p> 444 * 445 * @param symbols the list of symbols to be added to the known symbols 446 */ 447 private void addToKnownSymbols(List<T> symbols) { 448 for (T symbol : symbols) { 449 addToKnownSymbols(symbol); 450 } 451 } 452 453 /** 454 * <p> 308 455 * Helper class for graph visualization of a trie. 309 456 * </p> … … 441 588 knownSymbols = new HashSet<T>(); 442 589 for (TrieNode<T> node : rootNode.getChildren()) { 443 knownSymbols.add(node.getSymbol());590 addToKnownSymbols(node.getSymbol()); 444 591 } 445 592 } … … 478 625 return hash; 479 626 } 627 480 628 } -
trunk/autoquest-core-usageprofiles/src/main/java/de/ugoe/cs/autoquest/usageprofiles/TrieNode.java
r927 r1060 33 33 * </p> 34 34 * 35 * @author Steffen Herbold 35 * @author Steffen Herbold, Patrick Harms 36 36 * 37 37 * @param <T> … … 71 71 /** 72 72 * <p> 73 * Comparator to be used for comparing the symbols with each other 74 * </p> 75 */ 76 private SymbolComparator<T> comparator; 77 78 /** 79 * <p> 73 80 * Constructor. Creates a new TrieNode without a symbol associated.<br> 74 81 * <b>This constructor should only be used to create the root node of the trie!</b> 82 * The comparator used by the tree node will be a {@link DefaultSymbolComparator}. 75 83 * </p> 76 84 */ 77 85 TrieNode() { 86 this(new DefaultSymbolComparator<T>()); 87 } 88 89 /** 90 * <p> 91 * Constructor. Creates a new TrieNode. The symbol must not be null. 92 * The comparator used by the tree node will be a {@link DefaultSymbolComparator}. 93 * </p> 94 * 95 * @param symbol 96 * symbol associated with the trie node 97 */ 98 TrieNode(T symbol) { 99 this(symbol, new DefaultSymbolComparator<T>()); 100 } 101 102 /** 103 * <p> 104 * Constructor. Creates a new TrieNode without a symbol associated using the provided 105 * comparator.<br> 106 * <b>This constructor should only be used to create the root node of the trie!</b> 107 * <br>The comparator must not be null. 108 * </p> 109 */ 110 TrieNode(SymbolComparator<T> comparator) { 111 if (comparator == null) { 112 throw new IllegalArgumentException("comparator must not be null!"); 113 } 114 this.comparator = comparator; 78 115 this.symbol = null; 79 116 count = 0; … … 83 120 /** 84 121 * <p> 85 * Constructor. Creates a new TrieNode. The symbol must not be null. 122 * Constructor. Creates a new TrieNode using the provided comparator. The symbol and the 123 * comparator must not be null. 86 124 * </p> 87 125 * … … 89 127 * symbol associated with the trie node 90 128 */ 91 TrieNode(T symbol ) {129 TrieNode(T symbol, SymbolComparator<T> comparator) { 92 130 if (symbol == null) { 93 throw new IllegalArgumentException (94 131 throw new IllegalArgumentException 132 ("symbol must not be null. null is reserved for root node!"); 95 133 } 96 134 this.symbol = symbol; 135 136 if (comparator == null) { 137 throw new IllegalArgumentException("comparator must not be null!"); 138 } 139 this.comparator = comparator; 140 97 141 count = 0; 98 142 children = new LinkedList<TrieNode<T>>(); … … 112 156 symbol = other.symbol; 113 157 count = other.count; 158 comparator = other.comparator; 114 159 children = new LinkedList<TrieNode<T>>(); 115 160 for (TrieNode<T> child : other.children) { … … 129 174 public void add(List<T> subsequence) { 130 175 if (!subsequence.isEmpty()) { 131 if (!symbol.equals(subsequence.get(0))) { // should be guaranteed by 132 // the 133 // recursion/TrieRoot! 176 if (!comparator.equals(symbol, subsequence.get(0))) { // should be guaranteed by 177 // the recursion/TrieRoot! 134 178 throw new AssertionError("Invalid trie operation!"); 135 179 } … … 179 223 TrieNode<T> node = getChild(symbol); 180 224 if (node == null) { 181 node = new TrieNode<T>(symbol );225 node = new TrieNode<T>(symbol, comparator); 182 226 children.add(node); 183 227 } … … 197 241 protected TrieNode<T> getChild(T symbol) { 198 242 for (TrieNode<T> child : children) { 199 if (c hild.getSymbol().equals(symbol)) {243 if (comparator.equals(child.getSymbol(), symbol)) { 200 244 return child; 201 245 } … … 267 311 @Override 268 312 public String toString() { 269 String str = symbol.toString() + " #" + count; 313 String str; 314 315 if (symbol == null) { 316 str = "ROOT"; 317 } 318 else { 319 str = symbol.toString() + " #" + count; 320 } 321 270 322 if (!children.isEmpty()) { 271 323 str += StringTools.ENDLINE + children.toString(); … … 276 328 /** 277 329 * <p> 278 * Generates a {@link Tree} represen ation of the trie.330 * Generates a {@link Tree} representation of the trie. 279 331 * </p> 280 332 * … … 409 461 * <p> 410 462 * Two TrieNodes are defined as equal, if their {@link #count}, {@link #symbol}, and 411 * {@link #children} are equal. 463 * {@link #children} are equal. For the comparison of their symbols the comparator is used. 412 464 * </p> 413 465 * 414 466 * @see java.lang.Object#equals(java.lang.Object) 415 467 */ 416 @SuppressWarnings( "rawtypes")468 @SuppressWarnings({ "rawtypes", "unchecked" }) 417 469 @Override 418 470 public boolean equals(Object other) { … … 427 479 } 428 480 else { 429 return count == otherNode.count && symbol.equals(((TrieNode) other).symbol) && 481 return count == otherNode.count && 482 symbol.getClass().isInstance(((TrieNode) other).symbol) && 483 comparator.equals(symbol, ((TrieNode<T>) other).symbol) && 430 484 children.equals(((TrieNode) other).children); 431 485 }
Note: See TracChangeset
for help on using the changeset viewer.