source: branches/autoquest-core-tasktrees-alignment/src/main/java/de/ugoe/cs/autoquest/tasktrees/temporalrelation/SequenceForTaskDetectionRuleAlignment.java @ 1711

Last change on this file since 1711 was 1711, checked in by rkrimmel, 10 years ago

Removing useless code.

File size: 29.7 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.io.FileInputStream;
18import java.io.FileOutputStream;
19import java.io.IOException;
20import java.io.ObjectInputStream;
21import java.io.ObjectOutputStream;
22import java.io.Serializable;
23import java.util.ArrayList;
24import java.util.Collections;
25import java.util.Comparator;
26import java.util.HashMap;
27import java.util.HashSet;
28import java.util.Iterator;
29import java.util.LinkedList;
30import java.util.List;
31import java.util.Map;
32import java.util.Set;
33import java.util.logging.Level;
34
35import de.ugoe.cs.autoquest.CommandHelpers;
36import de.ugoe.cs.autoquest.tasktrees.alignment.algorithms.AlignmentAlgorithm;
37import de.ugoe.cs.autoquest.tasktrees.alignment.algorithms.AlignmentAlgorithmFactory;
38import de.ugoe.cs.autoquest.tasktrees.alignment.algorithms.Match;
39import de.ugoe.cs.autoquest.tasktrees.alignment.algorithms.MatchOccurence;
40import de.ugoe.cs.autoquest.tasktrees.alignment.algorithms.NumberSequence;
41import de.ugoe.cs.autoquest.tasktrees.alignment.matrix.ObjectDistanceSubstitionMatrix;
42import de.ugoe.cs.autoquest.tasktrees.taskequality.TaskEquality;
43import de.ugoe.cs.autoquest.tasktrees.treeifc.IIteration;
44import de.ugoe.cs.autoquest.tasktrees.treeifc.IIterationInstance;
45import de.ugoe.cs.autoquest.tasktrees.treeifc.IOptional;
46import de.ugoe.cs.autoquest.tasktrees.treeifc.ISelection;
47import de.ugoe.cs.autoquest.tasktrees.treeifc.ISelectionInstance;
48import de.ugoe.cs.autoquest.tasktrees.treeifc.ISequence;
49import de.ugoe.cs.autoquest.tasktrees.treeifc.ISequenceInstance;
50import de.ugoe.cs.autoquest.tasktrees.treeifc.ITask;
51import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskBuilder;
52import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskFactory;
53import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskInstance;
54import de.ugoe.cs.autoquest.tasktrees.treeifc.IUserSession;
55import de.ugoe.cs.autoquest.usageprofiles.SymbolMap;
56import de.ugoe.cs.util.StopWatch;
57import de.ugoe.cs.util.console.Console;
58import de.ugoe.cs.util.console.GlobalDataContainer;
59
60/**
61 * <p>
62 * This class implements the major rule for creating task trees based on a set
63 * of recorded user sessions. For this, it first harmonizes all tasks. This
64 * eases later comparison. Then it searches the sessions for iterations and
65 * replaces them accordingly. Then it searches for sub sequences being the
66 * longest and occurring most often. For each found sub sequence, it replaces
67 * the occurrences by creating appropriate {@link ISequence}s. Afterwards, again
68 * searches for iterations and then again for sub sequences until no more
69 * replacements are done.
70 * </p>
71 * <p>
72 *
73 *
74 * @author Patrick Harms
75 */
76public class SequenceForTaskDetectionRuleAlignment implements ISessionScopeRule {
77       
78       
79        public static int nThreads;
80        public static boolean harmonizeSequences;
81        public static boolean loadSubstutionMatrix;
82       
83
84        private int iteration = 0;
85        /**
86         * <p>
87         * the task factory to be used for creating substructures for the temporal
88         * relationships identified during rul application
89         * </p>
90         */
91        private ITaskFactory taskFactory;
92        /**
93         * <p>
94         * the task builder to be used for creating substructures for the temporal
95         * relationships identified during rule application
96         * </p>
97         */
98        private ITaskBuilder taskBuilder;
99
100        /**
101         * <p>
102         * the task handling strategy to be used for comparing tasks for
103         * preparation, i.e., before the tasks are harmonized
104         * </p>
105         */
106        private TaskHandlingStrategy preparationTaskHandlingStrategy;
107
108        /**
109         * <p>
110         * instantiates the rule and initializes it with a task equality to be
111         * considered when comparing tasks as well as a task factory and builder to
112         * be used for creating task structures.
113         * </p>
114         *
115         * @param minimalTaskEquality
116         *            the task equality to be considered when comparing tasks
117         * @param taskFactory
118         *            the task factory to be used for creating substructures
119         * @param taskBuilder
120         *            the task builder to be used for creating substructures
121         */
122
123        SequenceForTaskDetectionRuleAlignment(TaskEquality minimalTaskEquality,
124                        ITaskFactory taskFactory, ITaskBuilder taskBuilder) {
125                this.taskFactory = taskFactory;
126                this.taskBuilder = taskBuilder;
127
128                this.preparationTaskHandlingStrategy = new TaskHandlingStrategy(
129                                minimalTaskEquality);
130        }
131
132        /*
133         * (non-Javadoc)
134         *
135         * @see java.lang.Object#toString()
136         */
137        @Override
138        public String toString() {
139                return "SequenceForTaskDetectionRuleAlignment";
140        }
141
142        public void saveAppData(String name) {
143                String objectName = name;
144                String filename = name + ".dat";
145                Object dataObject = GlobalDataContainer.getInstance().getData(
146                                objectName);
147                if (dataObject == null) {
148                        CommandHelpers.objectNotFoundMessage(objectName);
149                }
150                FileOutputStream fos = null;
151                ObjectOutputStream out = null;
152                try {
153                        fos = new FileOutputStream(filename);
154                        out = new ObjectOutputStream(fos);
155                        out.writeObject(dataObject);
156                        out.close();
157                } catch (IOException ex) {
158                        Console.logException(ex);
159                }
160        }
161       
162        public RuleApplicationData loadAppData(String name) {
163                String objectName = name;
164                String filename = name + ".dat";
165       
166                Object data = null;
167                FileInputStream fis = null;
168                ObjectInputStream in = null;
169                try {
170                        fis = new FileInputStream(filename);
171                        in = new ObjectInputStream(fis);
172                        data = in.readObject();
173                        in.close();
174                } catch (IOException ex) {
175                        Console.logException(ex);
176                } catch (ClassNotFoundException ex) {
177                        Console.logException(ex);
178                }
179                if (GlobalDataContainer.getInstance().addData(objectName, data)) {
180                        CommandHelpers.dataOverwritten(objectName);
181                }
182                return (RuleApplicationData) GlobalDataContainer.getInstance().getData(name);
183        }
184       
185        /*
186         * (non-Javadoc)
187         *
188         * @see
189         * de.ugoe.cs.autoquest.tasktrees.temporalrelation.ISessionScopeRule#apply
190         * (java.util.List)
191         */
192        @Override
193        public RuleApplicationResult apply(List<IUserSession> sessions) {
194                RuleApplicationData appData = new RuleApplicationData(sessions);
195                if(SequenceForTaskDetectionRuleAlignment.harmonizeSequences) {
196                        //appData.getStopWatch().start("harmonization");
197                        harmonizeEventTaskInstancesModel(appData);
198                        //appData.getStopWatch().stop("harmonization");
199                        GlobalDataContainer.getInstance().addData("harmonized", appData);
200                        //Saving intermediate results to file
201                        Console.traceln(Level.INFO,"saving substitution matrix to file");
202                        saveAppData("harmonized");
203                }
204                else {
205                        Console.traceln(Level.INFO,"loading harmonized sessions from file");
206                        appData = loadAppData("harmonized");
207                }
208                System.out.println(SequenceForTaskDetectionRuleAlignment.loadSubstutionMatrix);
209                if(!SequenceForTaskDetectionRuleAlignment.loadSubstutionMatrix) {       
210                        Console.traceln(Level.INFO, "generating substitution matrix from " + appData.getUniqueTasks().size() + " unique tasks");
211                        appData.getStopWatch().start("substitution matrix");
212                        appData.getSubmat().generate(appData.getUniqueTasks());
213                        appData.getStopWatch().stop("substitution matrix");
214                        GlobalDataContainer.getInstance().addData("substitution", appData);
215                        saveAppData("substitution");
216                }
217                else {
218                        Console.traceln(Level.INFO,"loading substitution matrix from file");
219                        appData = loadAppData("substitution");
220                }
221               
222               
223                Console.traceln(Level.INFO, "Starting main loop");
224                do {
225                        Console.traceln(Level.INFO, "Iteration Number: " + iteration);
226                        iteration++;
227       
228                        appData.detectedAndReplacedTasks = false;
229                        appData.getStopWatch().start("whole loop");
230                        detectAndReplaceIterations(appData);
231                        appData.getStopWatch().start("task replacement");
232                        appData.updateSubstitutionMatrix();
233                        detectAndReplaceTasks(appData); //
234                        appData.getStopWatch().stop("task replacement");
235                        appData.getStopWatch().stop("whole loop");
236                        appData.getStopWatch().dumpStatistics(System.out);
237                        appData.getStopWatch().reset();
238
239                } while (appData.detectedAndReplacedTasks());
240
241                Console.println("created "
242                                + appData.getResult().getNewlyCreatedTasks().size()
243                                + " new tasks and "
244                                + appData.getResult().getNewlyCreatedTaskInstances().size()
245                                + " appropriate instances\n");
246
247                if ((appData.getResult().getNewlyCreatedTasks().size() > 0)
248                                || (appData.getResult().getNewlyCreatedTaskInstances().size() > 0)) {
249                        appData.getResult().setRuleApplicationStatus(
250                                        RuleApplicationStatus.FINISHED);
251                }
252
253                return appData.getResult();
254        }
255
256
257        private ArrayList<NumberSequence> createNumberSequences(
258                        RuleApplicationData appData) {
259                ArrayList<NumberSequence> result = new ArrayList<NumberSequence>();
260                for (int i = 0; i < appData.getSessions().size(); i++) {
261                        IUserSession session = appData.getSessions().get(i);
262                        NumberSequence templist = new NumberSequence(session.size());
263                        for (int j = 0; j < session.size(); j++) {
264                                ITaskInstance taskInstance = session.get(j);
265                                templist.getSequence()[j] = taskInstance.getTask().getId();
266                        }
267                        // Each NumberSequence is identified by its id, beginning to count
268                        // at zero
269                        templist.setId(i);
270                        result.add(templist);
271                }
272                return result;
273        }
274
275        /**
276         * <p>
277         * harmonizes the event task instances by unifying tasks. This is done, as
278         * initially the event tasks being equal with respect to the considered task
279         * equality are distinct objects. The comparison of these distinct objects
280         * is more time consuming than comparing the object references.
281         * </p>
282         *
283         * @param appData
284         *            the rule application data combining all data used for applying
285         *            this rule
286         * @return Returns the unique tasks symbol map
287         */
288        private void harmonizeEventTaskInstancesModel(RuleApplicationData appData) {
289                Console.traceln(Level.INFO,
290                                "harmonizing task model of event task instances");
291                appData.getStopWatch().start("harmonizing event tasks");
292                SymbolMap<ITaskInstance, ITask> uniqueTasks = preparationTaskHandlingStrategy
293                                .createSymbolMap();
294
295                TaskInstanceComparator comparator = preparationTaskHandlingStrategy
296                                .getTaskComparator();
297
298                int unifiedTasks = 0;
299                ITask task;
300                List<IUserSession> sessions = appData.getSessions();
301                for (int j = 0; j < sessions.size(); j++) {
302                        IUserSession session = sessions.get(j);
303
304                        for (int i = 0; i < session.size(); i++) {
305                                ITaskInstance taskInstance = session.get(i);
306                                task = uniqueTasks.getValue(taskInstance);
307
308                                if (task == null) {
309                                        uniqueTasks.addSymbol(taskInstance, taskInstance.getTask());
310                                        appData.getUniqueTasks().add(taskInstance.getTask());
311                                        appData.getNumber2Task().put(
312                                                        taskInstance.getTask().getId(),
313                                                        taskInstance.getTask());
314                                } else {
315                                        taskBuilder.setTask(taskInstance, task);
316                                        unifiedTasks++;
317                                }
318                        }
319                        comparator.clearBuffers();
320                }
321
322                appData.getStopWatch().stop("harmonizing event tasks");
323                Console.traceln(Level.INFO, "harmonized " + unifiedTasks
324                                + " task occurrences (still " + appData.getUniqueTasks().size()
325                                + " different tasks)");
326
327                appData.getStopWatch().dumpStatistics(System.out);
328                appData.getStopWatch().reset();
329        }
330
331        /**
332         * <p>
333         * searches for direct iterations of single tasks in all sequences and
334         * replaces them with {@link IIteration}s, respectively appropriate
335         * instances. Also all single occurrences of a task that is iterated
336         * somewhen are replaced with iterations to have again an efficient way for
337         * task comparisons.
338         * </p>
339         *
340         * @param appData
341         *            the rule application data combining all data used for applying
342         *            this rule
343         */
344        private void detectAndReplaceIterations(RuleApplicationData appData) {
345                Console.traceln(Level.FINE, "detecting iterations");
346                appData.getStopWatch().start("detecting iterations");
347
348                List<IUserSession> sessions = appData.getSessions();
349
350                Set<ITask> iteratedTasks = searchIteratedTasks(sessions);
351
352                if (iteratedTasks.size() > 0) {
353                        replaceIterationsOf(iteratedTasks, sessions, appData);
354                }
355
356                appData.getStopWatch().stop("detecting iterations");
357                Console.traceln(Level.INFO, "replaced " + iteratedTasks.size()
358                                + " iterated tasks");
359        }
360
361        /**
362         * <p>
363         * searches the provided sessions for task iterations. If a task is
364         * iterated, it is added to the returned set.
365         * </p>
366         *
367         * @param the
368         *            session to search for iterations in
369         *
370         * @return a set of tasks being iterated somewhere
371         */
372        private Set<ITask> searchIteratedTasks(List<IUserSession> sessions) {
373                Set<ITask> iteratedTasks = new HashSet<ITask>();
374                for (IUserSession session : sessions) {
375                        for (int i = 0; i < (session.size() - 1); i++) {
376                                // we prepared the task instances to refer to unique tasks, if
377                                // they are treated
378                                // as equal. Therefore, we just compare the identity of the
379                                // tasks of the task
380                                // instances
381                                if (session.get(i).getTask() == session.get(i + 1).getTask()) {
382                                        iteratedTasks.add(session.get(i).getTask());
383                                }
384                        }
385                }
386                return iteratedTasks;
387        }
388
389        /**
390         * <p>
391         * replaces all occurrences of all tasks provided in the set with iterations
392         * </p>
393         *
394         * @param iteratedTasks
395         *            the tasks to be replaced with iterations
396         * @param sessions
397         *            the sessions in which the tasks are to be replaced
398         * @param appData
399         *            the rule application data combining all data used for applying
400         *            this rule
401         */
402        private void replaceIterationsOf(Set<ITask> iteratedTasks,
403                        List<IUserSession> sessions, RuleApplicationData appData) {
404                Map<ITask, IIteration> iterations = new HashMap<ITask, IIteration>();
405                Map<IIteration, List<IIterationInstance>> iterationInstances = new HashMap<IIteration, List<IIterationInstance>>();
406
407                for (ITask iteratedTask : iteratedTasks) {
408
409                        IIteration iteration = taskFactory.createNewIteration();
410                        appData.newTaskCreated(iteration);
411                        iterations.put(iteratedTask, iteration);
412                        iterationInstances.put(iteration,
413                                        new LinkedList<IIterationInstance>());
414                }
415
416                IIterationInstance iterationInstance;
417
418                for (IUserSession session : sessions) {
419                        int index = 0;
420                        iterationInstance = null;
421
422                        while (index < session.size()) {
423                                // we prepared the task instances to refer to unique tasks, if
424                                // they are treated
425                                // as equal. Therefore, we just compare the identity of the
426                                // tasks of the task
427                                // instances
428                                ITask currentTask = session.get(index).getTask();
429                                IIteration iteration = iterations.get(currentTask);
430                                if (iteration != null) {
431                                        if ((iterationInstance == null)
432                                                        || (iterationInstance.getTask() != iteration)) {
433                                                iterationInstance = taskFactory
434                                                                .createNewTaskInstance(iteration);
435                                                iterationInstances.get(iteration)
436                                                                .add(iterationInstance);// TODO:: Don't create
437                                                                                                                // TaskInstances here,
438                                                                                                                // use a set of tasks
439                                                                                                                // instead
440                                                taskBuilder.addTaskInstance(session, index,
441                                                                iterationInstance);
442                                                index++;
443                                        }
444
445                                        taskBuilder.addChild(iterationInstance, session.get(index));
446                                        taskBuilder.removeTaskInstance(session, index);
447                                } else {
448                                        if (iterationInstance != null) {
449                                                iterationInstance = null;
450                                        }
451                                        index++;
452                                }
453                        }
454                }
455
456                for (Map.Entry<IIteration, List<IIterationInstance>> entry : iterationInstances
457                                .entrySet()) {
458                        harmonizeIterationInstancesModel(entry.getKey(), entry.getValue());
459                }
460        }
461
462        /**
463         * <p>
464         * TODO clarify why this is done
465         * </p>
466         */
467        private void harmonizeIterationInstancesModel(IIteration iteration,
468                        List<IIterationInstance> iterationInstances) {
469                List<ITask> iteratedTaskVariants = new LinkedList<ITask>();
470                TaskInstanceComparator comparator = preparationTaskHandlingStrategy
471                                .getTaskComparator();
472
473                // merge the lexically different variants of iterated task to a unique
474                // list
475                for (IIterationInstance iterationInstance : iterationInstances) {
476                        for (ITaskInstance executionVariant : iterationInstance) {
477                                ITask candidate = executionVariant.getTask();
478
479                                boolean found = false;
480                                for (ITask taskVariant : iteratedTaskVariants) {
481                                        if (comparator.areLexicallyEqual(taskVariant, candidate)) {
482                                                taskBuilder.setTask(executionVariant, taskVariant);
483                                                found = true;
484                                                break;
485                                        }
486                                }
487
488                                if (!found) {
489                                        iteratedTaskVariants.add(candidate);
490                                }
491                        }
492                }
493
494                // if there are more than one lexically different variant of iterated
495                // tasks, adapt the
496                // iteration model to be a selection of different variants. In this case
497                // also adapt
498                // the generated iteration instances to correctly contain selection
499                // instances. If there
500                // is only one variant of an iterated task, simply set this as the
501                // marked task of the
502                // iteration. In this case, the instances can be preserved as is
503                if (iteratedTaskVariants.size() > 1) {
504                        ISelection selection = taskFactory.createNewSelection();
505
506                        for (ITask variant : iteratedTaskVariants) {
507                                taskBuilder.addChild(selection, variant);
508                        }
509
510                        taskBuilder.setMarkedTask(iteration, selection);
511
512                        for (IIterationInstance instance : iterationInstances) {
513                                for (int i = 0; i < instance.size(); i++) {
514                                        ISelectionInstance selectionInstance = taskFactory
515                                                        .createNewTaskInstance(selection);
516                                        taskBuilder.setChild(selectionInstance, instance.get(i));
517                                        taskBuilder.setTaskInstance(instance, i, selectionInstance);
518                                }
519                        }
520                } else {
521                        taskBuilder.setMarkedTask(iteration, iteratedTaskVariants.get(0));
522                }
523        }
524
525        /**
526         * @param appData
527         * @param m
528         * @return
529         */
530        public ISequence matchAsSequence(RuleApplicationData appData, Match m) {       
531                ISequence sequence = taskFactory.createNewSequence();
532                appData.newTaskCreated(sequence);
533
534                int[] first = m.getFirstSequence().getSequence();
535                int[] second = m.getSecondSequence().getSequence();
536
537                // Both sequences of a match are equally long
538                for (int i = 0; i < m.getFirstSequence().size(); i++) {
539
540                        // Two gaps aligned to each other: Have not seen it happening so
541                        // far, just to handle it
542                        if (first[i] == -1 && second[i] == -1) {
543                                // Do nothing here.
544                        }
545                        // Both events are equal, we can simply add the task referring to
546                        // the number
547                        else if (first[i] == second[i]) {
548                                taskBuilder.addChild(sequence,
549                                                appData.getNumber2Task().get(first[i]));
550                        }
551                        // We have a gap in the first sequence, we need to add the task of
552                        // the second sequence as optional
553                        else if (first[i] == -1 && second[i] != -1) {
554                                IOptional optional = taskFactory.createNewOptional();
555                                appData.newTaskCreated(optional);
556                                taskBuilder.setMarkedTask(optional, appData.getNumber2Task()
557                                                .get(second[i]));
558                                taskBuilder.addChild(sequence, optional);
559                        }
560                        // We have a gap in the second sequence, we need to add the task of
561                        // the first sequence as optional
562                        else if (first[i] != -1 && second[i] == -1) {
563                                IOptional optional = taskFactory.createNewOptional();
564                                appData.newTaskCreated(optional);
565                                taskBuilder.setMarkedTask(optional, appData.getNumber2Task()
566                                                .get(first[i]));
567                                taskBuilder.addChild(sequence, optional);
568                        }
569                        // Both tasks are not equal, we need to insert a selection here.
570                        // Check if the next position is not a selection
571                        else if (i < first.length - 1) {
572
573                                if ((first[i] != second[i])
574                                                && ((first[i + 1] == second[i + 1]
575                                                                || first[i + 1] == -1 || second[i + 1] == -1))) {
576
577                                        ISelection selection = taskFactory.createNewSelection();
578                                        appData.newTaskCreated(selection);
579                                        taskBuilder.addChild(selection, appData.getNumber2Task()
580                                                        .get(first[i]));
581                                        taskBuilder.addChild(selection, appData.getNumber2Task()
582                                                        .get(second[i]));
583                                        taskBuilder.addChild(sequence, selection);
584                                } else {
585                                        boolean selectionfound = true;
586                                        ISelection selection = taskFactory.createNewSelection();
587                                        appData.newTaskCreated(selection);
588
589                                        ISequence subsequence1 = taskFactory.createNewSequence();
590                                        appData.newTaskCreated(subsequence1);
591
592                                        ISequence subsequence2 = taskFactory.createNewSequence();
593                                        appData.newTaskCreated(subsequence2);
594
595                                        taskBuilder.addChild(selection, subsequence1);
596                                        taskBuilder.addChild(selection, subsequence2);
597                                        taskBuilder.addChild(sequence,selection);
598                                        while (i < first.length - 1 && selectionfound) {
599                                                selectionfound = false;
600                                                taskBuilder.addChild(subsequence1, appData
601                                                                .getNumber2Task().get(first[i]));
602                                                taskBuilder.addChild(subsequence2, appData
603                                                                .getNumber2Task().get(second[i]));
604                                                if (first[i + 1] != second[i + 1] && first[i + 1] != -1
605                                                                && second[i + 1] != -1) {
606                                                        selectionfound = true;
607                                                }
608                                                else{
609                                                        continue;
610                                                }
611                                                i++;
612                                        }
613                                        if(i==first.length-1 && selectionfound) {
614                                                taskBuilder.addChild(subsequence1, appData
615                                                                .getNumber2Task().get(first[i]));
616                                                taskBuilder.addChild(subsequence2, appData
617                                                                .getNumber2Task().get(second[i]));
618                                        }
619                                }
620                        }
621                        else {
622                                if ((first[i] != second[i])) {
623
624                                        ISelection selection = taskFactory.createNewSelection();
625                                        appData.newTaskCreated(selection);
626                                        taskBuilder.addChild(selection, appData.getNumber2Task()
627                                                        .get(first[i]));
628                                        taskBuilder.addChild(selection, appData.getNumber2Task()
629                                                        .get(second[i]));
630                                        taskBuilder.addChild(sequence, selection);
631                                }
632                        }
633
634                }
635                return sequence;
636        }
637
638        /**
639         *
640         * @param appData
641         *            the rule application data combining all data used for applying
642         *            this rule
643         */
644        private void detectAndReplaceTasks(RuleApplicationData appData) {
645                Console.traceln(Level.FINE, "detecting and replacing tasks");
646                appData.getStopWatch().start("detecting tasks");
647
648                // Create NumberSequences
649                appData.setNumberSequences(this.createNumberSequences(appData));
650               
651                // Generate pairwise alignments
652                int size = appData.getNumberSequences().size();
653                Console.traceln(Level.INFO, "generating pairwise alignments");
654                LinkedList<Match> matchseqs = new LinkedList<Match>();
655                int count = 0;
656               
657                for (int i = 0; i < appData.getNumberSequences().size(); i++) {
658                        NumberSequence ns1 = appData.getNumberSequences().get(i);
659                        count++;
660                        if((count%(size/100)==0)) {
661                                Console.traceln(Level.INFO,(Math.round((float) count/size*100))+ "%");
662                        }
663                        for (int j = 0; j < appData.getNumberSequences().size(); j++) {
664                                NumberSequence ns2 = appData.getNumberSequences().get(j);
665                                if (i != j) {
666                                       
667                                        Console.traceln(Level.FINEST,"Aligning sequence " + i + " with sequence " + j);
668                                        AlignmentAlgorithm aa = AlignmentAlgorithmFactory.create();
669                                        aa.align(ns1, ns2, appData.getSubmat(),9);
670                                        matchseqs.addAll(aa.getMatches());
671                                }
672                        }
673                }
674
675
676                Console.traceln(Level.INFO, "searching for patterns occuring most");
677
678                // search each match in every other sequence
679                for (Iterator<Match> it = matchseqs.iterator(); it.hasNext();) {
680                        Match pattern = it.next();
681
682                        // Skip sequences with more 0 events (scrolls) than other events.
683                        // Both of the pattern sequences are equally long, so the zero
684                        // counts just need to be smaller than the length of one sequence
685                        if (pattern.getFirstSequence().eventCount(0)
686                                        + pattern.getSecondSequence().eventCount(0) + 1 > pattern
687                                        .getFirstSequence().size())
688                                continue;
689
690                        for (int j = 0; j < appData.getNumberSequences().size(); j++) {
691                                LinkedList<Integer> startpositions = appData
692                                                .getNumberSequences().get(j).containsPattern(pattern);
693                                if (startpositions.size() > 0) {
694                                        for (Iterator<Integer> jt = startpositions.iterator(); jt
695                                                        .hasNext();) {
696                                                int start = jt.next();
697                                                pattern.addOccurence(new MatchOccurence(start, start
698                                                                + pattern.size(), j));
699                                        }
700
701                                }
702                        }
703                }
704
705                Console.traceln(Level.INFO, "sorting results");
706                // Sort results to get the most occurring results
707                Comparator<Match> comparator = new Comparator<Match>() {
708                        public int compare(Match m1, Match m2) {
709                                return m2.occurenceCount() - m1.occurenceCount();
710
711                        }
712                };
713                Collections.sort(matchseqs, comparator);
714                appData.getStopWatch().stop("detecting tasks");
715
716                appData.getStopWatch().start("replacing tasks");
717                HashMap<Integer, List<MatchOccurence>> replacedOccurences = new HashMap<Integer, List<MatchOccurence>>();
718                // Replace matches in the sessions
719                for (int i = 0; i < matchseqs.size(); i++) {
720                        // Every pattern consists of 2 sequences, therefore the minimum
721                        // occurrences here is 2.
722                        // We just need the sequences also occurring in other sequences as
723                        // well
724                        if (matchseqs.get(i).occurenceCount() > 2) {
725
726                                appData.detectedAndReplacedTasks = true;
727                                ISequence task = matchAsSequence(appData, matchseqs.get(i));
728                                invalidOccurence: for (Iterator<MatchOccurence> it = matchseqs
729                                                .get(i).getOccurences().iterator(); it.hasNext();) {
730                                        MatchOccurence oc = it.next();
731                                       
732                                        /*
733                                        if (iteration > 1) {
734                                         
735                                        System.out.println("Trying to replace sequence: ");
736                                        matchseqs.get(i).getFirstSequence().printSequence();
737                                        matchseqs.get(i).getSecondSequence().printSequence();
738                                        System.out.println(" in session number: "
739                                                        + (oc.getSequenceId() + 1) + " at position "
740                                                        + (oc.getStartindex()) + "-" + oc.getEndindex());
741                                        System.out.println();
742
743                                        System.out.println("Printing session: ");
744                                        for (int j = 0; j < appData.getSessions()
745                                                        .get(oc.getSequenceId()).size(); j++) {
746                                                System.out.println(j
747                                                                + ": "
748                                                                + appData.getSessions().get(oc.getSequenceId())
749                                                                                .get(j));
750                                        }
751                                        }*/
752                                       
753                                        // Check if nothing has been replaced in the sequence we
754                                        // want to replace
755                                        if (replacedOccurences.get(oc.getSequenceId()) == null) {
756                                                replacedOccurences.put(oc.getSequenceId(),
757                                                                new LinkedList<MatchOccurence>());
758                                        } else {
759                                                // check if we have any replaced occurence with indexes
760                                                // smaller than ours. If so, we need to adjust our start
761                                                // and endpoints
762                                                // of the replacement.
763                                                // Also do a check if we have replaced this specific
764                                                // MatchOccurence in this sequence already. Jump to the
765                                                // next occurence if this is the case.
766                                                // This is no more neccessary once the matches are
767                                                // harmonized.
768                                                for (Iterator<MatchOccurence> jt = replacedOccurences
769                                                                .get(oc.getSequenceId()).iterator(); jt
770                                                                .hasNext();) {
771                                                        MatchOccurence tmpOC = jt.next();
772
773                                                        if (oc.getStartindex() >= tmpOC.getStartindex()
774                                                                        && oc.getStartindex() <= tmpOC
775                                                                                        .getEndindex()) {
776                                                                continue invalidOccurence;
777                                                        }
778                                                        if (oc.getEndindex() >= tmpOC.getStartindex()) {
779                                                                continue invalidOccurence;
780
781                                                        } else if (oc.getStartindex() > tmpOC.getEndindex()) {
782                                                                int diff = tmpOC.getEndindex()
783                                                                                - tmpOC.getStartindex();
784                                                                // Just to be sure.
785                                                                if (diff > 0) {
786                                                                        oc.setStartindex(oc.getStartindex() - diff
787                                                                                        + 1);
788                                                                        oc.setEndindex(oc.getEndindex() - diff + 1);
789                                                                } else {
790                                                                        Console.traceln(Level.WARNING,
791                                                                                        "End index of a Match before start. This should never happen");
792                                                                }
793                                                        }
794                                                }
795                                        }
796                                        ISequenceInstance sequenceInstances = RuleUtils
797                                                        .createNewSubSequenceInRange(appData.getSessions()
798                                                                        .get(oc.getSequenceId()), oc
799                                                                        .getStartindex(), oc.getEndindex(), task,
800                                                                        taskFactory, taskBuilder);
801                                        // Adjust the length of the match regarding to the length of
802                                        // instance. (OptionalInstances may be shorter)
803                                        oc.setEndindex(oc.getStartindex()
804                                                        + sequenceInstances.size()
805                                                        - RuleUtils.missedOptionals);
806                                        replacedOccurences.get(oc.getSequenceId()).add(oc);
807                                }
808                        }
809                }
810                matchseqs = null;
811                appData.getStopWatch().stop("replacing tasks");
812        }
813
814        /**
815     *
816     */
817        private static class RuleApplicationData implements Serializable {
818
819                /**
820                 *
821                 */
822                private static final long serialVersionUID = -7559657686755522960L;
823
824                private HashMap<Integer, ITask> number2task;
825
826                // TODO: We Actually just need number2task here, this structure can be removed in the future.
827                private HashSet<ITask> uniqueTasks;
828               
829                ObjectDistanceSubstitionMatrix submat;
830
831       
832                private ArrayList<NumberSequence> numberseqs;
833
834                private LinkedList<ITask> newTasks;
835               
836                /**
837         *
838         */
839                private List<IUserSession> sessions;
840
841                /**
842         *
843         */
844                private boolean detectedAndReplacedTasks;
845
846                /**
847         *
848         */
849                private RuleApplicationResult result;
850
851                /**
852         *
853         */
854                private StopWatch stopWatch;
855
856                /**
857         *
858         */
859                private RuleApplicationData(List<IUserSession> sessions) {
860                        this.sessions = sessions;
861                        numberseqs = new ArrayList<NumberSequence>();
862                        uniqueTasks = new HashSet<ITask>();
863                        number2task = new HashMap<Integer, ITask>();
864                        stopWatch = new StopWatch();
865                        result = new RuleApplicationResult();
866                        submat= new ObjectDistanceSubstitionMatrix(6,-3,false);
867                        newTasks = new LinkedList<ITask>();
868                }
869
870                private ObjectDistanceSubstitionMatrix getSubmat() {
871                        return submat;
872                }
873               
874                private void resetNewlyCreatedTasks() {
875                        uniqueTasks.addAll(newTasks);
876                        newTasks.clear();
877                }
878               
879                private void newTaskCreated(ITask task) {
880                        number2task.put(task.getId(), task);
881                        newTasks.add(task);
882                }
883
884                /**
885                 * @return the UserSessions as List.
886                 */
887                private List<IUserSession> getSessions() {
888                        return sessions;
889                }
890
891                private HashSet<ITask> getUniqueTasks() {
892                        return uniqueTasks;
893                }
894
895                private void setNumberSequences(ArrayList<NumberSequence> numberseqs) {
896                        this.numberseqs = numberseqs;
897                }
898
899                private ArrayList<NumberSequence> getNumberSequences() {
900                        return numberseqs;
901                }
902
903                private void updateSubstitutionMatrix() {
904                        submat.update(getNewTasks());
905                        resetNewlyCreatedTasks();
906                }
907
908               
909                /**
910         *
911         */
912                private boolean detectedAndReplacedTasks() {
913                        return detectedAndReplacedTasks;
914                }
915
916                /**
917                 * @return the result
918                 */
919                private RuleApplicationResult getResult() {
920                        return result;
921                }
922
923                public LinkedList<ITask> getNewTasks() {
924                        return newTasks;
925                }
926               
927                /**
928                 * @return the stopWatch
929                 */
930                private StopWatch getStopWatch() {
931                        return stopWatch;
932                }
933
934                private HashMap<Integer, ITask> getNumber2Task() {
935                        return number2task;
936                }
937
938        }
939
940}
Note: See TracBrowser for help on using the repository browser.