Ignore:
Timestamp:
12/23/14 11:49:50 (10 years ago)
Author:
pharms
Message:
  • refactoring to use correct terminology
  • implemented selection of which detected subsequence to replace first to be deterministic
  • corrected selection of shorter or longer detected subsequences if the shorter one is part of the longer one
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/autoquest-core-tasktrees/src/main/java/de/ugoe/cs/autoquest/tasktrees/temporalrelation/SequenceForTaskDetectionRule.java

    r1767 r1855  
    1515package de.ugoe.cs.autoquest.tasktrees.temporalrelation; 
    1616 
     17import java.util.ArrayList; 
    1718import java.util.HashMap; 
    1819import java.util.HashSet; 
     20import java.util.IdentityHashMap; 
    1921import java.util.Iterator; 
    2022import java.util.LinkedList; 
    2123import java.util.List; 
     24import java.util.ListIterator; 
    2225import java.util.Map; 
    2326import java.util.Set; 
     
    2528 
    2629import de.ugoe.cs.autoquest.tasktrees.taskequality.TaskEquality; 
     30import de.ugoe.cs.autoquest.tasktrees.temporalrelation.utils.DebuggingHelper; 
    2731import de.ugoe.cs.autoquest.tasktrees.treeifc.IIteration; 
    2832import de.ugoe.cs.autoquest.tasktrees.treeifc.IIterationInstance; 
     
    183187        appData.getStopWatch().start("harmonizing event tasks"); 
    184188 
    185         SymbolMap<ITaskInstance, ITask> uniqueTasks = 
    186             preparationTaskHandlingStrategy.createSymbolMap(); 
    187         TaskInstanceComparator comparator = preparationTaskHandlingStrategy.getTaskComparator(); 
     189        SymbolMap<ITask, ITask> uniqueTasks = preparationTaskHandlingStrategy.createSymbolMap(); 
     190        TaskComparator comparator = preparationTaskHandlingStrategy.getTaskComparator(); 
    188191         
    189192        int unifiedTasks = 0; 
     
    194197            Console.traceln(Level.FINE, "handling " + (++sessionNo) + ". " + session); 
    195198            for (ITaskInstance taskInstance : session) { 
    196                 task = uniqueTasks.getValue(taskInstance); 
     199                task = uniqueTasks.getValue(taskInstance.getTask()); 
    197200                 
    198201                if (task == null) { 
    199                     uniqueTasks.addSymbol(taskInstance, taskInstance.getTask()); 
     202                    uniqueTasks.addSymbol(taskInstance.getTask(), taskInstance.getTask()); 
    200203                } 
    201204                else { 
     
    374377    { 
    375378        List<ITask> iteratedTaskVariants = new LinkedList<ITask>(); 
    376         TaskInstanceComparator comparator = preparationTaskHandlingStrategy.getTaskComparator(); 
     379        TaskComparator comparator = preparationTaskHandlingStrategy.getTaskComparator(); 
    377380         
    378381        // merge the lexically different variants of iterated task to a unique list  
     
    432435        appData.getStopWatch().start("detecting tasks"); 
    433436         
    434         getSequencesOccuringMostOften(appData); 
    435  
     437        getSubsequencesOccuringMostOften(appData); 
     438         
    436439        appData.getStopWatch().stop("detecting tasks"); 
     440        appData.getStopWatch().start("sorting tasks"); 
     441         
     442        removeInterleavingTasks(appData); 
     443 
     444        appData.getStopWatch().stop("sorting tasks"); 
    437445        appData.getStopWatch().start("replacing tasks"); 
    438446         
     
    440448         
    441449        appData.getStopWatch().stop("replacing tasks"); 
    442         Console.traceln(Level.INFO, "detected and replaced " + appData.getLastFoundTasks().size() + 
    443                         " tasks occuring " + appData.getLastFoundTasks().getOccurrenceCount() + 
     450        Console.traceln(Level.INFO, "detected and replaced " + appData.getLastFoundSubsequences().size() + 
     451                        " tasks occuring " + appData.getLastFoundSubsequences().getOccurrenceCount() + 
    444452                        " times"); 
    445453    } 
     
    448456     * @param appData the rule application data combining all data used for applying this rule 
    449457     */ 
    450     private void getSequencesOccuringMostOften(RuleApplicationData appData) { 
    451         Console.traceln(Level.FINE, "determining most prominent tasks"); 
    452  
    453         Tasks tasks; 
     458    private void getSubsequencesOccuringMostOften(RuleApplicationData appData) { 
     459        Console.traceln(Level.FINER, "determining most prominent subsequences"); 
     460 
     461        Subsequences subsequences; 
    454462        boolean createNewTrie = (appData.getLastTrie() == null) || 
    455463            appData.detectedAndReplacedTasks(); // tree has changed 
     
    460468            } 
    461469             
    462             MaxCountAndLongestTasksFinder finder = new MaxCountAndLongestTasksFinder(); 
     470            MaxCountAndLongestSubsequencesFinder finder = new MaxCountAndLongestSubsequencesFinder(); 
    463471            appData.getLastTrie().process(finder); 
    464472         
    465             tasks = finder.getFoundTasks(); 
     473            subsequences = finder.getFoundSubsequences(); 
    466474             
    467475            createNewTrie = false; 
    468476             
    469             for (List<ITaskInstance> task : tasks) { 
    470                 if (task.size() >= appData.getTrainedSequenceLength()) { 
     477            for (Subsequence subsequence : subsequences) { 
     478                if (subsequence.size() >= appData.getTrainedSubsequenceLength()) { 
    471479                    // Trie must be recreated with a longer sequence length to be sure that 
    472480                    // the found sequences occurring most often are found in their whole length 
    473                     appData.setTrainedSequenceLength(appData.getTrainedSequenceLength() + 1); 
     481                    appData.setTrainedSubsequenceLength(appData.getTrainedSubsequenceLength() + 1); 
    474482                    createNewTrie = true; 
    475483                    break; 
     
    536544        dumper.dumpCounters();*/ 
    537545         
    538         appData.setLastFoundTasks(tasks); 
    539  
    540         Console.traceln(Level.FINE, "found " + appData.getLastFoundTasks().size() + " tasks " + 
    541                         "occurring " + appData.getLastFoundTasks().getOccurrenceCount() + " times"); 
     546        appData.setLastFoundSubsequences(subsequences); 
     547 
     548        Console.traceln(Level.FINE, "found " + appData.getLastFoundSubsequences().size() + 
     549                        " tasks occurring " + 
     550                        appData.getLastFoundSubsequences().getOccurrenceCount() + " times"); 
    542551    } 
    543552 
     
    546555     */ 
    547556    private void createNewTrie(RuleApplicationData appData) { 
    548         Console.traceln(Level.FINER, "training trie with a maximum sequence length of " + 
    549                         appData.getTrainedSequenceLength()); 
     557        Console.traceln(Level.FINEST, "training trie with a maximum sequence length of " + 
     558                        appData.getTrainedSubsequenceLength()); 
    550559 
    551560        appData.getStopWatch().start("training trie"); 
     
    557566     
    558567        appData.getLastTrie().trainSessions 
    559             (appData.getSessions(), appData.getTrainedSequenceLength()); 
     568            (appData.getSessions(), appData.getTrainedSubsequenceLength()); 
    560569         
    561570        appData.getStopWatch().stop("training trie"); 
     571    } 
     572 
     573    /** 
     574     * from the last found tasks, sort out those that interleave with each other as for them always 
     575     * the same replacement order needs to be taken. 
     576     */ 
     577    private void removeInterleavingTasks(RuleApplicationData appData) { 
     578        // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 
     579        // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> TEST IMPLEMENTATION >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 
     580        // dumpSortedCollectionOfSubsequences 
     581        //     ("found task", appData.getLastFoundSubsequences().subsequences); 
     582        // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< 
     583        // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< TEST IMPLEMENTATION <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< 
     584 
     585        List<InterleavingSubsequence> interleavings; 
     586         
     587        do { 
     588            interleavings = getInterleavings(appData.getLastFoundSubsequences(), appData); 
     589             
     590            if (interleavings.size() > 0) { 
     591                // dumpSorted(interleavings); 
     592 
     593                // Console.traceln(Level.FINEST, "found " + interleavings.size() + " subsequences " + 
     594                //                 "--> checking for most real interleavings"); 
     595                 
     596                // we found interleaving subsequences. We need to decide for them, which to replace 
     597                // first. For this, we need to remove some of them from the list of detected 
     598                // subsequences in an ordered way to always have the same prioritization for 
     599                // replacements. The ones to be removed are those with most interleavings. 
     600                interleavings = getMostIntensiveInterleavings(interleavings); 
     601                 
     602                //dumpSorted(interleavings); 
     603                 
     604                if (interleavings.size() == 1) { 
     605                    // Console.traceln(Level.FINEST, "found one most interleaving subsequence " + 
     606                    //                 "--> removing it and checking for further interleavings"); 
     607 
     608                    // we have exactly one most interleaving detected subsequence. In this case, 
     609                    // we remove it from the list of found subsequences and check again, if their 
     610                    // are remaining interleavings. If not, we have the final list of non 
     611                    // interleaving subsequences to be replaced. The order or their replacement 
     612                    // doesn't matter as they are not interleaving. 
     613                    appData.getLastFoundSubsequences().remove 
     614                        (interleavings.get(0).getSubsequence()); 
     615                     
     616                    continue; 
     617                } 
     618                else if (interleavings.size() == 0) { 
     619                    // this should never happen 
     620                    throw new RuntimeException("Implementation error: don't know how I got here"); 
     621                } 
     622                 
     623                // Console.traceln(Level.FINEST, "found " + interleavings.size() + " most " + 
     624                //                 "interleaving subsequences --> checking which are most often a " + 
     625                //                 "successor"); 
     626 
     627                // there are several subsequences with the same amount of interleavings. 
     628                // Check which of them is the most often a successor. This should be removed. 
     629                interleavings = getMostInterleavingsAsSuccessor(interleavings); 
     630                 
     631                // dumpSorted(interleavings); 
     632 
     633                if (interleavings.size() == 1) { 
     634                    //  Console.traceln(Level.FINEST, "found one interleaving subsequence being most " + 
     635                    //                  "often a successor --> removing it and checking for further " + 
     636                    //                  "interleavings"); 
     637 
     638                    // we have exactly one interleaving subsequence that is most often a successor 
     639                    // of the others. Remove it and try again to see if sufficient interleavings 
     640                    // were cleared. 
     641                    appData.getLastFoundSubsequences().remove 
     642                        (interleavings.get(0).getSubsequence()); 
     643                     
     644                    continue; 
     645                } 
     646                else if (interleavings.size() == 0) { 
     647                    // this should never happen 
     648                    throw new RuntimeException("Implementation error: don't know how I got here"); 
     649                } 
     650                 
     651                // Console.traceln(Level.FINEST, "found " + interleavings.size() + 
     652                //                 " most interleaving subsequences being most often a successor " + 
     653                //                 "--> checking which is most seldom a predecessor"); 
     654 
     655                // there are several subsequences with the same amount of interleavings being also 
     656                // the same times a successor of another subsequence. Hence, check which of them is 
     657                // the least often a predecessor. This should be removed. 
     658                interleavings = getLeastInterleavingsAsPredecessor(interleavings); 
     659                 
     660                //dumpSorted(interleavings); 
     661 
     662                if (interleavings.size() == 1) { 
     663                    // Console.traceln(Level.FINEST, "found one interleaving subsequence being most " + 
     664                    //                 "often a successor and most seldom a predecessor --> " + 
     665                    //                 "removing it and checking for further interleavings"); 
     666 
     667                    // we have exactly one interleaving subsequence that is most often a successor 
     668                    // and most seldom a predecessor of the others. Remove it and try again to see 
     669                    // if sufficient interleavings were cleared. 
     670                    appData.getLastFoundSubsequences().remove 
     671                        (interleavings.get(0).getSubsequence()); 
     672                     
     673                    continue; 
     674                } 
     675                else if (interleavings.size() == 0) { 
     676                    // this should never happen 
     677                    throw new RuntimeException("Implementation error: don't know how I got here"); 
     678                } 
     679                 
     680                // the remaining subsequences are interleaving the same amount of times and are 
     681                // used the same amount of times as successors and as predecessors by all other 
     682                // detected interleaving subsequences. Now lets check, which of them is mostly used 
     683                // as successor and most seldom used as predecessor only considering the remaining 
     684                // subsequences. If some of them do not interfere with the others, remove them and 
     685                // try again to see if sufficient interleavings were cleared. 
     686                 
     687                // Console.traceln(Level.FINEST, "found " + interleavings.size() + 
     688                //                 " most interleaving subsequences being most often a successor " + 
     689                //                 "and most seldom a predecessor --> removing collision being not " + 
     690                //                 "between themselves"); 
     691 
     692                interleavings = removeCollisionsOfOtherSubsequences(interleavings); 
     693                 
     694                // dumpSorted(interleavings); 
     695                 
     696                // Console.traceln(Level.FINEST, "removed collisions of other subsequences not " + 
     697                //                 "belonging to the remaining interleaving subsequences --> " + 
     698                //                 "checking of the remaining interleaving are most often a " + 
     699                //                 "successor of another one"); 
     700                 
     701                interleavings = getMostInterleavingsAsSuccessor(interleavings); 
     702                interleavings = removeCollisionsOfOtherSubsequences(interleavings); 
     703                 
     704                // dumpSorted(interleavings); 
     705 
     706                if (interleavings.size() == 1) { 
     707                    // Console.traceln(Level.FINEST, "found one interleaving subsequence being most " + 
     708                    //                 "often a successor in comparison to the other remaining " + 
     709                    //                 "interleavings --> removing it and checking for further " + 
     710                    //                 "interleavings"); 
     711 
     712                    appData.getLastFoundSubsequences().remove 
     713                        (interleavings.get(0).getSubsequence()); 
     714                     
     715                    continue; 
     716                } 
     717                else if (interleavings.size() == 0) { 
     718                    // this should never happen 
     719                    throw new RuntimeException("Implementation error: don't know how I got here"); 
     720                } 
     721                 
     722                // Console.traceln(Level.FINEST, "found " + interleavings.size() + 
     723                //                 " most interleaving subsequences being most often a successor in " + 
     724                //                 "comparison to the other remaining interleavings --> checking " + 
     725                //                 "which is most seldom a predecessor"); 
     726 
     727                interleavings = getLeastInterleavingsAsPredecessor(interleavings); 
     728                interleavings = removeCollisionsOfOtherSubsequences(interleavings); 
     729                 
     730                // dumpSorted(interleavings); 
     731 
     732                if (interleavings.size() == 1) { 
     733                    // Console.traceln(Level.FINEST, "found one interleaving subsequence being most " + 
     734                    //                 "often a successor and most seldom a predecessor in " + 
     735                    //                 "comparison to the other remaining interleavings --> " + 
     736                    //                 "removing it and checking for further interleavings"); 
     737 
     738                    appData.getLastFoundSubsequences().remove 
     739                        (interleavings.get(0).getSubsequence()); 
     740                     
     741                    continue; 
     742                } 
     743                else if (interleavings.size() == 0) { 
     744                    // this should never happen 
     745                    throw new RuntimeException("Implementation error: don't know how I got here"); 
     746                } 
     747                 
     748                // Console.traceln(Level.FINEST, "found " + interleavings.size() + 
     749                //                 " most interleaving subsequences being most often a successor " + 
     750                //                 "and most seldom a predecessor in comparison to the other " + 
     751                //                 "remaining interleavings --> this may happen if there are no " + 
     752                //                 "collisions between them anymore. If so, remove all of them at " + 
     753                //                 "once."); 
     754 
     755                int collisionCount = 0; 
     756                 
     757                for (InterleavingSubsequence subsequence : interleavings) { 
     758                    collisionCount += subsequence.getCollisionCounter(); 
     759                } 
     760                 
     761                if (collisionCount == 0) { 
     762                    // Console.traceln(Level.FINEST, "remaining interleaving subsequences have no " + 
     763                    //                 "further collisions with each other --> removing all of them " + 
     764                    //                 "and checking for further interleavings"); 
     765                     
     766                    for (InterleavingSubsequence subsequence : interleavings) { 
     767                        appData.getLastFoundSubsequences().remove(subsequence.getSubsequence()); 
     768                    } 
     769                     
     770                    continue; 
     771                } 
     772 
     773                // Console.traceln(Level.FINEST, "remaining interleaving subsequences still have " + 
     774                //                 "collisions with each other --> decide based on their occurrences" + 
     775                //                 " in the sessions (remove those, coming later in comparison to " + 
     776                //                 "the others)"); 
     777                 
     778                // determine the predecessor collisions being the last in all sessions. Those 
     779                // collisions show the interleaving subsequence occurring last  
     780                Map<IUserSession, Collision> sessions = 
     781                    new IdentityHashMap<IUserSession, Collision>(); 
     782                 
     783                for (InterleavingSubsequence interleaving : interleavings) { 
     784                    for (Collision coll : interleaving.getPredecessorCollisions()) { 
     785                        Collision maxPosColl = sessions.get(coll.getLocation().getSession()); 
     786                         
     787                        if ((maxPosColl == null) || 
     788                            (maxPosColl.getLocation().getIndex() < coll.getLocation().getIndex())) 
     789                        { 
     790                            sessions.put(coll.getLocation().getSession(), coll); 
     791                        } 
     792                    } 
     793                } 
     794                 
     795                // determine, which of the subsequences occurs most often as the last one 
     796                // interleaving with another 
     797                Map<Subsequence, Integer> lastOccurrenceCounters = 
     798                    new IdentityHashMap<Subsequence, Integer>(); 
     799                 
     800                for (Collision coll : sessions.values()) { 
     801                    Integer counter = lastOccurrenceCounters.get(coll.getSubsequence()); 
     802                     
     803                    if (counter == null) { 
     804                        lastOccurrenceCounters.put(coll.getSubsequence(), 1); 
     805                    } 
     806                    else { 
     807                        lastOccurrenceCounters.put(coll.getSubsequence(), counter + 1); 
     808                    } 
     809                } 
     810                 
     811                int maxCounter = 0; 
     812                Subsequence toRemove = null; 
     813                 
     814                for (Map.Entry<Subsequence, Integer> entry : lastOccurrenceCounters.entrySet()) { 
     815                    if (entry.getValue() > maxCounter) { 
     816                        maxCounter = entry.getValue(); 
     817                        toRemove = entry.getKey(); 
     818                    } 
     819                    else if (entry.getValue() == maxCounter) { 
     820                        // we can not decide again 
     821                        toRemove = null; 
     822                        break; 
     823                    } 
     824                } 
     825                 
     826                if (toRemove != null) { 
     827                    // Console.traceln(Level.FINEST, "one of the remaining interleaving subsequences" + 
     828                    //                 " is most often the last to occur --> removing it and " + 
     829                    //                 "checking for further interleavings"); 
     830             
     831                    appData.getLastFoundSubsequences().remove(toRemove); 
     832                    continue; 
     833                } 
     834                 
     835                // checking now, if there is one sequence, having the lowest index for any of 
     836                // its collisions and preserve it. If there are several ones with the same minimum 
     837                // index, throw an exception 
     838                int minPosInAnySequence = Integer.MAX_VALUE; 
     839                InterleavingSubsequence subsequenceWithMinPos = null; 
     840                 
     841                for (InterleavingSubsequence interleaving : interleavings) { 
     842                    for (Collision collision : interleaving.getSuccessorCollisions()) { 
     843                        if (minPosInAnySequence > collision.getLocation().getIndex()) { 
     844                            minPosInAnySequence = collision.getLocation().getIndex(); 
     845                            subsequenceWithMinPos = interleaving; 
     846                        } 
     847                        else if (minPosInAnySequence == collision.getLocation().getIndex()) { 
     848                            // several have the same min pos --> undecidable which to prefer 
     849                            subsequenceWithMinPos = null; 
     850                        } 
     851                    } 
     852                } 
     853                 
     854                if (subsequenceWithMinPos != null) { 
     855                    List<Subsequence> subsequencesToRemove = new LinkedList<Subsequence>(); 
     856                     
     857                    for (Subsequence candidate : appData.getLastFoundSubsequences()) { 
     858                        if (candidate != subsequenceWithMinPos.getSubsequence()) { 
     859                            subsequencesToRemove.add(candidate); 
     860                        } 
     861                    } 
     862                     
     863                    for (Subsequence candidate : subsequencesToRemove) { 
     864                        appData.getLastFoundSubsequences().remove(candidate); 
     865                    } 
     866                     
     867                    continue; 
     868                } 
     869                 
     870                // At this point, we can not decide anymore. But it should also not 
     871                // happen. Even if two subsequences ab and ba one of them should be 
     872                // more often a successor or predecessor than the other if they 
     873                // directly follow each other. If not, it can not be decided, which of 
     874                // them to replace first. Perhaps the one occurring more often as 
     875                // the first in a session that the other. But this can be implemented 
     876                // later. 
     877                dumpSorted(interleavings, Level.SEVERE); 
     878                 
     879                throw new RuntimeException 
     880                    ("can not decide which detected subsequence to replace first."); 
     881            } 
     882        } 
     883        while (interleavings.size() > 0); 
     884 
     885        // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 
     886        // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> TEST IMPLEMENTATION >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 
     887        // dumpSortedCollectionOfSubsequences 
     888        //    ("to replace", appData.getLastFoundSubsequences().subsequences); 
     889        // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< 
     890        // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< TEST IMPLEMENTATION <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< 
     891    } 
     892 
     893    /** 
     894     * 
     895     */ 
     896    private List<InterleavingSubsequence> getInterleavings(Subsequences        subsequences, 
     897                                                           RuleApplicationData appData) 
     898    { 
     899        List<InterleavingSubsequence> interleavings = new LinkedList<InterleavingSubsequence>(); 
     900        List<Subsequence> potentialPredecessors = new LinkedList<Subsequence>(); 
     901        List<Subsequence> potentialSuccessors = new LinkedList<Subsequence>(); 
     902         
     903        Map<Subsequence, List<SubsequenceLocation>> allLocations = 
     904            getLocations(subsequences, appData); 
     905         
     906        for (Subsequence subsequence : subsequences) { 
     907            // Console.traceln 
     908            //    (Level.FINEST, "searching for interleavings of " + toPlainStr(subsequence)); 
     909 
     910            potentialPredecessors.clear(); 
     911            potentialSuccessors.clear(); 
     912             
     913            getInterleavingSubsequences 
     914                (subsequence, subsequences, potentialPredecessors, potentialSuccessors); 
     915             
     916            if ((potentialPredecessors.size() <= 0) && (potentialSuccessors.size() <= 0)) { 
     917                // subsequence is not interleaving with others. Check next one. 
     918                continue; 
     919            } 
     920             
     921            // subsequence is interleaving. First, determine its locations in the user sessions. 
     922            List<SubsequenceLocation> locations = allLocations.get(subsequence); 
     923             
     924            List<Collision> precedingCollisions = 
     925                getPrecedingCollisions(subsequence, locations, potentialPredecessors, appData); 
     926             
     927            List<Collision> succeedingCollisions = 
     928                getSucceedingCollisions(subsequence, locations, potentialSuccessors, appData); 
     929             
     930            if ((precedingCollisions.size() <= 0) && (succeedingCollisions.size() <= 0)) { 
     931                // subsequence is not interleaving with others. Check next one. 
     932                continue; 
     933            } 
     934             
     935            interleavings.add(new InterleavingSubsequence(subsequence, precedingCollisions, 
     936                                                          succeedingCollisions)); 
     937        } 
     938         
     939        return interleavings; 
     940    } 
     941 
     942    /** 
     943     * 
     944     */ 
     945    private void getInterleavingSubsequences(Subsequence       subsequence, 
     946                                             Subsequences      allSubsequences, 
     947                                             List<Subsequence> potentialPredecessors, 
     948                                             List<Subsequence> potentialSuccessors) 
     949    { 
     950        TaskComparator comparator = identityTaskHandlingStrategy.getTaskComparator(); 
     951         
     952        for (Subsequence candidate : allSubsequences) { 
     953            if (comparator.equals(subsequence.get(subsequence.size() - 1), candidate.get(0))) { 
     954                potentialSuccessors.add(candidate); 
     955            } 
     956             
     957            if (comparator.equals(subsequence.get(0), candidate.get(candidate.size() - 1))) { 
     958                potentialPredecessors.add(candidate); 
     959            } 
     960        } 
     961 
     962        // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 
     963        // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> TEST IMPLEMENTATION >>>>>>>>>>>>>>>>>>>>>>>>>>>>> 
     964        // Console.traceln(Level.FINEST, "  potential successors of " + toPlainStr(subsequence)); 
     965        // dumpSortedCollectionOfSubsequences("    ", potentialSuccessors); 
     966         
     967        // Console.traceln(Level.FINEST, "  potential predecessors of " + toPlainStr(subsequence)); 
     968        // dumpSortedCollectionOfSubsequences("    ", potentialPredecessors); 
     969        // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< 
     970        // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< TEST IMPLEMENTATION <<<<<<<<<<<<<<<<<<<<<<<<<<<<< 
     971    } 
     972 
     973    /** 
     974     * 
     975     */ 
     976    private Map<Subsequence, List<SubsequenceLocation>> getLocations(Subsequences        subsequences, 
     977                                                                     RuleApplicationData appData) 
     978    { 
     979        Map<Subsequence, List<SubsequenceLocation>> result = 
     980            new IdentityHashMap<Subsequence, List<SubsequenceLocation>>(); 
     981         
     982        // fill the map with empty locations 
     983        for (Subsequence subsequence : subsequences) { 
     984            result.put(subsequence, new LinkedList<SubsequenceLocation>()); 
     985        } 
     986         
     987        LinkedList<LinkedList<Subsequence>> candidates = new LinkedList<LinkedList<Subsequence>>(); 
     988 
     989        for (IUserSession session : appData.getSessions()) { 
     990            for (int i = 0; i < session.size(); i++) { 
     991                ITask currentTask = session.get(i).getTask(); 
     992                 
     993                // create a list of candidates that may start here 
     994                LinkedList<Subsequence> candidatesToStartHere = new LinkedList<Subsequence>(); 
     995                 
     996                for (Subsequence candidate : subsequences) { 
     997                    if (candidate.get(0) == currentTask) { 
     998                        candidatesToStartHere.add(candidate); 
     999                    } 
     1000                } 
     1001                 
     1002                candidates.addFirst(candidatesToStartHere); 
     1003                 
     1004                // check if the other candidates continue here. 
     1005                ListIterator<LinkedList<Subsequence>> candidatesIt = candidates.listIterator(1); 
     1006                int index = 1; 
     1007                while (candidatesIt.hasNext()) { 
     1008                    ListIterator<Subsequence> candidateIt = candidatesIt.next().listIterator(); 
     1009                    while (candidateIt.hasNext()) { 
     1010                        Subsequence candidate = candidateIt.next(); 
     1011                         
     1012                        if (candidate.get(index) == currentTask) { 
     1013                            if (candidate.size() == (index + 1)) { 
     1014                                // subsequence was fully matched --> store location 
     1015                                result.get(candidate).add 
     1016                                    (new SubsequenceLocation(session, i - candidate.size() + 1)); 
     1017                                candidateIt.remove(); 
     1018                            } 
     1019                        } 
     1020                        else if (candidate.get(index) != currentTask) { 
     1021                            // remove the candidate as it is not located here 
     1022                            candidateIt.remove(); 
     1023                        } 
     1024                    } 
     1025                     
     1026                    index++; 
     1027                } 
     1028                 
     1029                // remove potential continuation being empty 
     1030                while ((candidates.size() > 0) && (candidates.getLast().size() == 0)) { 
     1031                    candidates.removeLast(); 
     1032                } 
     1033            } 
     1034        } 
     1035         
     1036        return result; 
     1037    } 
     1038 
     1039    /** 
     1040     * 
     1041     */ 
     1042    private List<Collision> getPrecedingCollisions(Subsequence               subsequence, 
     1043                                                   List<SubsequenceLocation> locations, 
     1044                                                   List<Subsequence>         potentialPredecessors, 
     1045                                                   RuleApplicationData       appData) 
     1046    { 
     1047        List<Collision> precedingCollisions = new LinkedList<Collision>(); 
     1048        int interleavingStartIndex; 
     1049        int interleavingEndIndex; 
     1050         
     1051        for (SubsequenceLocation location : locations) { 
     1052            for (Subsequence predecessor : potentialPredecessors) { 
     1053                // start where the interleaving would start 
     1054                interleavingStartIndex = location.getIndex() - predecessor.size() + 1; 
     1055                 
     1056                if (interleavingStartIndex >= 0) { 
     1057                    interleavingEndIndex = 
     1058                        getSubListIndex(location.getSession(), predecessor, interleavingStartIndex); 
     1059                 
     1060                    if (interleavingStartIndex == interleavingEndIndex) { 
     1061                        precedingCollisions.add(new Collision(location, subsequence, predecessor)); 
     1062                    } 
     1063                } 
     1064            } 
     1065        } 
     1066         
     1067        return precedingCollisions; 
     1068    } 
     1069 
     1070    /** 
     1071     * 
     1072     */ 
     1073    private List<Collision> getSucceedingCollisions(Subsequence               subsequence, 
     1074                                                    List<SubsequenceLocation> locations, 
     1075                                                    List<Subsequence>         potentialPredecessors, 
     1076                                                    RuleApplicationData       appData) 
     1077    { 
     1078        List<Collision> succeedingCollisions = new LinkedList<Collision>(); 
     1079        int interleavingStartIndex; 
     1080        int interleavingEndIndex; 
     1081 
     1082        for (SubsequenceLocation location : locations) { 
     1083            for (Subsequence successor : potentialPredecessors) { 
     1084                interleavingStartIndex = location.getIndex() + subsequence.size() - 1; 
     1085                interleavingEndIndex = 
     1086                    getSubListIndex(location.getSession(), successor, interleavingStartIndex); 
     1087 
     1088                if (interleavingStartIndex == interleavingEndIndex) { 
     1089                    succeedingCollisions.add(new Collision(location, subsequence, successor)); 
     1090                } 
     1091            } 
     1092        } 
     1093         
     1094        return succeedingCollisions; 
     1095    } 
     1096     
     1097    /** 
     1098     * 
     1099     */ 
     1100    private List<InterleavingSubsequence> getMostIntensiveInterleavings 
     1101        (List<InterleavingSubsequence> interleavings) 
     1102    { 
     1103        List<InterleavingSubsequence> mostIntensiveInterleavings = 
     1104            new LinkedList<InterleavingSubsequence>(); 
     1105         
     1106        int collisionCounter = 0; 
     1107         
     1108        for (InterleavingSubsequence interleaving : interleavings) { 
     1109            if (interleaving.getCollisionCounter() > collisionCounter) { 
     1110                collisionCounter = interleaving.getCollisionCounter(); 
     1111                mostIntensiveInterleavings.clear(); 
     1112            } 
     1113             
     1114            if (interleaving.getCollisionCounter() == collisionCounter) { 
     1115                mostIntensiveInterleavings.add(interleaving); 
     1116            } 
     1117        } 
     1118         
     1119        return mostIntensiveInterleavings; 
     1120    } 
     1121 
     1122    /** 
     1123     * 
     1124     */ 
     1125    private List<InterleavingSubsequence> getLeastInterleavingsAsPredecessor 
     1126        (List<InterleavingSubsequence> interleavings) 
     1127    { 
     1128        List<InterleavingSubsequence> leastInterleavingsAsPredecessor = 
     1129            new LinkedList<InterleavingSubsequence>(); 
     1130             
     1131        int collisionCounter = Integer.MAX_VALUE; 
     1132 
     1133        for (InterleavingSubsequence interleaving : interleavings) { 
     1134            if (interleaving.getSuccessorCollisionCounter() < collisionCounter) { 
     1135                collisionCounter = interleaving.getSuccessorCollisionCounter(); 
     1136                leastInterleavingsAsPredecessor.clear(); 
     1137            } 
     1138 
     1139            if (interleaving.getSuccessorCollisionCounter() == collisionCounter) { 
     1140                leastInterleavingsAsPredecessor.add(interleaving); 
     1141            } 
     1142        } 
     1143 
     1144        return leastInterleavingsAsPredecessor; 
     1145    } 
     1146 
     1147    /** 
     1148     * 
     1149     */ 
     1150    private List<InterleavingSubsequence> getMostInterleavingsAsSuccessor 
     1151        (List<InterleavingSubsequence> interleavings) 
     1152    { 
     1153        List<InterleavingSubsequence> mostInterleavingsAsSuccessor = 
     1154            new LinkedList<InterleavingSubsequence>(); 
     1155            
     1156        int collisionCounter = 0; 
     1157 
     1158        for (InterleavingSubsequence interleaving : interleavings) { 
     1159            if (interleaving.getPredecessorCollisionCounter() > collisionCounter) { 
     1160                collisionCounter = interleaving.getPredecessorCollisionCounter(); 
     1161                mostInterleavingsAsSuccessor.clear(); 
     1162            } 
     1163 
     1164            if (interleaving.getPredecessorCollisionCounter() == collisionCounter) { 
     1165                mostInterleavingsAsSuccessor.add(interleaving); 
     1166            } 
     1167        } 
     1168 
     1169        return mostInterleavingsAsSuccessor; 
     1170    } 
     1171 
     1172    /** 
     1173     * 
     1174     */ 
     1175    private List<InterleavingSubsequence> removeCollisionsOfOtherSubsequences 
     1176        (List<InterleavingSubsequence> interleavings) 
     1177    { 
     1178        List<InterleavingSubsequence> subsequencesWithoutOtherCollisions = 
     1179            new LinkedList<InterleavingSubsequence>(); 
     1180         
     1181        for (InterleavingSubsequence interleaving : interleavings) { 
     1182            List<Collision> reducedPredecessorCollisions = new LinkedList<>(); 
     1183             
     1184            for (Collision collision : interleaving.getPredecessorCollisions()) { 
     1185                for (InterleavingSubsequence otherInterleaving : interleavings) { 
     1186                    if (otherInterleaving.getSubsequence() == collision.getCollidingWith()) { 
     1187                        reducedPredecessorCollisions.add(collision); 
     1188                        break; 
     1189                    } 
     1190                } 
     1191            } 
     1192             
     1193            List<Collision> reducedSuccessorCollisions = new LinkedList<>(); 
     1194             
     1195            for (Collision collision : interleaving.getSuccessorCollisions()) { 
     1196                for (InterleavingSubsequence otherInterleaving : interleavings) { 
     1197                    if (otherInterleaving.getSubsequence() == collision.getCollidingWith()) { 
     1198                        reducedSuccessorCollisions.add(collision); 
     1199                        break; 
     1200                    } 
     1201                } 
     1202            } 
     1203             
     1204            subsequencesWithoutOtherCollisions.add 
     1205                (new InterleavingSubsequence(interleaving.getSubsequence(), 
     1206                                             reducedPredecessorCollisions, 
     1207                                             reducedSuccessorCollisions)); 
     1208        } 
     1209         
     1210        return subsequencesWithoutOtherCollisions; 
    5621211    } 
    5631212 
     
    5681217        appData.detectedAndReplacedTasks(false); 
    5691218 
    570         if ((appData.getLastFoundTasks().size() > 0) && 
    571             (appData.getLastFoundTasks().getOccurrenceCount() > 1)) 
     1219        if ((appData.getLastFoundSubsequences().size() > 0) && 
     1220            (appData.getLastFoundSubsequences().getOccurrenceCount() > 1)) 
    5721221        { 
    5731222            Console.traceln(Level.FINER, "replacing tasks occurrences"); 
    5741223 
    575             for (List<ITaskInstance> task : appData.getLastFoundTasks()) { 
     1224            for (Subsequence subsequence : appData.getLastFoundSubsequences()) { 
    5761225                ISequence sequence = taskFactory.createNewSequence(); 
    5771226                 
    578                 Console.traceln(Level.FINEST, "replacing " + sequence.getId() + ": " + task); 
    579  
    580                 List<ISequenceInstance> sequenceInstances = 
    581                     replaceTaskOccurrences(task, appData.getSessions(), sequence); 
    582                  
    583                 harmonizeSequenceInstancesModel(sequence, sequenceInstances, task.size()); 
     1227                Console.traceln(Level.FINEST, "replacing " + sequence.getId() + ": " + subsequence); 
     1228 
     1229                List<ISequenceInstance> sequenceInstances = replaceSubsequenceOccurrences 
     1230                    (subsequence, appData.getSessions(), sequence); 
     1231                 
     1232                harmonizeSequenceInstancesModel(sequence, sequenceInstances, subsequence.size()); 
    5841233                appData.detectedAndReplacedTasks 
    5851234                    (appData.detectedAndReplacedTasks() || (sequenceInstances.size() > 0)); 
    5861235 
    587                 if (sequenceInstances.size() < appData.getLastFoundTasks().getOccurrenceCount()) { 
     1236                if (sequenceInstances.size() < appData.getLastFoundSubsequences().getOccurrenceCount()) { 
    5881237                    Console.traceln(Level.FINE, sequence.getId() + ": replaced task only " + 
    5891238                                    sequenceInstances.size() + " times instead of expected " + 
    590                                     appData.getLastFoundTasks().getOccurrenceCount()); 
    591                 } 
    592             } 
    593         } 
    594          
     1239                                    appData.getLastFoundSubsequences().getOccurrenceCount()); 
     1240                } 
     1241            } 
     1242        } 
    5951243    } 
    5961244 
     
    6021250                                                 int                     sequenceLength) 
    6031251    { 
    604         TaskInstanceComparator comparator = preparationTaskHandlingStrategy.getTaskComparator(); 
     1252        TaskComparator comparator = preparationTaskHandlingStrategy.getTaskComparator(); 
    6051253         
    6061254        // ensure for each subtask that lexically different variants are preserved 
     
    6601308     * @param tree 
    6611309     */ 
    662     private List<ISequenceInstance> replaceTaskOccurrences(List<ITaskInstance> task, 
    663                                                            List<IUserSession>  sessions, 
    664                                                            ISequence           temporalTaskModel) 
     1310    private List<ISequenceInstance> replaceSubsequenceOccurrences(Subsequence         subsequence, 
     1311                                                                  List<IUserSession>  sessions, 
     1312                                                                  ISequence           temporalTaskModel) 
    6651313    { 
    6661314        List<ISequenceInstance> sequenceInstances = new LinkedList<ISequenceInstance>(); 
     
    6681316        for (IUserSession session : sessions) { 
    6691317            int index = -1; 
    670                  
     1318             
    6711319            do { 
    672                 index = getSubListIndex(session, task, ++index); 
     1320                index = getSubListIndex(session, subsequence, ++index); 
    6731321 
    6741322                if (index > -1) { 
     1323                    // subsequence is found --> perform replacement 
    6751324                    sequenceInstances.add 
    6761325                        (RuleUtils.createNewSubSequenceInRange 
    677                              (session, index, index + task.size() - 1, temporalTaskModel, 
     1326                             (session, index, index + subsequence.size() - 1, temporalTaskModel, 
    6781327                              taskFactory, taskBuilder)); 
    6791328                } 
     
    6911340     */ 
    6921341    private int getSubListIndex(ITaskInstanceList   list, 
    693                                 List<ITaskInstance> subList, 
     1342                                Subsequence         subsequence, 
    6941343                                int                 startIndex) 
    6951344    { 
     
    6971346        int result = -1; 
    6981347         
    699         for (int i = startIndex; i <= list.size() - subList.size(); i++) { 
     1348        for (int i = startIndex; i <= list.size() - subsequence.size(); i++) { 
    7001349            matchFound = true; 
    7011350             
    702             for (int j = 0; j < subList.size(); j++) { 
     1351            for (int j = 0; j < subsequence.size(); j++) { 
    7031352                // we prepared the task instances to refer to unique tasks, if they are treated 
    7041353                // as equal. Therefore, we just compare the identity of the tasks of the task 
    7051354                // instances 
    706                 if (list.get(i + j).getTask() != subList.get(j).getTask()) { 
     1355                if (list.get(i + j).getTask() != subsequence.get(j)) { 
    7071356                    matchFound = false; 
    7081357                    break; 
     
    7241373     * @return 
    7251374     */ 
    726     private int getSubListIndex(List<ITaskInstance> list, 
    727                                 List<ITaskInstance> subList, 
    728                                 int                 startIndex) 
     1375    private int getSubListIndex(Subsequence longerSubsequence, 
     1376                                Subsequence shorterSubsequence, 
     1377                                int         startIndex) 
    7291378    { 
    7301379        boolean matchFound; 
    7311380        int result = -1; 
    7321381         
    733         for (int i = startIndex; i <= list.size() - subList.size(); i++) { 
     1382        for (int i = startIndex; i <= longerSubsequence.size() - shorterSubsequence.size(); i++) { 
    7341383            matchFound = true; 
    7351384             
    736             for (int j = 0; j < subList.size(); j++) { 
     1385            for (int j = 0; j < shorterSubsequence.size(); j++) { 
    7371386                // we prepared the task instances to refer to unique tasks, if they are treated 
    7381387                // as equal. Therefore, we just compare the identity of the tasks of the task 
    7391388                // instances 
    740                 if (list.get(i + j) != subList.get(j)) { 
     1389                if (longerSubsequence.get(i + j) != shorterSubsequence.get(j)) { 
    7411390                    matchFound = false; 
    7421391                    break; 
     
    7521401        return result; 
    7531402    } 
     1403 
     1404//  /** 
     1405//   * 
     1406//   */ 
     1407//  private void dumpSorted(List<InterleavingSubsequence> interleavings) { 
     1408//      dumpSorted(interleavings, Level.FINEST); 
     1409//  } 
     1410 
     1411    /** 
     1412     * 
     1413     */ 
     1414    private void dumpSorted(List<InterleavingSubsequence> interleavings, Level level) { 
     1415        List<String> tmpList = new LinkedList<String>(); 
     1416 
     1417        for (InterleavingSubsequence interleaving : interleavings) { 
     1418            String taskStr = toPlainStr(interleaving); 
     1419            int index; 
     1420            for (index = 0; index < tmpList.size(); index++) { 
     1421                if (taskStr.compareTo(tmpList.get(index)) > 0) { 
     1422                    break; 
     1423                } 
     1424            } 
     1425 
     1426            tmpList.add(index, taskStr); 
     1427        } 
     1428 
     1429        for (String task : tmpList) { 
     1430            Console.traceln(level, task); 
     1431        } 
     1432    } 
     1433 
     1434//    /** 
     1435//     * 
     1436//     */ 
     1437//    private void dumpSortedCollectionOfSubsequences(String                  prefix, 
     1438//                                                    Collection<Subsequence> subsequences) 
     1439//    { 
     1440//        List<String> tmpList = new LinkedList<String>(); 
     1441// 
     1442//        for (Subsequence subsequence : subsequences) { 
     1443//            String taskStr = toPlainStr(subsequence); 
     1444//            int index; 
     1445//            for (index = 0; index < tmpList.size(); index++) { 
     1446//                if (taskStr.compareTo(tmpList.get(index)) > 0) { 
     1447//                    break; 
     1448//                } 
     1449//            } 
     1450// 
     1451//            tmpList.add(index, taskStr); 
     1452//        } 
     1453// 
     1454//        for (String task : tmpList) { 
     1455//            Console.traceln(Level.FINEST, prefix + " " + task); 
     1456//        } 
     1457//    } 
     1458 
     1459    /** 
     1460     * 
     1461     */ 
     1462    private String toPlainStr(InterleavingSubsequence interleaving) { 
     1463        StringBuffer result = new StringBuffer(); 
     1464        result.append("interleavings of "); 
     1465        result.append(toPlainStr(interleaving.getSubsequence())); 
     1466        result.append("\n  predecessor collisions:\n"); 
     1467 
     1468        for (Collision collision : interleaving.getPredecessorCollisions()) { 
     1469            result.append("    "); 
     1470            result.append(toPlainStr(collision.getCollidingWith())); 
     1471            result.append(" ("); 
     1472            result.append(collision.getLocation()); 
     1473            result.append(")\n"); 
     1474        } 
     1475 
     1476        result.append("  successor collisions:\n"); 
     1477 
     1478        for (Collision collision : interleaving.getSuccessorCollisions()) { 
     1479            result.append("    "); 
     1480            result.append(toPlainStr(collision.getCollidingWith())); 
     1481            result.append(" ("); 
     1482            result.append(collision.getLocation()); 
     1483            result.append(")\n"); 
     1484        } 
     1485 
     1486        return result.toString(); 
     1487    } 
     1488 
     1489    /** 
     1490     * 
     1491     */ 
     1492    private String toPlainStr(Subsequence subsequence) { 
     1493        StringBuffer result = new StringBuffer(); 
     1494        result.append(subsequence.size()); 
     1495        result.append(": "); 
     1496        for (ITask task : subsequence) { 
     1497            DebuggingHelper.toPlainStr(task, result); 
     1498            result.append(" --> "); 
     1499        } 
     1500 
     1501        return result.toString(); 
     1502    } 
    7541503     
     1504     
    7551505    /** 
    7561506     * @author Patrick Harms 
    7571507     */ 
    758     private class MaxCountAndLongestTasksFinder implements TrieProcessor<ITaskInstance> { 
     1508    private class MaxCountAndLongestSubsequencesFinder implements TrieProcessor<ITask> { 
    7591509         
    7601510        /** 
     
    7661516         *  
    7671517         */ 
    768         private List<List<ITaskInstance>> foundTasks = new LinkedList<List<ITaskInstance>>(); 
     1518        private LinkedList<Subsequence> foundSubsequences = new LinkedList<Subsequence>(); 
    7691519 
    7701520        /** 
    7711521         * 
    7721522         */ 
    773         public MaxCountAndLongestTasksFinder() { 
     1523        public MaxCountAndLongestSubsequencesFinder() { 
    7741524            super(); 
    7751525            this.currentCount = 0; 
     
    7801530         */ 
    7811531        @Override 
    782         public TrieProcessor.Result process(List<ITaskInstance> foundTask, int count) { 
     1532        public TrieProcessor.Result process(List<ITask> foundTask, int count) { 
    7831533            if (foundTask.size() < 2) { 
    7841534                // ignore single tasks 
     
    8001550                // the provided task occurs more often that all tasks found so far. 
    8011551                // clear all found tasks and use the new count as the one searched for 
    802                 foundTasks.clear(); 
     1552                foundSubsequences.clear(); 
    8031553                this.currentCount = count; 
    8041554            } 
     
    8081558                // the longest come first 
    8091559                boolean added = false; 
    810                 for (int i = 0; i < foundTasks.size(); i++) { 
    811                     if (foundTasks.get(i).size() < foundTask.size()) { 
    812                         // defensive copy 
    813                         foundTasks.add(i, new LinkedList<ITaskInstance>(foundTask)); // defensive copy 
     1560                for (int i = 0; i < foundSubsequences.size(); i++) { 
     1561                    if (foundSubsequences.get(i).size() < foundTask.size()) { 
     1562                        foundSubsequences.add(i, new Subsequence(currentCount, foundTask)); 
    8141563                        added = true; 
    8151564                        break; 
     
    8181567                 
    8191568                if (!added) { 
    820                     foundTasks.add(new LinkedList<ITaskInstance>(foundTask)); // defensive copy 
     1569                    foundSubsequences.add(new Subsequence(currentCount, foundTask)); 
    8211570                } 
    8221571            } 
     
    8281577         *  @return 
    8291578         */ 
    830         public Tasks getFoundTasks() { 
     1579        private Subsequences getFoundSubsequences() { 
    8311580            removePermutationsOfShorterTasks(); 
    832             return new Tasks(currentCount, foundTasks); 
     1581            return new Subsequences(currentCount, foundSubsequences); 
    8331582        } 
    8341583 
     
    8391588            // now iterate the sorted list and for each task remove all other tasks that are shorter 
    8401589            // (i.e. come later in the sorted list) and that represent a subpart of the task 
    841             for (int i = 0; i < foundTasks.size(); i++) { 
    842                 for (int j = i + 1; j < foundTasks.size();) { 
    843                     if (foundTasks.get(j).size() < foundTasks.get(i).size()) { 
     1590             
     1591            boolean removeI; 
     1592             
     1593            for (int i = 0; i < foundSubsequences.size();) { 
     1594                removeI = false; 
     1595                boolean removeJ; 
     1596                 
     1597                for (int j = i + 1; j < foundSubsequences.size();) { 
     1598                    removeJ = false; 
     1599                     
     1600                    if (foundSubsequences.get(j).size() < foundSubsequences.get(i).size()) { 
    8441601                        // found a task that is a potential subtask. Check for this and remove the 
    8451602                        // subtask if needed 
    846                         List<ITaskInstance> longTask = foundTasks.get(i); 
    847                         List<ITaskInstance> shortTask = foundTasks.get(j); 
     1603                        Subsequence longTask = foundSubsequences.get(i); 
     1604                        Subsequence shortTask = foundSubsequences.get(j); 
    8481605                         
    849                         if (getSubListIndex(longTask, shortTask, 0) > -1) { 
    850                             foundTasks.remove(j); 
     1606                        int index = getSubListIndex(longTask, shortTask, 0); 
     1607                        if (index > -1) { 
     1608                            if (index == 0) { 
     1609                                // check if the short task is included in the long task partially 
     1610                                // a second time. If so, prefer the short task 
     1611                                boolean secondInclude = true; 
     1612                                for (int pos = shortTask.size(); pos < longTask.size(); pos++) { 
     1613                                    // we prepared the task instances to refer to unique tasks, if 
     1614                                    // they are treated as equal. Therefore, we just compare the 
     1615                                    // identity of the tasks of the task instances 
     1616                                    if (longTask.get(pos) != shortTask.get(pos % shortTask.size())) 
     1617                                    { 
     1618                                        secondInclude = false; 
     1619                                        break; 
     1620                                    } 
     1621                                } 
     1622                                 
     1623                                if (secondInclude) { 
     1624                                    // delete the long task 
     1625                                    // Console.traceln(Level.FINEST, "1: short task is contained several times in longer one --> removing it"); 
     1626                                    // Console.traceln(Level.FINEST, "short: " + toPlainStr(shortTask)); 
     1627                                    // Console.traceln(Level.FINEST, "long: " + toPlainStr(longTask)); 
     1628                                    removeI = true; 
     1629                                } 
     1630                                else { 
     1631                                    // Console.traceln(Level.FINEST, "2: short task is a part of a longer one --> removing it"); 
     1632                                    // Console.traceln(Level.FINEST, "short: " + toPlainStr(shortTask)); 
     1633                                    // Console.traceln(Level.FINEST, "long: " + toPlainStr(longTask)); 
     1634                                    removeJ = true; 
     1635                                } 
     1636                            } 
     1637                            else { 
     1638                                // Console.traceln(Level.FINEST, "3: short task is a part of a longer one --> removing it"); 
     1639                                // Console.traceln(Level.FINEST, "short: " + toPlainStr(shortTask)); 
     1640                                // Console.traceln(Level.FINEST, "long: " + toPlainStr(longTask)); 
     1641                                removeJ = true; 
     1642                            } 
    8511643                        } 
    852                         else { 
    853                             j++; 
    854                         } 
     1644                    } 
     1645                     
     1646                    if (removeJ) { 
     1647                        foundSubsequences.remove(j); 
    8551648                    } 
    8561649                    else { 
     
    8581651                    } 
    8591652                } 
    860             } 
    861         } 
    862  
    863     } 
    864      
     1653                 
     1654                if (removeI) { 
     1655                    foundSubsequences.remove(i); 
     1656                } 
     1657                else { 
     1658                    i++; 
     1659                } 
     1660            } 
     1661        } 
     1662 
     1663    } 
     1664 
    8651665//    /** 
    8661666//     * @author Patrick Harms 
     
    9291729         
    9301730        /** 
    931          * default and minimum trained sequence length is 3 
    932          */ 
    933         private int trainedSequenceLength = 3; 
     1731         * default and minimum trained subsequence length is 3 
     1732         */ 
     1733        private int trainedSubsequenceLength = 3; 
    9341734         
    9351735        /** 
    9361736         *  
    9371737         */ 
    938         private Tasks lastFoundTasks = new Tasks(Integer.MAX_VALUE, null); 
     1738        private Subsequences lastFoundSubsequences = new Subsequences(Integer.MAX_VALUE, null); 
    9391739         
    9401740        /** 
     
    9821782 
    9831783        /** 
    984          * @param trainedSequenceLength the trainedSequenceLength to set 
    985          */ 
    986         private void setTrainedSequenceLength(int trainedSequenceLength) { 
    987             this.trainedSequenceLength = trainedSequenceLength; 
    988         } 
    989  
    990         /** 
    991          * @return the trainedSequenceLength 
    992          */ 
    993         private int getTrainedSequenceLength() { 
    994             return trainedSequenceLength; 
     1784         * @param trainedSubsequenceLength the trainedSubsequenceLength to set 
     1785         */ 
     1786        private void setTrainedSubsequenceLength(int trainedSubsequenceLength) { 
     1787            this.trainedSubsequenceLength = trainedSubsequenceLength; 
     1788        } 
     1789 
     1790        /** 
     1791         * @return the trainedSubsequenceLength 
     1792         */ 
     1793        private int getTrainedSubsequenceLength() { 
     1794            return trainedSubsequenceLength; 
    9951795        } 
    9961796 
     
    9981798         * @param lastFoundSequences the lastFoundSequences to set 
    9991799         */ 
    1000         private void setLastFoundTasks(Tasks lastFoundSequences) { 
    1001             this.lastFoundTasks = lastFoundSequences; 
     1800        private void setLastFoundSubsequences(Subsequences lastFoundSequences) { 
     1801            this.lastFoundSubsequences = lastFoundSequences; 
    10021802        } 
    10031803 
     
    10051805         * @return the lastFoundSequences 
    10061806         */ 
    1007         private Tasks getLastFoundTasks() { 
    1008             return lastFoundTasks; 
     1807        private Subsequences getLastFoundSubsequences() { 
     1808            return lastFoundSubsequences; 
    10091809        } 
    10101810 
     
    10391839    } 
    10401840     
    1041  
    10421841    /** 
    10431842     * @author Patrick Harms 
    10441843     */ 
    1045     private static class Tasks implements Iterable<List<ITaskInstance>> { 
     1844    private static class Subsequence implements Iterable<ITask> { 
    10461845         
    10471846        /** 
     
    10491848         */ 
    10501849        private int occurrenceCount; 
    1051          
     1850 
    10521851        /** 
    10531852         *  
    10541853         */ 
    1055         private List<List<ITaskInstance>> sequences; 
     1854        private List<ITask> subsequence; 
     1855         
     1856        /** 
     1857         * @param occurrenceCount 
     1858         * @param subsequences 
     1859         */ 
     1860        private Subsequence(int occurrenceCount, List<ITask> subsequence) { 
     1861            super(); 
     1862            this.occurrenceCount = occurrenceCount; 
     1863            this.subsequence = new ArrayList<ITask>(subsequence); 
     1864        } 
     1865 
     1866        /** 
     1867         * @return 
     1868         */ 
     1869        private int size() { 
     1870            return this.subsequence.size(); 
     1871        } 
     1872 
     1873        /** 
     1874         * @return 
     1875         */ 
     1876        private ITask get(int index) { 
     1877            return this.subsequence.get(index); 
     1878        } 
     1879 
     1880        /* (non-Javadoc) 
     1881         * @see java.lang.Iterable#iterator() 
     1882         */ 
     1883        @Override 
     1884        public Iterator<ITask> iterator() { 
     1885            return this.subsequence.iterator(); 
     1886        } 
     1887 
     1888        /* (non-Javadoc) 
     1889         * @see java.lang.Object#toString() 
     1890         */ 
     1891        @Override 
     1892        public String toString() { 
     1893            return subsequence.toString() + " (" + occurrenceCount + ")"; 
     1894        } 
     1895    } 
     1896 
     1897    /** 
     1898     * @author Patrick Harms 
     1899     */ 
     1900    private static class Subsequences implements Iterable<Subsequence> { 
     1901         
     1902        /** 
     1903         *  
     1904         */ 
     1905        private int occurrenceCount; 
     1906         
     1907        /** 
     1908         *  
     1909         */ 
     1910        private LinkedList<Subsequence> subsequences; 
    10561911 
    10571912        /** 
     
    10591914         * @param sequences 
    10601915         */ 
    1061         private Tasks(int occurrenceCount, List<List<ITaskInstance>> sequences) { 
     1916        private Subsequences(int occurrenceCount, LinkedList<Subsequence> subsequences) { 
    10621917            super(); 
    10631918            this.occurrenceCount = occurrenceCount; 
    1064             this.sequences = sequences; 
     1919            this.subsequences = subsequences; 
     1920        } 
     1921 
     1922        /** 
     1923         * 
     1924         */ 
     1925        private void remove(Subsequence subsequence) { 
     1926            ListIterator<Subsequence> it = subsequences.listIterator(); 
     1927             
     1928            while (it.hasNext()) { 
     1929                // reference comparison is sufficient 
     1930                if (it.next() == subsequence) { 
     1931                    it.remove(); 
     1932                } 
     1933            } 
    10651934        } 
    10661935 
     
    10761945         */ 
    10771946        private int size() { 
    1078             return this.sequences.size(); 
    1079         } 
    1080  
    1081         /** 
    1082          *  
    1083          */ 
     1947            return this.subsequences.size(); 
     1948        } 
    10841949 
    10851950        /* (non-Javadoc) 
     
    10871952         */ 
    10881953        @Override 
    1089         public Iterator<List<ITaskInstance>> iterator() { 
    1090             return this.sequences.iterator(); 
     1954        public Iterator<Subsequence> iterator() { 
     1955            return this.subsequences.iterator(); 
    10911956        } 
    10921957 
     
    10971962        public String toString() { 
    10981963            StringBuffer result = new StringBuffer(); 
     1964            result.append(" subsequences occuring "); 
    10991965            result.append(this.occurrenceCount); 
    1100             result.append(" occurrences:\n"); 
    1101              
    1102             for (List<ITaskInstance> task : sequences) { 
    1103                 result.append(task); 
     1966            result.append(" times:\n"); 
     1967             
     1968            for (Subsequence subsequence : subsequences) { 
     1969                result.append(subsequence); 
    11041970                result.append("\n"); 
    11051971            } 
     
    11071973            return result.toString(); 
    11081974        } 
    1109  
     1975    } 
     1976     
     1977    /** 
     1978     * @author Patrick Harms 
     1979     */ 
     1980    private static class InterleavingSubsequence { 
     1981         
     1982        /** */ 
     1983        private Subsequence subsequence; 
     1984         
     1985        /** */ 
     1986        private List<Collision> successorCollisions; 
     1987         
     1988        /** */ 
     1989        private List<Collision> predecessorCollisions; 
     1990 
     1991        /** 
     1992         * 
     1993         */ 
     1994        private InterleavingSubsequence(Subsequence     subsequence, 
     1995                                        List<Collision> predecessorCollisions, 
     1996                                        List<Collision> successorCollisions) 
     1997        { 
     1998            super(); 
     1999            this.subsequence = subsequence; 
     2000            this.predecessorCollisions = predecessorCollisions; 
     2001            this.successorCollisions = successorCollisions; 
     2002        } 
     2003 
     2004        /** 
     2005         * 
     2006         */ 
     2007        private int getCollisionCounter() { 
     2008            return getSuccessorCollisionCounter() + getPredecessorCollisionCounter(); 
     2009        } 
     2010 
     2011        /** 
     2012         * 
     2013         */ 
     2014        private int getSuccessorCollisionCounter() { 
     2015            return successorCollisions.size(); 
     2016        } 
     2017 
     2018        /** 
     2019         * 
     2020         */ 
     2021        private List<Collision> getSuccessorCollisions() { 
     2022            return successorCollisions; 
     2023        } 
     2024 
     2025        /** 
     2026         * 
     2027         */ 
     2028        private int getPredecessorCollisionCounter() { 
     2029            return predecessorCollisions.size(); 
     2030        } 
     2031 
     2032        /** 
     2033         * 
     2034         */ 
     2035        private List<Collision> getPredecessorCollisions() { 
     2036            return predecessorCollisions; 
     2037        } 
     2038 
     2039        /** 
     2040         * 
     2041         */ 
     2042        private Subsequence getSubsequence() { 
     2043            return subsequence; 
     2044        } 
     2045         
     2046        /* (non-Javadoc) 
     2047         * @see java.lang.Object#toString() 
     2048         */ 
     2049        @Override 
     2050        public String toString() { 
     2051            return "interleaving subsequence " + subsequence.toString() + " (" + 
     2052                successorCollisions.size() + " successor, " + predecessorCollisions.size() + 
     2053                " predecessor)"; 
     2054        } 
     2055    } 
     2056         
     2057    /** 
     2058     * @author Patrick Harms 
     2059     */ 
     2060    private static class SubsequenceLocation { 
     2061         
     2062        /** */ 
     2063        private IUserSession session; 
     2064         
     2065        /** */ 
     2066        private int index; 
     2067         
     2068        /** 
     2069         *  
     2070         */ 
     2071        private SubsequenceLocation(IUserSession session, int index) { 
     2072            this.session = session; 
     2073            this.index = index; 
     2074        } 
     2075 
     2076        /** 
     2077         * @return the session 
     2078         */ 
     2079        private IUserSession getSession() { 
     2080            return session; 
     2081        } 
     2082 
     2083        /** 
     2084         * @return the index 
     2085         */ 
     2086        private int getIndex() { 
     2087            return index; 
     2088        } 
     2089         
     2090        /* (non-Javadoc) 
     2091         * @see java.lang.Object#toString() 
     2092         */ 
     2093        @Override 
     2094        public String toString() { 
     2095            return "location (" + session + ", " + index + ")"; 
     2096        } 
     2097    } 
     2098     
     2099    /** 
     2100     * @author Patrick Harms 
     2101     */ 
     2102    private static class Collision { 
     2103         
     2104        /** */ 
     2105        private SubsequenceLocation location; 
     2106         
     2107        /** */ 
     2108        private Subsequence subsequence; 
     2109         
     2110        /** */ 
     2111        private Subsequence collidingWith; 
     2112         
     2113        /** 
     2114         *  
     2115         */ 
     2116        private Collision(SubsequenceLocation location, 
     2117                          Subsequence         subsequence, 
     2118                          Subsequence         collidingWith) 
     2119        { 
     2120            this.location = location; 
     2121            this.subsequence = subsequence; 
     2122            this.collidingWith = collidingWith; 
     2123        } 
     2124 
     2125        /** 
     2126         * @return the collidingWith 
     2127         */ 
     2128        private Subsequence getCollidingWith() { 
     2129            return collidingWith; 
     2130        } 
     2131 
     2132        /** 
     2133         * @return the location 
     2134         */ 
     2135        private SubsequenceLocation getLocation() { 
     2136            return location; 
     2137        } 
     2138 
     2139        /** 
     2140         * @return the subsequence 
     2141         */ 
     2142        private Subsequence getSubsequence() { 
     2143            return subsequence; 
     2144        } 
     2145 
     2146        /* (non-Javadoc) 
     2147         * @see java.lang.Object#toString() 
     2148         */ 
     2149        @Override 
     2150        public String toString() { 
     2151            return "collision (" + location + " ," + subsequence + ", " + collidingWith + ")"; 
     2152        } 
    11102153    } 
    11112154     
Note: See TracChangeset for help on using the changeset viewer.