Index: /trunk/quest-core-events/.classpath
===================================================================
--- /trunk/quest-core-events/.classpath	(revision 479)
+++ /trunk/quest-core-events/.classpath	(revision 480)
@@ -1,26 +1,27 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <classpath>
-	<classpathentry kind="src" path="src"/>
-	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
+	<classpathentry kind="src" output="target/classes" path="src/main/java">
+		<attributes>
+			<attribute name="optional" value="true"/>
+			<attribute name="maven.pomderived" value="true"/>
+		</attributes>
+	</classpathentry>
 	<classpathentry combineaccessrules="false" kind="src" path="/java-utils"/>
-	<classpathentry kind="lib" path="/Build/lib/collections-generic-4.01.jar"/>
-	<classpathentry kind="lib" path="/Build/lib/colt-1.2.0.jar"/>
-	<classpathentry kind="lib" path="/Build/lib/commons-codec-1.5.jar"/>
-	<classpathentry kind="lib" path="/Build/lib/concurrent-1.3.4.jar"/>
-	<classpathentry kind="lib" path="/Build/lib/j3d-core-1.3.1.jar"/>
-	<classpathentry kind="lib" path="/Build/lib/Jama-1.0.2.jar"/>
-	<classpathentry kind="lib" path="/Build/lib/jung-3d-2.0.1.jar"/>
-	<classpathentry kind="lib" path="/Build/lib/jung-3d-demos-2.0.1.jar"/>
-	<classpathentry kind="lib" path="/Build/lib/jung-algorithms-2.0.1.jar"/>
-	<classpathentry kind="lib" path="/Build/lib/jung-api-2.0.1.jar"/>
-	<classpathentry kind="lib" path="/Build/lib/jung-graph-impl-2.0.1.jar"/>
-	<classpathentry kind="lib" path="/Build/lib/jung-io-2.0.1.jar"/>
-	<classpathentry kind="lib" path="/Build/lib/jung-jai-2.0.1.jar"/>
-	<classpathentry kind="lib" path="/Build/lib/jung-jai-samples-2.0.1.jar"/>
-	<classpathentry kind="lib" path="/Build/lib/jung-samples-2.0.1.jar"/>
-	<classpathentry kind="lib" path="/Build/lib/jung-visualization-2.0.1.jar"/>
-	<classpathentry kind="lib" path="/Build/lib/stax-api-1.0.1.jar"/>
-	<classpathentry kind="lib" path="/Build/lib/vecmath-1.3.1.jar"/>
-	<classpathentry kind="lib" path="/Build/lib/wstx-asl-3.2.6.jar"/>
-	<classpathentry kind="output" path="bin"/>
+	<classpathentry kind="src" output="target/test-classes" path="src/test/java">
+		<attributes>
+			<attribute name="optional" value="true"/>
+			<attribute name="maven.pomderived" value="true"/>
+		</attributes>
+	</classpathentry>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6">
+		<attributes>
+			<attribute name="maven.pomderived" value="true"/>
+		</attributes>
+	</classpathentry>
+	<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
+		<attributes>
+			<attribute name="maven.pomderived" value="true"/>
+		</attributes>
+	</classpathentry>
+	<classpathentry kind="output" path="target/classes"/>
 </classpath>
Index: /trunk/quest-core-events/.project
===================================================================
--- /trunk/quest-core-events/.project	(revision 479)
+++ /trunk/quest-core-events/.project	(revision 480)
@@ -13,6 +13,12 @@
 			</arguments>
 		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.m2e.core.maven2Builder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
 	</buildSpec>
 	<natures>
+		<nature>org.eclipse.m2e.core.maven2Nature</nature>
 		<nature>org.eclipse.jdt.core.javanature</nature>
 	</natures>
Index: /trunk/quest-core-events/.settings/org.eclipse.jdt.core.prefs
===================================================================
--- /trunk/quest-core-events/.settings/org.eclipse.jdt.core.prefs	(revision 479)
+++ /trunk/quest-core-events/.settings/org.eclipse.jdt.core.prefs	(revision 480)
@@ -1,3 +1,2 @@
-#Wed Jan 26 14:52:29 CET 2011
 eclipse.preferences.version=1
 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
@@ -10,3 +9,4 @@
 org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
 org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
 org.eclipse.jdt.core.compiler.source=1.6
Index: /trunk/quest-core-events/.settings/org.eclipse.m2e.core.prefs
===================================================================
--- /trunk/quest-core-events/.settings/org.eclipse.m2e.core.prefs	(revision 480)
+++ /trunk/quest-core-events/.settings/org.eclipse.m2e.core.prefs	(revision 480)
@@ -0,0 +1,4 @@
+activeProfiles=
+eclipse.preferences.version=1
+resolveWorkspaceProjects=true
+version=1
Index: /trunk/quest-core-events/pom.xml
===================================================================
--- /trunk/quest-core-events/pom.xml	(revision 480)
+++ /trunk/quest-core-events/pom.xml	(revision 480)
@@ -0,0 +1,46 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+	<modelVersion>4.0.0</modelVersion>
+	<groupId>de.ugoe.cs.quest</groupId>
+	<artifactId>quest-core-events</artifactId>
+	<version>0.0.1-SNAPSHOT</version>
+	<name>quest-core-events</name>
+	<scm>
+		<url>https://quest.informatik.uni-goettingen.de/svn/quest/trunk/quest-core-events</url>
+	</scm>
+	<repositories>
+		<repository>
+			<id>mbari</id>
+			<url>http://mbari-maven-repository.googlecode.com/svn/repository</url>
+		</repository>
+	</repositories>
+	<dependencies>
+		<dependency>
+			<groupId>net.sf.jung</groupId>
+			<artifactId>jung-visualization</artifactId>
+			<version>2.0.1</version>
+		</dependency>
+		<dependency>
+			<groupId>net.sf.jung</groupId>
+			<artifactId>jung-graph-impl</artifactId>
+			<version>2.0.1</version>
+		</dependency>
+		<dependency>
+			<groupId>jama</groupId>
+			<artifactId>jama</artifactId>
+			<version>1.0.2</version>
+		</dependency>
+	</dependencies>
+	<build>
+		<plugins>
+			<plugin>
+				<artifactId>maven-compiler-plugin</artifactId>
+				<version>2.3.2</version>
+				<configuration>
+					<source>1.6</source>
+					<target>1.6</target>
+				</configuration>
+			</plugin>
+		</plugins>
+	</build>
+</project>
Index: /trunk/quest-core-events/src/main/java/de/ugoe/cs/quest/IReplayDecorator.java
===================================================================
--- /trunk/quest-core-events/src/main/java/de/ugoe/cs/quest/IReplayDecorator.java	(revision 480)
+++ /trunk/quest-core-events/src/main/java/de/ugoe/cs/quest/IReplayDecorator.java	(revision 480)
@@ -0,0 +1,55 @@
+package de.ugoe.cs.quest;
+
+import java.io.Serializable;
+
+/**
+ * <p>
+ * This interface defines the structure of decorators used when writing replay
+ * files.
+ * </p>
+ * 
+ * @author Steffen Herbold
+ * @version 1.0
+ */
+public interface IReplayDecorator extends Serializable {
+
+	/**
+	 * <p>
+	 * Header of the file. Called at the beginning of the writing.
+	 * </p>
+	 * 
+	 * @return file header
+	 */
+	String getHeader();
+
+	/**
+	 * <p>
+	 * Footer of the file. Called at the end of the writing.
+	 * </p>
+	 * 
+	 * @return file footer
+	 */
+	String getFooter();
+
+	/**
+	 * <p>
+	 * Session Header. Called before each session.
+	 * </p>
+	 * 
+	 * @param sessionId
+	 *            id of the session
+	 * @return session header
+	 */
+	String getSessionHeader(int sessionId);
+
+	/**
+	 * <p>
+	 * Session Footer. Called after each session.
+	 * </p>
+	 * 
+	 * @param sessionId
+	 *            id of the session
+	 * @return session footer
+	 */
+	String getSessionFooter(int sessionId);
+}
Index: /trunk/quest-core-events/src/main/java/de/ugoe/cs/quest/SequenceInstanceOf.java
===================================================================
--- /trunk/quest-core-events/src/main/java/de/ugoe/cs/quest/SequenceInstanceOf.java	(revision 480)
+++ /trunk/quest-core-events/src/main/java/de/ugoe/cs/quest/SequenceInstanceOf.java	(revision 480)
@@ -0,0 +1,79 @@
+package de.ugoe.cs.quest;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.NoSuchElementException;
+
+import de.ugoe.cs.quest.eventcore.Event;
+
+/**
+ * <p>
+ * Helper class that can be used to determine if an object is a sequence or a
+ * collection of sequences. {@code instanceof} does not work, because of
+ * the type erasure of generics.
+ * </p>
+ * 
+ * @author Steffen Herbold
+ * @version 1.0
+ */
+public class SequenceInstanceOf {
+	
+	/**
+	 * <p>
+	 * Private constructor to prevent initializing of the class.
+	 * </p>
+	 */
+	private SequenceInstanceOf() {
+		
+	}
+
+	/**
+	 * <p>
+	 * Checks if an object is of type {@link Collection}&lt;{@link List}&lt;
+	 * {@link Event}&lt;?&gt;&gt;&gt;.
+	 * </p>
+	 * 
+	 * @param obj
+	 *            object that is checked
+	 * @return true, if the obj is of type {@link Collection}&lt;{@link List}
+	 *         &lt; {@link Event}&lt;?&gt;&gt;&gt;; false otherwise
+	 */
+	public static boolean isCollectionOfSequences(Object obj) {
+		try {
+			if (obj instanceof Collection<?>) {
+				Object listObj = ((Collection<?>) obj).iterator().next();
+				if (listObj instanceof List<?>) {
+					if (((List<?>) listObj).iterator().next() instanceof Event<?>) {
+						return true;
+					}
+				}
+			}
+		} catch (NoSuchElementException e) {
+		}
+		return false;
+	}
+
+	/**
+	 * <p>
+	 * Checks if an object is of type {@link List}&lt;{@link Event}
+	 * &lt;?&gt;&gt;.
+	 * </p>
+	 * 
+	 * @param obj
+	 *            object that is checked
+	 * @return true, if obj is of type {@link List}&lt;{@link Event}
+	 *         &lt;?&gt;&gt;; false otherwise
+	 */
+	public static boolean isEventSequence(Object obj) {
+		try {
+			if (obj instanceof List<?>) {
+				if (((List<?>) obj).iterator().next() instanceof Event<?>) {
+					return true;
+				}
+			}
+		} catch (NoSuchElementException e) {
+		}
+		return false;
+	}
+
+}
Index: /trunk/quest-core-events/src/main/java/de/ugoe/cs/quest/assertions/AssertEvent.java
===================================================================
--- /trunk/quest-core-events/src/main/java/de/ugoe/cs/quest/assertions/AssertEvent.java	(revision 480)
+++ /trunk/quest-core-events/src/main/java/de/ugoe/cs/quest/assertions/AssertEvent.java	(revision 480)
@@ -0,0 +1,41 @@
+package de.ugoe.cs.quest.assertions;
+
+import de.ugoe.cs.quest.eventcore.Event;
+import de.ugoe.cs.quest.eventcore.IReplayable;
+import de.ugoe.cs.quest.eventcore.ReplayableEvent;
+
+/**
+ * <p>
+ * Subclass of {@link ReplayableEvent} for assertions
+ * </p>
+ * 
+ * @author Jeffrey Hall
+ * @version 1.0
+ * 
+ * @param <T>
+ *            Allows only types that extend {@link IReplayable} and is used to
+ *            define the type of the assertion.
+ * 
+ */
+public class AssertEvent<T extends IReplayable> extends ReplayableEvent<T> {
+
+	/**
+	 * <p>
+	 * Id for object serialization.
+	 * </p>
+	 */
+	private static final long serialVersionUID = 1L;
+
+	/**
+	 * <p>
+	 * Constructor. Creates a new event with the given type.
+	 * <p>
+	 * 
+	 * @param type
+	 *            type of the event
+	 * @see Event#Event(String)
+	 */
+	public AssertEvent(String type) {
+		super(type);
+	}
+}
Index: /trunk/quest-core-events/src/main/java/de/ugoe/cs/quest/assertions/FileEqualsReplay.java
===================================================================
--- /trunk/quest-core-events/src/main/java/de/ugoe/cs/quest/assertions/FileEqualsReplay.java	(revision 480)
+++ /trunk/quest-core-events/src/main/java/de/ugoe/cs/quest/assertions/FileEqualsReplay.java	(revision 480)
@@ -0,0 +1,91 @@
+package de.ugoe.cs.quest.assertions;
+
+import java.security.InvalidParameterException;
+
+import de.ugoe.cs.quest.eventcore.IReplayable;
+import de.ugoe.cs.util.StringTools;
+
+/**
+ * <p>
+ * This class defines the replay for file equals assertions.
+ * </p>
+ * 
+ * @author Jeffrey Hall, Steffen Herbold
+ * @version 2.0
+ */
+public class FileEqualsReplay implements IReplayable {
+
+	/**
+	 * <p>
+	 * The file that should be equal to expectedFile.
+	 * </p>
+	 */
+	protected final String actualFile;
+
+	/**
+	 * <p>
+	 * The file that is used as the reference.
+	 * </p>
+	 */
+	protected final String expectedFile;
+
+	/**
+	 * <p>
+	 * Id for object serialization.
+	 * </p>
+	 */
+	private static final long serialVersionUID = 1L;
+
+	/**
+	 * <p>
+	 * Constructor. Creates a new FileEqualsReplay.
+	 * </p>
+	 * 
+	 * @param expectedFile
+	 *            name and path of the expected file
+	 * @param actualFile
+	 *            name and path of the actual file
+	 * @throws InvalidParameterException
+	 *             thrown if expectedFile or actualFile are null
+	 */
+	public FileEqualsReplay(String expectedFile, String actualFile) {
+		if (expectedFile == null) {
+			throw new InvalidParameterException(
+					"expected file must not be null");
+		}
+		if (actualFile == null) {
+			throw new InvalidParameterException("actual file must not be null");
+		}
+		this.expectedFile = expectedFile;
+		this.actualFile = actualFile;
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see de.ugoe.cs.quest.eventcore.IReplayable#getReplay()
+	 */
+	public String getReplay() {
+
+		String actualFileTmp = StringTools.xmlEntityReplacement(actualFile);
+		String expectedFileTmp = StringTools.xmlEntityReplacement(expectedFile);
+
+		StringBuilder currentMsgStr = new StringBuilder(800);
+		currentMsgStr.append("  <fileEquals ");
+		currentMsgStr.append("actualFile=\"" + actualFileTmp + "\" ");
+		currentMsgStr.append("expectedFile=\"" + expectedFileTmp + "\"/>");
+		currentMsgStr.append(StringTools.ENDLINE);
+		return currentMsgStr.toString();
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see de.ugoe.cs.quest.eventcore.IReplayable#getTarget()
+	 */
+	@Override
+	public String getTarget() {
+		return "targetNotUsed";
+	}
+
+}
Index: /trunk/quest-core-events/src/main/java/de/ugoe/cs/quest/assertions/TextEqualsReplay.java
===================================================================
--- /trunk/quest-core-events/src/main/java/de/ugoe/cs/quest/assertions/TextEqualsReplay.java	(revision 480)
+++ /trunk/quest-core-events/src/main/java/de/ugoe/cs/quest/assertions/TextEqualsReplay.java	(revision 480)
@@ -0,0 +1,94 @@
+package de.ugoe.cs.quest.assertions;
+
+import java.security.InvalidParameterException;
+
+import de.ugoe.cs.quest.eventcore.IReplayable;
+import de.ugoe.cs.util.StringTools;
+
+/**
+ * <p>
+ * This class defines the replay for a textEquals assertion.
+ * </p>
+ * 
+ * @author Jeffrey Hall, Steffen Herbold
+ * @version 2.0
+ */
+public class TextEqualsReplay implements IReplayable {
+
+	/**
+	 * <p>
+	 * Reference value which is compared to the targets text.
+	 * </p>
+	 */
+	protected final String expectedValue;
+
+	/**
+	 * <p>
+	 * Target to which the text is compared.
+	 * </p>
+	 */
+	protected final String target;
+
+	/**
+	 * <p>
+	 * Id for object serialization.
+	 * </p>
+	 */
+	private static final long serialVersionUID = 1L;
+
+	/**
+	 * <p>
+	 * Constructor. Creates a new TextEqualsReplay.
+	 * 
+	 * @param expectedValue
+	 *            expected string value
+	 * @param target
+	 *            string description of the target whose string value is
+	 *            compared to the expected value
+	 * @throws InvalidParameterException
+	 *             thrown if target is null
+	 */
+	public TextEqualsReplay(String expectedValue, String target) {
+		if (target == null) {
+			throw new InvalidParameterException("target must not be null");
+		}
+		this.expectedValue = expectedValue;
+		this.target = target;
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see de.ugoe.cs.quest.eventcore.IReplayable#getReplay()
+	 */
+	@Override
+	public String getReplay() {
+
+		String expectedValueTmp = StringTools.xmlEntityReplacement(expectedValue);
+
+		StringBuilder currentMsgStr = new StringBuilder(400);
+		currentMsgStr.append(" <textEquals expectedValue=\"" + expectedValueTmp
+				+ "\">");
+		currentMsgStr.append(StringTools.ENDLINE);
+		currentMsgStr.append("<target>");
+		currentMsgStr.append(StringTools.ENDLINE);
+		currentMsgStr.append(target);
+		currentMsgStr.append(StringTools.ENDLINE);
+		currentMsgStr.append("</target>");
+		currentMsgStr.append(StringTools.ENDLINE);
+		currentMsgStr.append("</textEquals>");
+		currentMsgStr.append(StringTools.ENDLINE);
+		return currentMsgStr.toString();
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see de.ugoe.cs.quest.eventcore.IReplayable#getTarget()
+	 */
+	@Override
+	public String getTarget() {
+		return target;
+	}
+
+}
Index: /trunk/quest-core-events/src/main/java/de/ugoe/cs/quest/coverage/CoverageCalculatorObserved.java
===================================================================
--- /trunk/quest-core-events/src/main/java/de/ugoe/cs/quest/coverage/CoverageCalculatorObserved.java	(revision 480)
+++ /trunk/quest-core-events/src/main/java/de/ugoe/cs/quest/coverage/CoverageCalculatorObserved.java	(revision 480)
@@ -0,0 +1,272 @@
+package de.ugoe.cs.quest.coverage;
+
+import java.security.InvalidParameterException;
+import java.util.Collection;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+
+import de.ugoe.cs.quest.eventcore.Event;
+import de.ugoe.cs.quest.usageprofiles.IStochasticProcess;
+
+/**
+ * <p>
+ * This class calculates various types of sequence coverage in relation to a
+ * collection of observed sequences.
+ * </p>
+ * 
+ * @author Steffen Herbold
+ * @version 1.0
+ */
+public class CoverageCalculatorObserved {
+
+	/**
+	 * <p>
+	 * Sequences for which the coverage is calculated.
+	 * </p>
+	 */
+	private final Collection<List<? extends Event<?>>> sequences;
+
+	/**
+	 * <p>
+	 * Observed sequences that are baseline for the coverage calculation.
+	 * </p>
+	 */
+	private final Collection<List<? extends Event<?>>> observedSequences;
+
+	/**
+	 * <p>
+	 * Length of the subsequences in relation to which the covarage is
+	 * calculated.
+	 * </p>
+	 */
+	private final int length;
+
+	/**
+	 * <p>
+	 * All subsequences of {@link #length} of {@link #sequences}.
+	 * </p>
+	 */
+	private Collection<List<? extends Event<?>>> subSeqsGenerated = null;
+
+	/**
+	 * <p>
+	 * All subsequences of {@link #length} of {@link #observedSequences}.
+	 * </p>
+	 */
+	private Collection<List<? extends Event<?>>> subSeqsObserved = null;
+
+	/**
+	 * <p>
+	 * Constructor. Creates a new CoverageCalculatorObserved for given
+	 * collections of observed sequences and generated sequences.
+	 * </p>
+	 * 
+	 * @param observedSequences
+	 *            observed sequences in relation to which the coverage is
+	 *            calculated; must not be null
+	 * @param sequences
+	 *            sequences for which the coverage is calculated; must not be
+	 *            null
+	 * @param length
+	 *            length of the subsequences for which the coverage is analyzed;
+	 *            must be >0
+	 * @throws InvalidParameterException
+	 *             thrown if observedSequences or sequences is null or length
+	 *             less than or equal to 0
+	 */
+	public CoverageCalculatorObserved(
+			Collection<List<? extends Event<?>>> observedSequences,
+			Collection<List<? extends Event<?>>> sequences, int length) {
+		if (observedSequences == null) {
+			throw new InvalidParameterException(
+					"observed sequences must not be null");
+		}
+		if (sequences == null) {
+			throw new InvalidParameterException("sequences must not be null");
+		}
+		if (length <= 0) {
+			throw new InvalidParameterException(
+					"length must be >0; actual value: " + length);
+		}
+		this.observedSequences = observedSequences;
+		this.sequences = sequences;
+		this.length = length;
+	}
+
+	/**
+	 * <p>
+	 * Calculates the percentage of subsequences of length k that occur, with
+	 * reference to those that were observed.
+	 * </p>
+	 * 
+	 * @return coverage percentage
+	 */
+	public double getCoverageObserved() {
+		createSubSeqs();
+		Collection<List<? extends Event<?>>> subSeqsObservedCopy = new LinkedHashSet<List<? extends Event<?>>>(
+				subSeqsObserved);
+		subSeqsObservedCopy.retainAll(subSeqsGenerated);
+		return ((double) subSeqsObservedCopy.size()) / subSeqsObserved.size();
+	}
+
+	/**
+	 * <p>
+	 * Calculates the weight of subsequences of length k that occur, with
+	 * reference to those that were observed.
+	 * </p>
+	 * 
+	 * @param process
+	 *            stochastic process in reference to which the weight is
+	 *            calculated
+	 * @return coverage percentage
+	 */
+
+	public double getCoverageObservedWeigth(IStochasticProcess process) {
+		createSubSeqs();
+		Map<List<? extends Event<?>>, Double> weightMap = SequenceTools
+				.generateWeights(process, subSeqsObserved);
+
+		Collection<List<? extends Event<?>>> subSeqsObservedCopy = new LinkedHashSet<List<? extends Event<?>>>(
+				subSeqsObserved);
+		subSeqsObservedCopy.retainAll(subSeqsGenerated);
+		double weight = 0.0d;
+		for (List<? extends Event<?>> subSeq : subSeqsObservedCopy) {
+			weight += weightMap.get(subSeq);
+		}
+		return weight;
+	}
+
+	/**
+	 * <p>
+	 * Calculates the percentage of generated subsequences of length k that
+	 * occur and have not been observed, with reference to all generated
+	 * subsequences.
+	 * </p>
+	 * 
+	 * @return coverage percentage
+	 */
+	public double getNewPercentage() {
+		createSubSeqs();
+		Collection<List<? extends Event<?>>> subSeqsGeneratedCopy = new LinkedHashSet<List<? extends Event<?>>>(
+				subSeqsGenerated);
+		subSeqsGeneratedCopy.removeAll(subSeqsObserved);
+		return ((double) subSeqsGeneratedCopy.size()) / subSeqsGenerated.size();
+	}
+
+	/**
+	 * <p>
+	 * Calculates the percentage of generated subsequences of length k that
+	 * occur and have not been observed, with references to all possible new
+	 * subsequences.
+	 * </p>
+	 * 
+	 * @param process
+	 *            stochastic process which is used to determine which
+	 *            subsequences are possible
+	 * @return coverage percentage
+	 * @throws InvalidParameterException
+	 *             thrown if process is null
+	 */
+	public double getCoveragePossibleNew(IStochasticProcess process) {
+		if (process == null) {
+			throw new InvalidParameterException("process must not be null");
+		}
+		createSubSeqs();
+		Collection<List<? extends Event<?>>> subSeqsGeneratedCopy = new LinkedHashSet<List<? extends Event<?>>>(
+				subSeqsGenerated);
+		Collection<List<? extends Event<?>>> subSeqsPossible = process
+				.generateSequences(length);
+		subSeqsGeneratedCopy.removeAll(subSeqsObserved);
+		subSeqsPossible.removeAll(subSeqsObserved);
+		int possibleSize = subSeqsPossible.size();
+		subSeqsPossible.retainAll(subSeqsGeneratedCopy);
+		return ((double) subSeqsPossible.size()) / possibleSize;
+	}
+
+	/**
+	 * <p>
+	 * Calculates the weight of generated subsequences of length k that occur
+	 * and have not been observed, with references to all possible new
+	 * subsequences.
+	 * </p>
+	 * 
+	 * @param process
+	 *            stochastic process which is used to determine the weights and
+	 *            which subsequences are possible
+	 * @return coverage percentage
+	 * @throws InvalidParameterException
+	 *             thrown if process is null
+	 */
+	public double getCoveragePossibleNewWeight(IStochasticProcess process) {
+		if (process == null) {
+			throw new InvalidParameterException("process must not be null");
+		}
+		createSubSeqs();
+		Collection<List<? extends Event<?>>> subSeqsGeneratedCopy = new LinkedHashSet<List<? extends Event<?>>>(
+				subSeqsGenerated);
+		Collection<List<? extends Event<?>>> subSeqsPossible = process
+				.generateSequences(length);
+		subSeqsGeneratedCopy.removeAll(subSeqsObserved);
+		subSeqsPossible.removeAll(subSeqsObserved);
+		Map<List<? extends Event<?>>, Double> weightMap = SequenceTools
+				.generateWeights(process, subSeqsPossible);
+		double weight = 0.0d;
+		for (List<? extends Event<?>> subSeq : subSeqsGeneratedCopy) {
+			Double currentWeight = weightMap.get(subSeq);
+			if( currentWeight!=null ) {
+				weight += currentWeight;
+			}
+		}
+		return weight;
+	}
+
+	/**
+	 * <p>
+	 * Returns the number of covered subsequences of length k.
+	 * </p>
+	 * 
+	 * @return number of covered subsequences
+	 */
+	public int getNumObserved() {
+		createSubSeqs();
+		return subSeqsObserved.size();
+	}
+
+	/**
+	 * <p>
+	 * Returns the number of covered subsequences of length k.
+	 * </p>
+	 * 
+	 * @return number of covered subsequences
+	 */
+	public int getNumCovered() {
+		createSubSeqs();
+		return subSeqsGenerated.size();
+	}
+
+	public int getNumNew() {
+		createSubSeqs();
+		Collection<List<? extends Event<?>>> subSeqsGeneratedCopy = new LinkedHashSet<List<? extends Event<?>>>(
+				subSeqsGenerated);
+		subSeqsGeneratedCopy.removeAll(subSeqsObserved);
+		return subSeqsGeneratedCopy.size();
+	}
+
+	/**
+	 * <p>
+	 * Helper function that calcuates the subsequences of length k that have
+	 * been observed and generated.
+	 * </p>
+	 */
+	private void createSubSeqs() {
+		if (subSeqsObserved == null) {
+			subSeqsObserved = SequenceTools.containedSubSequences(
+					observedSequences, length);
+		}
+		if (subSeqsGenerated == null) {
+			subSeqsGenerated = SequenceTools.containedSubSequences(sequences,
+					length);
+		}
+	}
+}
Index: /trunk/quest-core-events/src/main/java/de/ugoe/cs/quest/coverage/CoverageCalculatorProcess.java
===================================================================
--- /trunk/quest-core-events/src/main/java/de/ugoe/cs/quest/coverage/CoverageCalculatorProcess.java	(revision 480)
+++ /trunk/quest-core-events/src/main/java/de/ugoe/cs/quest/coverage/CoverageCalculatorProcess.java	(revision 480)
@@ -0,0 +1,218 @@
+package de.ugoe.cs.quest.coverage;
+
+import java.security.InvalidParameterException;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+import de.ugoe.cs.quest.eventcore.Event;
+import de.ugoe.cs.quest.usageprofiles.IStochasticProcess;
+
+/**
+ * <p>
+ * This class calculates various types of sequence coverage in relation to a
+ * stochastic process.
+ * </p>
+ * 
+ * @author Steffen Herbold
+ * @version 1.0
+ */
+public class CoverageCalculatorProcess {
+
+	/**
+	 * <p>
+	 * Stochastic process that is the foundation for probabilistic coverages and
+	 * coverages with reference to all possible sequences.
+	 * </p>
+	 */
+	private final IStochasticProcess process;
+
+	/**
+	 * <p>
+	 * Sequences for which the coverage is calculated.
+	 * </p>
+	 */
+	private Collection<List<? extends Event<?>>> sequences;
+
+	/**
+	 * <p>
+	 * Length of the subsequences in relation to which the coverage is
+	 * calculated.
+	 * </p>
+	 */
+	private final int length;
+
+	/**
+	 * <p>
+	 * All subsequences of {@link #length} of {@link #sequences}.
+	 * </p>
+	 */
+	private Collection<List<? extends Event<?>>> containedSubSeqs = null;
+
+	/**
+	 * <p>
+	 * All subsequences of {@link #length} that can be generated by
+	 * {@link #process}.
+	 * </p>
+	 */
+	private Collection<List<? extends Event<?>>> allPossibleSubSeqs = null;
+
+	/**
+	 * <p>
+	 * The probabilities of all subsequences of {@link #length} according to
+	 * {@link #process}.
+	 * </p>
+	 */
+	private Map<List<? extends Event<?>>, Double> subSeqWeights = null;
+
+	/**
+	 * <p>
+	 * Constructor. Creates a new CoverageCalculatorProcess for a given
+	 * stochastic process and generated sequences.
+	 * </p>
+	 * 
+	 * @param process
+	 *            stochastic process used for coverage calculations; must not be
+	 *            null
+	 * @param sequences
+	 *            sequences for which the coverage is calculated; must not be
+	 *            null
+	 * @param length
+	 *            length of the subsequences for which the coverage is analyzed;
+	 *            must be >0
+	 * @throws InvalidParameterException
+	 *             thrown if process or sequences is null or length less than or equal to 0
+	 */
+	public CoverageCalculatorProcess(IStochasticProcess process,
+			Collection<List<? extends Event<?>>> sequences, int length) {
+		if (process == null) {
+			throw new InvalidParameterException("process must not be null");
+		}
+		if (sequences == null) {
+			throw new InvalidParameterException("sequences must not be null");
+		}
+		if (length <= 0) {
+			throw new InvalidParameterException(
+					"length must be >0; actual value: " + length);
+		}
+		this.process = process;
+		this.sequences = sequences;
+		this.length = length;
+	}
+
+	/**
+	 * <p>
+	 * Calculates the percentage of subsequences of length k that occur,
+	 * including those that cannot be generated by {@link #process}.
+	 * </p>
+	 * 
+	 * @return coverage percentage
+	 */
+	public double getCoverageAllNoWeight() {
+		if (containedSubSeqs == null) {
+			containedSubSeqs = SequenceTools.containedSubSequences(sequences,
+					length);
+		}
+		return ((double) containedSubSeqs.size())
+				/ SequenceTools.numSequences(process, length);
+	}
+
+	/**
+	 * <p>
+	 * Calculates the percentage of subsequences of length k that occur and can
+	 * generated by {@link #process}.
+	 * </p>
+	 * 
+	 * @return coverage percentage
+	 */
+	public double getCoveragePossibleNoWeight() {
+		if (containedSubSeqs == null) {
+			containedSubSeqs = SequenceTools.containedSubSequences(sequences,
+					length);
+		}
+		if (allPossibleSubSeqs == null) {
+			allPossibleSubSeqs = process.generateSequences(length);
+		}
+		return ((double) containedSubSeqs.size()) / allPossibleSubSeqs.size();
+	}
+
+	/**
+	 * <p>
+	 * Calculates the weight of the subsequences that occur with relation to
+	 * {@link #process}, i.e., the mass of the subsequence probability covered
+	 * by the subsequences.
+	 * </p>
+	 * 
+	 * @return coverage weight
+	 */
+	public double getCoveragePossibleWeight() {
+		if (containedSubSeqs == null) {
+			containedSubSeqs = SequenceTools.containedSubSequences(sequences,
+					length);
+		}
+		if (allPossibleSubSeqs == null) {
+			allPossibleSubSeqs = process.generateSequences(length);
+		}
+		if (subSeqWeights == null) {
+			subSeqWeights = SequenceTools.generateWeights(process,
+					allPossibleSubSeqs);
+		}
+		double weight = 0.0;
+		for (List<? extends Event<?>> subSeq : containedSubSeqs) {
+			Double curWeight = subSeqWeights.get(subSeq);
+			if( curWeight!=null ) {
+				weight += curWeight;
+			}
+		}
+		return weight;
+	}
+
+	/**
+	 * <p>
+	 * Returns the number of covered subsequences of length k.
+	 * </p>
+	 * 
+	 * @return number of covered subsequences
+	 */
+	public int getNumCovered() {
+		if (containedSubSeqs == null) {
+			containedSubSeqs = SequenceTools.containedSubSequences(sequences,
+					length);
+		}
+		return containedSubSeqs.size();
+	}
+
+	/**
+	 * <p>
+	 * Returns the number of possible subsequences of length k according to the
+	 * stochastic process.
+	 * </p>
+	 * 
+	 * @return number of possible subsequences
+	 */
+	public int getNumPossible() {
+		if (allPossibleSubSeqs == null) {
+			allPossibleSubSeqs = process.generateSequences(length);
+		}
+		return allPossibleSubSeqs.size();
+	}
+
+	/**
+	 * <p>
+	 * Sets a new collection of sequences for which the coverage is analyzed.
+	 * </p>
+	 * 
+	 * @param newSequences
+	 *            new collection of sequences
+	 * @throws InvalidParameterException
+	 *             thrown is newSequences is null
+	 */
+	public void setSequences(Collection<List<? extends Event<?>>> newSequences) {
+		if (newSequences == null) {
+			throw new InvalidParameterException("sequences must not be null");
+		}
+		this.sequences = newSequences;
+		containedSubSeqs = null;
+	}
+
+}
Index: /trunk/quest-core-events/src/main/java/de/ugoe/cs/quest/coverage/SequenceTools.java
===================================================================
--- /trunk/quest-core-events/src/main/java/de/ugoe/cs/quest/coverage/SequenceTools.java	(revision 480)
+++ /trunk/quest-core-events/src/main/java/de/ugoe/cs/quest/coverage/SequenceTools.java	(revision 480)
@@ -0,0 +1,147 @@
+package de.ugoe.cs.quest.coverage;
+
+import java.security.InvalidParameterException;
+import java.util.Collection;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import de.ugoe.cs.quest.eventcore.Event;
+import de.ugoe.cs.quest.usageprofiles.IStochasticProcess;
+
+/**
+ * <p>
+ * This class gathers some helper functions to work with sequences.
+ * </p>
+ * 
+ * @author Steffen Herbold
+ * @version 1.0
+ */
+public class SequenceTools {
+	
+	/**
+	 * <p>
+	 * Private constructor to prevent initializing of the class.
+	 * </p>
+	 */
+	private SequenceTools() {
+		
+	}
+
+	/**
+	 * <p>
+	 * Calculates the weights for all sequences passed to this function as
+	 * defined by the stochastic process and stores them in a {@link Map}. The
+	 * weights are normalized, i.e., the sum of all weights contained in this
+	 * map is 1.
+	 * </p>
+	 * 
+	 * @param process
+	 *            process used for weight calculation
+	 * @param sequences
+	 *            sequences for which the weights are calculated
+	 * @return {@link Map} of weights
+	 */
+	public static Map<List<? extends Event<?>>, Double> generateWeights(
+			IStochasticProcess process,
+			Collection<List<? extends Event<?>>> sequences) {
+		Map<List<? extends Event<?>>, Double> subSeqWeights = new LinkedHashMap<List<? extends Event<?>>, Double>();
+		if (sequences != null && !sequences.isEmpty()) {
+			if (process != null) {
+				double sum = 0.0;
+				for (List<? extends Event<?>> sequence : sequences) {
+					double prob = process.getProbability(sequence);
+					subSeqWeights.put(sequence, prob);
+					sum += prob;
+				}
+				if (sum < 1.0) {
+					for (Map.Entry<List<? extends Event<?>>, Double> entry : subSeqWeights
+							.entrySet()) {
+						entry.setValue(entry.getValue() / sum);
+					}
+				}
+			} else {
+				for( List<? extends Event<?>> sequence : sequences ) {
+					subSeqWeights.put(sequence, 0.0d);
+				}
+			}
+		}
+		return subSeqWeights;
+	}
+
+	/**
+	 * <p>
+	 * Calculates the number of all existing sequences of a given length,
+	 * regardless whether they are possible or not.
+	 * </p>
+	 * 
+	 * @param process
+	 *            stochastic process whose symbols are the basis for this
+	 *            calculation
+	 * @param length
+	 *            lenght of the sequences
+	 * @return numStates^length
+	 * @throws InvalidParameterException
+	 *             thrown if length less or equal to 0
+	 */
+	public static long numSequences(IStochasticProcess process, int length) {
+		if (length <= 0) {
+			throw new InvalidParameterException(
+					"length must be a positive integer");
+		}
+		long result = 0;
+		if (process != null) {
+			result = (long) Math.pow(process.getNumSymbols(), length);
+		}
+		return result;
+	}
+
+	/**
+	 * <p>
+	 * Creates a {@link Set} of all subsequences of a given length that are
+	 * contained in a sequence collection.
+	 * </p>
+	 * 
+	 * @param sequences
+	 *            sequences from which the subsequences are extracted
+	 * @param length
+	 *            length of the subsequences
+	 * @return {@link Set} of all subsequences
+	 * @throws InvalidParameterException
+	 *             thrown if length less or equal to 0
+	 */
+	public static Set<List<? extends Event<?>>> containedSubSequences(
+			Collection<List<? extends Event<?>>> sequences, int length) {
+		if (length <= 0) {
+			throw new InvalidParameterException(
+					"length must be a positive integer");
+		}
+		Set<List<? extends Event<?>>> containedSubSeqs = new LinkedHashSet<List<? extends Event<?>>>();
+		if (sequences != null) {
+			for (List<? extends Event<?>> sequence : sequences) {
+				List<Event<?>> subSeq = new LinkedList<Event<?>>();
+				boolean minLengthReached = false;
+				for (Event<?> event : sequence) {
+					subSeq.add(event);
+					if (!minLengthReached) {
+						if (subSeq.size() == length) {
+							minLengthReached = true;
+						}
+					} else {
+						subSeq.remove(0);
+					}
+					if (minLengthReached) {
+						if (!containedSubSeqs.contains(subSeq)) {
+							containedSubSeqs.add(new LinkedList<Event<?>>(
+									subSeq));
+						}
+					}
+				}
+			}
+		}
+		return containedSubSeqs;
+	}
+}
Index: /trunk/quest-core-events/src/main/java/de/ugoe/cs/quest/eventcore/Event.java
===================================================================
--- /trunk/quest-core-events/src/main/java/de/ugoe/cs/quest/eventcore/Event.java	(revision 480)
+++ /trunk/quest-core-events/src/main/java/de/ugoe/cs/quest/eventcore/Event.java	(revision 480)
@@ -0,0 +1,327 @@
+package de.ugoe.cs.quest.eventcore;
+
+import java.io.Serializable;
+import java.security.InvalidParameterException;
+
+/**
+ * <p>
+ * Base class for all events. An event is described by its {@link #type} and its
+ * {@link #target}.
+ * </p>
+ * 
+ * @author Steffen Herbold
+ * @version 1.0
+ * 
+ * @param <T>
+ *            Can be used to declare that events belong to a specific platform
+ *            without subclassing.
+ */
+public class Event<T> implements Serializable {
+
+	/**
+	 * Id for object serialization.
+	 */
+	private static final long serialVersionUID = 1L;
+
+	/**
+	 * <p>
+	 * Global start event that can be used to indicate the start of a sequence.
+	 * </p>
+	 */
+	public static final Event<Object> STARTEVENT = new Event<Object>("START");
+
+	/**
+	 * <p>
+	 * Global end event that can be used to indicate the end of a sequence.
+	 */
+	public static final Event<Object> ENDEVENT = new Event<Object>("END");
+
+	/**
+	 * <p>
+	 * Type of the event.
+	 * </p>
+	 */
+	protected String type;
+
+	/**
+	 * </p> Target of the event.
+	 */
+	protected String target = null;
+
+	/**
+	 * <p>
+	 * Short description of the event target.
+	 * </p>
+	 */
+	protected String targetShort = null;
+
+	/**
+	 * Further information about the event that shall be included in its Id.
+	 */
+	protected String idInfo = "";
+
+	/**
+	 * <p>
+	 * Constructor. Creates a new Event with a given type.
+	 * </p>
+	 * 
+	 * @param type
+	 *            type of the event
+	 */
+	public Event(String type) {
+		if (type == null) {
+			throw new InvalidParameterException("Event type must not be null");
+		}
+		this.type = type;
+	}
+
+	/**
+	 * <p>
+	 * Two events are equal, if their {@link #type} and {@link #target} are
+	 * equal.
+	 * </p>
+	 * <p>
+	 * See {@link Object#equals(Object)} for further information.
+	 * </p>
+	 * 
+	 * @param other
+	 *            Event that is compared to this
+	 * @return true, if events are equal, false otherwise
+	 */
+	@Override
+	public boolean equals(Object other) {
+		if (this == other) {
+			return true;
+		}
+		if (other instanceof Event<?>) {
+			Event<?> otherEvent = (Event<?>) other;
+			if (otherEvent.canEqual(this)) {
+				if (type != null) {
+					return targetEquals(otherEvent.target)
+							&& type.equals(otherEvent.type);
+				} else {
+					return targetEquals(otherEvent.target)
+							&& otherEvent.type == null;
+				}
+			} else {
+				return false;
+			}
+		} else {
+			return false;
+		}
+	}
+
+	public boolean canEqual(Object other) {
+		return (other instanceof Event<?>);
+	}
+
+	/**
+	 * <p>
+	 * Returns {@link #getStandardId()} as String representation of the event.
+	 * </p>
+	 * 
+	 * @return String represenation of the event
+	 */
+	@Override
+	public String toString() {
+		return getStandardId();
+	}
+
+	/**
+	 * Informations about the event important for its Id that is neither target
+	 * nor type.
+	 * 
+	 * @return {@link #idInfo} of the event
+	 */
+	public String getIdInfo() {
+		return idInfo;
+	}
+
+	/**
+	 * <p>
+	 * If {@link #targetShort} is set, a shortend version of the Id is returned
+	 * of the form {@link #targetShort}.{@link #type}.{@link #idInfo} is
+	 * returned. Otherwise the standard Id is returned (see
+	 * {@link #getStandardId()}).
+	 * </p>
+	 * 
+	 * @return if available, shortend Id string; {@link #getStandardId()}
+	 *         otherwise
+	 */
+	public String getShortId() {
+		String shortId = null;
+		if (targetShort != null) {
+			shortId = targetShort + "." + getType();
+			if (!"".equals(idInfo)) {
+				shortId += "." + idInfo;
+			}
+		} else {
+			shortId = getStandardId();
+		}
+		return shortId;
+	}
+
+	/**
+	 * <p>
+	 * Returns the Id string of the event. It has the form {@link #target}.
+	 * {@link #type}.{@link #idInfo};
+	 * <p>
+	 * 
+	 * @return Id string of the event
+	 */
+	public String getStandardId() {
+		String id = "";
+		if (target != null) {
+			id += target + ".";
+		}
+		id += getType();
+		if (!"".equals(idInfo)) {
+			id += "." + idInfo;
+		}
+		return id;
+	}
+
+	/**
+	 * <p>
+	 * Returns the {@link #target} of the event.
+	 * </p>
+	 * 
+	 * @return {@link #target} of the event
+	 */
+	public String getTarget() {
+		return target;
+	}
+
+	/**
+	 * <p>
+	 * Returns the {@link #targetShort} of the event.
+	 * </p>
+	 * 
+	 * @return {@link #targetShort} of the event
+	 */
+	protected String getTargetShort() {
+		return targetShort;
+	}
+
+	/**
+	 * <p>
+	 * Returns the {@link #type} of the event.
+	 * </p>
+	 * 
+	 * @return {@link #type} of the event
+	 */
+	public String getType() {
+		return type;
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see java.lang.Object#hashCode()
+	 */
+	@Override
+	public int hashCode() {
+		int multiplier = 17;
+		int hash = 42;
+		if (type != null) {
+			hash = multiplier * hash + type.hashCode();
+		}
+		hash = multiplier * hash + targetHashCode();
+
+		return hash;
+	}
+
+	/**
+	 * <p>
+	 * Sets the {@link #idInfo} of the event. The idInfo is optional and
+	 * contains information important for the event's Id that is neither target
+	 * nor type.
+	 * </p>
+	 * 
+	 * @param info
+	 *            {@link #idInfo} of the event
+	 */
+	public void setIdInfo(String info) {
+		idInfo = info;
+	}
+
+	/**
+	 * <p>
+	 * Sets the target of the event. Once set, the target cannot be changed.
+	 * </p>
+	 * 
+	 * @param target
+	 *            target of the event
+	 * @return true, if target was changed, false otherwise
+	 */
+	public boolean setTarget(String target) {
+		if (this.target != null) {
+			return false;
+		}
+		this.target = target;
+		return true;
+	}
+
+	/**
+	 * <p>
+	 * Sets the short description of the event target. Once set, the target
+	 * cannot be changed.
+	 * </p>
+	 * 
+	 * @param targetShort
+	 *            short target description
+	 * @return true, if target was changed, false otherwise
+	 */
+	public boolean setTargetShort(String targetShort) {
+		if (this.targetShort != null) {
+			return false;
+		}
+		this.targetShort = targetShort;
+		return true;
+	}
+
+	/**
+	 * <p>
+	 * This function is used by {@link #equals(Object)} to determine if the
+	 * targets of both events are equal. The standard implementation provided by
+	 * this class performs a String comparison between the target strings.
+	 * </p>
+	 * <p>
+	 * Subclasses can override this method to implemented more sophisticated
+	 * means for the target comparison, e.g., to account for changes in the
+	 * title of a widget.
+	 * </p>
+	 * 
+	 * @param otherTarget
+	 *            other target string to which the target if this event is
+	 *            compared to
+	 * @return true if the targets are equals; false otherwise
+	 */
+	protected boolean targetEquals(String otherTarget) {
+		boolean retVal;
+		if (target != null) {
+			retVal = target.equals(otherTarget);
+		} else {
+			retVal = (otherTarget == null);
+		}
+		return retVal;
+	}
+
+	/**
+	 * <p>
+	 * This function is used by {@link #hashCode()} to determine how the hash of
+	 * the {@link #target}. It has to be overridden by subclasses that implement
+	 * {@link #targetEquals(String)}, to ensure that the equals/hashCode
+	 * contract remains valid.
+	 * </p>
+	 * 
+	 * @return hash of the target
+	 */
+	protected int targetHashCode() {
+		if (target != null) {
+			return target.hashCode();
+		} else {
+			return 0;
+		}
+	}
+}
Index: /trunk/quest-core-events/src/main/java/de/ugoe/cs/quest/eventcore/IReplayable.java
===================================================================
--- /trunk/quest-core-events/src/main/java/de/ugoe/cs/quest/eventcore/IReplayable.java	(revision 480)
+++ /trunk/quest-core-events/src/main/java/de/ugoe/cs/quest/eventcore/IReplayable.java	(revision 480)
@@ -0,0 +1,35 @@
+package de.ugoe.cs.quest.eventcore;
+
+import java.io.Serializable;
+
+/**
+ * <p>
+ * This interface is used by {@link ReplayableEvent}to describe how events can
+ * be replayed. It can be used to define a sequence of fine-grained platform
+ * events that make up an abstract event.
+ * </p>
+ * 
+ * @author Steffen Herbold
+ * @version 1.0
+ */
+public interface IReplayable extends Serializable {
+
+	/**
+	 * <p>
+	 * Returns a string to be written to the replay script that describes the
+	 * replayable platform event.
+	 * </p>
+	 * 
+	 * @return string for the replay script
+	 */
+	String getReplay();
+
+	/**
+	 * <p>
+	 * Returns the target of the replayable.
+	 * </p>
+	 * 
+	 * @return target of the replayable
+	 */
+	String getTarget();
+}
Index: /trunk/quest-core-events/src/main/java/de/ugoe/cs/quest/eventcore/ReplayableEvent.java
===================================================================
--- /trunk/quest-core-events/src/main/java/de/ugoe/cs/quest/eventcore/ReplayableEvent.java	(revision 480)
+++ /trunk/quest-core-events/src/main/java/de/ugoe/cs/quest/eventcore/ReplayableEvent.java	(revision 480)
@@ -0,0 +1,167 @@
+package de.ugoe.cs.quest.eventcore;
+
+import java.security.InvalidParameterException;
+import java.util.LinkedList;
+import java.util.List;
+
+import de.ugoe.cs.quest.IReplayDecorator;
+
+/**
+ * <p>
+ * Subclass of {@link Event} for events that contain all informations required
+ * for replaying them, i.e., generating scripts that can used for automated
+ * software execution.
+ * </p>
+ * 
+ * @author Steffen Herbold
+ * @version 1.0
+ * 
+ * @param <T>
+ *            Allows only types that extend {@link IReplayable} and is used to
+ *            define a list of replayables that describe the replay of the
+ *            event.
+ */
+public class ReplayableEvent<T extends IReplayable> extends Event<T> {
+
+	/**
+	 * Id for object serialization.
+	 */
+	private static final long serialVersionUID = 1L;
+
+	/**
+	 * <p>
+	 * List of {@link IReplayable}s of type T that describes the replay of an
+	 * event. The {@link IReplayable}s can be interpreted as <it>sub-events</it>
+	 * on the platform level that make up the abstract event.
+	 * </p>
+	 */
+	protected List<T> replayEvents = new LinkedList<T>();;
+
+	/**
+	 * <p>
+	 * Defines whether the replay is valid or invalid. It may be invalid, e.g.,
+	 * due to errors during the generation of the event or lack of vital
+	 * information.
+	 * </p>
+	 */
+	protected boolean replayValid = true;
+
+	/**
+	 * <p>
+	 * {@link IReplayDecorator} used when replays of this type are written.
+	 * </p>
+	 */
+	protected IReplayDecorator decorator = null;
+
+	/**
+	 * <p>
+	 * Constructor. Creates a new event with the given type.
+	 * <p>
+	 * 
+	 * @param type
+	 *            type of the event
+	 * @see Event#Event(String)
+	 */
+	public ReplayableEvent(String type) {
+		super(type);
+	}
+
+	/**
+	 * <p>
+	 * Adds a new {@link IReplayable} of type T to the replay sequence.
+	 * </p>
+	 * 
+	 * @param replayable
+	 *            element that is added to the sequence
+	 * @throws InvalidParameterException
+	 *             thrown is replayable is null
+	 */
+	public void addReplayEvent(T replayable) {
+		if (replayable == null) {
+			throw new InvalidParameterException("replayble must not be null");
+		}
+		replayEvents.add(replayable);
+	}
+
+	/**
+	 * <p>
+	 * Adds a {@link List}ist of {@link IReplayable} to the replay sequence.
+	 * </p>
+	 * 
+	 * @param generatedReplaySeq
+	 *            {@link List} that is added to the sequence
+	 * @throws InvalidParameterException
+	 *             thrown if generatedReplaySeq is null
+	 */
+	public void addReplaySequence(List<T> generatedReplaySeq) {
+		if (generatedReplaySeq == null) {
+			throw new InvalidParameterException(
+					"generatedReplaySeq must not be null");
+		}
+		replayEvents.addAll(generatedReplaySeq);
+	}
+
+	/**
+	 * <p>
+	 * Returns the {@link IReplayDecorator} of the event.
+	 * </p>
+	 * 
+	 * @return {@link IReplayDecorator} of the event; null if no decorator has
+	 *         been set
+	 */
+	public IReplayDecorator getReplayDecorator() {
+		return decorator;
+	}
+
+	/**
+	 * <p>
+	 * Returns a the list of replay events.
+	 * </p>
+	 * <p>
+	 * The return value is a copy of the list used internally!
+	 * </p>
+	 * 
+	 * @return list of replay events.
+	 */
+	public List<T> getReplayMessages() {
+		return new LinkedList<T>(replayEvents);
+	}
+
+	/**
+	 * <p>
+	 * Returns whether the replay is valid or not.
+	 * </p>
+	 * 
+	 * @return true, if replay is valid; false otherwise.
+	 */
+	public boolean hasValidReplay() {
+		return replayValid;
+	}
+
+	/**
+	 * <p>
+	 * Marks the replay as invalid. Once marked as invalid, it remains so and
+	 * cannot be changed back to valid.
+	 * </p>
+	 */
+	public void invalidateReplay() {
+		replayValid = false;
+	}
+
+	/**
+	 * <p>
+	 * Sets the {@link IReplayDecorator} associated with the event.
+	 * </p>
+	 * 
+	 * @param decorator
+	 *            decorator associated with the event
+	 */
+	public void setDecorator(IReplayDecorator decorator) {
+		this.decorator = decorator;
+	}
+	
+	@Override
+	public boolean canEqual(Object other) {
+		return (other instanceof ReplayableEvent<?>);
+	}
+}
Index: /trunk/quest-core-events/src/main/java/de/ugoe/cs/quest/usageprofiles/DeterministicFiniteAutomaton.java
===================================================================
--- /trunk/quest-core-events/src/main/java/de/ugoe/cs/quest/usageprofiles/DeterministicFiniteAutomaton.java	(revision 480)
+++ /trunk/quest-core-events/src/main/java/de/ugoe/cs/quest/usageprofiles/DeterministicFiniteAutomaton.java	(revision 480)
@@ -0,0 +1,80 @@
+package de.ugoe.cs.quest.usageprofiles;
+
+import java.security.InvalidParameterException;
+import java.util.Collection;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Random;
+
+import de.ugoe.cs.quest.eventcore.Event;
+
+/**
+ * <p>
+ * Implements a Deterministic Finite Automata (DFA) capable of random session
+ * generation. It is a special case of a first-order Markov model, where the
+ * transition probability is equally high for all following states.
+ * </p>
+ * 
+ * @author Steffen Herbold
+ * @version 1.0
+ */
+public class DeterministicFiniteAutomaton extends FirstOrderMarkovModel {
+
+	/**
+	 * <p>
+	 * Id for object serialization.
+	 * </p>
+	 */
+	private static final long serialVersionUID = 1L;
+
+	/**
+	 * <p>
+	 * Constructor. Creates a new DeterministicFiniteAutomaton.
+	 * </p>
+	 * 
+	 * @param r
+	 *            random number generator used by probabilistic methods of the
+	 *            class
+	 */
+	public DeterministicFiniteAutomaton(Random r) {
+		super(r);
+	}
+
+	/**
+	 * <p>
+	 * Calculates the proability of the next state. Each of the following states
+	 * in the automaton is equally probable.
+	 * </p>
+	 * 
+	 * @see de.ugoe.cs.quest.usageprofiles.IStochasticProcess#getProbability(java.util.List,
+	 *      de.ugoe.cs.quest.eventcore.Event)
+	 */
+	@Override
+	public double getProbability(List<? extends Event<?>> context,
+			Event<?> symbol) {
+		if( context==null ) {
+			throw new InvalidParameterException("context must not be null");
+		}
+		if( symbol==null ) {
+			throw new InvalidParameterException("symbol must not be null");
+		}
+		double result = 0.0d;
+
+		List<Event<?>> contextCopy;
+		if (context.size() >= trieOrder) {
+			contextCopy = new LinkedList<Event<?>>(context.subList(
+					context.size() - trieOrder + 1, context.size()));
+		} else {
+			contextCopy = new LinkedList<Event<?>>(context);
+		}
+
+		Collection<Event<?>> followers = trie.getFollowingSymbols(contextCopy);
+
+		if (followers.size() != 0 && followers.contains(symbol)) {
+			result = 1.0d / followers.size();
+		}
+
+		return result;
+	}
+
+}
Index: /trunk/quest-core-events/src/main/java/de/ugoe/cs/quest/usageprofiles/FirstOrderMarkovModel.java
===================================================================
--- /trunk/quest-core-events/src/main/java/de/ugoe/cs/quest/usageprofiles/FirstOrderMarkovModel.java	(revision 480)
+++ /trunk/quest-core-events/src/main/java/de/ugoe/cs/quest/usageprofiles/FirstOrderMarkovModel.java	(revision 480)
@@ -0,0 +1,264 @@
+package de.ugoe.cs.quest.usageprofiles;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Random;
+
+import de.ugoe.cs.quest.eventcore.Event;
+import de.ugoe.cs.util.StringTools;
+import de.ugoe.cs.util.console.Console;
+import edu.uci.ics.jung.graph.Graph;
+import edu.uci.ics.jung.graph.SparseMultigraph;
+import edu.uci.ics.jung.graph.util.EdgeType;
+
+import Jama.Matrix;
+
+/**
+ * <p>
+ * Implements first-order Markov models. The implementation is based on
+ * {@link HighOrderMarkovModel} and restricts the Markov order to 1. In
+ * comparison to {@link HighOrderMarkovModel}, more calculations are possible
+ * with first-order models, e.g., the calculation of the entropy (
+ * {@link #calcEntropy()}).
+ * </p>
+ * 
+ * @author Steffen Herbold
+ * @version 1.0
+ */
+public class FirstOrderMarkovModel extends HighOrderMarkovModel implements
+		IDotCompatible {
+
+	/**
+	 * <p>
+	 * Id for object serialization.
+	 * </p>
+	 */
+	private static final long serialVersionUID = 1L;
+
+	/**
+	 * <p>
+	 * Maximum number of iterations when calculating the stationary distribution
+	 * as the limit of multiplying the transmission matrix with itself.
+	 * </p>
+	 */
+	final static int MAX_STATDIST_ITERATIONS = 1000;
+
+	/**
+	 * <p>
+	 * Constructor. Creates a new FirstOrderMarkovModel.
+	 * </p>
+	 * 
+	 * @param r
+	 *            random number generator used by probabilistic methods of the
+	 *            class
+	 */
+	public FirstOrderMarkovModel(Random r) {
+		super(1, r);
+	}
+
+	/**
+	 * <p>
+	 * Generates the transmission matrix of the Markov model.
+	 * </p>
+	 * 
+	 * @return transmission matrix
+	 */
+	private Matrix getTransmissionMatrix() {
+		List<Event<?>> knownSymbols = new ArrayList<Event<?>>(
+				trie.getKnownSymbols());
+		int numStates = knownSymbols.size();
+		Matrix transmissionMatrix = new Matrix(numStates, numStates);
+
+		for (int i = 0; i < numStates; i++) {
+			Event<?> currentSymbol = knownSymbols.get(i);
+			List<Event<?>> context = new ArrayList<Event<?>>();
+			context.add(currentSymbol);
+			for (int j = 0; j < numStates; j++) {
+				Event<?> follower = knownSymbols.get(j);
+				double prob = getProbability(context, follower);
+				transmissionMatrix.set(i, j, prob);
+			}
+		}
+		return transmissionMatrix;
+	}
+
+	/**
+	 * <p>
+	 * Calculates the entropy of the model. To make it possible that the model
+	 * is stationary, a transition from {@link Event#ENDEVENT} to
+	 * {@link Event#STARTEVENT} is added.
+	 * </p>
+	 * 
+	 * @return entropy of the model or NaN if it could not be calculated
+	 */
+	public double calcEntropy() {
+		Matrix transmissionMatrix = getTransmissionMatrix();
+		List<Event<?>> knownSymbols = new ArrayList<Event<?>>(
+				trie.getKnownSymbols());
+		int numStates = knownSymbols.size();
+
+		List<Integer> startIndexList = new LinkedList<Integer>();
+		List<Integer> endIndexList = new LinkedList<Integer>();
+		for( int i=0 ; i<knownSymbols.size() ; i++ ) {
+			String id = knownSymbols.get(i).getStandardId();
+			if( id.equals(Event.STARTEVENT.getStandardId()) || id.contains(Event.STARTEVENT.getStandardId()+"-=-") ) {
+				startIndexList.add(i);
+			}
+			if( id.equals(Event.ENDEVENT.getStandardId()) || id.contains("-=-"+Event.ENDEVENT.getStandardId()) ) {
+				endIndexList.add(i);
+			}
+		}
+		
+		if (startIndexList.isEmpty()) {	
+			Console.printerrln("Error calculating entropy. Initial state of markov chain not found.");
+			return Double.NaN;
+		}
+		if (endIndexList.isEmpty()) {
+			Console.printerrln("Error calculating entropy. End state of markov chain not found.");
+			return Double.NaN;
+		}
+		for( Integer i : endIndexList ) {
+			for(Integer j : startIndexList ) {
+				transmissionMatrix.set(i, j, 1);
+			}
+		}
+
+		// Calculate stationary distribution by raising the power of the
+		// transmission matrix.
+		// The rank of the matrix should fall to 1 and each two should be the
+		// vector of the stationory distribution.
+		int iter = 0;
+		int rank = transmissionMatrix.rank();
+		Matrix stationaryMatrix = (Matrix) transmissionMatrix.clone();
+		while (iter < MAX_STATDIST_ITERATIONS && rank > 1) {
+			stationaryMatrix = stationaryMatrix.times(stationaryMatrix);
+			rank = stationaryMatrix.rank();
+			iter++;
+		}
+
+		if (rank != 1) {
+			Console.traceln("rank: " + rank);
+			Console.printerrln("Unable to calculate stationary distribution.");
+			return Double.NaN;
+		}
+
+		double entropy = 0.0;
+		for (int i = 0; i < numStates; i++) {
+			for (int j = 0; j < numStates; j++) {
+				if (transmissionMatrix.get(i, j) != 0 && transmissionMatrix.get(i, j)!=1) {
+					double tmp = stationaryMatrix.get(0, i);
+					tmp *= transmissionMatrix.get(i, j);
+					tmp *= Math.log(transmissionMatrix.get(i, j)) / Math.log(2);
+					entropy -= tmp;
+				}
+			}
+		}
+		return entropy;
+	}
+
+	/**
+	 * <p>
+	 * The dot represenation of {@link FirstOrderMarkovModel}s is its graph
+	 * representation with the states as nodes and directed edges weighted with
+	 * transition probabilities.
+	 * </p>
+	 * 
+	 * @see de.ugoe.cs.quest.usageprofiles.IDotCompatible#getDotRepresentation()
+	 */
+	@Override
+	public String getDotRepresentation() {
+		StringBuilder stringBuilder = new StringBuilder();
+		stringBuilder.append("digraph model {" + StringTools.ENDLINE);
+
+		List<Event<?>> knownSymbols = new ArrayList<Event<?>>(
+				trie.getKnownSymbols());
+		for (Event<?> symbol : knownSymbols) {
+			final String thisSaneId = symbol.getShortId().replace("\"", "\\\"")
+					.replaceAll("[\r\n]", "");
+			stringBuilder.append(" " + knownSymbols.indexOf(symbol) + " [label=\""
+					+ thisSaneId + "\"];" + StringTools.ENDLINE);
+			List<Event<?>> context = new ArrayList<Event<?>>();
+			context.add(symbol);
+			Collection<Event<?>> followers = trie.getFollowingSymbols(context);
+			for (Event<?> follower : followers) {
+				stringBuilder.append(" " + knownSymbols.indexOf(symbol) + " -> "
+						+ knownSymbols.indexOf(follower) + " ");
+				stringBuilder.append("[label=\""
+						+ getProbability(context, follower) + "\"];"
+						+ StringTools.ENDLINE);
+			}
+		}
+		stringBuilder.append('}' + StringTools.ENDLINE);
+		return stringBuilder.toString();
+	}
+
+	/**
+	 * <p>
+	 * Returns a {@link Graph} representation of the model with the states as
+	 * nodes and directed edges weighted with transition probabilities.
+	 * </p>
+	 * 
+	 * @return {@link Graph} of the model
+	 */
+	public Graph<String, MarkovEdge> getGraph() {
+		Graph<String, MarkovEdge> graph = new SparseMultigraph<String, MarkovEdge>();
+
+		List<Event<?>> knownSymbols = new ArrayList<Event<?>>(
+				trie.getKnownSymbols());
+
+		for (Event<?> symbol : knownSymbols) {
+			String from = symbol.getShortId();
+			List<Event<?>> context = new ArrayList<Event<?>>();
+			context.add(symbol);
+
+			Collection<Event<?>> followers = trie.getFollowingSymbols(context);
+
+			for (Event<?> follower : followers) {
+				String to = follower.getShortId();
+				MarkovEdge prob = new MarkovEdge(getProbability(context,
+						follower));
+				graph.addEdge(prob, from, to, EdgeType.DIRECTED);
+			}
+		}
+		return graph;
+	}
+
+	/**
+	 * Inner class used for the {@link Graph} representation of the model.
+	 * 
+	 * @author Steffen Herbold
+	 * @version 1.0
+	 */
+	static public class MarkovEdge {
+		/**
+		 * <p>
+		 * Weight of the edge, i.e., its transition probability.
+		 * </p>
+		 */
+		double weight;
+
+		/**
+		 * <p>
+		 * Constructor. Creates a new MarkovEdge.
+		 * </p>
+		 * 
+		 * @param weight
+		 *            weight of the edge, i.e., its transition probability
+		 */
+		MarkovEdge(double weight) {
+			this.weight = weight;
+		}
+
+		/**
+		 * <p>
+		 * The weight of the edge as {@link String}.
+		 * </p>
+		 */
+		public String toString() {
+			return "" + weight;
+		}
+	}
+
+}
Index: /trunk/quest-core-events/src/main/java/de/ugoe/cs/quest/usageprofiles/HighOrderMarkovModel.java
===================================================================
--- /trunk/quest-core-events/src/main/java/de/ugoe/cs/quest/usageprofiles/HighOrderMarkovModel.java	(revision 480)
+++ /trunk/quest-core-events/src/main/java/de/ugoe/cs/quest/usageprofiles/HighOrderMarkovModel.java	(revision 480)
@@ -0,0 +1,87 @@
+package de.ugoe.cs.quest.usageprofiles;
+
+import java.security.InvalidParameterException;
+import java.util.Collection;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Random;
+
+import de.ugoe.cs.quest.eventcore.Event;
+
+/**
+ * <p>
+ * Implements high-order Markov models.
+ * </p>
+ * 
+ * @author Steffen Herbold
+ * @version 1.0
+ */
+public class HighOrderMarkovModel extends TrieBasedModel {
+
+	/**
+	 * <p>
+	 * Id for object serialization.
+	 * </p>
+	 */
+	private static final long serialVersionUID = 1L;
+
+	/**
+	 * <p>
+	 * Constructor. Creates a new HighOrderMarkovModel with a defined Markov
+	 * order.
+	 * </p>
+	 * 
+	 * @param maxOrder
+	 *            Markov order of the model
+	 * @param r
+	 *            random number generator used by probabilistic methods of the
+	 *            class
+	 */
+	public HighOrderMarkovModel(int maxOrder, Random r) {
+		super(maxOrder, r);
+	}
+
+	/**
+	 * <p>
+	 * Calculates the probability of the next Event being symbol based on the
+	 * order of the Markov model. The order is defined in the constructor
+	 * {@link #HighOrderMarkovModel(int, Random)}.
+	 * </p>
+	 * 
+	 * @see de.ugoe.cs.quest.usageprofiles.IStochasticProcess#getProbability(java.util.List,
+	 *      de.ugoe.cs.quest.eventcore.Event)
+	 */
+	@Override
+	public double getProbability(List<? extends Event<?>> context,
+			Event<?> symbol) {
+		if (context == null) {
+			throw new InvalidParameterException("context must not be null");
+		}
+		if (symbol == null) {
+			throw new InvalidParameterException("symbol must not be null");
+		}
+		double result = 0.0d;
+
+		List<Event<?>> contextCopy;
+		if (context.size() >= trieOrder) {
+			contextCopy = new LinkedList<Event<?>>(context.subList(
+					context.size() - trieOrder + 1, context.size()));
+		} else {
+			contextCopy = new LinkedList<Event<?>>(context);
+		}
+
+		Collection<Event<?>> followers = trie.getFollowingSymbols(contextCopy);
+		int sumCountFollowers = 0; // N(s\sigma')
+		for (Event<?> follower : followers) {
+			sumCountFollowers += trie.getCount(contextCopy, follower);
+		}
+
+		int countSymbol = trie.getCount(contextCopy, symbol);
+		if (sumCountFollowers != 0) {
+			result = ((double) countSymbol / sumCountFollowers);
+		}
+
+		return result;
+	}
+
+}
Index: /trunk/quest-core-events/src/main/java/de/ugoe/cs/quest/usageprofiles/IDotCompatible.java
===================================================================
--- /trunk/quest-core-events/src/main/java/de/ugoe/cs/quest/usageprofiles/IDotCompatible.java	(revision 480)
+++ /trunk/quest-core-events/src/main/java/de/ugoe/cs/quest/usageprofiles/IDotCompatible.java	(revision 480)
@@ -0,0 +1,22 @@
+package de.ugoe.cs.quest.usageprofiles;
+
+/**
+ * <p>
+ * Models implementing this interface provide a graph representation of
+ * themselves as a {@link String} with Dot syntax.
+ * </p>
+ * 
+ * @author Steffen Herbold
+ * @version 1.0
+ */
+public interface IDotCompatible {
+
+	/**
+	 * <p>
+	 * Returns a Dot representation of the model.
+	 * </p>
+	 * 
+	 * @return string with Dot syntax that describes the model.
+	 */
+	public abstract String getDotRepresentation();
+}
Index: /trunk/quest-core-events/src/main/java/de/ugoe/cs/quest/usageprofiles/IMemory.java
===================================================================
--- /trunk/quest-core-events/src/main/java/de/ugoe/cs/quest/usageprofiles/IMemory.java	(revision 480)
+++ /trunk/quest-core-events/src/main/java/de/ugoe/cs/quest/usageprofiles/IMemory.java	(revision 480)
@@ -0,0 +1,40 @@
+package de.ugoe.cs.quest.usageprofiles;
+
+import java.util.List;
+
+/**
+ * <p>
+ * This interface defines basic functions for classes that implement a memory
+ * about the recent events of a sequences.
+ * </p>
+ * 
+ * @author Steffen Herbold
+ * @version 1.0
+ * 
+ * @param <T>
+ *            Type of the sequence elements that are memorized.
+ */
+public interface IMemory<T> {
+
+	/**
+	 * Adds an element to the end of the memory.
+	 * 
+	 * @param element
+	 *            Element to be added.
+	 */
+	public void add(T element);
+
+	/**
+	 * <p>
+	 * Returns the last <code>num</code> memorized elements. If the history is
+	 * shorter than <code>num</code>, the length of the returned
+	 * {@link java.util.List} may be less than <code>num</code>.
+	 * </p>
+	 * 
+	 * @param num
+	 *            Number of states from the end of the memory to be returned.
+	 * @return {@link java.util.List} of memorized elements.
+	 */
+	public List<T> getLast(int num);
+
+}
Index: /trunk/quest-core-events/src/main/java/de/ugoe/cs/quest/usageprofiles/IStochasticProcess.java
===================================================================
--- /trunk/quest-core-events/src/main/java/de/ugoe/cs/quest/usageprofiles/IStochasticProcess.java	(revision 480)
+++ /trunk/quest-core-events/src/main/java/de/ugoe/cs/quest/usageprofiles/IStochasticProcess.java	(revision 480)
@@ -0,0 +1,194 @@
+package de.ugoe.cs.quest.usageprofiles;
+
+import java.io.Serializable;
+import java.security.InvalidParameterException;
+import java.util.Collection;
+import java.util.List;
+
+import de.ugoe.cs.quest.eventcore.Event;
+
+/**
+ * <p>
+ * This interface defines the functionalities provided by stochastic processes.
+ * </p>
+ * 
+ * @author Steffen Herbold
+ * @version 1.0
+ */
+public interface IStochasticProcess extends Serializable {
+
+	/**
+	 * <p>
+	 * Returns the probability, that the next event is {@code symbol} given the
+	 * last events are {@code context}. The last element of {@code context} is
+	 * the most recent in the history, the first element is the oldest.
+	 * </p>
+	 * 
+	 * @param context
+	 *            recently observed symbols
+	 * @param symbol
+	 *            event for which the probability is calculated
+	 * @return probabilty the {@code symbol} is the next event, given the last
+	 *         events {@code context}
+	 * @throws InvalidParameterException
+	 *             thrown if context or symbol is null
+	 */
+	double getProbability(List<? extends Event<?>> context, Event<?> symbol);
+
+	/**
+	 * <p>
+	 * Returns the probabilitiy that a given sequence is generated by the
+	 * stochastic process.
+	 * </p>
+	 * 
+	 * @param sequence
+	 *            sequences of which the probability is calculated
+	 * @return probability of the sequences; 1.0 if sequence is empty or null
+	 * @throws InvalidParameterException
+	 *             thrown if sequence is null
+	 */
+	double getProbability(List<? extends Event<?>> sequence);
+
+	/**
+	 * <p>
+	 * Generates a random sequence of events. The sequence starts with
+	 * {@link Event#STARTEVENT} and finishes with {@link Event#ENDEVENT}.
+	 * </p>
+	 * 
+	 * @return randomly generated sequence
+	 */
+	public List<? extends Event<?>> randomSequence();
+
+	/**
+	 * <p>
+	 * Generates a random sequence of events. The sequence starts with
+	 * {@link Event#STARTEVENT} and finishes with
+	 * <ul>
+	 * <li>{@link Event#ENDEVENT} if validEnd==true.</li>
+	 * <li>b) if a generated sequences reaches {@link Event#ENDEVENT} before
+	 * maxLength, the sequence finishes and is shorter than maxLenght.
+	 * Otherwise, the sequence finishes as soon as maxLength is reached and the
+	 * final event of the sequence must not be {@link Event#ENDEVENT}.</li>
+	 * </ul>
+	 * </p>
+	 * 
+	 * @param maxLength
+	 *            maximum length of the generated sequence
+	 * @param validEnd
+	 *            if true, only sequences that finish with
+	 *            {@link Event#ENDEVENT} are generated
+	 * @return randomly generated sequence
+	 * 
+	 */
+	public List<? extends Event<?>> randomSequence(int maxLength,
+			boolean validEnd);
+
+	/**
+	 * <p>
+	 * Generates all sequences of a given length are possible, i.e., have a
+	 * positive probability.<br>
+	 * All states are used as possible starting states.
+	 * </p>
+	 * 
+	 * @param length
+	 *            length of the generated sequences
+	 * @return generated sequences
+	 * @see #generateSequences(int, boolean)
+	 * @throws InvalidParameterException
+	 *             thrown if length is less than or equal to 0
+	 */
+	public Collection<List<? extends Event<?>>> generateSequences(int length);
+
+	/**
+	 * <p>
+	 * Generates all sequences of given length that can are possible, i.e., have
+	 * positive probability.<br>
+	 * If {@code fromStart==true}, all generated sequences start in
+	 * {@link Event#STARTEVENT}. Otherwise this method is the same as
+	 * {@link #generateSequences(int)}.
+	 * </p>
+	 * 
+	 * @param length
+	 *            length of the generated sequences
+	 * @param fromStart
+	 *            if true, all generated sequences start with
+	 *            {@link Event#STARTEVENT}
+	 * @return generated sequences
+	 * @throws InvalidParameterException
+	 *             thrown if length is less than or equal to 0
+	 */
+	public Collection<List<? extends Event<?>>> generateSequences(int length,
+			boolean fromStart);
+
+	/**
+	 * <p>
+	 * Generates all sequences starting with {@link Event#STARTEVENT} and
+	 * finishing with {@link Event#ENDEVENT} of a given length. It is possible
+	 * that no such sequence exists with the defined length and the returned set
+	 * is empty. If {@code length} is less than 2 the returned set is always
+	 * empty.
+	 * </p>
+	 * 
+	 * @param length
+	 * @return generated sequences
+	 * @throws InvalidParameterException
+	 *             thrown if length is less than or equal to 0
+	 */
+	public Collection<List<? extends Event<?>>> generateValidSequences(
+			int length);
+
+	/**
+	 * <p>
+	 * Returns the number of states known by the stochastic process, i.e., the
+	 * size of its alphabet.
+	 * </p>
+	 * 
+	 * @return number of states
+	 */
+	public int getNumSymbols();
+
+	/**
+	 * <p>
+	 * Returns a string representation of all known states.
+	 * </p>
+	 * 
+	 * @return string representation for all known states
+	 */
+	public String[] getSymbolStrings();
+
+	/**
+	 * <p>
+	 * Returns the number of states the process would have if it would be
+	 * flattened through state-splitting to a first-order Markov model.
+	 * </p>
+	 * <p>
+	 * If it is not possible to flatten the model, -1 is returned.
+	 * </p>
+	 * 
+	 * @return number of states an equivalent FOM would have; -1 if not
+	 *         available
+	 */
+	public int getNumFOMStates();
+
+	/**
+	 * <p>
+	 * Returns the number of transitions the process would have if it would be
+	 * flattened through state-splitting to a first-order Markov model.
+	 * </p>
+	 * 
+	 * @return number of transitions an equivalent FOM would have; -1 if not
+	 *         available
+	 */
+	public int getNumTransitions();
+
+	/**
+	 * <p>
+	 * Returns all states known by the stochastic process, i.e., its
+	 * {@link Event}s.
+	 * </p>
+	 * 
+	 * @return events known by the process
+	 */
+	public Collection<? extends Event<?>> getEvents();
+
+}
Index: /trunk/quest-core-events/src/main/java/de/ugoe/cs/quest/usageprofiles/IncompleteMemory.java
===================================================================
--- /trunk/quest-core-events/src/main/java/de/ugoe/cs/quest/usageprofiles/IncompleteMemory.java	(revision 480)
+++ /trunk/quest-core-events/src/main/java/de/ugoe/cs/quest/usageprofiles/IncompleteMemory.java	(revision 480)
@@ -0,0 +1,95 @@
+package de.ugoe.cs.quest.usageprofiles;
+
+import java.security.InvalidParameterException;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * <p>
+ * Implements a round-trip buffered memory of a specified length that can be
+ * used to remember the recent history. Every event that happend longer ago than
+ * the length of the memory is forgotten, hence the memory is incomplete.
+ * </p>
+ * 
+ * @author Steffen Herbold
+ * @version 1.0
+ * 
+ * @param <T>
+ *            Type which is memorized.
+ */
+public class IncompleteMemory<T> implements IMemory<T> {
+
+	/**
+	 * <p>
+	 * Maximum length of the memory.
+	 * </p>
+	 */
+	private int length;
+
+	/**
+	 * <p>
+	 * Internal storage of the history.
+	 * </p>
+	 */
+	private List<T> history;
+
+	/**
+	 * <p>
+	 * Constructor. Creates a new IncompleteMemory.
+	 * </p>
+	 * 
+	 * @param length
+	 *            number of recent events that are remembered
+	 * @throws InvalidParameterException
+	 *             This exception is thrown if the length is smaller than 1
+	 */
+	public IncompleteMemory(int length) {
+		if (length < 1) {
+			throw new InvalidParameterException(
+					"Length of IncompleteMemory must be at least 1.");
+		}
+		this.length = length;
+		history = new LinkedList<T>();
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see de.ugoe.cs.quest.usageprofiles.IMemory#add(java.lang.Object)
+	 */
+	@Override
+	public void add(T state) {
+		if (history.size() == length) {
+			history.remove(0);
+		}
+		history.add(state);
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see de.ugoe.cs.quest.usageprofiles.IMemory#getLast(int)
+	 */
+	@Override
+	public List<T> getLast(int num) {
+		if( num<1 ) {
+			return new LinkedList<T>();
+		} else {
+		return new LinkedList<T>(history.subList(
+				Math.max(0, history.size() - num),
+				history.size())); // defensive copy
+		}
+	}
+
+	/**
+	 * <p>
+	 * Returns the current length of the memory. This can be less than
+	 * {@link #length}, if the overall history is less than {@link #length}.
+	 * </p>
+	 * 
+	 * @return length of the current memory
+	 */
+	public int getLength() {
+		return history.size();
+	}
+}
Index: /trunk/quest-core-events/src/main/java/de/ugoe/cs/quest/usageprofiles/ModelFlattener.java
===================================================================
--- /trunk/quest-core-events/src/main/java/de/ugoe/cs/quest/usageprofiles/ModelFlattener.java	(revision 480)
+++ /trunk/quest-core-events/src/main/java/de/ugoe/cs/quest/usageprofiles/ModelFlattener.java	(revision 480)
@@ -0,0 +1,137 @@
+package de.ugoe.cs.quest.usageprofiles;
+
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Random;
+
+import de.ugoe.cs.quest.eventcore.Event;
+import de.ugoe.cs.quest.eventcore.ReplayableEvent;
+
+/**
+ * <p>
+ * This class provides functions to create flattened first-order Markov models
+ * from {@link HighOrderMarkovModel}s and {@link PredictionByPartialMatch}
+ * models through state splitting.
+ * </p>
+ * <p>
+ * If possible, the normal high-order markov model should be used, as the Events
+ * may be broken by the flattener, as, e.g., the information
+ * {@link ReplayableEvent}s contain is not preserved.
+ * </p>
+ * 
+ * @author Steffen Herbold
+ * @version 1.0
+ */
+public class ModelFlattener {
+
+	private static final String EVENT_SEPARATOR = "-=-";
+
+	Trie<Event<?>> firstOrderTrie;
+
+	/**
+	 * <p>
+	 * Takes a {@link HighOrderMarkovModel} and returns a
+	 * {@link FirstOrderMarkovModel} that conserves the high-order memory
+	 * through state splitting.
+	 * </p>
+	 * 
+	 * @param model
+	 *            model that is flattened
+	 * @return flattened first-order Markov model
+	 */
+	public FirstOrderMarkovModel flattenHighOrderMarkovModel(
+			HighOrderMarkovModel model) {
+		int markovOrder = model.trieOrder - 1;
+		FirstOrderMarkovModel firstOrderModel = new FirstOrderMarkovModel(
+				new Random());
+		firstOrderModel.trieOrder = 2;
+		if (markovOrder == 1) {
+			firstOrderModel.trie = new Trie<Event<?>>(model.trie);
+			firstOrderModel.trieOrder = 2;
+		} else {
+			firstOrderTrie = new Trie<Event<?>>();
+			TrieNode<Event<?>> rootNode = model.trie.find(null);
+			generateFirstOrderTrie(rootNode, new LinkedList<String>(), markovOrder);
+			firstOrderTrie.updateKnownSymbols();
+			firstOrderModel.trie = firstOrderTrie;
+		}
+
+		return firstOrderModel;
+	}
+
+	/**
+	 * <p>
+	 * <b>This method is not available yet and always return null!</b>
+	 * </p>
+	 * <p>
+	 * Takes a {@link PredictionByPartialMatch} model and returns a
+	 * {@link FirstOrderMarkovModel} that conserves the high-order memory
+	 * through state splitting.
+	 * </p>
+	 * 
+	 * @param model
+	 *            model that is flattened
+	 * @return flattened first-order Markov model
+	 */
+	public FirstOrderMarkovModel flattenPredictionByPartialMatch(
+			PredictionByPartialMatch model) {
+		// TODO implement method
+		return null;
+	}
+
+	/**
+	 * <p>
+	 * Converts all nodes of the given depth into first-order node through
+	 * state-splitting. For each node at the given depth a new node is created
+	 * and appropriate transitions will be added.
+	 * </p>
+	 * <p>
+	 * This method traverses through the tree recursively. If the recursion
+	 * reaches the desired depth in the tree, node are added.
+	 * </p>
+	 * 
+	 * @param currentNode
+	 *            node whose sub-trie is currently traversed
+	 * @param parentIDs
+	 *            ID strings of the ancestors of the currentNode
+	 * @param depth
+	 *            depth to go - NOT the current depth.
+	 */
+	private void generateFirstOrderTrie(TrieNode<Event<?>> currentNode,
+			List<String> parentIDs, int depth) {
+		for (TrieNode<Event<?>> child : currentNode.getChildren()) {
+			String currentId = child.getSymbol().getStandardId();
+			if (depth > 1) {
+				List<String> childParentIDs = new LinkedList<String>(parentIDs);
+				childParentIDs.add(currentId);
+				generateFirstOrderTrie(child, childParentIDs, depth - 1);
+
+			} else {
+				StringBuilder firstOrderID = new StringBuilder();
+				for (String parentID : parentIDs) {
+					firstOrderID.append(parentID + EVENT_SEPARATOR);
+				}
+				firstOrderID.append(currentId);
+				TrieNode<Event<?>> firstOrderNode = firstOrderTrie
+						.getChildCreate(new Event<Object>(firstOrderID
+								.toString()));
+				firstOrderNode.setCount(child.getCount());
+				for (TrieNode<Event<?>> transitionChild : child.getChildren()) {
+					StringBuilder transitionID = new StringBuilder();
+					for (String parentID : parentIDs.subList(1,
+							parentIDs.size())) {
+						transitionID.append(parentID + EVENT_SEPARATOR);
+					}
+					transitionID.append(currentId + EVENT_SEPARATOR);
+					transitionID.append(transitionChild.getSymbol()
+							.getStandardId());
+					TrieNode<Event<?>> firstOrderTransitionChild = firstOrderNode
+							.getChildCreate(new Event<Object>(transitionID
+									.toString()));
+					firstOrderTransitionChild.setCount(transitionChild
+							.getCount());
+				}
+			}
+		}
+	}
+}
Index: /trunk/quest-core-events/src/main/java/de/ugoe/cs/quest/usageprofiles/PredictionByPartialMatch.java
===================================================================
--- /trunk/quest-core-events/src/main/java/de/ugoe/cs/quest/usageprofiles/PredictionByPartialMatch.java	(revision 480)
+++ /trunk/quest-core-events/src/main/java/de/ugoe/cs/quest/usageprofiles/PredictionByPartialMatch.java	(revision 480)
@@ -0,0 +1,200 @@
+package de.ugoe.cs.quest.usageprofiles;
+
+import java.security.InvalidParameterException;
+import java.util.Collection;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Random;
+
+import de.ugoe.cs.quest.eventcore.Event;
+
+/**
+ * <p>
+ * Implements Prediction by Partial Match (PPM) based on the following formula
+ * (LaTeX-style notation):<br>
+ * P_{PPM}(X_n|X_{n-1},...,X_{n-k}) = \sum_{i=k}^min escape^{k-i} P_{MM^i}(X_n
+ * |X_{n-1},...,X_{n-i})(1-escape)+escape^(k-min)P(X_n|X_{n-i},... ,X_{n-min})<br>
+ * P_{MM^i} denotes the probability in an i-th order Markov model.
+ * </p>
+ * 
+ * @author Steffen Herbold
+ * 
+ */
+public class PredictionByPartialMatch extends TrieBasedModel {
+
+	/**
+	 * <p>
+	 * Id for object serialization.
+	 * </p>
+	 */
+	private static final long serialVersionUID = 1L;
+
+	/**
+	 * <p>
+	 * Minimum order of the Markov model.
+	 * </p>
+	 */
+	protected int minOrder;
+
+	/**
+	 * <p>
+	 * Probability to use a lower-order Markov model
+	 * </p>
+	 */
+	protected double probEscape;
+
+	/**
+	 * <p>
+	 * Constructor. Creates a new PredictionByPartialMatch model with a given
+	 * Markov order and a default escape probability of 0.1.
+	 * </p>
+	 * 
+	 * @param markovOrder
+	 *            Markov order of the model
+	 * @param r
+	 *            random number generator used by probabilistic methods of the
+	 *            class
+	 */
+	public PredictionByPartialMatch(int markovOrder, Random r) {
+		this(markovOrder, r, 0.1);
+	}
+
+	/**
+	 * <p>
+	 * Creates a new PredictionByPartialMatch model with a given Markov order
+	 * and escape probability.
+	 * </p>
+	 * 
+	 * @param markovOrder
+	 *            Markov order of the model
+	 * @param r
+	 *            random number generator used by probabilistic methods of the
+	 *            class
+	 * @param probEscape
+	 *            escape probability used by the model
+	 */
+	public PredictionByPartialMatch(int markovOrder, Random r, double probEscape) {
+		this(markovOrder, 0, r, probEscape);
+	}
+
+	/**
+	 * <p>
+	 * Creates a new PredictionByPartialMatch model with a given Markov order
+	 * and escape probability.
+	 * </p>
+	 * 
+	 * @param markovOrder
+	 *            Markov order of the model
+	 * @param minOrder
+	 *            minimum order of the model; if this order is reached, there is
+	 *            no escape
+	 * @param r
+	 *            random number generator used by probabilistic methods of the
+	 *            class
+	 * @param probEscape
+	 *            escape probability used by the model
+	 * @throws InvalidParameterException thrown if minOrder is less than 0 or greater than markovOrder or probEscape is not in the interval (0,1)
+	 */
+	public PredictionByPartialMatch(int markovOrder, int minOrder, Random r,
+			double probEscape) {
+		super(markovOrder, r);
+		if( minOrder< 0 ) {
+			throw new InvalidParameterException("minOrder must be greather than or equal to 0");
+		}
+		if( minOrder>markovOrder) {
+			throw new InvalidParameterException("minOrder must be less than or equal to markovOrder");
+		}
+		if( probEscape<=0.0 || probEscape>=1.0) {
+			throw new InvalidParameterException("probEscape must be in the interval (0,1)");
+		}
+		this.probEscape = probEscape;
+		this.minOrder = minOrder;
+	}
+
+	/**
+	 * <p>
+	 * Sets the escape probability of the model.
+	 * </p>
+	 * 
+	 * @param probEscape
+	 *            new escape probability
+	 */
+	public void setProbEscape(double probEscape) {
+		this.probEscape = probEscape;
+	}
+
+	/**
+	 * <p>
+	 * Returns the escape probability of the model.
+	 * </p>
+	 * 
+	 * @return escape probability of the model
+	 */
+	public double getProbEscape() {
+		return probEscape;
+	}
+
+	/**
+	 * <p>
+	 * Calculates the probability of the next event based on the formula:<br>
+	 * P_{PPM}(X_n|X_{n-1},...,X_{n-k}) = \sum_{i=k}^min escape^{k-i}
+	 * P_{MM^i}(X_n
+	 * |X_{n-1},...,X_{n-i})(1-escape)+escape^(k-min)P(X_n|X_{n-i},...
+	 * ,X_{n-min})<br>
+	 * P_{MM^i} denotes the probability in an i-th order Markov model.
+	 * </p>
+	 * 
+	 * @see de.ugoe.cs.quest.usageprofiles.IStochasticProcess#getProbability(java.util.List,
+	 *      de.ugoe.cs.quest.eventcore.Event)
+	 */
+	@Override
+	public double getProbability(List<? extends Event<?>> context,
+			Event<?> symbol) {
+		if (context == null) {
+			throw new InvalidParameterException("context must not be null");
+		}
+		if (symbol == null) {
+			throw new InvalidParameterException("symbol must not be null");
+		}
+		double result = 0.0d;
+		double resultCurrentContex = 0.0d;
+		double resultShorterContex = 0.0d;
+
+		List<Event<?>> contextCopy;
+		if (context.size() >= trieOrder) {
+			contextCopy = new LinkedList<Event<?>>(context.subList(
+					context.size() - trieOrder + 1, context.size()));
+		} else {
+			contextCopy = new LinkedList<Event<?>>(context);
+		}
+
+		Collection<Event<?>> followers = trie.getFollowingSymbols(contextCopy); // \Sigma'
+		int sumCountFollowers = 0; // N(s\sigma')
+		for (Event<?> follower : followers) {
+			sumCountFollowers += trie.getCount(contextCopy, follower);
+		}
+
+		int countSymbol = trie.getCount(contextCopy, symbol); // N(s\sigma)
+		if (sumCountFollowers == 0) {
+			resultCurrentContex = 0.0;
+		} else {
+			resultCurrentContex = (double) countSymbol / sumCountFollowers;
+		}
+		if (contextCopy.size() > minOrder) {
+			resultCurrentContex *= (1 - probEscape);
+			contextCopy.remove(0);
+			if (contextCopy.size() >= minOrder) {
+				double probSuffix = getProbability(contextCopy, symbol);
+
+				if (followers.size() == 0) {
+					resultShorterContex = probSuffix;
+				} else {
+					resultShorterContex = probEscape * probSuffix;
+				}
+			}
+		}
+		result = resultCurrentContex + resultShorterContex;
+
+		return result;
+	}
+}
Index: /trunk/quest-core-events/src/main/java/de/ugoe/cs/quest/usageprofiles/Trie.java
===================================================================
--- /trunk/quest-core-events/src/main/java/de/ugoe/cs/quest/usageprofiles/Trie.java	(revision 480)
+++ /trunk/quest-core-events/src/main/java/de/ugoe/cs/quest/usageprofiles/Trie.java	(revision 480)
@@ -0,0 +1,472 @@
+package de.ugoe.cs.quest.usageprofiles;
+
+import java.io.Serializable;
+import java.security.InvalidParameterException;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.LinkedList;
+import java.util.List;
+
+import de.ugoe.cs.util.StringTools;
+
+import edu.uci.ics.jung.graph.DelegateTree;
+import edu.uci.ics.jung.graph.Graph;
+import edu.uci.ics.jung.graph.Tree;
+
+/**
+ * <p>
+ * This class implements a <it>trie</it>, i.e., a tree of sequences that the
+ * occurence of subsequences up to a predefined length. This length is the trie
+ * order.
+ * </p>
+ * 
+ * @author Steffen Herbold
+ * 
+ * @param <T>
+ *            Type of the symbols that are stored in the trie.
+ * 
+ * @see TrieNode
+ */
+public class Trie<T> implements IDotCompatible, Serializable {
+
+	/**
+	 * <p>
+	 * Id for object serialization.
+	 * </p>
+	 */
+	private static final long serialVersionUID = 1L;
+
+	/**
+	 * <p>
+	 * Collection of all symbols occuring in the trie.
+	 * </p>
+	 */
+	private Collection<T> knownSymbols;
+
+	/**
+	 * <p>
+	 * Reference to the root of the trie.
+	 * </p>
+	 */
+	private final TrieNode<T> rootNode;
+
+	/**
+	 * <p>
+	 * Contructor. Creates a new Trie.
+	 * </p>
+	 */
+	public Trie() {
+		rootNode = new TrieNode<T>();
+		knownSymbols = new LinkedHashSet<T>();
+	}
+
+	/**
+	 * <p>
+	 * Copy-Constructor. Creates a new Trie as the copy of other. The other trie
+	 * must noch be null.
+	 * </p>
+	 * 
+	 * @param other
+	 *            Trie that is copied
+	 */
+	public Trie(Trie<T> other) {
+		if (other == null) {
+			throw new InvalidParameterException("other trie must not be null");
+		}
+		rootNode = new TrieNode<T>(other.rootNode);
+		knownSymbols = new LinkedHashSet<T>(other.knownSymbols);
+	}
+
+	/**
+	 * <p>
+	 * Returns a collection of all symbols occuring in the trie.
+	 * </p>
+	 * 
+	 * @return symbols occuring in the trie
+	 */
+	public Collection<T> getKnownSymbols() {
+		return new LinkedHashSet<T>(knownSymbols);
+	}
+
+	/**
+	 * <p>
+	 * Trains the current trie using the given sequence and adds all subsequence
+	 * of length {@code maxOrder}.
+	 * </p>
+	 * 
+	 * @param sequence
+	 *            sequence whose subsequences are added to the trie
+	 * @param maxOrder
+	 *            maximum length of the subsequences added to the trie
+	 */
+	public void train(List<T> sequence, int maxOrder) {
+		if (maxOrder < 1) {
+			return;
+		}
+		IncompleteMemory<T> latestActions = new IncompleteMemory<T>(maxOrder);
+		int i = 0;
+		for (T currentEvent : sequence) {
+			latestActions.add(currentEvent);
+			knownSymbols.add(currentEvent);
+			i++;
+			if (i >= maxOrder) {
+				add(latestActions.getLast(maxOrder));
+			}
+		}
+		int sequenceLength = sequence.size();
+		for (int j = maxOrder - 1; j > 0; j--) {
+			add(sequence.subList(sequenceLength - j, sequenceLength));
+		}
+	}
+
+	/**
+	 * <p>
+	 * Adds a given subsequence to the trie and increases the counters
+	 * accordingly.
+	 * </p>
+	 * 
+	 * @param subsequence
+	 *            subsequence whose counters are increased
+	 * @see TrieNode#add(List)
+	 */
+	protected void add(List<T> subsequence) {
+		if (subsequence != null && !subsequence.isEmpty()) {
+			knownSymbols.addAll(subsequence);
+			subsequence = new LinkedList<T>(subsequence); // defensive copy!
+			T firstSymbol = subsequence.get(0);
+			TrieNode<T> node = getChildCreate(firstSymbol);
+			node.add(subsequence);
+		}
+	}
+
+	/**
+	 * <p>
+	 * Returns the child of the root node associated with the given symbol or
+	 * creates it if it does not exist yet.
+	 * </p>
+	 * 
+	 * @param symbol
+	 *            symbol whose node is required
+	 * @return node associated with the symbol
+	 * @see TrieNode#getChildCreate(Object)
+	 */
+	protected TrieNode<T> getChildCreate(T symbol) {
+		return rootNode.getChildCreate(symbol);
+	}
+
+	/**
+	 * <p>
+	 * Returns the child of the root node associated with the given symbol or
+	 * null if it does not exist.
+	 * </p>
+	 * 
+	 * @param symbol
+	 *            symbol whose node is required
+	 * @return node associated with the symbol; null if no such node exists
+	 * @see TrieNode#getChild(Object)
+	 */
+	protected TrieNode<T> getChild(T symbol) {
+		return rootNode.getChild(symbol);
+	}
+
+	/**
+	 * <p>
+	 * Returns the number of occurences of the given sequence.
+	 * </p>
+	 * 
+	 * @param sequence
+	 *            sequence whose number of occurences is required
+	 * @return number of occurences of the sequence
+	 */
+	public int getCount(List<T> sequence) {
+		int count = 0;
+		TrieNode<T> node = find(sequence);
+		if (node != null) {
+			count = node.getCount();
+		}
+		return count;
+	}
+
+	/**
+	 * <p>
+	 * Returns the number of occurences of the given prefix and a symbol that
+	 * follows it.<br>
+	 * Convenience function to simplify usage of {@link #getCount(List)}.
+	 * </p>
+	 * 
+	 * @param sequence
+	 *            prefix of the sequence
+	 * @param follower
+	 *            suffix of the sequence
+	 * @return number of occurences of the sequence
+	 * @see #getCount(List)
+	 */
+	public int getCount(List<T> sequence, T follower) {
+		List<T> tmpSequence = new LinkedList<T>(sequence);
+		tmpSequence.add(follower);
+		return getCount(tmpSequence);
+
+	}
+
+	/**
+	 * <p>
+	 * Searches the trie for a given sequence and returns the node associated
+	 * with the sequence or null if no such node is found.
+	 * </p>
+	 * 
+	 * @param sequence
+	 *            sequence that is searched for
+	 * @return node associated with the sequence
+	 * @see TrieNode#find(List)
+	 */
+	public TrieNode<T> find(List<T> sequence) {
+		if (sequence == null || sequence.isEmpty()) {
+			return rootNode;
+		}
+		List<T> sequenceCopy = new LinkedList<T>(sequence);
+		TrieNode<T> result = null;
+		TrieNode<T> node = getChild(sequenceCopy.get(0));
+		if (node != null) {
+			sequenceCopy.remove(0);
+			result = node.find(sequenceCopy);
+		}
+		return result;
+	}
+
+	/**
+	 * <p>
+	 * Returns a collection of all symbols that follow a given sequence in the
+	 * trie. In case the sequence is not found or no symbols follow the sequence
+	 * the result will be empty.
+	 * </p>
+	 * 
+	 * @param sequence
+	 *            sequence whose followers are returned
+	 * @return symbols following the given sequence
+	 * @see TrieNode#getFollowingSymbols()
+	 */
+	public Collection<T> getFollowingSymbols(List<T> sequence) {
+		Collection<T> result = new LinkedList<T>();
+		TrieNode<T> node = find(sequence);
+		if (node != null) {
+			result = node.getFollowingSymbols();
+		}
+		return result;
+	}
+
+	/**
+	 * <p>
+	 * Returns the longest suffix of the given context that is contained in the
+	 * tree and whose children are leaves.
+	 * </p>
+	 * 
+	 * @param context
+	 *            context whose suffix is searched for
+	 * @return longest suffix of the context
+	 */
+	public List<T> getContextSuffix(List<T> context) {
+		List<T> contextSuffix;
+		if (context != null) {
+			contextSuffix = new LinkedList<T>(context); // defensive copy
+		} else {
+			contextSuffix = new LinkedList<T>();
+		}
+		boolean suffixFound = false;
+
+		while (!suffixFound) {
+			if (contextSuffix.isEmpty()) {
+				suffixFound = true; // suffix is the empty word
+			} else {
+				TrieNode<T> node = find(contextSuffix);
+				if (node != null) {
+					if (!node.getFollowingSymbols().isEmpty()) {
+						suffixFound = true;
+					}
+				}
+				if (!suffixFound) {
+					contextSuffix.remove(0);
+				}
+			}
+		}
+
+		return contextSuffix;
+	}
+
+	/**
+	 * <p>
+	 * Helper class for graph visualization of a trie.
+	 * </p>
+	 * 
+	 * @author Steffen Herbold
+	 * @version 1.0
+	 */
+	static public class Edge {
+	}
+
+	/**
+	 * <p>
+	 * Helper class for graph visualization of a trie.
+	 * </p>
+	 * 
+	 * @author Steffen Herbold
+	 * @version 1.0
+	 */
+	static public class TrieVertex {
+
+		/**
+		 * <p>
+		 * Id of the vertex.
+		 * </p>
+		 */
+		private String id;
+
+		/**
+		 * <p>
+		 * Contructor. Creates a new TrieVertex.
+		 * </p>
+		 * 
+		 * @param id
+		 *            id of the vertex
+		 */
+		protected TrieVertex(String id) {
+			this.id = id;
+		}
+
+		/**
+		 * <p>
+		 * Returns the id of the vertex.
+		 * </p>
+		 * 
+		 * @see java.lang.Object#toString()
+		 */
+		@Override
+		public String toString() {
+			return id;
+		}
+	}
+
+	/**
+	 * <p>
+	 * Returns a {@link Graph} representation of the trie.
+	 * </p>
+	 * 
+	 * @return {@link Graph} representation of the trie
+	 */
+	protected Tree<TrieVertex, Edge> getGraph() {
+		DelegateTree<TrieVertex, Edge> graph = new DelegateTree<TrieVertex, Edge>();
+		rootNode.getGraph(null, graph);
+		return graph;
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see de.ugoe.cs.quest.usageprofiles.IDotCompatible#getDotRepresentation()
+	 */
+	public String getDotRepresentation() {
+		StringBuilder stringBuilder = new StringBuilder();
+		stringBuilder.append("digraph model {" + StringTools.ENDLINE);
+		rootNode.appendDotRepresentation(stringBuilder);
+		stringBuilder.append('}' + StringTools.ENDLINE);
+		return stringBuilder.toString();
+	}
+
+	/**
+	 * <p>
+	 * Returns the string representation of the root node.
+	 * </p>
+	 * 
+	 * @see TrieNode#toString()
+	 * @see java.lang.Object#toString()
+	 */
+	@Override
+	public String toString() {
+		return rootNode.toString();
+	}
+
+	/**
+	 * <p>
+	 * Returns the number of symbols contained in the trie.
+	 * </p>
+	 * 
+	 * @return number of symbols contained in the trie
+	 */
+	public int getNumSymbols() {
+		return knownSymbols.size();
+	}
+
+	/**
+	 * <p>
+	 * Returns the number of trie nodes that are ancestors of a leaf. This is
+	 * the equivalent to the number of states a first-order markov model would
+	 * have.
+	 * <p>
+	 * 
+	 * @return number of trie nodes that are ancestors of leafs.
+	 */
+	public int getNumLeafAncestors() {
+		List<TrieNode<T>> ancestors = new LinkedList<TrieNode<T>>();
+		rootNode.getLeafAncestors(ancestors);
+		return ancestors.size();
+	}
+
+	/**
+	 * <p>
+	 * Returns the number of trie nodes that are leafs.
+	 * </p>
+	 * 
+	 * @return number of leafs in the trie
+	 */
+	public int getNumLeafs() {
+		return rootNode.getNumLeafs();
+	}
+
+	/**
+	 * <p>
+	 * Updates the list of known symbols by replacing it with all symbols that
+	 * are found in the child nodes of the root node. This should be the same as
+	 * all symbols that are contained in the trie.
+	 * </p>
+	 */
+	public void updateKnownSymbols() {
+		knownSymbols = new HashSet<T>();
+		for (TrieNode<T> node : rootNode.getChildren()) {
+			knownSymbols.add(node.getSymbol());
+		}
+	}
+
+	/**
+	 * <p>
+	 * Two Tries are defined as equal, if their {@link #rootNode} are equal.
+	 * </p>
+	 * 
+	 * @see java.lang.Object#equals(java.lang.Object)
+	 */
+	@SuppressWarnings("rawtypes")
+	@Override
+	public boolean equals(Object other) {
+		if (other == this) {
+			return true;
+		}
+		if (other instanceof Trie) {
+			return rootNode.equals(((Trie) other).rootNode);
+		}
+		return false;
+	}
+	
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see java.lang.Object#hashCode()
+	 */
+	@Override
+	public int hashCode() {
+		int multiplier = 17;
+		int hash = 42;
+		if (rootNode != null) {
+			hash = multiplier * hash + rootNode.hashCode();
+		}
+		return hash;
+	}
+}
Index: /trunk/quest-core-events/src/main/java/de/ugoe/cs/quest/usageprofiles/TrieBasedModel.java
===================================================================
--- /trunk/quest-core-events/src/main/java/de/ugoe/cs/quest/usageprofiles/TrieBasedModel.java	(revision 480)
+++ /trunk/quest-core-events/src/main/java/de/ugoe/cs/quest/usageprofiles/TrieBasedModel.java	(revision 480)
@@ -0,0 +1,416 @@
+package de.ugoe.cs.quest.usageprofiles;
+
+import java.security.InvalidParameterException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Random;
+import java.util.Set;
+
+import de.ugoe.cs.quest.eventcore.Event;
+import de.ugoe.cs.quest.usageprofiles.Trie.Edge;
+import de.ugoe.cs.quest.usageprofiles.Trie.TrieVertex;
+import edu.uci.ics.jung.graph.Tree;
+
+/**
+ * <p>
+ * Implements a skeleton for stochastic processes that can calculate
+ * probabilities based on a trie. The skeleton provides all functionalities of
+ * {@link IStochasticProcess} except
+ * {@link IStochasticProcess#getProbability(List, Event)}.
+ * </p>
+ * 
+ * @author Steffen Herbold
+ * @version 1.0
+ */
+public abstract class TrieBasedModel implements IStochasticProcess {
+
+	/**
+	 * <p>
+	 * Id for object serialization.
+	 * </p>
+	 */
+	private static final long serialVersionUID = 1L;
+
+	/**
+	 * <p>
+	 * The order of the trie, i.e., the maximum length of subsequences stored in
+	 * the trie.
+	 * </p>
+	 */
+	protected int trieOrder;
+
+	/**
+	 * <p>
+	 * Trie on which the probability calculations are based.
+	 * </p>
+	 */
+	protected Trie<Event<?>> trie = null;
+
+	/**
+	 * <p>
+	 * Random number generator used by probabilistic sequence generation
+	 * methods.
+	 * </p>
+	 */
+	protected final Random r;
+
+	/**
+	 * <p>
+	 * Constructor. Creates a new TrieBasedModel that can be used for stochastic
+	 * processes with a Markov order less than or equal to {@code markovOrder}.
+	 * </p>
+	 * 
+	 * @param markovOrder
+	 *            Markov order of the model
+	 * @param r
+	 *            random number generator used by probabilistic methods of the
+	 *            class
+	 * @throws InvalidParameterException
+	 *             thrown if markovOrder is less than 0 or the random number
+	 *             generator r is null
+	 */
+	public TrieBasedModel(int markovOrder, Random r) {
+		super();
+		if (markovOrder < 0) {
+			throw new InvalidParameterException(
+					"markov order must not be less than 0");
+		}
+		if (r == null) {
+			throw new InvalidParameterException(
+					"random number generator r must not be null");
+		}
+		this.trieOrder = markovOrder + 1;
+		this.r = r;
+	}
+
+	/**
+	 * <p>
+	 * Trains the model by generating a trie from which probabilities are
+	 * calculated. The trie is newly generated based solely on the passed
+	 * sequences. If an existing model should only be updated, use
+	 * {@link #update(Collection)} instead.
+	 * </p>
+	 * 
+	 * @param sequences
+	 *            training data
+	 * @throws InvalidParameterException
+	 *             thrown is sequences is null
+	 */
+	public void train(Collection<List<? extends Event<?>>> sequences) {
+		trie = null;
+		update(sequences);
+	}
+
+	/**
+	 * <p>
+	 * Trains the model by updating the trie from which the probabilities are
+	 * calculated. This function updates an existing trie. In case no trie
+	 * exists yet, a new trie is generated and the function behaves like
+	 * {@link #train(Collection)}.
+	 * </p>
+	 * 
+	 * @param sequences
+	 *            training data
+	 * @throws InvalidParameterException
+	 *             thrown is sequences is null
+	 */
+	public void update(Collection<List<? extends Event<?>>> sequences) {
+		if (sequences == null) {
+			throw new InvalidParameterException("sequences must not be null");
+		}
+		if (trie == null) {
+			trie = new Trie<Event<?>>();
+		}
+		for (List<? extends Event<?>> sequence : sequences) {
+			List<Event<?>> currentSequence = new LinkedList<Event<?>>(sequence); // defensive
+																					// copy
+			currentSequence.add(0, Event.STARTEVENT);
+			currentSequence.add(Event.ENDEVENT);
+
+			trie.train(currentSequence, trieOrder);
+		}
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see de.ugoe.cs.quest.usageprofiles.IStochasticProcess#randomSequence()
+	 */
+	@Override
+	public List<? extends Event<?>> randomSequence() {
+		return randomSequence(Integer.MAX_VALUE, true);
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see de.ugoe.cs.quest.usageprofiles.IStochasticProcess#randomSequence()
+	 */
+	@Override
+	public List<? extends Event<?>> randomSequence(int maxLength,
+			boolean validEnd) {
+		List<Event<?>> sequence = new LinkedList<Event<?>>();
+		if (trie != null) {
+			boolean endFound = false;
+			while (!endFound) { // outer loop for length checking
+				sequence = new LinkedList<Event<?>>();
+				IncompleteMemory<Event<?>> context = new IncompleteMemory<Event<?>>(
+						trieOrder - 1);
+				context.add(Event.STARTEVENT);
+
+				while (!endFound && sequence.size() <= maxLength) {
+					double randVal = r.nextDouble();
+					double probSum = 0.0;
+					List<Event<?>> currentContext = context.getLast(trieOrder);
+					for (Event<?> symbol : trie.getKnownSymbols()) {
+						probSum += getProbability(currentContext, symbol);
+						if (probSum >= randVal) {
+							if (!(Event.STARTEVENT.equals(symbol) || Event.ENDEVENT
+									.equals(symbol))) {
+								// only add the symbol the sequence if it is not
+								// START or END
+								context.add(symbol);
+								sequence.add(symbol);
+							}
+							endFound = (Event.ENDEVENT.equals(symbol))
+									|| (!validEnd && sequence.size() == maxLength);
+							break;
+						}
+					}
+				}
+			}
+		}
+		return sequence;
+	}
+
+	/**
+	 * <p>
+	 * Returns a Dot representation of the internal trie.
+	 * </p>
+	 * 
+	 * @return dot representation of the internal trie
+	 */
+	public String getTrieDotRepresentation() {
+		if (trie == null) {
+			return "";
+		} else {
+			return trie.getDotRepresentation();
+		}
+	}
+
+	/**
+	 * <p>
+	 * Returns a {@link Tree} of the internal trie that can be used for
+	 * visualization.
+	 * </p>
+	 * 
+	 * @return {@link Tree} depicting the internal trie
+	 */
+	public Tree<TrieVertex, Edge> getTrieGraph() {
+		if (trie == null) {
+			return null;
+		} else {
+			return trie.getGraph();
+		}
+	}
+
+	/**
+	 * <p>
+	 * The string representation of the model is {@link Trie#toString()} of
+	 * {@link #trie}.
+	 * </p>
+	 * 
+	 * @see java.lang.Object#toString()
+	 */
+	@Override
+	public String toString() {
+		if (trie == null) {
+			return "";
+		} else {
+			return trie.toString();
+		}
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see de.ugoe.cs.quest.usageprofiles.IStochasticProcess#getNumStates()
+	 */
+	@Override
+	public int getNumSymbols() {
+		if (trie == null) {
+			return 0;
+		} else {
+			return trie.getNumSymbols();
+		}
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see de.ugoe.cs.quest.usageprofiles.IStochasticProcess#getStateStrings()
+	 */
+	@Override
+	public String[] getSymbolStrings() {
+		if (trie == null) {
+			return new String[0];
+		}
+		String[] stateStrings = new String[getNumSymbols()];
+		int i = 0;
+		for (Event<?> symbol : trie.getKnownSymbols()) {
+			if (symbol.toString() == null) {
+				stateStrings[i] = "null";
+			} else {
+				stateStrings[i] = symbol.toString();
+			}
+			i++;
+		}
+		return stateStrings;
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see de.ugoe.cs.quest.usageprofiles.IStochasticProcess#getEvents()
+	 */
+	@Override
+	public Collection<? extends Event<?>> getEvents() {
+		if (trie == null) {
+			return new HashSet<Event<?>>();
+		} else {
+			return trie.getKnownSymbols();
+		}
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see
+	 * de.ugoe.cs.quest.usageprofiles.IStochasticProcess#generateSequences(int)
+	 */
+	@Override
+	public Collection<List<? extends Event<?>>> generateSequences(int length) {
+		return generateSequences(length, false);
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see
+	 * de.ugoe.cs.quest.usageprofiles.IStochasticProcess#generateSequences(int,
+	 * boolean)
+	 */
+	@Override
+	public Set<List<? extends Event<?>>> generateSequences(int length,
+			boolean fromStart) {
+		Set<List<? extends Event<?>>> sequenceSet = new LinkedHashSet<List<? extends Event<?>>>();
+		if (length < 1) {
+			throw new InvalidParameterException(
+					"Length of generated subsequences must be at least 1.");
+		}
+		if (length == 1) {
+			if (fromStart) {
+				List<Event<?>> subSeq = new LinkedList<Event<?>>();
+				subSeq.add(Event.STARTEVENT);
+				sequenceSet.add(subSeq);
+			} else {
+				for (Event<?> event : getEvents()) {
+					List<Event<?>> subSeq = new LinkedList<Event<?>>();
+					subSeq.add(event);
+					sequenceSet.add(subSeq);
+				}
+			}
+			return sequenceSet;
+		}
+		Collection<? extends Event<?>> events = getEvents();
+		Collection<List<? extends Event<?>>> seqsShorter = generateSequences(
+				length - 1, fromStart);
+		for (Event<?> event : events) {
+			for (List<? extends Event<?>> seqShorter : seqsShorter) {
+				Event<?> lastEvent = event;
+				if (getProbability(seqShorter, lastEvent) > 0.0) {
+					List<Event<?>> subSeq = new ArrayList<Event<?>>(seqShorter);
+					subSeq.add(lastEvent);
+					sequenceSet.add(subSeq);
+				}
+			}
+		}
+		return sequenceSet;
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see
+	 * de.ugoe.cs.quest.usageprofiles.IStochasticProcess#generateValidSequences
+	 * (int)
+	 */
+	@Override
+	public Collection<List<? extends Event<?>>> generateValidSequences(
+			int length) {
+		// check for min-length implicitly done by generateSequences
+		Collection<List<? extends Event<?>>> allSequences = generateSequences(
+				length, true);
+		Collection<List<? extends Event<?>>> validSequences = new LinkedHashSet<List<? extends Event<?>>>();
+		for (List<? extends Event<?>> sequence : allSequences) {
+			if (sequence.size() == length
+					&& Event.ENDEVENT.equals(sequence.get(sequence.size() - 1))) {
+				validSequences.add(sequence);
+			}
+		}
+		return validSequences;
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see
+	 * de.ugoe.cs.quest.usageprofiles.IStochasticProcess#getProbability(java.util
+	 * .List)
+	 */
+	@Override
+	public double getProbability(List<? extends Event<?>> sequence) {
+		if (sequence == null) {
+			throw new InvalidParameterException("sequence must not be null");
+		}
+		double prob = 1.0;
+		List<Event<?>> context = new LinkedList<Event<?>>();
+		for (Event<?> event : sequence) {
+			prob *= getProbability(context, event);
+			context.add(event);
+		}
+		return prob;
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see de.ugoe.cs.quest.usageprofiles.IStochasticProcess#getNumFOMStates()
+	 */
+	@Override
+	public int getNumFOMStates() {
+		if (trie == null) {
+			return 0;
+		} else {
+			return trie.getNumLeafAncestors();
+		}
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see de.ugoe.cs.quest.usageprofiles.IStochasticProcess#getNumTransitions()
+	 */
+	@Override
+	public int getNumTransitions() {
+		if (trie == null) {
+			return 0;
+		} else {
+			return trie.getNumLeafs();
+		}
+	}
+}
Index: /trunk/quest-core-events/src/main/java/de/ugoe/cs/quest/usageprofiles/TrieNode.java
===================================================================
--- /trunk/quest-core-events/src/main/java/de/ugoe/cs/quest/usageprofiles/TrieNode.java	(revision 480)
+++ /trunk/quest-core-events/src/main/java/de/ugoe/cs/quest/usageprofiles/TrieNode.java	(revision 480)
@@ -0,0 +1,443 @@
+package de.ugoe.cs.quest.usageprofiles;
+
+import java.io.Serializable;
+import java.security.InvalidParameterException;
+import java.util.Collection;
+import java.util.LinkedList;
+import java.util.List;
+
+import de.ugoe.cs.quest.usageprofiles.Trie.Edge;
+import de.ugoe.cs.quest.usageprofiles.Trie.TrieVertex;
+import de.ugoe.cs.util.StringTools;
+import edu.uci.ics.jung.graph.DelegateTree;
+import edu.uci.ics.jung.graph.Tree;
+
+/**
+ * <p>
+ * This class implements a node of a trie. Each node is associated with a symbol
+ * and has a counter. The counter marks the number of occurences of the sequence
+ * defined by the path from the root of the trie to this node.
+ * </p>
+ * 
+ * @author Steffen Herbold
+ * 
+ * @param <T>
+ *            Type of the symbols that are stored in the trie.
+ * @see Trie
+ */
+class TrieNode<T> implements Serializable {
+
+	/**
+	 * <p>
+	 * Id for object serialization.
+	 * </p>
+	 */
+	private static final long serialVersionUID = 1L;
+
+	/**
+	 * <p>
+	 * Counter for the number of occurences of the sequence.
+	 * </p>
+	 */
+	private int count;
+
+	/**
+	 * <p>
+	 * Symbol associated with the node.
+	 * </p>
+	 */
+	private final T symbol;
+
+	/**
+	 * <p>
+	 * Child nodes of this node. If the node is a leaf this collection is empty.
+	 * </p>
+	 */
+	private Collection<TrieNode<T>> children;
+
+	/**
+	 * <p>
+	 * Constructor. Creates a new TrieNode without a symbol associated.<br>
+	 * <b>This constructor should only be used to create the root node of the
+	 * trie!</b>
+	 * </p>
+	 */
+	TrieNode() {
+		this.symbol = null;
+		count = 0;
+		children = new LinkedList<TrieNode<T>>();
+	}
+
+	/**
+	 * <p>
+	 * Constructor. Creates a new TrieNode. The symbol must not be null.
+	 * </p>
+	 * 
+	 * @param symbol
+	 *            symbol associated with the trie node
+	 */
+	TrieNode(T symbol) {
+		if (symbol == null) {
+			throw new InvalidParameterException(
+					"symbol must not be null. null is reserved for root node!");
+		}
+		this.symbol = symbol;
+		count = 0;
+		children = new LinkedList<TrieNode<T>>();
+	}
+
+	/**
+	 * <p>
+	 * Copy-Constructor. Creates a new TrieNode as copy of other. Other must not
+	 * be null.
+	 * </p>
+	 * 
+	 * @param other
+	 */
+	TrieNode(TrieNode<T> other) {
+		if (other == null) {
+			throw new InvalidParameterException("other must not be null");
+		}
+		symbol = other.symbol;
+		count = other.count;
+		children = new LinkedList<TrieNode<T>>();
+		for (TrieNode<T> child : other.children) {
+			children.add(new TrieNode<T>(child));
+		}
+	}
+
+	/**
+	 * <p>
+	 * Adds a given subsequence to the trie and increases the counters
+	 * accordingly.
+	 * </p>
+	 * 
+	 * @param subsequence
+	 *            subsequence whose counters are increased
+	 * @see Trie#add(List)
+	 */
+	public void add(List<T> subsequence) {
+		if (!subsequence.isEmpty()) {
+			if (!symbol.equals(subsequence.get(0))) { // should be guaranteed by
+														// the
+														// recursion/TrieRoot!
+				throw new AssertionError("Invalid trie operation!");
+			}
+			count++;
+			subsequence.remove(0);
+			if (!subsequence.isEmpty()) {
+				T nextSymbol = subsequence.get(0);
+				getChildCreate(nextSymbol).add(subsequence);
+			}
+		}
+	}
+
+	/**
+	 * <p>
+	 * Returns the symbol associated with the node.
+	 * </p>
+	 * 
+	 * @return symbol associated with the node
+	 */
+	public T getSymbol() {
+		return symbol;
+	}
+
+	/**
+	 * <p>
+	 * Returns the number of occurences of the sequence represented by the node.
+	 * </p>
+	 * 
+	 * @return number of occurences of the sequence represented by the node
+	 */
+	public int getCount() {
+		return count;
+	}
+
+	/**
+	 * <p>
+	 * Returns the child of the node associated with the given symbol or creates
+	 * it if it does not exist yet.
+	 * </p>
+	 * 
+	 * @param symbol
+	 *            symbol whose node is required
+	 * @return node associated with the symbol
+	 * @see Trie#getChildCreate(Object)
+	 */
+	protected TrieNode<T> getChildCreate(T symbol) {
+		TrieNode<T> node = getChild(symbol);
+		if (node == null) {
+			node = new TrieNode<T>(symbol);
+			children.add(node);
+		}
+		return node;
+	}
+
+	/**
+	 * <p>
+	 * Returns the child of the node associated with the given symbol or null if
+	 * it does not exist.
+	 * </p>
+	 * 
+	 * @param symbol
+	 *            symbol whose node is required
+	 * @return node associated with the symbol; null if no such node exists
+	 * @see Trie#getChild(Object)
+	 */
+	protected TrieNode<T> getChild(T symbol) {
+		for (TrieNode<T> child : children) {
+			if (child.getSymbol().equals(symbol)) {
+				return child;
+			}
+		}
+		return null;
+	}
+
+	/**
+	 * <p>
+	 * Returns all children of this node.
+	 * </p>
+	 * 
+	 * @return children of this node
+	 */
+	protected Collection<TrieNode<T>> getChildren() {
+		return children;
+	}
+
+	/**
+	 * <p>
+	 * Searches the sub-trie of this trie node for a given sequence and returns
+	 * the node associated with the sequence or null if no such node is found.
+	 * </p>
+	 * 
+	 * @param sequence
+	 *            sequence that is searched for
+	 * @return node associated with the sequence
+	 * @see Trie#find(List)
+	 */
+	public TrieNode<T> find(List<T> subsequence) {
+		TrieNode<T> result = null;
+		if (subsequence.isEmpty()) {
+			result = this;
+		} else {
+			TrieNode<T> node = getChild(subsequence.get(0));
+			if (node != null) {
+				subsequence.remove(0);
+				result = node.find(subsequence);
+			}
+		}
+		return result;
+	}
+
+	/**
+	 * <p>
+	 * Returns a collection of all symbols that follow a this node, i.e., the
+	 * symbols associated with the children of this node.
+	 * </p>
+	 * 
+	 * @return symbols follow this node
+	 * @see TrieNode#getFollowingSymbols()
+	 */
+	public Collection<T> getFollowingSymbols() {
+		Collection<T> followingSymbols = new LinkedList<T>();
+		for (TrieNode<T> child : children) {
+			followingSymbols.add(child.getSymbol());
+		}
+		return followingSymbols;
+	}
+
+	/**
+	 * <p>
+	 * The string representation of a node is {@code symbol.toString()#count}
+	 * </p>
+	 * 
+	 * @see java.lang.Object#toString()
+	 */
+	@Override
+	public String toString() {
+		String str = symbol.toString() + " #" + count;
+		if (!children.isEmpty()) {
+			str += StringTools.ENDLINE + children.toString();
+		}
+		return str;
+	}
+
+	/**
+	 * <p>
+	 * Generates a {@link Tree} represenation of the trie.
+	 * </p>
+	 * 
+	 * @param parent
+	 *            parent vertex in the generated tree
+	 * @param graph
+	 *            complete tree
+	 */
+	void getGraph(TrieVertex parent, DelegateTree<TrieVertex, Edge> graph) {
+		TrieVertex currentVertex;
+		if (isRoot()) {
+			currentVertex = new TrieVertex("root");
+			graph.addVertex(currentVertex);
+		} else {
+			currentVertex = new TrieVertex(getSymbol().toString() + "#"
+					+ getCount());
+			graph.addChild(new Edge(), parent, currentVertex);
+		}
+		for (TrieNode<T> node : children) {
+			node.getGraph(currentVertex, graph);
+		}
+	}
+
+	/**
+	 * <p>
+	 * Appends the current node to the dot representation of the trie.
+	 * </p>
+	 * 
+	 * @param stringBuilder
+	 *            {@link StringBuilder} to which the dot representation is
+	 *            appended
+	 */
+	void appendDotRepresentation(StringBuilder stringBuilder) {
+		String thisSaneId;
+		if (isRoot()) {
+			thisSaneId = "root";
+		} else {
+			thisSaneId = symbol.toString().replace("\"", "\\\"")
+					.replaceAll("[\r\n]", "")
+					+ "#" + count;
+		}
+		stringBuilder.append(" " + hashCode() + " [label=\"" + thisSaneId
+				+ "\"];" + StringTools.ENDLINE);
+		for (TrieNode<T> childNode : children) {
+			stringBuilder.append(" " + hashCode() + " -> "
+					+ childNode.hashCode() + ";" + StringTools.ENDLINE);
+		}
+		for (TrieNode<T> childNode : children) {
+			childNode.appendDotRepresentation(stringBuilder);
+		}
+	}
+
+	/**
+	 * <p>
+	 * Checks if the node is a leaf.
+	 * </p>
+	 * 
+	 * @return true if the node is a leaf, false otherwise.
+	 */
+	protected boolean isLeaf() {
+		return children.isEmpty();
+	}
+
+	/**
+	 * <p>
+	 * Checks if the node is the root.
+	 * </p>
+	 * 
+	 * @return true if the node is the root of the trie, false otherwise
+	 */
+	protected boolean isRoot() {
+		return symbol == null;
+	}
+
+	/**
+	 * <p>
+	 * Recursive methods that collects all nodes that are ancestors of leafs and
+	 * stores them in the set.
+	 * </p>
+	 * 
+	 * @param ancestors
+	 *            set of all ancestors of leafs
+	 */
+	protected void getLeafAncestors(List<TrieNode<T>> ancestors) {
+		boolean isAncestor = false;
+		for (TrieNode<T> child : children) {
+			child.getLeafAncestors(ancestors);
+			isAncestor |= child.isLeaf();
+		}
+		if (isAncestor) {
+			ancestors.add(this);
+		}
+	}
+
+	/**
+	 * <p>
+	 * Returns the number of descendants of this node that are leafs. This does
+	 * not only include direct children of this node, but all leafs in the
+	 * sub-trie with this node as root.
+	 * </p>
+	 * 
+	 * @return number of leafs in this sub-trie
+	 */
+	protected int getNumLeafs() {
+		int numLeafs = 0;
+		for (TrieNode<T> child : children) {
+			if (child.isLeaf()) {
+				numLeafs++;
+			} else {
+				numLeafs += child.getNumLeafs();
+			}
+		}
+		return numLeafs;
+	}
+
+	/**
+	 * <p>
+	 * Sets the {@link #count} of this node.
+	 * </p>
+	 * <p>
+	 * This function should only be used sparingly and very carefully! The count
+	 * is usually maintained automatically by the training procedures.
+	 * </p>
+	 * 
+	 * @param count
+	 *            new count
+	 */
+	protected void setCount(int count) {
+		this.count = count;
+	}
+
+	/**
+	 * <p>
+	 * Two TrieNodes are defined as equal, if their {@link #count},
+	 * {@link #symbol}, and {@link #children} are equal.
+	 * </p>
+	 * 
+	 * @see java.lang.Object#equals(java.lang.Object)
+	 */
+	@SuppressWarnings("rawtypes")
+	@Override
+	public boolean equals(Object other) {
+		if (other == this) {
+			return true;
+		}
+		if (other instanceof TrieNode) {
+			TrieNode otherNode = (TrieNode) other;
+			if (symbol == null) {
+				return count == otherNode.count && otherNode.symbol == null
+						&& children.equals(otherNode.children);
+			} else {
+				return count == otherNode.count
+						&& symbol.equals(((TrieNode) other).symbol)
+						&& children.equals(((TrieNode) other).children);
+			}
+		}
+		return false;
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see java.lang.Object#hashCode()
+	 */
+	@Override
+	public int hashCode() {
+		int multiplier = 17;
+		int hash = 42;
+		if (symbol != null) {
+			hash = multiplier * hash + symbol.hashCode();
+		}
+		hash = multiplier * hash + count;
+		hash = multiplier * hash + children.hashCode();
+		return hash;
+	}
+}
