source: trunk/autoquest-core-tasktrees/src/main/java/de/ugoe/cs/autoquest/tasktrees/temporalrelation/SequenceForTaskDetectionRule.java @ 1294

Last change on this file since 1294 was 1294, checked in by pharms, 11 years ago
  • rework of task model to move event instance stuff to task instances
  • introduction of sequence, selection, iteration and optional instances
File size: 35.3 KB
RevLine 
[1113]1//   Copyright 2012 Georg-August-Universität Göttingen, Germany
2//
3//   Licensed under the Apache License, Version 2.0 (the "License");
4//   you may not use this file except in compliance with the License.
5//   You may obtain a copy of the License at
6//
7//       http://www.apache.org/licenses/LICENSE-2.0
8//
9//   Unless required by applicable law or agreed to in writing, software
10//   distributed under the License is distributed on an "AS IS" BASIS,
11//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12//   See the License for the specific language governing permissions and
13//   limitations under the License.
14
[1107]15package de.ugoe.cs.autoquest.tasktrees.temporalrelation;
16
[1285]17import java.util.HashMap;
18import java.util.HashSet;
[1107]19import java.util.Iterator;
20import java.util.LinkedList;
21import java.util.List;
[1285]22import java.util.Map;
23import java.util.Set;
24import java.util.logging.Level;
[1107]25
[1146]26import de.ugoe.cs.autoquest.tasktrees.taskequality.TaskEquality;
[1127]27import de.ugoe.cs.autoquest.tasktrees.treeifc.IIteration;
[1294]28import de.ugoe.cs.autoquest.tasktrees.treeifc.IIterationInstance;
[1127]29import de.ugoe.cs.autoquest.tasktrees.treeifc.ISelection;
[1294]30import de.ugoe.cs.autoquest.tasktrees.treeifc.ISelectionInstance;
[1107]31import de.ugoe.cs.autoquest.tasktrees.treeifc.ISequence;
[1294]32import de.ugoe.cs.autoquest.tasktrees.treeifc.ISequenceInstance;
[1146]33import de.ugoe.cs.autoquest.tasktrees.treeifc.ITask;
34import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskBuilder;
35import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskFactory;
36import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskInstance;
37import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskInstanceList;
38import de.ugoe.cs.autoquest.tasktrees.treeifc.IUserSession;
[1256]39import de.ugoe.cs.autoquest.usageprofiles.SymbolMap;
[1119]40import de.ugoe.cs.autoquest.usageprofiles.TrieProcessor;
[1129]41import de.ugoe.cs.util.StopWatch;
[1285]42import de.ugoe.cs.util.console.Console;
[1107]43
44/**
45 * <p>
46 * TODO comment
47 * </p>
48 *
49 * @author Patrick Harms
50 */
[1146]51class SequenceForTaskDetectionRule implements ISessionScopeRule {
[1107]52   
53    /**
54     * <p>
[1146]55     * the task factory to be used for creating substructures for the temporal
[1107]56     * relationships identified during rule
57     * </p>
58     */
[1146]59    private ITaskFactory taskFactory;
[1107]60    /**
61     * <p>
[1146]62     * the task builder to be used for creating substructures for the temporal relationships
[1107]63     * identified during rule application
64     * </p>
65     */
[1146]66    private ITaskBuilder taskBuilder;
[1107]67
68    /**
69     * <p>
[1285]70     * the task comparator to be used for comparing tasks for preparation
[1107]71     * </p>
72     */
[1285]73    private TaskHandlingStrategy preparationTaskHandlingStrategy;
74   
[1107]75    /**
76     * <p>
[1285]77     * the task comparator to be used for comparing tasks during iteration detection an trie
78     * generation
79     * </p>
80     */
81    private TaskHandlingStrategy identityTaskHandlingStrategy;;
82   
83    /**
84     * <p>
[1146]85     * instantiates the rule and initializes it with a task equality rule manager and the minimal
86     * task equality identified sublist must have to consider them as iterated.
[1107]87     * </p>
88     */
[1189]89    SequenceForTaskDetectionRule(TaskEquality minimalTaskEquality,
90                                 ITaskFactory taskFactory,
91                                 ITaskBuilder taskBuilder)
[1107]92    {
[1146]93        this.taskFactory = taskFactory;
94        this.taskBuilder = taskBuilder;
[1107]95       
[1285]96        this.preparationTaskHandlingStrategy = new TaskHandlingStrategy(minimalTaskEquality);
97        this.identityTaskHandlingStrategy = new TaskHandlingStrategy(TaskEquality.IDENTICAL);
[1107]98    }
99
[1119]100    /* (non-Javadoc)
101     * @see java.lang.Object#toString()
102     */
103    @Override
104    public String toString() {
[1127]105        return "SequenceForTaskDetectionRule";
[1119]106    }
107
[1146]108    /* (non-Javadoc)
109     * @see de.ugoe.cs.autoquest.tasktrees.temporalrelation.ISessionScopeRule#apply(java.util.List)
[1107]110     */
111    @Override
[1146]112    public RuleApplicationResult apply(List<IUserSession> sessions) {
[1127]113        RuleApplicationData appData = new RuleApplicationData(sessions);
114
115        // this is the real rule application. Loop while something is replaced.
[1256]116        harmonizeEventTaskInstancesModel(appData);
[1107]117        do {
[1127]118            System.out.println();
[1107]119           
[1127]120            appData.getStopWatch().start("whole loop");
121            detectAndReplaceIterations(appData);
[1133]122
[1127]123            appData.getStopWatch().start("task replacement");
124            detectAndReplaceTasks(appData);
125            appData.getStopWatch().stop("task replacement");
126            appData.getStopWatch().stop("whole loop");
[1107]127           
[1146]128            //((TaskTreeNodeComparator) taskComparator).getStopWatch().dumpStatistics(System.out);
129            //((TaskTreeNodeComparator) taskComparator).getStopWatch().reset();
[1127]130           
131            appData.getStopWatch().dumpStatistics(System.out);
132            appData.getStopWatch().reset();
133           
[1107]134        }
[1146]135        while (appData.detectedAndReplacedTasks());
[1107]136       
[1146]137        System.out.println
138            ("created " + appData.getResult().getNewlyCreatedTasks().size() +
139             " new tasks and " + appData.getResult().getNewlyCreatedTaskInstances().size() +
140             " appropriate instances\n");
[1107]141       
[1146]142        if ((appData.getResult().getNewlyCreatedTasks().size() > 0) ||
143            (appData.getResult().getNewlyCreatedTaskInstances().size() > 0))
144        {
[1127]145            appData.getResult().setRuleApplicationStatus(RuleApplicationStatus.FINISHED);
[1119]146        }
147       
[1127]148        return appData.getResult();
149    }
150
151    /**
[1256]152     * <p>
153     * TODO: comment
154     * </p>
155     *
[1127]156     * @param appData
157     */
[1256]158    private void harmonizeEventTaskInstancesModel(RuleApplicationData appData) {
[1285]159        Console.traceln(Level.INFO, "harmonizing task model of event task instances");
[1256]160        appData.getStopWatch().start("harmonizing event tasks");
[1285]161
162        SymbolMap<ITaskInstance, ITask> uniqueTasks =
163            preparationTaskHandlingStrategy.createSymbolMap();
[1294]164        TaskInstanceComparator comparator = preparationTaskHandlingStrategy.getTaskComparator();
[1256]165       
166        int unifiedTasks = 0;
[1285]167        ITask task;
[1256]168        List<IUserSession> sessions = appData.getSessions();
169        for (IUserSession session : sessions) {
[1285]170            Console.traceln(Level.FINE, "handling session " + session);
[1256]171            for (ITaskInstance taskInstance : session) {
[1285]172                task = uniqueTasks.getValue(taskInstance);
[1256]173               
174                if (task == null) {
[1285]175                    uniqueTasks.addSymbol(taskInstance, taskInstance.getTask());
[1256]176                }
177                else {
178                    taskBuilder.setTask(taskInstance, task);
179                    unifiedTasks++;
180                }
181            }
[1285]182           
183            comparator.clearBuffers();
[1256]184        }
185       
186        appData.getStopWatch().stop("harmonizing event tasks");
[1285]187        Console.traceln(Level.INFO, "harmonized " + unifiedTasks + " task occurrences (still " +
188                        uniqueTasks.size() + " different tasks)");
189
[1256]190        appData.getStopWatch().dumpStatistics(System.out);
[1285]191        appData.getStopWatch().reset();
[1256]192    }
193
194    /**
195     * @param appData
196     */
[1127]197    private void detectAndReplaceIterations(RuleApplicationData appData) {
[1285]198        Console.traceln(Level.FINE, "detecting iterations");
[1127]199        appData.getStopWatch().start("detecting iterations");
[1119]200       
[1146]201        List<IUserSession> sessions = appData.getSessions();
[1127]202       
[1285]203        Set<ITask> iteratedTasks = searchIteratedTasks(sessions);
[1146]204       
[1285]205        if (iteratedTasks.size() > 0) {
206            replaceIterationsOf(iteratedTasks, sessions, appData);
[1127]207        }
208       
209        appData.getStopWatch().stop("detecting iterations");
[1285]210        Console.traceln(Level.INFO, "replaced " + iteratedTasks.size() + " iterated tasks");
[1127]211    }
212
213    /**
[1146]214     *
[1127]215     */
[1285]216    private Set<ITask> searchIteratedTasks(List<IUserSession> sessions) {
217        Set<ITask> iteratedTasks = new HashSet<ITask>();
[1146]218        for (IUserSession session : sessions) {
219            for (int i = 0; i < (session.size() - 1); i++) {
[1285]220                // we prepared the task instances to refer to unique tasks, if they are treated
221                // as equal. Therefore, we just compare the identity of the tasks of the task
222                // instances
223                if (session.get(i).getTask() == session.get(i + 1).getTask()) {
224                    iteratedTasks.add(session.get(i).getTask());
[1146]225                }
226            }
227        }
228       
[1285]229        return iteratedTasks;
[1146]230    }
231
232    /**
233     *
234     */
[1285]235    private void replaceIterationsOf(Set<ITask>          iteratedTasks,
[1146]236                                     List<IUserSession>  sessions,
237                                     RuleApplicationData appData)
[1127]238    {
[1285]239        Map<ITask, IIteration> iterations = new HashMap<ITask, IIteration>();
[1294]240        Map<IIteration, List<IIterationInstance>> iterationInstances =
241                new HashMap<IIteration, List<IIterationInstance>>();
[1285]242           
243        for (ITask iteratedTask : iteratedTasks) {
244            IIteration iteration = taskFactory.createNewIteration();
245            iterations.put(iteratedTask, iteration);
[1294]246            iterationInstances.put(iteration, new LinkedList<IIterationInstance>());
[1285]247        }
248       
[1294]249        IIterationInstance iterationInstance = null;
[1127]250       
[1146]251        for (IUserSession session : sessions) {
252            int index = 0;
253            while (index < session.size()) {
[1285]254                // we prepared the task instances to refer to unique tasks, if they are treated
255                // as equal. Therefore, we just compare the identity of the tasks of the task
256                // instances
257                ITask currentTask = session.get(index).getTask();
258                IIteration iteration = iterations.get(currentTask);
259                if (iteration != null) {
260                    if ((iterationInstance == null) || (iterationInstance.getTask() != iteration))
261                    {
[1146]262                        iterationInstance = taskFactory.createNewTaskInstance(iteration);
[1285]263                        iterationInstances.get(iteration).add(iterationInstance);
[1146]264                        taskBuilder.addTaskInstance(session, index, iterationInstance);
265                        index++;
266                    }
267                   
268                    taskBuilder.addChild(iterationInstance, session.get(index));
269                    taskBuilder.removeTaskInstance(session, index);
270                }
271                else {
272                    if (iterationInstance != null) {
273                        iterationInstance = null;
274                    }
275                    index++;
276                }
277            }
278        }
279       
[1294]280        for (Map.Entry<IIteration, List<IIterationInstance>> entry : iterationInstances.entrySet())
281        {
[1285]282            harmonizeIterationInstancesModel(entry.getKey(), entry.getValue());
283        }
[1146]284    }
[1127]285
[1146]286    /**
287     *
288     */
[1294]289    private void harmonizeIterationInstancesModel(IIteration               iteration,
290                                                  List<IIterationInstance> iterationInstances)
[1146]291    {
292        List<ITask> iteratedTaskVariants = new LinkedList<ITask>();
[1294]293        TaskInstanceComparator comparator = preparationTaskHandlingStrategy.getTaskComparator();
[1146]294       
295        // merge the lexically different variants of iterated task to a unique list
[1294]296        for (IIterationInstance iterationInstance : iterationInstances) {
[1146]297            for (ITaskInstance executionVariant : iterationInstance) {
298                ITask candidate = executionVariant.getTask();
[1127]299           
[1146]300                boolean found = false;
301                for (ITask taskVariant : iteratedTaskVariants) {
[1285]302                    if (comparator.areLexicallyEqual(taskVariant, candidate)) {
[1146]303                        taskBuilder.setTask(executionVariant, taskVariant);
304                        found = true;
305                        break;
306                    }
[1127]307                }
[1146]308               
309                if (!found) {
310                    iteratedTaskVariants.add(candidate);
311                }
[1107]312            }
313        }
314       
[1146]315        // if there are more than one lexically different variant of iterated tasks, adapt the
316        // iteration model to be a selection of different variants. In this case also adapt
317        // the generated iteration instances to correctly contain selection instances. If there
318        // is only one variant of an iterated task, simply set this as the marked task of the
319        // iteration. In this case, the instances can be preserved as is
320        if (iteratedTaskVariants.size() > 1) {
321            ISelection selection = taskFactory.createNewSelection();
322           
323            for (ITask variant : iteratedTaskVariants) {
324                taskBuilder.addChild(selection, variant);
325            }
326           
327            taskBuilder.setMarkedTask(iteration, selection);
328           
[1294]329            for (IIterationInstance instance : iterationInstances) {
[1146]330                for (int i = 0; i < instance.size(); i++) {
[1294]331                    ISelectionInstance selectionInstance =
332                        taskFactory.createNewTaskInstance(selection);
333                    taskBuilder.setChild(selectionInstance, instance.get(i));
[1146]334                    taskBuilder.setTaskInstance(instance, i, selectionInstance);
335                }
336            }
337        }
338        else {
339            taskBuilder.setMarkedTask(iteration, iteratedTaskVariants.get(0));
340        }
[1107]341    }
342
343    /**
[1127]344     * @param appData
345     */
346    private void detectAndReplaceTasks(RuleApplicationData appData) {
[1285]347        Console.traceln(Level.FINE, "detecting and replacing tasks");
[1127]348        appData.getStopWatch().start("detecting tasks");
349       
350        getSequencesOccuringMostOften(appData);
351
352        appData.getStopWatch().stop("detecting tasks");
353        appData.getStopWatch().start("replacing tasks");
354       
355        replaceSequencesOccurringMostOften(appData);
356       
357        appData.getStopWatch().stop("replacing tasks");
[1285]358        Console.traceln(Level.INFO, "detected and replaced " + appData.getLastFoundTasks().size() +
359                        " tasks occuring " + appData.getLastFoundTasks().getOccurrenceCount() +
[1287]360                        " times");
[1127]361    }
362
363    /**
[1119]364     * @return
[1107]365     */
[1127]366    private void getSequencesOccuringMostOften(RuleApplicationData appData) {
[1285]367        Console.traceln(Level.FINE, "determining most prominent tasks");
[1119]368
[1127]369        Tasks tasks;
[1119]370        boolean createNewTrie = (appData.getLastTrie() == null) ||
[1146]371            appData.detectedAndReplacedTasks(); // tree has changed
[1107]372       
[1119]373        do {
374            if (createNewTrie) {
375                createNewTrie(appData);
376            }
[1107]377           
[1127]378            MaxCountAndLongestTasksFinder finder = new MaxCountAndLongestTasksFinder();
[1119]379            appData.getLastTrie().process(finder);
380       
[1127]381            tasks = finder.getFoundTasks();
[1119]382           
383            createNewTrie = false;
384           
[1146]385            for (List<ITaskInstance> task : tasks) {
[1119]386                if (task.size() >= appData.getTrainedSequenceLength()) {
387                    // Trie must be recreated with a longer sequence length to be sure that
388                    // the found sequences occurring most often are found in their whole length
389                    appData.setTrainedSequenceLength(appData.getTrainedSequenceLength() + 1);
390                    createNewTrie = true;
391                    break;
392                }
[1107]393            }
394        }
[1119]395        while (createNewTrie);
396       
[1256]397        // create a normal trie for comparison
398        /*System.out.println("creating test trie for comparison");
399       
400        appData.getStopWatch().start("testtrie");
[1285]401        Trie<ITaskInstance> trie = new Trie<ITaskInstance>(identityTaskComparator);
[1256]402       
403        for (IUserSession session : appData.getSessions()) {
404            trie.train(session.getExecutedTasks(), appData.getTrainedSequenceLength());
405        }
406       
407        appData.getStopWatch().stop("testtrie");
408       
409        MaxCountAndLongestTasksFinder finder = new MaxCountAndLongestTasksFinder();
410        trie.process(finder);
411
412        boolean allTasksEqual = finder.getFoundTasks().size() == tasks.size();
413       
414        allTasksEqual &= finder.getFoundTasks().occurrenceCount == tasks.occurrenceCount;
415       
416        for (List<ITaskInstance> task1 : finder.getFoundTasks()) {
417            boolean foundTask = false;
418            for (List<ITaskInstance> task2 : tasks) {
419                boolean tasksEqual = false;
420                if (task1.size() == task2.size()) {
421                    tasksEqual = true;
422                    for (int i = 0; i < task1.size(); i++) {
[1285]423                        if (!identityTaskComparator.equals(task1.get(i).getTask(), task2.get(i).getTask()))
[1256]424                        {
425                            tasksEqual = false;
426                        }
427                    }
428                }
429               
430                if (tasksEqual) {
431                    foundTask = true;
432                    break;
433                }
434            }
435           
436            if (!foundTask) {
437                System.out.println("different is " + task1);
438                allTasksEqual = false;
439                break;
440            }
441        }
442       
443        if (!allTasksEqual) {
444            System.out.println(finder.getFoundTasks());
445            System.out.println(tasks);
446           
447            throw new IllegalArgumentException("both tries calculated different subsequences");
[1285]448        }
[1256]449       
450        /*TrieStatisticsDumper dumper = new TrieStatisticsDumper();
451        appData.getLastTrie().process(dumper);
452        dumper.dumpCounters();*/
453       
[1127]454        appData.setLastFoundTasks(tasks);
455
[1285]456        Console.traceln(Level.FINE, "found " + appData.getLastFoundTasks().size() + " tasks " +
457                        "occurring " + appData.getLastFoundTasks().getOccurrenceCount() + " times");
[1107]458    }
459
460    /**
[1119]461     * @param parent
462     * @return
[1107]463     */
[1127]464    private void createNewTrie(RuleApplicationData appData) {
[1285]465        Console.traceln(Level.FINER, "training trie with a maximum sequence length of " +
466                        appData.getTrainedSequenceLength());
[1119]467
468        appData.getStopWatch().start("training trie");
[1285]469       
470        // we prepared the task instances to refer to unique tasks, if they are treated
471        // as equal. Therefore, we just compare the identity of the tasks of the task
472        // instances
473        appData.setLastTrie(new TaskInstanceTrie(identityTaskHandlingStrategy));
[1119]474   
[1256]475        appData.getLastTrie().trainSessions
476            (appData.getSessions(), appData.getTrainedSequenceLength());
[1127]477       
[1119]478        appData.getStopWatch().stop("training trie");
479    }
480
481    /**
[1127]482     * @param appData
483     */
484    private void replaceSequencesOccurringMostOften(RuleApplicationData appData) {
[1146]485        appData.detectedAndReplacedTasks(false);
[1127]486
487        if ((appData.getLastFoundTasks().size() > 0) &&
488            (appData.getLastFoundTasks().getOccurrenceCount() > 1))
489        {
[1285]490            Console.traceln(Level.FINER, "replacing tasks occurrences");
[1127]491
[1146]492            for (List<ITaskInstance> task : appData.getLastFoundTasks()) {
493                ISequence sequence = taskFactory.createNewSequence();
494               
[1285]495                Console.traceln(Level.FINEST, "replacing " + sequence.getId() + ": " + task);
[1127]496
[1294]497                List<ISequenceInstance> sequenceInstances =
[1146]498                    replaceTaskOccurrences(task, appData.getSessions(), sequence);
[1119]499               
[1146]500                harmonizeSequenceInstancesModel(sequence, sequenceInstances,task.size());
[1285]501                appData.detectedAndReplacedTasks
502                    (appData.detectedAndReplacedTasks() || (sequenceInstances.size() > 0));
[1127]503
[1146]504                if (sequenceInstances.size() < appData.getLastFoundTasks().getOccurrenceCount()) {
[1285]505                    Console.traceln(Level.FINE, sequence.getId() + ": replaced task only " +
506                                    sequenceInstances.size() + " times instead of expected " +
507                                    appData.getLastFoundTasks().getOccurrenceCount());
[1127]508                }
509            }
510        }
511       
512    }
513
514    /**
[1146]515     *
516     */
[1294]517    private void harmonizeSequenceInstancesModel(ISequence               sequence,
518                                                 List<ISequenceInstance> sequenceInstances,
519                                                 int                     sequenceLength)
[1146]520    {
[1294]521        TaskInstanceComparator comparator = preparationTaskHandlingStrategy.getTaskComparator();
[1146]522       
523        // ensure for each subtask that lexically different variants are preserved
524        for (int subTaskIndex = 0; subTaskIndex < sequenceLength; subTaskIndex++) {
525            List<ITask> subTaskVariants = new LinkedList<ITask>();
526           
[1294]527            for (ISequenceInstance sequenceInstance : sequenceInstances) {
[1146]528                ITask candidate = sequenceInstance.get(subTaskIndex).getTask();
529               
530                boolean found = false;
531               
532                for (int i = 0; i < subTaskVariants.size(); i++) {
[1285]533                    if (comparator.areLexicallyEqual(subTaskVariants.get(i), candidate)) {
[1146]534                        taskBuilder.setTask
535                            (sequenceInstance.get(subTaskIndex), subTaskVariants.get(i));
536                       
537                        found = true;
538                        break;
539                    }
540                }
541               
542                if (!found) {
543                    subTaskVariants.add(candidate);
544                }
545            }
546           
547            // if there are more than one lexically different variant of the sub task at
548            // the considered position, adapt the sequence model at that position to have
549            // a selection of the different variants. In this case also adapt the
550            // generated sequence instances to correctly contain selection instances. If
551            // there is only one variant of sub tasks at the given position, simply set
552            // this variant as the sub task of the selection. In this case, the instances
553            // can be preserved as is
554            if (subTaskVariants.size() > 1) {
555                ISelection selection = taskFactory.createNewSelection();
556               
557                for (ITask variant : subTaskVariants) {
558                    taskBuilder.addChild(selection, variant);
559                }
560               
561                taskBuilder.addChild(sequence, selection);
562               
[1294]563                for (ISequenceInstance instance : sequenceInstances) {
564                    ISelectionInstance selectionInstance =
[1146]565                        taskFactory.createNewTaskInstance(selection);
[1294]566                    taskBuilder.setChild(selectionInstance, instance.get(subTaskIndex));
[1146]567                    taskBuilder.setTaskInstance(instance, subTaskIndex, selectionInstance);
568                }
569            }
570            else if (subTaskVariants.size() == 1) {
571                taskBuilder.addChild(sequence, subTaskVariants.get(0));
572            }
573        }
574    }
575
576    /**
[1127]577     * @param tree
578     */
[1294]579    private List<ISequenceInstance> replaceTaskOccurrences(List<ITaskInstance> task,
580                                                           List<IUserSession>  sessions,
581                                                           ISequence           temporalTaskModel)
[1127]582    {
[1294]583        List<ISequenceInstance> sequenceInstances = new LinkedList<ISequenceInstance>();
[1146]584       
585        for (IUserSession session : sessions) {
[1127]586            int index = -1;
[1119]587               
[1127]588            do {
[1146]589                index = getSubListIndex(session, task, ++index);
[1127]590
591                if (index > -1) {
[1146]592                    sequenceInstances.add
593                        (RuleUtils.createNewSubSequenceInRange
594                             (session, index, index + task.size() - 1, temporalTaskModel,
595                              taskFactory, taskBuilder));
[1107]596                }
597            }
[1127]598            while (index > -1);
[1107]599        }
[1146]600       
601        return sequenceInstances;
[1107]602    }
603
604    /**
[1146]605     * @param trie
606     * @param object
[1127]607     * @return
608     */
[1146]609    private int getSubListIndex(ITaskInstanceList   list,
610                                List<ITaskInstance> subList,
611                                int                 startIndex)
[1127]612    {
[1146]613        boolean matchFound;
614        int result = -1;
[1127]615       
[1146]616        for (int i = startIndex; i <= list.size() - subList.size(); i++) {
617            matchFound = true;
[1127]618           
[1146]619            for (int j = 0; j < subList.size(); j++) {
[1285]620                // we prepared the task instances to refer to unique tasks, if they are treated
621                // as equal. Therefore, we just compare the identity of the tasks of the task
622                // instances
623                if (list.get(i + j).getTask() != subList.get(j).getTask()) {
[1146]624                    matchFound = false;
625                    break;
626                }
[1127]627            }
628           
[1146]629            if (matchFound) {
630                result = i;
631                break;
632            }
[1127]633        }
[1107]634       
[1146]635        return result;
[1107]636    }
637
638    /**
639     * @param trie
640     * @param object
641     * @return
642     */
[1146]643    private int getSubListIndex(List<ITaskInstance> list,
644                                List<ITaskInstance> subList,
[1107]645                                int                 startIndex)
646    {
647        boolean matchFound;
648        int result = -1;
649       
650        for (int i = startIndex; i <= list.size() - subList.size(); i++) {
651            matchFound = true;
652           
653            for (int j = 0; j < subList.size(); j++) {
[1285]654                // we prepared the task instances to refer to unique tasks, if they are treated
655                // as equal. Therefore, we just compare the identity of the tasks of the task
656                // instances
657                if (list.get(i + j) != subList.get(j)) {
[1107]658                    matchFound = false;
659                    break;
660                }
661            }
662           
663            if (matchFound) {
664                result = i;
665                break;
666            }
667        }
668       
669        return result;
670    }
671   
[1119]672    /**
673     * @author Patrick Harms
674     */
[1146]675    private class MaxCountAndLongestTasksFinder implements TrieProcessor<ITaskInstance> {
[1119]676       
677        /**
678         *
679         */
680        private int currentCount;
681       
682        /**
683         *
684         */
[1146]685        private List<List<ITaskInstance>> foundTasks = new LinkedList<List<ITaskInstance>>();
[1119]686
687        /**
688         *
689         */
[1127]690        public MaxCountAndLongestTasksFinder() {
[1119]691            super();
692            this.currentCount = 0;
693        }
694
695        /* (non-Javadoc)
696         * @see de.ugoe.cs.autoquest.usageprofiles.TrieProcessor#process(java.util.List, int)
697         */
698        @Override
[1146]699        public TrieProcessor.Result process(List<ITaskInstance> foundTask, int count) {
700            if (foundTask.size() < 2) {
701                // ignore single tasks
[1119]702                return TrieProcessor.Result.CONTINUE;
703            }
704           
705            if (count < 2) {
706                // ignore singular occurrences
707                return TrieProcessor.Result.SKIP_NODE;
708            }
709
710            if (this.currentCount > count) {
[1146]711                // ignore this children of this task, as they may have only smaller counts than
[1127]712                // the already found tasks
[1119]713                return TrieProcessor.Result.SKIP_NODE;
714            }
715           
716            if (this.currentCount < count) {
[1127]717                // the provided task occurs more often that all tasks found so far.
718                // clear all found tasks and use the new count as the one searched for
719                foundTasks.clear();
[1119]720                this.currentCount = count;
721            }
722           
723            if (this.currentCount == count) {
[1127]724                // the task is of interest. Sort it into the other found tasks so that
[1119]725                // the longest come first
726                boolean added = false;
[1127]727                for (int i = 0; i < foundTasks.size(); i++) {
[1146]728                    if (foundTasks.get(i).size() < foundTask.size()) {
[1119]729                        // defensive copy
[1146]730                        foundTasks.add(i, new LinkedList<ITaskInstance>(foundTask)); // defensive copy
[1119]731                        added = true;
732                        break;
733                    }
734                }
735               
736                if (!added) {
[1146]737                    foundTasks.add(new LinkedList<ITaskInstance>(foundTask)); // defensive copy
[1119]738                }
739            }
740           
741            return TrieProcessor.Result.CONTINUE;
742        }
743
744        /**
[1133]745         *  @return
[1119]746         */
[1127]747        public Tasks getFoundTasks() {
[1119]748            removePermutationsOfShorterTasks();
[1127]749            return new Tasks(currentCount, foundTasks);
[1119]750        }
751
752        /**
753         *
754         */
755        private void removePermutationsOfShorterTasks() {
756            // now iterate the sorted list and for each task remove all other tasks that are shorter
757            // (i.e. come later in the sorted list) and that represent a subpart of the task
[1127]758            for (int i = 0; i < foundTasks.size(); i++) {
759                for (int j = i + 1; j < foundTasks.size();) {
760                    if (foundTasks.get(j).size() < foundTasks.get(i).size()) {
[1119]761                        // found a task that is a potential subtask. Check for this and remove the
762                        // subtask if needed
[1146]763                        List<ITaskInstance> longTask = foundTasks.get(i);
764                        List<ITaskInstance> shortTask = foundTasks.get(j);
[1119]765                       
766                        if (getSubListIndex(longTask, shortTask, 0) > -1) {
[1127]767                            foundTasks.remove(j);
[1119]768                        }
769                        else {
770                            j++;
771                        }
772                    }
773                    else {
774                        j++;
775                    }
776                }
777            }
778        }
779
780    }
781   
[1256]782//    /**
783//     * @author Patrick Harms
784//     */
785//    private class TrieStatisticsDumper implements TrieProcessor<ITaskInstance> {
786//       
787//        /**
788//         *
789//         */
790//        private Map<Integer, Integer> counters = new HashMap<Integer, Integer>();
791//       
792//        /* (non-Javadoc)
793//         * @see de.ugoe.cs.autoquest.usageprofiles.TrieProcessor#process(java.util.List, int)
794//         */
795//        @Override
796//        public TrieProcessor.Result process(List<ITaskInstance> subsequence, int count) {
797//            if (subsequence.size() == 1) {
798//                Integer value = counters.get(count);
799//               
800//                if (value == null) {
801//                    value = 0;
802//                }
803//               
804//                counters.put(count, value + 1);
805//               
806//                return TrieProcessor.Result.CONTINUE;
807//            }
808//            else {
809//                // ignore singular occurrences
810//                return TrieProcessor.Result.SKIP_NODE;
811//            }
812//        }
813//
814//        /**
815//         *  @return
816//         */
817//        public void dumpCounters() {
818//            int dumpedCounters = 0;
819//           
820//            int count = 1;
821//            while (dumpedCounters < counters.size()) {
822//                Integer value = counters.get(count++);
823//                if (value != null) {
824//                    System.out.println(value + " symbols occurred " + count + " times");
825//                    dumpedCounters++;
826//                }
827//            }
828//        }
829//
830//    }
831   
[1119]832    /**
833     *
834     */
[1133]835    private static class RuleApplicationData {
[1119]836       
837        /**
838         *
839         */
[1146]840        private List<IUserSession> sessions;
[1119]841       
842        /**
843         *
844         */
[1256]845        private TaskInstanceTrie lastTrie;
[1119]846       
847        /**
[1127]848         * default and minimum trained sequence length is 3
[1119]849         */
[1127]850        private int trainedSequenceLength = 3;
[1119]851       
852        /**
853         *
854         */
[1127]855        private Tasks lastFoundTasks = new Tasks(Integer.MAX_VALUE, null);
[1119]856       
857        /**
[1127]858         *
[1119]859         */
[1146]860        private boolean detectedAndReplacedTasks;
[1119]861       
862        /**
863         *
864         */
[1127]865        private RuleApplicationResult result = new RuleApplicationResult();
866       
867        /**
868         *
869         */
[1119]870        private StopWatch stopWatch = new StopWatch();
871       
872        /**
873         *
874         */
[1146]875        private RuleApplicationData(List<IUserSession> sessions) {
[1127]876            this.sessions = sessions;
[1119]877        }
878
879        /**
[1127]880         * @return the tree
[1119]881         */
[1146]882        private List<IUserSession> getSessions() {
[1127]883            return sessions;
[1119]884        }
885
886        /**
[1127]887         * @param lastTrie the lastTrie to set
[1119]888         */
[1256]889        private void setLastTrie(TaskInstanceTrie lastTrie) {
[1127]890            this.lastTrie = lastTrie;
[1119]891        }
892
893        /**
894         * @return the lastTrie
895         */
[1256]896        private TaskInstanceTrie getLastTrie() {
[1119]897            return lastTrie;
898        }
899
900        /**
[1127]901         * @param trainedSequenceLength the trainedSequenceLength to set
902         */
903        private void setTrainedSequenceLength(int trainedSequenceLength) {
904            this.trainedSequenceLength = trainedSequenceLength;
905        }
906
907        /**
[1119]908         * @return the trainedSequenceLength
909         */
910        private int getTrainedSequenceLength() {
911            return trainedSequenceLength;
912        }
913
914        /**
[1127]915         * @param lastFoundSequences the lastFoundSequences to set
[1119]916         */
[1127]917        private void setLastFoundTasks(Tasks lastFoundSequences) {
918            this.lastFoundTasks = lastFoundSequences;
[1119]919        }
920
921        /**
[1127]922         * @return the lastFoundSequences
[1119]923         */
[1127]924        private Tasks getLastFoundTasks() {
925            return lastFoundTasks;
[1119]926        }
927
928        /**
929         *
930         */
[1146]931        private void detectedAndReplacedTasks(boolean detectedAndReplacedTasks) {
932            this.detectedAndReplacedTasks = detectedAndReplacedTasks;
[1119]933        }
934
935        /**
936         *
937         */
[1146]938        private boolean detectedAndReplacedTasks() {
939            return detectedAndReplacedTasks;
[1119]940        }
[1127]941       
942        /**
943         * @return the result
944         */
945        private RuleApplicationResult getResult() {
946            return result;
947        }
948
949        /**
950         * @return the stopWatch
951         */
952        private StopWatch getStopWatch() {
953            return stopWatch;
954        }
955
[1119]956    }
957   
958
959    /**
960     * @author Patrick Harms
961     */
[1146]962    private static class Tasks implements Iterable<List<ITaskInstance>> {
[1119]963       
964        /**
965         *
966         */
967        private int occurrenceCount;
968       
969        /**
970         *
971         */
[1146]972        private List<List<ITaskInstance>> sequences;
[1119]973
974        /**
975         * @param occurrenceCount
976         * @param sequences
977         */
[1146]978        private Tasks(int occurrenceCount, List<List<ITaskInstance>> sequences) {
[1119]979            super();
980            this.occurrenceCount = occurrenceCount;
981            this.sequences = sequences;
982        }
983
984        /**
985         * @return
986         */
987        private int getOccurrenceCount() {
988            return occurrenceCount;
989        }
990
991        /**
992         * @return
993         */
994        private int size() {
995            return this.sequences.size();
996        }
997
998        /**
999         *
1000         */
1001
1002        /* (non-Javadoc)
1003         * @see java.lang.Iterable#iterator()
1004         */
1005        @Override
[1146]1006        public Iterator<List<ITaskInstance>> iterator() {
[1119]1007            return this.sequences.iterator();
1008        }
1009
[1146]1010        /* (non-Javadoc)
[1256]1011         * @see java.lang.Object#toString()
[1146]1012         */
1013        @Override
[1256]1014        public String toString() {
1015            StringBuffer result = new StringBuffer();
1016            result.append(this.occurrenceCount);
1017            result.append(" occurrences:\n");
[1146]1018           
[1256]1019            for (List<ITaskInstance> task : sequences) {
1020                result.append(task);
1021                result.append("\n");
[1146]1022            }
1023           
[1256]1024            return result.toString();
[1146]1025        }
1026
1027    }
[1107]1028}
Note: See TracBrowser for help on using the repository browser.