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

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