Index: trunk/autoquest-core-tasktrees/src/main/java/de/ugoe/cs/autoquest/tasktrees/temporalrelation/SequenceForTaskDetectionRule.java
===================================================================
--- trunk/autoquest-core-tasktrees/src/main/java/de/ugoe/cs/autoquest/tasktrees/temporalrelation/SequenceForTaskDetectionRule.java	(revision 1284)
+++ trunk/autoquest-core-tasktrees/src/main/java/de/ugoe/cs/autoquest/tasktrees/temporalrelation/SequenceForTaskDetectionRule.java	(revision 1285)
@@ -15,7 +15,12 @@
 package de.ugoe.cs.autoquest.tasktrees.temporalrelation;
 
+import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.logging.Level;
 
 import de.ugoe.cs.autoquest.tasktrees.taskequality.TaskEquality;
@@ -32,4 +37,5 @@
 import de.ugoe.cs.autoquest.usageprofiles.TrieProcessor;
 import de.ugoe.cs.util.StopWatch;
+import de.ugoe.cs.util.console.Console;
 
 /**
@@ -59,9 +65,17 @@
     /**
      * <p>
-     * the task comparator to be used for comparing tasks
+     * the task comparator to be used for comparing tasks for preparation
      * </p>
      */
-    private TaskComparator taskComparator;
-
+    private TaskHandlingStrategy preparationTaskHandlingStrategy;
+    
+    /**
+     * <p>
+     * the task comparator to be used for comparing tasks during iteration detection an trie
+     * generation
+     * </p>
+     */
+    private TaskHandlingStrategy identityTaskHandlingStrategy;;
+    
     /**
      * <p>
@@ -77,5 +91,6 @@
         this.taskBuilder = taskBuilder;
         
-        this.taskComparator = new TaskComparator(minimalTaskEquality);
+        this.preparationTaskHandlingStrategy = new TaskHandlingStrategy(minimalTaskEquality);
+        this.identityTaskHandlingStrategy = new TaskHandlingStrategy(TaskEquality.IDENTICAL);
     }
 
@@ -139,19 +154,21 @@
      */
     private void harmonizeEventTaskInstancesModel(RuleApplicationData appData) {
-        System.out.print("harmonizing task model of event task instances");
+        Console.traceln(Level.INFO, "harmonizing task model of event task instances");
         appData.getStopWatch().start("harmonizing event tasks");
-        
-        SymbolMap<ITaskInstance, ITask> unifiedTaskMap =
-            new SymbolMap<ITaskInstance, ITask>(taskComparator);
+
+        SymbolMap<ITaskInstance, ITask> uniqueTasks =
+            preparationTaskHandlingStrategy.createSymbolMap();
+        TaskComparator comparator = preparationTaskHandlingStrategy.getTaskComparator();
         
         int unifiedTasks = 0;
-        
+        ITask task;
         List<IUserSession> sessions = appData.getSessions();
         for (IUserSession session : sessions) {
+            Console.traceln(Level.FINE, "handling session " + session);
             for (ITaskInstance taskInstance : session) {
-                ITask task = unifiedTaskMap.getValue(taskInstance);
+                task = uniqueTasks.getValue(taskInstance);
                 
                 if (task == null) {
-                    unifiedTaskMap.addSymbol(taskInstance, taskInstance.getTask());
+                    uniqueTasks.addSymbol(taskInstance, taskInstance.getTask());
                 }
                 else {
@@ -160,12 +177,14 @@
                 }
             }
-        }
-        
+            
+            comparator.clearBuffers();
+        }
         
         appData.getStopWatch().stop("harmonizing event tasks");
-        System.out.println(" --> harmonized " + unifiedTasks + " task occurrences (still " +
-                           unifiedTaskMap.size() + " different tasks)");
-        
+        Console.traceln(Level.INFO, "harmonized " + unifiedTasks + " task occurrences (still " +
+                        uniqueTasks.size() + " different tasks)");
+
         appData.getStopWatch().dumpStatistics(System.out);
+        appData.getStopWatch().reset();
     }
 
@@ -174,24 +193,17 @@
      */
     private void detectAndReplaceIterations(RuleApplicationData appData) {
-        System.out.print("detecting iterations");
+        Console.traceln(Level.FINE, "detecting iterations");
         appData.getStopWatch().start("detecting iterations");
         
         List<IUserSession> sessions = appData.getSessions();
-        int iteratedTasks = 0;
-        
-        ITask iteratedTask = null;
-        
-        do {
-            iteratedTask = searchIteratedTask(sessions);
-            
-            if (iteratedTask != null) {
-                replaceIterationsOf(iteratedTask, sessions, appData);
-                iteratedTasks++;
-            }
-        }
-        while (iteratedTask != null);
+        
+        Set<ITask> iteratedTasks = searchIteratedTasks(sessions);
+        
+        if (iteratedTasks.size() > 0) {
+            replaceIterationsOf(iteratedTasks, sessions, appData);
+        }
         
         appData.getStopWatch().stop("detecting iterations");
-        System.out.println(" --> found " + iteratedTasks + " iterated tasks");
+        Console.traceln(Level.INFO, "replaced " + iteratedTasks.size() + " iterated tasks");
     }
 
@@ -199,14 +211,18 @@
      *
      */
-    private ITask searchIteratedTask(List<IUserSession> sessions) {
+    private Set<ITask> searchIteratedTasks(List<IUserSession> sessions) {
+        Set<ITask> iteratedTasks = new HashSet<ITask>();
         for (IUserSession session : sessions) {
             for (int i = 0; i < (session.size() - 1); i++) {
-                if (taskComparator.equals(session.get(i), session.get(i + 1))) {
-                    return session.get(i).getTask();
-                }
-            }
-        }
-        
-        return null;
+                // we prepared the task instances to refer to unique tasks, if they are treated
+                // as equal. Therefore, we just compare the identity of the tasks of the task
+                // instances
+                if (session.get(i).getTask() == session.get(i + 1).getTask()) {
+                    iteratedTasks.add(session.get(i).getTask());
+                }
+            }
+        }
+        
+        return iteratedTasks;
     }
 
@@ -214,71 +230,33 @@
      *
      */
-/*    private ITask searchIteratedTask(List<IUserSession> sessions) {
-        int minNoOfRepetitions = 2;
-        int minNoOfIterationOccurrences = 1;
-        
-        Map<ITask, Integer> iterationsCounter = new HashMap<ITask, Integer>();
-        
-        for (IUserSession session : sessions) {
-            for (int i = 0; i < (session.size() - minNoOfRepetitions + 1); i++) {
-                ITask task = session.get(i).getTask();
-
-                // check if the task is iterated
-                boolean isIterated = true;
-                for (int j = i + 1; j < i + minNoOfRepetitions; j++) {
-                    if (!taskComparator.equals(task, session.get(j).getTask())) {
-                        isIterated = false;
-                        break;
-                    }
-                }
-                
-                if (isIterated) {
-                    Integer currentCounter = null;
-                    
-                    for (Map.Entry<ITask, Integer> entry : iterationsCounter.entrySet()) {
-                        if (taskComparator.equals(task, entry.getKey())) {
-                            currentCounter = entry.getValue();
-                            break;
-                        }
-                    }
-                    
-                    if (currentCounter == null) {
-                        currentCounter = 1;
-                        iterationsCounter.put(task, currentCounter);
-                    }
-                    else {
-                        currentCounter++;
-                        iterationsCounter.put(task, currentCounter);
-                    }
-                    
-                    if (currentCounter >= minNoOfIterationOccurrences) {
-                        return task;
-                    }
-                }
-            }
-        }
-        
-        return null;
-    }*/
-
-    /**
-     *
-     */
-    private void replaceIterationsOf(ITask               iteratedTask,
+    private void replaceIterationsOf(Set<ITask>          iteratedTasks,
                                      List<IUserSession>  sessions,
                                      RuleApplicationData appData)
     {
-        IIteration iteration = taskFactory.createNewIteration();
+        Map<ITask, IIteration> iterations = new HashMap<ITask, IIteration>();
+        Map<IIteration, List<ITaskInstance>> iterationInstances =
+                new HashMap<IIteration, List<ITaskInstance>>();
+            
+        for (ITask iteratedTask : iteratedTasks) {
+            IIteration iteration = taskFactory.createNewIteration();
+            iterations.put(iteratedTask, iteration);
+            iterationInstances.put(iteration, new LinkedList<ITaskInstance>());
+        }
+        
         ITaskInstance iterationInstance = null;
-        
-        List<ITaskInstance> iterationInstances = new LinkedList<ITaskInstance>();
         
         for (IUserSession session : sessions) {
             int index = 0;
             while (index < session.size()) {
-                if (taskComparator.equals(iteratedTask, session.get(index).getTask())) {
-                    if (iterationInstance == null) {
+                // we prepared the task instances to refer to unique tasks, if they are treated
+                // as equal. Therefore, we just compare the identity of the tasks of the task
+                // instances
+                ITask currentTask = session.get(index).getTask();
+                IIteration iteration = iterations.get(currentTask);
+                if (iteration != null) {
+                    if ((iterationInstance == null) || (iterationInstance.getTask() != iteration))
+                    {
                         iterationInstance = taskFactory.createNewTaskInstance(iteration);
-                        iterationInstances.add(iterationInstance);
+                        iterationInstances.get(iteration).add(iterationInstance);
                         taskBuilder.addTaskInstance(session, index, iterationInstance);
                         index++;
@@ -297,5 +275,7 @@
         }
         
-        harmonizeIterationInstancesModel(iteration, iterationInstances);
+        for (Map.Entry<IIteration, List<ITaskInstance>> entry : iterationInstances.entrySet()) {
+            harmonizeIterationInstancesModel(entry.getKey(), entry.getValue());
+        }
     }
 
@@ -307,4 +287,5 @@
     {
         List<ITask> iteratedTaskVariants = new LinkedList<ITask>();
+        TaskComparator comparator = preparationTaskHandlingStrategy.getTaskComparator();
         
         // merge the lexically different variants of iterated task to a unique list 
@@ -315,5 +296,5 @@
                 boolean found = false;
                 for (ITask taskVariant : iteratedTaskVariants) {
-                    if (taskComparator.areLexicallyEqual(taskVariant, candidate)) {
+                    if (comparator.areLexicallyEqual(taskVariant, candidate)) {
                         taskBuilder.setTask(executionVariant, taskVariant);
                         found = true;
@@ -359,5 +340,5 @@
      */
     private void detectAndReplaceTasks(RuleApplicationData appData) {
-        System.out.println("detecting and replacing tasks");
+        Console.traceln(Level.FINE, "detecting and replacing tasks");
         appData.getStopWatch().start("detecting tasks");
         
@@ -370,5 +351,7 @@
         
         appData.getStopWatch().stop("replacing tasks");
-        System.out.println("detected and replaced " + appData.getLastFoundTasks().size() + " tasks");
+        Console.traceln(Level.INFO, "detected and replaced " + appData.getLastFoundTasks().size() +
+                        " tasks occuring " + appData.getLastFoundTasks().getOccurrenceCount() +
+                        "times");
     }
 
@@ -377,5 +360,5 @@
      */
     private void getSequencesOccuringMostOften(RuleApplicationData appData) {
-        System.out.println("determining most prominent tasks");
+        Console.traceln(Level.FINE, "determining most prominent tasks");
 
         Tasks tasks;
@@ -411,5 +394,5 @@
         
         appData.getStopWatch().start("testtrie");
-        Trie<ITaskInstance> trie = new Trie<ITaskInstance>(taskComparator);
+        Trie<ITaskInstance> trie = new Trie<ITaskInstance>(identityTaskComparator);
         
         for (IUserSession session : appData.getSessions()) {
@@ -433,5 +416,5 @@
                     tasksEqual = true;
                     for (int i = 0; i < task1.size(); i++) {
-                        if (!taskComparator.equals(task1.get(i).getTask(), task2.get(i).getTask()))
+                        if (!identityTaskComparator.equals(task1.get(i).getTask(), task2.get(i).getTask()))
                         {
                             tasksEqual = false;
@@ -458,5 +441,5 @@
             
             throw new IllegalArgumentException("both tries calculated different subsequences");
-        }*/
+        }
         
         /*TrieStatisticsDumper dumper = new TrieStatisticsDumper();
@@ -466,6 +449,6 @@
         appData.setLastFoundTasks(tasks);
 
-        System.out.println("found " + appData.getLastFoundTasks().size() + " tasks occurring " +
-                           appData.getLastFoundTasks().getOccurrenceCount() + " times");
+        Console.traceln(Level.FINE, "found " + appData.getLastFoundTasks().size() + " tasks " +
+        		"occurring " + appData.getLastFoundTasks().getOccurrenceCount() + " times");
     }
 
@@ -475,9 +458,13 @@
      */
     private void createNewTrie(RuleApplicationData appData) {
-        System.out.println("training trie with a maximum sequence length of " +
-                           appData.getTrainedSequenceLength());
+        Console.traceln(Level.FINER, "training trie with a maximum sequence length of " +
+                        appData.getTrainedSequenceLength());
 
         appData.getStopWatch().start("training trie");
-        appData.setLastTrie(new TaskInstanceTrie(taskComparator));
+        
+        // we prepared the task instances to refer to unique tasks, if they are treated
+        // as equal. Therefore, we just compare the identity of the tasks of the task
+        // instances
+        appData.setLastTrie(new TaskInstanceTrie(identityTaskHandlingStrategy));
     
         appData.getLastTrie().trainSessions
@@ -496,10 +483,10 @@
             (appData.getLastFoundTasks().getOccurrenceCount() > 1))
         {
-            System.out.println("replacing tasks occurrences");
+            Console.traceln(Level.FINER, "replacing tasks occurrences");
 
             for (List<ITaskInstance> task : appData.getLastFoundTasks()) {
                 ISequence sequence = taskFactory.createNewSequence();
                 
-                System.out.println("replacing " + sequence.getId() + ": " + task);
+                Console.traceln(Level.FINEST, "replacing " + sequence.getId() + ": " + task);
 
                 List<ITaskInstance> sequenceInstances =
@@ -507,10 +494,11 @@
                 
                 harmonizeSequenceInstancesModel(sequence, sequenceInstances,task.size());
-                appData.detectedAndReplacedTasks(sequenceInstances.size() > 0);
+                appData.detectedAndReplacedTasks
+                    (appData.detectedAndReplacedTasks() || (sequenceInstances.size() > 0));
 
                 if (sequenceInstances.size() < appData.getLastFoundTasks().getOccurrenceCount()) {
-                    System.out.println(sequence.getId() + ": replaced task only " +
-                                       sequenceInstances.size() + " times instead of expected " +
-                                       appData.getLastFoundTasks().getOccurrenceCount());
+                    Console.traceln(Level.FINE, sequence.getId() + ": replaced task only " +
+                                    sequenceInstances.size() + " times instead of expected " +
+                                    appData.getLastFoundTasks().getOccurrenceCount());
                 }
             }
@@ -526,4 +514,5 @@
                                                  int                 sequenceLength)
     {
+        TaskComparator comparator = preparationTaskHandlingStrategy.getTaskComparator();
         
         // ensure for each subtask that lexically different variants are preserved
@@ -537,5 +526,5 @@
                 
                 for (int i = 0; i < subTaskVariants.size(); i++) {
-                    if (taskComparator.areLexicallyEqual(subTaskVariants.get(i), candidate)) {
+                    if (comparator.areLexicallyEqual(subTaskVariants.get(i), candidate)) {
                         taskBuilder.setTask
                             (sequenceInstance.get(subTaskIndex), subTaskVariants.get(i));
@@ -624,5 +613,8 @@
             
             for (int j = 0; j < subList.size(); j++) {
-                if (!taskComparator.equals(list.get(i + j), subList.get(j))) {
+                // we prepared the task instances to refer to unique tasks, if they are treated
+                // as equal. Therefore, we just compare the identity of the tasks of the task
+                // instances
+                if (list.get(i + j).getTask() != subList.get(j).getTask()) {
                     matchFound = false;
                     break;
@@ -655,5 +647,8 @@
             
             for (int j = 0; j < subList.size(); j++) {
-                if (!taskComparator.equals(list.get(i + j), subList.get(j))) {
+                // we prepared the task instances to refer to unique tasks, if they are treated
+                // as equal. Therefore, we just compare the identity of the tasks of the task
+                // instances
+                if (list.get(i + j) != subList.get(j)) {
                     matchFound = false;
                     break;
Index: trunk/autoquest-core-tasktrees/src/main/java/de/ugoe/cs/autoquest/tasktrees/temporalrelation/TaskComparator.java
===================================================================
--- trunk/autoquest-core-tasktrees/src/main/java/de/ugoe/cs/autoquest/tasktrees/temporalrelation/TaskComparator.java	(revision 1284)
+++ trunk/autoquest-core-tasktrees/src/main/java/de/ugoe/cs/autoquest/tasktrees/temporalrelation/TaskComparator.java	(revision 1285)
@@ -19,11 +19,6 @@
 import java.util.HashMap;
 
-import de.ugoe.cs.autoquest.eventcore.IEventType;
 import de.ugoe.cs.autoquest.tasktrees.taskequality.TaskEquality;
 import de.ugoe.cs.autoquest.tasktrees.taskequality.TaskEqualityRuleManager;
-import de.ugoe.cs.autoquest.tasktrees.treeifc.IEventTask;
-import de.ugoe.cs.autoquest.tasktrees.treeifc.IIteration;
-import de.ugoe.cs.autoquest.tasktrees.treeifc.ISelection;
-import de.ugoe.cs.autoquest.tasktrees.treeifc.ISequence;
 import de.ugoe.cs.autoquest.tasktrees.treeifc.ITask;
 import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskInstance;
@@ -39,5 +34,5 @@
     
     /** */
-    private static final int MAX_BUFFER_SIZE = 10 * 1024 * 1024;
+    private static final int MAX_BUFFER_SIZE = 2 * 1024 * 1024;
 
     /** */
@@ -79,5 +74,5 @@
         
         if (task1 != task2) {
-            if ((task1 instanceof IEventTask) && (task2 instanceof IEventTask)) {
+            //if ((task1 instanceof IEventTask) && (task2 instanceof IEventTask)) {
                 long key = ((long) System.identityHashCode(task1)) << 32;
                 key += System.identityHashCode(task2);
@@ -92,8 +87,8 @@
                     }
                 }
-            }
+            /*}
             else {
                 result = false;
-            }
+            }*/
         }
         else {
@@ -118,5 +113,5 @@
             if (result == null) {
                 result = lexicalComparer.compare(task1, task2);
-                if (equalityBuffer.size() < 1024 * 1024 * 10) {
+                if (equalityBuffer.size() < MAX_BUFFER_SIZE) {
                     lexicalEqualityBuffer.put(key, result);
                 }
@@ -130,34 +125,15 @@
     }
     
-    /* (non-Javadoc)
-     * @see SymbolComparator#getBucketSearchOrder(Object)
-     */
-    @Override
-    public int[] getBucketSearchOrder(ITaskInstance taskInstance) {
-        // 0 = sequence; 1 = selection; 2 = iteration; 3 = optional; 4 = event task in general;
-        // other = hashCode of name of event type
-        
-        ITask task = taskInstance.getTask();
-        
-        if (task instanceof IEventTask) {
-            // event tasks are most likely equal to those of the event type with the same name,
-            // Afterwards, they may be equal to iterations, optionals, other event tasks,
-            // selections, and finally the rest.
-            IEventType eventType = ((IEventTask) task).getEventType();
-            return new int[] { eventType.getName().hashCode(), 2, 3, 4, 1 };                       
-        }
-        else if (task instanceof ISequence) {
-            return new int[] { 0, 2, 3, 1 };                       
-        }
-        else if (task instanceof ISelection) {
-            return new int[] { 1, 4, 2, 3 };                       
-        }
-        else if (task instanceof IIteration) {
-            return new int[] { 2, 1, 4 };                       
-        }
-        
-        return null;
-    }
-
+    /**
+     * <p>
+     * TODO: comment
+     * </p>
+     *
+     */
+    void clearBuffers() {
+        equalityBuffer.clear();
+        init();
+    }
+    
     /**
      * 
@@ -275,3 +251,4 @@
         }
     }
+
 }
Index: trunk/autoquest-core-tasktrees/src/main/java/de/ugoe/cs/autoquest/tasktrees/temporalrelation/TaskHandlingStrategy.java
===================================================================
--- trunk/autoquest-core-tasktrees/src/main/java/de/ugoe/cs/autoquest/tasktrees/temporalrelation/TaskHandlingStrategy.java	(revision 1285)
+++ trunk/autoquest-core-tasktrees/src/main/java/de/ugoe/cs/autoquest/tasktrees/temporalrelation/TaskHandlingStrategy.java	(revision 1285)
@@ -0,0 +1,109 @@
+//   Copyright 2012 Georg-August-Universität Göttingen, Germany
+//
+//   Licensed under the Apache License, Version 2.0 (the "License");
+//   you may not use this file except in compliance with the License.
+//   You may obtain a copy of the License at
+//
+//       http://www.apache.org/licenses/LICENSE-2.0
+//
+//   Unless required by applicable law or agreed to in writing, software
+//   distributed under the License is distributed on an "AS IS" BASIS,
+//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//   See the License for the specific language governing permissions and
+//   limitations under the License.
+
+package de.ugoe.cs.autoquest.tasktrees.temporalrelation;
+
+import de.ugoe.cs.autoquest.tasktrees.taskequality.TaskEquality;
+import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskInstance;
+import de.ugoe.cs.autoquest.usageprofiles.DefaultSymbolMap;
+import de.ugoe.cs.autoquest.usageprofiles.SymbolComparator;
+import de.ugoe.cs.autoquest.usageprofiles.SymbolMap;
+import de.ugoe.cs.autoquest.usageprofiles.SymbolStrategy;
+
+/**
+ * <p>
+ * TODO comment
+ * </p>
+ * 
+ * @author Patrick Harms
+ */
+class TaskHandlingStrategy implements SymbolStrategy<ITaskInstance> {
+    
+    /**  */
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 
+     */
+    private TaskEquality consideredEquality;
+
+    /**
+     * 
+     */
+    private TaskComparator comparator;
+
+    /**
+     * <p>
+     * TODO: comment
+     * </p>
+     *
+     * @param consideredEquality
+     */
+    TaskHandlingStrategy(TaskEquality consideredEquality) {
+        this.consideredEquality = consideredEquality;
+        
+        if (this.consideredEquality == TaskEquality.IDENTICAL) {
+            comparator = new TaskIdentityComparator();
+        }
+        else {
+            comparator = new TaskComparator(this.consideredEquality);
+        }
+    }
+
+    /* (non-Javadoc)
+     * @see de.ugoe.cs.autoquest.usageprofiles.SymbolStrategy#getSymbolComparator()
+     */
+    @Override
+    public SymbolComparator<ITaskInstance> getSymbolComparator() {
+        return comparator;
+    }
+
+    /**
+     * <p>
+     * TODO: comment
+     * </p>
+     *
+     * @return
+     */
+    public TaskComparator getTaskComparator() {
+        return comparator;
+    }
+
+    /* (non-Javadoc)
+     * @see de.ugoe.cs.autoquest.usageprofiles.SymbolStrategy#createSymbolMap()
+     */
+    @Override
+    public <V> SymbolMap<ITaskInstance, V> createSymbolMap() {
+        if (consideredEquality == TaskEquality.IDENTICAL) {
+            return new TaskSymbolIdentityMap<V>();
+        }
+        else {
+            return new TaskSymbolBucketedMap<V>(comparator);
+        }
+    }
+
+    /* (non-Javadoc)
+     * @see de.ugoe.cs.autoquest.usageprofiles.SymbolStrategy#copySymbolMap(de.ugoe.cs.autoquest.usageprofiles.SymbolMap)
+     */
+    @Override
+    public <V> SymbolMap<ITaskInstance, V> copySymbolMap(SymbolMap<ITaskInstance, V> other) {
+        if (consideredEquality == TaskEquality.IDENTICAL) {
+            return new DefaultSymbolMap<ITaskInstance, V>(other);
+        }
+        else {
+            return new TaskSymbolBucketedMap<V>(comparator);
+        }
+    }
+
+}
Index: trunk/autoquest-core-tasktrees/src/main/java/de/ugoe/cs/autoquest/tasktrees/temporalrelation/TaskIdentityComparator.java
===================================================================
--- trunk/autoquest-core-tasktrees/src/main/java/de/ugoe/cs/autoquest/tasktrees/temporalrelation/TaskIdentityComparator.java	(revision 1285)
+++ trunk/autoquest-core-tasktrees/src/main/java/de/ugoe/cs/autoquest/tasktrees/temporalrelation/TaskIdentityComparator.java	(revision 1285)
@@ -0,0 +1,47 @@
+//   Copyright 2012 Georg-August-Universität Göttingen, Germany
+//
+//   Licensed under the Apache License, Version 2.0 (the "License");
+//   you may not use this file except in compliance with the License.
+//   You may obtain a copy of the License at
+//
+//       http://www.apache.org/licenses/LICENSE-2.0
+//
+//   Unless required by applicable law or agreed to in writing, software
+//   distributed under the License is distributed on an "AS IS" BASIS,
+//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//   See the License for the specific language governing permissions and
+//   limitations under the License.
+
+package de.ugoe.cs.autoquest.tasktrees.temporalrelation;
+
+import de.ugoe.cs.autoquest.tasktrees.taskequality.TaskEquality;
+import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskInstance;
+
+/**
+ * TODO comment
+ */
+class TaskIdentityComparator extends TaskComparator {
+
+    /**  */
+    private static final long serialVersionUID = 1L;
+    
+    /**
+     * <p>
+     * TODO: comment
+     * </p>
+     *
+     * @param minimalNodeEquality
+     */
+    public TaskIdentityComparator() {
+        super(TaskEquality.IDENTICAL);
+    }
+    
+    /* (non-Javadoc)
+     * @see SymbolComparator#equals(Object, Object)
+     */
+    @Override
+    public boolean equals(ITaskInstance taskInstance1, ITaskInstance taskInstance2) {
+        return taskInstance1.getTask() == taskInstance2.getTask();
+    }        
+
+}
Index: trunk/autoquest-core-tasktrees/src/main/java/de/ugoe/cs/autoquest/tasktrees/temporalrelation/TaskInstanceTrie.java
===================================================================
--- trunk/autoquest-core-tasktrees/src/main/java/de/ugoe/cs/autoquest/tasktrees/temporalrelation/TaskInstanceTrie.java	(revision 1284)
+++ trunk/autoquest-core-tasktrees/src/main/java/de/ugoe/cs/autoquest/tasktrees/temporalrelation/TaskInstanceTrie.java	(revision 1285)
@@ -20,4 +20,5 @@
 import java.util.Map;
 
+import de.ugoe.cs.autoquest.tasktrees.treeifc.ITask;
 import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskInstance;
 import de.ugoe.cs.autoquest.tasktrees.treeifc.IUserSession;
@@ -33,5 +34,5 @@
  * @author Patrick Harms
  */
-public class TaskInstanceTrie extends Trie<ITaskInstance> {
+class TaskInstanceTrie extends Trie<ITaskInstance> {
 
     /**  */
@@ -43,6 +44,6 @@
      * </p>
      */
-    private TaskComparator comparator;
-
+    private TaskHandlingStrategy taskStrategy;
+    
     /**
      * <p>
@@ -52,7 +53,7 @@
      * @param taskComparator2
      */
-    public TaskInstanceTrie(TaskComparator taskComparator) {
-        super(taskComparator);
-        this.comparator = taskComparator;
+    public TaskInstanceTrie(TaskHandlingStrategy taskStrategy) {
+        super(taskStrategy);
+        this.taskStrategy = taskStrategy;
     }
 
@@ -65,29 +66,33 @@
         }
         
-        SymbolMap<ITaskInstance, List<ITaskInstance>> equalTaskInstancesMap =
-            new SymbolMap<ITaskInstance, List<ITaskInstance>>(comparator);
-        
-        Map<ITaskInstance, List<ITaskInstance>> taskInstancesMap =
-            new HashMap<ITaskInstance, List<ITaskInstance>>();
+        SymbolMap<ITaskInstance, Counter> equalTaskInstancesMap =
+            taskStrategy.createSymbolMap();
+        
+        Map<ITask, Counter> instanceCountMap = new HashMap<ITask, Counter>();
         
         System.out.println("preparing training");
+        int noOfTaskInstances = 0;
         for (IUserSession session : userSessions) {
             for (ITaskInstance taskInstance : session) {
-                List<ITaskInstance> equalTaskInstances =
-                    equalTaskInstancesMap.getValue(taskInstance);
-                
-                if (equalTaskInstances == null) {
-                    equalTaskInstances = new LinkedList<ITaskInstance>();
-                    equalTaskInstancesMap.addSymbol(taskInstance, equalTaskInstances);
+                Counter counter = equalTaskInstancesMap.getValue(taskInstance);
+                
+                if (counter == null) {
+                    counter = new Counter();
+                    equalTaskInstancesMap.addSymbol(taskInstance, counter);
                 }
                 
-                equalTaskInstances.add(taskInstance);
-                taskInstancesMap.put(taskInstance, equalTaskInstances);
-            }
-        }
-        
-        System.out.println("performing training");
+                counter.count++;
+                instanceCountMap.put(taskInstance.getTask(), counter);
+                
+                noOfTaskInstances++;
+            }
+        }
+        
+        System.out.println("performing training of " + noOfTaskInstances + " task instances");
+        Counter processedTaskInstances = new Counter();
+        int counterRecheckAt = noOfTaskInstances / 10; // recheck the maximum count after each
+                                                       // 10% of processed task instances
         for (IUserSession session : userSessions) {
-            train(session, maxOrder, taskInstancesMap);
+            train(session, maxOrder, instanceCountMap, processedTaskInstances, counterRecheckAt);
         }      
         
@@ -122,7 +127,9 @@
      * 
      */
-    private void train(IUserSession                            userSession,
-                       int                                     maxOrder,
-                       Map<ITaskInstance, List<ITaskInstance>> taskInstancesMap)
+    private void train(IUserSession        userSession,
+                       int                 maxOrder,
+                       Map<ITask, Counter> taskInstanceCountMap,
+                       Counter             processedTaskInstances,
+                       int                 counterRecheckAt)
     {
         List<ITaskInstance> executedTasks = userSession.getExecutedTasks();
@@ -130,12 +137,13 @@
         List<ITaskInstance> subsequence = new LinkedList<ITaskInstance>();
         
-        int numberOfTrainedSubsequences = 0;
         int sequenceMaxCount = 0;
         
         for (ITaskInstance currentTaskInstance : executedTasks) {
-            int occurrenceCount = taskInstancesMap.get(currentTaskInstance).size();
-            
-            if ((numberOfTrainedSubsequences % 10) == 0) {
+            
+            int occurrenceCount = taskInstanceCountMap.get(currentTaskInstance.getTask()).count;
+            
+            if (processedTaskInstances.count >= counterRecheckAt) {
                 sequenceMaxCount = getCurrentSequenceMaxCount();
+                processedTaskInstances.count = 0;
             }
             
@@ -158,8 +166,8 @@
                     add(subsequence);
                     subsequence.remove(0);
-
-                    numberOfTrainedSubsequences++;
                 }
             }
+            
+            processedTaskInstances.count++;
         }
         
@@ -219,3 +227,10 @@
     }
     
+    /**
+     * @author Patrick Harms
+     */
+    private static class Counter {
+        int count = 0;
+    }
+        
 }
Index: trunk/autoquest-core-tasktrees/src/main/java/de/ugoe/cs/autoquest/tasktrees/temporalrelation/TaskSymbolBucketedMap.java
===================================================================
--- trunk/autoquest-core-tasktrees/src/main/java/de/ugoe/cs/autoquest/tasktrees/temporalrelation/TaskSymbolBucketedMap.java	(revision 1285)
+++ trunk/autoquest-core-tasktrees/src/main/java/de/ugoe/cs/autoquest/tasktrees/temporalrelation/TaskSymbolBucketedMap.java	(revision 1285)
@@ -0,0 +1,915 @@
+//   Copyright 2012 Georg-August-Universität Göttingen, Germany
+//
+//   Licensed under the Apache License, Version 2.0 (the "License");
+//   you may not use this file except in compliance with the License.
+//   You may obtain a copy of the License at
+//
+//       http://www.apache.org/licenses/LICENSE-2.0
+//
+//   Unless required by applicable law or agreed to in writing, software
+//   distributed under the License is distributed on an "AS IS" BASIS,
+//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//   See the License for the specific language governing permissions and
+//   limitations under the License.
+
+package de.ugoe.cs.autoquest.tasktrees.temporalrelation;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import de.ugoe.cs.autoquest.eventcore.IEventType;
+import de.ugoe.cs.autoquest.tasktrees.treeifc.IEventTask;
+import de.ugoe.cs.autoquest.tasktrees.treeifc.IIteration;
+import de.ugoe.cs.autoquest.tasktrees.treeifc.ISelection;
+import de.ugoe.cs.autoquest.tasktrees.treeifc.ISequence;
+import de.ugoe.cs.autoquest.tasktrees.treeifc.ITask;
+import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskInstance;
+import de.ugoe.cs.autoquest.usageprofiles.SymbolMap;
+
+/**
+ * TODO correct comment
+ * <p>
+ * This class is a data structure for holding symbols which is more efficient than a simple list.
+ * This data structure can be used with a comparator to adapt the effective list behavior and to
+ * define the equals strategy for comparing objects. After a certain size ({@link #MAX_LIST_SIZE}),
+ * the symbol map creates a symbol index consisting of buckets. This allows searching for symbols
+ * in a more efficient order as the search can start in the most appropriate of the internal
+ * buckets.
+ * </p>
+ * <p>
+ * The class is called a map, although it is not. It may contain the same element as separate keys.
+ * This implementation is done for performance improvements. If it is required to really assure,
+ * that a key exists only once, then each call to the {@link #addSymbol(Object, Object)} method
+ * should be done only, if the {@link #containsSymbol(Object)} method for the same symbol returns
+ * false.
+ * </p>
+ * 
+ * @see SymbolComparator
+ * 
+ * @author Patrick Harms
+ * @param <V>
+ */
+class TaskSymbolBucketedMap<V> implements SymbolMap<ITaskInstance, V>, Serializable {
+
+    /**
+     * <p>
+     * default serial version UID
+     * </p>
+     */
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * <p>
+     * the maximum number of symbols in this map which is still only treated as list instead of
+     * using buckets.
+     * </p>
+     */
+    private static final int MAX_LIST_SIZE = 15;
+    
+    /**
+     * <p>
+     * Comparator to be used for comparing the symbols with each other and to determine a bucket
+     * search order
+     * </p>
+     */
+    private TaskComparator comparator;
+
+    /**
+     * <p>
+     * Internally maintained plain list of symbols and associated values
+     * </p>
+     */
+    private List<Map.Entry<ITaskInstance, V>> symbolList;
+
+    /**
+     * <p>
+     * If the size of the map exceeds {@link #MAX_LIST_SIZE}, this is the symbol index using buckets
+     * for optimizing the search order.
+     * </p>
+     */
+    private Map<Integer, List<Map.Entry<ITaskInstance, V>>> symbolBuckets;
+    
+    /**
+     * <p>
+     * When using buckets, not any symbol may be associated a correct bucket by the used
+     * comparator. Therefore, we set a default bucket for all such symbols. This may change
+     * if the comparator defines the same bucket for a specific symbol.
+     * </p>
+     */
+    private int defaultBucket = 0;
+    
+    /**
+     * <p>
+     * Instantiates a symbol map with a comparator
+     * </p>
+     *
+     * @param comparator the comparator to use for comparing symbols and for determining bucket
+     *                   search orders
+     * 
+     * @throws IllegalArgumentException if the provided comparator is null
+     */
+    public TaskSymbolBucketedMap(TaskComparator comparator) {
+        if (comparator == null) {
+            throw new IllegalArgumentException("comparator must not be null");
+        }
+        
+        this.comparator = comparator;
+        this.symbolList = new ArrayList<Map.Entry<ITaskInstance, V>>();
+    }
+
+    /**
+     * <p>
+     * Copy constructure
+     * </p>
+     * 
+     * @param otherMap the other map to be copied including its comparator
+     * 
+     * @throws IllegalArgumentException if the provided other map is null
+     */
+    public TaskSymbolBucketedMap(TaskSymbolBucketedMap<V> otherMap) {
+        if (otherMap == null) {
+            throw new IllegalArgumentException("otherMap must not be null");
+        }
+
+        this.comparator = otherMap.comparator;
+        this.symbolList = new ArrayList<Map.Entry<ITaskInstance, V>>(otherMap.symbolList);
+        
+        if (this.symbolList.size() > MAX_LIST_SIZE) {
+            createSymbolBuckets();
+        }
+    }
+
+    /**
+     * <p>
+     * Returns the size of the map, i.e. the number of symbol entries
+     * </p>
+     * 
+     * @return as described
+     */
+    public int size() {
+        return symbolList.size();
+    }
+
+    /**
+     * <p>
+     * Returns true if this map is empty, i.e. if {@link #size()} returns 0
+     * </p>
+     * 
+     * @return as described
+     */
+    public boolean isEmpty() {
+        return symbolList.isEmpty();
+    }
+
+    /**
+     * <p>
+     * Returns true if the provided symbol was stored in this map.
+     * </p>
+     * 
+     * @param symbol the symbol to check if it was stored in this map
+     * 
+     * @return as described
+     * 
+     * @throws IllegalArgumentException if the provided symbol is null
+     */
+    public boolean containsSymbol(ITaskInstance symbol) {
+        if (symbol == null) {
+            throw new IllegalArgumentException("symbol must not be null");
+        }
+        
+        return getEntry(symbol) != null;
+    }
+
+    /**
+     * <p>
+     * Returns the value associated to the provided symbol in this map. If there is no value
+     * associated to the given symbol or if the symbol is not stored in this map, the method
+     * returns null.
+     * </p>
+     * 
+     * @param symbol the symbol to return the value for
+     * 
+     * @return as described
+     * 
+     * @throws IllegalArgumentException if the provided symbol is null
+     */
+    public V getValue(ITaskInstance symbol) {
+        if (symbol == null) {
+            throw new IllegalArgumentException("symbol must not be null");
+        }
+        
+        Map.Entry<ITaskInstance, V> entry = getEntry(symbol);
+        
+        if (entry != null) {
+            return entry.getValue();
+        }
+        else {
+            return null;
+        }
+    }
+
+    /**
+     * <p>
+     * Adds a symbol and an associated value to the map. If the value is null, the symbol is added,
+     * anyway and {@link #containsSymbol(Object)} will return true for that symbol. Adding the
+     * same symbol twice will produce two entries. This is contradictory to typical map
+     * implementations. To prevent this, the {@link #containsSymbol(Object)} and
+     * {@link #removeSymbol(Object)} methods should be used to ensure map behavior.
+     * </p>
+     * 
+     * @param symbol the symbol to add to the map
+     * @param value  the value to associate to the symbol in this map
+     * 
+     * @return as described
+     * 
+     * @throws IllegalArgumentException if the provided symbol is null
+     */
+    public void addSymbol(ITaskInstance symbol, V value) {
+        if (symbol == null) {
+            throw new IllegalArgumentException("symbol must not be null");
+        }
+        
+        Map.Entry<ITaskInstance, V> entry = new SymbolMapEntry(symbol, value);
+        
+        symbolList.add(entry);
+            
+        if (symbolList.size() > MAX_LIST_SIZE) {
+            if (symbolBuckets == null) {
+                createSymbolBuckets();
+            }
+            else {
+                addToSymbolBucket(entry);
+            }
+        }
+    }
+
+    /**
+     * <p>
+     * Removes a symbol and its associated value from the map. If the symbol is stored several
+     * times, the first of its occurrences is removed. 
+     * </p>
+     * 
+     * @param symbol the symbol to be removed from the map
+     * 
+     * @return as described
+     * 
+     * @throws IllegalArgumentException if the provided symbol is null
+     */
+    public V removeSymbol(ITaskInstance symbol) {
+        if (symbol == null) {
+            throw new IllegalArgumentException("symbol must not be null");
+        }
+        
+        for (int i = 0; i < symbolList.size(); i++) {
+            if (comparator.equals(symbolList.get(i).getKey(), symbol)) {
+                // found the symbol. Remove it from the list, and if required, also from the map.
+                V value = symbolList.remove(i).getValue();
+                
+                if (symbolList.size() > MAX_LIST_SIZE) {
+                    removeFromSymbolBuckets(symbol);
+                }
+                
+                return value;
+            }
+        }
+        
+        return null;
+    }
+
+    /**
+     * <p>
+     * Returns a collection of all symbols in this map.
+     * </p>
+     *
+     * @return as described
+     */
+    public Collection<ITaskInstance> getSymbols() {
+        return new ReadOnlyCollectionFacade<ITaskInstance>(symbolList, new SymbolFacade());
+    }
+    
+    /**
+     * <p>
+     * Returns a collection of all values associated to symbols in this map. May contain null
+     * values, if some of the symbols are mapped to null. The length of the returned collection
+     * is in any case the same as the size of the map.
+     * </p>
+     *
+     * @return as described
+     */
+    public Collection<V> getValues() {
+        return new ReadOnlyCollectionFacade<V>(symbolList, new ValueFacade());
+    }
+    
+    /**
+     * <p>
+     * Removes all symbols and associated values from the map.
+     * </p>
+     */
+    public void clear() {
+        symbolList.clear();
+        symbolBuckets = null;
+    }
+
+    /* (non-Javadoc)
+     * @see java.lang.Object#hashCode()
+     */
+    @Override
+    public int hashCode() {
+        return symbolList.size();
+    }
+
+    /* (non-Javadoc)
+     * @see java.lang.Object#equals(java.lang.Object)
+     */
+    @SuppressWarnings("unchecked")
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        else if (this.getClass().isInstance(obj)) {
+            TaskSymbolBucketedMap<V> other = (TaskSymbolBucketedMap<V>) obj;
+            
+            return (symbolList.size() == other.symbolList.size()) &&
+                   (symbolList.containsAll(other.symbolList));
+        }
+        else {
+            return false;
+        }
+    }
+
+    /**
+     * <p>
+     * Internally used to create symbol buckets in case the number of stored symbols increased
+     * above {@link #MAX_LIST_SIZE}.
+     * </p>
+     */
+    private void createSymbolBuckets() {
+        //System.out.println("creating symbol buckets");
+        symbolBuckets = new HashMap<Integer, List<Map.Entry<ITaskInstance, V>>>();
+        
+        for (Map.Entry<ITaskInstance, V> symbol : symbolList) {
+            addToSymbolBucket(symbol);
+        }
+    }
+
+    /**
+     * <p>
+     * Adds a symbol and its value to its corresponding bucket. The corresponding bucket is
+     * retrieved from the symbol comparator. It is the first element of the search order returned
+     * by the symbol comparator. If the comparator does not define a search order for the symbol
+     * the entry is added to the default bucket. If the comparator defines a bucket id
+     * identical to the default bucket id, the default bucket id is shifted to another value.
+     * </p>
+     */
+    private void addToSymbolBucket(Map.Entry<ITaskInstance, V> symbolEntry) {
+        int bucketId = defaultBucket;
+        int[] bucketSearchOrder = getBucketSearchOrder(symbolEntry.getKey());
+        
+        if ((bucketSearchOrder != null) && (bucketSearchOrder.length > 0)) {
+            bucketId = bucketSearchOrder[0];
+            
+            if (bucketId == defaultBucket) {
+                setNewDefaultBucketId();
+            }
+        }
+        
+        List<Map.Entry<ITaskInstance, V>> list = symbolBuckets.get(bucketId);
+        
+        if (list == null) {
+            list = new LinkedList<Map.Entry<ITaskInstance, V>>();
+            symbolBuckets.put(bucketId, list);
+        }
+        
+        list.add(symbolEntry);
+    }
+    
+    /**
+     * 
+     */
+    public int[] getBucketSearchOrder(ITaskInstance taskInstance) {
+        // 0 = sequence; 1 = selection; 2 = iteration; 3 = optional; 4 = event task in general;
+        // other = hashCode of name of event type
+        
+        ITask task = taskInstance.getTask();
+        
+        if (task instanceof IEventTask) {
+            // event tasks are most likely equal to those of the event type with the same name,
+            // Afterwards, they may be equal to iterations, optionals, other event tasks,
+            // selections, and finally the rest.
+            IEventType eventType = ((IEventTask) task).getEventType();
+            return new int[] { eventType.getName().hashCode(), 2, 3, 4, 1 };                       
+        }
+        else if (task instanceof ISequence) {
+            return new int[] { 0, 2, 3, 1 };                       
+        }
+        else if (task instanceof ISelection) {
+            return new int[] { 1, 4, 2, 3 };                       
+        }
+        else if (task instanceof IIteration) {
+            return new int[] { 2, 1, 4 };                       
+        }
+        
+        return null;
+    }
+
+    /**
+     * <p>
+     * Removes the entry for a given symbol from the buckets. It uses the bucket search order
+     * defined by the symbol comparator to find the symbol as fast as possible.
+     * </p>
+     */
+    private Map.Entry<ITaskInstance, V> removeFromSymbolBuckets(ITaskInstance symbol) {
+        int bucketId = defaultBucket;
+        int[] bucketSearchOrder = getBucketSearchOrder(symbol);
+        
+        if ((bucketSearchOrder != null) && (bucketSearchOrder.length > 0)) {
+            bucketId = bucketSearchOrder[0];
+        }
+        
+        List<Map.Entry<ITaskInstance, V>> list = symbolBuckets.get(bucketId);
+        Map.Entry<ITaskInstance, V> result = null;
+        
+        if (list != null) {
+            for (int i = 0; i < list.size(); i++) {
+                if (comparator.equals(list.get(i).getKey(), symbol)) {
+                    result = list.remove(i);
+                    break;
+                }
+            }
+            
+            if (list.isEmpty()) {
+                symbolBuckets.remove(bucketId);
+            }
+        }
+        
+        return result;
+    }
+
+    /**
+     * <p>
+     * Updates the default bucket id to a new one
+     * </p>
+     */
+    private void setNewDefaultBucketId() {
+        int oldDefaultBucket = defaultBucket;
+        do {
+            defaultBucket += 1;
+        }
+        while (symbolBuckets.containsKey(defaultBucket));
+        
+        symbolBuckets.put(defaultBucket, symbolBuckets.get(oldDefaultBucket));
+    }
+
+    /**
+     * <p>
+     * searches for the entry belonging to the given symbol. The method either uses the list if
+     * buckets are not used yet, or it uses the buckets and searches them in the order defined
+     * by the comparator. If the symbol isn't found and the comparator does not refer all buckets,
+     * then also the other buckets are searched for the symbol.
+     * </p>
+     */
+    private Map.Entry<ITaskInstance, V> getEntry(ITaskInstance symbol) {
+        Map.Entry<ITaskInstance, V> entry = null;
+        if (symbolBuckets == null) {
+            entry = lookup(symbol, symbolList);
+        }
+        else {
+            int[] bucketSearchOrder = getBucketSearchOrder(symbol);
+            for (int bucketId : bucketSearchOrder) {
+                List<Map.Entry<ITaskInstance, V>> list = symbolBuckets.get(bucketId);
+                if (list != null) {
+                    entry = lookup(symbol, list);
+                    if (entry != null) {
+                        break;
+                    }
+                }
+            }
+            
+            // try to search the other buckets
+            if (entry == null) {
+                Arrays.sort(bucketSearchOrder);
+                for (Map.Entry<Integer, List<Map.Entry<ITaskInstance, V>>> bucket : symbolBuckets.entrySet()) {
+                    if (Arrays.binarySearch(bucketSearchOrder, bucket.getKey()) < 0) {
+                        List<Map.Entry<ITaskInstance, V>> list = bucket.getValue();
+                        if (list != null) {
+                            entry = lookup(symbol, list);
+                            if (entry != null) {
+                                break;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        
+        return entry;
+    }
+
+    /**
+     * <p>
+     * Convenience method to look up a symbol in a list of entries using the comparator.
+     * </p>
+     */
+    private Map.Entry<ITaskInstance, V> lookup(ITaskInstance symbol, List<Map.Entry<ITaskInstance, V>> list) {
+        for (Map.Entry<ITaskInstance, V> candidate : list) {
+            if (comparator.equals(candidate.getKey(), symbol)) {
+                return candidate;
+            }
+        }
+        
+        return null;
+    }
+
+    /**
+     * <p>
+     * Internally used data structure for storing symbol value pairs
+     * </p>
+     * 
+     * @author Patrick Harms
+     */
+    private class SymbolMapEntry implements Map.Entry<ITaskInstance, V> {
+        
+        /**
+         * the symbol to map to a value
+         */
+        private ITaskInstance symbol;
+        
+        /**
+         * the value associated with the symbol
+         */
+        private V value;
+
+        /**
+         * <p>
+         * Simple constructor for initializing the entry with a symbol and its associated value.
+         * </p>
+         */
+        private SymbolMapEntry(ITaskInstance symbol, V value) {
+            super();
+            this.symbol = symbol;
+            this.value = value;
+        }
+
+        /* (non-Javadoc)
+         * @see java.util.Map.Entry#getKey()
+         */
+        @Override
+        public ITaskInstance getKey() {
+            return symbol;
+        }
+
+        /* (non-Javadoc)
+         * @see java.util.Map.Entry#getValue()
+         */
+        @Override
+        public V getValue() {
+            return value;
+        }
+
+        /* (non-Javadoc)
+         * @see java.util.Map.Entry#setValue(java.lang.Object)
+         */
+        @Override
+        public V setValue(V value) {
+            V oldValue = this.value;
+            this.value = value;
+            return oldValue;
+        }
+
+        /* (non-Javadoc)
+         * @see java.lang.Object#hashCode()
+         */
+        @Override
+        public int hashCode() {
+            return symbol.hashCode();
+        }
+
+        /* (non-Javadoc)
+         * @see java.lang.Object#equals(java.lang.Object)
+         */
+        @SuppressWarnings("unchecked")
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            else if (this.getClass().isInstance(obj)) {
+                SymbolMapEntry other = (SymbolMapEntry) obj;
+                return (symbol.equals(other.symbol) &&
+                        (value == null ? other.value == null : value.equals(other.value)));
+            }
+            else {
+                return false;
+            }
+        }
+
+        /* (non-Javadoc)
+         * @see java.lang.Object#toString()
+         */
+        @Override
+        public String toString() {
+            return symbol + "=" + value;
+        }
+
+    }
+
+    /**
+     * <p>
+     * Used to create an efficient facade for accessing the internal list of entries either only
+     * for the symbols or only for the values. It is a default implementation of the collection
+     * interface. The entry facade provided to the constructor decides, if either the list
+     * accesses only the symbols or only the values. 
+     * </p>
+     * 
+     * @author Patrick Harms
+     */
+    private class ReadOnlyCollectionFacade<TYPE> implements Collection<TYPE> {
+        
+        /**
+         * the list facaded by this facade
+         */
+        private List<Map.Entry<ITaskInstance, V>> list;
+        
+        /**
+         * the facade to be used for the entries
+         */
+        private EntryFacade<TYPE> entryFacade;
+        
+        /**
+         * <p>
+         * Initializes the facade with the facaded list and the facade to be used for the entries
+         * </p>
+         */
+        private ReadOnlyCollectionFacade(List<Map.Entry<ITaskInstance, V>> list, EntryFacade<TYPE> entryFacade)
+        {
+            this.list = list;
+            this.entryFacade = entryFacade;
+        }
+
+        /* (non-Javadoc)
+         * @see java.util.Collection#size()
+         */
+        @Override
+        public int size() {
+            return list.size();
+        }
+
+        /* (non-Javadoc)
+         * @see java.util.Collection#isEmpty()
+         */
+        @Override
+        public boolean isEmpty() {
+            return list.isEmpty();
+        }
+
+        /* (non-Javadoc)
+         * @see java.util.Collection#contains(java.lang.Object)
+         */
+        @Override
+        public boolean contains(Object o) {
+            if (o == null) {
+                for (Map.Entry<ITaskInstance, V> entry : list) {
+                    if (entryFacade.getFacadedElement(entry) == null) {
+                        return true;
+                    }
+                }
+            }
+            else {
+                for (Map.Entry<ITaskInstance, V> entry : list) {
+                    if (o.equals(entryFacade.getFacadedElement(entry))) {
+                        return true;
+                    }
+                }
+            }
+            
+            return false;
+        }
+
+        /* (non-Javadoc)
+         * @see java.util.Collection#toArray()
+         */
+        @Override
+        public Object[] toArray() {
+            Object[] result = new Object[list.size()];
+            
+            for (int i = 0; i < list.size(); i++) {
+                result[i] = entryFacade.getFacadedElement(list.get(i));
+            }
+            
+            return result;
+        }
+
+        /* (non-Javadoc)
+         * @see java.util.Collection#toArray(T[])
+         */
+        @SuppressWarnings("unchecked")
+        @Override
+        public <T> T[] toArray(T[] a) {
+            T[] result = a;
+            
+            for (int i = 0; i < list.size(); i++) {
+                result[i] = (T) entryFacade.getFacadedElement(list.get(i));
+            }
+            
+            return result;
+        }
+
+        /* (non-Javadoc)
+         * @see java.util.Collection#add(java.lang.Object)
+         */
+        @Override
+        public boolean add(TYPE e) {
+            throw new UnsupportedOperationException("this collection is read only");
+        }
+
+        /* (non-Javadoc)
+         * @see java.util.Collection#remove(java.lang.Object)
+         */
+        @Override
+        public boolean remove(Object o) {
+            throw new UnsupportedOperationException("this collection is read only");
+        }
+
+        /* (non-Javadoc)
+         * @see java.util.Collection#containsAll(java.util.Collection)
+         */
+        @Override
+        public boolean containsAll(Collection<?> c) {
+            for (Object candidate : c) {
+                if (!contains(candidate)) {
+                    return false;
+                }
+            }
+            
+            return true;
+        }
+
+        /* (non-Javadoc)
+         * @see java.util.Collection#addAll(java.util.Collection)
+         */
+        @Override
+        public boolean addAll(Collection<? extends TYPE> c) {
+            throw new UnsupportedOperationException("this collection is read only");
+        }
+
+        /* (non-Javadoc)
+         * @see java.util.Collection#removeAll(java.util.Collection)
+         */
+        @Override
+        public boolean removeAll(Collection<?> c) {
+            throw new UnsupportedOperationException("this collection is read only");
+        }
+
+        /* (non-Javadoc)
+         * @see java.util.Collection#retainAll(java.util.Collection)
+         */
+        @Override
+        public boolean retainAll(Collection<?> c) {
+            throw new UnsupportedOperationException("this collection is read only");
+        }
+
+        /* (non-Javadoc)
+         * @see java.util.Collection#clear()
+         */
+        @Override
+        public void clear() {
+            throw new UnsupportedOperationException("this collection is read only");
+        }
+
+        /* (non-Javadoc)
+         * @see java.util.Collection#iterator()
+         */
+        @Override
+        public Iterator<TYPE> iterator() {
+            return new ReadOnlyCollectionIteratorFacade<TYPE>(list.iterator(), entryFacade);
+        }
+        
+    }
+
+    /**
+     * <p>
+     * Implementation of an iterator to facade an iterator on the internal list of symbol entries.
+     * </p>
+     * 
+     * @author Patrick Harms
+     */
+    private class ReadOnlyCollectionIteratorFacade<TYPE> implements Iterator<TYPE> {
+        
+        /**
+         * the facaded iterator
+         */
+        private Iterator<Map.Entry<ITaskInstance, V>> iterator;
+        
+        /**
+         * the facade for the entries provided by the facaded iterator
+         */
+        private EntryFacade<TYPE> entryFacade;
+        
+        /**
+         * <p>
+         * initialized this facade with the facaded iterator and the entry facade to be used for
+         * the entries.
+         * </p>
+         */
+        private ReadOnlyCollectionIteratorFacade(Iterator<Map.Entry<ITaskInstance, V>> iterator,
+                                                 EntryFacade<TYPE>         entryFacade)
+        {
+            this.iterator = iterator;
+            this.entryFacade = entryFacade;
+        }
+
+        /* (non-Javadoc)
+         * @see java.util.Iterator#hasNext()
+         */
+        @Override
+        public boolean hasNext() {
+            return iterator.hasNext();
+        }
+
+        /* (non-Javadoc)
+         * @see java.util.Iterator#next()
+         */
+        @Override
+        public TYPE next() {
+            return entryFacade.getFacadedElement(iterator.next());
+        }
+
+        /* (non-Javadoc)
+         * @see java.util.Iterator#remove()
+         */
+        @Override
+        public void remove() {
+            throw new UnsupportedOperationException("this iterator is read only");
+        }
+        
+    }
+        
+    /**
+     * <p>
+     * Used to facade symbol entries and to return only this part of an entry, that is relevant.
+     * </p>
+     * 
+     * @author Patrick Harms
+     */
+    private abstract class EntryFacade<T> {
+        
+        /**
+         * <p>
+         * Returns only the part of an entry that is relevant or required.
+         * </p>
+         *
+         * @param entry of which the part shall be returned
+         * 
+         * @return the part of the entry to be returned
+         */
+        protected abstract T getFacadedElement(Entry<ITaskInstance, V> entry);
+        
+    }
+    
+    /**
+     * <p>
+     * Implementation of the entry facade returning the entries key, i.e. the symbol.
+     * </p>
+     * 
+     * @author Patrick Harms
+     */
+    private class SymbolFacade extends EntryFacade<ITaskInstance> {
+
+        /* (non-Javadoc)
+         * @see ReadOnlyCollectionIteratorFacade#getFacadedElement(Entry)
+         */
+        @Override
+        protected ITaskInstance getFacadedElement(Entry<ITaskInstance, V> entry) {
+            return entry.getKey();
+        }
+    }
+    
+    /**
+     * <p>
+     * Implementation of the entry facade returning the entries value, i.e. the value associated to
+     * the symbol.
+     * </p>
+     * 
+     * @author Patrick Harms
+     */
+    private class ValueFacade extends EntryFacade<V> {
+
+        /* (non-Javadoc)
+         * @see ReadOnlyCollectionIteratorFacade#getFacadedElement(Entry)
+         */
+        @Override
+        protected V getFacadedElement(Entry<ITaskInstance, V> entry) {
+            return entry.getValue();
+        }
+    }
+
+}
Index: trunk/autoquest-core-tasktrees/src/main/java/de/ugoe/cs/autoquest/tasktrees/temporalrelation/TaskSymbolIdentityMap.java
===================================================================
--- trunk/autoquest-core-tasktrees/src/main/java/de/ugoe/cs/autoquest/tasktrees/temporalrelation/TaskSymbolIdentityMap.java	(revision 1285)
+++ trunk/autoquest-core-tasktrees/src/main/java/de/ugoe/cs/autoquest/tasktrees/temporalrelation/TaskSymbolIdentityMap.java	(revision 1285)
@@ -0,0 +1,195 @@
+//   Copyright 2012 Georg-August-Universität Göttingen, Germany
+//
+//   Licensed under the Apache License, Version 2.0 (the "License");
+//   you may not use this file except in compliance with the License.
+//   You may obtain a copy of the License at
+//
+//       http://www.apache.org/licenses/LICENSE-2.0
+//
+//   Unless required by applicable law or agreed to in writing, software
+//   distributed under the License is distributed on an "AS IS" BASIS,
+//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//   See the License for the specific language governing permissions and
+//   limitations under the License.
+
+package de.ugoe.cs.autoquest.tasktrees.temporalrelation;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+import de.ugoe.cs.autoquest.tasktrees.treeifc.ITask;
+import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskInstance;
+import de.ugoe.cs.autoquest.usageprofiles.SymbolMap;
+
+/**
+ * <p>
+ * TODO comment
+ * </p>
+ * 
+ * @author Patrick Harms
+ */
+public class TaskSymbolIdentityMap<V> implements SymbolMap<ITaskInstance, V> {
+
+    /**  */
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 
+     */
+    private Map<ITask, V> delegate;
+
+    /**
+     * 
+     */
+    private Map<ITask, ITaskInstance> symbols;
+
+    /**
+     * <p>
+     * TODO: comment
+     * </p>
+     *
+     * @param other
+     */
+    public TaskSymbolIdentityMap() {
+        delegate = new HashMap<ITask, V>();
+        symbols = new HashMap<ITask, ITaskInstance>();
+    }
+
+    /**
+     * <p>
+     * TODO: comment
+     * </p>
+     *
+     * @param other
+     */
+    public TaskSymbolIdentityMap(SymbolMap<ITaskInstance, V> other) {
+        if (other == null) {
+            throw new IllegalArgumentException("other map must not be null");
+        }
+        
+        delegate = new HashMap<ITask, V>();
+        symbols = new HashMap<ITask, ITaskInstance>();
+        
+        for (ITaskInstance symbol : other.getSymbols()) {
+            delegate.put(symbol.getTask(), other.getValue(symbol));
+            symbols.put(symbol.getTask(), symbol);
+        }
+    }
+
+    /* (non-Javadoc)
+     * @see de.ugoe.cs.autoquest.usageprofiles.SymbolMap#size()
+     */
+    @Override
+    public int size() {
+        return delegate.size();
+    }
+
+    /* (non-Javadoc)
+     * @see de.ugoe.cs.autoquest.usageprofiles.SymbolMap#isEmpty()
+     */
+    @Override
+    public boolean isEmpty() {
+        return delegate.isEmpty();
+    }
+
+    /* (non-Javadoc)
+     * @see de.ugoe.cs.autoquest.usageprofiles.SymbolMap#containsSymbol(java.lang.Object)
+     */
+    @Override
+    public boolean containsSymbol(ITaskInstance symbol) {
+        if (symbol == null) {
+            throw new IllegalArgumentException("symbol must not be null");
+        }
+        
+        return delegate.containsKey(symbol.getTask());
+    }
+
+    /* (non-Javadoc)
+     * @see de.ugoe.cs.autoquest.usageprofiles.SymbolMap#getValue(java.lang.Object)
+     */
+    @Override
+    public V getValue(ITaskInstance symbol) {
+        if (symbol == null) {
+            throw new IllegalArgumentException("symbol must not be null");
+        }
+        
+        return delegate.get(symbol.getTask());
+    }
+
+    /* (non-Javadoc)
+     * @see de.ugoe.cs.autoquest.usageprofiles.SymbolMap#addSymbol(java.lang.Object, java.lang.Object)
+     */
+    @Override
+    public void addSymbol(ITaskInstance symbol, V value) {
+        if (symbol == null) {
+            throw new IllegalArgumentException("symbol must not be null");
+        }
+        
+        delegate.put(symbol.getTask(), value);
+        symbols.put(symbol.getTask(), symbol);
+    }
+
+    /* (non-Javadoc)
+     * @see de.ugoe.cs.autoquest.usageprofiles.SymbolMap#removeSymbol(java.lang.Object)
+     */
+    @Override
+    public V removeSymbol(ITaskInstance symbol) {
+        if (symbol == null) {
+            throw new IllegalArgumentException("symbol must not be null");
+        }
+        
+        symbols.remove(symbol.getTask());
+        return delegate.remove(symbol.getTask());
+    }
+
+    /* (non-Javadoc)
+     * @see de.ugoe.cs.autoquest.usageprofiles.SymbolMap#getSymbols()
+     */
+    @Override
+    public Collection<ITaskInstance> getSymbols() {
+        return symbols.values();
+    }
+
+    /* (non-Javadoc)
+     * @see de.ugoe.cs.autoquest.usageprofiles.SymbolMap#getValues()
+     */
+    @Override
+    public Collection<V> getValues() {
+        return delegate.values();
+    }
+
+    /* (non-Javadoc)
+     * @see de.ugoe.cs.autoquest.usageprofiles.SymbolMap#clear()
+     */
+    @Override
+    public void clear() {
+        delegate.clear();
+    }
+
+    /* (non-Javadoc)
+     * @see java.lang.Object#hashCode()
+     */
+    @Override
+    public int hashCode() {
+        return delegate.hashCode();
+    }
+        
+    /* (non-Javadoc)
+     * @see java.lang.Object#equals(java.lang.Object)
+     */
+    @SuppressWarnings("unchecked")
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        else if (this.getClass().isInstance(obj)) {
+            return delegate.equals(((TaskSymbolIdentityMap<V>) obj).delegate);
+        }
+        else {
+            return false;
+        }
+    }
+
+}
