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
Line 
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
15package de.ugoe.cs.autoquest.tasktrees.temporalrelation;
16
17import java.util.HashMap;
18import java.util.HashSet;
19import java.util.Iterator;
20import java.util.LinkedList;
21import java.util.List;
22import java.util.Map;
23import java.util.Set;
24import java.util.logging.Level;
25
26import de.ugoe.cs.autoquest.tasktrees.taskequality.TaskEquality;
27import de.ugoe.cs.autoquest.tasktrees.treeifc.IIteration;
28import de.ugoe.cs.autoquest.tasktrees.treeifc.IIterationInstance;
29import de.ugoe.cs.autoquest.tasktrees.treeifc.ISelection;
30import de.ugoe.cs.autoquest.tasktrees.treeifc.ISelectionInstance;
31import de.ugoe.cs.autoquest.tasktrees.treeifc.ISequence;
32import de.ugoe.cs.autoquest.tasktrees.treeifc.ISequenceInstance;
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;
39import de.ugoe.cs.autoquest.usageprofiles.SymbolMap;
40import de.ugoe.cs.autoquest.usageprofiles.TrieProcessor;
41import de.ugoe.cs.util.StopWatch;
42import de.ugoe.cs.util.console.Console;
43
44/**
45 * <p>
46 * TODO comment
47 * </p>
48 *
49 * @author Patrick Harms
50 */
51class SequenceForTaskDetectionRule implements ISessionScopeRule {
52   
53    /**
54     * <p>
55     * the task factory to be used for creating substructures for the temporal
56     * relationships identified during rule
57     * </p>
58     */
59    private ITaskFactory taskFactory;
60    /**
61     * <p>
62     * the task builder to be used for creating substructures for the temporal relationships
63     * identified during rule application
64     * </p>
65     */
66    private ITaskBuilder taskBuilder;
67
68    /**
69     * <p>
70     * the task comparator to be used for comparing tasks for preparation
71     * </p>
72     */
73    private TaskHandlingStrategy preparationTaskHandlingStrategy;
74   
75    /**
76     * <p>
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>
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.
87     * </p>
88     */
89    SequenceForTaskDetectionRule(TaskEquality minimalTaskEquality,
90                                 ITaskFactory taskFactory,
91                                 ITaskBuilder taskBuilder)
92    {
93        this.taskFactory = taskFactory;
94        this.taskBuilder = taskBuilder;
95       
96        this.preparationTaskHandlingStrategy = new TaskHandlingStrategy(minimalTaskEquality);
97        this.identityTaskHandlingStrategy = new TaskHandlingStrategy(TaskEquality.IDENTICAL);
98    }
99
100    /* (non-Javadoc)
101     * @see java.lang.Object#toString()
102     */
103    @Override
104    public String toString() {
105        return "SequenceForTaskDetectionRule";
106    }
107
108    /* (non-Javadoc)
109     * @see de.ugoe.cs.autoquest.tasktrees.temporalrelation.ISessionScopeRule#apply(java.util.List)
110     */
111    @Override
112    public RuleApplicationResult apply(List<IUserSession> sessions) {
113        RuleApplicationData appData = new RuleApplicationData(sessions);
114
115        // this is the real rule application. Loop while something is replaced.
116        harmonizeEventTaskInstancesModel(appData);
117        do {
118            System.out.println();
119           
120            appData.getStopWatch().start("whole loop");
121            detectAndReplaceIterations(appData);
122
123            appData.getStopWatch().start("task replacement");
124            detectAndReplaceTasks(appData);
125            appData.getStopWatch().stop("task replacement");
126            appData.getStopWatch().stop("whole loop");
127           
128            //((TaskTreeNodeComparator) taskComparator).getStopWatch().dumpStatistics(System.out);
129            //((TaskTreeNodeComparator) taskComparator).getStopWatch().reset();
130           
131            appData.getStopWatch().dumpStatistics(System.out);
132            appData.getStopWatch().reset();
133           
134        }
135        while (appData.detectedAndReplacedTasks());
136       
137        System.out.println
138            ("created " + appData.getResult().getNewlyCreatedTasks().size() +
139             " new tasks and " + appData.getResult().getNewlyCreatedTaskInstances().size() +
140             " appropriate instances\n");
141       
142        if ((appData.getResult().getNewlyCreatedTasks().size() > 0) ||
143            (appData.getResult().getNewlyCreatedTaskInstances().size() > 0))
144        {
145            appData.getResult().setRuleApplicationStatus(RuleApplicationStatus.FINISHED);
146        }
147       
148        return appData.getResult();
149    }
150
151    /**
152     * <p>
153     * TODO: comment
154     * </p>
155     *
156     * @param appData
157     */
158    private void harmonizeEventTaskInstancesModel(RuleApplicationData appData) {
159        Console.traceln(Level.INFO, "harmonizing task model of event task instances");
160        appData.getStopWatch().start("harmonizing event tasks");
161
162        SymbolMap<ITaskInstance, ITask> uniqueTasks =
163            preparationTaskHandlingStrategy.createSymbolMap();
164        TaskInstanceComparator comparator = preparationTaskHandlingStrategy.getTaskComparator();
165       
166        int unifiedTasks = 0;
167        ITask task;
168        List<IUserSession> sessions = appData.getSessions();
169        for (IUserSession session : sessions) {
170            Console.traceln(Level.FINE, "handling session " + session);
171            for (ITaskInstance taskInstance : session) {
172                task = uniqueTasks.getValue(taskInstance);
173               
174                if (task == null) {
175                    uniqueTasks.addSymbol(taskInstance, taskInstance.getTask());
176                }
177                else {
178                    taskBuilder.setTask(taskInstance, task);
179                    unifiedTasks++;
180                }
181            }
182           
183            comparator.clearBuffers();
184        }
185       
186        appData.getStopWatch().stop("harmonizing event tasks");
187        Console.traceln(Level.INFO, "harmonized " + unifiedTasks + " task occurrences (still " +
188                        uniqueTasks.size() + " different tasks)");
189
190        appData.getStopWatch().dumpStatistics(System.out);
191        appData.getStopWatch().reset();
192    }
193
194    /**
195     * @param appData
196     */
197    private void detectAndReplaceIterations(RuleApplicationData appData) {
198        Console.traceln(Level.FINE, "detecting iterations");
199        appData.getStopWatch().start("detecting iterations");
200       
201        List<IUserSession> sessions = appData.getSessions();
202       
203        Set<ITask> iteratedTasks = searchIteratedTasks(sessions);
204       
205        if (iteratedTasks.size() > 0) {
206            replaceIterationsOf(iteratedTasks, sessions, appData);
207        }
208       
209        appData.getStopWatch().stop("detecting iterations");
210        Console.traceln(Level.INFO, "replaced " + iteratedTasks.size() + " iterated tasks");
211    }
212
213    /**
214     *
215     */
216    private Set<ITask> searchIteratedTasks(List<IUserSession> sessions) {
217        Set<ITask> iteratedTasks = new HashSet<ITask>();
218        for (IUserSession session : sessions) {
219            for (int i = 0; i < (session.size() - 1); i++) {
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());
225                }
226            }
227        }
228       
229        return iteratedTasks;
230    }
231
232    /**
233     *
234     */
235    private void replaceIterationsOf(Set<ITask>          iteratedTasks,
236                                     List<IUserSession>  sessions,
237                                     RuleApplicationData appData)
238    {
239        Map<ITask, IIteration> iterations = new HashMap<ITask, IIteration>();
240        Map<IIteration, List<IIterationInstance>> iterationInstances =
241                new HashMap<IIteration, List<IIterationInstance>>();
242           
243        for (ITask iteratedTask : iteratedTasks) {
244            IIteration iteration = taskFactory.createNewIteration();
245            iterations.put(iteratedTask, iteration);
246            iterationInstances.put(iteration, new LinkedList<IIterationInstance>());
247        }
248       
249        IIterationInstance iterationInstance = null;
250       
251        for (IUserSession session : sessions) {
252            int index = 0;
253            while (index < session.size()) {
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                    {
262                        iterationInstance = taskFactory.createNewTaskInstance(iteration);
263                        iterationInstances.get(iteration).add(iterationInstance);
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       
280        for (Map.Entry<IIteration, List<IIterationInstance>> entry : iterationInstances.entrySet())
281        {
282            harmonizeIterationInstancesModel(entry.getKey(), entry.getValue());
283        }
284    }
285
286    /**
287     *
288     */
289    private void harmonizeIterationInstancesModel(IIteration               iteration,
290                                                  List<IIterationInstance> iterationInstances)
291    {
292        List<ITask> iteratedTaskVariants = new LinkedList<ITask>();
293        TaskInstanceComparator comparator = preparationTaskHandlingStrategy.getTaskComparator();
294       
295        // merge the lexically different variants of iterated task to a unique list
296        for (IIterationInstance iterationInstance : iterationInstances) {
297            for (ITaskInstance executionVariant : iterationInstance) {
298                ITask candidate = executionVariant.getTask();
299           
300                boolean found = false;
301                for (ITask taskVariant : iteratedTaskVariants) {
302                    if (comparator.areLexicallyEqual(taskVariant, candidate)) {
303                        taskBuilder.setTask(executionVariant, taskVariant);
304                        found = true;
305                        break;
306                    }
307                }
308               
309                if (!found) {
310                    iteratedTaskVariants.add(candidate);
311                }
312            }
313        }
314       
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           
329            for (IIterationInstance instance : iterationInstances) {
330                for (int i = 0; i < instance.size(); i++) {
331                    ISelectionInstance selectionInstance =
332                        taskFactory.createNewTaskInstance(selection);
333                    taskBuilder.setChild(selectionInstance, instance.get(i));
334                    taskBuilder.setTaskInstance(instance, i, selectionInstance);
335                }
336            }
337        }
338        else {
339            taskBuilder.setMarkedTask(iteration, iteratedTaskVariants.get(0));
340        }
341    }
342
343    /**
344     * @param appData
345     */
346    private void detectAndReplaceTasks(RuleApplicationData appData) {
347        Console.traceln(Level.FINE, "detecting and replacing tasks");
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");
358        Console.traceln(Level.INFO, "detected and replaced " + appData.getLastFoundTasks().size() +
359                        " tasks occuring " + appData.getLastFoundTasks().getOccurrenceCount() +
360                        " times");
361    }
362
363    /**
364     * @return
365     */
366    private void getSequencesOccuringMostOften(RuleApplicationData appData) {
367        Console.traceln(Level.FINE, "determining most prominent tasks");
368
369        Tasks tasks;
370        boolean createNewTrie = (appData.getLastTrie() == null) ||
371            appData.detectedAndReplacedTasks(); // tree has changed
372       
373        do {
374            if (createNewTrie) {
375                createNewTrie(appData);
376            }
377           
378            MaxCountAndLongestTasksFinder finder = new MaxCountAndLongestTasksFinder();
379            appData.getLastTrie().process(finder);
380       
381            tasks = finder.getFoundTasks();
382           
383            createNewTrie = false;
384           
385            for (List<ITaskInstance> task : tasks) {
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                }
393            }
394        }
395        while (createNewTrie);
396       
397        // create a normal trie for comparison
398        /*System.out.println("creating test trie for comparison");
399       
400        appData.getStopWatch().start("testtrie");
401        Trie<ITaskInstance> trie = new Trie<ITaskInstance>(identityTaskComparator);
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++) {
423                        if (!identityTaskComparator.equals(task1.get(i).getTask(), task2.get(i).getTask()))
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");
448        }
449       
450        /*TrieStatisticsDumper dumper = new TrieStatisticsDumper();
451        appData.getLastTrie().process(dumper);
452        dumper.dumpCounters();*/
453       
454        appData.setLastFoundTasks(tasks);
455
456        Console.traceln(Level.FINE, "found " + appData.getLastFoundTasks().size() + " tasks " +
457                        "occurring " + appData.getLastFoundTasks().getOccurrenceCount() + " times");
458    }
459
460    /**
461     * @param parent
462     * @return
463     */
464    private void createNewTrie(RuleApplicationData appData) {
465        Console.traceln(Level.FINER, "training trie with a maximum sequence length of " +
466                        appData.getTrainedSequenceLength());
467
468        appData.getStopWatch().start("training trie");
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));
474   
475        appData.getLastTrie().trainSessions
476            (appData.getSessions(), appData.getTrainedSequenceLength());
477       
478        appData.getStopWatch().stop("training trie");
479    }
480
481    /**
482     * @param appData
483     */
484    private void replaceSequencesOccurringMostOften(RuleApplicationData appData) {
485        appData.detectedAndReplacedTasks(false);
486
487        if ((appData.getLastFoundTasks().size() > 0) &&
488            (appData.getLastFoundTasks().getOccurrenceCount() > 1))
489        {
490            Console.traceln(Level.FINER, "replacing tasks occurrences");
491
492            for (List<ITaskInstance> task : appData.getLastFoundTasks()) {
493                ISequence sequence = taskFactory.createNewSequence();
494               
495                Console.traceln(Level.FINEST, "replacing " + sequence.getId() + ": " + task);
496
497                List<ISequenceInstance> sequenceInstances =
498                    replaceTaskOccurrences(task, appData.getSessions(), sequence);
499               
500                harmonizeSequenceInstancesModel(sequence, sequenceInstances,task.size());
501                appData.detectedAndReplacedTasks
502                    (appData.detectedAndReplacedTasks() || (sequenceInstances.size() > 0));
503
504                if (sequenceInstances.size() < appData.getLastFoundTasks().getOccurrenceCount()) {
505                    Console.traceln(Level.FINE, sequence.getId() + ": replaced task only " +
506                                    sequenceInstances.size() + " times instead of expected " +
507                                    appData.getLastFoundTasks().getOccurrenceCount());
508                }
509            }
510        }
511       
512    }
513
514    /**
515     *
516     */
517    private void harmonizeSequenceInstancesModel(ISequence               sequence,
518                                                 List<ISequenceInstance> sequenceInstances,
519                                                 int                     sequenceLength)
520    {
521        TaskInstanceComparator comparator = preparationTaskHandlingStrategy.getTaskComparator();
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           
527            for (ISequenceInstance sequenceInstance : sequenceInstances) {
528                ITask candidate = sequenceInstance.get(subTaskIndex).getTask();
529               
530                boolean found = false;
531               
532                for (int i = 0; i < subTaskVariants.size(); i++) {
533                    if (comparator.areLexicallyEqual(subTaskVariants.get(i), candidate)) {
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               
563                for (ISequenceInstance instance : sequenceInstances) {
564                    ISelectionInstance selectionInstance =
565                        taskFactory.createNewTaskInstance(selection);
566                    taskBuilder.setChild(selectionInstance, instance.get(subTaskIndex));
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    /**
577     * @param tree
578     */
579    private List<ISequenceInstance> replaceTaskOccurrences(List<ITaskInstance> task,
580                                                           List<IUserSession>  sessions,
581                                                           ISequence           temporalTaskModel)
582    {
583        List<ISequenceInstance> sequenceInstances = new LinkedList<ISequenceInstance>();
584       
585        for (IUserSession session : sessions) {
586            int index = -1;
587               
588            do {
589                index = getSubListIndex(session, task, ++index);
590
591                if (index > -1) {
592                    sequenceInstances.add
593                        (RuleUtils.createNewSubSequenceInRange
594                             (session, index, index + task.size() - 1, temporalTaskModel,
595                              taskFactory, taskBuilder));
596                }
597            }
598            while (index > -1);
599        }
600       
601        return sequenceInstances;
602    }
603
604    /**
605     * @param trie
606     * @param object
607     * @return
608     */
609    private int getSubListIndex(ITaskInstanceList   list,
610                                List<ITaskInstance> subList,
611                                int                 startIndex)
612    {
613        boolean matchFound;
614        int result = -1;
615       
616        for (int i = startIndex; i <= list.size() - subList.size(); i++) {
617            matchFound = true;
618           
619            for (int j = 0; j < subList.size(); j++) {
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()) {
624                    matchFound = false;
625                    break;
626                }
627            }
628           
629            if (matchFound) {
630                result = i;
631                break;
632            }
633        }
634       
635        return result;
636    }
637
638    /**
639     * @param trie
640     * @param object
641     * @return
642     */
643    private int getSubListIndex(List<ITaskInstance> list,
644                                List<ITaskInstance> subList,
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++) {
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)) {
658                    matchFound = false;
659                    break;
660                }
661            }
662           
663            if (matchFound) {
664                result = i;
665                break;
666            }
667        }
668       
669        return result;
670    }
671   
672    /**
673     * @author Patrick Harms
674     */
675    private class MaxCountAndLongestTasksFinder implements TrieProcessor<ITaskInstance> {
676       
677        /**
678         *
679         */
680        private int currentCount;
681       
682        /**
683         *
684         */
685        private List<List<ITaskInstance>> foundTasks = new LinkedList<List<ITaskInstance>>();
686
687        /**
688         *
689         */
690        public MaxCountAndLongestTasksFinder() {
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
699        public TrieProcessor.Result process(List<ITaskInstance> foundTask, int count) {
700            if (foundTask.size() < 2) {
701                // ignore single tasks
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) {
711                // ignore this children of this task, as they may have only smaller counts than
712                // the already found tasks
713                return TrieProcessor.Result.SKIP_NODE;
714            }
715           
716            if (this.currentCount < count) {
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();
720                this.currentCount = count;
721            }
722           
723            if (this.currentCount == count) {
724                // the task is of interest. Sort it into the other found tasks so that
725                // the longest come first
726                boolean added = false;
727                for (int i = 0; i < foundTasks.size(); i++) {
728                    if (foundTasks.get(i).size() < foundTask.size()) {
729                        // defensive copy
730                        foundTasks.add(i, new LinkedList<ITaskInstance>(foundTask)); // defensive copy
731                        added = true;
732                        break;
733                    }
734                }
735               
736                if (!added) {
737                    foundTasks.add(new LinkedList<ITaskInstance>(foundTask)); // defensive copy
738                }
739            }
740           
741            return TrieProcessor.Result.CONTINUE;
742        }
743
744        /**
745         *  @return
746         */
747        public Tasks getFoundTasks() {
748            removePermutationsOfShorterTasks();
749            return new Tasks(currentCount, foundTasks);
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
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()) {
761                        // found a task that is a potential subtask. Check for this and remove the
762                        // subtask if needed
763                        List<ITaskInstance> longTask = foundTasks.get(i);
764                        List<ITaskInstance> shortTask = foundTasks.get(j);
765                       
766                        if (getSubListIndex(longTask, shortTask, 0) > -1) {
767                            foundTasks.remove(j);
768                        }
769                        else {
770                            j++;
771                        }
772                    }
773                    else {
774                        j++;
775                    }
776                }
777            }
778        }
779
780    }
781   
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   
832    /**
833     *
834     */
835    private static class RuleApplicationData {
836       
837        /**
838         *
839         */
840        private List<IUserSession> sessions;
841       
842        /**
843         *
844         */
845        private TaskInstanceTrie lastTrie;
846       
847        /**
848         * default and minimum trained sequence length is 3
849         */
850        private int trainedSequenceLength = 3;
851       
852        /**
853         *
854         */
855        private Tasks lastFoundTasks = new Tasks(Integer.MAX_VALUE, null);
856       
857        /**
858         *
859         */
860        private boolean detectedAndReplacedTasks;
861       
862        /**
863         *
864         */
865        private RuleApplicationResult result = new RuleApplicationResult();
866       
867        /**
868         *
869         */
870        private StopWatch stopWatch = new StopWatch();
871       
872        /**
873         *
874         */
875        private RuleApplicationData(List<IUserSession> sessions) {
876            this.sessions = sessions;
877        }
878
879        /**
880         * @return the tree
881         */
882        private List<IUserSession> getSessions() {
883            return sessions;
884        }
885
886        /**
887         * @param lastTrie the lastTrie to set
888         */
889        private void setLastTrie(TaskInstanceTrie lastTrie) {
890            this.lastTrie = lastTrie;
891        }
892
893        /**
894         * @return the lastTrie
895         */
896        private TaskInstanceTrie getLastTrie() {
897            return lastTrie;
898        }
899
900        /**
901         * @param trainedSequenceLength the trainedSequenceLength to set
902         */
903        private void setTrainedSequenceLength(int trainedSequenceLength) {
904            this.trainedSequenceLength = trainedSequenceLength;
905        }
906
907        /**
908         * @return the trainedSequenceLength
909         */
910        private int getTrainedSequenceLength() {
911            return trainedSequenceLength;
912        }
913
914        /**
915         * @param lastFoundSequences the lastFoundSequences to set
916         */
917        private void setLastFoundTasks(Tasks lastFoundSequences) {
918            this.lastFoundTasks = lastFoundSequences;
919        }
920
921        /**
922         * @return the lastFoundSequences
923         */
924        private Tasks getLastFoundTasks() {
925            return lastFoundTasks;
926        }
927
928        /**
929         *
930         */
931        private void detectedAndReplacedTasks(boolean detectedAndReplacedTasks) {
932            this.detectedAndReplacedTasks = detectedAndReplacedTasks;
933        }
934
935        /**
936         *
937         */
938        private boolean detectedAndReplacedTasks() {
939            return detectedAndReplacedTasks;
940        }
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
956    }
957   
958
959    /**
960     * @author Patrick Harms
961     */
962    private static class Tasks implements Iterable<List<ITaskInstance>> {
963       
964        /**
965         *
966         */
967        private int occurrenceCount;
968       
969        /**
970         *
971         */
972        private List<List<ITaskInstance>> sequences;
973
974        /**
975         * @param occurrenceCount
976         * @param sequences
977         */
978        private Tasks(int occurrenceCount, List<List<ITaskInstance>> sequences) {
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
1006        public Iterator<List<ITaskInstance>> iterator() {
1007            return this.sequences.iterator();
1008        }
1009
1010        /* (non-Javadoc)
1011         * @see java.lang.Object#toString()
1012         */
1013        @Override
1014        public String toString() {
1015            StringBuffer result = new StringBuffer();
1016            result.append(this.occurrenceCount);
1017            result.append(" occurrences:\n");
1018           
1019            for (List<ITaskInstance> task : sequences) {
1020                result.append(task);
1021                result.append("\n");
1022            }
1023           
1024            return result.toString();
1025        }
1026
1027    }
1028}
Note: See TracBrowser for help on using the repository browser.