Changeset 1851
- Timestamp:
- 12/23/14 11:34:43 (10 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/autoquest-core-tasktrees/src/main/java/de/ugoe/cs/autoquest/tasktrees/temporalrelation/utils/MostSimilarTaskDeterminer.java
r1767 r1851 15 15 package de.ugoe.cs.autoquest.tasktrees.temporalrelation.utils; 16 16 17 import java.util.ArrayList;18 17 import java.util.HashMap; 19 18 import java.util.HashSet; … … 25 24 import java.util.logging.Level; 26 25 27 import de.ugoe.cs.autoquest.tasktrees.temporalrelation.Task InstanceComparator;26 import de.ugoe.cs.autoquest.tasktrees.temporalrelation.TaskComparator; 28 27 import de.ugoe.cs.autoquest.tasktrees.treeifc.DefaultTaskTraversingVisitor; 28 import de.ugoe.cs.autoquest.tasktrees.treeifc.IEventTaskInstance; 29 import de.ugoe.cs.autoquest.tasktrees.treeifc.ISelectionInstance; 29 30 import de.ugoe.cs.autoquest.tasktrees.treeifc.IStructuringTemporalRelationship; 30 31 import de.ugoe.cs.autoquest.tasktrees.treeifc.ITask; 31 32 import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskInfo; 33 import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskInstance; 34 import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskInstanceList; 32 35 import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskModel; 33 36 import de.ugoe.cs.autoquest.tasktrees.treeifc.TaskMetric; … … 61 64 62 65 /** 63 * default indicator for unequal tasks64 */65 private static final SimilarTasks UNEQUAL_TASKS = new SimilarTasks(null, null, null, null, null);66 67 /**68 66 * task comparator used internally 69 67 */ 70 private Task InstanceComparator comparator;68 private TaskComparator comparator; 71 69 72 70 /** … … 75 73 */ 76 74 private Set<Long> comparisonsToSkip = new HashSet<>(); 75 76 /** TODO comment */ 77 private long comparisonCounter = 0; 77 78 78 79 /** 79 80 * Initialize instances of this class with the task comparator to be used 80 81 */ 81 public MostSimilarTaskDeterminer(Task InstanceComparator comparator) {82 public MostSimilarTaskDeterminer(TaskComparator comparator) { 82 83 this.comparator = comparator; 83 84 } … … 95 96 */ 96 97 public List<SimilarTasks> getMostSimilarTasks(List<ITask> tasks, ITaskModel taskModel) { 97 Console.println("comparing " + tasks.size() + " tasks with each other"); 98 99 LinkedList<SimilarTasks> mostSimilarTasksList = performComparisons(tasks); 98 Console.println("comparing " + tasks.size() + " sequences with each other"); 99 100 LinkedList<SimilarTasks> mostSimilarTasksList = performComparisons(taskModel, tasks); 101 102 Console.println("initially found " + mostSimilarTasksList.size() + " similar sequences"); 100 103 101 104 applyFilterForSmallestDiffLevel(mostSimilarTasksList); 105 106 Console.println("only " + mostSimilarTasksList.size() + " have the smallest diff level"); 107 102 108 applyFilterForParents(mostSimilarTasksList); 109 110 Console.println(mostSimilarTasksList.size() + " remain after filtering for parents"); 111 103 112 applyFilterForMostCoveredEvents(mostSimilarTasksList, taskModel); 104 113 105 Console.traceln 106 (Level.FINER, "calculated " + mostSimilarTasksList.size() + " most similar tasks"); 114 Console.println("calculated " + mostSimilarTasksList.size() + " most similar sequences"); 107 115 108 116 return mostSimilarTasksList; … … 147 155 // generated through this rule 148 156 Iterator<SimilarTasks> listIterator = mostSimilarTasksList.iterator(); 157 List<SimilarTasks> similarTasksToRemove = new LinkedList<SimilarTasks>(); 149 158 150 159 while (listIterator.hasNext()) { … … 161 170 TaskTreeUtils.isChild(task4, task2)) 162 171 { 172 similarTasksToRemove.add(candidate); 173 break; 174 } 175 } 176 } 177 178 listIterator = mostSimilarTasksList.iterator(); 179 180 while (listIterator.hasNext()) { 181 SimilarTasks candidate = listIterator.next(); 182 183 for (SimilarTasks toRemove : similarTasksToRemove) { 184 if (candidate == toRemove) { 163 185 listIterator.remove(); 164 break;165 186 } 166 187 } … … 204 225 mostSimilarTasksList.clear(); 205 226 206 System.out.println("several comparisons for the same task exist with same diff level" +207 "--> filtering for pair to be merged first");227 Console.traceln(Level.FINEST, "several comparisons for the same task exist with " + 228 "same diff level --> filtering for pair to be merged first"); 208 229 209 230 SimilarTasks firstToMerge = null; … … 285 306 // depth is equal. Calculate for both the similarity 286 307 // based on which the merging will take place 287 valFirst = 288 SimilarTasks.getMergableLevelOfSimilarity(first, comparator).getDiffLevel(); 289 valSecond = 290 SimilarTasks.getMergableLevelOfSimilarity(second, comparator).getDiffLevel(); 291 292 if (valSecond > valFirst) { 308 SimilarTasks tmp = SimilarTasks.getMergableLevelOfSimilarity(first, comparator); 309 valFirst = tmp != null ? tmp.getDiffLevel() : Integer.MAX_VALUE; 310 311 tmp = SimilarTasks.getMergableLevelOfSimilarity(second, comparator); 312 valSecond = tmp != null ? tmp.getDiffLevel() : Integer.MAX_VALUE; 313 314 if (valSecond < valFirst) { 293 315 return second; 294 316 } 295 else if (valSecond <valFirst) {317 else if (valSecond > valFirst) { 296 318 return first; 297 319 } … … 325 347 * starts several threads performing the task comparisons 326 348 */ 327 private LinkedList<SimilarTasks> performComparisons( List<ITask> tasks) {349 private LinkedList<SimilarTasks> performComparisons(ITaskModel taskModel, List<ITask> tasks) { 328 350 LinkedList<SimilarTasks> mostSimilarTasks = new LinkedList<SimilarTasks>(); 329 351 List<Runnable> startedRunnables = new LinkedList<Runnable>(); 330 List<Runnable> runnables = createRunnables(tasks, mostSimilarTasks, startedRunnables); 331 332 // create Runnables for all buckets 333 int noOfParallelThreads = Math.min(2, runnables.size()); 334 335 Console.traceln(Level.FINER, "will start " + runnables.size() + " threads"); 336 337 // start the Threads, wait for their completion, and start the next ones if there are 338 // remaining 352 353 comparisonCounter = 0; 354 355 // groups size is minimal 100 or maximal 1000 356 int groupSize = Math.max 357 (100, Math.min(3000, 1 + (tasks.size() / Runtime.getRuntime().availableProcessors()))); 358 339 359 synchronized (startedRunnables) { 340 while ((runnables.size() > 0) || (startedRunnables.size() > 0)) { 341 while ((startedRunnables.size() < noOfParallelThreads) && (runnables.size() > 0)) { 342 Runnable runnable = runnables.remove(0); 360 int start1 = 0; 361 int end1; 362 int start2; 363 int end2; 364 365 do { 366 end1 = Math.min(start1 + groupSize, tasks.size()); 367 TaskTraversal[] leftHandTraversals = new TaskTraversal[end1 - start1]; 368 369 Console.traceln(Level.FINE, "calculating left hand traversals from " + start1 + 370 " to " + end1); 371 372 int index = 0; 373 for (int j = start1; j < end1; j++) { 374 leftHandTraversals[index++] = 375 TaskTraversal.getTraversal(tasks.get(j), null); 376 } 377 378 start2 = 0; 379 do { 380 end2 = Math.min(start2 + groupSize, end1 - 1); 381 TaskTraversal[] rightHandTraversals = new TaskTraversal[end2 - start2]; 382 383 if (end2 <= start1) { 384 Console.traceln(Level.FINE, "calculating right hand traversals from " + 385 start2 + " to " + end2); 386 387 // traversals need to be created 388 index = 0; 389 for (int j = start2; j < end2; j++) { 390 rightHandTraversals[index++] = 391 TaskTraversal.getTraversal(tasks.get(j), null); 392 } 393 394 } 395 else { 396 // traversals can be reused 397 Console.traceln(Level.FINE, "reusing traversals for right hand from " + 398 start2 + " to " + end2); 399 400 rightHandTraversals = leftHandTraversals; 401 } 402 403 Runnable runnable = new CompareRunnable(taskModel, leftHandTraversals, 404 rightHandTraversals, 405 mostSimilarTasks, startedRunnables); 406 407 while (startedRunnables.size() >= 408 Math.max(1, Runtime.getRuntime().availableProcessors())) 409 { 410 try { 411 Console.traceln(Level.FINER, "waiting for next thread to finish"); 412 startedRunnables.wait(); 413 Console.traceln(Level.FINER, "thread finished"); 414 } 415 catch (InterruptedException e) { 416 // should not happen 417 Console.logException(e); 418 } 419 } 420 421 Console.traceln(Level.FINER, "starting next thread"); 343 422 startedRunnables.add(runnable); 344 423 new Thread(runnable).start(); 345 Console.traceln(Level.FINEST, "started next thread"); 346 } 347 424 Console.traceln(Level.FINER, "started next thread " + runnable); 425 426 start2 = end2; 427 } 428 while (end2 < (end1 - 1)); 429 430 start1 = end1; 431 } 432 while (end1 < tasks.size()); 433 434 435 while (startedRunnables.size() > 0) { 348 436 try { 437 Console.traceln(Level.FINER, "waiting for next thread to finish"); 349 438 startedRunnables.wait(); 439 Console.traceln(Level.FINER, "thread finished"); 350 440 } 351 441 catch (InterruptedException e) { … … 353 443 Console.logException(e); 354 444 } 355 356 Console.traceln(Level.FINEST, "thread finished (" + runnables.size() + ", " + 357 startedRunnables.size() + ")"); 358 } 359 } 360 Console.traceln(Level.FINER, "all threads finished"); 445 } 446 } 447 448 Console.traceln 449 (Level.FINER, "all threads finished, " + comparisonCounter + " comparisons done"); 450 451 if (comparisonCounter != (((tasks.size() - 1) * tasks.size()) / 2)) { 452 throw new RuntimeException(comparisonCounter + " " + 453 (((tasks.size() - 1) * tasks.size()) / 2)); 454 } 361 455 362 456 return mostSimilarTasks; 363 }364 365 /**366 * creates runnables for comparing tasks by subdiving the input set of comparisons into367 * several subsets where each is compared in a corresponding runnable. The subsets are368 * at most 150000 comparisons large.369 */370 private List<Runnable> createRunnables(List<ITask> tasks,371 LinkedList<SimilarTasks> mostSimilarTasksList,372 List<Runnable> startedRunnables)373 {374 // subdivide comparisons into buckets to be spread to different threads375 int noOfComparisons = 0;376 int noOfScheduledComparisons = 0;377 List<Integer> bucketIndexes = new ArrayList<Integer>();378 379 bucketIndexes.add(0);380 381 for (int i = 0; i < tasks.size(); i++) {382 noOfComparisons += i;383 384 if ((noOfComparisons - noOfScheduledComparisons) > 150000) {385 bucketIndexes.add(i);386 noOfScheduledComparisons = noOfComparisons;387 }388 }389 390 bucketIndexes.add(tasks.size());391 392 Console.traceln(Level.FINER, "scheduling " + noOfComparisons + " comparisons");393 394 List<Runnable> runnables = new LinkedList<Runnable>();395 396 for (int i = 1; i < bucketIndexes.size(); i++) {397 CompareRunnable runnable = new CompareRunnable398 (tasks, bucketIndexes.get(i - 1), bucketIndexes.get(i), mostSimilarTasksList,399 startedRunnables);400 401 runnables.add(runnable);402 }403 404 return runnables;405 457 } 406 458 … … 468 520 469 521 /** */ 470 private List<ITask> taskList;522 private ITaskModel taskModel; 471 523 472 524 /** */ 473 private int startIndex;525 private TaskTraversal[] leftHandTraversals; 474 526 475 527 /** */ 476 private int endIndex;477 528 private TaskTraversal[] rightHandTraversals; 529 478 530 /** */ 479 531 private List<SimilarTasks> mostSimilarTasksList; … … 485 537 * 486 538 */ 487 public CompareRunnable( List<ITask> taskList,488 int startIndex,489 int endIndex,490 List<SimilarTasks> 491 List<Runnable> 539 public CompareRunnable(ITaskModel taskModel, 540 TaskTraversal[] leftHandTraversals, 541 TaskTraversal[] rightHandTraversals, 542 List<SimilarTasks> mostSimilarTasksList, 543 List<Runnable> unfinishedRunnables) 492 544 { 493 this.task List = taskList;494 this. startIndex = startIndex;495 this. endIndex = endIndex;545 this.taskModel = taskModel; 546 this.leftHandTraversals = leftHandTraversals; 547 this.rightHandTraversals = rightHandTraversals; 496 548 this.mostSimilarTasksList = mostSimilarTasksList; 497 549 this.unfinishedRunnables = unfinishedRunnables; … … 503 555 @Override 504 556 public void run() { 505 int noOfComparisons = 0; 506 507 for (int i = startIndex; i < endIndex; i++) { 508 noOfComparisons += i; 509 } 510 511 System.out.println("performing " + noOfComparisons + " comparisons"); 512 513 SimilarTasks mostSimilarTasks = UNEQUAL_TASKS; 557 SimilarTasks mostSimilarTasks = SimilarTasks.UNEQUAL_TASKS; 558 int mostSimilarDiffLevel = MAX_DIFF_LEVEL; 514 559 List<SimilarTasks> allMostSimilarTasks = new LinkedList<SimilarTasks>(); 515 516 for (int i = startIndex + 1; i < endIndex; i++) { 517 /*if (appData.isSelfCreatedTask(taskList.get(i))) { 518 continue; 519 }*/ 520 521 for (int j = startIndex; j < i; j++) { 522 /*if (appData.isSelfCreatedTask(taskList.get(j))) { 523 continue; 524 }*/ 560 int counter = 0; 561 562 LEFT_HAND_TRAVERSAL: 563 for (int i = 0; i < leftHandTraversals.length; i++) { 564 565 ITask leftHandTask = leftHandTraversals[i].getTask(); 566 567 RIGHT_HAND_TRAVERSAL: 568 for (int j = 0; j < rightHandTraversals.length; j++) { 569 570 ITask rightHandTask = rightHandTraversals[j].getTask(); 525 571 526 if (isComparisonToSkip(taskList.get(i), taskList.get(j))) { 527 continue; 528 } 529 530 SimilarTasks similarTasks = SimilarTasks.compareTasks 531 (taskList.get(i), taskList.get(j), comparator); 532 533 if (similarTasks.isInBetweenDifference()) { 534 if (similarTasks.getDiffLevel() < mostSimilarTasks.getDiffLevel()) { 535 mostSimilarTasks = similarTasks; 536 allMostSimilarTasks.clear(); 537 allMostSimilarTasks.add(similarTasks); 572 try { 573 if (leftHandTask == rightHandTask) { 574 continue LEFT_HAND_TRAVERSAL; 538 575 } 539 else if (similarTasks.getDiffLevel() == mostSimilarTasks.getDiffLevel()) { 540 allMostSimilarTasks.add(similarTasks); 576 577 counter++; 578 579 if (isComparisonToSkip(leftHandTask, rightHandTask)) { 580 continue RIGHT_HAND_TRAVERSAL; 541 581 } 582 583 if (!isBasicallySimilar(leftHandTraversals[i], rightHandTraversals[j])) { 584 continue RIGHT_HAND_TRAVERSAL; 585 } 586 587 SimilarTasks similarTasks1 = SimilarTasks.compareTraversals 588 (leftHandTraversals[i], rightHandTraversals[j], comparator); 589 590 SimilarTasks similarTasks2 = SimilarTasks.compareTraversals 591 (rightHandTraversals[j], leftHandTraversals[i], comparator); 592 593 if ((similarTasks1.getDiffLevel() <= mostSimilarDiffLevel) || 594 (similarTasks2.getDiffLevel() <= mostSimilarDiffLevel)) 595 { 596 SimilarTasks similarTasks = 597 getSimilarTasksToPrefer(similarTasks1, similarTasks2); 598 599 if (similarTasks.isInBetweenDifference()) { 600 if (similarTasks.getDiffLevel() < mostSimilarDiffLevel) { 601 mostSimilarTasks = similarTasks; 602 mostSimilarDiffLevel = mostSimilarTasks.getDiffLevel(); 603 allMostSimilarTasks.clear(); 604 allMostSimilarTasks.add(similarTasks); 605 } 606 else if (similarTasks.getDiffLevel() == mostSimilarDiffLevel) { 607 allMostSimilarTasks.add(similarTasks); 608 } 609 } 610 } 611 } 612 catch (Exception e) { 613 e.printStackTrace(); 614 615 SimilarTasks similarTasks1 = SimilarTasks.compareTraversals 616 (leftHandTraversals[i], rightHandTraversals[j], comparator); 617 618 SimilarTasks similarTasks2 = SimilarTasks.compareTraversals 619 (rightHandTraversals[j], leftHandTraversals[i], comparator); 620 621 similarTasks1.dump(System.err); 622 623 similarTasks2.dump(System.err); 542 624 } 543 625 } … … 546 628 synchronized (unfinishedRunnables) { 547 629 mostSimilarTasksList.addAll(allMostSimilarTasks); 548 549 //System.out.println("notifying finish");630 comparisonCounter += counter; 631 550 632 for (int i = 0; i < unfinishedRunnables.size(); i++) { 551 633 if (unfinishedRunnables.get(i) == this) { … … 557 639 } 558 640 641 /** 642 * 643 */ 644 private boolean isBasicallySimilar(TaskTraversal traversal1, TaskTraversal traversal2) { 645 int length1 = traversal1.size(); 646 int length2 = traversal2.size(); 647 int maxLength = Math.max(length1, length2); 648 int lengthDiff = 100 * Math.abs(length1 - length2) / maxLength; 649 650 if (lengthDiff > MAX_DIFF_LEVEL) { 651 return false; 652 } 653 else { 654 return true; 655 } 656 } 657 658 /** 659 * <p> 660 * TODO: comment 661 * </p> 662 * 663 * @param similarTasks1 664 * @param similarTasks2 665 * @return 666 */ 667 private SimilarTasks getSimilarTasksToPrefer(SimilarTasks similarTasks1, 668 SimilarTasks similarTasks2) 669 { 670 if (similarTasks2.getDiffLevel() > similarTasks1.getDiffLevel()) { 671 return similarTasks2; 672 } 673 else if (similarTasks1.getDiffLevel() > similarTasks2.getDiffLevel()) { 674 return similarTasks1; 675 } 676 else if (similarTasks1.getDiffLevel() == similarTasks2.getDiffLevel()) { 677 ITask first = similarTasks1.getLeftHandSide(); 678 ITask second = similarTasks2.getLeftHandSide(); 679 680 long valFirst = getTaskMetric(first, TaskMetric.EVENT_COVERAGE); 681 long valSecond = getTaskMetric(second, TaskMetric.EVENT_COVERAGE); 682 683 if (valSecond > valFirst) { 684 return similarTasks2; 685 } 686 else if (valSecond < valFirst) { 687 return similarTasks1; 688 } 689 690 // no of covered events is equal, try to distinguish by count 691 692 valFirst = getTaskMetric(first, TaskMetric.COUNT); 693 valSecond = getTaskMetric(second, TaskMetric.COUNT); 694 695 if (valSecond > valFirst) { 696 return similarTasks2; 697 } 698 else if (valSecond < valFirst) { 699 return similarTasks1; 700 } 701 702 // count is equal, try to distinguish by depth 703 704 valFirst = getTaskMetric(first, TaskMetric.DEPTH); 705 valSecond = getTaskMetric(second, TaskMetric.DEPTH); 706 707 if (valSecond < valFirst) { 708 return similarTasks2; 709 } 710 else if (valSecond > valFirst) { 711 return similarTasks1; 712 } 713 714 // no of covered events is equal, try to distinguish by count 715 716 valFirst = cumulateTaskMetric(first, TaskMetric.COUNT); 717 valSecond = cumulateTaskMetric(second, TaskMetric.COUNT); 718 719 if (valSecond > valFirst) { 720 return similarTasks2; 721 } 722 else if (valSecond < valFirst) { 723 return similarTasks1; 724 } 725 726 // depth is equal. Calculate for both the similarity 727 // based on which the merging will take place 728 SimilarTasks tmp = 729 SimilarTasks.getMergableLevelOfSimilarity(similarTasks1, comparator); 730 731 valFirst = tmp != null ? tmp.getDiffLevel() : Integer.MAX_VALUE; 732 733 tmp = SimilarTasks.getMergableLevelOfSimilarity(similarTasks2, comparator); 734 valSecond = tmp != null ? tmp.getDiffLevel() : Integer.MAX_VALUE; 735 736 if (valSecond < valFirst) { 737 return similarTasks2; 738 } 739 else if (valSecond > valFirst) { 740 return similarTasks1; 741 } 742 743 valFirst = getFirstTimestamp(first); 744 valSecond = getFirstTimestamp(second); 745 746 if (valSecond > valFirst) { 747 return similarTasks1; 748 } 749 else if (valSecond < valFirst) { 750 return similarTasks2; 751 } 752 753 similarTasks1.dump(System.out); 754 similarTasks2.dump(System.out); 755 756 throw new RuntimeException 757 ("several tasks are similar so that it is undecidable which to merge first"); 758 } 759 760 return null; 761 } 762 763 /** 764 * <p> 765 * TODO: comment 766 * </p> 767 * 768 * @param first 769 * @param eventCoverage 770 * @param taskModel2 771 * @return 772 */ 773 private int getTaskMetric(ITask task, TaskMetric metric) { 774 ITaskInfo info = taskModel.getTaskInfo(task); 775 return info.getMeasureValue(metric); 776 } 777 778 /** 779 * convenience method to get the cumulative value of a task metric 780 */ 781 private int cumulateTaskMetric(ITask task, 782 final TaskMetric metric) 783 { 784 final int[] value = new int[1]; 785 value[0] = 0; 786 787 DefaultTaskTraversingVisitor visitor = new DefaultTaskTraversingVisitor() { 788 @Override 789 public void visit(IStructuringTemporalRelationship relationship) { 790 value[0] += taskModel.getTaskInfo(relationship).getMeasureValue(metric); 791 super.visit(relationship); 792 } 793 }; 794 795 task.accept(visitor); 796 797 return value[0]; 798 } 799 800 /** 801 * <p> 802 * TODO: comment 803 * </p> 804 * 805 * @param first 806 * @return 807 */ 808 private long getFirstTimestamp(ITask task) { 809 long timestamp = Long.MAX_VALUE; 810 811 for (ITaskInstance instance : task.getInstances()) { 812 ITaskInstance eventTaskInstance = instance; 813 814 do { 815 if (eventTaskInstance instanceof ITaskInstanceList) { 816 eventTaskInstance = ((ITaskInstanceList) eventTaskInstance).get(0); 817 } 818 else if (eventTaskInstance instanceof ISelectionInstance) { 819 eventTaskInstance = ((ISelectionInstance) eventTaskInstance).getChild(); 820 } 821 } 822 while (!(eventTaskInstance instanceof IEventTaskInstance)); 823 824 if (eventTaskInstance != null) { 825 long newTimestamp = 826 ((IEventTaskInstance) eventTaskInstance).getEvent().getTimestamp(); 827 828 if (timestamp > newTimestamp) { 829 timestamp = newTimestamp; 830 } 831 } 832 } 833 834 return timestamp; 835 } 836 837 /* (non-Javadoc) 838 * @see java.lang.Object#toString() 839 */ 840 @Override 841 public String toString() { 842 return "CompareThread(" + leftHandTraversals.length + ", " + 843 rightHandTraversals.length + ")"; 844 } 845 559 846 } 560 847 }
Note: See TracChangeset
for help on using the changeset viewer.