Index: branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Dataset.cs
===================================================================
--- branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Dataset.cs	(revision 9073)
+++ branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Dataset.cs	(revision 9073)
@@ -0,0 +1,246 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  [Item("Dataset", "Represents a dataset containing data that should be analyzed.")]
+  [StorableClass]
+  public sealed class Dataset : NamedItem, IStringConvertibleMatrix {
+    [StorableConstructor]
+    private Dataset(bool deserializing) : base(deserializing) { }
+    private Dataset(Dataset original, Cloner cloner)
+      : base(original, cloner) {
+      variableValues = new Dictionary<string, IList>(original.variableValues);
+      variableNames = new List<string>(original.variableNames);
+      rows = original.rows;
+    }
+    public override IDeepCloneable Clone(Cloner cloner) { return new Dataset(this, cloner); }
+
+    public Dataset()
+      : base() {
+      Name = "-";
+      VariableNames = Enumerable.Empty<string>();
+      variableValues = new Dictionary<string, IList>();
+      rows = 0;
+    }
+
+    public Dataset(IEnumerable<string> variableNames, IEnumerable<IList> variableValues)
+      : base() {
+      Name = "-";
+      if (!variableNames.Any()) {
+        this.variableNames = Enumerable.Range(0, variableValues.Count()).Select(x => "Column " + x).ToList();
+      } else if (variableNames.Count() != variableValues.Count()) {
+        throw new ArgumentException("Number of variable names doesn't match the number of columns of variableValues");
+      } else if (!variableValues.All(list => list.Count == variableValues.First().Count)) {
+        throw new ArgumentException("The number of values must be equal for every variable");
+      } else if (variableNames.Distinct().Count() != variableNames.Count()) {
+        var duplicateVariableNames =
+          variableNames.GroupBy(v => v).Where(g => g.Count() > 1).Select(g => g.Key).ToList();
+        string message = "The dataset cannot contain duplicate variables names: " + Environment.NewLine;
+        foreach (var duplicateVariableName in duplicateVariableNames)
+          message += duplicateVariableName + Environment.NewLine;
+        throw new ArgumentException(message);
+      }
+
+      rows = variableValues.First().Count;
+      this.variableNames = new List<string>(variableNames);
+      this.variableValues = new Dictionary<string, IList>(this.variableNames.Count);
+      for (int i = 0; i < this.variableNames.Count; i++) {
+        var values = variableValues.ElementAt(i);
+        IList clonedValues = null;
+        if (values is List<double>)
+          clonedValues = new List<double>(values.Cast<double>());
+        else if (values is List<string>)
+          clonedValues = new List<string>(values.Cast<string>());
+        else if (values is List<DateTime>)
+          clonedValues = new List<DateTime>(values.Cast<DateTime>());
+        else {
+          this.variableNames = new List<string>();
+          this.variableValues = new Dictionary<string, IList>();
+          throw new ArgumentException("The variable values must be of type List<double>, List<string> or List<DateTime>");
+        }
+        this.variableValues.Add(this.variableNames[i], clonedValues);
+      }
+    }
+
+    public Dataset(IEnumerable<string> variableNames, double[,] variableValues) {
+      Name = "-";
+      if (variableNames.Count() != variableValues.GetLength(1)) {
+        throw new ArgumentException("Number of variable names doesn't match the number of columns of variableValues");
+      }
+      if (variableNames.Distinct().Count() != variableNames.Count()) {
+        var duplicateVariableNames = variableNames.GroupBy(v => v).Where(g => g.Count() > 1).Select(g => g.Key).ToList();
+        string message = "The dataset cannot contain duplicate variables names: " + Environment.NewLine;
+        foreach (var duplicateVariableName in duplicateVariableNames)
+          message += duplicateVariableName + Environment.NewLine;
+        throw new ArgumentException(message);
+      }
+
+      rows = variableValues.GetLength(0);
+      this.variableNames = new List<string>(variableNames);
+
+      this.variableValues = new Dictionary<string, IList>(variableValues.GetLength(1));
+      for (int col = 0; col < variableValues.GetLength(1); col++) {
+        string columName = this.variableNames[col];
+        var values = new List<double>(variableValues.GetLength(0));
+        for (int row = 0; row < variableValues.GetLength(0); row++) {
+          values.Add(variableValues[row, col]);
+        }
+        this.variableValues.Add(columName, values);
+      }
+    }
+
+    #region Backwards compatible code, remove with 3.5
+    private double[,] storableData;
+    //name alias used to suppport backwards compatibility
+    [Storable(Name = "data", AllowOneWay = true)]
+    private double[,] StorableData { set { storableData = value; } }
+
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() {
+      if (variableValues == null) {
+        rows = storableData.GetLength(0);
+        variableValues = new Dictionary<string, IList>();
+        for (int col = 0; col < storableData.GetLength(1); col++) {
+          string columName = variableNames[col];
+          var values = new List<double>(rows);
+          for (int row = 0; row < rows; row++) {
+            values.Add(storableData[row, col]);
+          }
+          variableValues.Add(columName, values);
+        }
+        storableData = null;
+      }
+    }
+    #endregion
+
+    [Storable(Name = "VariableValues")]
+    private Dictionary<string, IList> variableValues;
+
+    private List<string> variableNames;
+    [Storable]
+    public IEnumerable<string> VariableNames {
+      get { return variableNames; }
+      private set {
+        if (variableNames != null) throw new InvalidOperationException();
+        variableNames = new List<string>(value);
+      }
+    }
+
+    public IEnumerable<string> DoubleVariables {
+      get { return variableValues.Where(p => p.Value is List<double>).Select(p => p.Key); }
+    }
+
+    public IEnumerable<double> GetDoubleValues(string variableName) {
+      IList list;
+      if (!variableValues.TryGetValue(variableName, out list))
+        throw new ArgumentException("The variable " + variableName + " does not exist in the dataset.");
+      List<double> values = list as List<double>;
+      if (values == null) throw new ArgumentException("The variable " + variableName + " is not a double variable.");
+
+      //mkommend yield return used to enable lazy evaluation
+      foreach (double value in values)
+        yield return value;
+    }
+    public ReadOnlyCollection<double> GetReadOnlyDoubleValues(string variableName) {
+      IList list;
+      if (!variableValues.TryGetValue(variableName, out list))
+        throw new ArgumentException("The variable " + variableName + " does not exist in the dataset.");
+      List<double> values = list as List<double>;
+      if (values == null) throw new ArgumentException("The variable " + variableName + " is not a double variable.");
+      return values.AsReadOnly();
+    }
+    public double GetDoubleValue(string variableName, int row) {
+      IList list;
+      if (!variableValues.TryGetValue(variableName, out list))
+        throw new ArgumentException("The variable " + variableName + " does not exist in the dataset.");
+      List<double> values = list as List<double>;
+      if (values == null) throw new ArgumentException("The variable " + variableName + " is not a double variable.");
+      return values[row];
+    }
+    public IEnumerable<double> GetDoubleValues(string variableName, IEnumerable<int> rows) {
+      IList list;
+      if (!variableValues.TryGetValue(variableName, out list))
+        throw new ArgumentException("The variable " + variableName + " does not exist in the dataset.");
+      List<double> values = list as List<double>;
+      if (values == null) throw new ArgumentException("The varialbe " + variableName + " is not a double variable.");
+
+      return rows.Select(index => values[index]);
+    }
+
+    #region IStringConvertibleMatrix Members
+    [Storable]
+    private int rows;
+    public int Rows {
+      get { return rows; }
+      set { throw new NotSupportedException(); }
+    }
+    public int Columns {
+      get { return variableNames.Count; }
+      set { throw new NotSupportedException(); }
+    }
+
+    public bool SortableView {
+      get { return false; }
+      set { throw new NotSupportedException(); }
+    }
+    public bool ReadOnly {
+      get { return true; }
+    }
+
+    IEnumerable<string> IStringConvertibleMatrix.ColumnNames {
+      get { return this.VariableNames; }
+      set { throw new NotSupportedException(); }
+    }
+    IEnumerable<string> IStringConvertibleMatrix.RowNames {
+      get { return Enumerable.Empty<string>(); }
+      set { throw new NotSupportedException(); }
+    }
+
+    public string GetValue(int rowIndex, int columnIndex) {
+      return variableValues[variableNames[columnIndex]][rowIndex].ToString();
+    }
+    public bool SetValue(string value, int rowIndex, int columnIndex) {
+      throw new NotSupportedException();
+    }
+    public bool Validate(string value, out string errorMessage) {
+      throw new NotSupportedException();
+    }
+
+    public event EventHandler ColumnsChanged { add { } remove { } }
+    public event EventHandler RowsChanged { add { } remove { } }
+    public event EventHandler ColumnNamesChanged { add { } remove { } }
+    public event EventHandler RowNamesChanged { add { } remove { } }
+    public event EventHandler SortableViewChanged { add { } remove { } }
+    public event EventHandler<EventArgs<int, int>> ItemChanged { add { } remove { } }
+    public event EventHandler Reset { add { } remove { } }
+    #endregion
+  }
+}
Index: branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/DatasetExtensions.cs
===================================================================
--- branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/DatasetExtensions.cs	(revision 9073)
+++ branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/DatasetExtensions.cs	(revision 9073)
@@ -0,0 +1,34 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2011 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Collections.Generic;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  public static class DatasetExtensions {
+    public static IEnumerable<T> TakeEvery<T>(this IEnumerable<T> xs, int nth) {
+      int i = 0;
+      foreach (var x in xs) {
+        if (i % nth == 0) yield return x;
+        i++;
+      }
+    }
+  }
+}
Index: branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/DoubleLimit.cs
===================================================================
--- branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/DoubleLimit.cs	(revision 9073)
+++ branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/DoubleLimit.cs	(revision 9073)
@@ -0,0 +1,66 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  [StorableClass]
+  [Item("DoubleLimit", "Represents a lower and a upper bound for double values.")]
+  public class DoubleLimit : StringConvertibleValueTuple<DoubleValue, DoubleValue> {
+
+    public double Lower {
+      get { return Item1.Value; }
+      set { Item1.Value = value; }
+    }
+    public double Upper {
+      get { return Item2.Value; }
+      set { Item2.Value = value; }
+    }
+
+    [StorableConstructor]
+    protected DoubleLimit(bool deserializing) : base(deserializing) { }
+    protected DoubleLimit(DoubleLimit original, Cloner cloner)
+      : base(original, cloner) {
+    }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new DoubleLimit(this, cloner);
+    }
+
+    public DoubleLimit() : base(new DoubleValue(), new DoubleValue()) { }
+    public DoubleLimit(DoubleValue start, DoubleValue end) : base(start, end) { }
+    public DoubleLimit(double start, double end) : base(new DoubleValue(start), new DoubleValue(end)) { }
+
+    public override string ToString() {
+      return string.Format("Lower: {0}, Upper: {1}", Lower, Upper);
+    }
+
+    public override StringConvertibleValueTuple<DoubleValue, DoubleValue> AsReadOnly() {
+      var readOnly = new DoubleLimit();
+      readOnly.values = Tuple.Create<DoubleValue, DoubleValue>((DoubleValue)Item1.AsReadOnly(), (DoubleValue)Item2.AsReadOnly());
+      readOnly.readOnly = true;
+      return readOnly;
+    }
+  }
+}
Index: branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/HeuristicLab.Problems.DataAnalysis-3.4.csproj
===================================================================
--- branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/HeuristicLab.Problems.DataAnalysis-3.4.csproj	(revision 9073)
+++ branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/HeuristicLab.Problems.DataAnalysis-3.4.csproj	(revision 9073)
@@ -0,0 +1,316 @@
+﻿<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProductVersion>9.0.30729</ProductVersion>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{DF87C13E-A889-46FF-8153-66DCAA8C5674}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>HeuristicLab.Problems.DataAnalysis</RootNamespace>
+    <AssemblyName>HeuristicLab.Problems.DataAnalysis-3.4</AssemblyName>
+    <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
+    <TargetFrameworkProfile>
+    </TargetFrameworkProfile>
+    <FileAlignment>512</FileAlignment>
+    <SignAssembly>true</SignAssembly>
+    <AssemblyOriginatorKeyFile>HeuristicLab.snk</AssemblyOriginatorKeyFile>
+    <FileUpgradeFlags>
+    </FileUpgradeFlags>
+    <OldToolsVersion>3.5</OldToolsVersion>
+    <UpgradeBackupLocation />
+    <PublishUrl>publish\</PublishUrl>
+    <Install>true</Install>
+    <InstallFrom>Disk</InstallFrom>
+    <UpdateEnabled>false</UpdateEnabled>
+    <UpdateMode>Foreground</UpdateMode>
+    <UpdateInterval>7</UpdateInterval>
+    <UpdateIntervalUnits>Days</UpdateIntervalUnits>
+    <UpdatePeriodically>false</UpdatePeriodically>
+    <UpdateRequired>false</UpdateRequired>
+    <MapFileExtensions>true</MapFileExtensions>
+    <ApplicationRevision>0</ApplicationRevision>
+    <ApplicationVersion>1.0.0.%2a</ApplicationVersion>
+    <IsWebBootstrapper>false</IsWebBootstrapper>
+    <UseApplicationTrust>false</UseApplicationTrust>
+    <BootstrapperEnabled>true</BootstrapperEnabled>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>$(SolutionDir)\bin\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>$(SolutionDir)\bin\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x64' ">
+    <DebugSymbols>true</DebugSymbols>
+    <OutputPath>$(SolutionDir)\bin\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <DebugType>full</DebugType>
+    <PlatformTarget>x64</PlatformTarget>
+    <ErrorReport>prompt</ErrorReport>
+    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x64' ">
+    <OutputPath>$(SolutionDir)\bin\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <Optimize>true</Optimize>
+    <DebugType>pdbonly</DebugType>
+    <PlatformTarget>x64</PlatformTarget>
+    <ErrorReport>prompt</ErrorReport>
+    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
+    <DebugSymbols>true</DebugSymbols>
+    <OutputPath>$(SolutionDir)\bin\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <DebugType>full</DebugType>
+    <PlatformTarget>x86</PlatformTarget>
+    <ErrorReport>prompt</ErrorReport>
+    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
+    <OutputPath>$(SolutionDir)\bin\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <Optimize>true</Optimize>
+    <DebugType>pdbonly</DebugType>
+    <PlatformTarget>x86</PlatformTarget>
+    <ErrorReport>prompt</ErrorReport>
+    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="ALGLIB-3.6.0, Version=3.6.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <HintPath>..\..\bin\ALGLIB-3.6.0.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.ALGLIB-3.6.0, Version=3.6.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <HintPath>..\..\bin\HeuristicLab.ALGLIB-3.6.0.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="System" />
+    <Reference Include="System.Core">
+      <RequiredTargetFramework>3.5</RequiredTargetFramework>
+    </Reference>
+    <Reference Include="System.Drawing" />
+    <Reference Include="System.Xml.Linq">
+      <RequiredTargetFramework>3.5</RequiredTargetFramework>
+    </Reference>
+    <Reference Include="System.Data.DataSetExtensions">
+      <RequiredTargetFramework>3.5</RequiredTargetFramework>
+    </Reference>
+    <Reference Include="System.Data" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="DatasetExtensions.cs" />
+    <Compile Include="DoubleLimit.cs" />
+    <Compile Include="Implementation\Classification\ClassificationEnsembleModel.cs">
+      <SubType>Code</SubType>
+    </Compile>
+    <Compile Include="Implementation\Classification\ClassificationEnsembleSolution.cs" />
+    <Compile Include="Implementation\Classification\ClassificationProblemData.cs" />
+    <Compile Include="Implementation\Classification\ClassificationProblem.cs" />
+    <Compile Include="Implementation\Classification\ClassificationSolution.cs" />
+    <Compile Include="Implementation\Classification\ClassificationEnsembleProblemData.cs" />
+    <Compile Include="Implementation\Classification\ClassificationSolutionBase.cs" />
+    <Compile Include="Implementation\Classification\DiscriminantFunctionClassificationSolutionBase.cs" />
+    <Compile Include="Implementation\Clustering\ClusteringProblem.cs" />
+    <Compile Include="Implementation\Clustering\ClusteringProblemData.cs" />
+    <Compile Include="Implementation\Clustering\ClusteringSolution.cs" />
+    <Compile Include="Implementation\Regression\ConstantRegressionModel.cs" />
+    <Compile Include="Implementation\Regression\ConstantRegressionSolution.cs" />
+    <Compile Include="Implementation\Regression\RegressionEnsembleProblemData.cs" />
+    <Compile Include="Implementation\Regression\RegressionEnsembleModel.cs">
+      <SubType>Code</SubType>
+    </Compile>
+    <Compile Include="Implementation\Regression\RegressionEnsembleSolution.cs" />
+    <Compile Include="Implementation\TimeSeriesPrognosis\Models\ConstantTimeSeriesPrognosisModel.cs" />
+    <Compile Include="Implementation\TimeSeriesPrognosis\Models\TimeSeriesPrognosisAutoRegressiveModel.cs" />
+    <Compile Include="Implementation\TimeSeriesPrognosis\TimeSeriesPrognosisProblem.cs" />
+    <Compile Include="Implementation\TimeSeriesPrognosis\TimeSeriesPrognosisProblemData.cs" />
+    <Compile Include="Implementation\TimeSeriesPrognosis\TimeSeriesPrognosisResults.cs" />
+    <Compile Include="Implementation\TimeSeriesPrognosis\TimeSeriesPrognosisSolution.cs" />
+    <Compile Include="Implementation\TimeSeriesPrognosis\TimeSeriesPrognosisSolutionBase.cs" />
+    <Compile Include="Interfaces\Classification\IClassificationEnsembleModel.cs">
+      <SubType>Code</SubType>
+    </Compile>
+    <Compile Include="Interfaces\Classification\IClassificationEnsembleSolution.cs">
+      <SubType>Code</SubType>
+    </Compile>
+    <Compile Include="Interfaces\Classification\IDiscriminantFunctionThresholdCalculator.cs" />
+    <Compile Include="Interfaces\IDependencyCalculator.cs" />
+    <Compile Include="Interfaces\Regression\IRegressionEnsembleModel.cs">
+      <SubType>Code</SubType>
+    </Compile>
+    <Compile Include="Interfaces\Regression\IRegressionEnsembleSolution.cs" />
+    <Compile Include="Implementation\Regression\RegressionSolutionBase.cs" />
+    <Compile Include="Interfaces\TimeSeriesPrognosis\IOnlineTimeSeriesCalculator.cs" />
+    <Compile Include="Interfaces\TimeSeriesPrognosis\ITimeSeriesPrognosisModel.cs" />
+    <Compile Include="Interfaces\TimeSeriesPrognosis\ITimeSeriesPrognosisProblem.cs" />
+    <Compile Include="Interfaces\TimeSeriesPrognosis\ITimeSeriesPrognosisProblemData.cs" />
+    <Compile Include="Interfaces\TimeSeriesPrognosis\ITimeSeriesPrognosisSolution.cs" />
+    <Compile Include="OnlineCalculators\AutoCorrelationCalculator.cs" />
+    <Compile Include="OnlineCalculators\DependencyCalculator\HoeffdingsDependenceCalculator.cs" />
+    <Compile Include="OnlineCalculators\DependencyCalculator\PearsonsRDependenceCalculator.cs" />
+    <Compile Include="OnlineCalculators\DependencyCalculator\PearsonsRSquaredDependenceCalculator.cs" />
+    <Compile Include="OnlineCalculators\DependencyCalculator\SpearmansRankCorrelationCoefficientCalculator.cs" />
+    <Compile Include="OnlineCalculators\OnlineBoundedMeanSquaredErrorCalculator.cs" />
+    <Compile Include="OnlineCalculators\OnlineDirectionalSymmetryCalculator.cs" />
+    <Compile Include="OnlineCalculators\OnlineMaxAbsoluteErrorCalculator.cs" />
+    <Compile Include="OnlineCalculators\OnlineMeanErrorCalculator.cs" />
+    <Compile Include="OnlineCalculators\NormalizedGiniCalculator.cs" />
+    <Compile Include="OnlineCalculators\OnlineMeanAbsoluteErrorCalculator.cs" />
+    <Compile Include="OnlineCalculators\OnlineLinearScalingParameterCalculator.cs" />
+    <Compile Include="Implementation\Classification\DiscriminantFunctionClassificationModel.cs" />
+    <Compile Include="Implementation\Classification\DiscriminantFunctionClassificationSolution.cs" />
+    <Compile Include="Implementation\DataAnalysisSolution.cs" />
+    <Compile Include="Interfaces\Classification\IDiscriminantFunctionClassificationModel.cs" />
+    <Compile Include="Interfaces\Classification\IDiscriminantFunctionClassificationSolution.cs" />
+    <Compile Include="Interfaces\Clustering\IClusteringModel.cs" />
+    <Compile Include="Interfaces\Clustering\IClusteringProblem.cs" />
+    <Compile Include="Interfaces\Clustering\IClusteringProblemData.cs" />
+    <Compile Include="Interfaces\Clustering\IClusteringSolution.cs" />
+    <Compile Include="OnlineCalculators\OnlineAccuracyCalculator.cs" />
+    <Compile Include="Implementation\Regression\RegressionProblemData.cs" />
+    <Compile Include="Implementation\DataAnalysisProblemData.cs" />
+    <Compile Include="Implementation\Regression\RegressionProblem.cs" />
+    <Compile Include="Implementation\DataAnalysisProblem.cs" />
+    <Compile Include="Dataset.cs" />
+    <Compile Include="Interfaces\Classification\IClassificationModel.cs" />
+    <Compile Include="Interfaces\Classification\IClassificationProblem.cs" />
+    <Compile Include="Interfaces\Classification\IClassificationProblemData.cs" />
+    <Compile Include="Interfaces\Classification\IClassificationSolution.cs" />
+    <Compile Include="Interfaces\IDataAnalysisProblemData.cs" />
+    <Compile Include="Interfaces\IDataAnalysisSolution.cs" />
+    <Compile Include="Interfaces\IOnlineCalculator.cs" />
+    <Compile Include="Interfaces\Regression\IRegressionModel.cs" />
+    <Compile Include="Interfaces\Regression\IRegressionProblem.cs" />
+    <Compile Include="Interfaces\Regression\IRegressionProblemData.cs" />
+    <Compile Include="Interfaces\Regression\IRegressionSolution.cs" />
+    <Compile Include="OnlineCalculators\OnlineCovarianceCalcualtor.cs" />
+    <Compile Include="OnlineCalculators\OnlineMeanAbsolutePercentageErrorCalculator.cs" />
+    <Compile Include="OnlineCalculators\OnlineMeanAndVarianceCalculator.cs" />
+    <Compile Include="OnlineCalculators\OnlineMeanSquaredErrorCalculator.cs" />
+    <Compile Include="OnlineCalculators\OnlineNormalizedMeanSquaredErrorCalculator.cs" />
+    <Compile Include="OnlineCalculators\OnlinePearsonsRSquaredCalculator.cs" />
+    <Compile Include="Implementation\Regression\RegressionSolution.cs" />
+    <Compile Include="OnlineCalculators\OnlineTheilsUStatisticCalculator.cs" />
+    <Compile Include="OnlineCalculators\OnlineWeightedDirectionalSymmetryCalculator.cs" />
+    <Compile Include="Plugin.cs" />
+    <Compile Include="Implementation\Classification\ThresholdCalculators\AccuracyMaximizationThresholdCalculator.cs" />
+    <Compile Include="Implementation\Classification\ThresholdCalculators\NormalDistributionCutPointsThresholdCalculator.cs" />
+    <Compile Include="Implementation\Classification\ThresholdCalculators\ThresholdCalculator.cs" />
+    <None Include="HeuristicLab.snk" />
+    <None Include="Plugin.cs.frame" />
+    <None Include="Properties\AssemblyInfo.cs.frame" />
+    <Compile Include="Interfaces\IDataAnalysisModel.cs" />
+    <Compile Include="Interfaces\IDataAnalysisProblem.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <BootstrapperPackage Include="Microsoft.Net.Client.3.5">
+      <Visible>False</Visible>
+      <ProductName>.NET Framework 3.5 SP1 Client Profile</ProductName>
+      <Install>false</Install>
+    </BootstrapperPackage>
+    <BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
+      <Visible>False</Visible>
+      <ProductName>.NET Framework 3.5 SP1</ProductName>
+      <Install>true</Install>
+    </BootstrapperPackage>
+    <BootstrapperPackage Include="Microsoft.Windows.Installer.3.1">
+      <Visible>False</Visible>
+      <ProductName>Windows Installer 3.1</ProductName>
+      <Install>true</Install>
+    </BootstrapperPackage>
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\..\HeuristicLab.Collections\3.3\HeuristicLab.Collections-3.3.csproj">
+      <Project>{958B43BC-CC5C-4FA2-8628-2B3B01D890B6}</Project>
+      <Name>HeuristicLab.Collections-3.3</Name>
+      <Private>False</Private>
+    </ProjectReference>
+    <ProjectReference Include="..\..\HeuristicLab.Common.Resources\3.3\HeuristicLab.Common.Resources-3.3.csproj">
+      <Project>{0E27A536-1C4A-4624-A65E-DC4F4F23E3E1}</Project>
+      <Name>HeuristicLab.Common.Resources-3.3</Name>
+      <Private>False</Private>
+    </ProjectReference>
+    <ProjectReference Include="..\..\HeuristicLab.Common\3.3\HeuristicLab.Common-3.3.csproj">
+      <Project>{A9AD58B9-3EF9-4CC1-97E5-8D909039FF5C}</Project>
+      <Name>HeuristicLab.Common-3.3</Name>
+      <Private>False</Private>
+    </ProjectReference>
+    <ProjectReference Include="..\..\HeuristicLab.Core\3.3\HeuristicLab.Core-3.3.csproj">
+      <Project>{C36BD924-A541-4A00-AFA8-41701378DDC5}</Project>
+      <Name>HeuristicLab.Core-3.3</Name>
+      <Private>False</Private>
+    </ProjectReference>
+    <ProjectReference Include="..\..\HeuristicLab.Data\3.3\HeuristicLab.Data-3.3.csproj">
+      <Project>{BBAB9DF5-5EF3-4BA8-ADE9-B36E82114937}</Project>
+      <Name>HeuristicLab.Data-3.3</Name>
+      <Private>False</Private>
+    </ProjectReference>
+    <ProjectReference Include="..\..\HeuristicLab.Optimization\3.3\HeuristicLab.Optimization-3.3.csproj">
+      <Project>{14AB8D24-25BC-400C-A846-4627AA945192}</Project>
+      <Name>HeuristicLab.Optimization-3.3</Name>
+      <Private>False</Private>
+    </ProjectReference>
+    <ProjectReference Include="..\..\HeuristicLab.Parameters\3.3\HeuristicLab.Parameters-3.3.csproj">
+      <Project>{56F9106A-079F-4C61-92F6-86A84C2D84B7}</Project>
+      <Name>HeuristicLab.Parameters-3.3</Name>
+      <Private>False</Private>
+    </ProjectReference>
+    <ProjectReference Include="..\..\HeuristicLab.Persistence\3.3\HeuristicLab.Persistence-3.3.csproj">
+      <Project>{102BC7D3-0EF9-439C-8F6D-96FF0FDB8E1B}</Project>
+      <Name>HeuristicLab.Persistence-3.3</Name>
+      <Private>False</Private>
+    </ProjectReference>
+    <ProjectReference Include="..\..\HeuristicLab.PluginInfrastructure\3.3\HeuristicLab.PluginInfrastructure-3.3.csproj">
+      <Project>{94186A6A-5176-4402-AE83-886557B53CCA}</Project>
+      <Name>HeuristicLab.PluginInfrastructure-3.3</Name>
+      <Private>False</Private>
+    </ProjectReference>
+    <ProjectReference Include="..\..\HeuristicLab.Problems.Instances\3.3\HeuristicLab.Problems.Instances-3.3.csproj">
+      <Project>{3540E29E-4793-49E7-8EE2-FEA7F61C3994}</Project>
+      <Name>HeuristicLab.Problems.Instances-3.3</Name>
+      <Private>False</Private>
+    </ProjectReference>
+  </ItemGroup>
+  <ItemGroup />
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+  <PropertyGroup>
+    <PreBuildEvent Condition=" '$(OS)' == 'Windows_NT' ">set Path=%25Path%25;$(ProjectDir);$(SolutionDir)
+set ProjectDir=$(ProjectDir)
+set SolutionDir=$(SolutionDir)
+set Outdir=$(Outdir)
+
+call PreBuildEvent.cmd
+</PreBuildEvent>
+    <PreBuildEvent Condition=" '$(OS)' != 'Windows_NT' ">
+export ProjectDir=$(ProjectDir)
+export SolutionDir=$(SolutionDir)
+
+$SolutionDir/PreBuildEvent.sh
+</PreBuildEvent>
+  </PropertyGroup>
+</Project>
Index: branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ClassificationEnsembleModel.cs
===================================================================
--- branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ClassificationEnsembleModel.cs	(revision 9073)
+++ branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ClassificationEnsembleModel.cs	(revision 9073)
@@ -0,0 +1,101 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  /// <summary>
+  /// Represents classification solutions that contain an ensemble of multiple classification models
+  /// </summary>
+  [StorableClass]
+  [Item("ClassificationEnsembleModel", "A classification model that contains an ensemble of multiple classification models")]
+  public class ClassificationEnsembleModel : NamedItem, IClassificationEnsembleModel {
+
+    [Storable]
+    private List<IClassificationModel> models;
+    public IEnumerable<IClassificationModel> Models {
+      get { return new List<IClassificationModel>(models); }
+    }
+
+    [StorableConstructor]
+    protected ClassificationEnsembleModel(bool deserializing) : base(deserializing) { }
+    protected ClassificationEnsembleModel(ClassificationEnsembleModel original, Cloner cloner)
+      : base(original, cloner) {
+      this.models = original.Models.Select(m => cloner.Clone(m)).ToList();
+    }
+
+    public ClassificationEnsembleModel() : this(Enumerable.Empty<IClassificationModel>()) { }
+    public ClassificationEnsembleModel(IEnumerable<IClassificationModel> models)
+      : base() {
+      this.name = ItemName;
+      this.description = ItemDescription;
+      this.models = new List<IClassificationModel>(models);
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new ClassificationEnsembleModel(this, cloner);
+    }
+
+    #region IClassificationEnsembleModel Members
+    public void Add(IClassificationModel model) {
+      models.Add(model);
+    }
+    public void Remove(IClassificationModel model) {
+      models.Remove(model);
+    }
+
+    public IEnumerable<IEnumerable<double>> GetEstimatedClassValueVectors(Dataset dataset, IEnumerable<int> rows) {
+      var estimatedValuesEnumerators = (from model in models
+                                        select model.GetEstimatedClassValues(dataset, rows).GetEnumerator())
+                                       .ToList();
+
+      while (estimatedValuesEnumerators.All(en => en.MoveNext())) {
+        yield return from enumerator in estimatedValuesEnumerators
+                     select enumerator.Current;
+      }
+    }
+
+    #endregion
+
+    #region IClassificationModel Members
+
+    public IEnumerable<double> GetEstimatedClassValues(Dataset dataset, IEnumerable<int> rows) {
+      foreach (var estimatedValuesVector in GetEstimatedClassValueVectors(dataset, rows)) {
+        // return the class which is most often occuring
+        yield return
+          estimatedValuesVector
+          .GroupBy(x => x)
+          .OrderBy(g => -g.Count())
+          .Select(g => g.Key)
+          .First();
+      }
+    }
+
+    IClassificationSolution IClassificationModel.CreateClassificationSolution(IClassificationProblemData problemData) {
+      return new ClassificationEnsembleSolution(models, new ClassificationEnsembleProblemData(problemData));
+    }
+    #endregion
+  }
+}
Index: branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ClassificationEnsembleProblemData.cs
===================================================================
--- branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ClassificationEnsembleProblemData.cs	(revision 9073)
+++ branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ClassificationEnsembleProblemData.cs	(revision 9073)
@@ -0,0 +1,87 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Collections.Generic;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  [StorableClass]
+  [Item("ClassificationEnsembleProblemData", "Represents an item containing all data defining a classification problem.")]
+  public class ClassificationEnsembleProblemData : ClassificationProblemData {
+
+    public override bool IsTrainingSample(int index) {
+      return index >= 0 && index < Dataset.Rows &&
+             TrainingPartition.Start <= index && index < TrainingPartition.End;
+    }
+
+    public override bool IsTestSample(int index) {
+      return index >= 0 && index < Dataset.Rows &&
+             TestPartition.Start <= index && index < TestPartition.End;
+    }
+
+    private static readonly ClassificationEnsembleProblemData emptyProblemData;
+    public static new ClassificationEnsembleProblemData EmptyProblemData {
+      get { return emptyProblemData; }
+    }
+
+    static ClassificationEnsembleProblemData() {
+      var problemData = new ClassificationEnsembleProblemData();
+      problemData.Parameters.Clear();
+      problemData.Name = "Empty Classification ProblemData";
+      problemData.Description = "This ProblemData acts as place holder before the correct problem data is loaded.";
+      problemData.isEmpty = true;
+
+      problemData.Parameters.Add(new FixedValueParameter<Dataset>(DatasetParameterName, "", new Dataset()));
+      problemData.Parameters.Add(new FixedValueParameter<ReadOnlyCheckedItemList<StringValue>>(InputVariablesParameterName, ""));
+      problemData.Parameters.Add(new FixedValueParameter<IntRange>(TrainingPartitionParameterName, "", (IntRange)new IntRange(0, 0).AsReadOnly()));
+      problemData.Parameters.Add(new FixedValueParameter<IntRange>(TestPartitionParameterName, "", (IntRange)new IntRange(0, 0).AsReadOnly()));
+      problemData.Parameters.Add(new ConstrainedValueParameter<StringValue>(TargetVariableParameterName, new ItemSet<StringValue>()));
+      problemData.Parameters.Add(new FixedValueParameter<StringMatrix>(ClassNamesParameterName, "", new StringMatrix(0, 0).AsReadOnly()));
+      problemData.Parameters.Add(new FixedValueParameter<DoubleMatrix>(ClassificationPenaltiesParameterName, "", (DoubleMatrix)new DoubleMatrix(0, 0).AsReadOnly()));
+      emptyProblemData = problemData;
+    }
+
+    [StorableConstructor]
+    protected ClassificationEnsembleProblemData(bool deserializing) : base(deserializing) { }
+    protected ClassificationEnsembleProblemData(ClassificationEnsembleProblemData original, Cloner cloner) : base(original, cloner) { }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      if (this == emptyProblemData) return emptyProblemData;
+      return new ClassificationEnsembleProblemData(this, cloner);
+    }
+
+    public ClassificationEnsembleProblemData() : base() { }
+    public ClassificationEnsembleProblemData(IClassificationProblemData classificationProblemData)
+      : base(classificationProblemData.Dataset, classificationProblemData.AllowedInputVariables, classificationProblemData.TargetVariable) {
+      this.TrainingPartition.Start = classificationProblemData.TrainingPartition.Start;
+      this.TrainingPartition.End = classificationProblemData.TrainingPartition.End;
+      this.TestPartition.Start = classificationProblemData.TestPartition.Start;
+      this.TestPartition.End = classificationProblemData.TestPartition.End;
+    }
+
+    public ClassificationEnsembleProblemData(Dataset dataset, IEnumerable<string> allowedInputVariables, string targetVariable)
+      : base(dataset, allowedInputVariables, targetVariable) {
+    }
+  }
+}
Index: branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ClassificationEnsembleSolution.cs
===================================================================
--- branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ClassificationEnsembleSolution.cs	(revision 9073)
+++ branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ClassificationEnsembleSolution.cs	(revision 9073)
@@ -0,0 +1,337 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Collections;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  /// <summary>
+  /// Represents classification solutions that contain an ensemble of multiple classification models
+  /// </summary>
+  [StorableClass]
+  [Item("Classification Ensemble Solution", "A classification solution that contains an ensemble of multiple classification models")]
+  [Creatable("Data Analysis - Ensembles")]
+  public sealed class ClassificationEnsembleSolution : ClassificationSolutionBase, IClassificationEnsembleSolution {
+    private readonly Dictionary<int, double> trainingEvaluationCache = new Dictionary<int, double>();
+    private readonly Dictionary<int, double> testEvaluationCache = new Dictionary<int, double>();
+    private readonly Dictionary<int, double> evaluationCache = new Dictionary<int, double>();
+
+    public new IClassificationEnsembleModel Model {
+      get { return (IClassificationEnsembleModel)base.Model; }
+    }
+    public new ClassificationEnsembleProblemData ProblemData {
+      get { return (ClassificationEnsembleProblemData)base.ProblemData; }
+      set { base.ProblemData = value; }
+    }
+
+    private readonly ItemCollection<IClassificationSolution> classificationSolutions;
+    public IItemCollection<IClassificationSolution> ClassificationSolutions {
+      get { return classificationSolutions; }
+    }
+
+    [Storable]
+    private Dictionary<IClassificationModel, IntRange> trainingPartitions;
+    [Storable]
+    private Dictionary<IClassificationModel, IntRange> testPartitions;
+
+    [StorableConstructor]
+    private ClassificationEnsembleSolution(bool deserializing)
+      : base(deserializing) {
+      classificationSolutions = new ItemCollection<IClassificationSolution>();
+    }
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() {
+      foreach (var model in Model.Models) {
+        IClassificationProblemData problemData = (IClassificationProblemData)ProblemData.Clone();
+        problemData.TrainingPartition.Start = trainingPartitions[model].Start;
+        problemData.TrainingPartition.End = trainingPartitions[model].End;
+        problemData.TestPartition.Start = testPartitions[model].Start;
+        problemData.TestPartition.End = testPartitions[model].End;
+
+        classificationSolutions.Add(model.CreateClassificationSolution(problemData));
+      }
+      RegisterClassificationSolutionsEventHandler();
+    }
+
+    private ClassificationEnsembleSolution(ClassificationEnsembleSolution original, Cloner cloner)
+      : base(original, cloner) {
+      trainingPartitions = new Dictionary<IClassificationModel, IntRange>();
+      testPartitions = new Dictionary<IClassificationModel, IntRange>();
+      foreach (var pair in original.trainingPartitions) {
+        trainingPartitions[cloner.Clone(pair.Key)] = cloner.Clone(pair.Value);
+      }
+      foreach (var pair in original.testPartitions) {
+        testPartitions[cloner.Clone(pair.Key)] = cloner.Clone(pair.Value);
+      }
+
+      trainingEvaluationCache = new Dictionary<int, double>(original.ProblemData.TrainingIndices.Count());
+      testEvaluationCache = new Dictionary<int, double>(original.ProblemData.TestIndices.Count());
+
+      classificationSolutions = cloner.Clone(original.classificationSolutions);
+      RegisterClassificationSolutionsEventHandler();
+    }
+
+    public ClassificationEnsembleSolution()
+      : base(new ClassificationEnsembleModel(), ClassificationEnsembleProblemData.EmptyProblemData) {
+      trainingPartitions = new Dictionary<IClassificationModel, IntRange>();
+      testPartitions = new Dictionary<IClassificationModel, IntRange>();
+      classificationSolutions = new ItemCollection<IClassificationSolution>();
+
+      RegisterClassificationSolutionsEventHandler();
+    }
+
+    public ClassificationEnsembleSolution(IClassificationProblemData problemData) :
+      this(Enumerable.Empty<IClassificationModel>(), problemData) { }
+
+    public ClassificationEnsembleSolution(IEnumerable<IClassificationModel> models, IClassificationProblemData problemData)
+      : this(models, problemData,
+             models.Select(m => (IntRange)problemData.TrainingPartition.Clone()),
+             models.Select(m => (IntRange)problemData.TestPartition.Clone())
+      ) { }
+
+    public ClassificationEnsembleSolution(IEnumerable<IClassificationModel> models, IClassificationProblemData problemData, IEnumerable<IntRange> trainingPartitions, IEnumerable<IntRange> testPartitions)
+      : base(new ClassificationEnsembleModel(Enumerable.Empty<IClassificationModel>()), new ClassificationEnsembleProblemData(problemData)) {
+      this.trainingPartitions = new Dictionary<IClassificationModel, IntRange>();
+      this.testPartitions = new Dictionary<IClassificationModel, IntRange>();
+      this.classificationSolutions = new ItemCollection<IClassificationSolution>();
+
+      List<IClassificationSolution> solutions = new List<IClassificationSolution>();
+      var modelEnumerator = models.GetEnumerator();
+      var trainingPartitionEnumerator = trainingPartitions.GetEnumerator();
+      var testPartitionEnumerator = testPartitions.GetEnumerator();
+
+      while (modelEnumerator.MoveNext() & trainingPartitionEnumerator.MoveNext() & testPartitionEnumerator.MoveNext()) {
+        var p = (IClassificationProblemData)problemData.Clone();
+        p.TrainingPartition.Start = trainingPartitionEnumerator.Current.Start;
+        p.TrainingPartition.End = trainingPartitionEnumerator.Current.End;
+        p.TestPartition.Start = testPartitionEnumerator.Current.Start;
+        p.TestPartition.End = testPartitionEnumerator.Current.End;
+
+        solutions.Add(modelEnumerator.Current.CreateClassificationSolution(p));
+      }
+      if (modelEnumerator.MoveNext() | trainingPartitionEnumerator.MoveNext() | testPartitionEnumerator.MoveNext()) {
+        throw new ArgumentException();
+      }
+
+      trainingEvaluationCache = new Dictionary<int, double>(problemData.TrainingIndices.Count());
+      testEvaluationCache = new Dictionary<int, double>(problemData.TestIndices.Count());
+
+      RegisterClassificationSolutionsEventHandler();
+      classificationSolutions.AddRange(solutions);
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new ClassificationEnsembleSolution(this, cloner);
+    }
+    private void RegisterClassificationSolutionsEventHandler() {
+      classificationSolutions.ItemsAdded += new CollectionItemsChangedEventHandler<IClassificationSolution>(classificationSolutions_ItemsAdded);
+      classificationSolutions.ItemsRemoved += new CollectionItemsChangedEventHandler<IClassificationSolution>(classificationSolutions_ItemsRemoved);
+      classificationSolutions.CollectionReset += new CollectionItemsChangedEventHandler<IClassificationSolution>(classificationSolutions_CollectionReset);
+    }
+
+
+    #region Evaluation
+    public override IEnumerable<double> EstimatedClassValues {
+      get { return GetEstimatedClassValues(Enumerable.Range(0, ProblemData.Dataset.Rows)); }
+    }
+
+    public override IEnumerable<double> EstimatedTrainingClassValues {
+      get {
+        var rows = ProblemData.TrainingIndices;
+        var rowsToEvaluate = rows.Except(trainingEvaluationCache.Keys);
+        var rowsEnumerator = rowsToEvaluate.GetEnumerator();
+        var valuesEnumerator = GetEstimatedValues(rowsToEvaluate, (r, m) => RowIsTrainingForModel(r, m) && !RowIsTestForModel(r, m)).GetEnumerator();
+
+        while (rowsEnumerator.MoveNext() & valuesEnumerator.MoveNext()) {
+          trainingEvaluationCache.Add(rowsEnumerator.Current, valuesEnumerator.Current);
+        }
+
+        return rows.Select(row => trainingEvaluationCache[row]);
+      }
+    }
+
+    public override IEnumerable<double> EstimatedTestClassValues {
+      get {
+        var rows = ProblemData.TestIndices;
+        var rowsToEvaluate = rows.Except(testEvaluationCache.Keys);
+        var rowsEnumerator = rowsToEvaluate.GetEnumerator();
+        var valuesEnumerator = GetEstimatedValues(rowsToEvaluate, RowIsTestForModel).GetEnumerator();
+
+        while (rowsEnumerator.MoveNext() & valuesEnumerator.MoveNext()) {
+          testEvaluationCache.Add(rowsEnumerator.Current, valuesEnumerator.Current);
+        }
+
+        return rows.Select(row => testEvaluationCache[row]);
+      }
+    }
+
+    private IEnumerable<double> GetEstimatedValues(IEnumerable<int> rows, Func<int, IClassificationModel, bool> modelSelectionPredicate) {
+      var estimatedValuesEnumerators = (from model in Model.Models
+                                        select new { Model = model, EstimatedValuesEnumerator = model.GetEstimatedClassValues(ProblemData.Dataset, rows).GetEnumerator() })
+                                       .ToList();
+      var rowsEnumerator = rows.GetEnumerator();
+      // aggregate to make sure that MoveNext is called for all enumerators 
+      while (rowsEnumerator.MoveNext() & estimatedValuesEnumerators.Select(en => en.EstimatedValuesEnumerator.MoveNext()).Aggregate(true, (acc, b) => acc & b)) {
+        int currentRow = rowsEnumerator.Current;
+
+        var selectedEnumerators = from pair in estimatedValuesEnumerators
+                                  where modelSelectionPredicate(currentRow, pair.Model)
+                                  select pair.EstimatedValuesEnumerator;
+
+        yield return AggregateEstimatedClassValues(selectedEnumerators.Select(x => x.Current));
+      }
+    }
+
+    private bool RowIsTrainingForModel(int currentRow, IClassificationModel model) {
+      return trainingPartitions == null || !trainingPartitions.ContainsKey(model) ||
+              (trainingPartitions[model].Start <= currentRow && currentRow < trainingPartitions[model].End);
+    }
+
+    private bool RowIsTestForModel(int currentRow, IClassificationModel model) {
+      return testPartitions == null || !testPartitions.ContainsKey(model) ||
+              (testPartitions[model].Start <= currentRow && currentRow < testPartitions[model].End);
+    }
+
+    public override IEnumerable<double> GetEstimatedClassValues(IEnumerable<int> rows) {
+      var rowsToEvaluate = rows.Except(evaluationCache.Keys);
+      var rowsEnumerator = rowsToEvaluate.GetEnumerator();
+      var valuesEnumerator = (from xs in GetEstimatedClassValueVectors(ProblemData.Dataset, rowsToEvaluate)
+                              select AggregateEstimatedClassValues(xs))
+                             .GetEnumerator();
+
+      while (rowsEnumerator.MoveNext() & valuesEnumerator.MoveNext()) {
+        evaluationCache.Add(rowsEnumerator.Current, valuesEnumerator.Current);
+      }
+
+      return rows.Select(row => evaluationCache[row]);
+    }
+
+    public IEnumerable<IEnumerable<double>> GetEstimatedClassValueVectors(Dataset dataset, IEnumerable<int> rows) {
+      if (!Model.Models.Any()) yield break;
+      var estimatedValuesEnumerators = (from model in Model.Models
+                                        select model.GetEstimatedClassValues(dataset, rows).GetEnumerator())
+                                       .ToList();
+
+      while (estimatedValuesEnumerators.All(en => en.MoveNext())) {
+        yield return from enumerator in estimatedValuesEnumerators
+                     select enumerator.Current;
+      }
+    }
+
+    private double AggregateEstimatedClassValues(IEnumerable<double> estimatedClassValues) {
+      return estimatedClassValues
+      .GroupBy(x => x)
+      .OrderBy(g => -g.Count())
+      .Select(g => g.Key)
+      .DefaultIfEmpty(double.NaN)
+      .First();
+    }
+    #endregion
+
+    protected override void OnProblemDataChanged() {
+      trainingEvaluationCache.Clear();
+      testEvaluationCache.Clear();
+      evaluationCache.Clear();
+
+      IClassificationProblemData problemData = new ClassificationProblemData(ProblemData.Dataset,
+                                                                     ProblemData.AllowedInputVariables,
+                                                                     ProblemData.TargetVariable);
+      problemData.TrainingPartition.Start = ProblemData.TrainingPartition.Start;
+      problemData.TrainingPartition.End = ProblemData.TrainingPartition.End;
+      problemData.TestPartition.Start = ProblemData.TestPartition.Start;
+      problemData.TestPartition.End = ProblemData.TestPartition.End;
+
+      foreach (var solution in ClassificationSolutions) {
+        if (solution is ClassificationEnsembleSolution)
+          solution.ProblemData = ProblemData;
+        else
+          solution.ProblemData = problemData;
+      }
+      foreach (var trainingPartition in trainingPartitions.Values) {
+        trainingPartition.Start = ProblemData.TrainingPartition.Start;
+        trainingPartition.End = ProblemData.TrainingPartition.End;
+      }
+      foreach (var testPartition in testPartitions.Values) {
+        testPartition.Start = ProblemData.TestPartition.Start;
+        testPartition.End = ProblemData.TestPartition.End;
+      }
+
+      base.OnProblemDataChanged();
+    }
+
+    public void AddClassificationSolutions(IEnumerable<IClassificationSolution> solutions) {
+      classificationSolutions.AddRange(solutions);
+
+      trainingEvaluationCache.Clear();
+      testEvaluationCache.Clear();
+      evaluationCache.Clear();
+    }
+    public void RemoveClassificationSolutions(IEnumerable<IClassificationSolution> solutions) {
+      classificationSolutions.RemoveRange(solutions);
+
+      trainingEvaluationCache.Clear();
+      testEvaluationCache.Clear();
+      evaluationCache.Clear();
+    }
+
+    private void classificationSolutions_ItemsAdded(object sender, CollectionItemsChangedEventArgs<IClassificationSolution> e) {
+      foreach (var solution in e.Items) AddClassificationSolution(solution);
+      RecalculateResults();
+    }
+    private void classificationSolutions_ItemsRemoved(object sender, CollectionItemsChangedEventArgs<IClassificationSolution> e) {
+      foreach (var solution in e.Items) RemoveClassificationSolution(solution);
+      RecalculateResults();
+    }
+    private void classificationSolutions_CollectionReset(object sender, CollectionItemsChangedEventArgs<IClassificationSolution> e) {
+      foreach (var solution in e.OldItems) RemoveClassificationSolution(solution);
+      foreach (var solution in e.Items) AddClassificationSolution(solution);
+      RecalculateResults();
+    }
+
+    private void AddClassificationSolution(IClassificationSolution solution) {
+      if (Model.Models.Contains(solution.Model)) throw new ArgumentException();
+      Model.Add(solution.Model);
+      trainingPartitions[solution.Model] = solution.ProblemData.TrainingPartition;
+      testPartitions[solution.Model] = solution.ProblemData.TestPartition;
+
+      trainingEvaluationCache.Clear();
+      testEvaluationCache.Clear();
+      evaluationCache.Clear();
+    }
+
+    private void RemoveClassificationSolution(IClassificationSolution solution) {
+      if (!Model.Models.Contains(solution.Model)) throw new ArgumentException();
+      Model.Remove(solution.Model);
+      trainingPartitions.Remove(solution.Model);
+      testPartitions.Remove(solution.Model);
+
+      trainingEvaluationCache.Clear();
+      testEvaluationCache.Clear();
+      evaluationCache.Clear();
+    }
+  }
+}
Index: branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ClassificationProblem.cs
===================================================================
--- branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ClassificationProblem.cs	(revision 9073)
+++ branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ClassificationProblem.cs	(revision 9073)
@@ -0,0 +1,43 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  [StorableClass]
+  [Item("Classification Problem", "A general classification problem.")]
+  [Creatable("Problems")]
+  public class ClassificationProblem : DataAnalysisProblem<IClassificationProblemData>, IClassificationProblem, IStorableContent {
+    public string Filename { get; set; }
+
+    [StorableConstructor]
+    protected ClassificationProblem(bool deserializing) : base(deserializing) { }
+    protected ClassificationProblem(ClassificationProblem original, Cloner cloner) : base(original, cloner) { }
+    public override IDeepCloneable Clone(Cloner cloner) { return new ClassificationProblem(this, cloner); }
+
+    public ClassificationProblem()
+      : base() {
+      ProblemData = new ClassificationProblemData();
+    }
+  }
+}
Index: branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ClassificationProblemData.cs
===================================================================
--- branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ClassificationProblemData.cs	(revision 9073)
+++ branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ClassificationProblemData.cs	(revision 9073)
@@ -0,0 +1,411 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  [StorableClass]
+  [Item("ClassificationProblemData", "Represents an item containing all data defining a classification problem.")]
+  public class ClassificationProblemData : DataAnalysisProblemData, IClassificationProblemData, IStorableContent {
+    protected const string TargetVariableParameterName = "TargetVariable";
+    protected const string ClassNamesParameterName = "ClassNames";
+    protected const string ClassificationPenaltiesParameterName = "ClassificationPenalties";
+    protected const int MaximumNumberOfClasses = 100;
+    protected const int InspectedRowsToDetermineTargets = 2000;
+
+    public string Filename { get; set; }
+
+    #region default data
+    private static string[] defaultVariableNames = new string[] { "sample", "clump thickness", "cell size", "cell shape", "marginal adhesion", "epithelial cell size", "bare nuclei", "chromatin", "nucleoli", "mitoses", "class" };
+    private static double[,] defaultData = new double[,]{
+     {1000025,5,1,1,1,2,1,3,1,1,2      },
+     {1002945,5,4,4,5,7,10,3,2,1,2     },
+     {1015425,3,1,1,1,2,2,3,1,1,2      },
+     {1016277,6,8,8,1,3,4,3,7,1,2      },
+     {1017023,4,1,1,3,2,1,3,1,1,2      },
+     {1017122,8,10,10,8,7,10,9,7,1,4   },
+     {1018099,1,1,1,1,2,10,3,1,1,2     },
+     {1018561,2,1,2,1,2,1,3,1,1,2      },
+     {1033078,2,1,1,1,2,1,1,1,5,2      },
+     {1033078,4,2,1,1,2,1,2,1,1,2      },
+     {1035283,1,1,1,1,1,1,3,1,1,2      },
+     {1036172,2,1,1,1,2,1,2,1,1,2      },
+     {1041801,5,3,3,3,2,3,4,4,1,4      },
+     {1043999,1,1,1,1,2,3,3,1,1,2      },
+     {1044572,8,7,5,10,7,9,5,5,4,4     },
+     {1047630,7,4,6,4,6,1,4,3,1,4      },
+     {1048672,4,1,1,1,2,1,2,1,1,2      },
+     {1049815,4,1,1,1,2,1,3,1,1,2      },
+     {1050670,10,7,7,6,4,10,4,1,2,4    },
+     {1050718,6,1,1,1,2,1,3,1,1,2      },
+     {1054590,7,3,2,10,5,10,5,4,4,4    },
+     {1054593,10,5,5,3,6,7,7,10,1,4    },
+     {1056784,3,1,1,1,2,1,2,1,1,2      },
+     {1057013,8,4,5,1,2,2,7,3,1,4      },
+     {1059552,1,1,1,1,2,1,3,1,1,2      },
+     {1065726,5,2,3,4,2,7,3,6,1,4      },
+     {1066373,3,2,1,1,1,1,2,1,1,2      },
+     {1066979,5,1,1,1,2,1,2,1,1,2      },
+     {1067444,2,1,1,1,2,1,2,1,1,2      },
+     {1070935,1,1,3,1,2,1,1,1,1,2      },
+     {1070935,3,1,1,1,1,1,2,1,1,2      },
+     {1071760,2,1,1,1,2,1,3,1,1,2      },
+     {1072179,10,7,7,3,8,5,7,4,3,4     },
+     {1074610,2,1,1,2,2,1,3,1,1,2      },
+     {1075123,3,1,2,1,2,1,2,1,1,2      },
+     {1079304,2,1,1,1,2,1,2,1,1,2      },
+     {1080185,10,10,10,8,6,1,8,9,1,4   },
+     {1081791,6,2,1,1,1,1,7,1,1,2      },
+     {1084584,5,4,4,9,2,10,5,6,1,4     },
+     {1091262,2,5,3,3,6,7,7,5,1,4      },
+     {1096800,6,6,6,9,6,4,7,8,1,2      },
+     {1099510,10,4,3,1,3,3,6,5,2,4     },
+     {1100524,6,10,10,2,8,10,7,3,3,4   },
+     {1102573,5,6,5,6,10,1,3,1,1,4     },
+     {1103608,10,10,10,4,8,1,8,10,1,4  },
+     {1103722,1,1,1,1,2,1,2,1,2,2      },
+     {1105257,3,7,7,4,4,9,4,8,1,4      },
+     {1105524,1,1,1,1,2,1,2,1,1,2      },
+     {1106095,4,1,1,3,2,1,3,1,1,2      },
+     {1106829,7,8,7,2,4,8,3,8,2,4      },
+     {1108370,9,5,8,1,2,3,2,1,5,4      },
+     {1108449,5,3,3,4,2,4,3,4,1,4      },
+     {1110102,10,3,6,2,3,5,4,10,2,4    },
+     {1110503,5,5,5,8,10,8,7,3,7,4     },
+     {1110524,10,5,5,6,8,8,7,1,1,4     },
+     {1111249,10,6,6,3,4,5,3,6,1,4     },
+     {1112209,8,10,10,1,3,6,3,9,1,4    },
+     {1113038,8,2,4,1,5,1,5,4,4,4      },
+     {1113483,5,2,3,1,6,10,5,1,1,4     },
+     {1113906,9,5,5,2,2,2,5,1,1,4      },
+     {1115282,5,3,5,5,3,3,4,10,1,4     },
+     {1115293,1,1,1,1,2,2,2,1,1,2      },
+     {1116116,9,10,10,1,10,8,3,3,1,4   },
+     {1116132,6,3,4,1,5,2,3,9,1,4      },
+     {1116192,1,1,1,1,2,1,2,1,1,2      },
+     {1116998,10,4,2,1,3,2,4,3,10,4    },
+     {1117152,4,1,1,1,2,1,3,1,1,2      },
+     {1118039,5,3,4,1,8,10,4,9,1,4     },
+     {1120559,8,3,8,3,4,9,8,9,8,4      },
+     {1121732,1,1,1,1,2,1,3,2,1,2      },
+     {1121919,5,1,3,1,2,1,2,1,1,2      },
+     {1123061,6,10,2,8,10,2,7,8,10,4   },
+     {1124651,1,3,3,2,2,1,7,2,1,2      },
+     {1125035,9,4,5,10,6,10,4,8,1,4    },
+     {1126417,10,6,4,1,3,4,3,2,3,4     },
+     {1131294,1,1,2,1,2,2,4,2,1,2      },
+     {1132347,1,1,4,1,2,1,2,1,1,2      },
+     {1133041,5,3,1,2,2,1,2,1,1,2      },
+     {1133136,3,1,1,1,2,3,3,1,1,2      },
+     {1136142,2,1,1,1,3,1,2,1,1,2      },
+     {1137156,2,2,2,1,1,1,7,1,1,2      },
+     {1143978,4,1,1,2,2,1,2,1,1,2      },
+     {1143978,5,2,1,1,2,1,3,1,1,2      },
+     {1147044,3,1,1,1,2,2,7,1,1,2      },
+     {1147699,3,5,7,8,8,9,7,10,7,4     },
+     {1147748,5,10,6,1,10,4,4,10,10,4  },
+     {1148278,3,3,6,4,5,8,4,4,1,4      },
+     {1148873,3,6,6,6,5,10,6,8,3,4     },
+     {1152331,4,1,1,1,2,1,3,1,1,2      },
+     {1155546,2,1,1,2,3,1,2,1,1,2      },
+     {1156272,1,1,1,1,2,1,3,1,1,2      },
+     {1156948,3,1,1,2,2,1,1,1,1,2      },
+     {1157734,4,1,1,1,2,1,3,1,1,2      },
+     {1158247,1,1,1,1,2,1,2,1,1,2      },
+     {1160476,2,1,1,1,2,1,3,1,1,2      },
+     {1164066,1,1,1,1,2,1,3,1,1,2      },
+     {1165297,2,1,1,2,2,1,1,1,1,2      },
+     {1165790,5,1,1,1,2,1,3,1,1,2      },
+     {1165926,9,6,9,2,10,6,2,9,10,4    },
+     {1166630,7,5,6,10,5,10,7,9,4,4    },
+     {1166654,10,3,5,1,10,5,3,10,2,4   },
+     {1167439,2,3,4,4,2,5,2,5,1,4      },
+     {1167471,4,1,2,1,2,1,3,1,1,2      },
+     {1168359,8,2,3,1,6,3,7,1,1,4      },
+     {1168736,10,10,10,10,10,1,8,8,8,4 },
+     {1169049,7,3,4,4,3,3,3,2,7,4      },
+     {1170419,10,10,10,8,2,10,4,1,1,4  },
+     {1170420,1,6,8,10,8,10,5,7,1,4    },
+     {1171710,1,1,1,1,2,1,2,3,1,2      },
+     {1171710,6,5,4,4,3,9,7,8,3,4      },
+     {1171795,1,3,1,2,2,2,5,3,2,2      },
+     {1171845,8,6,4,3,5,9,3,1,1,4      },
+     {1172152,10,3,3,10,2,10,7,3,3,4   },
+     {1173216,10,10,10,3,10,8,8,1,1,4  },
+     {1173235,3,3,2,1,2,3,3,1,1,2      },
+     {1173347,1,1,1,1,2,5,1,1,1,2      },
+     {1173347,8,3,3,1,2,2,3,2,1,2      },
+     {1173509,4,5,5,10,4,10,7,5,8,4    },
+     {1173514,1,1,1,1,4,3,1,1,1,2      },
+     {1173681,3,2,1,1,2,2,3,1,1,2      },
+     {1174057,1,1,2,2,2,1,3,1,1,2      },
+     {1174057,4,2,1,1,2,2,3,1,1,2      },
+     {1174131,10,10,10,2,10,10,5,3,3,4 },
+     {1174428,5,3,5,1,8,10,5,3,1,4     },
+     {1175937,5,4,6,7,9,7,8,10,1,4     },
+     {1176406,1,1,1,1,2,1,2,1,1,2      },
+     {1176881,7,5,3,7,4,10,7,5,5,4        }
+};
+    private static readonly Dataset defaultDataset;
+    private static readonly IEnumerable<string> defaultAllowedInputVariables;
+    private static readonly string defaultTargetVariable;
+
+    private static readonly ClassificationProblemData emptyProblemData;
+    public static ClassificationProblemData EmptyProblemData {
+      get { return EmptyProblemData; }
+    }
+
+    static ClassificationProblemData() {
+      defaultDataset = new Dataset(defaultVariableNames, defaultData);
+      defaultDataset.Name = "Wisconsin classification problem";
+      defaultDataset.Description = "subset from to ..";
+
+      defaultAllowedInputVariables = defaultVariableNames.Except(new List<string>() { "sample", "class" });
+      defaultTargetVariable = "class";
+
+      var problemData = new ClassificationProblemData();
+      problemData.Parameters.Clear();
+      problemData.Name = "Empty Classification ProblemData";
+      problemData.Description = "This ProblemData acts as place holder before the correct problem data is loaded.";
+      problemData.isEmpty = true;
+
+      problemData.Parameters.Add(new FixedValueParameter<Dataset>(DatasetParameterName, "", new Dataset()));
+      problemData.Parameters.Add(new FixedValueParameter<ReadOnlyCheckedItemList<StringValue>>(InputVariablesParameterName, ""));
+      problemData.Parameters.Add(new FixedValueParameter<IntRange>(TrainingPartitionParameterName, "", (IntRange)new IntRange(0, 0).AsReadOnly()));
+      problemData.Parameters.Add(new FixedValueParameter<IntRange>(TestPartitionParameterName, "", (IntRange)new IntRange(0, 0).AsReadOnly()));
+      problemData.Parameters.Add(new ConstrainedValueParameter<StringValue>(TargetVariableParameterName, new ItemSet<StringValue>()));
+      problemData.Parameters.Add(new FixedValueParameter<StringMatrix>(ClassNamesParameterName, "", new StringMatrix(0, 0).AsReadOnly()));
+      problemData.Parameters.Add(new FixedValueParameter<DoubleMatrix>(ClassificationPenaltiesParameterName, "", (DoubleMatrix)new DoubleMatrix(0, 0).AsReadOnly()));
+      emptyProblemData = problemData;
+    }
+    #endregion
+
+    #region parameter properties
+    public IConstrainedValueParameter<StringValue> TargetVariableParameter {
+      get { return (IConstrainedValueParameter<StringValue>)Parameters[TargetVariableParameterName]; }
+    }
+    public IFixedValueParameter<StringMatrix> ClassNamesParameter {
+      get { return (IFixedValueParameter<StringMatrix>)Parameters[ClassNamesParameterName]; }
+    }
+    public IFixedValueParameter<DoubleMatrix> ClassificationPenaltiesParameter {
+      get { return (IFixedValueParameter<DoubleMatrix>)Parameters[ClassificationPenaltiesParameterName]; }
+    }
+    #endregion
+
+    #region properties
+    public string TargetVariable {
+      get { return TargetVariableParameter.Value.Value; }
+    }
+
+    private List<double> classValuesCache;
+    private List<double> ClassValuesCache {
+      get {
+        if (classValuesCache == null) {
+          classValuesCache = Dataset.GetDoubleValues(TargetVariableParameter.Value.Value).Distinct().OrderBy(x => x).ToList();
+        }
+        return classValuesCache;
+      }
+    }
+    public IEnumerable<double> ClassValues {
+      get { return ClassValuesCache; }
+    }
+    public int Classes {
+      get { return ClassValuesCache.Count; }
+    }
+
+    private List<string> classNamesCache;
+    private List<string> ClassNamesCache {
+      get {
+        if (classNamesCache == null) {
+          classNamesCache = new List<string>();
+          for (int i = 0; i < ClassNamesParameter.Value.Rows; i++)
+            classNamesCache.Add(ClassNamesParameter.Value[i, 0]);
+        }
+        return classNamesCache;
+      }
+    }
+    public IEnumerable<string> ClassNames {
+      get { return ClassNamesCache; }
+    }
+    #endregion
+
+
+    [StorableConstructor]
+    protected ClassificationProblemData(bool deserializing) : base(deserializing) { }
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() {
+      RegisterParameterEvents();
+    }
+
+    protected ClassificationProblemData(ClassificationProblemData original, Cloner cloner)
+      : base(original, cloner) {
+      RegisterParameterEvents();
+    }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      if (this == emptyProblemData) return emptyProblemData;
+      return new ClassificationProblemData(this, cloner);
+    }
+
+    public ClassificationProblemData() : this(defaultDataset, defaultAllowedInputVariables, defaultTargetVariable) { }
+
+    public ClassificationProblemData(IClassificationProblemData classificationProblemData)
+      : this(classificationProblemData.Dataset, classificationProblemData.AllowedInputVariables, classificationProblemData.TargetVariable) {
+      TrainingPartition.Start = classificationProblemData.TrainingPartition.Start;
+      TrainingPartition.End = classificationProblemData.TrainingPartition.End;
+      TestPartition.Start = classificationProblemData.TestPartition.Start;
+      TestPartition.End = classificationProblemData.TestPartition.End;
+
+      for (int i = 0; i < classificationProblemData.ClassNames.Count(); i++)
+        ClassNamesParameter.Value[i, 0] = classificationProblemData.ClassNames.ElementAt(i);
+
+      for (int i = 0; i < Classes; i++) {
+        for (int j = 0; j < Classes; j++) {
+          ClassificationPenaltiesParameter.Value[i, j] = classificationProblemData.GetClassificationPenalty(ClassValuesCache[i], ClassValuesCache[j]);
+        }
+      }
+    }
+
+    public ClassificationProblemData(Dataset dataset, IEnumerable<string> allowedInputVariables, string targetVariable)
+      : base(dataset, allowedInputVariables) {
+      var validTargetVariableValues = CheckVariablesForPossibleTargetVariables(dataset).Select(x => new StringValue(x).AsReadOnly()).ToList();
+      var target = validTargetVariableValues.Where(x => x.Value == targetVariable).DefaultIfEmpty(validTargetVariableValues.First()).First();
+
+      Parameters.Add(new ConstrainedValueParameter<StringValue>(TargetVariableParameterName, new ItemSet<StringValue>(validTargetVariableValues), target));
+      Parameters.Add(new FixedValueParameter<StringMatrix>(ClassNamesParameterName, ""));
+      Parameters.Add(new FixedValueParameter<DoubleMatrix>(ClassificationPenaltiesParameterName, ""));
+
+      RegisterParameterEvents();
+      ResetTargetVariableDependentMembers();
+    }
+
+    public static IEnumerable<string> CheckVariablesForPossibleTargetVariables(Dataset dataset) {
+      int maxSamples = Math.Min(InspectedRowsToDetermineTargets, dataset.Rows);
+      var validTargetVariables = (from v in dataset.DoubleVariables
+                                  let distinctValues = dataset.GetDoubleValues(v)
+                                    .Take(maxSamples)
+                                    .Distinct()
+                                    .Count()
+                                  where distinctValues < MaximumNumberOfClasses
+                                  select v).ToArray();
+
+      if (!validTargetVariables.Any())
+        throw new ArgumentException("Import of classification problem data was not successful, because no target variable was found." +
+          " A target variable must have at most " + MaximumNumberOfClasses + " distinct values to be applicable to classification.");
+      return validTargetVariables;
+    }
+
+
+    private void ResetTargetVariableDependentMembers() {
+      DeregisterParameterEvents();
+
+      ((IStringConvertibleMatrix)ClassNamesParameter.Value).Columns = 1;
+      ((IStringConvertibleMatrix)ClassNamesParameter.Value).Rows = ClassValuesCache.Count;
+      for (int i = 0; i < Classes; i++)
+        ClassNamesParameter.Value[i, 0] = "Class " + ClassValuesCache[i];
+      ClassNamesParameter.Value.ColumnNames = new List<string>() { "ClassNames" };
+      ClassNamesParameter.Value.RowNames = ClassValues.Select(s => "ClassValue: " + s);
+
+      ((IStringConvertibleMatrix)ClassificationPenaltiesParameter.Value).Rows = Classes;
+      ((IStringConvertibleMatrix)ClassificationPenaltiesParameter.Value).Columns = Classes;
+      ClassificationPenaltiesParameter.Value.RowNames = ClassNames.Select(name => "Actual " + name);
+      ClassificationPenaltiesParameter.Value.ColumnNames = ClassNames.Select(name => "Estimated " + name);
+      for (int i = 0; i < Classes; i++) {
+        for (int j = 0; j < Classes; j++) {
+          if (i != j) ClassificationPenaltiesParameter.Value[i, j] = 1;
+          else ClassificationPenaltiesParameter.Value[i, j] = 0;
+        }
+      }
+      RegisterParameterEvents();
+    }
+
+    public string GetClassName(double classValue) {
+      if (!ClassValuesCache.Contains(classValue)) throw new ArgumentException();
+      int index = ClassValuesCache.IndexOf(classValue);
+      return ClassNamesCache[index];
+    }
+    public double GetClassValue(string className) {
+      if (!ClassNamesCache.Contains(className)) throw new ArgumentException();
+      int index = ClassNamesCache.IndexOf(className);
+      return ClassValuesCache[index];
+    }
+    public void SetClassName(double classValue, string className) {
+      if (!ClassValuesCache.Contains(classValue)) throw new ArgumentException();
+      int index = ClassValuesCache.IndexOf(classValue);
+      ClassNamesParameter.Value[index, 0] = className;
+      // updating of class names cache is not necessary here as the parameter value fires a changed event which updates the cache
+    }
+
+    public double GetClassificationPenalty(string correctClassName, string estimatedClassName) {
+      return GetClassificationPenalty(GetClassValue(correctClassName), GetClassValue(estimatedClassName));
+    }
+    public double GetClassificationPenalty(double correctClassValue, double estimatedClassValue) {
+      int correctClassIndex = ClassValuesCache.IndexOf(correctClassValue);
+      int estimatedClassIndex = ClassValuesCache.IndexOf(estimatedClassValue);
+      return ClassificationPenaltiesParameter.Value[correctClassIndex, estimatedClassIndex];
+    }
+    public void SetClassificationPenalty(string correctClassName, string estimatedClassName, double penalty) {
+      SetClassificationPenalty(GetClassValue(correctClassName), GetClassValue(estimatedClassName), penalty);
+    }
+    public void SetClassificationPenalty(double correctClassValue, double estimatedClassValue, double penalty) {
+      int correctClassIndex = ClassValuesCache.IndexOf(correctClassValue);
+      int estimatedClassIndex = ClassValuesCache.IndexOf(estimatedClassValue);
+
+      ClassificationPenaltiesParameter.Value[correctClassIndex, estimatedClassIndex] = penalty;
+    }
+
+    #region events
+    private void RegisterParameterEvents() {
+      TargetVariableParameter.ValueChanged += new EventHandler(TargetVariableParameter_ValueChanged);
+      ClassNamesParameter.Value.Reset += new EventHandler(Parameter_ValueChanged);
+      ClassNamesParameter.Value.ItemChanged += new EventHandler<EventArgs<int, int>>(Parameter_ValueChanged);
+      ClassificationPenaltiesParameter.Value.ItemChanged += new EventHandler<EventArgs<int, int>>(Parameter_ValueChanged);
+      ClassificationPenaltiesParameter.Value.Reset += new EventHandler(Parameter_ValueChanged);
+    }
+    private void DeregisterParameterEvents() {
+      TargetVariableParameter.ValueChanged -= new EventHandler(TargetVariableParameter_ValueChanged);
+      ClassNamesParameter.Value.Reset -= new EventHandler(Parameter_ValueChanged);
+      ClassNamesParameter.Value.ItemChanged -= new EventHandler<EventArgs<int, int>>(Parameter_ValueChanged);
+      ClassificationPenaltiesParameter.Value.ItemChanged -= new EventHandler<EventArgs<int, int>>(Parameter_ValueChanged);
+      ClassificationPenaltiesParameter.Value.Reset -= new EventHandler(Parameter_ValueChanged);
+    }
+
+    private void TargetVariableParameter_ValueChanged(object sender, EventArgs e) {
+      classValuesCache = null;
+      classNamesCache = null;
+      ResetTargetVariableDependentMembers();
+      OnChanged();
+    }
+    private void Parameter_ValueChanged(object sender, EventArgs e) {
+      classNamesCache = null;
+      ClassificationPenaltiesParameter.Value.RowNames = ClassNames.Select(name => "Actual " + name);
+      ClassificationPenaltiesParameter.Value.ColumnNames = ClassNames.Select(name => "Estimated " + name);
+      OnChanged();
+    }
+    #endregion
+  }
+}
Index: branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ClassificationSolution.cs
===================================================================
--- branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ClassificationSolution.cs	(revision 9073)
+++ branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ClassificationSolution.cs	(revision 9073)
@@ -0,0 +1,82 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  /// <summary>
+  /// Represents a classification data analysis solution
+  /// </summary>
+  [StorableClass]
+  public abstract class ClassificationSolution : ClassificationSolutionBase {
+    protected readonly Dictionary<int, double> evaluationCache;
+
+    [StorableConstructor]
+    protected ClassificationSolution(bool deserializing)
+      : base(deserializing) {
+      evaluationCache = new Dictionary<int, double>();
+    }
+    protected ClassificationSolution(ClassificationSolution original, Cloner cloner)
+      : base(original, cloner) {
+      evaluationCache = new Dictionary<int, double>(original.evaluationCache);
+    }
+    public ClassificationSolution(IClassificationModel model, IClassificationProblemData problemData)
+      : base(model, problemData) {
+      evaluationCache = new Dictionary<int, double>(problemData.Dataset.Rows);
+      CalculateClassificationResults();
+    }
+
+    public override IEnumerable<double> EstimatedClassValues {
+      get { return GetEstimatedClassValues(Enumerable.Range(0, ProblemData.Dataset.Rows)); }
+    }
+    public override IEnumerable<double> EstimatedTrainingClassValues {
+      get { return GetEstimatedClassValues(ProblemData.TrainingIndices); }
+    }
+    public override IEnumerable<double> EstimatedTestClassValues {
+      get { return GetEstimatedClassValues(ProblemData.TestIndices); }
+    }
+
+    public override IEnumerable<double> GetEstimatedClassValues(IEnumerable<int> rows) {
+      var rowsToEvaluate = rows.Except(evaluationCache.Keys);
+      var rowsEnumerator = rowsToEvaluate.GetEnumerator();
+      var valuesEnumerator = Model.GetEstimatedClassValues(ProblemData.Dataset, rowsToEvaluate).GetEnumerator();
+
+      while (rowsEnumerator.MoveNext() & valuesEnumerator.MoveNext()) {
+        evaluationCache.Add(rowsEnumerator.Current, valuesEnumerator.Current);
+      }
+
+      return rows.Select(row => evaluationCache[row]);
+    }
+
+    protected override void OnProblemDataChanged() {
+      evaluationCache.Clear();
+      base.OnProblemDataChanged();
+    }
+
+    protected override void OnModelChanged() {
+      evaluationCache.Clear();
+      base.OnModelChanged();
+    }
+  }
+}
Index: branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ClassificationSolutionBase.cs
===================================================================
--- branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ClassificationSolutionBase.cs	(revision 9073)
+++ branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ClassificationSolutionBase.cs	(revision 9073)
@@ -0,0 +1,121 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Data;
+using HeuristicLab.Optimization;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  [StorableClass]
+  public abstract class ClassificationSolutionBase : DataAnalysisSolution, IClassificationSolution {
+    private const string TrainingAccuracyResultName = "Accuracy (training)";
+    private const string TestAccuracyResultName = "Accuracy (test)";
+    private const string TrainingNormalizedGiniCoefficientResultName = "Normalized Gini Coefficient (training)";
+    private const string TestNormalizedGiniCoefficientResultName = "Normalized Gini Coefficient (test)";
+
+    public new IClassificationModel Model {
+      get { return (IClassificationModel)base.Model; }
+      protected set { base.Model = value; }
+    }
+
+    public new IClassificationProblemData ProblemData {
+      get { return (IClassificationProblemData)base.ProblemData; }
+      set { base.ProblemData = value; }
+    }
+
+    #region Results
+    public double TrainingAccuracy {
+      get { return ((DoubleValue)this[TrainingAccuracyResultName].Value).Value; }
+      private set { ((DoubleValue)this[TrainingAccuracyResultName].Value).Value = value; }
+    }
+    public double TestAccuracy {
+      get { return ((DoubleValue)this[TestAccuracyResultName].Value).Value; }
+      private set { ((DoubleValue)this[TestAccuracyResultName].Value).Value = value; }
+    }
+    public double TrainingNormalizedGiniCoefficient {
+      get { return ((DoubleValue)this[TrainingNormalizedGiniCoefficientResultName].Value).Value; }
+      protected set { ((DoubleValue)this[TrainingNormalizedGiniCoefficientResultName].Value).Value = value; }
+    }
+    public double TestNormalizedGiniCoefficient {
+      get { return ((DoubleValue)this[TestNormalizedGiniCoefficientResultName].Value).Value; }
+      protected set { ((DoubleValue)this[TestNormalizedGiniCoefficientResultName].Value).Value = value; }
+    }
+    #endregion
+
+    [StorableConstructor]
+    protected ClassificationSolutionBase(bool deserializing) : base(deserializing) { }
+    protected ClassificationSolutionBase(ClassificationSolutionBase original, Cloner cloner)
+      : base(original, cloner) {
+    }
+    protected ClassificationSolutionBase(IClassificationModel model, IClassificationProblemData problemData)
+      : base(model, problemData) {
+      Add(new Result(TrainingAccuracyResultName, "Accuracy of the model on the training partition (percentage of correctly classified instances).", new PercentValue()));
+      Add(new Result(TestAccuracyResultName, "Accuracy of the model on the test partition (percentage of correctly classified instances).", new PercentValue()));
+      Add(new Result(TrainingNormalizedGiniCoefficientResultName, "Normalized Gini coefficient of the model on the training partition.", new DoubleValue()));
+      Add(new Result(TestNormalizedGiniCoefficientResultName, "Normalized Gini coefficient of the model on the test partition.", new DoubleValue()));
+    }
+
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() {
+      if (!this.ContainsKey(TrainingNormalizedGiniCoefficientResultName))
+        Add(new Result(TrainingNormalizedGiniCoefficientResultName, "Normalized Gini coefficient of the model on the training partition.", new DoubleValue()));
+      if (!this.ContainsKey(TestNormalizedGiniCoefficientResultName))
+        Add(new Result(TestNormalizedGiniCoefficientResultName, "Normalized Gini coefficient of the model on the test partition.", new DoubleValue()));
+    }
+
+    protected void CalculateClassificationResults() {
+      double[] estimatedTrainingClassValues = EstimatedTrainingClassValues.ToArray(); // cache values
+      double[] originalTrainingClassValues = ProblemData.Dataset.GetDoubleValues(ProblemData.TargetVariable, ProblemData.TrainingIndices).ToArray();
+      double[] estimatedTestClassValues = EstimatedTestClassValues.ToArray(); // cache values
+      double[] originalTestClassValues = ProblemData.Dataset.GetDoubleValues(ProblemData.TargetVariable, ProblemData.TestIndices).ToArray();
+
+      OnlineCalculatorError errorState;
+      double trainingAccuracy = OnlineAccuracyCalculator.Calculate(originalTrainingClassValues, estimatedTrainingClassValues, out errorState);
+      if (errorState != OnlineCalculatorError.None) trainingAccuracy = double.NaN;
+      double testAccuracy = OnlineAccuracyCalculator.Calculate(originalTestClassValues, estimatedTestClassValues, out errorState);
+      if (errorState != OnlineCalculatorError.None) testAccuracy = double.NaN;
+
+      TrainingAccuracy = trainingAccuracy;
+      TestAccuracy = testAccuracy;
+
+      double trainingNormalizedGini = NormalizedGiniCalculator.Calculate(originalTrainingClassValues, estimatedTrainingClassValues, out errorState);
+      if (errorState != OnlineCalculatorError.None) trainingNormalizedGini = double.NaN;
+      double testNormalizedGini = NormalizedGiniCalculator.Calculate(originalTestClassValues, estimatedTestClassValues, out errorState);
+      if (errorState != OnlineCalculatorError.None) testNormalizedGini = double.NaN;
+
+      TrainingNormalizedGiniCoefficient = trainingNormalizedGini;
+      TestNormalizedGiniCoefficient = testNormalizedGini;
+    }
+
+    public abstract IEnumerable<double> EstimatedClassValues { get; }
+    public abstract IEnumerable<double> EstimatedTrainingClassValues { get; }
+    public abstract IEnumerable<double> EstimatedTestClassValues { get; }
+
+    public abstract IEnumerable<double> GetEstimatedClassValues(IEnumerable<int> rows);
+
+    protected override void RecalculateResults() {
+      CalculateClassificationResults();
+    }
+  }
+}
Index: branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/DiscriminantFunctionClassificationModel.cs
===================================================================
--- branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/DiscriminantFunctionClassificationModel.cs	(revision 9073)
+++ branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/DiscriminantFunctionClassificationModel.cs	(revision 9073)
@@ -0,0 +1,145 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  /// <summary>
+  /// Represents discriminant function classification data analysis models.
+  /// </summary>
+  [StorableClass]
+  [Item("DiscriminantFunctionClassificationModel", "Represents a classification model that uses a discriminant function and classification thresholds.")]
+  public class DiscriminantFunctionClassificationModel : NamedItem, IDiscriminantFunctionClassificationModel {
+    [Storable]
+    private IRegressionModel model;
+    public IRegressionModel Model {
+      get { return model; }
+      private set { model = value; }
+    }
+
+    [Storable]
+    private double[] classValues;
+    public IEnumerable<double> ClassValues {
+      get { return (double[])classValues.Clone(); }
+      private set { classValues = value.ToArray(); }
+    }
+
+    [Storable]
+    private double[] thresholds;
+    public IEnumerable<double> Thresholds {
+      get { return (IEnumerable<double>)thresholds.Clone(); }
+      private set { thresholds = value.ToArray(); }
+    }
+
+    private IDiscriminantFunctionThresholdCalculator thresholdCalculator;
+    [Storable]
+    public IDiscriminantFunctionThresholdCalculator ThresholdCalculator {
+      get { return thresholdCalculator; }
+      private set { thresholdCalculator = value; }
+    }
+
+
+    [StorableConstructor]
+    protected DiscriminantFunctionClassificationModel(bool deserializing) : base(deserializing) { }
+    protected DiscriminantFunctionClassificationModel(DiscriminantFunctionClassificationModel original, Cloner cloner)
+      : base(original, cloner) {
+      model = cloner.Clone(original.model);
+      classValues = (double[])original.classValues.Clone();
+      thresholds = (double[])original.thresholds.Clone();
+    }
+
+    public DiscriminantFunctionClassificationModel(IRegressionModel model, IDiscriminantFunctionThresholdCalculator thresholdCalculator)
+      : base() {
+      this.name = ItemName;
+      this.description = ItemDescription;
+      this.model = model;
+      this.classValues = new double[0];
+      this.thresholds = new double[0];
+      this.thresholdCalculator = thresholdCalculator;
+    }
+
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() {
+      if (ThresholdCalculator == null) ThresholdCalculator = new AccuracyMaximizationThresholdCalculator();
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new DiscriminantFunctionClassificationModel(this, cloner);
+    }
+
+    public void SetThresholdsAndClassValues(IEnumerable<double> thresholds, IEnumerable<double> classValues) {
+      var classValuesArr = classValues.ToArray();
+      var thresholdsArr = thresholds.ToArray();
+      if (thresholdsArr.Length != classValuesArr.Length) throw new ArgumentException();
+
+      this.classValues = classValuesArr;
+      this.thresholds = thresholdsArr;
+      OnThresholdsChanged(EventArgs.Empty);
+    }
+
+    public virtual void RecalculateModelParameters(IClassificationProblemData problemData, IEnumerable<int> rows) {
+      double[] classValues;
+      double[] thresholds;
+      var targetClassValues = problemData.Dataset.GetDoubleValues(problemData.TargetVariable, rows);
+      var estimatedTrainingValues = GetEstimatedValues(problemData.Dataset, rows);
+      thresholdCalculator.Calculate(problemData, estimatedTrainingValues, targetClassValues, out classValues, out thresholds);
+      SetThresholdsAndClassValues(thresholds, classValues);
+    }
+
+
+    public IEnumerable<double> GetEstimatedValues(Dataset dataset, IEnumerable<int> rows) {
+      return model.GetEstimatedValues(dataset, rows);
+    }
+
+    public IEnumerable<double> GetEstimatedClassValues(Dataset dataset, IEnumerable<int> rows) {
+      if (!Thresholds.Any() && !ClassValues.Any()) throw new ArgumentException("No thresholds and class values were set for the current classification model.");
+      foreach (var x in GetEstimatedValues(dataset, rows)) {
+        int classIndex = 0;
+        // find first threshold value which is larger than x => class index = threshold index + 1
+        for (int i = 0; i < thresholds.Length; i++) {
+          if (x > thresholds[i]) classIndex++;
+          else break;
+        }
+        yield return classValues.ElementAt(classIndex - 1);
+      }
+    }
+    #region events
+    public event EventHandler ThresholdsChanged;
+    protected virtual void OnThresholdsChanged(EventArgs e) {
+      var listener = ThresholdsChanged;
+      if (listener != null) listener(this, e);
+    }
+    #endregion
+
+    public virtual IDiscriminantFunctionClassificationSolution CreateDiscriminantFunctionClassificationSolution(IClassificationProblemData problemData) {
+      return new DiscriminantFunctionClassificationSolution(this, new ClassificationProblemData(problemData));
+    }
+
+    public virtual IClassificationSolution CreateClassificationSolution(IClassificationProblemData problemData) {
+      return CreateDiscriminantFunctionClassificationSolution(problemData);
+    }
+  }
+}
Index: branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/DiscriminantFunctionClassificationSolution.cs
===================================================================
--- branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/DiscriminantFunctionClassificationSolution.cs	(revision 9073)
+++ branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/DiscriminantFunctionClassificationSolution.cs	(revision 9073)
@@ -0,0 +1,121 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  /// <summary>
+  /// Represents a classification solution that uses a discriminant function and classification thresholds.
+  /// </summary>
+  [StorableClass]
+  [Item("DiscriminantFunctionClassificationSolution", "Represents a classification solution that uses a discriminant function and classification thresholds.")]
+  public class DiscriminantFunctionClassificationSolution : DiscriminantFunctionClassificationSolutionBase {
+    protected readonly Dictionary<int, double> valueEvaluationCache;
+    protected readonly Dictionary<int, double> classValueEvaluationCache;
+
+    [StorableConstructor]
+    protected DiscriminantFunctionClassificationSolution(bool deserializing)
+      : base(deserializing) {
+      valueEvaluationCache = new Dictionary<int, double>();
+      classValueEvaluationCache = new Dictionary<int, double>();
+    }
+    protected DiscriminantFunctionClassificationSolution(DiscriminantFunctionClassificationSolution original, Cloner cloner)
+      : base(original, cloner) {
+      valueEvaluationCache = new Dictionary<int, double>(original.valueEvaluationCache);
+      classValueEvaluationCache = new Dictionary<int, double>(original.classValueEvaluationCache);
+    }
+    public DiscriminantFunctionClassificationSolution(IDiscriminantFunctionClassificationModel model, IClassificationProblemData problemData)
+      : base(model, problemData) {
+      valueEvaluationCache = new Dictionary<int, double>();
+      classValueEvaluationCache = new Dictionary<int, double>();
+      CalculateRegressionResults();
+      CalculateClassificationResults();
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new DiscriminantFunctionClassificationSolution(this, cloner);
+    }
+
+    public override IEnumerable<double> EstimatedClassValues {
+      get { return GetEstimatedClassValues(Enumerable.Range(0, ProblemData.Dataset.Rows)); }
+    }
+    public override IEnumerable<double> EstimatedTrainingClassValues {
+      get { return GetEstimatedClassValues(ProblemData.TrainingIndices); }
+    }
+    public override IEnumerable<double> EstimatedTestClassValues {
+      get { return GetEstimatedClassValues(ProblemData.TestIndices); }
+    }
+
+    public override IEnumerable<double> GetEstimatedClassValues(IEnumerable<int> rows) {
+      var rowsToEvaluate = rows.Except(classValueEvaluationCache.Keys);
+      var rowsEnumerator = rowsToEvaluate.GetEnumerator();
+      var valuesEnumerator = Model.GetEstimatedClassValues(ProblemData.Dataset, rowsToEvaluate).GetEnumerator();
+
+      while (rowsEnumerator.MoveNext() & valuesEnumerator.MoveNext()) {
+        classValueEvaluationCache.Add(rowsEnumerator.Current, valuesEnumerator.Current);
+      }
+
+      return rows.Select(row => classValueEvaluationCache[row]);
+    }
+
+
+    public override IEnumerable<double> EstimatedValues {
+      get { return GetEstimatedValues(Enumerable.Range(0, ProblemData.Dataset.Rows)); }
+    }
+    public override IEnumerable<double> EstimatedTrainingValues {
+      get { return GetEstimatedValues(ProblemData.TrainingIndices); }
+    }
+    public override IEnumerable<double> EstimatedTestValues {
+      get { return GetEstimatedValues(ProblemData.TestIndices); }
+    }
+
+    public override IEnumerable<double> GetEstimatedValues(IEnumerable<int> rows) {
+      var rowsToEvaluate = rows.Except(valueEvaluationCache.Keys);
+      var rowsEnumerator = rowsToEvaluate.GetEnumerator();
+      var valuesEnumerator = Model.GetEstimatedValues(ProblemData.Dataset, rowsToEvaluate).GetEnumerator();
+
+      while (rowsEnumerator.MoveNext() & valuesEnumerator.MoveNext()) {
+        valueEvaluationCache.Add(rowsEnumerator.Current, valuesEnumerator.Current);
+      }
+
+      return rows.Select(row => valueEvaluationCache[row]);
+    }
+
+    protected override void OnModelChanged() {
+      valueEvaluationCache.Clear();
+      classValueEvaluationCache.Clear();
+      base.OnModelChanged();
+    }
+    protected override void OnModelThresholdsChanged(System.EventArgs e) {
+      classValueEvaluationCache.Clear();
+      base.OnModelThresholdsChanged(e);
+    }
+    protected override void OnProblemDataChanged() {
+      valueEvaluationCache.Clear();
+      classValueEvaluationCache.Clear();
+      base.OnProblemDataChanged();
+    }
+  }
+}
Index: branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/DiscriminantFunctionClassificationSolutionBase.cs
===================================================================
--- branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/DiscriminantFunctionClassificationSolutionBase.cs	(revision 9073)
+++ branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/DiscriminantFunctionClassificationSolutionBase.cs	(revision 9073)
@@ -0,0 +1,146 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Optimization;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  /// <summary>
+  /// Represents a classification solution that uses a discriminant function and classification thresholds.
+  /// </summary>
+  [StorableClass]
+  [Item("DiscriminantFunctionClassificationSolution", "Represents a classification solution that uses a discriminant function and classification thresholds.")]
+  public abstract class DiscriminantFunctionClassificationSolutionBase : ClassificationSolutionBase, IDiscriminantFunctionClassificationSolution {
+    private const string TrainingMeanSquaredErrorResultName = "Mean squared error (training)";
+    private const string TestMeanSquaredErrorResultName = "Mean squared error (test)";
+    private const string TrainingRSquaredResultName = "Pearson's R² (training)";
+    private const string TestRSquaredResultName = "Pearson's R² (test)";
+
+    public new IDiscriminantFunctionClassificationModel Model {
+      get { return (IDiscriminantFunctionClassificationModel)base.Model; }
+      protected set {
+        if (value != null && value != Model) {
+          if (Model != null) {
+            Model.ThresholdsChanged -= new EventHandler(Model_ThresholdsChanged);
+          }
+          value.ThresholdsChanged += new EventHandler(Model_ThresholdsChanged);
+          base.Model = value;
+        }
+      }
+    }
+
+    #region Results
+    public double TrainingMeanSquaredError {
+      get { return ((DoubleValue)this[TrainingMeanSquaredErrorResultName].Value).Value; }
+      private set { ((DoubleValue)this[TrainingMeanSquaredErrorResultName].Value).Value = value; }
+    }
+    public double TestMeanSquaredError {
+      get { return ((DoubleValue)this[TestMeanSquaredErrorResultName].Value).Value; }
+      private set { ((DoubleValue)this[TestMeanSquaredErrorResultName].Value).Value = value; }
+    }
+    public double TrainingRSquared {
+      get { return ((DoubleValue)this[TrainingRSquaredResultName].Value).Value; }
+      private set { ((DoubleValue)this[TrainingRSquaredResultName].Value).Value = value; }
+    }
+    public double TestRSquared {
+      get { return ((DoubleValue)this[TestRSquaredResultName].Value).Value; }
+      private set { ((DoubleValue)this[TestRSquaredResultName].Value).Value = value; }
+    }
+    #endregion
+
+    [StorableConstructor]
+    protected DiscriminantFunctionClassificationSolutionBase(bool deserializing) : base(deserializing) { }
+    protected DiscriminantFunctionClassificationSolutionBase(DiscriminantFunctionClassificationSolutionBase original, Cloner cloner)
+      : base(original, cloner) {
+      RegisterEventHandler();
+    }
+    protected DiscriminantFunctionClassificationSolutionBase(IDiscriminantFunctionClassificationModel model, IClassificationProblemData problemData)
+      : base(model, problemData) {
+      Add(new Result(TrainingMeanSquaredErrorResultName, "Mean of squared errors of the model on the training partition", new DoubleValue()));
+      Add(new Result(TestMeanSquaredErrorResultName, "Mean of squared errors of the model on the test partition", new DoubleValue()));
+      Add(new Result(TrainingRSquaredResultName, "Squared Pearson's correlation coefficient of the model output and the actual values on the training partition", new DoubleValue()));
+      Add(new Result(TestRSquaredResultName, "Squared Pearson's correlation coefficient of the model output and the actual values on the test partition", new DoubleValue()));
+      RegisterEventHandler();
+    }
+
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() {
+      RegisterEventHandler();
+    }
+
+    protected void CalculateRegressionResults() {
+      double[] estimatedTrainingValues = EstimatedTrainingValues.ToArray(); // cache values
+      double[] originalTrainingValues = ProblemData.Dataset.GetDoubleValues(ProblemData.TargetVariable, ProblemData.TrainingIndices).ToArray();
+      double[] estimatedTestValues = EstimatedTestValues.ToArray(); // cache values
+      double[] originalTestValues = ProblemData.Dataset.GetDoubleValues(ProblemData.TargetVariable, ProblemData.TestIndices).ToArray();
+
+      OnlineCalculatorError errorState;
+      double trainingMSE = OnlineMeanSquaredErrorCalculator.Calculate(originalTrainingValues, estimatedTrainingValues, out errorState);
+      TrainingMeanSquaredError = errorState == OnlineCalculatorError.None ? trainingMSE : double.NaN;
+      double testMSE = OnlineMeanSquaredErrorCalculator.Calculate(originalTestValues, estimatedTestValues, out errorState);
+      TestMeanSquaredError = errorState == OnlineCalculatorError.None ? testMSE : double.NaN;
+
+      double trainingR2 = OnlinePearsonsRSquaredCalculator.Calculate(originalTrainingValues, estimatedTrainingValues, out errorState);
+      TrainingRSquared = errorState == OnlineCalculatorError.None ? trainingR2 : double.NaN;
+      double testR2 = OnlinePearsonsRSquaredCalculator.Calculate(originalTestValues, estimatedTestValues, out errorState);
+      TestRSquared = errorState == OnlineCalculatorError.None ? testR2 : double.NaN;
+
+      double trainingNormalizedGini = NormalizedGiniCalculator.Calculate(originalTrainingValues, estimatedTrainingValues, out errorState);
+      if (errorState != OnlineCalculatorError.None) trainingNormalizedGini = double.NaN;
+      double testNormalizedGini = NormalizedGiniCalculator.Calculate(originalTestValues, estimatedTestValues, out errorState);
+      if (errorState != OnlineCalculatorError.None) testNormalizedGini = double.NaN;
+
+      TrainingNormalizedGiniCoefficient = trainingNormalizedGini;
+      TestNormalizedGiniCoefficient = testNormalizedGini;
+    }
+
+    private void RegisterEventHandler() {
+      Model.ThresholdsChanged += new EventHandler(Model_ThresholdsChanged);
+    }
+    private void DeregisterEventHandler() {
+      Model.ThresholdsChanged -= new EventHandler(Model_ThresholdsChanged);
+    }
+    private void Model_ThresholdsChanged(object sender, EventArgs e) {
+      OnModelThresholdsChanged(e);
+    }
+
+    protected virtual void OnModelThresholdsChanged(EventArgs e) {
+      OnModelChanged();
+    }
+
+    public abstract IEnumerable<double> EstimatedValues { get; }
+    public abstract IEnumerable<double> EstimatedTrainingValues { get; }
+    public abstract IEnumerable<double> EstimatedTestValues { get; }
+
+    public abstract IEnumerable<double> GetEstimatedValues(IEnumerable<int> rows);
+
+    protected override void RecalculateResults() {
+      base.RecalculateResults();
+      CalculateRegressionResults();
+    }
+  }
+}
Index: branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ThresholdCalculators/AccuracyMaximizationThresholdCalculator.cs
===================================================================
--- branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ThresholdCalculators/AccuracyMaximizationThresholdCalculator.cs	(revision 9073)
+++ branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ThresholdCalculators/AccuracyMaximizationThresholdCalculator.cs	(revision 9073)
@@ -0,0 +1,133 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  /// <summary>
+  /// Represents a threshold calculator that maximizes the weighted accuracy of the classifcation model.
+  /// </summary>
+  [StorableClass]
+  [Item("AccuracyMaximizationThresholdCalculator", "Represents a threshold calculator that maximizes the weighted accuracy of the classifcation model.")]
+  public class AccuracyMaximizationThresholdCalculator : ThresholdCalculator {
+
+    [StorableConstructor]
+    protected AccuracyMaximizationThresholdCalculator(bool deserializing) : base(deserializing) { }
+    protected AccuracyMaximizationThresholdCalculator(AccuracyMaximizationThresholdCalculator original, Cloner cloner)
+      : base(original, cloner) {
+    }
+    public AccuracyMaximizationThresholdCalculator()
+      : base() {
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new AccuracyMaximizationThresholdCalculator(this, cloner);
+    }
+
+    public override void Calculate(IClassificationProblemData problemData, IEnumerable<double> estimatedValues, IEnumerable<double> targetClassValues, out double[] classValues, out double[] thresholds) {
+      AccuracyMaximizationThresholdCalculator.CalculateThresholds(problemData, estimatedValues, targetClassValues, out classValues, out thresholds);
+    }
+
+    public static void CalculateThresholds(IClassificationProblemData problemData, IEnumerable<double> estimatedValues, IEnumerable<double> targetClassValues, out double[] classValues, out double[] thresholds) {
+      const int slices = 100;
+      const double minThresholdInc = 10e-5; // necessary to prevent infinite loop when maxEstimated - minEstimated is effectively zero (constant model)
+      List<double> estimatedValuesList = estimatedValues.ToList();
+      double maxEstimatedValue = estimatedValuesList.Max();
+      double minEstimatedValue = estimatedValuesList.Min();
+      double thresholdIncrement = Math.Max((maxEstimatedValue - minEstimatedValue) / slices, minThresholdInc);
+      var estimatedAndTargetValuePairs =
+        estimatedValuesList.Zip(targetClassValues, (x, y) => new { EstimatedValue = x, TargetClassValue = y })
+        .OrderBy(x => x.EstimatedValue).ToList();
+
+      classValues = estimatedAndTargetValuePairs.GroupBy(x => x.TargetClassValue)
+        .Select(x => new { Median = x.Select(y => y.EstimatedValue).Median(), Class = x.Key })
+        .OrderBy(x => x.Median).Select(x => x.Class).ToArray();
+
+      int nClasses = classValues.Length;
+      thresholds = new double[nClasses];
+      thresholds[0] = double.NegativeInfinity;
+
+      // incrementally calculate accuracy of all possible thresholds
+      for (int i = 1; i < thresholds.Length; i++) {
+        double lowerThreshold = thresholds[i - 1];
+        double actualThreshold = Math.Max(lowerThreshold, minEstimatedValue);
+        double lowestBestThreshold = double.NaN;
+        double highestBestThreshold = double.NaN;
+        double bestClassificationScore = double.PositiveInfinity;
+        bool seriesOfEqualClassificationScores = false;
+
+        while (actualThreshold < maxEstimatedValue) {
+          double classificationScore = 0.0;
+
+          foreach (var pair in estimatedAndTargetValuePairs) {
+            //all positives
+            if (pair.TargetClassValue.IsAlmost(classValues[i - 1])) {
+              if (pair.EstimatedValue > lowerThreshold && pair.EstimatedValue <= actualThreshold)
+                //true positive
+                classificationScore += problemData.GetClassificationPenalty(pair.TargetClassValue, pair.TargetClassValue);
+              else
+                //false negative
+                classificationScore += problemData.GetClassificationPenalty(pair.TargetClassValue, classValues[i]);
+            }
+              //all negatives
+            else {
+              //false positive
+              if (pair.EstimatedValue > lowerThreshold && pair.EstimatedValue <= actualThreshold)
+                classificationScore += problemData.GetClassificationPenalty(pair.TargetClassValue, classValues[i - 1]);
+              else if (pair.EstimatedValue <= lowerThreshold)
+                classificationScore += problemData.GetClassificationPenalty(pair.TargetClassValue, classValues[i - 2]);
+              else if (pair.EstimatedValue > actualThreshold) {
+                if (pair.TargetClassValue < classValues[i - 1]) //negative in wrong class, consider upper class
+                  classificationScore += problemData.GetClassificationPenalty(pair.TargetClassValue, classValues[i]);
+                else //true negative, must be optimized by the other thresholds
+                  classificationScore += problemData.GetClassificationPenalty(pair.TargetClassValue, pair.TargetClassValue);
+              }
+            }
+          }
+
+          //new best classification score found
+          if (classificationScore < bestClassificationScore) {
+            bestClassificationScore = classificationScore;
+            lowestBestThreshold = actualThreshold;
+            highestBestThreshold = actualThreshold;
+            seriesOfEqualClassificationScores = true;
+          }
+            //equal classification scores => if seriesOfEqualClassifcationScores == true update highest threshold
+          else if (Math.Abs(classificationScore - bestClassificationScore) < double.Epsilon && seriesOfEqualClassificationScores)
+            highestBestThreshold = actualThreshold;
+          //worse classificatoin score found reset seriesOfEqualClassifcationScores
+          else seriesOfEqualClassificationScores = false;
+
+          actualThreshold += thresholdIncrement;
+        }
+        //scale lowest thresholds and highest found optimal threshold according to the misclassification matrix
+        double falseNegativePenalty = problemData.GetClassificationPenalty(classValues[i], classValues[i - 1]);
+        double falsePositivePenalty = problemData.GetClassificationPenalty(classValues[i - 1], classValues[i]);
+        thresholds[i] = (lowestBestThreshold * falsePositivePenalty + highestBestThreshold * falseNegativePenalty) / (falseNegativePenalty + falsePositivePenalty);
+      }
+    }
+  }
+}
Index: branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ThresholdCalculators/NormalDistributionCutPointsThresholdCalculator.cs
===================================================================
--- branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ThresholdCalculators/NormalDistributionCutPointsThresholdCalculator.cs	(revision 9073)
+++ branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ThresholdCalculators/NormalDistributionCutPointsThresholdCalculator.cs	(revision 9073)
@@ -0,0 +1,216 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  /// <summary>
+  /// Represents a threshold calculator that calculates thresholds as the cutting points between the estimated class distributions (assuming normally distributed class values).
+  /// </summary>
+  [StorableClass]
+  [Item("NormalDistributionCutPointsThresholdCalculator", "Represents a threshold calculator that calculates thresholds as the cutting points between the estimated class distributions (assuming normally distributed class values).")]
+  public class NormalDistributionCutPointsThresholdCalculator : ThresholdCalculator {
+
+    [StorableConstructor]
+    protected NormalDistributionCutPointsThresholdCalculator(bool deserializing) : base(deserializing) { }
+    protected NormalDistributionCutPointsThresholdCalculator(NormalDistributionCutPointsThresholdCalculator original, Cloner cloner)
+      : base(original, cloner) {
+    }
+    public NormalDistributionCutPointsThresholdCalculator()
+      : base() {
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new NormalDistributionCutPointsThresholdCalculator(this, cloner);
+    }
+
+    public override void Calculate(IClassificationProblemData problemData, IEnumerable<double> estimatedValues, IEnumerable<double> targetClassValues, out double[] classValues, out double[] thresholds) {
+      NormalDistributionCutPointsThresholdCalculator.CalculateThresholds(problemData, estimatedValues, targetClassValues, out classValues, out thresholds);
+    }
+
+    public static void CalculateThresholds(IClassificationProblemData problemData, IEnumerable<double> estimatedValues, IEnumerable<double> targetClassValues, out double[] classValues, out double[] thresholds) {
+      var estimatedTargetValues = Enumerable.Zip(estimatedValues, targetClassValues, (e, t) => new { EstimatedValue = e, TargetValue = t }).ToList();
+      double estimatedValuesRange = estimatedValues.Range();
+
+      Dictionary<double, double> classMean = new Dictionary<double, double>();
+      Dictionary<double, double> classStdDev = new Dictionary<double, double>();
+      // calculate moments per class
+      foreach (var group in estimatedTargetValues.GroupBy(p => p.TargetValue)) {
+        IEnumerable<double> estimatedClassValues = group.Select(x => x.EstimatedValue);
+        double classValue = group.Key;
+        double mean, variance;
+        OnlineCalculatorError meanErrorState, varianceErrorState;
+        OnlineMeanAndVarianceCalculator.Calculate(estimatedClassValues, out mean, out variance, out meanErrorState, out varianceErrorState);
+
+        if (meanErrorState == OnlineCalculatorError.None && varianceErrorState == OnlineCalculatorError.None) {
+          classMean[classValue] = mean;
+          classStdDev[classValue] = Math.Sqrt(variance);
+        }
+      }
+
+      double[] originalClasses = classMean.Keys.OrderBy(x => x).ToArray();
+      int nClasses = originalClasses.Length;
+      List<double> thresholdList = new List<double>();
+      for (int i = 0; i < nClasses - 1; i++) {
+        for (int j = i + 1; j < nClasses; j++) {
+          double x1, x2;
+          double class0 = originalClasses[i];
+          double class1 = originalClasses[j];
+          // calculate all thresholds
+          CalculateCutPoints(classMean[class0], classStdDev[class0], classMean[class1], classStdDev[class1], out x1, out x2);
+
+          // if the two cut points are too close (for instance because the stdDev=0)
+          // then move them by 0.1% of the range of estimated values
+          if (x1.IsAlmost(x2)) {
+            x1 -= 0.001 * estimatedValuesRange;
+            x2 += 0.001 * estimatedValuesRange;
+          }
+          if (!double.IsInfinity(x1) && !thresholdList.Any(x => x.IsAlmost(x1))) thresholdList.Add(x1);
+          if (!double.IsInfinity(x2) && !thresholdList.Any(x => x.IsAlmost(x2))) thresholdList.Add(x2);
+        }
+      }
+      thresholdList.Sort();
+
+      // add small value and large value for the calculation of most influential class in each thresholded section
+      thresholdList.Insert(0, double.NegativeInfinity);
+      thresholdList.Add(double.PositiveInfinity);
+
+
+      // find the most likely class for the points between thresholds m
+      List<double> filteredThresholds = new List<double>();
+      List<double> filteredClassValues = new List<double>();
+      for (int i = 0; i < thresholdList.Count - 1; i++) {
+        // determine class with maximal density mass between the thresholds
+        double maxDensity = DensityMass(thresholdList[i], thresholdList[i + 1], classMean[originalClasses[0]], classStdDev[originalClasses[0]]);
+        double maxDensityClassValue = originalClasses[0];
+        foreach (var classValue in originalClasses.Skip(1)) {
+          double density = DensityMass(thresholdList[i], thresholdList[i + 1], classMean[classValue], classStdDev[classValue]);
+          if (density > maxDensity) {
+            maxDensity = density;
+            maxDensityClassValue = classValue;
+          }
+        }
+        if (maxDensity > double.NegativeInfinity &&
+          (filteredClassValues.Count == 0 || !maxDensityClassValue.IsAlmost(filteredClassValues.Last()))) {
+          filteredThresholds.Add(thresholdList[i]);
+          filteredClassValues.Add(maxDensityClassValue);
+        }
+      }
+
+      if (filteredThresholds.Count == 0 || !double.IsNegativeInfinity(filteredThresholds.First())) {
+        // this happens if there are no thresholds (distributions for all classes are exactly the same)
+        // or when the CDF up to the first threshold is zero
+        // -> all samples should be classified as the class with the most observations
+        // group observations by target class and select the class with largest count 
+        double mostFrequentClass = targetClassValues.GroupBy(c => c)
+                              .OrderBy(g => g.Count())
+                              .Last().Key;
+        filteredThresholds.Insert(0, double.NegativeInfinity);
+        filteredClassValues.Insert(0, mostFrequentClass);
+      }
+
+      thresholds = filteredThresholds.ToArray();
+      classValues = filteredClassValues.ToArray();
+    }
+
+    private static double sqr2 = Math.Sqrt(2.0);
+    // returns the density function of the standard normal distribution at x
+    private static double NormalCDF(double x) {
+      return 0.5 * (1 + alglib.errorfunction(x / sqr2));
+    }
+
+    // approximation of the log of the normal cummulative distribution from the lightspeed toolbox by Tom Minka
+    // http://research.microsoft.com/en-us/um/people/minka/software/lightspeed/
+    private static double[] c = new double[] { -1, 5 / 2.0, -37 / 3.0, 353 / 4.0, -4081 / 5.0, 55205 / 6.0, -854197 / 7.0 };
+    private static double LogNormalCDF(double x) {
+      if (x >= -6.5)
+        // calculate the log directly if x is large enough
+        return Math.Log(NormalCDF(x));
+      else {
+        double z = Math.Pow(x, -2);
+        // asymptotic series for logcdf
+        double y = z * (c[0] + z * (c[1] + z * (c[2] + z * (c[3] + z * (c[4] + z * (c[5] + z * c[6]))))));
+        return y - 0.5 * Math.Log(2 * Math.PI) - 0.5 * x * x - Math.Log(-x);
+      }
+    }
+
+    // determines the value NormalCDF(mu,sigma, upper)  - NormalCDF(mu, sigma, lower)
+    // = the integral of the PDF of N(mu, sigma) in the range [lower, upper]
+    private static double DensityMass(double lower, double upper, double mu, double sigma) {
+      if (sigma.IsAlmost(0.0)) {
+        if (lower < mu && mu < upper) return 0.0; // all mass is between lower and upper
+        else return double.NegativeInfinity; // no mass is between lower and upper
+      }
+
+      if (lower > mu) {
+        return DensityMass(-upper, -lower, -mu, sigma);
+      }
+
+      upper = (upper - mu) / sigma;
+      lower = (lower - mu) / sigma;
+      if (double.IsNegativeInfinity(lower)) return LogNormalCDF(upper);
+
+      return LogNormalCDF(upper) + Math.Log(1 - Math.Exp(LogNormalCDF(lower) - LogNormalCDF(upper)));
+    }
+
+    // Calculates the points x1 and x2 where the distributions N(m1, s1) == N(m2,s2). 
+    // In the general case there should be two cut points. If either s1 or s2 is 0 then x1==x2. 
+    // If both s1 and s2 are zero than there are no cut points but we should return something reasonable (e.g. (m1 + m2) / 2) then.
+    private static void CalculateCutPoints(double m1, double s1, double m2, double s2, out double x1, out double x2) {
+      if (s1.IsAlmost(s2)) {
+        if (m1.IsAlmost(m2)) {
+          x1 = double.NegativeInfinity;
+          x2 = double.NegativeInfinity;
+        } else {
+          // s1==s2 and m1 != m2
+          // return something reasonable. cut point should be half way between m1 and m2
+          x1 = (m1 + m2) / 2;
+          x2 = double.NegativeInfinity;
+        }
+      } else if (s1.IsAlmost(0.0)) {
+        // when s1 is 0.0 the cut points are exactly at m1 ...
+        x1 = m1;
+        x2 = m1;
+      } else if (s2.IsAlmost(0.0)) {
+        // ... same for s2
+        x1 = m2;
+        x2 = m2;
+      } else {
+        if (s2 < s1) {
+          // make sure s2 is the larger std.dev.
+          CalculateCutPoints(m2, s2, m1, s1, out x1, out x2);
+        } else {
+          // general case
+          // calculate the solutions x1, x2 where N(m1,s1) == N(m2,s2)
+          double g = Math.Sqrt(2 * s2 * s2 * Math.Log(s2 / s1) - 2 * s1 * s1 * Math.Log(s2 / s1) - 2 * m1 * m2 + m1 * m1 + m2 * m2);
+          double s = (s1 * s1 - s2 * s2);
+          x1 = (m2 * s1 * s1 - m1 * s2 * s2 + s1 * s2 * g) / s;
+          x2 = -(m1 * s2 * s2 - m2 * s1 * s1 + s1 * s2 * g) / s;
+        }
+      }
+    }
+  }
+}
Index: branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ThresholdCalculators/ThresholdCalculator.cs
===================================================================
--- branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ThresholdCalculators/ThresholdCalculator.cs	(revision 9073)
+++ branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ThresholdCalculators/ThresholdCalculator.cs	(revision 9073)
@@ -0,0 +1,47 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Collections.Generic;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  /// <summary>
+  /// Base class for threshold calculators for discriminant function classification models.
+  /// </summary>
+  [StorableClass]
+  public abstract class ThresholdCalculator : NamedItem, IDiscriminantFunctionThresholdCalculator {
+
+    [StorableConstructor]
+    protected ThresholdCalculator(bool deserializing) : base(deserializing) { }
+    protected ThresholdCalculator(ThresholdCalculator original, Cloner cloner)
+      : base(original, cloner) {
+    }
+    public ThresholdCalculator()
+      : base() {
+      this.name = ItemName;
+      this.description = ItemDescription;
+    }
+
+    public abstract void Calculate(IClassificationProblemData problemData, IEnumerable<double> estimatedValues, IEnumerable<double> targetClassValues, out double[] classValues, out double[] thresholds);
+  }
+}
Index: branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Clustering/ClusteringProblem.cs
===================================================================
--- branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Clustering/ClusteringProblem.cs	(revision 9073)
+++ branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Clustering/ClusteringProblem.cs	(revision 9073)
@@ -0,0 +1,41 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  [StorableClass]
+  [Item("Clustering Problem", "A general clustering problem.")]
+  [Creatable("Problems")]
+  public class ClusteringProblem : DataAnalysisProblem<IClusteringProblemData>, IClusteringProblem {
+    [StorableConstructor]
+    protected ClusteringProblem(bool deserializing) : base(deserializing) { }
+    protected ClusteringProblem(ClusteringProblem original, Cloner cloner) : base(original, cloner) { }
+    public override IDeepCloneable Clone(Cloner cloner) { return new ClusteringProblem(this, cloner); }
+
+    public ClusteringProblem()
+      : base() {
+      ProblemData = new ClusteringProblemData();
+    }
+  }
+}
Index: branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Clustering/ClusteringProblemData.cs
===================================================================
--- branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Clustering/ClusteringProblemData.cs	(revision 9073)
+++ branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Clustering/ClusteringProblemData.cs	(revision 9073)
@@ -0,0 +1,92 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Collections.Generic;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  [StorableClass]
+  [Item("ClusteringProblemData", "Represents an item containing all data defining a clustering problem.")]
+  public sealed class ClusteringProblemData : DataAnalysisProblemData, IClusteringProblemData, IStorableContent {
+    public string Filename { get; set; }
+
+    #region default data
+    private static double[,] kozaF1 = new double[,] {
+          {2.017885919,	-1.449165046},
+          {1.30060506,	-1.344523885},
+          {1.147134798,	-1.317989331},
+          {0.877182504,	-1.266142284},
+          {0.852562452,	-1.261020794},
+          {0.431095788,	-1.158793317},
+          {0.112586002,	-1.050908405},
+          {0.04594507,	-1.021989402},
+          {0.042572879,	-1.020438113},
+          {-0.074027291,	-0.959859562},
+          {-0.109178553,	-0.938094706},
+          {-0.259721109,	-0.803635355},
+          {-0.272991057,	-0.387519561},
+          {-0.161978191,	-0.193611001},
+          {-0.102489983,	-0.114215349},
+          {-0.01469968,	-0.014918985},
+          {-0.008863365,	-0.008942626},
+          {0.026751057,	0.026054094},
+          {0.166922436,	0.14309643},
+          {0.176953808,	0.1504144},
+          {0.190233418,	0.159916534},
+          {0.199800708,	0.166635331},
+          {0.261502822,	0.207600348},
+          {0.30182879,	0.232370249},
+          {0.83763905,	0.468046718}
+    };
+    private static Dataset defaultDataset;
+    private static IEnumerable<string> defaultAllowedInputVariables;
+
+    static ClusteringProblemData() {
+      defaultDataset = new Dataset(new string[] { "y", "x" }, kozaF1);
+      defaultDataset.Name = "Fourth-order Polynomial Function Benchmark Dataset";
+      defaultDataset.Description = "f(x) = x^4 + x^3 + x^2 + x^1";
+      defaultAllowedInputVariables = new List<string>() { "x", "y" };
+    }
+    #endregion
+
+    [StorableConstructor]
+    private ClusteringProblemData(bool deserializing) : base(deserializing) { }
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() {
+    }
+
+
+    private ClusteringProblemData(ClusteringProblemData original, Cloner cloner)
+      : base(original, cloner) {
+    }
+    public override IDeepCloneable Clone(Cloner cloner) { return new ClusteringProblemData(this, cloner); }
+
+    public ClusteringProblemData()
+      : this(defaultDataset, defaultAllowedInputVariables) {
+    }
+
+    public ClusteringProblemData(Dataset dataset, IEnumerable<string> allowedInputVariables)
+      : base(dataset, allowedInputVariables) {
+    }
+  }
+}
Index: branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Clustering/ClusteringSolution.cs
===================================================================
--- branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Clustering/ClusteringSolution.cs	(revision 9073)
+++ branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Clustering/ClusteringSolution.cs	(revision 9073)
@@ -0,0 +1,85 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  /// <summary>
+  /// Represents a clustering data analysis solution
+  /// </summary>
+  [StorableClass]
+  public class ClusteringSolution : DataAnalysisSolution, IClusteringSolution {
+
+    [StorableConstructor]
+    protected ClusteringSolution(bool deserializing) : base(deserializing) { }
+    protected ClusteringSolution(ClusteringSolution original, Cloner cloner)
+      : base(original, cloner) {
+    }
+    public ClusteringSolution(IClusteringModel model, IClusteringProblemData problemData)
+      : base(model, problemData) {
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new ClusteringSolution(this, cloner);
+    }
+
+    protected override void RecalculateResults() {
+    }
+
+    #region IClusteringSolution Members
+
+    public new IClusteringModel Model {
+      get { return (IClusteringModel)base.Model; }
+      set { base.Model = value; }
+    }
+
+    public new IClusteringProblemData ProblemData {
+      get { return (IClusteringProblemData)base.ProblemData; }
+      set { base.ProblemData = value; }
+    }
+
+    public virtual IEnumerable<int> ClusterValues {
+      get {
+        return GetClusterValues(Enumerable.Range(0, ProblemData.Dataset.Rows));
+      }
+    }
+
+    public virtual IEnumerable<int> TrainingClusterValues {
+      get {
+        return GetClusterValues(ProblemData.TrainingIndices);
+      }
+    }
+
+    public virtual IEnumerable<int> TestClusterValues {
+      get {
+        return GetClusterValues(ProblemData.TestIndices);
+      }
+    }
+
+    public virtual IEnumerable<int> GetClusterValues(IEnumerable<int> rows) {
+      return Model.GetClusterValues(ProblemData.Dataset, rows);
+    }
+    #endregion
+  }
+}
Index: branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/DataAnalysisProblem.cs
===================================================================
--- branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/DataAnalysisProblem.cs	(revision 9073)
+++ branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/DataAnalysisProblem.cs	(revision 9073)
@@ -0,0 +1,111 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Optimization;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Problems.Instances;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  [StorableClass]
+  public abstract class DataAnalysisProblem<T> : Problem, IDataAnalysisProblem<T>,
+    IProblemInstanceConsumer<T>, IProblemInstanceExporter<T>
+    where T : class, IDataAnalysisProblemData {
+    private const string ProblemDataParameterName = "ProblemData";
+    private const string ProblemDataParameterDescription = "The data set, target variable and input variables of the data analysis problem.";
+    #region parameter properties
+    IParameter IDataAnalysisProblem.ProblemDataParameter {
+      get { return ProblemDataParameter; }
+    }
+    public IValueParameter<T> ProblemDataParameter {
+      get { return (IValueParameter<T>)Parameters[ProblemDataParameterName]; }
+    }
+    #endregion
+    #region properties
+    IDataAnalysisProblemData IDataAnalysisProblem.ProblemData {
+      get { return ProblemData; }
+    }
+    public T ProblemData {
+      get { return ProblemDataParameter.Value; }
+      protected set {
+        ProblemDataParameter.Value = value;
+      }
+    }
+    #endregion
+    protected DataAnalysisProblem(DataAnalysisProblem<T> original, Cloner cloner)
+      : base(original, cloner) {
+      RegisterEventHandlers();
+    }
+    [StorableConstructor]
+    protected DataAnalysisProblem(bool deserializing) : base(deserializing) { }
+    public DataAnalysisProblem()
+      : base() {
+      Parameters.Add(new ValueParameter<T>(ProblemDataParameterName, ProblemDataParameterDescription));
+      RegisterEventHandlers();
+    }
+
+    protected DataAnalysisProblem(T problemData)
+      : this() {
+      ProblemData = problemData;
+    }
+
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() {
+      RegisterEventHandlers();
+    }
+
+    private void RegisterEventHandlers() {
+      ProblemDataParameter.ValueChanged += new EventHandler(ProblemDataParameter_ValueChanged);
+      if (ProblemDataParameter.Value != null) ProblemDataParameter.Value.Changed += new EventHandler(ProblemData_Changed);
+    }
+
+    private void ProblemDataParameter_ValueChanged(object sender, EventArgs e) {
+      ProblemDataParameter.Value.Changed += new EventHandler(ProblemData_Changed);
+      OnProblemDataChanged();
+      OnReset();
+    }
+
+    private void ProblemData_Changed(object sender, EventArgs e) {
+      OnReset();
+    }
+
+    public event EventHandler ProblemDataChanged;
+    protected virtual void OnProblemDataChanged() {
+      var handler = ProblemDataChanged;
+      if (handler != null) handler(this, EventArgs.Empty);
+    }
+
+    #region Import & Export
+    public void Load(T data) {
+      Name = data.Name;
+      Description = data.Description;
+      ProblemData = data;
+    }
+
+    public T Export() {
+      return ProblemData;
+    }
+    #endregion
+  }
+}
Index: branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/DataAnalysisProblemData.cs
===================================================================
--- branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/DataAnalysisProblemData.cs	(revision 9073)
+++ branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/DataAnalysisProblemData.cs	(revision 9073)
@@ -0,0 +1,161 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Collections;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  [StorableClass]
+  public abstract class DataAnalysisProblemData : ParameterizedNamedItem, IDataAnalysisProblemData {
+    protected const string DatasetParameterName = "Dataset";
+    protected const string InputVariablesParameterName = "InputVariables";
+    protected const string TrainingPartitionParameterName = "TrainingPartition";
+    protected const string TestPartitionParameterName = "TestPartition";
+
+    #region parameter properites
+    public IFixedValueParameter<Dataset> DatasetParameter {
+      get { return (IFixedValueParameter<Dataset>)Parameters[DatasetParameterName]; }
+    }
+    public IFixedValueParameter<ReadOnlyCheckedItemList<StringValue>> InputVariablesParameter {
+      get { return (IFixedValueParameter<ReadOnlyCheckedItemList<StringValue>>)Parameters[InputVariablesParameterName]; }
+    }
+    public IFixedValueParameter<IntRange> TrainingPartitionParameter {
+      get { return (IFixedValueParameter<IntRange>)Parameters[TrainingPartitionParameterName]; }
+    }
+    public IFixedValueParameter<IntRange> TestPartitionParameter {
+      get { return (IFixedValueParameter<IntRange>)Parameters[TestPartitionParameterName]; }
+    }
+    #endregion
+
+    #region properties
+    protected bool isEmpty = false;
+    public bool IsEmpty {
+      get { return isEmpty; }
+    }
+    public Dataset Dataset {
+      get { return DatasetParameter.Value; }
+    }
+    public ICheckedItemList<StringValue> InputVariables {
+      get { return InputVariablesParameter.Value; }
+    }
+    public IEnumerable<string> AllowedInputVariables {
+      get { return InputVariables.CheckedItems.Select(x => x.Value.Value); }
+    }
+
+    public IntRange TrainingPartition {
+      get { return TrainingPartitionParameter.Value; }
+    }
+    public IntRange TestPartition {
+      get { return TestPartitionParameter.Value; }
+    }
+
+    public virtual IEnumerable<int> TrainingIndices {
+      get {
+        return Enumerable.Range(TrainingPartition.Start, Math.Max(0, TrainingPartition.End - TrainingPartition.Start))
+                         .Where(IsTrainingSample);
+      }
+    }
+    public virtual IEnumerable<int> TestIndices {
+      get {
+        return Enumerable.Range(TestPartition.Start, Math.Max(0, TestPartition.End - TestPartition.Start))
+           .Where(IsTestSample);
+      }
+    }
+
+    public virtual bool IsTrainingSample(int index) {
+      return index >= 0 && index < Dataset.Rows &&
+        TrainingPartition.Start <= index && index < TrainingPartition.End &&
+        (index < TestPartition.Start || TestPartition.End <= index);
+    }
+
+    public virtual bool IsTestSample(int index) {
+      return index >= 0 && index < Dataset.Rows &&
+             TestPartition.Start <= index && index < TestPartition.End;
+    }
+    #endregion
+
+    protected DataAnalysisProblemData(DataAnalysisProblemData original, Cloner cloner)
+      : base(original, cloner) {
+      isEmpty = original.isEmpty;
+      RegisterEventHandlers();
+    }
+    [StorableConstructor]
+    protected DataAnalysisProblemData(bool deserializing) : base(deserializing) { }
+
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() {
+      RegisterEventHandlers();
+    }
+
+    protected DataAnalysisProblemData(Dataset dataset, IEnumerable<string> allowedInputVariables) {
+      if (dataset == null) throw new ArgumentNullException("The dataset must not be null.");
+      if (allowedInputVariables == null) throw new ArgumentNullException("The allowedInputVariables must not be null.");
+
+      if (allowedInputVariables.Except(dataset.DoubleVariables).Any())
+        throw new ArgumentException("All allowed input variables must be present in the dataset and of type double.");
+
+      var inputVariables = new CheckedItemList<StringValue>(dataset.DoubleVariables.Select(x => new StringValue(x)));
+      foreach (StringValue x in inputVariables)
+        inputVariables.SetItemCheckedState(x, allowedInputVariables.Contains(x.Value));
+
+      int trainingPartitionStart = 0;
+      int trainingPartitionEnd = dataset.Rows / 2;
+      int testPartitionStart = dataset.Rows / 2;
+      int testPartitionEnd = dataset.Rows;
+
+      Parameters.Add(new FixedValueParameter<Dataset>(DatasetParameterName, "", dataset));
+      Parameters.Add(new FixedValueParameter<ReadOnlyCheckedItemList<StringValue>>(InputVariablesParameterName, "", inputVariables.AsReadOnly()));
+      Parameters.Add(new FixedValueParameter<IntRange>(TrainingPartitionParameterName, "", new IntRange(trainingPartitionStart, trainingPartitionEnd)));
+      Parameters.Add(new FixedValueParameter<IntRange>(TestPartitionParameterName, "", new IntRange(testPartitionStart, testPartitionEnd)));
+
+      ((ValueParameter<Dataset>)DatasetParameter).ReactOnValueToStringChangedAndValueItemImageChanged = false;
+      RegisterEventHandlers();
+    }
+
+    private void RegisterEventHandlers() {
+      DatasetParameter.ValueChanged += new EventHandler(Parameter_ValueChanged);
+      InputVariables.CheckedItemsChanged += new CollectionItemsChangedEventHandler<IndexedItem<StringValue>>(InputVariables_CheckedItemsChanged);
+      TrainingPartition.ValueChanged += new EventHandler(Parameter_ValueChanged);
+      TestPartition.ValueChanged += new EventHandler(Parameter_ValueChanged);
+    }
+
+    private void InputVariables_CheckedItemsChanged(object sender, CollectionItemsChangedEventArgs<IndexedItem<StringValue>> e) {
+      OnChanged();
+    }
+
+    private void Parameter_ValueChanged(object sender, EventArgs e) {
+      OnChanged();
+    }
+
+    public event EventHandler Changed;
+    protected virtual void OnChanged() {
+      var listeners = Changed;
+      if (listeners != null) listeners(this, EventArgs.Empty);
+    }
+  }
+}
Index: branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/DataAnalysisSolution.cs
===================================================================
--- branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/DataAnalysisSolution.cs	(revision 9073)
+++ branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/DataAnalysisSolution.cs	(revision 9073)
@@ -0,0 +1,168 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Drawing;
+using HeuristicLab.Common;
+using HeuristicLab.Optimization;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  /// <summary>
+  /// Abstract base class for data analysis solutions
+  /// </summary>
+  [StorableClass]
+  public abstract class DataAnalysisSolution : ResultCollection, IDataAnalysisSolution {
+    private const string ModelResultName = "Model";
+    private const string ProblemDataResultName = "ProblemData";
+
+    public string Filename { get; set; }
+
+    public static new Image StaticItemImage {
+      get { return HeuristicLab.Common.Resources.VSImageLibrary.Function; }
+    }
+
+    #region properties
+    public IDataAnalysisModel Model {
+      get { return (IDataAnalysisModel)this[ModelResultName].Value; }
+      protected set {
+        if (this[ModelResultName].Value != value) {
+          if (value != null) {
+            this[ModelResultName].Value = value;
+            OnModelChanged();
+          }
+        }
+      }
+    }
+
+    public IDataAnalysisProblemData ProblemData {
+      get { return (IDataAnalysisProblemData)this[ProblemDataResultName].Value; }
+      set {
+        if (this[ProblemDataResultName].Value != value) {
+          if (value != null) {
+            ProblemData.Changed -= new EventHandler(ProblemData_Changed);
+            this[ProblemDataResultName].Value = value;
+            ProblemData.Changed += new EventHandler(ProblemData_Changed);
+            OnProblemDataChanged();
+          }
+        }
+      }
+    }
+    #endregion
+
+    [StorableConstructor]
+    protected DataAnalysisSolution(bool deserializing) : base(deserializing) { }
+    protected DataAnalysisSolution(DataAnalysisSolution original, Cloner cloner)
+      : base(original, cloner) {
+      name = original.Name;
+      description = original.Description;
+    }
+    public DataAnalysisSolution(IDataAnalysisModel model, IDataAnalysisProblemData problemData)
+      : base() {
+      name = ItemName;
+      description = ItemDescription;
+      Add(new Result(ModelResultName, "The data analysis model.", model));
+      Add(new Result(ProblemDataResultName, "The data analysis problem data.", problemData));
+
+      problemData.Changed += new EventHandler(ProblemData_Changed);
+    }
+
+    protected abstract void RecalculateResults();
+
+    private void ProblemData_Changed(object sender, EventArgs e) {
+      OnProblemDataChanged();
+    }
+
+    public event EventHandler ModelChanged;
+    protected virtual void OnModelChanged() {
+      RecalculateResults();
+      var listeners = ModelChanged;
+      if (listeners != null) listeners(this, EventArgs.Empty);
+    }
+
+    public event EventHandler ProblemDataChanged;
+    protected virtual void OnProblemDataChanged() {
+      RecalculateResults();
+      var listeners = ProblemDataChanged;
+      if (listeners != null) listeners(this, EventArgs.Empty);
+    }
+
+    #region INamedItem Members
+    [Storable]
+    protected string name;
+    public string Name {
+      get { return name; }
+      set {
+        if (!CanChangeName) throw new NotSupportedException("Name cannot be changed.");
+        if (!(name.Equals(value) || (value == null) && (name == string.Empty))) {
+          CancelEventArgs<string> e = value == null ? new CancelEventArgs<string>(string.Empty) : new CancelEventArgs<string>(value);
+          OnNameChanging(e);
+          if (!e.Cancel) {
+            name = value == null ? string.Empty : value;
+            OnNameChanged();
+          }
+        }
+      }
+    }
+    public virtual bool CanChangeName {
+      get { return true; }
+    }
+    [Storable]
+    protected string description;
+    public string Description {
+      get { return description; }
+      set {
+        if (!CanChangeDescription) throw new NotSupportedException("Description cannot be changed.");
+        if (!(description.Equals(value) || (value == null) && (description == string.Empty))) {
+          description = value == null ? string.Empty : value;
+          OnDescriptionChanged();
+        }
+      }
+    }
+    public virtual bool CanChangeDescription {
+      get { return true; }
+    }
+
+    public override string ToString() {
+      return Name;
+    }
+
+    public event EventHandler<CancelEventArgs<string>> NameChanging;
+    protected virtual void OnNameChanging(CancelEventArgs<string> e) {
+      var handler = NameChanging;
+      if (handler != null) handler(this, e);
+    }
+
+    public event EventHandler NameChanged;
+    protected virtual void OnNameChanged() {
+      var handler = NameChanged;
+      if (handler != null) handler(this, EventArgs.Empty);
+      OnToStringChanged();
+    }
+
+    public event EventHandler DescriptionChanged;
+    protected virtual void OnDescriptionChanged() {
+      var handler = DescriptionChanged;
+      if (handler != null) handler(this, EventArgs.Empty);
+    }
+    #endregion
+  }
+}
Index: branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/ConstantRegressionModel.cs
===================================================================
--- branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/ConstantRegressionModel.cs	(revision 9073)
+++ branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/ConstantRegressionModel.cs	(revision 9073)
@@ -0,0 +1,60 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  [Item("Constant Regression Model", "A model that always returns the same constant value regardless of the presented input data.")]
+  public class ConstantRegressionModel : NamedItem, IRegressionModel {
+    [Storable]
+    protected double constant;
+    public double Constant {
+      get { return constant; }
+    }
+
+    [StorableConstructor]
+    protected ConstantRegressionModel(bool deserializing) : base(deserializing) { }
+    protected ConstantRegressionModel(ConstantRegressionModel original, Cloner cloner)
+      : base(original, cloner) {
+      this.constant = original.constant;
+    }
+    public override IDeepCloneable Clone(Cloner cloner) { return new ConstantRegressionModel(this, cloner); }
+
+    public ConstantRegressionModel(double constant)
+      : base() {
+      this.name = ItemName;
+      this.description = ItemDescription;
+      this.constant = constant;
+    }
+
+    public IEnumerable<double> GetEstimatedValues(Dataset dataset, IEnumerable<int> rows) {
+      return rows.Select(row => Constant);
+    }
+
+    public IRegressionSolution CreateRegressionSolution(IRegressionProblemData problemData) {
+      return new ConstantRegressionSolution(this, new RegressionProblemData(problemData));
+    }
+  }
+}
Index: branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/ConstantRegressionSolution.cs
===================================================================
--- branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/ConstantRegressionSolution.cs	(revision 9073)
+++ branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/ConstantRegressionSolution.cs	(revision 9073)
@@ -0,0 +1,47 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  [StorableClass]
+  [Item(Name = "Constant Regression Solution", Description = "Represents a constant regression solution (model + data).")]
+  public class ConstantRegressionSolution : RegressionSolution {
+    public new ConstantRegressionModel Model {
+      get { return (ConstantRegressionModel)base.Model; }
+      set { base.Model = value; }
+    }
+
+    [StorableConstructor]
+    protected ConstantRegressionSolution(bool deserializing) : base(deserializing) { }
+    protected ConstantRegressionSolution(ConstantRegressionSolution original, Cloner cloner) : base(original, cloner) { }
+    public ConstantRegressionSolution(ConstantRegressionModel model, IRegressionProblemData problemData)
+      : base(model, problemData) {
+      RecalculateResults();
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new ConstantRegressionSolution(this, cloner);
+    }
+  }
+}
Index: branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/RegressionEnsembleModel.cs
===================================================================
--- branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/RegressionEnsembleModel.cs	(revision 9073)
+++ branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/RegressionEnsembleModel.cs	(revision 9073)
@@ -0,0 +1,112 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  /// <summary>
+  /// Represents regression solutions that contain an ensemble of multiple regression models
+  /// </summary>
+  [StorableClass]
+  [Item("RegressionEnsembleModel", "A regression model that contains an ensemble of multiple regression models")]
+  public class RegressionEnsembleModel : NamedItem, IRegressionEnsembleModel {
+
+    private List<IRegressionModel> models;
+    public IEnumerable<IRegressionModel> Models {
+      get { return new List<IRegressionModel>(models); }
+    }
+
+    [Storable(Name = "Models")]
+    private IEnumerable<IRegressionModel> StorableModels {
+      get { return models; }
+      set { models = value.ToList(); }
+    }
+
+    #region backwards compatiblity 3.3.5
+    [Storable(Name = "models", AllowOneWay = true)]
+    private List<IRegressionModel> OldStorableModels {
+      set { models = value; }
+    }
+    #endregion
+
+    [StorableConstructor]
+    protected RegressionEnsembleModel(bool deserializing) : base(deserializing) { }
+    protected RegressionEnsembleModel(RegressionEnsembleModel original, Cloner cloner)
+      : base(original, cloner) {
+      this.models = original.Models.Select(m => cloner.Clone(m)).ToList();
+    }
+
+    public RegressionEnsembleModel() : this(Enumerable.Empty<IRegressionModel>()) { }
+    public RegressionEnsembleModel(IEnumerable<IRegressionModel> models)
+      : base() {
+      this.name = ItemName;
+      this.description = ItemDescription;
+      this.models = new List<IRegressionModel>(models);
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new RegressionEnsembleModel(this, cloner);
+    }
+
+    #region IRegressionEnsembleModel Members
+
+    public void Add(IRegressionModel model) {
+      models.Add(model);
+    }
+    public void Remove(IRegressionModel model) {
+      models.Remove(model);
+    }
+
+    public IEnumerable<IEnumerable<double>> GetEstimatedValueVectors(Dataset dataset, IEnumerable<int> rows) {
+      var estimatedValuesEnumerators = (from model in models
+                                        select model.GetEstimatedValues(dataset, rows).GetEnumerator())
+                                       .ToList();
+
+      while (estimatedValuesEnumerators.All(en => en.MoveNext())) {
+        yield return from enumerator in estimatedValuesEnumerators
+                     select enumerator.Current;
+      }
+    }
+
+    #endregion
+
+    #region IRegressionModel Members
+
+    public IEnumerable<double> GetEstimatedValues(Dataset dataset, IEnumerable<int> rows) {
+      foreach (var estimatedValuesVector in GetEstimatedValueVectors(dataset, rows)) {
+        yield return estimatedValuesVector.Average();
+      }
+    }
+
+    public RegressionEnsembleSolution CreateRegressionSolution(IRegressionProblemData problemData) {
+      return new RegressionEnsembleSolution(this.Models, new RegressionEnsembleProblemData(problemData));
+    }
+    IRegressionSolution IRegressionModel.CreateRegressionSolution(IRegressionProblemData problemData) {
+      return CreateRegressionSolution(problemData);
+    }
+
+    #endregion
+  }
+}
Index: branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/RegressionEnsembleProblemData.cs
===================================================================
--- branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/RegressionEnsembleProblemData.cs	(revision 9073)
+++ branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/RegressionEnsembleProblemData.cs	(revision 9073)
@@ -0,0 +1,83 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Collections.Generic;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  [StorableClass]
+  [Item("RegressionEnsembleProblemData", "Represents an item containing all data defining a regression problem.")]
+  public sealed class RegressionEnsembleProblemData : RegressionProblemData {
+
+    public override bool IsTrainingSample(int index) {
+      return index >= 0 && index < Dataset.Rows &&
+             TrainingPartition.Start <= index && index < TrainingPartition.End;
+    }
+
+    public override bool IsTestSample(int index) {
+      return index >= 0 && index < Dataset.Rows &&
+             TestPartition.Start <= index && index < TestPartition.End;
+    }
+
+    private static readonly RegressionEnsembleProblemData emptyProblemData;
+    public new static RegressionEnsembleProblemData EmptyProblemData {
+      get { return emptyProblemData; }
+    }
+    static RegressionEnsembleProblemData() {
+      var problemData = new RegressionEnsembleProblemData();
+      problemData.Parameters.Clear();
+      problemData.Name = "Empty Regression ProblemData";
+      problemData.Description = "This ProblemData acts as place holder before the correct problem data is loaded.";
+      problemData.isEmpty = true;
+
+      problemData.Parameters.Add(new FixedValueParameter<Dataset>(DatasetParameterName, "", new Dataset()));
+      problemData.Parameters.Add(new FixedValueParameter<ReadOnlyCheckedItemList<StringValue>>(InputVariablesParameterName, ""));
+      problemData.Parameters.Add(new FixedValueParameter<IntRange>(TrainingPartitionParameterName, "", (IntRange)new IntRange(0, 0).AsReadOnly()));
+      problemData.Parameters.Add(new FixedValueParameter<IntRange>(TestPartitionParameterName, "", (IntRange)new IntRange(0, 0).AsReadOnly()));
+      problemData.Parameters.Add(new ConstrainedValueParameter<StringValue>(TargetVariableParameterName, new ItemSet<StringValue>()));
+      emptyProblemData = problemData;
+    }
+
+    [StorableConstructor]
+    private RegressionEnsembleProblemData(bool deserializing) : base(deserializing) { }
+    private RegressionEnsembleProblemData(RegressionEnsembleProblemData original, Cloner cloner) : base(original, cloner) { }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      if (this == emptyProblemData) return emptyProblemData;
+      return new RegressionEnsembleProblemData(this, cloner);
+    }
+
+    public RegressionEnsembleProblemData() : base() { }
+    public RegressionEnsembleProblemData(IRegressionProblemData regressionProblemData)
+      : base(regressionProblemData.Dataset, regressionProblemData.AllowedInputVariables, regressionProblemData.TargetVariable) {
+      TrainingPartition.Start = regressionProblemData.TrainingPartition.Start;
+      TrainingPartition.End = regressionProblemData.TrainingPartition.End;
+      TestPartition.Start = regressionProblemData.TestPartition.Start;
+      TestPartition.End = regressionProblemData.TestPartition.End;
+    }
+    public RegressionEnsembleProblemData(Dataset dataset, IEnumerable<string> allowedInputVariables, string targetVariable)
+      : base(dataset, allowedInputVariables, targetVariable) {
+    }
+  }
+}
Index: branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/RegressionEnsembleSolution.cs
===================================================================
--- branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/RegressionEnsembleSolution.cs	(revision 9073)
+++ branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/RegressionEnsembleSolution.cs	(revision 9073)
@@ -0,0 +1,332 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Collections;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  /// <summary>
+  /// Represents regression solutions that contain an ensemble of multiple regression models
+  /// </summary>
+  [StorableClass]
+  [Item("Regression Ensemble Solution", "A regression solution that contains an ensemble of multiple regression models")]
+  [Creatable("Data Analysis - Ensembles")]
+  public sealed class RegressionEnsembleSolution : RegressionSolutionBase, IRegressionEnsembleSolution {
+    private readonly Dictionary<int, double> trainingEvaluationCache = new Dictionary<int, double>();
+    private readonly Dictionary<int, double> testEvaluationCache = new Dictionary<int, double>();
+    private readonly Dictionary<int, double> evaluationCache = new Dictionary<int, double>();
+
+    public new IRegressionEnsembleModel Model {
+      get { return (IRegressionEnsembleModel)base.Model; }
+    }
+
+    public new RegressionEnsembleProblemData ProblemData {
+      get { return (RegressionEnsembleProblemData)base.ProblemData; }
+      set { base.ProblemData = value; }
+    }
+
+    private readonly ItemCollection<IRegressionSolution> regressionSolutions;
+    public IItemCollection<IRegressionSolution> RegressionSolutions {
+      get { return regressionSolutions; }
+    }
+
+    [Storable]
+    private readonly Dictionary<IRegressionModel, IntRange> trainingPartitions;
+    [Storable]
+    private readonly Dictionary<IRegressionModel, IntRange> testPartitions;
+
+    [StorableConstructor]
+    private RegressionEnsembleSolution(bool deserializing)
+      : base(deserializing) {
+      regressionSolutions = new ItemCollection<IRegressionSolution>();
+    }
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() {
+      foreach (var model in Model.Models) {
+        IRegressionProblemData problemData = (IRegressionProblemData)ProblemData.Clone();
+        problemData.TrainingPartition.Start = trainingPartitions[model].Start;
+        problemData.TrainingPartition.End = trainingPartitions[model].End;
+        problemData.TestPartition.Start = testPartitions[model].Start;
+        problemData.TestPartition.End = testPartitions[model].End;
+
+        regressionSolutions.Add(model.CreateRegressionSolution(problemData));
+      }
+      RegisterRegressionSolutionsEventHandler();
+    }
+
+    private RegressionEnsembleSolution(RegressionEnsembleSolution original, Cloner cloner)
+      : base(original, cloner) {
+      trainingPartitions = new Dictionary<IRegressionModel, IntRange>();
+      testPartitions = new Dictionary<IRegressionModel, IntRange>();
+      foreach (var pair in original.trainingPartitions) {
+        trainingPartitions[cloner.Clone(pair.Key)] = cloner.Clone(pair.Value);
+      }
+      foreach (var pair in original.testPartitions) {
+        testPartitions[cloner.Clone(pair.Key)] = cloner.Clone(pair.Value);
+      }
+
+      trainingEvaluationCache = new Dictionary<int, double>(original.ProblemData.TrainingIndices.Count());
+      testEvaluationCache = new Dictionary<int, double>(original.ProblemData.TestIndices.Count());
+
+      regressionSolutions = cloner.Clone(original.regressionSolutions);
+      RegisterRegressionSolutionsEventHandler();
+    }
+
+    public RegressionEnsembleSolution()
+      : base(new RegressionEnsembleModel(), RegressionEnsembleProblemData.EmptyProblemData) {
+      trainingPartitions = new Dictionary<IRegressionModel, IntRange>();
+      testPartitions = new Dictionary<IRegressionModel, IntRange>();
+      regressionSolutions = new ItemCollection<IRegressionSolution>();
+
+      RegisterRegressionSolutionsEventHandler();
+    }
+
+    public RegressionEnsembleSolution(IRegressionProblemData problemData)
+      : this(Enumerable.Empty<IRegressionModel>(), problemData) {
+    }
+
+    public RegressionEnsembleSolution(IEnumerable<IRegressionModel> models, IRegressionProblemData problemData)
+      : this(models, problemData,
+             models.Select(m => (IntRange)problemData.TrainingPartition.Clone()),
+             models.Select(m => (IntRange)problemData.TestPartition.Clone())
+      ) { }
+
+    public RegressionEnsembleSolution(IEnumerable<IRegressionModel> models, IRegressionProblemData problemData, IEnumerable<IntRange> trainingPartitions, IEnumerable<IntRange> testPartitions)
+      : base(new RegressionEnsembleModel(Enumerable.Empty<IRegressionModel>()), new RegressionEnsembleProblemData(problemData)) {
+      this.trainingPartitions = new Dictionary<IRegressionModel, IntRange>();
+      this.testPartitions = new Dictionary<IRegressionModel, IntRange>();
+      this.regressionSolutions = new ItemCollection<IRegressionSolution>();
+
+      List<IRegressionSolution> solutions = new List<IRegressionSolution>();
+      var modelEnumerator = models.GetEnumerator();
+      var trainingPartitionEnumerator = trainingPartitions.GetEnumerator();
+      var testPartitionEnumerator = testPartitions.GetEnumerator();
+
+      while (modelEnumerator.MoveNext() & trainingPartitionEnumerator.MoveNext() & testPartitionEnumerator.MoveNext()) {
+        var p = (IRegressionProblemData)problemData.Clone();
+        p.TrainingPartition.Start = trainingPartitionEnumerator.Current.Start;
+        p.TrainingPartition.End = trainingPartitionEnumerator.Current.End;
+        p.TestPartition.Start = testPartitionEnumerator.Current.Start;
+        p.TestPartition.End = testPartitionEnumerator.Current.End;
+
+        solutions.Add(modelEnumerator.Current.CreateRegressionSolution(p));
+      }
+      if (modelEnumerator.MoveNext() | trainingPartitionEnumerator.MoveNext() | testPartitionEnumerator.MoveNext()) {
+        throw new ArgumentException();
+      }
+
+      trainingEvaluationCache = new Dictionary<int, double>(problemData.TrainingIndices.Count());
+      testEvaluationCache = new Dictionary<int, double>(problemData.TestIndices.Count());
+
+      RegisterRegressionSolutionsEventHandler();
+      regressionSolutions.AddRange(solutions);
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new RegressionEnsembleSolution(this, cloner);
+    }
+    private void RegisterRegressionSolutionsEventHandler() {
+      regressionSolutions.ItemsAdded += new CollectionItemsChangedEventHandler<IRegressionSolution>(regressionSolutions_ItemsAdded);
+      regressionSolutions.ItemsRemoved += new CollectionItemsChangedEventHandler<IRegressionSolution>(regressionSolutions_ItemsRemoved);
+      regressionSolutions.CollectionReset += new CollectionItemsChangedEventHandler<IRegressionSolution>(regressionSolutions_CollectionReset);
+    }
+
+    #region Evaluation
+    public override IEnumerable<double> EstimatedValues {
+      get { return GetEstimatedValues(Enumerable.Range(0, ProblemData.Dataset.Rows)); }
+    }
+
+    public override IEnumerable<double> EstimatedTrainingValues {
+      get {
+        var rows = ProblemData.TrainingIndices;
+        var rowsToEvaluate = rows.Except(trainingEvaluationCache.Keys);
+        var rowsEnumerator = rowsToEvaluate.GetEnumerator();
+        var valuesEnumerator = GetEstimatedValues(rowsToEvaluate, (r, m) => RowIsTrainingForModel(r, m) && !RowIsTestForModel(r, m)).GetEnumerator();
+
+        while (rowsEnumerator.MoveNext() & valuesEnumerator.MoveNext()) {
+          trainingEvaluationCache.Add(rowsEnumerator.Current, valuesEnumerator.Current);
+        }
+
+        return rows.Select(row => trainingEvaluationCache[row]);
+      }
+    }
+
+    public override IEnumerable<double> EstimatedTestValues {
+      get {
+        var rows = ProblemData.TestIndices;
+        var rowsToEvaluate = rows.Except(testEvaluationCache.Keys);
+        var rowsEnumerator = rowsToEvaluate.GetEnumerator();
+        var valuesEnumerator = GetEstimatedValues(rowsToEvaluate, RowIsTestForModel).GetEnumerator();
+
+        while (rowsEnumerator.MoveNext() & valuesEnumerator.MoveNext()) {
+          testEvaluationCache.Add(rowsEnumerator.Current, valuesEnumerator.Current);
+        }
+
+        return rows.Select(row => testEvaluationCache[row]);
+      }
+    }
+
+    private IEnumerable<double> GetEstimatedValues(IEnumerable<int> rows, Func<int, IRegressionModel, bool> modelSelectionPredicate) {
+      var estimatedValuesEnumerators = (from model in Model.Models
+                                        select new { Model = model, EstimatedValuesEnumerator = model.GetEstimatedValues(ProblemData.Dataset, rows).GetEnumerator() })
+                                       .ToList();
+      var rowsEnumerator = rows.GetEnumerator();
+      // aggregate to make sure that MoveNext is called for all enumerators 
+      while (rowsEnumerator.MoveNext() & estimatedValuesEnumerators.Select(en => en.EstimatedValuesEnumerator.MoveNext()).Aggregate(true, (acc, b) => acc & b)) {
+        int currentRow = rowsEnumerator.Current;
+
+        var selectedEnumerators = from pair in estimatedValuesEnumerators
+                                  where modelSelectionPredicate(currentRow, pair.Model)
+                                  select pair.EstimatedValuesEnumerator;
+
+        yield return AggregateEstimatedValues(selectedEnumerators.Select(x => x.Current));
+      }
+    }
+
+    private bool RowIsTrainingForModel(int currentRow, IRegressionModel model) {
+      return trainingPartitions == null || !trainingPartitions.ContainsKey(model) ||
+              (trainingPartitions[model].Start <= currentRow && currentRow < trainingPartitions[model].End);
+    }
+
+    private bool RowIsTestForModel(int currentRow, IRegressionModel model) {
+      return testPartitions == null || !testPartitions.ContainsKey(model) ||
+              (testPartitions[model].Start <= currentRow && currentRow < testPartitions[model].End);
+    }
+
+    public override IEnumerable<double> GetEstimatedValues(IEnumerable<int> rows) {
+      var rowsToEvaluate = rows.Except(evaluationCache.Keys);
+      var rowsEnumerator = rowsToEvaluate.GetEnumerator();
+      var valuesEnumerator = (from xs in GetEstimatedValueVectors(ProblemData.Dataset, rowsToEvaluate)
+                              select AggregateEstimatedValues(xs))
+                             .GetEnumerator();
+
+      while (rowsEnumerator.MoveNext() & valuesEnumerator.MoveNext()) {
+        evaluationCache.Add(rowsEnumerator.Current, valuesEnumerator.Current);
+      }
+
+      return rows.Select(row => evaluationCache[row]);
+    }
+
+    public IEnumerable<IEnumerable<double>> GetEstimatedValueVectors(Dataset dataset, IEnumerable<int> rows) {
+      if (!Model.Models.Any()) yield break;
+      var estimatedValuesEnumerators = (from model in Model.Models
+                                        select model.GetEstimatedValues(dataset, rows).GetEnumerator())
+                                       .ToList();
+
+      while (estimatedValuesEnumerators.All(en => en.MoveNext())) {
+        yield return from enumerator in estimatedValuesEnumerators
+                     select enumerator.Current;
+      }
+    }
+
+    private double AggregateEstimatedValues(IEnumerable<double> estimatedValues) {
+      return estimatedValues.DefaultIfEmpty(double.NaN).Average();
+    }
+    #endregion
+
+    protected override void OnProblemDataChanged() {
+      trainingEvaluationCache.Clear();
+      testEvaluationCache.Clear();
+      evaluationCache.Clear();
+      IRegressionProblemData problemData = new RegressionProblemData(ProblemData.Dataset,
+                                                                     ProblemData.AllowedInputVariables,
+                                                                     ProblemData.TargetVariable);
+      problemData.TrainingPartition.Start = ProblemData.TrainingPartition.Start;
+      problemData.TrainingPartition.End = ProblemData.TrainingPartition.End;
+      problemData.TestPartition.Start = ProblemData.TestPartition.Start;
+      problemData.TestPartition.End = ProblemData.TestPartition.End;
+
+      foreach (var solution in RegressionSolutions) {
+        if (solution is RegressionEnsembleSolution)
+          solution.ProblemData = ProblemData;
+        else
+          solution.ProblemData = problemData;
+      }
+      foreach (var trainingPartition in trainingPartitions.Values) {
+        trainingPartition.Start = ProblemData.TrainingPartition.Start;
+        trainingPartition.End = ProblemData.TrainingPartition.End;
+      }
+      foreach (var testPartition in testPartitions.Values) {
+        testPartition.Start = ProblemData.TestPartition.Start;
+        testPartition.End = ProblemData.TestPartition.End;
+      }
+
+      base.OnProblemDataChanged();
+    }
+
+    public void AddRegressionSolutions(IEnumerable<IRegressionSolution> solutions) {
+      regressionSolutions.AddRange(solutions);
+
+      trainingEvaluationCache.Clear();
+      testEvaluationCache.Clear();
+      evaluationCache.Clear();
+    }
+    public void RemoveRegressionSolutions(IEnumerable<IRegressionSolution> solutions) {
+      regressionSolutions.RemoveRange(solutions);
+
+      trainingEvaluationCache.Clear();
+      testEvaluationCache.Clear();
+      evaluationCache.Clear();
+    }
+
+    private void regressionSolutions_ItemsAdded(object sender, CollectionItemsChangedEventArgs<IRegressionSolution> e) {
+      foreach (var solution in e.Items) AddRegressionSolution(solution);
+      RecalculateResults();
+    }
+    private void regressionSolutions_ItemsRemoved(object sender, CollectionItemsChangedEventArgs<IRegressionSolution> e) {
+      foreach (var solution in e.Items) RemoveRegressionSolution(solution);
+      RecalculateResults();
+    }
+    private void regressionSolutions_CollectionReset(object sender, CollectionItemsChangedEventArgs<IRegressionSolution> e) {
+      foreach (var solution in e.OldItems) RemoveRegressionSolution(solution);
+      foreach (var solution in e.Items) AddRegressionSolution(solution);
+      RecalculateResults();
+    }
+
+    private void AddRegressionSolution(IRegressionSolution solution) {
+      if (Model.Models.Contains(solution.Model)) throw new ArgumentException();
+      Model.Add(solution.Model);
+      trainingPartitions[solution.Model] = solution.ProblemData.TrainingPartition;
+      testPartitions[solution.Model] = solution.ProblemData.TestPartition;
+
+      trainingEvaluationCache.Clear();
+      testEvaluationCache.Clear();
+      evaluationCache.Clear();
+    }
+
+    private void RemoveRegressionSolution(IRegressionSolution solution) {
+      if (!Model.Models.Contains(solution.Model)) throw new ArgumentException();
+      Model.Remove(solution.Model);
+      trainingPartitions.Remove(solution.Model);
+      testPartitions.Remove(solution.Model);
+
+      trainingEvaluationCache.Clear();
+      testEvaluationCache.Clear();
+      evaluationCache.Clear();
+    }
+  }
+}
Index: branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/RegressionProblem.cs
===================================================================
--- branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/RegressionProblem.cs	(revision 9073)
+++ branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/RegressionProblem.cs	(revision 9073)
@@ -0,0 +1,41 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  [StorableClass]
+  [Item("Regression Problem", "A general regression problem.")]
+  [Creatable("Problems")]
+  public class RegressionProblem : DataAnalysisProblem<IRegressionProblemData>, IRegressionProblem, IStorableContent {
+    public string Filename { get; set; }
+
+    [StorableConstructor]
+    protected RegressionProblem(bool deserializing) : base(deserializing) { }
+    protected RegressionProblem(RegressionProblem original, Cloner cloner) : base(original, cloner) { }
+    public override IDeepCloneable Clone(Cloner cloner) { return new RegressionProblem(this, cloner); }
+
+    public RegressionProblem() : base(new RegressionProblemData()) { }
+
+  }
+}
Index: branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/RegressionProblemData.cs
===================================================================
--- branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/RegressionProblemData.cs	(revision 9073)
+++ branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/RegressionProblemData.cs	(revision 9073)
@@ -0,0 +1,145 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  [StorableClass]
+  [Item("RegressionProblemData", "Represents an item containing all data defining a regression problem.")]
+  public class RegressionProblemData : DataAnalysisProblemData, IRegressionProblemData, IStorableContent {
+    protected const string TargetVariableParameterName = "TargetVariable";
+    public string Filename { get; set; }
+
+    #region default data
+    private static double[,] kozaF1 = new double[,] {
+          {2.017885919,	-1.449165046},
+          {1.30060506,	-1.344523885},
+          {1.147134798,	-1.317989331},
+          {0.877182504,	-1.266142284},
+          {0.852562452,	-1.261020794},
+          {0.431095788,	-1.158793317},
+          {0.112586002,	-1.050908405},
+          {0.04594507,	-1.021989402},
+          {0.042572879,	-1.020438113},
+          {-0.074027291,	-0.959859562},
+          {-0.109178553,	-0.938094706},
+          {-0.259721109,	-0.803635355},
+          {-0.272991057,	-0.387519561},
+          {-0.161978191,	-0.193611001},
+          {-0.102489983,	-0.114215349},
+          {-0.01469968,	-0.014918985},
+          {-0.008863365,	-0.008942626},
+          {0.026751057,	0.026054094},
+          {0.166922436,	0.14309643},
+          {0.176953808,	0.1504144},
+          {0.190233418,	0.159916534},
+          {0.199800708,	0.166635331},
+          {0.261502822,	0.207600348},
+          {0.30182879,	0.232370249},
+          {0.83763905,	0.468046718}
+    };
+    private static readonly Dataset defaultDataset;
+    private static readonly IEnumerable<string> defaultAllowedInputVariables;
+    private static readonly string defaultTargetVariable;
+
+    private static readonly RegressionProblemData emptyProblemData;
+    public static RegressionProblemData EmptyProblemData {
+      get { return emptyProblemData; }
+    }
+
+    static RegressionProblemData() {
+      defaultDataset = new Dataset(new string[] { "y", "x" }, kozaF1);
+      defaultDataset.Name = "Fourth-order Polynomial Function Benchmark Dataset";
+      defaultDataset.Description = "f(x) = x^4 + x^3 + x^2 + x^1";
+      defaultAllowedInputVariables = new List<string>() { "x" };
+      defaultTargetVariable = "y";
+
+      var problemData = new RegressionProblemData();
+      problemData.Parameters.Clear();
+      problemData.Name = "Empty Regression ProblemData";
+      problemData.Description = "This ProblemData acts as place holder before the correct problem data is loaded.";
+      problemData.isEmpty = true;
+
+      problemData.Parameters.Add(new FixedValueParameter<Dataset>(DatasetParameterName, "", new Dataset()));
+      problemData.Parameters.Add(new FixedValueParameter<ReadOnlyCheckedItemList<StringValue>>(InputVariablesParameterName, ""));
+      problemData.Parameters.Add(new FixedValueParameter<IntRange>(TrainingPartitionParameterName, "", (IntRange)new IntRange(0, 0).AsReadOnly()));
+      problemData.Parameters.Add(new FixedValueParameter<IntRange>(TestPartitionParameterName, "", (IntRange)new IntRange(0, 0).AsReadOnly()));
+      problemData.Parameters.Add(new ConstrainedValueParameter<StringValue>(TargetVariableParameterName, new ItemSet<StringValue>()));
+      emptyProblemData = problemData;
+    }
+    #endregion
+
+    public IConstrainedValueParameter<StringValue> TargetVariableParameter {
+      get { return (IConstrainedValueParameter<StringValue>)Parameters[TargetVariableParameterName]; }
+    }
+    public string TargetVariable {
+      get { return TargetVariableParameter.Value.Value; }
+    }
+
+    [StorableConstructor]
+    protected RegressionProblemData(bool deserializing) : base(deserializing) { }
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() {
+      RegisterParameterEvents();
+    }
+
+    protected RegressionProblemData(RegressionProblemData original, Cloner cloner)
+      : base(original, cloner) {
+      RegisterParameterEvents();
+    }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      if (this == emptyProblemData) return emptyProblemData;
+      return new RegressionProblemData(this, cloner);
+    }
+
+    public RegressionProblemData()
+      : this(defaultDataset, defaultAllowedInputVariables, defaultTargetVariable) {
+    }
+    public RegressionProblemData(IRegressionProblemData regressionProblemData)
+      : this(regressionProblemData.Dataset, regressionProblemData.AllowedInputVariables, regressionProblemData.TargetVariable) {
+      TrainingPartition.Start = regressionProblemData.TrainingPartition.Start;
+      TrainingPartition.End = regressionProblemData.TrainingPartition.End;
+      TestPartition.Start = regressionProblemData.TestPartition.Start;
+      TestPartition.End = regressionProblemData.TestPartition.End;
+    }
+
+    public RegressionProblemData(Dataset dataset, IEnumerable<string> allowedInputVariables, string targetVariable)
+      : base(dataset, allowedInputVariables) {
+      var variables = InputVariables.Select(x => x.AsReadOnly()).ToList();
+      Parameters.Add(new ConstrainedValueParameter<StringValue>(TargetVariableParameterName, new ItemSet<StringValue>(variables), variables.Where(x => x.Value == targetVariable).First()));
+      RegisterParameterEvents();
+    }
+
+    private void RegisterParameterEvents() {
+      TargetVariableParameter.ValueChanged += new EventHandler(TargetVariableParameter_ValueChanged);
+    }
+    private void TargetVariableParameter_ValueChanged(object sender, EventArgs e) {
+      OnChanged();
+    }
+  }
+}
Index: branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/RegressionSolution.cs
===================================================================
--- branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/RegressionSolution.cs	(revision 9073)
+++ branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/RegressionSolution.cs	(revision 9073)
@@ -0,0 +1,83 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  /// <summary>
+  /// Represents a regression data analysis solution
+  /// </summary>
+  [StorableClass]
+  public abstract class RegressionSolution : RegressionSolutionBase {
+    protected readonly Dictionary<int, double> evaluationCache;
+
+    [StorableConstructor]
+    protected RegressionSolution(bool deserializing)
+      : base(deserializing) {
+      evaluationCache = new Dictionary<int, double>();
+    }
+    protected RegressionSolution(RegressionSolution original, Cloner cloner)
+      : base(original, cloner) {
+      evaluationCache = new Dictionary<int, double>(original.evaluationCache);
+    }
+    protected RegressionSolution(IRegressionModel model, IRegressionProblemData problemData)
+      : base(model, problemData) {
+      evaluationCache = new Dictionary<int, double>(problemData.Dataset.Rows);
+      CalculateRegressionResults();
+    }
+
+
+    public override IEnumerable<double> EstimatedValues {
+      get { return GetEstimatedValues(Enumerable.Range(0, ProblemData.Dataset.Rows)); }
+    }
+    public override IEnumerable<double> EstimatedTrainingValues {
+      get { return GetEstimatedValues(ProblemData.TrainingIndices); }
+    }
+    public override IEnumerable<double> EstimatedTestValues {
+      get { return GetEstimatedValues(ProblemData.TestIndices); }
+    }
+
+    public override IEnumerable<double> GetEstimatedValues(IEnumerable<int> rows) {
+      var rowsToEvaluate = rows.Except(evaluationCache.Keys);
+      var rowsEnumerator = rowsToEvaluate.GetEnumerator();
+      var valuesEnumerator = Model.GetEstimatedValues(ProblemData.Dataset, rowsToEvaluate).GetEnumerator();
+
+      while (rowsEnumerator.MoveNext() & valuesEnumerator.MoveNext()) {
+        evaluationCache.Add(rowsEnumerator.Current, valuesEnumerator.Current);
+      }
+
+      return rows.Select(row => evaluationCache[row]);
+    }
+
+    protected override void OnProblemDataChanged() {
+      evaluationCache.Clear();
+      base.OnProblemDataChanged();
+    }
+
+    protected override void OnModelChanged() {
+      evaluationCache.Clear();
+      base.OnModelChanged();
+    }
+  }
+}
Index: branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/RegressionSolutionBase.cs
===================================================================
--- branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/RegressionSolutionBase.cs	(revision 9073)
+++ branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/RegressionSolutionBase.cs	(revision 9073)
@@ -0,0 +1,221 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Collections.Generic;
+using HeuristicLab.Common;
+using HeuristicLab.Data;
+using HeuristicLab.Optimization;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  [StorableClass]
+  public abstract class RegressionSolutionBase : DataAnalysisSolution, IRegressionSolution {
+    protected const string TrainingMeanSquaredErrorResultName = "Mean squared error (training)";
+    protected const string TestMeanSquaredErrorResultName = "Mean squared error (test)";
+    protected const string TrainingMeanAbsoluteErrorResultName = "Mean absolute error (training)";
+    protected const string TestMeanAbsoluteErrorResultName = "Mean absolute error (test)";
+    protected const string TrainingSquaredCorrelationResultName = "Pearson's R² (training)";
+    protected const string TestSquaredCorrelationResultName = "Pearson's R² (test)";
+    protected const string TrainingRelativeErrorResultName = "Average relative error (training)";
+    protected const string TestRelativeErrorResultName = "Average relative error (test)";
+    protected const string TrainingNormalizedMeanSquaredErrorResultName = "Normalized mean squared error (training)";
+    protected const string TestNormalizedMeanSquaredErrorResultName = "Normalized mean squared error (test)";
+    protected const string TrainingMeanErrorResultName = "Mean error (training)";
+    protected const string TestMeanErrorResultName = "Mean error (test)";
+
+    protected const string TrainingMeanSquaredErrorResultDescription = "Mean of squared errors of the model on the training partition";
+    protected const string TestMeanSquaredErrorResultDescription = "Mean of squared errors of the model on the test partition";
+    protected const string TrainingMeanAbsoluteErrorResultDescription = "Mean of absolute errors of the model on the training partition";
+    protected const string TestMeanAbsoluteErrorResultDescription = "Mean of absolute errors of the model on the test partition";
+    protected const string TrainingSquaredCorrelationResultDescription = "Squared Pearson's correlation coefficient of the model output and the actual values on the training partition";
+    protected const string TestSquaredCorrelationResultDescription = "Squared Pearson's correlation coefficient of the model output and the actual values on the test partition";
+    protected const string TrainingRelativeErrorResultDescription = "Average of the relative errors of the model output and the actual values on the training partition";
+    protected const string TestRelativeErrorResultDescription = "Average of the relative errors of the model output and the actual values on the test partition";
+    protected const string TrainingNormalizedMeanSquaredErrorResultDescription = "Normalized mean of squared errors of the model on the training partition";
+    protected const string TestNormalizedMeanSquaredErrorResultDescription = "Normalized mean of squared errors of the model on the test partition";
+    protected const string TrainingMeanErrorResultDescription = "Mean of errors of the model on the training partition";
+    protected const string TestMeanErrorResultDescription = "Mean of errors of the model on the test partition";
+
+    public new IRegressionModel Model {
+      get { return (IRegressionModel)base.Model; }
+      protected set { base.Model = value; }
+    }
+
+    public new IRegressionProblemData ProblemData {
+      get { return (IRegressionProblemData)base.ProblemData; }
+      set { base.ProblemData = value; }
+    }
+
+    public abstract IEnumerable<double> EstimatedValues { get; }
+    public abstract IEnumerable<double> EstimatedTrainingValues { get; }
+    public abstract IEnumerable<double> EstimatedTestValues { get; }
+    public abstract IEnumerable<double> GetEstimatedValues(IEnumerable<int> rows);
+
+    #region Results
+    public double TrainingMeanSquaredError {
+      get { return ((DoubleValue)this[TrainingMeanSquaredErrorResultName].Value).Value; }
+      private set { ((DoubleValue)this[TrainingMeanSquaredErrorResultName].Value).Value = value; }
+    }
+    public double TestMeanSquaredError {
+      get { return ((DoubleValue)this[TestMeanSquaredErrorResultName].Value).Value; }
+      private set { ((DoubleValue)this[TestMeanSquaredErrorResultName].Value).Value = value; }
+    }
+    public double TrainingMeanAbsoluteError {
+      get { return ((DoubleValue)this[TrainingMeanAbsoluteErrorResultName].Value).Value; }
+      private set { ((DoubleValue)this[TrainingMeanAbsoluteErrorResultName].Value).Value = value; }
+    }
+    public double TestMeanAbsoluteError {
+      get { return ((DoubleValue)this[TestMeanAbsoluteErrorResultName].Value).Value; }
+      private set { ((DoubleValue)this[TestMeanAbsoluteErrorResultName].Value).Value = value; }
+    }
+    public double TrainingRSquared {
+      get { return ((DoubleValue)this[TrainingSquaredCorrelationResultName].Value).Value; }
+      private set { ((DoubleValue)this[TrainingSquaredCorrelationResultName].Value).Value = value; }
+    }
+    public double TestRSquared {
+      get { return ((DoubleValue)this[TestSquaredCorrelationResultName].Value).Value; }
+      private set { ((DoubleValue)this[TestSquaredCorrelationResultName].Value).Value = value; }
+    }
+    public double TrainingRelativeError {
+      get { return ((DoubleValue)this[TrainingRelativeErrorResultName].Value).Value; }
+      private set { ((DoubleValue)this[TrainingRelativeErrorResultName].Value).Value = value; }
+    }
+    public double TestRelativeError {
+      get { return ((DoubleValue)this[TestRelativeErrorResultName].Value).Value; }
+      private set { ((DoubleValue)this[TestRelativeErrorResultName].Value).Value = value; }
+    }
+    public double TrainingNormalizedMeanSquaredError {
+      get { return ((DoubleValue)this[TrainingNormalizedMeanSquaredErrorResultName].Value).Value; }
+      private set { ((DoubleValue)this[TrainingNormalizedMeanSquaredErrorResultName].Value).Value = value; }
+    }
+    public double TestNormalizedMeanSquaredError {
+      get { return ((DoubleValue)this[TestNormalizedMeanSquaredErrorResultName].Value).Value; }
+      private set { ((DoubleValue)this[TestNormalizedMeanSquaredErrorResultName].Value).Value = value; }
+    }
+    public double TrainingMeanError {
+      get { return ((DoubleValue)this[TrainingMeanErrorResultName].Value).Value; }
+      private set { ((DoubleValue)this[TrainingMeanErrorResultName].Value).Value = value; }
+    }
+    public double TestMeanError {
+      get { return ((DoubleValue)this[TestMeanErrorResultName].Value).Value; }
+      private set { ((DoubleValue)this[TestMeanErrorResultName].Value).Value = value; }
+    }
+    #endregion
+
+    [StorableConstructor]
+    protected RegressionSolutionBase(bool deserializing) : base(deserializing) { }
+    protected RegressionSolutionBase(RegressionSolutionBase original, Cloner cloner)
+      : base(original, cloner) {
+    }
+    protected RegressionSolutionBase(IRegressionModel model, IRegressionProblemData problemData)
+      : base(model, problemData) {
+      Add(new Result(TrainingMeanSquaredErrorResultName, TrainingMeanSquaredErrorResultDescription, new DoubleValue()));
+      Add(new Result(TestMeanSquaredErrorResultName, TestMeanSquaredErrorResultDescription, new DoubleValue()));
+      Add(new Result(TrainingMeanAbsoluteErrorResultName, TrainingMeanAbsoluteErrorResultDescription, new DoubleValue()));
+      Add(new Result(TestMeanAbsoluteErrorResultName, TestMeanAbsoluteErrorResultDescription, new DoubleValue()));
+      Add(new Result(TrainingSquaredCorrelationResultName, TrainingSquaredCorrelationResultDescription, new DoubleValue()));
+      Add(new Result(TestSquaredCorrelationResultName, TestSquaredCorrelationResultDescription, new DoubleValue()));
+      Add(new Result(TrainingRelativeErrorResultName, TrainingRelativeErrorResultDescription, new PercentValue()));
+      Add(new Result(TestRelativeErrorResultName, TestRelativeErrorResultDescription, new PercentValue()));
+      Add(new Result(TrainingNormalizedMeanSquaredErrorResultName, TrainingNormalizedMeanSquaredErrorResultDescription, new DoubleValue()));
+      Add(new Result(TestNormalizedMeanSquaredErrorResultName, TestNormalizedMeanSquaredErrorResultDescription, new DoubleValue()));
+      Add(new Result(TrainingMeanErrorResultName, TrainingMeanErrorResultDescription, new DoubleValue()));
+      Add(new Result(TestMeanErrorResultName, TestMeanErrorResultDescription, new DoubleValue()));
+    }
+
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() {
+      // BackwardsCompatibility3.4
+
+      #region Backwards compatible code, remove with 3.5
+
+      if (!ContainsKey(TrainingMeanAbsoluteErrorResultName)) {
+        OnlineCalculatorError errorState;
+        Add(new Result(TrainingMeanAbsoluteErrorResultName, "Mean of absolute errors of the model on the training partition", new DoubleValue()));
+        double trainingMAE = OnlineMeanAbsoluteErrorCalculator.Calculate(EstimatedTrainingValues, ProblemData.Dataset.GetDoubleValues(ProblemData.TargetVariable, ProblemData.TrainingIndices), out errorState);
+        TrainingMeanAbsoluteError = errorState == OnlineCalculatorError.None ? trainingMAE : double.NaN;
+      }
+
+      if (!ContainsKey(TestMeanAbsoluteErrorResultName)) {
+        OnlineCalculatorError errorState;
+        Add(new Result(TestMeanAbsoluteErrorResultName, "Mean of absolute errors of the model on the test partition", new DoubleValue()));
+        double testMAE = OnlineMeanAbsoluteErrorCalculator.Calculate(EstimatedTestValues, ProblemData.Dataset.GetDoubleValues(ProblemData.TargetVariable, ProblemData.TestIndices), out errorState);
+        TestMeanAbsoluteError = errorState == OnlineCalculatorError.None ? testMAE : double.NaN;
+      }
+
+      if (!ContainsKey(TrainingMeanErrorResultName)) {
+        OnlineCalculatorError errorState;
+        Add(new Result(TrainingMeanErrorResultName, "Mean of errors of the model on the training partition", new DoubleValue()));
+        double trainingME = OnlineMeanErrorCalculator.Calculate(EstimatedTrainingValues, ProblemData.Dataset.GetDoubleValues(ProblemData.TargetVariable, ProblemData.TrainingIndices), out errorState);
+        TrainingMeanError = errorState == OnlineCalculatorError.None ? trainingME : double.NaN;
+      }
+      if (!ContainsKey(TestMeanErrorResultName)) {
+        OnlineCalculatorError errorState;
+        Add(new Result(TestMeanErrorResultName, "Mean of errors of the model on the test partition", new DoubleValue()));
+        double testME = OnlineMeanErrorCalculator.Calculate(EstimatedTestValues, ProblemData.Dataset.GetDoubleValues(ProblemData.TargetVariable, ProblemData.TestIndices), out errorState);
+        TestMeanError = errorState == OnlineCalculatorError.None ? testME : double.NaN;
+      }
+      #endregion
+    }
+
+    protected override void RecalculateResults() {
+      CalculateRegressionResults();
+    }
+
+    protected void CalculateRegressionResults() {
+      IEnumerable<double> estimatedTrainingValues = EstimatedTrainingValues; // cache values
+      IEnumerable<double> originalTrainingValues = ProblemData.Dataset.GetDoubleValues(ProblemData.TargetVariable, ProblemData.TrainingIndices);
+      IEnumerable<double> estimatedTestValues = EstimatedTestValues; // cache values
+      IEnumerable<double> originalTestValues = ProblemData.Dataset.GetDoubleValues(ProblemData.TargetVariable, ProblemData.TestIndices);
+
+      OnlineCalculatorError errorState;
+      double trainingMSE = OnlineMeanSquaredErrorCalculator.Calculate(originalTrainingValues, estimatedTrainingValues, out errorState);
+      TrainingMeanSquaredError = errorState == OnlineCalculatorError.None ? trainingMSE : double.NaN;
+      double testMSE = OnlineMeanSquaredErrorCalculator.Calculate(originalTestValues, estimatedTestValues, out errorState);
+      TestMeanSquaredError = errorState == OnlineCalculatorError.None ? testMSE : double.NaN;
+
+      double trainingMAE = OnlineMeanAbsoluteErrorCalculator.Calculate(originalTrainingValues, estimatedTrainingValues, out errorState);
+      TrainingMeanAbsoluteError = errorState == OnlineCalculatorError.None ? trainingMAE : double.NaN;
+      double testMAE = OnlineMeanAbsoluteErrorCalculator.Calculate(originalTestValues, estimatedTestValues, out errorState);
+      TestMeanAbsoluteError = errorState == OnlineCalculatorError.None ? testMAE : double.NaN;
+
+      double trainingR2 = OnlinePearsonsRSquaredCalculator.Calculate(originalTrainingValues, estimatedTrainingValues, out errorState);
+      TrainingRSquared = errorState == OnlineCalculatorError.None ? trainingR2 : double.NaN;
+      double testR2 = OnlinePearsonsRSquaredCalculator.Calculate(originalTestValues, estimatedTestValues, out errorState);
+      TestRSquared = errorState == OnlineCalculatorError.None ? testR2 : double.NaN;
+
+      double trainingRelError = OnlineMeanAbsolutePercentageErrorCalculator.Calculate(originalTrainingValues, estimatedTrainingValues, out errorState);
+      TrainingRelativeError = errorState == OnlineCalculatorError.None ? trainingRelError : double.NaN;
+      double testRelError = OnlineMeanAbsolutePercentageErrorCalculator.Calculate(originalTestValues, estimatedTestValues, out errorState);
+      TestRelativeError = errorState == OnlineCalculatorError.None ? testRelError : double.NaN;
+
+      double trainingNMSE = OnlineNormalizedMeanSquaredErrorCalculator.Calculate(originalTrainingValues, estimatedTrainingValues, out errorState);
+      TrainingNormalizedMeanSquaredError = errorState == OnlineCalculatorError.None ? trainingNMSE : double.NaN;
+      double testNMSE = OnlineNormalizedMeanSquaredErrorCalculator.Calculate(originalTestValues, estimatedTestValues, out errorState);
+      TestNormalizedMeanSquaredError = errorState == OnlineCalculatorError.None ? testNMSE : double.NaN;
+
+      double trainingME = OnlineMeanErrorCalculator.Calculate(originalTrainingValues, estimatedTrainingValues, out errorState);
+      TrainingMeanError = errorState == OnlineCalculatorError.None ? trainingME : double.NaN;
+      double testME = OnlineMeanErrorCalculator.Calculate(originalTestValues, estimatedTestValues, out errorState);
+      TestMeanError = errorState == OnlineCalculatorError.None ? testME : double.NaN;
+    }
+  }
+}
Index: branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/TimeSeriesPrognosis/Models/ConstantTimeSeriesPrognosisModel.cs
===================================================================
--- branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/TimeSeriesPrognosis/Models/ConstantTimeSeriesPrognosisModel.cs	(revision 9073)
+++ branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/TimeSeriesPrognosis/Models/ConstantTimeSeriesPrognosisModel.cs	(revision 9073)
@@ -0,0 +1,49 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  [StorableClass]
+  [Item("Constant TimeSeries Model", "A time series model that returns for all prediciton the same constant value.")]
+  public class ConstantTimeSeriesPrognosisModel : ConstantRegressionModel, ITimeSeriesPrognosisModel {
+    [StorableConstructor]
+    protected ConstantTimeSeriesPrognosisModel(bool deserializing) : base(deserializing) { }
+    protected ConstantTimeSeriesPrognosisModel(ConstantTimeSeriesPrognosisModel original, Cloner cloner) : base(original, cloner) { }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new ConstantTimeSeriesPrognosisModel(this, cloner);
+    }
+
+    public ConstantTimeSeriesPrognosisModel(double constant) : base(constant) { }
+
+    public IEnumerable<IEnumerable<double>> GetPrognosedValues(Dataset dataset, IEnumerable<int> rows, IEnumerable<int> horizons) {
+      return horizons.Select(horizon => Enumerable.Repeat(Constant, horizon));
+    }
+
+    public ITimeSeriesPrognosisSolution CreateTimeSeriesPrognosisSolution(ITimeSeriesPrognosisProblemData problemData) {
+      return new TimeSeriesPrognosisSolution(this, new TimeSeriesPrognosisProblemData(problemData));
+    }
+  }
+}
Index: branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/TimeSeriesPrognosis/Models/TimeSeriesPrognosisAutoRegressiveModel.cs
===================================================================
--- branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/TimeSeriesPrognosis/Models/TimeSeriesPrognosisAutoRegressiveModel.cs	(revision 9073)
+++ branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/TimeSeriesPrognosis/Models/TimeSeriesPrognosisAutoRegressiveModel.cs	(revision 9073)
@@ -0,0 +1,118 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  [StorableClass]
+  [Item("Autoregressive TimeSeries Model", "A linear autoregressive time series model used to predict future values.")]
+  public class TimeSeriesPrognosisAutoRegressiveModel : NamedItem, ITimeSeriesPrognosisModel {
+    [Storable]
+    public double[] Phi { get; private set; }
+    [Storable]
+    public double Constant { get; private set; }
+    [Storable]
+    public string TargetVariable { get; private set; }
+
+    public int TimeOffset { get { return Phi.Length; } }
+
+    [StorableConstructor]
+    protected TimeSeriesPrognosisAutoRegressiveModel(bool deserializing) : base(deserializing) { }
+    protected TimeSeriesPrognosisAutoRegressiveModel(TimeSeriesPrognosisAutoRegressiveModel original, Cloner cloner)
+      : base(original, cloner) {
+      this.Phi = (double[])original.Phi.Clone();
+      this.Constant = original.Constant;
+      this.TargetVariable = original.TargetVariable;
+    }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new TimeSeriesPrognosisAutoRegressiveModel(this, cloner);
+    }
+    public TimeSeriesPrognosisAutoRegressiveModel(string targetVariable, double[] phi, double constant)
+      : base("AR(1) Model") {
+      Phi = (double[])phi.Clone();
+      Constant = constant;
+      TargetVariable = targetVariable;
+    }
+
+    public IEnumerable<IEnumerable<double>> GetPrognosedValues(Dataset dataset, IEnumerable<int> rows, IEnumerable<int> horizons) {
+      var rowsEnumerator = rows.GetEnumerator();
+      var horizonsEnumerator = horizons.GetEnumerator();
+      var targetValues = dataset.GetReadOnlyDoubleValues(TargetVariable);
+      // produce a n-step forecast for all rows
+      while (rowsEnumerator.MoveNext() & horizonsEnumerator.MoveNext()) {
+        int row = rowsEnumerator.Current;
+        int horizon = horizonsEnumerator.Current;
+        if (row - TimeOffset < 0) {
+          yield return Enumerable.Repeat(double.NaN, horizon);
+          continue;
+        }
+
+        double[] prognosis = new double[horizon];
+        for (int h = 0; h < horizon; h++) {
+          double estimatedValue = 0.0;
+          for (int i = 1; i <= TimeOffset; i++) {
+            int offset = h - i;
+            if (offset >= 0) estimatedValue += prognosis[offset] * Phi[i - 1];
+            else estimatedValue += targetValues[row + offset] * Phi[i - 1];
+
+          }
+          estimatedValue += Constant;
+          prognosis[h] = estimatedValue;
+        }
+
+        yield return prognosis;
+      }
+
+      if (rowsEnumerator.MoveNext() || horizonsEnumerator.MoveNext())
+        throw new ArgumentException("Number of elements in rows and horizon enumerations doesn't match.");
+    }
+
+    public IEnumerable<double> GetEstimatedValues(Dataset dataset, IEnumerable<int> rows) {
+      var targetVariables = dataset.GetReadOnlyDoubleValues(TargetVariable);
+      foreach (int row in rows) {
+        double estimatedValue = 0.0;
+        if (row - TimeOffset < 0) {
+          yield return double.NaN;
+          continue;
+        }
+
+        for (int i = 1; i <= TimeOffset; i++) {
+          estimatedValue += targetVariables[row - i] * Phi[i - 1];
+        }
+        estimatedValue += Constant;
+        yield return estimatedValue;
+      }
+    }
+
+    public ITimeSeriesPrognosisSolution CreateTimeSeriesPrognosisSolution(ITimeSeriesPrognosisProblemData problemData) {
+      return new TimeSeriesPrognosisSolution(this, new TimeSeriesPrognosisProblemData(problemData));
+    }
+    public IRegressionSolution CreateRegressionSolution(IRegressionProblemData problemData) {
+      throw new NotSupportedException();
+    }
+
+  }
+}
Index: branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/TimeSeriesPrognosis/TimeSeriesPrognosisProblem.cs
===================================================================
--- branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/TimeSeriesPrognosis/TimeSeriesPrognosisProblem.cs	(revision 9073)
+++ branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/TimeSeriesPrognosis/TimeSeriesPrognosisProblem.cs	(revision 9073)
@@ -0,0 +1,38 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2011 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  [StorableClass]
+  [Item("Time-series Prognosis Problem", "A general time-series prognosis problem.")]
+  [Creatable("Problems")]
+  public class TimeSeriesPrognosisProblem : DataAnalysisProblem<ITimeSeriesPrognosisProblemData>, ITimeSeriesPrognosisProblem {
+    [StorableConstructor]
+    protected TimeSeriesPrognosisProblem(bool deserializing) : base(deserializing) { }
+    protected TimeSeriesPrognosisProblem(TimeSeriesPrognosisProblem original, Cloner cloner) : base(original, cloner) { }
+    public override IDeepCloneable Clone(Cloner cloner) { return new TimeSeriesPrognosisProblem(this, cloner); }
+
+    public TimeSeriesPrognosisProblem() : base(new TimeSeriesPrognosisProblemData()) { }
+  }
+}
Index: branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/TimeSeriesPrognosis/TimeSeriesPrognosisProblemData.cs
===================================================================
--- branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/TimeSeriesPrognosis/TimeSeriesPrognosisProblemData.cs	(revision 9073)
+++ branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/TimeSeriesPrognosis/TimeSeriesPrognosisProblemData.cs	(revision 9073)
@@ -0,0 +1,1619 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2011 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  [StorableClass]
+  [Item("TimeSeriesPrognosisProblemData", "Represents an item containing all data defining a time series prognosis problem.")]
+  public class TimeSeriesPrognosisProblemData : RegressionProblemData, ITimeSeriesPrognosisProblemData {
+    #region default data
+    private static double[,] mackey_glass_17 = new double[,] {
+{9.0000000e-01},
+{9.0000000e-01},
+{9.0000000e-01},
+{9.4136145e-01},
+{1.1188041e+00},
+{1.2161867e+00},
+{1.2476827e+00},
+{1.0067861e+00},
+{7.1297054e-01},
+{5.0349420e-01},
+{5.8392542e-01},
+{9.4327347e-01},
+{1.0178784e+00},
+{1.0346794e+00},
+{1.1640420e+00},
+{1.0670009e+00},
+{1.0026658e+00},
+{7.7000347e-01},
+{7.0782984e-01},
+{7.9370192e-01},
+{1.0558440e+00},
+{1.2000510e+00},
+{1.2998549e+00},
+{1.1857500e+00},
+{8.4250325e-01},
+{5.5885374e-01},
+{4.2572016e-01},
+{7.5043060e-01},
+{9.7291951e-01},
+{9.3785503e-01},
+{1.0653587e+00},
+{1.1355961e+00},
+{1.1533842e+00},
+{1.0678134e+00},
+{8.1349649e-01},
+{6.6246660e-01},
+{6.2210481e-01},
+{9.3890430e-01},
+{1.1287058e+00},
+{1.1699535e+00},
+{1.2412759e+00},
+{9.8090748e-01},
+{7.3311051e-01},
+{5.2596003e-01},
+{6.3134850e-01},
+{9.7849655e-01},
+{1.0578901e+00},
+{1.0888001e+00},
+{1.1681297e+00},
+{9.9896471e-01},
+{8.7928027e-01},
+{6.6864116e-01},
+{7.3694626e-01},
+{9.7850487e-01},
+{1.1571565e+00},
+{1.2440406e+00},
+{1.2532851e+00},
+{9.3967388e-01},
+{6.5403177e-01},
+{4.5549437e-01},
+{6.4110939e-01},
+{9.6727507e-01},
+{9.8419122e-01},
+{1.0332443e+00},
+{1.1440570e+00},
+{1.0922307e+00},
+{1.0485820e+00},
+{8.0447560e-01},
+{7.1465526e-01},
+{7.1296010e-01},
+{9.9300973e-01},
+{1.1766813e+00},
+{1.2618288e+00},
+{1.2517022e+00},
+{9.2078170e-01},
+{6.2369710e-01},
+{4.3562308e-01},
+{6.4988558e-01},
+{9.5895791e-01},
+{9.5866122e-01},
+{1.0183775e+00},
+{1.1415533e+00},
+{1.1289579e+00},
+{1.1022163e+00},
+{8.4414928e-01},
+{6.9891813e-01},
+{6.2493643e-01},
+{9.0049230e-01},
+{1.1246569e+00},
+{1.1850486e+00},
+{1.2646400e+00},
+{1.0193893e+00},
+{7.3830722e-01},
+{5.1921750e-01},
+{5.6836076e-01},
+{9.3609361e-01},
+{1.0324202e+00},
+{1.0360676e+00},
+{1.1675966e+00},
+{1.0504944e+00},
+{9.8129158e-01},
+{7.5798016e-01},
+{7.1660079e-01},
+{8.3950658e-01},
+{1.0870027e+00},
+{1.2170776e+00},
+{1.3123779e+00},
+{1.1361782e+00},
+{7.9337369e-01},
+{5.2230472e-01},
+{4.3857925e-01},
+{8.0873950e-01},
+{9.7422631e-01},
+{9.3291515e-01},
+{1.0947530e+00},
+{1.1335086e+00},
+{1.1645714e+00},
+{1.0315895e+00},
+{7.9058261e-01},
+{6.3878936e-01},
+{6.4385427e-01},
+{9.7290237e-01},
+{1.1330941e+00},
+{1.1738960e+00},
+{1.2210669e+00},
+{9.4813374e-01},
+{7.1548595e-01},
+{5.2046031e-01},
+{6.8100333e-01},
+{1.0072944e+00},
+{1.0641199e+00},
+{1.1194312e+00},
+{1.1522817e+00},
+{9.7118023e-01},
+{8.2966445e-01},
+{6.3876024e-01},
+{7.6770138e-01},
+{1.0325752e+00},
+{1.1660632e+00},
+{1.2543878e+00},
+{1.1956003e+00},
+{8.7571542e-01},
+{6.1252082e-01},
+{4.5699619e-01},
+{7.4030148e-01},
+{1.0017485e+00},
+{9.8958385e-01},
+{1.0949833e+00},
+{1.1249612e+00},
+{1.0658962e+00},
+{9.5636335e-01},
+{7.4498806e-01},
+{7.2563393e-01},
+{8.3530455e-01},
+{1.0977307e+00},
+{1.2314926e+00},
+{1.3167422e+00},
+{1.1172604e+00},
+{7.6900341e-01},
+{5.0549771e-01},
+{4.4450990e-01},
+{8.2808038e-01},
+{9.6930396e-01},
+{9.2772189e-01},
+{1.1010458e+00},
+{1.1366939e+00},
+{1.1770457e+00},
+{1.0282839e+00},
+{7.8657093e-01},
+{6.2340354e-01},
+{6.3476140e-01},
+{9.6941037e-01},
+{1.1224823e+00},
+{1.1576217e+00},
+{1.2147442e+00},
+{9.5631199e-01},
+{7.3947874e-01},
+{5.4187646e-01},
+{6.8681641e-01},
+{1.0131445e+00},
+{1.0865854e+00},
+{1.1414849e+00},
+{1.1594630e+00},
+{9.4411600e-01},
+{7.7794034e-01},
+{5.9741518e-01},
+{7.7225037e-01},
+{1.0587360e+00},
+{1.1485933e+00},
+{1.2344562e+00},
+{1.1458853e+00},
+{8.5415118e-01},
+{6.2127481e-01},
+{4.9756097e-01},
+{8.0931406e-01},
+{1.0430891e+00},
+{1.0367506e+00},
+{1.1608048e+00},
+{1.0902522e+00},
+{9.6945804e-01},
+{7.9607346e-01},
+{6.7035674e-01},
+{8.2493000e-01},
+{1.0685565e+00},
+{1.1912458e+00},
+{1.2916937e+00},
+{1.1585237e+00},
+{8.2653804e-01},
+{5.5624667e-01},
+{4.4364773e-01},
+{7.8679896e-01},
+{9.8947432e-01},
+{9.5587476e-01},
+{1.0976735e+00},
+{1.1247419e+00},
+{1.1220470e+00},
+{9.9754667e-01},
+{7.7406653e-01},
+{6.7630712e-01},
+{7.2445263e-01},
+{1.0303591e+00},
+{1.1801427e+00},
+{1.2506686e+00},
+{1.1989987e+00},
+{8.7114663e-01},
+{6.0602798e-01},
+{4.5163741e-01},
+{7.3553573e-01},
+{9.9456302e-01},
+{9.8098646e-01},
+{1.0857031e+00},
+{1.1289641e+00},
+{1.0828069e+00},
+{9.8224963e-01},
+{7.5966277e-01},
+{7.1111527e-01},
+{7.8645769e-01},
+{1.0673541e+00},
+{1.2116816e+00},
+{1.2990734e+00},
+{1.1657704e+00},
+{8.1779454e-01},
+{5.4428063e-01},
+{4.3047549e-01},
+{7.7832590e-01},
+{9.7551443e-01},
+{9.3705618e-01},
+{1.0807206e+00},
+{1.1339189e+00},
+{1.1551319e+00},
+{1.0473610e+00},
+{8.0021464e-01},
+{6.5377513e-01},
+{6.3810292e-01},
+{9.6140773e-01},
+{1.1354401e+00},
+{1.1782311e+00},
+{1.2323246e+00},
+{9.5811452e-01},
+{7.1400985e-01},
+{5.1434848e-01},
+{6.5876782e-01},
+{9.9374878e-01},
+{1.0532057e+00},
+{1.0987291e+00},
+{1.1569941e+00},
+{9.9327584e-01},
+{8.7055783e-01},
+{6.6607204e-01},
+{7.5154249e-01},
+{9.9147904e-01},
+{1.1618652e+00},
+{1.2531013e+00},
+{1.2445235e+00},
+{9.2459418e-01},
+{6.3924685e-01},
+{4.4899067e-01},
+{6.5946924e-01},
+{9.7165260e-01},
+{9.7791817e-01},
+{1.0391898e+00},
+{1.1412631e+00},
+{1.0983393e+00},
+{1.0493420e+00},
+{8.0399406e-01},
+{7.0992449e-01},
+{7.0350356e-01},
+{9.8952236e-01},
+{1.1734521e+00},
+{1.2538876e+00},
+{1.2508500e+00},
+{9.2423636e-01},
+{6.3070030e-01},
+{4.4136962e-01},
+{6.4946966e-01},
+{9.6197955e-01},
+{9.6606332e-01},
+{1.0237953e+00},
+{1.1421522e+00},
+{1.1183774e+00},
+{1.0857179e+00},
+{8.3157725e-01},
+{7.0250588e-01},
+{6.4917325e-01},
+{9.2959329e-01},
+{1.1407976e+00},
+{1.2080261e+00},
+{1.2684960e+00},
+{9.9122930e-01},
+{7.0220017e-01},
+{4.8816416e-01},
+{5.8586111e-01},
+{9.4668329e-01},
+{1.0087590e+00},
+{1.0232927e+00},
+{1.1559444e+00},
+{1.0720927e+00},
+{1.0286336e+00},
+{7.9460252e-01},
+{7.2093651e-01},
+{7.6292167e-01},
+{1.0248985e+00},
+{1.1929944e+00},
+{1.2920208e+00},
+{1.2293181e+00},
+{8.8290244e-01},
+{5.8527613e-01},
+{4.1855360e-01},
+{6.9074767e-01},
+{9.5977708e-01},
+{9.3601019e-01},
+{1.0268467e+00},
+{1.1397909e+00},
+{1.1581327e+00},
+{1.1205956e+00},
+{8.5280669e-01},
+{6.7763483e-01},
+{5.7983286e-01},
+{8.6429914e-01},
+{1.0976939e+00},
+{1.1367408e+00},
+{1.2374931e+00},
+{1.0493382e+00},
+{8.0588138e-01},
+{5.9127581e-01},
+{5.7929225e-01},
+{9.2472931e-01},
+{1.0849831e+00},
+{1.0943246e+00},
+{1.2041235e+00},
+{1.0091917e+00},
+{8.4987188e-01},
+{6.3876182e-01},
+{6.7747918e-01},
+{9.7202288e-01},
+{1.1405471e+00},
+{1.1943368e+00},
+{1.2338428e+00},
+{9.4462558e-01},
+{6.9738430e-01},
+{4.9856007e-01},
+{6.6823589e-01},
+{9.9611375e-01},
+{1.0393748e+00},
+{1.0920087e+00},
+{1.1489492e+00},
+{1.0066576e+00},
+{8.9589007e-01},
+{6.8845995e-01},
+{7.5294149e-01},
+{9.6184563e-01},
+{1.1555071e+00},
+{1.2567316e+00},
+{1.2751778e+00},
+{9.6335246e-01},
+{6.5830948e-01},
+{4.4799275e-01},
+{5.9888825e-01},
+{9.4430988e-01},
+{9.6837958e-01},
+{9.9677549e-01},
+{1.1434629e+00},
+{1.1210684e+00},
+{1.1148356e+00},
+{8.6401556e-01},
+{7.1420118e-01},
+{6.2999725e-01},
+{8.7537864e-01},
+{1.1167941e+00},
+{1.1896694e+00},
+{1.2722030e+00},
+{1.0454715e+00},
+{7.4997564e-01},
+{5.2383173e-01},
+{5.3664145e-01},
+{9.1117041e-01},
+{1.0244044e+00},
+{1.0151287e+00},
+{1.1633675e+00},
+{1.0695966e+00},
+{1.0183575e+00},
+{8.0087884e-01},
+{7.1535296e-01},
+{7.8553095e-01},
+{1.0319822e+00},
+{1.1937155e+00},
+{1.2977947e+00},
+{1.2217806e+00},
+{8.7524512e-01},
+{5.7851885e-01},
+{4.1763620e-01},
+{7.0155638e-01},
+{9.6135267e-01},
+{9.3393602e-01},
+{1.0323424e+00},
+{1.1394608e+00},
+{1.1605598e+00},
+{1.1161968e+00},
+{8.4854339e-01},
+{6.7338626e-01},
+{5.7982826e-01},
+{8.7043086e-01},
+{1.0990834e+00},
+{1.1357404e+00},
+{1.2369383e+00},
+{1.0441753e+00},
+{8.0417958e-01},
+{5.9002711e-01},
+{5.8533894e-01},
+{9.3051649e-01},
+{1.0871279e+00},
+{1.0984983e+00},
+{1.2044155e+00},
+{1.0039892e+00},
+{8.4210523e-01},
+{6.3124655e-01},
+{6.8055115e-01},
+{9.7935183e-01},
+{1.1399170e+00},
+{1.1935307e+00},
+{1.2269029e+00},
+{9.3758049e-01},
+{6.9527243e-01},
+{5.0033084e-01},
+{6.8171448e-01},
+{1.0034848e+00},
+{1.0435853e+00},
+{1.1027381e+00},
+{1.1454200e+00},
+{9.9636446e-01},
+{8.7575610e-01},
+{6.7572455e-01},
+{7.6161436e-01},
+{9.8751885e-01},
+{1.1634852e+00},
+{1.2613366e+00},
+{1.2527158e+00},
+{9.3041078e-01},
+{6.3648886e-01},
+{4.4289908e-01},
+{6.4543043e-01},
+{9.6271252e-01},
+{9.6856037e-01},
+{1.0237816e+00},
+{1.1419384e+00},
+{1.1143808e+00},
+{1.0817980e+00},
+{8.2952128e-01},
+{7.0565231e-01},
+{6.5745758e-01},
+{9.3688510e-01},
+{1.1457239e+00},
+{1.2160319e+00},
+{1.2696485e+00},
+{9.8373294e-01},
+{6.9141844e-01},
+{4.7910268e-01},
+{5.8995166e-01},
+{9.4754885e-01},
+{1.0004197e+00},
+{1.0182334e+00},
+{1.1527974e+00},
+{1.0815601e+00},
+{1.0462772e+00},
+{8.0856012e-01},
+{7.2009150e-01},
+{7.3360533e-01},
+{9.9726771e-01},
+{1.1799228e+00},
+{1.2752553e+00},
+{1.2545993e+00},
+{9.1834232e-01},
+{6.1478702e-01},
+{4.2718988e-01},
+{6.4709630e-01},
+{9.5321724e-01},
+{9.4745071e-01},
+{1.0082615e+00},
+{1.1408283e+00},
+{1.1449070e+00},
+{1.1287695e+00},
+{8.6506953e-01},
+{6.9506068e-01},
+{5.9077914e-01},
+{8.5235412e-01},
+{1.0981812e+00},
+{1.1502068e+00},
+{1.2457878e+00},
+{1.0606248e+00},
+{7.9743949e-01},
+{5.7871635e-01},
+{5.5597309e-01},
+{9.0976389e-01},
+{1.0678545e+00},
+{1.0678466e+00},
+{1.1926843e+00},
+{1.0306506e+00},
+{9.0068600e-01},
+{6.8968565e-01},
+{6.8293693e-01},
+{9.2938386e-01},
+{1.1389931e+00},
+{1.2107723e+00},
+{1.2742112e+00},
+{9.9571305e-01},
+{7.0900966e-01},
+{4.8711002e-01},
+{5.7843327e-01},
+{9.4262722e-01},
+{1.0068885e+00},
+{1.0174671e+00},
+{1.1549847e+00},
+{1.0752383e+00},
+{1.0382561e+00},
+{8.0493588e-01},
+{7.2297438e-01},
+{7.5109199e-01},
+{1.0099650e+00},
+{1.1869526e+00},
+{1.2859723e+00},
+{1.2455314e+00},
+{9.0247113e-01},
+{5.9968946e-01},
+{4.2056794e-01},
+{6.6467784e-01},
+{9.5461231e-01},
+{9.3926954e-01},
+{1.0128964e+00},
+{1.1403075e+00},
+{1.1549599e+00},
+{1.1335031e+00},
+{8.6584651e-01},
+{6.8689154e-01},
+{5.7663890e-01},
+{8.4338430e-01},
+{1.0904343e+00},
+{1.1347127e+00},
+{1.2344704e+00},
+{1.0665197e+00},
+{8.1831436e-01},
+{6.0374950e-01},
+{5.6609914e-01},
+{9.0609488e-01},
+{1.0837698e+00},
+{1.0903349e+00},
+{1.2068005e+00},
+{1.0215332e+00},
+{8.5834739e-01},
+{6.4797779e-01},
+{6.6278967e-01},
+{9.5567807e-01},
+{1.1370612e+00},
+{1.1868501e+00},
+{1.2426235e+00},
+{9.6133342e-01},
+{7.1189926e-01},
+{5.0582127e-01},
+{6.4642134e-01},
+{9.8585814e-01},
+{1.0428580e+00},
+{1.0831242e+00},
+{1.1568123e+00},
+{1.0097872e+00},
+{9.0412446e-01},
+{6.9144384e-01},
+{7.4452934e-01},
+{9.5158341e-01},
+{1.1512270e+00},
+{1.2509608e+00},
+{1.2807229e+00},
+{9.7601316e-01},
+{6.6959369e-01},
+{4.5362019e-01},
+{5.8397806e-01},
+{9.3866865e-01},
+{9.7211974e-01},
+{9.9154526e-01},
+{1.1440232e+00},
+{1.1182310e+00},
+{1.1159711e+00},
+{8.6902975e-01},
+{7.1839537e-01},
+{6.3437176e-01},
+{8.7058758e-01},
+{1.1155207e+00},
+{1.1929730e+00},
+{1.2750340e+00},
+{1.0511137e+00},
+{7.5075715e-01},
+{5.2249794e-01},
+{5.2857771e-01},
+{9.0479637e-01},
+{1.0201490e+00},
+{1.0078239e+00},
+{1.1602784e+00},
+{1.0762699e+00},
+{1.0328279e+00},
+{8.1754050e-01},
+{7.1739458e-01},
+{7.6521302e-01},
+{1.0063562e+00},
+{1.1829441e+00},
+{1.2880301e+00},
+{1.2505618e+00},
+{9.0963666e-01},
+{6.0373594e-01},
+{4.2059572e-01},
+{6.5552332e-01},
+{9.5216646e-01},
+{9.3915492e-01},
+{1.0073402e+00},
+{1.1402595e+00},
+{1.1555473e+00},
+{1.1400569e+00},
+{8.7240707e-01},
+{6.8972093e-01},
+{5.7304964e-01},
+{8.3155186e-01},
+{1.0852244e+00},
+{1.1309096e+00},
+{1.2300408e+00},
+{1.0756716e+00},
+{8.2836037e-01},
+{6.1503305e-01},
+{5.6289537e-01},
+{8.9596963e-01},
+{1.0857176e+00},
+{1.0933045e+00},
+{1.2103223e+00},
+{1.0266092e+00},
+{8.5466111e-01},
+{6.4485312e-01},
+{6.5137619e-01},
+{9.5039035e-01},
+{1.1326982e+00},
+{1.1771304e+00},
+{1.2406618e+00},
+{9.6686921e-01},
+{7.2402007e-01},
+{5.1657512e-01},
+{6.4610863e-01},
+{9.8716024e-01},
+{1.0536774e+00},
+{1.0920775e+00},
+{1.1611436e+00},
+{9.9694608e-01},
+{8.7913715e-01},
+{6.7096137e-01},
+{7.4646346e-01},
+{9.8211586e-01},
+{1.1596887e+00},
+{1.2506463e+00},
+{1.2528610e+00},
+{9.3574881e-01},
+{6.4708026e-01},
+{4.5058777e-01},
+{6.4326949e-01},
+{9.6585146e-01},
+{9.7825812e-01},
+{1.0299115e+00},
+{1.1430802e+00},
+{1.1005190e+00},
+{1.0609387e+00},
+{8.1379890e-01},
+{7.1122428e-01},
+{6.9156533e-01},
+{9.7259709e-01},
+{1.1655186e+00},
+{1.2452699e+00},
+{1.2619116e+00},
+{9.4482161e-01},
+{6.4801701e-01},
+{4.4907240e-01},
+{6.2485209e-01},
+{9.5564190e-01},
+{9.7288683e-01},
+{1.0147847e+00},
+{1.1443809e+00},
+{1.1120870e+00},
+{1.0877802e+00},
+{8.3639407e-01},
+{7.0935594e-01},
+{6.5684224e-01},
+{9.2695542e-01},
+{1.1418485e+00},
+{1.2155793e+00},
+{1.2744439e+00},
+{9.9526406e-01},
+{6.9858658e-01},
+{4.8225678e-01},
+{5.7551868e-01},
+{9.3953863e-01},
+{1.0000682e+00},
+{1.0105854e+00},
+{1.1531271e+00},
+{1.0852683e+00},
+{1.0562598e+00},
+{8.2024340e-01},
+{7.2070006e-01},
+{7.2200828e-01},
+{9.7907123e-01},
+{1.1713283e+00},
+{1.2668075e+00},
+{1.2685662e+00},
+{9.4120299e-01},
+{6.3302397e-01},
+{4.3403723e-01},
+{6.1877701e-01},
+{9.4622798e-01},
+{9.5365292e-01},
+{9.9618857e-01},
+{1.1414351e+00},
+{1.1389950e+00},
+{1.1349258e+00},
+{8.7553815e-01},
+{7.0489527e-01},
+{5.9575516e-01},
+{8.3938416e-01},
+{1.0946321e+00},
+{1.1549299e+00},
+{1.2478627e+00},
+{1.0727433e+00},
+{8.0007945e-01},
+{5.7879852e-01},
+{5.4142544e-01},
+{8.9584895e-01},
+{1.0605852e+00},
+{1.0558398e+00},
+{1.1875826e+00},
+{1.0434789e+00},
+{9.2439267e-01},
+{7.1612758e-01},
+{6.8218882e-01},
+{9.0102182e-01},
+{1.1275375e+00},
+{1.2109971e+00},
+{1.2892493e+00},
+{1.0360675e+00},
+{7.3214326e-01},
+{4.9603224e-01},
+{5.2859768e-01},
+{9.0839931e-01},
+{9.9967438e-01},
+{9.8761933e-01},
+{1.1495807e+00},
+{1.0955451e+00},
+{1.0837190e+00},
+{8.6306190e-01},
+{7.2864571e-01},
+{6.9570443e-01},
+{9.1466309e-01},
+{1.1416079e+00},
+{1.2423455e+00},
+{1.2979661e+00},
+{1.0158501e+00},
+{6.9306586e-01},
+{4.6540187e-01},
+{5.3429520e-01},
+{9.1176535e-01},
+{9.7214664e-01},
+{9.6587930e-01},
+{1.1395672e+00},
+{1.1254350e+00},
+{1.1438751e+00},
+{9.1306791e-01},
+{7.3239337e-01},
+{6.1798523e-01},
+{7.9591503e-01},
+{1.0777494e+00},
+{1.1677842e+00},
+{1.2502967e+00},
+{1.1151699e+00},
+{8.1642087e-01},
+{5.8442000e-01},
+{5.0055038e-01},
+{8.4650946e-01},
+{1.0385843e+00},
+{1.0234916e+00},
+{1.1635033e+00},
+{1.0803258e+00},
+{9.9050756e-01},
+{8.0394987e-01},
+{6.9093478e-01},
+{8.1258118e-01},
+{1.0510811e+00},
+{1.1928214e+00},
+{1.2964341e+00},
+{1.1903709e+00},
+{8.5006682e-01},
+{5.6609363e-01},
+{4.2789827e-01},
+{7.4508986e-01},
+{9.7546850e-01},
+{9.4304490e-01},
+{1.0657257e+00},
+{1.1344752e+00},
+{1.1448680e+00},
+{1.0604924e+00},
+{8.0946851e-01},
+{6.6897242e-01},
+{6.3751840e-01},
+{9.5203759e-01},
+{1.1383222e+00},
+{1.1857882e+00},
+{1.2429358e+00},
+{9.6640521e-01},
+{7.0943525e-01},
+{5.0606242e-01},
+{6.3814517e-01},
+{9.8050653e-01},
+{1.0400252e+00},
+{1.0768445e+00},
+{1.1586073e+00},
+{1.0171349e+00},
+{9.1652446e-01},
+{7.0015343e-01},
+{7.3826470e-01},
+{9.3314098e-01},
+{1.1436325e+00},
+{1.2463125e+00},
+{1.2921798e+00},
+{1.0004180e+00},
+{6.8706555e-01},
+{4.6091370e-01},
+{5.5360860e-01},
+{9.2333217e-01},
+{9.7324082e-01},
+{9.7644851e-01},
+{1.1422917e+00},
+{1.1211038e+00},
+{1.1312591e+00},
+{8.9312684e-01},
+{7.2669146e-01},
+{6.2634170e-01},
+{8.3089176e-01},
+{1.0962164e+00},
+{1.1808500e+00},
+{1.2661262e+00},
+{1.0871224e+00},
+{7.8484345e-01},
+{5.5241172e-01},
+{5.0720010e-01},
+{8.7433135e-01},
+{1.0293171e+00},
+{1.0110677e+00},
+{1.1612664e+00},
+{1.0781429e+00},
+{1.0169296e+00},
+{8.1818733e-01},
+{7.0825239e-01},
+{7.8555548e-01},
+{1.0202406e+00},
+{1.1861871e+00},
+{1.2927766e+00},
+{1.2345608e+00},
+{8.9196638e-01},
+{5.9165129e-01},
+{4.1993302e-01},
+{6.8133251e-01},
+{9.5902336e-01},
+{9.3840491e-01},
+{1.0229760e+00},
+{1.1397483e+00},
+{1.1549910e+00},
+{1.1221729e+00},
+{8.5521466e-01},
+{6.8171599e-01},
+{5.8253142e-01},
+{8.6249156e-01},
+{1.0984374e+00},
+{1.1402897e+00},
+{1.2397438e+00},
+{1.0509675e+00},
+{8.0267914e-01},
+{5.8719202e-01},
+{5.7423177e-01},
+{9.2225657e-01},
+{1.0807070e+00},
+{1.0878295e+00},
+{1.2011335e+00},
+{1.0137713e+00},
+{8.6200406e-01},
+{6.5063788e-01},
+{6.7962388e-01},
+{9.6415425e-01},
+{1.1427244e+00},
+{1.2001432e+00},
+{1.2435862e+00},
+{9.5255718e-01},
+{6.9548843e-01},
+{4.9228114e-01},
+{6.4975070e-01},
+{9.8475452e-01},
+{1.0290189e+00},
+{1.0735305e+00},
+{1.1514964e+00},
+{1.0265685e+00},
+{9.3450570e-01},
+{7.1609613e-01},
+{7.4066401e-01},
+{9.0672547e-01},
+{1.1323663e+00},
+{1.2457251e+00},
+{1.3080265e+00},
+{1.0368462e+00},
+{7.0922252e-01},
+{4.6922499e-01},
+{5.0971665e-01},
+{8.9530783e-01},
+{9.6897032e-01},
+{9.5144881e-01},
+{1.1327578e+00},
+{1.1313397e+00},
+{1.1615669e+00},
+{9.4490349e-01},
+{7.4435097e-01},
+{6.0879030e-01},
+{7.4201167e-01},
+{1.0475442e+00},
+{1.1489683e+00},
+{1.2189341e+00},
+{1.1527726e+00},
+{8.6373864e-01},
+{6.3765290e-01},
+{5.0482479e-01},
+{7.9976041e-01},
+{1.0463811e+00},
+{1.0486243e+00},
+{1.1650654e+00},
+{1.0937932e+00},
+{9.5242412e-01},
+{7.7776887e-01},
+{6.5337298e-01},
+{8.3412675e-01},
+{1.0842165e+00},
+{1.1876958e+00},
+{1.2860798e+00},
+{1.1277640e+00},
+{8.0705117e-01},
+{5.4933954e-01},
+{4.6409423e-01},
+{8.2407983e-01},
+{1.0029510e+00},
+{9.7182671e-01},
+{1.1248927e+00},
+{1.1108497e+00},
+{1.0927585e+00},
+{9.3345740e-01},
+{7.4563087e-01},
+{6.9815644e-01},
+{8.2911579e-01},
+{1.0975320e+00},
+{1.2225208e+00},
+{1.3041931e+00},
+{1.1107874e+00},
+{7.6954799e-01},
+{5.1381033e-01},
+{4.5656108e-01},
+{8.3803614e-01},
+{9.8059578e-01},
+{9.4343837e-01},
+{1.1139527e+00},
+{1.1272959e+00},
+{1.1505047e+00},
+{9.8802150e-01},
+{7.6846480e-01},
+{6.4059710e-01},
+{7.0404249e-01},
+{1.0213995e+00},
+{1.1571646e+00},
+{1.2167098e+00},
+{1.1922700e+00},
+{8.8891917e-01},
+{6.4610240e-01},
+{4.8423413e-01},
+{7.4237703e-01},
+{1.0194305e+00},
+{1.0263817e+00},
+{1.1223002e+00},
+{1.1218476e+00},
+{1.0047937e+00},
+{8.6916869e-01},
+{6.8761628e-01},
+{7.7272726e-01},
+{9.8680374e-01},
+{1.1662112e+00},
+{1.2718586e+00},
+{1.2599891e+00},
+{9.3374084e-01},
+{6.3070745e-01},
+{4.3512068e-01},
+{6.3400337e-01},
+{9.5387123e-01},
+{9.5725486e-01},
+{1.0083783e+00},
+{1.1414776e+00},
+{1.1320033e+00},
+{1.1156485e+00},
+{8.5730304e-01},
+{7.0257566e-01},
+{6.1385070e-01},
+{8.7645096e-01},
+{1.1135407e+00},
+{1.1743915e+00},
+{1.2617479e+00},
+{1.0416530e+00},
+{7.6141001e-01},
+{5.3947941e-01},
+{5.5263397e-01},
+{9.2079176e-01},
+{1.0423877e+00},
+{1.0391593e+00},
+{1.1741828e+00},
+{1.0475738e+00},
+{9.6528247e-01},
+{7.4824631e-01},
+{7.0765109e-01},
+{8.6076413e-01},
+{1.1015853e+00},
+{1.2180296e+00},
+{1.3087379e+00},
+{1.1050105e+00},
+{7.7144492e-01},
+{5.1073157e-01},
+{4.5959721e-01},
+{8.4138746e-01},
+{9.8058403e-01},
+{9.4385625e-01},
+{1.1155190e+00},
+{1.1265194e+00},
+{1.1505430e+00},
+{9.8480260e-01},
+{7.6753361e-01},
+{6.3998096e-01},
+{7.0790430e-01},
+{1.0242649e+00},
+{1.1582776e+00},
+{1.2187970e+00},
+{1.1895283e+00},
+{8.8519343e-01},
+{6.4254017e-01},
+{4.8336487e-01},
+{7.4700679e-01},
+{1.0202300e+00},
+{1.0250636e+00},
+{1.1237335e+00},
+{1.1201468e+00},
+{1.0057497e+00},
+{8.6867488e-01},
+{6.8876595e-01},
+{7.7314271e-01},
+{9.8646241e-01},
+{1.1663720e+00},
+{1.2725046e+00},
+{1.2607985e+00},
+{9.3432428e-01},
+{6.3055002e-01},
+{4.3462242e-01},
+{6.3267663e-01},
+{9.5306639e-01},
+{9.5647018e-01},
+{1.0069834e+00},
+{1.1414283e+00},
+{1.1332454e+00},
+{1.1183329e+00},
+{8.5964718e-01},
+{7.0259273e-01},
+{6.1086847e-01},
+{8.7145976e-01},
+{1.1109278e+00},
+{1.1713319e+00},
+{1.2600859e+00},
+{1.0459933e+00},
+{7.6697548e-01},
+{5.4492361e-01},
+{5.5082792e-01},
+{9.1787603e-01},
+{1.0454451e+00},
+{1.0416026e+00},
+{1.1762039e+00},
+{1.0460129e+00},
+{9.5856257e-01},
+{7.4291843e-01},
+{7.0478730e-01},
+{8.6904294e-01},
+{1.1074327e+00},
+{1.2185136e+00},
+{1.3067057e+00},
+{1.0916662e+00},
+{7.6226341e-01},
+{5.0599582e-01},
+{4.7004755e-01},
+{8.5459323e-01},
+{9.8292600e-01},
+{9.4923741e-01},
+{1.1230180e+00},
+{1.1230727e+00},
+{1.1436380e+00},
+{9.6517685e-01},
+{7.5906667e-01},
+{6.4229098e-01},
+{7.3739829e-01},
+{1.0441989e+00},
+{1.1689429e+00},
+{1.2377221e+00},
+{1.1702644e+00},
+{8.5776744e-01},
+{6.1283507e-01},
+{4.7508171e-01},
+{7.7650778e-01},
+{1.0199875e+00},
+{1.0098181e+00},
+{1.1277738e+00},
+{1.1115547e+00},
+{1.0256012e+00},
+{8.8156161e-01},
+{7.0600708e-01},
+{7.6171841e-01},
+{9.5613909e-01},
+{1.1569502e+00},
+{1.2691300e+00},
+{1.2887802e+00},
+{9.7384680e-01},
+{6.5493328e-01},
+{4.3953117e-01},
+{5.7648851e-01},
+{9.2999054e-01},
+{9.5436230e-01},
+{9.7297008e-01},
+{1.1391325e+00},
+{1.1416064e+00},
+{1.1590944e+00},
+{9.0850247e-01},
+{7.1895834e-01},
+{5.8564424e-01},
+{7.8301903e-01},
+{1.0675300e+00},
+{1.1390766e+00},
+{1.2237314e+00},
+{1.1158432e+00},
+{8.4615038e-01},
+{6.2929929e-01},
+{5.3024321e-01},
+{8.4771779e-01},
+{1.0679772e+00},
+{1.0707805e+00},
+{1.1942615e+00},
+{1.0628072e+00},
+{9.0277875e-01},
+{7.0464579e-01},
+{6.4124982e-01},
+{8.9445063e-01},
+{1.1236998e+00},
+{1.1838208e+00},
+{1.2721938e+00},
+{1.0302053e+00},
+{7.4928918e-01},
+{5.2054789e-01},
+{5.5300914e-01},
+{9.2450978e-01},
+{1.0290172e+00},
+{1.0254177e+00},
+{1.1658431e+00},
+{1.0585030e+00},
+{9.9937151e-01},
+{7.7845423e-01},
+{7.1727834e-01},
+{8.1473462e-01},
+{1.0635825e+00},
+{1.2081434e+00},
+{1.3087387e+00},
+{1.1774543e+00},
+{8.2930325e-01},
+{5.4568406e-01},
+{4.2252006e-01},
+{7.6155262e-01},
+{9.6902023e-01},
+{9.2946430e-01},
+{1.0663917e+00},
+{1.1373062e+00},
+{1.1667915e+00},
+{1.0769457e+00},
+{8.1823128e-01},
+{6.5190054e-01},
+{6.0082155e-01},
+{9.2122516e-01},
+{1.1147361e+00},
+{1.1467530e+00},
+{1.2352757e+00},
+{9.9993521e-01},
+{7.6890308e-01},
+{5.5857496e-01},
+{6.2725763e-01},
+{9.7318317e-01},
+{1.0840117e+00},
+{1.1108847e+00},
+{1.1857549e+00},
+{9.7757101e-01},
+{8.2394503e-01},
+{6.1941336e-01},
+{7.2410931e-01},
+{1.0158088e+00},
+{1.1491174e+00},
+{1.2188178e+00},
+{1.2007209e+00},
+{8.9859946e-01},
+{6.5456633e-01},
+{4.8391373e-01},
+{7.3135136e-01},
+{1.0176181e+00},
+{1.0277501e+00},
+{1.1176213e+00},
+{1.1248859e+00},
+{1.0041498e+00},
+{8.7364691e-01},
+{6.8812425e-01},
+{7.7228478e-01},
+{9.8423833e-01},
+{1.1655135e+00},
+{1.2710944e+00},
+{1.2619166e+00},
+{9.3651452e-01},
+{6.3284215e-01},
+{4.3578889e-01},
+{6.3021849e-01},
+{9.5269846e-01},
+{9.5770175e-01},
+{1.0064613e+00},
+{1.1416014e+00},
+{1.1318041e+00},
+{1.1173687e+00},
+{8.5933718e-01},
+{7.0364317e-01},
+{6.1326177e-01},
+{8.7318554e-01},
+{1.1121947e+00},
+{1.1737687e+00},
+{1.2616019e+00},
+{1.0447114e+00},
+{7.6386287e-01},
+{5.4149208e-01},
+{5.5006680e-01},
+{9.1816862e-01},
+{1.0427545e+00},
+{1.0385725e+00},
+{1.1744959e+00},
+{1.0484442e+00},
+{9.6566520e-01},
+{7.4941645e-01},
+{7.0654030e-01},
+{8.5978495e-01},
+{1.1007328e+00},
+{1.2172148e+00},
+{1.3084224e+00},
+{1.1066295e+00},
+{7.7306455e-01},
+{5.1195750e-01},
+{4.5881820e-01},
+{8.3991753e-01},
+{9.8090418e-01},
+{9.4402667e-01},
+{1.1150495e+00},
+{1.1263864e+00},
+{1.1498512e+00},
+{9.8537193e-01},
+{7.6788821e-01},
+{6.4101222e-01},
+{7.0798171e-01},
+{1.0241973e+00},
+{1.1588402e+00},
+{1.2194902e+00},
+{1.1900225e+00},
+{8.8503290e-01},
+{6.4170616e-01},
+{4.8247262e-01},
+{7.4633801e-01},
+{1.0194608e+00},
+{1.0238758e+00},
+{1.1225142e+00},
+{1.1204876e+00},
+{1.0078894e+00},
+{8.7195748e-01},
+{6.9071922e-01},
+{7.7128559e-01},
+{9.8171063e-01},
+{1.1648359e+00},
+{1.2716060e+00},
+{1.2653194e+00},
+{9.4044785e-01},
+{6.3462126e-01},
+{4.3541986e-01},
+{6.2397592e-01},
+{9.4996429e-01},
+{9.5654324e-01},
+{1.0018949e+00},
+{1.1415375e+00},
+{1.1340702e+00},
+{1.1242483e+00},
+{8.6601272e-01},
+{7.0479002e-01},
+{6.0700568e-01},
+{8.6003770e-01},
+{1.1056434e+00},
+{1.1671804e+00},
+{1.2575999e+00},
+{1.0561104e+00},
+{7.7723774e-01},
+{5.5451638e-01},
+{5.4470017e-01},
+{9.0953268e-01},
+{1.0489983e+00},
+{1.0432715e+00},
+{1.1787522e+00},
+{1.0466535e+00},
+{9.5253913e-01},
+{7.3976965e-01},
+{6.9910727e-01},
+{8.7457184e-01},
+{1.1111747e+00},
+{1.2168058e+00},
+{1.3037145e+00},
+{1.0820947e+00},
+{7.5710433e-01},
+{5.0441461e-01},
+{4.7923251e-01},
+{8.6434525e-01},
+{9.8624111e-01},
+{9.5555561e-01},
+{1.1291297e+00},
+{1.1187232e+00},
+{1.1339455e+00},
+{9.4624297e-01},
+{7.5185473e-01},
+{6.4886735e-01},
+{7.6947931e-01},
+{1.0640658e+00},
+{1.1819490e+00},
+{1.2581006e+00},
+{1.1479357e+00},
+{8.2795383e-01},
+{5.8084914e-01},
+{4.6968322e-01},
+{8.0540679e-01},
+{1.0147037e+00},
+{9.9267552e-01},
+{1.1297166e+00},
+{1.1074520e+00},
+{1.0535732e+00},
+{8.9989357e-01},
+{7.2414622e-01},
+{7.3710872e-01},
+{9.0842211e-01},
+{1.1372436e+00},
+{1.2550645e+00},
+{1.3118017e+00},
+{1.0309191e+00},
+{6.9715233e-01},
+{4.6014528e-01},
+{5.1093338e-01},
+{8.9602085e-01},
+{9.6063866e-01},
+{9.4454964e-01},
+{1.1299822e+00},
+{1.1400660e+00},
+{1.1784050e+00},
+{9.5942169e-01},
+{7.4592605e-01},
+{5.9179210e-01},
+{7.0833096e-01},
+{1.0269127e+00},
+{1.1280089e+00},
+{1.1874924e+00},
+{1.1668412e+00},
+{8.9924653e-01},
+{6.8916581e-01},
+{5.3047422e-01},
+{7.7534076e-01},
+{1.0549099e+00},
+{1.0847312e+00},
+{1.1818109e+00},
+{1.1071479e+00},
+{9.0609669e-01},
+{7.2016981e-01},
+{5.9922569e-01},
+{8.4631545e-01},
+{1.1007330e+00},
+{1.1539455e+00},
+{1.2548057e+00},
+{1.0707369e+00},
+{7.9955359e-01},
+{5.7211183e-01},
+{5.3729384e-01},
+{8.9511329e-01},
+{1.0559775e+00},
+{1.0482488e+00},
+{1.1833103e+00},
+{1.0467011e+00},
+{9.3892077e-01},
+{7.3109756e-01},
+{6.8881096e-01},
+{8.8724202e-01},
+{1.1196405e+00},
+{1.2137632e+00},
+{1.2969341e+00},
+{1.0598913e+00},
+{7.4476987e-01},
+{5.0025043e-01},
+{5.0175473e-01},
+{8.8612613e-01},
+{9.9295902e-01},
+{9.7027740e-01},
+{1.1406663e+00},
+{1.1082236e+00},
+{1.1111857e+00},
+{9.0519862e-01},
+{7.3853971e-01},
+{6.6752554e-01},
+{8.4076984e-01},
+{1.1041197e+00},
+{1.2107499e+00},
+{1.2910787e+00},
+{1.0889124e+00},
+{7.6218879e-01},
+{5.1854183e-01},
+{4.8212027e-01},
+{8.6343438e-01},
+{9.9664176e-01},
+{9.6786348e-01},
+{1.1354766e+00},
+{1.1100558e+00},
+{1.1078273e+00},
+{9.1950063e-01},
+{7.4186814e-01},
+{6.7554741e-01},
+{8.2771704e-01},
+{1.0970261e+00},
+{1.2115055e+00},
+{1.2926801e+00},
+{1.1044430e+00},
+{7.7268354e-01},
+{5.2367729e-01},
+{4.6962326e-01},
+{8.4775775e-01},
+{9.9325612e-01},
+{9.6094332e-01},
+{1.1271528e+00},
+{1.1156670e+00},
+{1.1183008e+00},
+{9.4351589e-01},
+{7.5035067e-01},
+{6.6773972e-01},
+{7.8886291e-01},
+{1.0750322e+00},
+{1.1971741e+00},
+{1.2770426e+00},
+{1.1387571e+00},
+{8.0837143e-01},
+{5.5509702e-01},
+{4.5955065e-01},
+{8.1398530e-01},
+{1.0008314e+00},
+{9.7057086e-01},
+{1.1195985e+00},
+{1.1149111e+00},
+{1.0957539e+00},
+{9.4451157e-01},
+{7.4819097e-01},
+{6.9474604e-01},
+{8.1250200e-01},
+{1.0876804e+00},
+{1.2158509e+00},
+{1.2988266e+00},
+{1.1270851e+00},
+{7.8595861e-01},
+{5.2690470e-01},
+{4.5032342e-01},
+{8.2266007e-01},
+{9.8371303e-01},
+{9.4630598e-01},
+{1.1090276e+00}};
+
+    private static readonly Dataset defaultDataset;
+    private static readonly IEnumerable<string> defaultAllowedInputVariables;
+    private static readonly string defaultTargetVariable;
+
+    static TimeSeriesPrognosisProblemData() {
+      defaultDataset = new Dataset(new string[] { "x" }, mackey_glass_17);
+      defaultDataset.Name = "Mackey-Glass (t=17) Time Series Benchmark Dataset";
+      defaultAllowedInputVariables = Enumerable.Empty<string>();
+      defaultTargetVariable = "x";
+    }
+    #endregion
+
+    private const string TrainingHorizonParameterName = "Training Horizon";
+    private const string TestHorizonParameterName = "Test Horizon";
+
+    public IFixedValueParameter<IntValue> TrainingHorizonParameter {
+      get { return (IFixedValueParameter<IntValue>)Parameters[TrainingHorizonParameterName]; }
+    }
+    public IFixedValueParameter<IntValue> TestHorizonParameter {
+      get { return (IFixedValueParameter<IntValue>)Parameters[TestHorizonParameterName]; }
+    }
+
+    #region Properties
+    public int TrainingHorizon {
+      get { return TrainingHorizonParameter.Value.Value; }
+      set { TrainingHorizonParameter.Value.Value = value; }
+    }
+
+    public int TestHorizon {
+      get { return TestHorizonParameter.Value.Value; }
+      set { TestHorizonParameter.Value.Value = value; }
+    }
+    #endregion
+
+    [StorableConstructor]
+    protected TimeSeriesPrognosisProblemData(bool deserializing) : base(deserializing) { }
+
+    protected TimeSeriesPrognosisProblemData(TimeSeriesPrognosisProblemData original, Cloner cloner) : base(original, cloner) { }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new TimeSeriesPrognosisProblemData(this, cloner);
+    }
+
+    public TimeSeriesPrognosisProblemData()
+      : this(defaultDataset, defaultAllowedInputVariables, defaultTargetVariable) {
+      TrainingPartition.Start = 50;
+    }
+    public TimeSeriesPrognosisProblemData(Dataset dataset, IEnumerable<string> allowedInputVariables, string targetVariable)
+      : base(dataset, allowedInputVariables, targetVariable) {
+      Parameters.Add(new FixedValueParameter<IntValue>(TrainingHorizonParameterName, "Specifies the horizon (how far the prognosis reaches in the future) for each training sample.", new IntValue(1)));
+      Parameters.Add(new FixedValueParameter<IntValue>(TestHorizonParameterName, "Specifies the horizon (how far the prognosis reaches in the future) for each test sample.", new IntValue(1)));
+
+      TrainingHorizonParameter.Hidden = true;
+      TestHorizonParameter.Hidden = true;
+
+      TrainingPartition.Start = Math.Min((int)(TrainingPartition.Size * 0.2), 50);
+
+      RegisterParameterEventHandlers();
+    }
+
+    public TimeSeriesPrognosisProblemData(ITimeSeriesPrognosisProblemData timeseriesProblemData)
+      : this(timeseriesProblemData.Dataset, timeseriesProblemData.AllowedInputVariables, timeseriesProblemData.TargetVariable) {
+
+      TestHorizon = timeseriesProblemData.TestHorizon;
+      TrainingHorizon = timeseriesProblemData.TestHorizon;
+    }
+
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() {
+      RegisterParameterEventHandlers();
+    }
+
+    private void RegisterParameterEventHandlers() {
+      TrainingHorizonParameter.Value.ValueChanged += new System.EventHandler(Parameter_ValueChanged);
+      TestHorizonParameter.Value.ValueChanged += new System.EventHandler(Parameter_ValueChanged);
+    }
+
+    private void Parameter_ValueChanged(object sender, EventArgs e) {
+      OnChanged();
+    }
+
+  }
+}
Index: branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/TimeSeriesPrognosis/TimeSeriesPrognosisResults.cs
===================================================================
--- branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/TimeSeriesPrognosis/TimeSeriesPrognosisResults.cs	(revision 9073)
+++ branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/TimeSeriesPrognosis/TimeSeriesPrognosisResults.cs	(revision 9073)
@@ -0,0 +1,461 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Optimization;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  [StorableClass]
+  [Item("Prognosis Results", "Represents a collection of time series prognosis results.")]
+  public class TimeSeriesPrognosisResults : ResultCollection {
+    #region result names
+    protected const string PrognosisTrainingMeanSquaredErrorResultName = "Mean squared error (training)";
+    protected const string PrognosisTestMeanSquaredErrorResultName = "Mean squared error (test)";
+    protected const string PrognosisTrainingMeanAbsoluteErrorResultName = "Mean absolute error (training)";
+    protected const string PrognosisTestMeanAbsoluteErrorResultName = "Mean absolute error (test)";
+    protected const string PrognosisTrainingSquaredCorrelationResultName = "Pearson's R² (training)";
+    protected const string PrognosisTestSquaredCorrelationResultName = "Pearson's R² (test)";
+    protected const string PrognosisTrainingRelativeErrorResultName = "Average relative error (training)";
+    protected const string PrognosisTestRelativeErrorResultName = "Average relative error (test)";
+    protected const string PrognosisTrainingNormalizedMeanSquaredErrorResultName = "Normalized mean squared error (training)";
+    protected const string PrognosisTestNormalizedMeanSquaredErrorResultName = "Normalized mean squared error (test)";
+    protected const string PrognosisTrainingMeanErrorResultName = "Mean error (training)";
+    protected const string PrognosisTestMeanErrorResultName = "Mean error (test)";
+
+    protected const string PrognosisTrainingDirectionalSymmetryResultName = "Average directional symmetry (training)";
+    protected const string PrognosisTestDirectionalSymmetryResultName = "Average directional symmetry (test)";
+    protected const string PrognosisTrainingWeightedDirectionalSymmetryResultName = "Average weighted directional symmetry (training)";
+    protected const string PrognosisTestWeightedDirectionalSymmetryResultName = "Average weighted directional symmetry (test)";
+    protected const string PrognosisTrainingTheilsUStatisticAR1ResultName = "Theil's U2 (AR1) (training)";
+    protected const string PrognosisTestTheilsUStatisticAR1ResultName = "Theil's U2 (AR1) (test)";
+    protected const string PrognosisTrainingTheilsUStatisticMeanResultName = "Theil's U2 (mean) (training)";
+    protected const string PrognosisTestTheilsUStatisticMeanResultName = "Theil's U2 (mean) (test)";
+    #endregion
+
+    #region result descriptions
+    protected const string PrognosisTrainingMeanSquaredErrorResultDescription = "Mean of squared errors of the model on the training partition";
+    protected const string PrognosisTestMeanSquaredErrorResultDescription = "Mean of squared errors of the model on the test partition";
+    protected const string PrognosisTrainingMeanAbsoluteErrorResultDescription = "Mean of absolute errors of the model on the training partition";
+    protected const string PrognosisTestMeanAbsoluteErrorResultDescription = "Mean of absolute errors of the model on the test partition";
+    protected const string PrognosisTrainingSquaredCorrelationResultDescription = "Squared Pearson's correlation coefficient of the model output and the actual values on the training partition";
+    protected const string PrognosisTestSquaredCorrelationResultDescription = "Squared Pearson's correlation coefficient of the model output and the actual values on the test partition";
+    protected const string PrognosisTrainingRelativeErrorResultDescription = "Average of the relative errors of the model output and the actual values on the training partition";
+    protected const string PrognosisTestRelativeErrorResultDescription = "Average of the relative errors of the model output and the actual values on the test partition";
+    protected const string PrognosisTrainingNormalizedMeanSquaredErrorResultDescription = "Normalized mean of squared errors of the model on the training partition";
+    protected const string PrognosisTestNormalizedMeanSquaredErrorResultDescription = "Normalized mean of squared errors of the model on the test partition";
+    protected const string PrognosisTrainingMeanErrorResultDescription = "Mean of errors of the model on the training partition";
+    protected const string PrognosisTestMeanErrorResultDescription = "Mean of errors of the model on the test partition";
+
+    protected const string PrognosisTrainingDirectionalSymmetryResultDescription = "The average directional symmetry of the forecasts of the model on the training partition";
+    protected const string PrognosisTestDirectionalSymmetryResultDescription = "The average directional symmetry of the forecasts of the model on the test partition";
+    protected const string PrognosisTrainingWeightedDirectionalSymmetryResultDescription = "The average weighted directional symmetry of the forecasts of the model on the training partition";
+    protected const string PrognosisTestWeightedDirectionalSymmetryResultDescription = "The average weighted directional symmetry of the forecasts of the model on the test partition";
+    protected const string PrognosisTrainingTheilsUStatisticAR1ResultDescription = "The Theil's U statistic (reference: AR1 model) of the forecasts of the model on the training partition";
+    protected const string PrognosisTestTheilsUStatisticAR1ResultDescription = "The Theil's U statistic (reference: AR1 model) of the forecasts of the model on the test partition";
+    protected const string PrognosisTrainingTheilsUStatisticMeanResultDescription = "The Theil's U statistic (reference: mean model) of the forecasts of the model on the training partition";
+    protected const string PrognosisTestTheilsUStatisticMeanResultDescription = "The Theil's U statistic (reference: mean value) of the forecasts of the model on the test partition";
+    #endregion
+
+    #region result properties
+    //prognosis results for different horizons
+    public double PrognosisTrainingMeanSquaredError {
+      get {
+        if (!ContainsKey(PrognosisTrainingMeanSquaredErrorResultName)) return double.NaN;
+        return ((DoubleValue)this[PrognosisTrainingMeanSquaredErrorResultName].Value).Value;
+      }
+      private set {
+        if (!ContainsKey(PrognosisTrainingMeanSquaredErrorResultName)) Add(new Result(PrognosisTrainingMeanSquaredErrorResultName, PrognosisTrainingMeanSquaredErrorResultDescription, new DoubleValue()));
+        ((DoubleValue)this[PrognosisTrainingMeanSquaredErrorResultName].Value).Value = value;
+      }
+    }
+
+    public double PrognosisTestMeanSquaredError {
+      get {
+        if (!ContainsKey(PrognosisTestMeanSquaredErrorResultName)) return double.NaN;
+        return ((DoubleValue)this[PrognosisTestMeanSquaredErrorResultName].Value).Value;
+      }
+      private set {
+        if (!ContainsKey(PrognosisTestMeanSquaredErrorResultName)) Add(new Result(PrognosisTestMeanSquaredErrorResultName, PrognosisTestMeanSquaredErrorResultDescription, new DoubleValue()));
+        ((DoubleValue)this[PrognosisTestMeanSquaredErrorResultName].Value).Value = value;
+      }
+    }
+
+    public double PrognosisTrainingMeanAbsoluteError {
+      get {
+        if (!ContainsKey(PrognosisTrainingMeanAbsoluteErrorResultName)) return double.NaN;
+        return ((DoubleValue)this[PrognosisTrainingMeanAbsoluteErrorResultName].Value).Value;
+      }
+      private set {
+        if (!ContainsKey(PrognosisTrainingMeanAbsoluteErrorResultName)) Add(new Result(PrognosisTrainingMeanAbsoluteErrorResultName, PrognosisTrainingMeanAbsoluteErrorResultDescription, new DoubleValue()));
+        ((DoubleValue)this[PrognosisTrainingMeanAbsoluteErrorResultName].Value).Value = value;
+      }
+    }
+
+    public double PrognosisTestMeanAbsoluteError {
+      get {
+        if (!ContainsKey(PrognosisTestMeanAbsoluteErrorResultName)) return double.NaN;
+        return ((DoubleValue)this[PrognosisTestMeanAbsoluteErrorResultName].Value).Value;
+      }
+      private set {
+        if (!ContainsKey(PrognosisTestMeanAbsoluteErrorResultName)) Add(new Result(PrognosisTestMeanAbsoluteErrorResultName, PrognosisTestMeanAbsoluteErrorResultDescription, new DoubleValue()));
+        ((DoubleValue)this[PrognosisTestMeanAbsoluteErrorResultName].Value).Value = value;
+      }
+    }
+
+    public double PrognosisTrainingRSquared {
+      get {
+        if (!ContainsKey(PrognosisTrainingSquaredCorrelationResultName)) return double.NaN;
+        return ((DoubleValue)this[PrognosisTrainingSquaredCorrelationResultName].Value).Value;
+      }
+      private set {
+        if (!ContainsKey(PrognosisTrainingSquaredCorrelationResultName)) Add(new Result(PrognosisTrainingSquaredCorrelationResultName, PrognosisTrainingSquaredCorrelationResultDescription, new DoubleValue()));
+        ((DoubleValue)this[PrognosisTrainingSquaredCorrelationResultName].Value).Value = value;
+      }
+    }
+
+    public double PrognosisTestRSquared {
+      get {
+        if (!ContainsKey(PrognosisTestSquaredCorrelationResultName)) return double.NaN;
+        return ((DoubleValue)this[PrognosisTestSquaredCorrelationResultName].Value).Value;
+      }
+      private set {
+        if (!ContainsKey(PrognosisTestSquaredCorrelationResultName)) Add(new Result(PrognosisTestSquaredCorrelationResultName, PrognosisTestSquaredCorrelationResultDescription, new DoubleValue()));
+        ((DoubleValue)this[PrognosisTestSquaredCorrelationResultName].Value).Value = value;
+      }
+    }
+
+    public double PrognosisTrainingRelativeError {
+      get {
+        if (!ContainsKey(PrognosisTrainingRelativeErrorResultName)) return double.NaN;
+        return ((DoubleValue)this[PrognosisTrainingRelativeErrorResultName].Value).Value;
+      }
+      private set {
+        if (!ContainsKey(PrognosisTrainingRelativeErrorResultName)) Add(new Result(PrognosisTrainingRelativeErrorResultName, PrognosisTrainingRelativeErrorResultDescription, new DoubleValue()));
+        ((DoubleValue)this[PrognosisTrainingRelativeErrorResultName].Value).Value = value;
+      }
+    }
+
+    public double PrognosisTestRelativeError {
+      get {
+        if (!ContainsKey(PrognosisTestRelativeErrorResultName)) return double.NaN;
+        return ((DoubleValue)this[PrognosisTestRelativeErrorResultName].Value).Value;
+      }
+      private set {
+        if (!ContainsKey(PrognosisTestRelativeErrorResultName)) Add(new Result(PrognosisTestRelativeErrorResultName, PrognosisTestRelativeErrorResultDescription, new DoubleValue()));
+        ((DoubleValue)this[PrognosisTestRelativeErrorResultName].Value).Value = value;
+      }
+    }
+
+    public double PrognosisTrainingNormalizedMeanSquaredError {
+      get {
+        if (!ContainsKey(PrognosisTrainingNormalizedMeanSquaredErrorResultName)) return double.NaN;
+        return ((DoubleValue)this[PrognosisTrainingNormalizedMeanSquaredErrorResultName].Value).Value;
+      }
+      private set {
+        if (!ContainsKey(PrognosisTrainingNormalizedMeanSquaredErrorResultName)) Add(new Result(PrognosisTrainingNormalizedMeanSquaredErrorResultName, PrognosisTrainingNormalizedMeanSquaredErrorResultDescription, new DoubleValue()));
+        ((DoubleValue)this[PrognosisTrainingNormalizedMeanSquaredErrorResultName].Value).Value = value;
+      }
+    }
+
+    public double PrognosisTestNormalizedMeanSquaredError {
+      get {
+        if (!ContainsKey(PrognosisTestNormalizedMeanSquaredErrorResultName)) return double.NaN;
+        return ((DoubleValue)this[PrognosisTestNormalizedMeanSquaredErrorResultName].Value).Value;
+      }
+      private set {
+        if (!ContainsKey(PrognosisTestNormalizedMeanSquaredErrorResultName)) Add(new Result(PrognosisTestNormalizedMeanSquaredErrorResultName, PrognosisTestNormalizedMeanSquaredErrorResultDescription, new DoubleValue()));
+        ((DoubleValue)this[PrognosisTestNormalizedMeanSquaredErrorResultName].Value).Value = value;
+      }
+    }
+
+    public double PrognosisTrainingMeanError {
+      get {
+        if (!ContainsKey(PrognosisTrainingMeanErrorResultName)) return double.NaN;
+        return ((DoubleValue)this[PrognosisTrainingMeanErrorResultName].Value).Value;
+      }
+      private set {
+        if (!ContainsKey(PrognosisTrainingMeanErrorResultName)) Add(new Result(PrognosisTrainingMeanErrorResultName, PrognosisTrainingMeanErrorResultDescription, new DoubleValue()));
+        ((DoubleValue)this[PrognosisTrainingMeanErrorResultName].Value).Value = value;
+      }
+    }
+
+    public double PrognosisTestMeanError {
+      get {
+        if (!ContainsKey(PrognosisTestMeanErrorResultName)) return double.NaN;
+        return ((DoubleValue)this[PrognosisTestMeanErrorResultName].Value).Value;
+      }
+      private set {
+        if (!ContainsKey(PrognosisTestMeanErrorResultName)) Add(new Result(PrognosisTestMeanErrorResultName, PrognosisTestMeanErrorResultDescription, new DoubleValue()));
+        ((DoubleValue)this[PrognosisTestMeanErrorResultName].Value).Value = value;
+      }
+    }
+
+
+    public double PrognosisTrainingDirectionalSymmetry {
+      get {
+        if (!ContainsKey(PrognosisTrainingDirectionalSymmetryResultName)) return double.NaN;
+        return ((DoubleValue)this[PrognosisTrainingDirectionalSymmetryResultName].Value).Value;
+      }
+      private set {
+        if (!ContainsKey(PrognosisTrainingDirectionalSymmetryResultName)) Add(new Result(PrognosisTrainingDirectionalSymmetryResultName, PrognosisTrainingDirectionalSymmetryResultDescription, new DoubleValue()));
+        ((DoubleValue)this[PrognosisTrainingDirectionalSymmetryResultName].Value).Value = value;
+      }
+    }
+    public double PrognosisTestDirectionalSymmetry {
+      get {
+        if (!ContainsKey(PrognosisTestDirectionalSymmetryResultName)) return double.NaN;
+        return ((DoubleValue)this[PrognosisTestDirectionalSymmetryResultName].Value).Value;
+      }
+      private set {
+        if (!ContainsKey(PrognosisTestDirectionalSymmetryResultName)) Add(new Result(PrognosisTestDirectionalSymmetryResultName, PrognosisTestDirectionalSymmetryResultDescription, new DoubleValue()));
+        ((DoubleValue)this[PrognosisTestDirectionalSymmetryResultName].Value).Value = value;
+      }
+    }
+    public double PrognosisTrainingWeightedDirectionalSymmetry {
+      get {
+        if (!ContainsKey(PrognosisTrainingWeightedDirectionalSymmetryResultName)) return double.NaN;
+        return ((DoubleValue)this[PrognosisTrainingWeightedDirectionalSymmetryResultName].Value).Value;
+      }
+      private set {
+        if (!ContainsKey(PrognosisTrainingWeightedDirectionalSymmetryResultName)) Add(new Result(PrognosisTrainingWeightedDirectionalSymmetryResultName, PrognosisTrainingWeightedDirectionalSymmetryResultDescription, new DoubleValue()));
+        ((DoubleValue)this[PrognosisTrainingWeightedDirectionalSymmetryResultName].Value).Value = value;
+      }
+    }
+    public double PrognosisTestWeightedDirectionalSymmetry {
+      get {
+        if (!ContainsKey(PrognosisTestWeightedDirectionalSymmetryResultName)) return double.NaN;
+        return ((DoubleValue)this[PrognosisTestWeightedDirectionalSymmetryResultName].Value).Value;
+      }
+      private set {
+        if (!ContainsKey(PrognosisTestWeightedDirectionalSymmetryResultName)) Add(new Result(PrognosisTestWeightedDirectionalSymmetryResultName, PrognosisTestWeightedDirectionalSymmetryResultDescription, new DoubleValue()));
+        ((DoubleValue)this[PrognosisTestWeightedDirectionalSymmetryResultName].Value).Value = value;
+      }
+    }
+    public double PrognosisTrainingTheilsUStatisticAR1 {
+      get {
+        if (!ContainsKey(PrognosisTrainingTheilsUStatisticAR1ResultName)) return double.NaN;
+        return ((DoubleValue)this[PrognosisTrainingTheilsUStatisticAR1ResultName].Value).Value;
+      }
+      private set {
+        if (!ContainsKey(PrognosisTrainingTheilsUStatisticAR1ResultName)) Add(new Result(PrognosisTrainingTheilsUStatisticAR1ResultName, PrognosisTrainingTheilsUStatisticAR1ResultDescription, new DoubleValue()));
+        ((DoubleValue)this[PrognosisTrainingTheilsUStatisticAR1ResultName].Value).Value = value;
+      }
+    }
+    public double PrognosisTestTheilsUStatisticAR1 {
+      get {
+        if (!ContainsKey(PrognosisTestTheilsUStatisticAR1ResultName)) return double.NaN;
+        return ((DoubleValue)this[PrognosisTestTheilsUStatisticAR1ResultName].Value).Value;
+      }
+      private set {
+        if (!ContainsKey(PrognosisTestTheilsUStatisticAR1ResultName)) Add(new Result(PrognosisTestTheilsUStatisticAR1ResultName, PrognosisTestTheilsUStatisticAR1ResultDescription, new DoubleValue()));
+        ((DoubleValue)this[PrognosisTestTheilsUStatisticAR1ResultName].Value).Value = value;
+      }
+    }
+    public double PrognosisTrainingTheilsUStatisticMean {
+      get {
+        if (!ContainsKey(PrognosisTrainingTheilsUStatisticMeanResultName)) return double.NaN;
+        return ((DoubleValue)this[PrognosisTrainingTheilsUStatisticMeanResultName].Value).Value;
+      }
+      private set {
+        if (!ContainsKey(PrognosisTrainingTheilsUStatisticMeanResultName)) Add(new Result(PrognosisTrainingTheilsUStatisticMeanResultName, PrognosisTrainingTheilsUStatisticMeanResultDescription, new DoubleValue()));
+        ((DoubleValue)this[PrognosisTrainingTheilsUStatisticMeanResultName].Value).Value = value;
+      }
+    }
+    public double PrognosisTestTheilsUStatisticMean {
+      get {
+        if (!ContainsKey(PrognosisTestTheilsUStatisticMeanResultName)) return double.NaN;
+        return ((DoubleValue)this[PrognosisTestTheilsUStatisticMeanResultName].Value).Value;
+      }
+      private set {
+        if (!ContainsKey(PrognosisTestTheilsUStatisticMeanResultName)) Add(new Result(PrognosisTestTheilsUStatisticMeanResultName, PrognosisTestTheilsUStatisticMeanResultDescription, new DoubleValue()));
+        ((DoubleValue)this[PrognosisTestTheilsUStatisticMeanResultName].Value).Value = value;
+      }
+    }
+    #endregion
+
+    [Storable]
+    private int trainingHorizon;
+    public int TrainingHorizon {
+      get { return trainingHorizon; }
+      set {
+        if (trainingHorizon != value) {
+          trainingHorizon = value;
+          OnTrainingHorizonChanged();
+        }
+      }
+    }
+
+    [Storable]
+    private int testHorizon;
+    public int TestHorizon {
+      get { return testHorizon; }
+      set {
+        if (testHorizon != value) {
+          testHorizon = value;
+          OnTestHorizonChanged();
+        }
+      }
+    }
+
+    private ITimeSeriesPrognosisSolution solution;
+    [Storable]
+    public ITimeSeriesPrognosisSolution Solution {
+      get { return solution; }
+      private set { solution = value; } //necessary for persistence
+    }
+
+    [StorableConstructor]
+    public TimeSeriesPrognosisResults(bool deserializing) : base(deserializing) { }
+    protected TimeSeriesPrognosisResults(TimeSeriesPrognosisResults original, Cloner cloner)
+      : base(original, cloner) {
+      this.trainingHorizon = original.trainingHorizon;
+      this.testHorizon = original.testHorizon;
+      this.solution = cloner.Clone(original.solution);
+    }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new TimeSeriesPrognosisResults(this, cloner);
+    }
+
+    public TimeSeriesPrognosisResults(int trainingHorizon, int testHorizon, ITimeSeriesPrognosisSolution solution)
+      : base() {
+      this.trainingHorizon = trainingHorizon;
+      this.testHorizon = testHorizon;
+      this.solution = solution;
+      CalculateTrainingPrognosisResults();
+      CalculateTestPrognosisResults();
+    }
+
+    #region events
+    public event EventHandler TrainingHorizonChanged;
+    protected virtual void OnTrainingHorizonChanged() {
+      CalculateTrainingPrognosisResults();
+      var handler = TrainingHorizonChanged;
+      if (handler != null) handler(this, EventArgs.Empty);
+    }
+
+    public event EventHandler TestHorizonChanged;
+    protected virtual void OnTestHorizonChanged() {
+      CalculateTestPrognosisResults();
+      var handler = TestHorizonChanged;
+      if (handler != null) handler(this, EventArgs.Empty);
+    }
+    #endregion
+
+    private void CalculateTrainingPrognosisResults() {
+      OnlineCalculatorError errorState;
+      var problemData = Solution.ProblemData;
+      var model = Solution.Model;
+      //mean model
+      double trainingMean = problemData.Dataset.GetDoubleValues(problemData.TargetVariable, problemData.TrainingIndices).Average();
+      var meanModel = new ConstantTimeSeriesPrognosisModel(trainingMean);
+
+      //AR1 model
+      double alpha, beta;
+      IEnumerable<double> trainingStartValues = problemData.Dataset.GetDoubleValues(problemData.TargetVariable, problemData.TrainingIndices.Select(r => r - 1).Where(r => r > 0)).ToList();
+      OnlineLinearScalingParameterCalculator.Calculate(problemData.Dataset.GetDoubleValues(problemData.TargetVariable, problemData.TrainingIndices.Where(x => x > 0)), trainingStartValues, out alpha, out beta, out errorState);
+      var AR1model = new TimeSeriesPrognosisAutoRegressiveModel(problemData.TargetVariable, new double[] { beta }, alpha);
+
+      var trainingHorizions = problemData.TrainingIndices.Select(r => Math.Min(trainingHorizon, problemData.TrainingPartition.End - r)).ToList();
+      IEnumerable<IEnumerable<double>> trainingTargetValues = problemData.TrainingIndices.Zip(trainingHorizions, Enumerable.Range).Select(r => problemData.Dataset.GetDoubleValues(problemData.TargetVariable, r)).ToList();
+      IEnumerable<IEnumerable<double>> trainingEstimatedValues = model.GetPrognosedValues(problemData.Dataset, problemData.TrainingIndices, trainingHorizions).ToList();
+      IEnumerable<IEnumerable<double>> trainingMeanModelPredictions = meanModel.GetPrognosedValues(problemData.Dataset, problemData.TrainingIndices, trainingHorizions).ToList();
+      IEnumerable<IEnumerable<double>> trainingAR1ModelPredictions = AR1model.GetPrognosedValues(problemData.Dataset, problemData.TrainingIndices, trainingHorizions).ToList();
+
+      IEnumerable<double> originalTrainingValues = trainingTargetValues.SelectMany(x => x).ToList();
+      IEnumerable<double> estimatedTrainingValues = trainingEstimatedValues.SelectMany(x => x).ToList();
+
+      double trainingMSE = OnlineMeanSquaredErrorCalculator.Calculate(originalTrainingValues, estimatedTrainingValues, out errorState);
+      PrognosisTrainingMeanSquaredError = errorState == OnlineCalculatorError.None ? trainingMSE : double.NaN;
+      double trainingMAE = OnlineMeanAbsoluteErrorCalculator.Calculate(originalTrainingValues, estimatedTrainingValues, out errorState);
+      PrognosisTrainingMeanAbsoluteError = errorState == OnlineCalculatorError.None ? trainingMAE : double.NaN;
+      double trainingR2 = OnlinePearsonsRSquaredCalculator.Calculate(originalTrainingValues, estimatedTrainingValues, out errorState);
+      PrognosisTrainingRSquared = errorState == OnlineCalculatorError.None ? trainingR2 : double.NaN;
+      double trainingRelError = OnlineMeanAbsolutePercentageErrorCalculator.Calculate(originalTrainingValues, estimatedTrainingValues, out errorState);
+      PrognosisTrainingRelativeError = errorState == OnlineCalculatorError.None ? trainingRelError : double.NaN;
+      double trainingNMSE = OnlineNormalizedMeanSquaredErrorCalculator.Calculate(originalTrainingValues, estimatedTrainingValues, out errorState);
+      PrognosisTrainingNormalizedMeanSquaredError = errorState == OnlineCalculatorError.None ? trainingNMSE : double.NaN;
+      double trainingME = OnlineMeanErrorCalculator.Calculate(originalTrainingValues, estimatedTrainingValues, out errorState);
+      PrognosisTrainingMeanError = errorState == OnlineCalculatorError.None ? trainingME : double.NaN;
+
+      PrognosisTrainingDirectionalSymmetry = OnlineDirectionalSymmetryCalculator.Calculate(trainingStartValues, trainingTargetValues, trainingEstimatedValues, out errorState);
+      PrognosisTrainingDirectionalSymmetry = errorState == OnlineCalculatorError.None ? PrognosisTrainingDirectionalSymmetry : 0.0;
+      PrognosisTrainingWeightedDirectionalSymmetry = OnlineWeightedDirectionalSymmetryCalculator.Calculate(trainingStartValues, trainingTargetValues, trainingEstimatedValues, out errorState);
+      PrognosisTrainingWeightedDirectionalSymmetry = errorState == OnlineCalculatorError.None ? PrognosisTrainingWeightedDirectionalSymmetry : 0.0;
+      PrognosisTrainingTheilsUStatisticAR1 = OnlineTheilsUStatisticCalculator.Calculate(trainingStartValues, trainingTargetValues, trainingAR1ModelPredictions, trainingEstimatedValues, out errorState);
+      PrognosisTrainingTheilsUStatisticAR1 = errorState == OnlineCalculatorError.None ? PrognosisTrainingTheilsUStatisticAR1 : double.PositiveInfinity;
+      PrognosisTrainingTheilsUStatisticMean = OnlineTheilsUStatisticCalculator.Calculate(trainingStartValues, trainingTargetValues, trainingMeanModelPredictions, trainingEstimatedValues, out errorState);
+      PrognosisTrainingTheilsUStatisticMean = errorState == OnlineCalculatorError.None ? PrognosisTrainingTheilsUStatisticMean : double.PositiveInfinity;
+    }
+
+    private void CalculateTestPrognosisResults() {
+      OnlineCalculatorError errorState;
+      var problemData = Solution.ProblemData;
+      var model = Solution.Model;
+      //mean model
+      double trainingMean = problemData.Dataset.GetDoubleValues(problemData.TargetVariable, problemData.TrainingIndices).Average();
+      var meanModel = new ConstantTimeSeriesPrognosisModel(trainingMean);
+
+      //AR1 model
+      double alpha, beta;
+      IEnumerable<double> trainingStartValues = problemData.Dataset.GetDoubleValues(problemData.TargetVariable, problemData.TrainingIndices.Select(r => r - 1).Where(r => r > 0)).ToList();
+      OnlineLinearScalingParameterCalculator.Calculate(problemData.Dataset.GetDoubleValues(problemData.TargetVariable, problemData.TrainingIndices.Where(x => x > 0)), trainingStartValues, out alpha, out beta, out errorState);
+      var AR1model = new TimeSeriesPrognosisAutoRegressiveModel(problemData.TargetVariable, new double[] { beta }, alpha);
+
+      var testHorizions = problemData.TestIndices.Select(r => Math.Min(testHorizon, problemData.TestPartition.End - r)).ToList();
+      IEnumerable<IEnumerable<double>> testTargetValues = problemData.TestIndices.Zip(testHorizions, Enumerable.Range).Select(r => problemData.Dataset.GetDoubleValues(problemData.TargetVariable, r)).ToList();
+      IEnumerable<IEnumerable<double>> testEstimatedValues = model.GetPrognosedValues(problemData.Dataset, problemData.TestIndices, testHorizions).ToList();
+      IEnumerable<double> testStartValues = problemData.Dataset.GetDoubleValues(problemData.TargetVariable, problemData.TestIndices.Select(r => r - 1).Where(r => r > 0)).ToList();
+      IEnumerable<IEnumerable<double>> testMeanModelPredictions = meanModel.GetPrognosedValues(problemData.Dataset, problemData.TestIndices, testHorizions).ToList();
+      IEnumerable<IEnumerable<double>> testAR1ModelPredictions = AR1model.GetPrognosedValues(problemData.Dataset, problemData.TestIndices, testHorizions).ToList();
+
+      IEnumerable<double> originalTestValues = testTargetValues.SelectMany(x => x).ToList();
+      IEnumerable<double> estimatedTestValues = testEstimatedValues.SelectMany(x => x).ToList();
+
+      double testMSE = OnlineMeanSquaredErrorCalculator.Calculate(originalTestValues, estimatedTestValues, out errorState);
+      PrognosisTestMeanSquaredError = errorState == OnlineCalculatorError.None ? testMSE : double.NaN;
+      double testMAE = OnlineMeanAbsoluteErrorCalculator.Calculate(originalTestValues, estimatedTestValues, out errorState);
+      PrognosisTestMeanAbsoluteError = errorState == OnlineCalculatorError.None ? testMAE : double.NaN;
+      double testR2 = OnlinePearsonsRSquaredCalculator.Calculate(originalTestValues, estimatedTestValues, out errorState);
+      PrognosisTestRSquared = errorState == OnlineCalculatorError.None ? testR2 : double.NaN;
+      double testRelError = OnlineMeanAbsolutePercentageErrorCalculator.Calculate(originalTestValues, estimatedTestValues, out errorState);
+      PrognosisTestRelativeError = errorState == OnlineCalculatorError.None ? testRelError : double.NaN;
+      double testNMSE = OnlineNormalizedMeanSquaredErrorCalculator.Calculate(originalTestValues, estimatedTestValues, out errorState);
+      PrognosisTestNormalizedMeanSquaredError = errorState == OnlineCalculatorError.None ? testNMSE : double.NaN;
+      double testME = OnlineMeanErrorCalculator.Calculate(originalTestValues, estimatedTestValues, out errorState);
+      PrognosisTestMeanError = errorState == OnlineCalculatorError.None ? testME : double.NaN;
+
+      PrognosisTestDirectionalSymmetry = OnlineDirectionalSymmetryCalculator.Calculate(testStartValues, testTargetValues, testEstimatedValues, out errorState);
+      PrognosisTestDirectionalSymmetry = errorState == OnlineCalculatorError.None ? PrognosisTestDirectionalSymmetry : 0.0;
+      PrognosisTestWeightedDirectionalSymmetry = OnlineWeightedDirectionalSymmetryCalculator.Calculate(testStartValues, testTargetValues, testEstimatedValues, out errorState);
+      PrognosisTestWeightedDirectionalSymmetry = errorState == OnlineCalculatorError.None ? PrognosisTestWeightedDirectionalSymmetry : 0.0;
+      PrognosisTestTheilsUStatisticAR1 = OnlineTheilsUStatisticCalculator.Calculate(testStartValues, testTargetValues, testAR1ModelPredictions, testEstimatedValues, out errorState);
+      PrognosisTestTheilsUStatisticAR1 = errorState == OnlineCalculatorError.None ? PrognosisTestTheilsUStatisticAR1 : double.PositiveInfinity;
+      PrognosisTestTheilsUStatisticMean = OnlineTheilsUStatisticCalculator.Calculate(testStartValues, testTargetValues, testMeanModelPredictions, testEstimatedValues, out errorState);
+      PrognosisTestTheilsUStatisticMean = errorState == OnlineCalculatorError.None ? PrognosisTestTheilsUStatisticMean : double.PositiveInfinity;
+    }
+  }
+}
Index: branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/TimeSeriesPrognosis/TimeSeriesPrognosisSolution.cs
===================================================================
--- branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/TimeSeriesPrognosis/TimeSeriesPrognosisSolution.cs	(revision 9073)
+++ branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/TimeSeriesPrognosis/TimeSeriesPrognosisSolution.cs	(revision 9073)
@@ -0,0 +1,46 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2011 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Collections.Generic;
+using HeuristicLab.Common;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  /// <summary>
+  /// Represents a time series prognosis data analysis solution
+  /// </summary>
+  [StorableClass]
+  public class TimeSeriesPrognosisSolution : TimeSeriesPrognosisSolutionBase {
+    [StorableConstructor]
+    protected TimeSeriesPrognosisSolution(bool deserializing) : base(deserializing) { }
+    protected TimeSeriesPrognosisSolution(TimeSeriesPrognosisSolution original, Cloner cloner) : base(original, cloner) { }
+    protected internal TimeSeriesPrognosisSolution(ITimeSeriesPrognosisModel model, ITimeSeriesPrognosisProblemData problemData)
+      : base(model, problemData) {
+      CalculateRegressionResults();
+      CalculateTimeSeriesResults();
+      CalculateTimeSeriesResults(ProblemData.TrainingHorizon, ProblemData.TestHorizon);
+    }
+
+    public override IEnumerable<IEnumerable<double>> GetPrognosedValues(IEnumerable<int> rows, IEnumerable<int> horizons) {
+      return Model.GetPrognosedValues(ProblemData.Dataset, rows, horizons);
+    }
+  }
+}
Index: branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/TimeSeriesPrognosis/TimeSeriesPrognosisSolutionBase.cs
===================================================================
--- branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/TimeSeriesPrognosis/TimeSeriesPrognosisSolutionBase.cs	(revision 9073)
+++ branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/TimeSeriesPrognosis/TimeSeriesPrognosisSolutionBase.cs	(revision 9073)
@@ -0,0 +1,197 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2011 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Data;
+using HeuristicLab.Optimization;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  [StorableClass]
+  public abstract class TimeSeriesPrognosisSolutionBase : RegressionSolutionBase, ITimeSeriesPrognosisSolution {
+    #region result names
+    protected const string TrainingDirectionalSymmetryResultName = "Average directional symmetry (training)";
+    protected const string TestDirectionalSymmetryResultName = "Average directional symmetry (test)";
+    protected const string TrainingWeightedDirectionalSymmetryResultName = "Average weighted directional symmetry (training)";
+    protected const string TestWeightedDirectionalSymmetryResultName = "Average weighted directional symmetry (test)";
+    protected const string TrainingTheilsUStatisticAR1ResultName = "Theil's U2 (AR1) (training)";
+    protected const string TestTheilsUStatisticLastResultName = "Theil's U2 (AR1) (test)";
+    protected const string TrainingTheilsUStatisticMeanResultName = "Theil's U2 (mean) (training)";
+    protected const string TestTheilsUStatisticMeanResultName = "Theil's U2 (mean) (test)";
+    protected const string TimeSeriesPrognosisResultName = "Prognosis Results";
+    #endregion
+
+    #region result descriptions
+    protected const string TrainingDirectionalSymmetryResultDescription = "The average directional symmetry of the forecasts of the model on the training partition";
+    protected const string TestDirectionalSymmetryResultDescription = "The average directional symmetry of the forecasts of the model on the test partition";
+    protected const string TrainingWeightedDirectionalSymmetryResultDescription = "The average weighted directional symmetry of the forecasts of the model on the training partition";
+    protected const string TestWeightedDirectionalSymmetryResultDescription = "The average weighted directional symmetry of the forecasts of the model on the test partition";
+    protected const string TrainingTheilsUStatisticAR1ResultDescription = "The Theil's U statistic (reference: AR1 model) of the forecasts of the model on the training partition";
+    protected const string TestTheilsUStatisticAR1ResultDescription = "The Theil's U statistic (reference: AR1 model) of the forecasts of the model on the test partition";
+    protected const string TrainingTheilsUStatisticMeanResultDescription = "The Theil's U statistic (reference: mean model) of the forecasts of the model on the training partition";
+    protected const string TestTheilsUStatisticMeanResultDescription = "The Theil's U statistic (reference: mean value) of the forecasts of the model on the test partition";
+    protected const string TimeSeriesPrognosisResultDescription = "The calculated results of predictions in the future.";
+    #endregion
+
+    public new ITimeSeriesPrognosisModel Model {
+      get { return (ITimeSeriesPrognosisModel)base.Model; }
+      protected set { base.Model = value; }
+    }
+
+    public new ITimeSeriesPrognosisProblemData ProblemData {
+      get { return (ITimeSeriesPrognosisProblemData)base.ProblemData; }
+      set { base.ProblemData = value; }
+    }
+
+    public abstract IEnumerable<IEnumerable<double>> GetPrognosedValues(IEnumerable<int> rows, IEnumerable<int> horizon);
+
+    #region Results
+    public double TrainingDirectionalSymmetry {
+      get { return ((DoubleValue)this[TrainingDirectionalSymmetryResultName].Value).Value; }
+      private set { ((DoubleValue)this[TrainingDirectionalSymmetryResultName].Value).Value = value; }
+    }
+    public double TestDirectionalSymmetry {
+      get { return ((DoubleValue)this[TestDirectionalSymmetryResultName].Value).Value; }
+      private set { ((DoubleValue)this[TestDirectionalSymmetryResultName].Value).Value = value; }
+    }
+    public double TrainingWeightedDirectionalSymmetry {
+      get { return ((DoubleValue)this[TrainingWeightedDirectionalSymmetryResultName].Value).Value; }
+      private set { ((DoubleValue)this[TrainingWeightedDirectionalSymmetryResultName].Value).Value = value; }
+    }
+    public double TestWeightedDirectionalSymmetry {
+      get { return ((DoubleValue)this[TestWeightedDirectionalSymmetryResultName].Value).Value; }
+      private set { ((DoubleValue)this[TestWeightedDirectionalSymmetryResultName].Value).Value = value; }
+    }
+    public double TrainingTheilsUStatisticAR1 {
+      get { return ((DoubleValue)this[TrainingTheilsUStatisticAR1ResultName].Value).Value; }
+      private set { ((DoubleValue)this[TrainingTheilsUStatisticAR1ResultName].Value).Value = value; }
+    }
+    public double TestTheilsUStatisticAR1 {
+      get { return ((DoubleValue)this[TestTheilsUStatisticLastResultName].Value).Value; }
+      private set { ((DoubleValue)this[TestTheilsUStatisticLastResultName].Value).Value = value; }
+    }
+    public double TrainingTheilsUStatisticMean {
+      get { return ((DoubleValue)this[TrainingTheilsUStatisticMeanResultName].Value).Value; }
+      private set { ((DoubleValue)this[TrainingTheilsUStatisticMeanResultName].Value).Value = value; }
+    }
+    public double TestTheilsUStatisticMean {
+      get { return ((DoubleValue)this[TestTheilsUStatisticMeanResultName].Value).Value; }
+      private set { ((DoubleValue)this[TestTheilsUStatisticMeanResultName].Value).Value = value; }
+    }
+
+    public TimeSeriesPrognosisResults TimeSeriesPrognosisResults {
+      get {
+        if (!ContainsKey(TimeSeriesPrognosisResultName)) return null;
+        return (TimeSeriesPrognosisResults)this[TimeSeriesPrognosisResultName];
+      }
+      set {
+        if (ContainsKey(TimeSeriesPrognosisResultName)) Remove(TimeSeriesPrognosisResultName);
+        Add(new Result(TimeSeriesPrognosisResultName, TimeSeriesPrognosisResultDescription, value));
+      }
+    }
+    #endregion
+
+
+    public override IEnumerable<double> EstimatedValues {
+      get { return GetEstimatedValues(Enumerable.Range(0, ProblemData.Dataset.Rows)); }
+    }
+    public override IEnumerable<double> EstimatedTrainingValues {
+      get { return GetEstimatedValues(ProblemData.TrainingIndices); }
+    }
+    public override IEnumerable<double> EstimatedTestValues {
+      get { return GetEstimatedValues(ProblemData.TestIndices); }
+    }
+    public override IEnumerable<double> GetEstimatedValues(IEnumerable<int> rows) {
+      return Model.GetEstimatedValues(ProblemData.Dataset, rows);
+    }
+
+    [StorableConstructor]
+    protected TimeSeriesPrognosisSolutionBase(bool deserializing) : base(deserializing) { }
+    protected TimeSeriesPrognosisSolutionBase(TimeSeriesPrognosisSolutionBase original, Cloner cloner) : base(original, cloner) { }
+    protected TimeSeriesPrognosisSolutionBase(ITimeSeriesPrognosisModel model, ITimeSeriesPrognosisProblemData problemData)
+      : base(model, problemData) {
+      Add(new Result(TrainingDirectionalSymmetryResultName, TrainingDirectionalSymmetryResultDescription, new DoubleValue()));
+      Add(new Result(TestDirectionalSymmetryResultName, TestDirectionalSymmetryResultDescription, new DoubleValue()));
+      Add(new Result(TrainingWeightedDirectionalSymmetryResultName, TrainingWeightedDirectionalSymmetryResultDescription, new DoubleValue()));
+      Add(new Result(TestWeightedDirectionalSymmetryResultName, TestWeightedDirectionalSymmetryResultDescription, new DoubleValue()));
+      Add(new Result(TrainingTheilsUStatisticAR1ResultName, TrainingTheilsUStatisticAR1ResultDescription, new DoubleValue()));
+      Add(new Result(TestTheilsUStatisticLastResultName, TestTheilsUStatisticAR1ResultDescription, new DoubleValue()));
+      Add(new Result(TrainingTheilsUStatisticMeanResultName, TrainingTheilsUStatisticMeanResultDescription, new DoubleValue()));
+      Add(new Result(TestTheilsUStatisticMeanResultName, TestTheilsUStatisticMeanResultDescription, new DoubleValue()));
+    }
+
+    protected override void RecalculateResults() {
+      base.RecalculateResults();
+      CalculateTimeSeriesResults();
+      CalculateTimeSeriesResults(ProblemData.TrainingHorizon, ProblemData.TestHorizon);
+    }
+
+    protected void CalculateTimeSeriesResults() {
+      OnlineCalculatorError errorState;
+      double trainingMean = ProblemData.Dataset.GetDoubleValues(ProblemData.TargetVariable, ProblemData.TrainingIndices).Average();
+      var meanModel = new ConstantTimeSeriesPrognosisModel(trainingMean);
+
+      double alpha, beta;
+      IEnumerable<double> trainingStartValues = ProblemData.Dataset.GetDoubleValues(ProblemData.TargetVariable, ProblemData.TrainingIndices.Select(r => r - 1).Where(r => r > 0)).ToList();
+      OnlineLinearScalingParameterCalculator.Calculate(ProblemData.Dataset.GetDoubleValues(ProblemData.TargetVariable, ProblemData.TrainingIndices.Where(x => x > 0)), trainingStartValues, out alpha, out beta, out errorState);
+      var AR1model = new TimeSeriesPrognosisAutoRegressiveModel(ProblemData.TargetVariable, new double[] { beta }, alpha);
+
+
+      #region Calculate training quality measures
+      IEnumerable<double> trainingTargetValues = ProblemData.Dataset.GetDoubleValues(ProblemData.TargetVariable, ProblemData.TrainingIndices).ToList();
+      IEnumerable<double> trainingEstimatedValues = EstimatedTrainingValues.ToList();
+      IEnumerable<double> trainingMeanModelPredictions = meanModel.GetEstimatedValues(ProblemData.Dataset, ProblemData.TrainingIndices).ToList();
+      IEnumerable<double> trainingAR1ModelPredictions = AR1model.GetEstimatedValues(ProblemData.Dataset, ProblemData.TrainingIndices).ToList();
+
+      TrainingDirectionalSymmetry = OnlineDirectionalSymmetryCalculator.Calculate(trainingTargetValues.First(), trainingTargetValues, trainingEstimatedValues, out errorState);
+      TrainingDirectionalSymmetry = errorState == OnlineCalculatorError.None ? TrainingDirectionalSymmetry : 0.0;
+      TrainingWeightedDirectionalSymmetry = OnlineWeightedDirectionalSymmetryCalculator.Calculate(trainingTargetValues.First(), trainingTargetValues, trainingEstimatedValues, out errorState);
+      TrainingWeightedDirectionalSymmetry = errorState == OnlineCalculatorError.None ? TrainingWeightedDirectionalSymmetry : 0.0;
+      TrainingTheilsUStatisticAR1 = OnlineTheilsUStatisticCalculator.Calculate(trainingTargetValues.First(), trainingTargetValues, trainingAR1ModelPredictions, trainingEstimatedValues, out errorState);
+      TrainingTheilsUStatisticAR1 = errorState == OnlineCalculatorError.None ? TrainingTheilsUStatisticAR1 : double.PositiveInfinity;
+      TrainingTheilsUStatisticMean = OnlineTheilsUStatisticCalculator.Calculate(trainingTargetValues.First(), trainingTargetValues, trainingMeanModelPredictions, trainingEstimatedValues, out errorState);
+      TrainingTheilsUStatisticMean = errorState == OnlineCalculatorError.None ? TrainingTheilsUStatisticMean : double.PositiveInfinity;
+      #endregion
+
+      #region Calculate test quality measures
+      IEnumerable<double> testTargetValues = ProblemData.Dataset.GetDoubleValues(ProblemData.TargetVariable, ProblemData.TestIndices).ToList();
+      IEnumerable<double> testEstimatedValues = EstimatedTestValues.ToList();
+      IEnumerable<double> testMeanModelPredictions = meanModel.GetEstimatedValues(ProblemData.Dataset, ProblemData.TestIndices).ToList();
+      IEnumerable<double> testAR1ModelPredictions = AR1model.GetEstimatedValues(ProblemData.Dataset, ProblemData.TestIndices).ToList();
+
+      TestDirectionalSymmetry = OnlineDirectionalSymmetryCalculator.Calculate(testTargetValues.First(), testTargetValues, testEstimatedValues, out errorState);
+      TestDirectionalSymmetry = errorState == OnlineCalculatorError.None ? TestDirectionalSymmetry : 0.0;
+      TestWeightedDirectionalSymmetry = OnlineWeightedDirectionalSymmetryCalculator.Calculate(testTargetValues.First(), testTargetValues, testEstimatedValues, out errorState);
+      TestWeightedDirectionalSymmetry = errorState == OnlineCalculatorError.None ? TestWeightedDirectionalSymmetry : 0.0;
+      TestTheilsUStatisticAR1 = OnlineTheilsUStatisticCalculator.Calculate(testTargetValues.First(), testTargetValues, testAR1ModelPredictions, testEstimatedValues, out errorState);
+      TestTheilsUStatisticAR1 = errorState == OnlineCalculatorError.None ? TestTheilsUStatisticAR1 : double.PositiveInfinity;
+      TestTheilsUStatisticMean = OnlineTheilsUStatisticCalculator.Calculate(testTargetValues.First(), testTargetValues, testMeanModelPredictions, testEstimatedValues, out errorState);
+      TestTheilsUStatisticMean = errorState == OnlineCalculatorError.None ? TestTheilsUStatisticMean : double.PositiveInfinity;
+      #endregion
+    }
+
+    protected void CalculateTimeSeriesResults(int trainingHorizon, int testHorizon) {
+      TimeSeriesPrognosisResults = new TimeSeriesPrognosisResults(trainingHorizon, testHorizon, this);
+    }
+  }
+}
Index: branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Classification/IClassificationEnsembleModel.cs
===================================================================
--- branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Classification/IClassificationEnsembleModel.cs	(revision 9073)
+++ branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Classification/IClassificationEnsembleModel.cs	(revision 9073)
@@ -0,0 +1,30 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Collections.Generic;
+namespace HeuristicLab.Problems.DataAnalysis {
+  public interface IClassificationEnsembleModel : IClassificationModel {
+    void Add(IClassificationModel model);
+    void Remove(IClassificationModel model);
+    IEnumerable<IClassificationModel> Models { get; }
+    IEnumerable<IEnumerable<double>> GetEstimatedClassValueVectors(Dataset dataset, IEnumerable<int> rows);
+  }
+}
Index: branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Classification/IClassificationEnsembleSolution.cs
===================================================================
--- branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Classification/IClassificationEnsembleSolution.cs	(revision 9073)
+++ branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Classification/IClassificationEnsembleSolution.cs	(revision 9073)
@@ -0,0 +1,30 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Collections.Generic;
+using HeuristicLab.Core;
+namespace HeuristicLab.Problems.DataAnalysis {
+  public interface IClassificationEnsembleSolution : IClassificationSolution {
+    new IClassificationEnsembleModel Model { get; }
+    IItemCollection<IClassificationSolution> ClassificationSolutions { get; }
+    IEnumerable<IEnumerable<double>> GetEstimatedClassValueVectors(Dataset dataset, IEnumerable<int> rows);
+  }
+}
Index: branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Classification/IClassificationModel.cs
===================================================================
--- branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Classification/IClassificationModel.cs	(revision 9073)
+++ branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Classification/IClassificationModel.cs	(revision 9073)
@@ -0,0 +1,28 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Collections.Generic;
+namespace HeuristicLab.Problems.DataAnalysis {
+  public interface IClassificationModel : IDataAnalysisModel {
+    IEnumerable<double> GetEstimatedClassValues(Dataset dataset, IEnumerable<int> rows);
+    IClassificationSolution CreateClassificationSolution(IClassificationProblemData problemData);
+  }
+}
Index: branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Classification/IClassificationProblem.cs
===================================================================
--- branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Classification/IClassificationProblem.cs	(revision 9073)
+++ branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Classification/IClassificationProblem.cs	(revision 9073)
@@ -0,0 +1,25 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  public interface IClassificationProblem : IDataAnalysisProblem<IClassificationProblemData> {
+  }
+}
Index: branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Classification/IClassificationProblemData.cs
===================================================================
--- branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Classification/IClassificationProblemData.cs	(revision 9073)
+++ branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Classification/IClassificationProblemData.cs	(revision 9073)
@@ -0,0 +1,40 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Collections.Generic;
+namespace HeuristicLab.Problems.DataAnalysis {
+  public interface IClassificationProblemData : IDataAnalysisProblemData {
+    string TargetVariable { get; }
+
+    IEnumerable<string> ClassNames { get; }
+    IEnumerable<double> ClassValues { get; }
+    int Classes { get; }
+
+    string GetClassName(double classValue);
+    double GetClassValue(string className);
+    void SetClassName(double classValue, string className);
+
+    double GetClassificationPenalty(string correctClass, string estimatedClass);
+    double GetClassificationPenalty(double correctClassValue, double estimatedClassValue);
+    void SetClassificationPenalty(string correctClassName, string estimatedClassName, double penalty);
+    void SetClassificationPenalty(double correctClassValue, double estimatedClassValue, double penalty);
+  }
+}
Index: branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Classification/IClassificationSolution.cs
===================================================================
--- branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Classification/IClassificationSolution.cs	(revision 9073)
+++ branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Classification/IClassificationSolution.cs	(revision 9073)
@@ -0,0 +1,36 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Collections.Generic;
+namespace HeuristicLab.Problems.DataAnalysis {
+  public interface IClassificationSolution : IDataAnalysisSolution {
+    new IClassificationModel Model { get; }
+    new IClassificationProblemData ProblemData { get; set; }
+
+    IEnumerable<double> EstimatedClassValues { get; }
+    IEnumerable<double> EstimatedTrainingClassValues { get; }
+    IEnumerable<double> EstimatedTestClassValues { get; }
+    IEnumerable<double> GetEstimatedClassValues(IEnumerable<int> rows);
+
+    double TrainingAccuracy { get; }
+    double TestAccuracy { get; }
+  }
+}
Index: branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Classification/IDiscriminantFunctionClassificationModel.cs
===================================================================
--- branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Classification/IDiscriminantFunctionClassificationModel.cs	(revision 9073)
+++ branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Classification/IDiscriminantFunctionClassificationModel.cs	(revision 9073)
@@ -0,0 +1,38 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+namespace HeuristicLab.Problems.DataAnalysis {
+  public interface IDiscriminantFunctionClassificationModel : IClassificationModel {
+    IEnumerable<double> Thresholds { get; }
+    IEnumerable<double> ClassValues { get; }
+    IDiscriminantFunctionThresholdCalculator ThresholdCalculator { get; }
+    void RecalculateModelParameters(IClassificationProblemData problemData, IEnumerable<int> rows);
+    // class values and thresholds can only be assigned simultanously
+    void SetThresholdsAndClassValues(IEnumerable<double> thresholds, IEnumerable<double> classValues);
+    IEnumerable<double> GetEstimatedValues(Dataset dataset, IEnumerable<int> rows);
+
+    event EventHandler ThresholdsChanged;
+
+    IDiscriminantFunctionClassificationSolution CreateDiscriminantFunctionClassificationSolution(IClassificationProblemData problemData);
+  }
+}
Index: branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Classification/IDiscriminantFunctionClassificationSolution.cs
===================================================================
--- branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Classification/IDiscriminantFunctionClassificationSolution.cs	(revision 9073)
+++ branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Classification/IDiscriminantFunctionClassificationSolution.cs	(revision 9073)
@@ -0,0 +1,33 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+namespace HeuristicLab.Problems.DataAnalysis {
+  public interface IDiscriminantFunctionClassificationSolution : IClassificationSolution {
+    new IDiscriminantFunctionClassificationModel Model { get; }
+
+    IEnumerable<double> EstimatedValues { get; }
+    IEnumerable<double> EstimatedTrainingValues { get; }
+    IEnumerable<double> EstimatedTestValues { get; }
+    IEnumerable<double> GetEstimatedValues(IEnumerable<int> rows);
+  }
+}
Index: branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Classification/IDiscriminantFunctionThresholdCalculator.cs
===================================================================
--- branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Classification/IDiscriminantFunctionThresholdCalculator.cs	(revision 9073)
+++ branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Classification/IDiscriminantFunctionThresholdCalculator.cs	(revision 9073)
@@ -0,0 +1,28 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Collections.Generic;
+using HeuristicLab.Core;
+namespace HeuristicLab.Problems.DataAnalysis {
+  public interface IDiscriminantFunctionThresholdCalculator : INamedItem {
+    void Calculate(IClassificationProblemData problemData, IEnumerable<double> estimatedValues, IEnumerable<double> targetClassValues, out double[] classValues, out double[] thresholds);
+  }
+}
Index: branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Clustering/IClusteringModel.cs
===================================================================
--- branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Clustering/IClusteringModel.cs	(revision 9073)
+++ branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Clustering/IClusteringModel.cs	(revision 9073)
@@ -0,0 +1,27 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Collections.Generic;
+namespace HeuristicLab.Problems.DataAnalysis {
+  public interface IClusteringModel : IDataAnalysisModel {
+    IEnumerable<int> GetClusterValues(Dataset dataset, IEnumerable<int> rows);
+  }
+}
Index: branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Clustering/IClusteringProblem.cs
===================================================================
--- branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Clustering/IClusteringProblem.cs	(revision 9073)
+++ branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Clustering/IClusteringProblem.cs	(revision 9073)
@@ -0,0 +1,25 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  public interface IClusteringProblem : IDataAnalysisProblem<IClusteringProblemData> {
+  }
+}
Index: branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Clustering/IClusteringProblemData.cs
===================================================================
--- branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Clustering/IClusteringProblemData.cs	(revision 9073)
+++ branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Clustering/IClusteringProblemData.cs	(revision 9073)
@@ -0,0 +1,25 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  public interface IClusteringProblemData : IDataAnalysisProblemData {
+  }
+}
Index: branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Clustering/IClusteringSolution.cs
===================================================================
--- branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Clustering/IClusteringSolution.cs	(revision 9073)
+++ branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Clustering/IClusteringSolution.cs	(revision 9073)
@@ -0,0 +1,33 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Collections.Generic;
+namespace HeuristicLab.Problems.DataAnalysis {
+  public interface IClusteringSolution : IDataAnalysisSolution {
+    new IClusteringModel Model { get; }
+    new IClusteringProblemData ProblemData { get; set; }
+
+    IEnumerable<int> ClusterValues { get; }
+    IEnumerable<int> TrainingClusterValues { get; }
+    IEnumerable<int> TestClusterValues { get; }
+    IEnumerable<int> GetClusterValues(IEnumerable<int> rows);
+  }
+}
Index: branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/IDataAnalysisModel.cs
===================================================================
--- branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/IDataAnalysisModel.cs	(revision 9073)
+++ branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/IDataAnalysisModel.cs	(revision 9073)
@@ -0,0 +1,27 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using HeuristicLab.Core;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  public interface IDataAnalysisModel : INamedItem {
+  }
+}
Index: branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/IDataAnalysisProblem.cs
===================================================================
--- branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/IDataAnalysisProblem.cs	(revision 9073)
+++ branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/IDataAnalysisProblem.cs	(revision 9073)
@@ -0,0 +1,38 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using HeuristicLab.Core;
+using HeuristicLab.Optimization;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  public interface IDataAnalysisProblem : IProblem {
+    IParameter ProblemDataParameter { get; }
+    IDataAnalysisProblemData ProblemData { get; }
+    event EventHandler ProblemDataChanged;
+  }
+
+  public interface IDataAnalysisProblem<T> : IDataAnalysisProblem
+  where T : class, IDataAnalysisProblemData {
+    new IValueParameter<T> ProblemDataParameter { get; }
+    new T ProblemData { get; }
+  }
+}
Index: branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/IDataAnalysisProblemData.cs
===================================================================
--- branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/IDataAnalysisProblemData.cs	(revision 9073)
+++ branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/IDataAnalysisProblemData.cs	(revision 9073)
@@ -0,0 +1,46 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  public interface IDataAnalysisProblemData : INamedItem {
+    bool IsEmpty { get; }
+
+    Dataset Dataset { get; }
+    ICheckedItemList<StringValue> InputVariables { get; }
+    IEnumerable<string> AllowedInputVariables { get; }
+
+    IntRange TrainingPartition { get; }
+    IntRange TestPartition { get; }
+
+    IEnumerable<int> TrainingIndices { get; }
+    IEnumerable<int> TestIndices { get; }
+
+    bool IsTrainingSample(int index);
+    bool IsTestSample(int index);
+
+    event EventHandler Changed;
+  }
+}
Index: branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/IDataAnalysisSolution.cs
===================================================================
--- branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/IDataAnalysisSolution.cs	(revision 9073)
+++ branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/IDataAnalysisSolution.cs	(revision 9073)
@@ -0,0 +1,34 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  public interface IDataAnalysisSolution : INamedItem, IStorableContent {
+    IDataAnalysisModel Model { get; }
+    IDataAnalysisProblemData ProblemData { get; set; }
+
+    event EventHandler ModelChanged;
+    event EventHandler ProblemDataChanged;
+  }
+}
Index: branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/IDependencyCalculator.cs
===================================================================
--- branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/IDependencyCalculator.cs	(revision 9073)
+++ branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/IDependencyCalculator.cs	(revision 9073)
@@ -0,0 +1,32 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Collections.Generic;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  public interface IDependencyCalculator {
+    double Maximum { get; }
+    double Minimum { get; }
+    string Name { get; }
+
+    double Calculate(IEnumerable<double> originalValues, IEnumerable<double> estimatedValues, out OnlineCalculatorError errorState);
+  }
+}
Index: branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/IOnlineCalculator.cs
===================================================================
--- branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/IOnlineCalculator.cs	(revision 9073)
+++ branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/IOnlineCalculator.cs	(revision 9073)
@@ -0,0 +1,46 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+
+using System;
+namespace HeuristicLab.Problems.DataAnalysis {
+  [Flags]
+  public enum OnlineCalculatorError {
+    /// <summary>
+    /// No error occurred
+    /// </summary>
+    None = 0,
+    /// <summary>
+    /// An invalid value has been added (often +/- Infinity and NaN are invalid values)
+    /// </summary>
+    InvalidValueAdded = 1,
+    /// <summary>
+    /// The number of elements added to the evaluator is not sufficient to calculate the result value
+    /// </summary>
+    InsufficientElementsAdded = 2
+  }
+  public interface IOnlineCalculator {
+    OnlineCalculatorError ErrorState { get; }
+    double Value { get; }
+    void Reset();
+    void Add(double original, double estimated);
+  }
+}
Index: branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Regression/IRegressionEnsembleModel.cs
===================================================================
--- branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Regression/IRegressionEnsembleModel.cs	(revision 9073)
+++ branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Regression/IRegressionEnsembleModel.cs	(revision 9073)
@@ -0,0 +1,30 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Collections.Generic;
+namespace HeuristicLab.Problems.DataAnalysis {
+  public interface IRegressionEnsembleModel : IRegressionModel {
+    void Add(IRegressionModel model);
+    void Remove(IRegressionModel model);
+    IEnumerable<IRegressionModel> Models { get; }
+    IEnumerable<IEnumerable<double>> GetEstimatedValueVectors(Dataset dataset, IEnumerable<int> rows);
+  }
+}
Index: branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Regression/IRegressionEnsembleSolution.cs
===================================================================
--- branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Regression/IRegressionEnsembleSolution.cs	(revision 9073)
+++ branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Regression/IRegressionEnsembleSolution.cs	(revision 9073)
@@ -0,0 +1,31 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Collections.Generic;
+using HeuristicLab.Core;
+namespace HeuristicLab.Problems.DataAnalysis {
+  public interface IRegressionEnsembleSolution : IRegressionSolution {
+    new IRegressionEnsembleModel Model { get; }
+    new RegressionEnsembleProblemData ProblemData { get; set; }
+    IItemCollection<IRegressionSolution> RegressionSolutions { get; }
+    IEnumerable<IEnumerable<double>> GetEstimatedValueVectors(Dataset dataset, IEnumerable<int> rows);
+  }
+}
Index: branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Regression/IRegressionModel.cs
===================================================================
--- branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Regression/IRegressionModel.cs	(revision 9073)
+++ branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Regression/IRegressionModel.cs	(revision 9073)
@@ -0,0 +1,28 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Collections.Generic;
+namespace HeuristicLab.Problems.DataAnalysis {
+  public interface IRegressionModel : IDataAnalysisModel {
+    IEnumerable<double> GetEstimatedValues(Dataset dataset, IEnumerable<int> rows);
+    IRegressionSolution CreateRegressionSolution(IRegressionProblemData problemData);
+  }
+}
Index: branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Regression/IRegressionProblem.cs
===================================================================
--- branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Regression/IRegressionProblem.cs	(revision 9073)
+++ branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Regression/IRegressionProblem.cs	(revision 9073)
@@ -0,0 +1,25 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  public interface IRegressionProblem : IDataAnalysisProblem<IRegressionProblemData> {
+  }
+}
Index: branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Regression/IRegressionProblemData.cs
===================================================================
--- branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Regression/IRegressionProblemData.cs	(revision 9073)
+++ branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Regression/IRegressionProblemData.cs	(revision 9073)
@@ -0,0 +1,26 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  public interface IRegressionProblemData : IDataAnalysisProblemData {
+    string TargetVariable { get; }
+  }
+}
Index: branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Regression/IRegressionSolution.cs
===================================================================
--- branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Regression/IRegressionSolution.cs	(revision 9073)
+++ branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Regression/IRegressionSolution.cs	(revision 9073)
@@ -0,0 +1,44 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Collections.Generic;
+namespace HeuristicLab.Problems.DataAnalysis {
+  public interface IRegressionSolution : IDataAnalysisSolution {
+    new IRegressionModel Model { get; }
+    new IRegressionProblemData ProblemData { get; set; }
+
+    IEnumerable<double> EstimatedValues { get; }
+    IEnumerable<double> EstimatedTrainingValues { get; }
+    IEnumerable<double> EstimatedTestValues { get; }
+    IEnumerable<double> GetEstimatedValues(IEnumerable<int> rows);
+
+    double TrainingMeanSquaredError { get; }
+    double TestMeanSquaredError { get; }
+    double TrainingMeanAbsoluteError { get; }
+    double TestMeanAbsoluteError { get; }
+    double TrainingRSquared { get; }
+    double TestRSquared { get; }
+    double TrainingRelativeError { get; }
+    double TestRelativeError { get; }
+    double TrainingNormalizedMeanSquaredError { get; }
+    double TestNormalizedMeanSquaredError { get; }
+  }
+}
Index: branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/TimeSeriesPrognosis/IOnlineTimeSeriesCalculator.cs
===================================================================
--- branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/TimeSeriesPrognosis/IOnlineTimeSeriesCalculator.cs	(revision 9073)
+++ branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/TimeSeriesPrognosis/IOnlineTimeSeriesCalculator.cs	(revision 9073)
@@ -0,0 +1,33 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2011 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+
+using System;
+using System.Collections.Generic;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  public interface IOnlineTimeSeriesCalculator {
+    OnlineCalculatorError ErrorState { get; }
+    double Value { get; }
+    void Reset();
+    void Add(double startValue, IEnumerable<double> actualContinuation, IEnumerable<double> predictedContinuation);
+  }
+}
Index: branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/TimeSeriesPrognosis/ITimeSeriesPrognosisModel.cs
===================================================================
--- branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/TimeSeriesPrognosis/ITimeSeriesPrognosisModel.cs	(revision 9073)
+++ branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/TimeSeriesPrognosis/ITimeSeriesPrognosisModel.cs	(revision 9073)
@@ -0,0 +1,28 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2011 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Collections.Generic;
+namespace HeuristicLab.Problems.DataAnalysis {
+  public interface ITimeSeriesPrognosisModel : IRegressionModel {
+    IEnumerable<IEnumerable<double>> GetPrognosedValues(Dataset dataset, IEnumerable<int> rows, IEnumerable<int> horizons);
+    ITimeSeriesPrognosisSolution CreateTimeSeriesPrognosisSolution(ITimeSeriesPrognosisProblemData problemData);
+  }
+}
Index: branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/TimeSeriesPrognosis/ITimeSeriesPrognosisProblem.cs
===================================================================
--- branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/TimeSeriesPrognosis/ITimeSeriesPrognosisProblem.cs	(revision 9073)
+++ branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/TimeSeriesPrognosis/ITimeSeriesPrognosisProblem.cs	(revision 9073)
@@ -0,0 +1,25 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2011 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  public interface ITimeSeriesPrognosisProblem : IDataAnalysisProblem<ITimeSeriesPrognosisProblemData> {
+  }
+}
Index: branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/TimeSeriesPrognosis/ITimeSeriesPrognosisProblemData.cs
===================================================================
--- branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/TimeSeriesPrognosis/ITimeSeriesPrognosisProblemData.cs	(revision 9073)
+++ branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/TimeSeriesPrognosis/ITimeSeriesPrognosisProblemData.cs	(revision 9073)
@@ -0,0 +1,27 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2011 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  public interface ITimeSeriesPrognosisProblemData : IRegressionProblemData {
+    int TrainingHorizon { get; set; }
+    int TestHorizon { get; set; }
+  }
+}
Index: branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/TimeSeriesPrognosis/ITimeSeriesPrognosisSolution.cs
===================================================================
--- branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/TimeSeriesPrognosis/ITimeSeriesPrognosisSolution.cs	(revision 9073)
+++ branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/TimeSeriesPrognosis/ITimeSeriesPrognosisSolution.cs	(revision 9073)
@@ -0,0 +1,39 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2011 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Collections.Generic;
+namespace HeuristicLab.Problems.DataAnalysis {
+  public interface ITimeSeriesPrognosisSolution : IRegressionSolution {
+    new ITimeSeriesPrognosisModel Model { get; }
+    new ITimeSeriesPrognosisProblemData ProblemData { get; set; }
+
+    IEnumerable<IEnumerable<double>> GetPrognosedValues(IEnumerable<int> rows, IEnumerable<int> horizon);
+
+    double TrainingTheilsUStatisticAR1 { get; }
+    double TestTheilsUStatisticAR1 { get; }
+    double TrainingTheilsUStatisticMean { get; }
+    double TestTheilsUStatisticMean { get; }
+    double TrainingDirectionalSymmetry { get; }
+    double TestDirectionalSymmetry { get; }
+    double TrainingWeightedDirectionalSymmetry { get; }
+    double TestWeightedDirectionalSymmetry { get; }
+  }
+}
Index: branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/AutoCorrelationCalculator.cs
===================================================================
--- branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/AutoCorrelationCalculator.cs	(revision 9073)
+++ branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/AutoCorrelationCalculator.cs	(revision 9073)
@@ -0,0 +1,38 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Linq;
+
+namespace HeuristicLab.Problems.DataAnalysis.OnlineCalculators {
+  public class AutoCorrelationCalculator {
+    public static double[] Calculate(double[] values, out OnlineCalculatorError error) {
+      error = OnlineCalculatorError.None;
+      if (values.Any(x => double.IsNaN(x) || double.IsInfinity(x))) {
+        error = OnlineCalculatorError.InvalidValueAdded;
+        return new double[0];
+      }
+
+      double[] correlations = new double[values.Length];
+      alglib.corr.corrr1dcircular(values, values.Length, values, values.Length, ref correlations);
+      return correlations;
+    }
+  }
+}
Index: branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/DependencyCalculator/HoeffdingsDependenceCalculator.cs
===================================================================
--- branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/DependencyCalculator/HoeffdingsDependenceCalculator.cs	(revision 9073)
+++ branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/DependencyCalculator/HoeffdingsDependenceCalculator.cs	(revision 9073)
@@ -0,0 +1,139 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  public class HoeffdingsDependenceCalculator : IDependencyCalculator {
+
+    public double Maximum { get { return 1.0; } }
+
+    public double Minimum { get { return -0.5; } }
+
+    public string Name { get { return "Hoeffdings Dependence"; } }
+
+    public double Calculate(IEnumerable<double> originalValues, IEnumerable<double> estimatedValues, out OnlineCalculatorError errorState) {
+      return HoeffdingsDependenceCalculator.CalculateHoeffdings(originalValues, estimatedValues, out errorState);
+    }
+
+    public static double CalculateHoeffdings(IEnumerable<double> originalValues, IEnumerable<double> estimatedValues, out OnlineCalculatorError errorState) {
+      double d = HoeffD(originalValues, estimatedValues, out errorState);
+      if (errorState != OnlineCalculatorError.None) return double.NaN;
+      return d;
+    }
+
+    /// <summary>
+    /// computes Hoeffding's dependence coefficient. 
+    /// Source: hoeffd.r from R package hmisc http://cran.r-project.org/web/packages/Hmisc/index.html
+    /// </summary>
+    private static double HoeffD(IEnumerable<double> xs, IEnumerable<double> ys, out OnlineCalculatorError errorState) {
+      double[] rx = TiedRank(xs);
+      double[] ry = TiedRank(ys);
+      if (rx.Length != ry.Length) throw new ArgumentException("The number of elements in xs and ys does not match");
+      double[] rxy = TiedRank(xs, ys);
+
+      int n = rx.Length;
+      double q = 0, r = 0, s = 0;
+      double scaling = 1.0 / (n * (n - 1));
+      for (int i = 0; i < n; i++) {
+        q += (rx[i] - 1) * (rx[i] - 2) * (ry[i] - 1) * (ry[i] - 2) * scaling;
+        r += (rx[i] - 2) * (ry[i] - 2) * rxy[i] * scaling;
+        s += rxy[i] * (rxy[i] - 1) * scaling;
+      }
+      errorState = OnlineCalculatorError.None;
+      // return 30.0 * (q - 2 * (n - 2) * r + (n - 2) * (n - 3) * s) / n / (n - 1) / (n - 2) / (n - 3) / (n - 4);
+      double t0 = q / (n - 2) / (n - 3) / (n - 4);
+      double t1 = 2 * r / (n - 3) / (n - 4);
+      double t2 = s / (n - 4);
+      return 30.0 * (t0 - t1 + t2);
+    }
+
+    private static double[] TiedRank(IEnumerable<double> xs) {
+      var xsArr = xs.ToArray();
+      var idx = Enumerable.Range(1, xsArr.Length).ToArray();
+      Array.Sort(xsArr, idx);
+      CRank(xsArr);
+      Array.Sort(idx, xsArr);
+      return xsArr;
+    }
+
+    /// <summary>
+    /// Calculates the joint rank with midranks for ties. Source: hoeffd.r from R package hmisc http://cran.r-project.org/web/packages/Hmisc/index.html
+    /// </summary>
+    /// <param name="xs"></param>
+    /// <param name="ys"></param>
+    /// <returns></returns>
+    private static double[] TiedRank(IEnumerable<double> xs, IEnumerable<double> ys) {
+      var xsArr = xs.ToArray();
+      var ysArr = ys.ToArray();
+      var r = new double[xsArr.Length];
+      int n = r.Length;
+      for (int i = 0; i < n; i++) {
+        var xi = xsArr[i];
+        var yi = ysArr[i];
+        double ri = 0.0;
+        for (int j = 0; j < n; j++) {
+          if (i != j) {
+            double cx;
+            if (xsArr[j] < xi) cx = 1.0;
+            else if (xsArr[j] > xi) cx = 0.0;
+            else cx = 0.5;  // eq
+            double cy;
+            if (ysArr[j] < yi) cy = 1.0;
+            else if (ysArr[j] > yi) cy = 0.0;
+            else cy = 0.5; // eq
+            ri = ri + cx * cy;
+          }
+        }
+        r[i] = ri;
+      }
+      return r;
+    }
+
+    /// <summary>
+    /// Calculates midranks. Source: Numerical Recipes in C. p 642
+    /// </summary>
+    /// <param name="w">Sorted array of elements, replaces the elements by their rank, including midranking of ties</param>
+    /// <returns></returns>
+    private static void CRank(double[] w) {
+      int i = 0;
+      int n = w.Length;
+      while (i < n - 1) {
+        if (w[i + 1] > w[i]) {    // w[i+1] must be larger or equal w[i] as w must be sorted
+          // not a tie
+          w[i] = i + 1;
+          i++;
+        } else {
+          int j;
+          for (j = i + 1; j < n && w[j] <= w[i]; j++) ; // how far does it go (<= effectively means == as w must be sorted, side-step equality for double values)
+          double rank = 1 + 0.5 * (i + j - 1);
+          int k;
+          for (k = i; k < j; k++) w[k] = rank; // set the rank for all tied entries
+          i = j;
+        }
+      }
+
+      if (i == n - 1) w[n - 1] = n;   // if the last element was not tied, this is its rank
+    }
+  }
+}
Index: branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/DependencyCalculator/PearsonsRDependenceCalculator.cs
===================================================================
--- branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/DependencyCalculator/PearsonsRDependenceCalculator.cs	(revision 9073)
+++ branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/DependencyCalculator/PearsonsRDependenceCalculator.cs	(revision 9073)
@@ -0,0 +1,38 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  public class PearsonsRDependenceCalculator : IDependencyCalculator {
+
+    public double Maximum { get { return 1.0; } }
+
+    public double Minimum { get { return -1.0; } }
+
+    public string Name { get { return "Pearsons R"; } }
+
+    public double Calculate(IEnumerable<double> originalValues, IEnumerable<double> estimatedValues, out OnlineCalculatorError errorState) {
+      return Math.Sqrt(OnlinePearsonsRSquaredCalculator.Calculate(originalValues, estimatedValues, out errorState));
+    }
+  }
+}
Index: branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/DependencyCalculator/PearsonsRSquaredDependenceCalculator.cs
===================================================================
--- branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/DependencyCalculator/PearsonsRSquaredDependenceCalculator.cs	(revision 9073)
+++ branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/DependencyCalculator/PearsonsRSquaredDependenceCalculator.cs	(revision 9073)
@@ -0,0 +1,37 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Collections.Generic;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  public class PearsonsRSquaredDependenceCalculator : IDependencyCalculator {
+
+    public double Maximum { get { return 1.0; } }
+
+    public double Minimum { get { return 0.0; } }
+
+    public string Name { get { return "Pearsons R Squared"; } }
+
+    public double Calculate(IEnumerable<double> originalValues, IEnumerable<double> estimatedValues, out OnlineCalculatorError errorState) {
+      return OnlinePearsonsRSquaredCalculator.Calculate(originalValues, estimatedValues, out errorState);
+    }
+  }
+}
Index: branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/DependencyCalculator/SpearmansRankCorrelationCoefficientCalculator.cs
===================================================================
--- branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/DependencyCalculator/SpearmansRankCorrelationCoefficientCalculator.cs	(revision 9073)
+++ branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/DependencyCalculator/SpearmansRankCorrelationCoefficientCalculator.cs	(revision 9073)
@@ -0,0 +1,53 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Collections.Generic;
+using System.Linq;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  public class SpearmansRankCorrelationCoefficientCalculator : IDependencyCalculator {
+
+    public double Maximum { get { return 1.0; } }
+
+    public double Minimum { get { return -1.0; } }
+
+    public string Name { get { return "Spearmans Rank"; } }
+
+    public double Calculate(IEnumerable<double> originalValues, IEnumerable<double> estimatedValues, out OnlineCalculatorError errorState) {
+      return SpearmansRankCorrelationCoefficientCalculator.CalculateSpearmansRank(originalValues, estimatedValues, out errorState);
+    }
+
+    public static double CalculateSpearmansRank(IEnumerable<double> originalValues, IEnumerable<double> estimatedValues, out OnlineCalculatorError errorState) {
+      double rs = double.NaN;
+      try {
+        var original = originalValues.ToArray();
+        var estimated = estimatedValues.ToArray();
+        rs = alglib.basestat.spearmancorr2(original, estimated, original.Length);
+        errorState = OnlineCalculatorError.None;
+      }
+      catch (alglib.alglibexception) {
+        errorState = OnlineCalculatorError.InvalidValueAdded;
+      }
+
+      return rs;
+    }
+  }
+}
Index: branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/NormalizedGiniCalculator.cs
===================================================================
--- branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/NormalizedGiniCalculator.cs	(revision 9073)
+++ branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/NormalizedGiniCalculator.cs	(revision 9073)
@@ -0,0 +1,65 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  public class NormalizedGiniCalculator {
+
+    public static double Calculate(IEnumerable<double> originalValues, IEnumerable<double> estimatedValues, out OnlineCalculatorError errorState) {
+      var originalValuesArr = originalValues.ToArray();
+      var estimatedValuesArr = estimatedValues.ToArray();
+      if (originalValuesArr.Count() != estimatedValuesArr.Count()) {
+        throw new ArgumentException("Number of elements in originalValues and estimatedValues enumerations doesn't match.");
+      }
+      double oe = Gini(originalValuesArr, estimatedValuesArr, out errorState);
+      if (errorState != OnlineCalculatorError.None) return double.NaN;
+
+      return oe / (Gini(originalValuesArr, originalValuesArr, out errorState));
+    }
+
+    private static double Gini(IEnumerable<double> original, IEnumerable<double> estimated, out OnlineCalculatorError errorState) {
+      var pairs =
+        estimated.Zip(original, (e, o) => new { e, o })
+          .OrderByDescending(p => p.e);
+      if (pairs.Any()) errorState = OnlineCalculatorError.None;
+      else errorState = OnlineCalculatorError.InsufficientElementsAdded;
+      double giniSum = 0.0;
+      double sumOriginal = 0.0;
+      int n = 0;
+      foreach (var p in pairs) {
+        if (double.IsNaN(p.o) || double.IsNaN(p.e)) {
+          errorState = OnlineCalculatorError.InvalidValueAdded;
+          return double.NaN;
+        }
+        sumOriginal += p.o;
+        giniSum += sumOriginal;
+        n++;
+      }
+      giniSum /= sumOriginal;
+
+      return (giniSum - ((n + 1) / 2.0)) / n;
+    }
+  }
+}
Index: branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineAccuracyCalculator.cs
===================================================================
--- branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineAccuracyCalculator.cs	(revision 9073)
+++ branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineAccuracyCalculator.cs	(revision 9073)
@@ -0,0 +1,93 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using HeuristicLab.Common;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  public class OnlineAccuracyCalculator : IOnlineCalculator {
+
+    private int correctlyClassified;
+    private int n;
+    public double Accuracy {
+      get {
+        return correctlyClassified / (double)n;
+      }
+    }
+
+    public OnlineAccuracyCalculator() {
+      Reset();
+    }
+
+    #region IOnlineCalculator Members
+    private OnlineCalculatorError errorState;
+    public OnlineCalculatorError ErrorState {
+      get { return errorState; }
+    }
+    public double Value {
+      get { return Accuracy; }
+    }
+    public void Reset() {
+      n = 0;
+      correctlyClassified = 0;
+      errorState = OnlineCalculatorError.InsufficientElementsAdded;
+    }
+
+    public void Add(double original, double estimated) {
+      // ignore cases where original is NaN completly 
+      if (!double.IsNaN(original)) {
+        // increment number of observed samples
+        n++;
+        if (original.IsAlmost(estimated)) {
+          // original = estimated = +Inf counts as correctly classified
+          // original = estimated = -Inf counts as correctly classified
+          correctlyClassified++;
+        }
+        errorState = OnlineCalculatorError.None; // number of (non-NaN) samples >= 1
+      }
+    }
+    #endregion
+
+    public static double Calculate(IEnumerable<double> originalValues, IEnumerable<double> estimatedValues, out OnlineCalculatorError errorState) {
+      IEnumerator<double> originalEnumerator = originalValues.GetEnumerator();
+      IEnumerator<double> estimatedEnumerator = estimatedValues.GetEnumerator();
+      OnlineAccuracyCalculator accuracyCalculator = new OnlineAccuracyCalculator();
+
+      // always move forward both enumerators (do not use short-circuit evaluation!)
+      while (originalEnumerator.MoveNext() & estimatedEnumerator.MoveNext()) {
+        double original = originalEnumerator.Current;
+        double estimated = estimatedEnumerator.Current;
+        accuracyCalculator.Add(original, estimated);
+        if (accuracyCalculator.ErrorState != OnlineCalculatorError.None) break;
+      }
+
+      // check if both enumerators are at the end to make sure both enumerations have the same length
+      if (accuracyCalculator.ErrorState == OnlineCalculatorError.None &&
+          (estimatedEnumerator.MoveNext() || originalEnumerator.MoveNext())) {
+        throw new ArgumentException("Number of elements in originalValues and estimatedValues enumerations doesn't match.");
+      } else {
+        errorState = accuracyCalculator.ErrorState;
+        return accuracyCalculator.Accuracy;
+      }
+    }
+  }
+}
Index: branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineBoundedMeanSquaredErrorCalculator.cs
===================================================================
--- branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineBoundedMeanSquaredErrorCalculator.cs	(revision 9073)
+++ branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineBoundedMeanSquaredErrorCalculator.cs	(revision 9073)
@@ -0,0 +1,99 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  public class OnlineBoundedMeanSquaredErrorCalculator : IOnlineCalculator {
+
+    private double errorSum;
+    private int n;
+    public double BoundedMeanSquaredError {
+      get {
+        return n > 0 ? errorSum / n : 0.0;
+      }
+    }
+
+    public double LowerBound { get; private set; }
+    public double UpperBound { get; private set; }
+
+
+    public OnlineBoundedMeanSquaredErrorCalculator(double lowerBound, double upperbound) {
+      LowerBound = lowerBound;
+      UpperBound = upperbound;
+      Reset();
+    }
+
+    #region IOnlineCalculator Members
+    private OnlineCalculatorError errorState;
+    public OnlineCalculatorError ErrorState {
+      get { return errorState; }
+    }
+    public double Value {
+      get { return BoundedMeanSquaredError; }
+    }
+    public void Reset() {
+      n = 0;
+      errorSum = 0.0;
+      errorState = OnlineCalculatorError.InsufficientElementsAdded;
+    }
+
+    public void Add(double original, double estimated) {
+      if (double.IsNaN(estimated) || double.IsInfinity(estimated) ||
+          double.IsNaN(original) || double.IsInfinity(original) || (errorState & OnlineCalculatorError.InvalidValueAdded) > 0) {
+        errorState = errorState | OnlineCalculatorError.InvalidValueAdded;
+      } else {
+        double error = estimated - original;
+        if (estimated < LowerBound || estimated > UpperBound)
+          errorSum += Math.Abs(error);
+        else
+          errorSum += error * error;
+        n++;
+        errorState = errorState & (~OnlineCalculatorError.InsufficientElementsAdded);        // n >= 1
+      }
+    }
+    #endregion
+
+    public static double Calculate(IEnumerable<double> originalValues, IEnumerable<double> estimatedValues, double lowerBound, double upperBound, out OnlineCalculatorError errorState) {
+      IEnumerator<double> originalEnumerator = originalValues.GetEnumerator();
+      IEnumerator<double> estimatedEnumerator = estimatedValues.GetEnumerator();
+      OnlineBoundedMeanSquaredErrorCalculator boundedMseCalculator = new OnlineBoundedMeanSquaredErrorCalculator(lowerBound, upperBound);
+
+      // always move forward both enumerators (do not use short-circuit evaluation!)
+      while (originalEnumerator.MoveNext() & estimatedEnumerator.MoveNext()) {
+        double original = originalEnumerator.Current;
+        double estimated = estimatedEnumerator.Current;
+        boundedMseCalculator.Add(original, estimated);
+        if (boundedMseCalculator.ErrorState != OnlineCalculatorError.None) break;
+      }
+
+      // check if both enumerators are at the end to make sure both enumerations have the same length
+      if (boundedMseCalculator.ErrorState == OnlineCalculatorError.None &&
+         (estimatedEnumerator.MoveNext() || originalEnumerator.MoveNext())) {
+        throw new ArgumentException("Number of elements in originalValues and estimatedValues enumerations doesn't match.");
+      } else {
+        errorState = boundedMseCalculator.ErrorState;
+        return boundedMseCalculator.BoundedMeanSquaredError;
+      }
+    }
+  }
+}
Index: branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineCovarianceCalcualtor.cs
===================================================================
--- branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineCovarianceCalcualtor.cs	(revision 9073)
+++ branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineCovarianceCalcualtor.cs	(revision 9073)
@@ -0,0 +1,97 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  public class OnlineCovarianceCalculator : IOnlineCalculator {
+
+    private double xMean, yMean, Cn;
+    private int n;
+    public double Covariance {
+      get {
+        return n > 0 ? Cn / n : 0.0;
+      }
+    }
+
+    public OnlineCovarianceCalculator() {
+      Reset();
+    }
+
+    #region IOnlineCalculator Members
+    private OnlineCalculatorError errorState;
+    public OnlineCalculatorError ErrorState {
+      get { return errorState; }
+    }
+    public double Value {
+      get { return Covariance; }
+    }
+    public void Reset() {
+      n = 0;
+      Cn = 0.0;
+      xMean = 0.0;
+      yMean = 0.0;
+      errorState = OnlineCalculatorError.InsufficientElementsAdded;
+    }
+
+    public void Add(double x, double y) {
+      if (double.IsNaN(y) || double.IsInfinity(y) || double.IsNaN(x) || double.IsInfinity(x) || (errorState & OnlineCalculatorError.InvalidValueAdded) > 0) {
+        errorState = errorState | OnlineCalculatorError.InvalidValueAdded;
+      } else {
+        n++;
+        errorState = errorState & (~OnlineCalculatorError.InsufficientElementsAdded);        // n >= 1
+
+        // online calculation of tMean
+        xMean = xMean + (x - xMean) / n;
+        double delta = y - yMean; // delta = (y - yMean(n-1))
+        yMean = yMean + delta / n;
+
+        // online calculation of covariance
+        Cn = Cn + delta * (x - xMean); // C(n) = C(n-1) + (y - yMean(n-1)) (t - tMean(n))       
+      }
+    }
+    #endregion
+
+    public static double Calculate(IEnumerable<double> first, IEnumerable<double> second, out OnlineCalculatorError errorState) {
+      IEnumerator<double> firstEnumerator = first.GetEnumerator();
+      IEnumerator<double> secondEnumerator = second.GetEnumerator();
+      OnlineCovarianceCalculator covarianceCalculator = new OnlineCovarianceCalculator();
+
+      // always move forward both enumerators (do not use short-circuit evaluation!)
+      while (firstEnumerator.MoveNext() & secondEnumerator.MoveNext()) {
+        double x = secondEnumerator.Current;
+        double y = firstEnumerator.Current;
+        covarianceCalculator.Add(x, y);
+        if (covarianceCalculator.ErrorState != OnlineCalculatorError.None) break;
+      }
+
+      // check if both enumerators are at the end to make sure both enumerations have the same length
+      if (covarianceCalculator.ErrorState == OnlineCalculatorError.None &&
+          (secondEnumerator.MoveNext() || firstEnumerator.MoveNext())) {
+        throw new ArgumentException("Number of elements in first and second enumeration doesn't match.");
+      } else {
+        errorState = covarianceCalculator.ErrorState;
+        return covarianceCalculator.Covariance;
+      }
+    }
+  }
+}
Index: branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineDirectionalSymmetryCalculator.cs
===================================================================
--- branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineDirectionalSymmetryCalculator.cs	(revision 9073)
+++ branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineDirectionalSymmetryCalculator.cs	(revision 9073)
@@ -0,0 +1,119 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2011 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using HeuristicLab.Common;
+
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  public class OnlineDirectionalSymmetryCalculator : IOnlineTimeSeriesCalculator {
+    private int n;
+    private int nCorrect;
+
+    public double DirectionalSymmetry {
+      get {
+        if (n < 1) return 0.0;
+        return (double)nCorrect / n;
+      }
+    }
+
+    public OnlineDirectionalSymmetryCalculator() {
+      Reset();
+    }
+
+    public double Value {
+      get { return DirectionalSymmetry; }
+    }
+
+    private OnlineCalculatorError errorState;
+    public OnlineCalculatorError ErrorState {
+      get { return errorState; }
+    }
+
+    public void Add(double startValue, IEnumerable<double> actualContinuation, IEnumerable<double> predictedContinuation) {
+      if (double.IsNaN(startValue) || (errorState & OnlineCalculatorError.InvalidValueAdded) > 0) {
+        errorState = errorState | OnlineCalculatorError.InvalidValueAdded;
+      } else {
+        var actualEnumerator = actualContinuation.GetEnumerator();
+        var predictedEnumerator = predictedContinuation.GetEnumerator();
+        double prevActual = startValue;
+        double prevPredicted = startValue;
+        while (actualEnumerator.MoveNext() & predictedEnumerator.MoveNext() & errorState != OnlineCalculatorError.InvalidValueAdded) {
+          double actual = actualEnumerator.Current;
+          double predicted = predictedEnumerator.Current;
+          if (double.IsNaN(actual) || double.IsNaN(predicted)) {
+            errorState = errorState | OnlineCalculatorError.InvalidValueAdded;
+          } else {
+            // count a prediction correct if the trend (positive/negative/no change) is predicted correctly
+            if ((actual - prevActual) * (predicted - prevPredicted) > 0.0 ||
+                (actual - prevActual).IsAlmost(predicted - prevPredicted)
+              ) {
+              nCorrect++;
+            }
+            n++;
+          }
+        }
+        // check if both enumerators are at the end to make sure both enumerations have the same length
+        if (actualEnumerator.MoveNext() || predictedEnumerator.MoveNext()) {
+          errorState = errorState | OnlineCalculatorError.InvalidValueAdded;
+        } else {
+          errorState = errorState & (~OnlineCalculatorError.InsufficientElementsAdded); // n >= 1
+        }
+      }
+    }
+
+    public void Reset() {
+      n = 0;
+      nCorrect = 0;
+      errorState = OnlineCalculatorError.InsufficientElementsAdded;
+    }
+
+    public static double Calculate(double startValue, IEnumerable<double> actualContinuation, IEnumerable<double> predictedContinuation, out OnlineCalculatorError errorState) {
+      OnlineDirectionalSymmetryCalculator dsCalculator = new OnlineDirectionalSymmetryCalculator();
+      dsCalculator.Add(startValue, actualContinuation, predictedContinuation);
+      errorState = dsCalculator.ErrorState;
+      return dsCalculator.DirectionalSymmetry;
+    }
+    
+    public static double Calculate(IEnumerable<double> startValues, IEnumerable<IEnumerable<double>> actualContinuations, IEnumerable<IEnumerable<double>> predictedContinuations, out OnlineCalculatorError errorState) {
+      IEnumerator<double> startValueEnumerator = startValues.GetEnumerator();
+      IEnumerator<IEnumerable<double>> actualContinuationsEnumerator = actualContinuations.GetEnumerator();
+      IEnumerator<IEnumerable<double>> predictedContinuationsEnumerator = predictedContinuations.GetEnumerator();
+      OnlineDirectionalSymmetryCalculator dsCalculator = new OnlineDirectionalSymmetryCalculator();
+
+      // always move forward all enumerators (do not use short-circuit evaluation!)
+      while (startValueEnumerator.MoveNext() & actualContinuationsEnumerator.MoveNext() & predictedContinuationsEnumerator.MoveNext()) {
+        dsCalculator.Add(startValueEnumerator.Current, actualContinuationsEnumerator.Current, predictedContinuationsEnumerator.Current);
+        if (dsCalculator.ErrorState != OnlineCalculatorError.None) break;
+      }
+
+      // check if all enumerators are at the end to make sure both enumerations have the same length
+      if (dsCalculator.ErrorState == OnlineCalculatorError.None &&
+          (startValueEnumerator.MoveNext() || actualContinuationsEnumerator.MoveNext() || predictedContinuationsEnumerator.MoveNext())) {
+        throw new ArgumentException("Number of elements in startValues, actualContinuations and estimatedValues predictedContinuations doesn't match.");
+      } else {
+        errorState = dsCalculator.ErrorState;
+        return dsCalculator.DirectionalSymmetry;
+      }
+    }
+  }
+}
Index: branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineLinearScalingParameterCalculator.cs
===================================================================
--- branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineLinearScalingParameterCalculator.cs	(revision 9073)
+++ branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineLinearScalingParameterCalculator.cs	(revision 9073)
@@ -0,0 +1,120 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using HeuristicLab.Common;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  public class OnlineLinearScalingParameterCalculator {
+
+    /// <summary>
+    /// Additive constant
+    /// </summary>
+    public double Alpha {
+      get {
+        return targetMeanCalculator.Mean - Beta * originalMeanAndVarianceCalculator.Mean;
+      }
+    }
+
+    /// <summary>
+    /// Multiplicative factor
+    /// </summary>
+    public double Beta {
+      get {
+        if (originalMeanAndVarianceCalculator.PopulationVariance.IsAlmost(0.0))
+          return 1;
+        else
+          return originalTargetCovarianceCalculator.Covariance / originalMeanAndVarianceCalculator.PopulationVariance;
+      }
+    }
+
+    public OnlineCalculatorError ErrorState {
+      get {
+        return targetMeanCalculator.MeanErrorState | originalMeanAndVarianceCalculator.MeanErrorState |
+          originalMeanAndVarianceCalculator.PopulationVarianceErrorState | originalTargetCovarianceCalculator.ErrorState;
+      }
+    }
+
+    private OnlineMeanAndVarianceCalculator targetMeanCalculator;
+    private OnlineMeanAndVarianceCalculator originalMeanAndVarianceCalculator;
+    private OnlineCovarianceCalculator originalTargetCovarianceCalculator;
+
+    public OnlineLinearScalingParameterCalculator() {
+      targetMeanCalculator = new OnlineMeanAndVarianceCalculator();
+      originalMeanAndVarianceCalculator = new OnlineMeanAndVarianceCalculator();
+      originalTargetCovarianceCalculator = new OnlineCovarianceCalculator();
+      Reset();
+    }
+
+    public void Reset() {
+      targetMeanCalculator.Reset();
+      originalMeanAndVarianceCalculator.Reset();
+      originalTargetCovarianceCalculator.Reset();
+    }
+
+    /// <summary>
+    /// Calculates linear scaling parameters in one pass.
+    /// The formulas to calculate the scaling parameters were taken from Scaled Symblic Regression by Maarten Keijzer.
+    /// http://www.springerlink.com/content/x035121165125175/
+    /// </summary>
+    public void Add(double original, double target) {
+      // validity of values is checked in mean calculator and covariance calculator
+      targetMeanCalculator.Add(target);
+      originalMeanAndVarianceCalculator.Add(original);
+      originalTargetCovarianceCalculator.Add(original, target);
+
+    }
+
+    /// <summary>
+    /// Calculates alpha and beta parameters to linearly scale elements of original to the scale and location of target
+    /// original[i] * beta + alpha
+    /// </summary>
+    /// <param name="original">Values that should be scaled</param>
+    /// <param name="target">Target values to which the original values should be scaled</param>
+    /// <param name="alpha">Additive constant for the linear scaling</param>
+    /// <param name="beta">Multiplicative factor for the linear scaling</param>
+    /// <param name="errorState">Flag that indicates if errors occurred in the calculation of the linea scaling parameters.</param>
+    public static void Calculate(IEnumerable<double> original, IEnumerable<double> target, out double alpha, out double beta, out OnlineCalculatorError errorState) {
+      OnlineLinearScalingParameterCalculator calculator = new OnlineLinearScalingParameterCalculator();
+      IEnumerator<double> originalEnumerator = original.GetEnumerator();
+      IEnumerator<double> targetEnumerator = target.GetEnumerator();
+
+      // always move forward both enumerators (do not use short-circuit evaluation!)
+      while (originalEnumerator.MoveNext() & targetEnumerator.MoveNext()) {
+        double originalElement = originalEnumerator.Current;
+        double targetElement = targetEnumerator.Current;
+        calculator.Add(originalElement, targetElement);
+        if (calculator.ErrorState != OnlineCalculatorError.None) break;
+      }
+
+      // check if both enumerators are at the end to make sure both enumerations have the same length
+      if (calculator.ErrorState == OnlineCalculatorError.None &&
+            (originalEnumerator.MoveNext() || targetEnumerator.MoveNext())) {
+        throw new ArgumentException("Number of elements in original and target enumeration do not match.");
+      } else {
+        errorState = calculator.ErrorState;
+        alpha = calculator.Alpha;
+        beta = calculator.Beta;
+      }
+    }
+  }
+}
Index: branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineMaxAbsoluteErrorCalculator.cs
===================================================================
--- branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineMaxAbsoluteErrorCalculator.cs	(revision 9073)
+++ branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineMaxAbsoluteErrorCalculator.cs	(revision 9073)
@@ -0,0 +1,91 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  public class OnlineMaxAbsoluteErrorCalculator : IOnlineCalculator {
+
+    private double mae;
+    private int n;
+    public double MaxAbsoluteError {
+      get {
+        return n > 0 ? mae : 0.0;
+      }
+    }
+
+    public OnlineMaxAbsoluteErrorCalculator() {
+      Reset();
+    }
+
+    #region IOnlineCalculator Members
+    private OnlineCalculatorError errorState;
+    public OnlineCalculatorError ErrorState {
+      get { return errorState; }
+    }
+    public double Value {
+      get { return MaxAbsoluteError; }
+    }
+    public void Reset() {
+      n = 0;
+      mae = double.MinValue;
+      errorState = OnlineCalculatorError.InsufficientElementsAdded;
+    }
+
+    public void Add(double original, double estimated) {
+      if (double.IsNaN(estimated) || double.IsInfinity(estimated) ||
+          double.IsNaN(original) || double.IsInfinity(original) || (errorState & OnlineCalculatorError.InvalidValueAdded) > 0) {
+        errorState = errorState | OnlineCalculatorError.InvalidValueAdded;
+      } else {
+        double error = Math.Abs(estimated - original);
+        if (error > mae)
+          mae = error;
+        n++;
+        errorState = errorState & (~OnlineCalculatorError.InsufficientElementsAdded);        // n >= 1
+      }
+    }
+    #endregion
+
+    public static double Calculate(IEnumerable<double> originalValues, IEnumerable<double> estimatedValues, out OnlineCalculatorError errorState) {
+      IEnumerator<double> originalEnumerator = originalValues.GetEnumerator();
+      IEnumerator<double> estimatedEnumerator = estimatedValues.GetEnumerator();
+      OnlineMaxAbsoluteErrorCalculator maeCalculator = new OnlineMaxAbsoluteErrorCalculator();
+
+      // always move forward both enumerators (do not use short-circuit evaluation!)
+      while (originalEnumerator.MoveNext() & estimatedEnumerator.MoveNext()) {
+        double original = originalEnumerator.Current;
+        double estimated = estimatedEnumerator.Current;
+        maeCalculator.Add(original, estimated);
+        if (maeCalculator.ErrorState != OnlineCalculatorError.None) break;
+      }
+
+      // check if both enumerators are at the end to make sure both enumerations have the same length
+      if (maeCalculator.ErrorState == OnlineCalculatorError.None &&
+         (estimatedEnumerator.MoveNext() || originalEnumerator.MoveNext())) {
+        throw new ArgumentException("Number of elements in originalValues and estimatedValues enumerations doesn't match.");
+      } else {
+        errorState = maeCalculator.ErrorState;
+        return maeCalculator.MaxAbsoluteError;
+      }
+    }
+  }
+}
Index: branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineMeanAbsoluteErrorCalculator.cs
===================================================================
--- branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineMeanAbsoluteErrorCalculator.cs	(revision 9073)
+++ branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineMeanAbsoluteErrorCalculator.cs	(revision 9073)
@@ -0,0 +1,90 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  public class OnlineMeanAbsoluteErrorCalculator : IOnlineCalculator {
+
+    private double sae;
+    private int n;
+    public double MeanAbsoluteError {
+      get {
+        return n > 0 ? sae / n : 0.0;
+      }
+    }
+
+    public OnlineMeanAbsoluteErrorCalculator() {
+      Reset();
+    }
+
+    #region IOnlineCalculator Members
+    private OnlineCalculatorError errorState;
+    public OnlineCalculatorError ErrorState {
+      get { return errorState; }
+    }
+    public double Value {
+      get { return MeanAbsoluteError; }
+    }
+    public void Reset() {
+      n = 0;
+      sae = 0.0;
+      errorState = OnlineCalculatorError.InsufficientElementsAdded;
+    }
+
+    public void Add(double original, double estimated) {
+      if (double.IsNaN(estimated) || double.IsInfinity(estimated) ||
+          double.IsNaN(original) || double.IsInfinity(original) || (errorState & OnlineCalculatorError.InvalidValueAdded) > 0) {
+        errorState = errorState | OnlineCalculatorError.InvalidValueAdded;
+      } else {
+        double error = estimated - original;
+        sae += Math.Abs(error);
+        n++;
+        errorState = errorState & (~OnlineCalculatorError.InsufficientElementsAdded);        // n >= 1
+      }
+    }
+    #endregion
+
+    public static double Calculate(IEnumerable<double> originalValues, IEnumerable<double> estimatedValues, out OnlineCalculatorError errorState) {
+      IEnumerator<double> originalEnumerator = originalValues.GetEnumerator();
+      IEnumerator<double> estimatedEnumerator = estimatedValues.GetEnumerator();
+      OnlineMeanAbsoluteErrorCalculator maeCalculator = new OnlineMeanAbsoluteErrorCalculator();
+
+      // always move forward both enumerators (do not use short-circuit evaluation!)
+      while (originalEnumerator.MoveNext() & estimatedEnumerator.MoveNext()) {
+        double original = originalEnumerator.Current;
+        double estimated = estimatedEnumerator.Current;
+        maeCalculator.Add(original, estimated);
+        if (maeCalculator.ErrorState != OnlineCalculatorError.None) break;
+      }
+
+      // check if both enumerators are at the end to make sure both enumerations have the same length
+      if (maeCalculator.ErrorState == OnlineCalculatorError.None &&
+         (estimatedEnumerator.MoveNext() || originalEnumerator.MoveNext())) {
+        throw new ArgumentException("Number of elements in originalValues and estimatedValues enumerations doesn't match.");
+      } else {
+        errorState = maeCalculator.ErrorState;
+        return maeCalculator.MeanAbsoluteError;
+      }
+    }
+  }
+}
Index: branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineMeanAbsolutePercentageErrorCalculator.cs
===================================================================
--- branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineMeanAbsolutePercentageErrorCalculator.cs	(revision 9073)
+++ branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineMeanAbsolutePercentageErrorCalculator.cs	(revision 9073)
@@ -0,0 +1,92 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using HeuristicLab.Common;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  public class OnlineMeanAbsolutePercentageErrorCalculator : IOnlineCalculator {
+
+    private double sre;
+    private int n;
+    public double MeanAbsolutePercentageError {
+      get {
+        return n > 0 ? sre / n : 0.0;
+      }
+    }
+
+    public OnlineMeanAbsolutePercentageErrorCalculator() {
+      Reset();
+    }
+
+    #region IOnlineCalculator Members
+    private OnlineCalculatorError errorState;
+    public OnlineCalculatorError ErrorState {
+      get { return errorState; }
+    }
+    public double Value {
+      get { return MeanAbsolutePercentageError; }
+    }
+    public void Reset() {
+      n = 0;
+      sre = 0.0;
+      errorState = OnlineCalculatorError.InsufficientElementsAdded;
+    }
+
+    public void Add(double original, double estimated) {
+      if (double.IsNaN(estimated) || double.IsInfinity(estimated) ||
+          double.IsNaN(original) || double.IsInfinity(original) ||
+        original.IsAlmost(0.0)) {
+        errorState = errorState | OnlineCalculatorError.InvalidValueAdded;
+      } else {
+        sre += Math.Abs((estimated - original) / original);
+        n++;
+        errorState = errorState & (~OnlineCalculatorError.InsufficientElementsAdded);        // n >= 1
+      }
+    }
+
+    #endregion
+
+    public static double Calculate(IEnumerable<double> originalValues, IEnumerable<double> estimatedValues, out OnlineCalculatorError errorState) {
+      IEnumerator<double> originalEnumerator = originalValues.GetEnumerator();
+      IEnumerator<double> estimatedEnumerator = estimatedValues.GetEnumerator();
+      OnlineMeanAbsolutePercentageErrorCalculator calculator = new OnlineMeanAbsolutePercentageErrorCalculator();
+
+      // always move forward both enumerators (do not use short-circuit evaluation!)
+      while (originalEnumerator.MoveNext() & estimatedEnumerator.MoveNext()) {
+        double original = originalEnumerator.Current;
+        double estimated = estimatedEnumerator.Current;
+        calculator.Add(original, estimated);
+        if (calculator.ErrorState != OnlineCalculatorError.None) break;
+      }
+
+      // check if both enumerators are at the end to make sure both enumerations have the same length
+      if (calculator.ErrorState == OnlineCalculatorError.None &&
+            (estimatedEnumerator.MoveNext() || originalEnumerator.MoveNext())) {
+        throw new ArgumentException("Number of elements in originalValues and second estimatedValues doesn't match.");
+      } else {
+        errorState = calculator.ErrorState;
+        return calculator.MeanAbsolutePercentageError;
+      }
+    }
+  }
+}
Index: branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineMeanAndVarianceCalculator.cs
===================================================================
--- branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineMeanAndVarianceCalculator.cs	(revision 9073)
+++ branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineMeanAndVarianceCalculator.cs	(revision 9073)
@@ -0,0 +1,109 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Collections.Generic;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  public class OnlineMeanAndVarianceCalculator {
+
+    private double m_oldM, m_newM, m_oldS, m_newS;
+    private int n;
+
+    private OnlineCalculatorError varianceErrorState;
+    public OnlineCalculatorError VarianceErrorState {
+      get { return varianceErrorState; }
+    }
+
+    public double Variance {
+      get {
+        return (n > 1) ? m_newS / (n - 1) : 0.0;
+      }
+    }
+
+    private OnlineCalculatorError errorState;
+    public OnlineCalculatorError PopulationVarianceErrorState {
+      get { return errorState; }
+    }
+    public double PopulationVariance {
+      get {
+        return (n > 0) ? m_newS / n : 0.0;
+      }
+    }
+
+    public OnlineCalculatorError MeanErrorState {
+      get { return errorState; }
+    }
+    public double Mean {
+      get {
+        return (n > 0) ? m_newM : 0.0;
+      }
+    }
+
+    public int Count {
+      get { return n; }
+    }
+
+    public OnlineMeanAndVarianceCalculator() {
+      Reset();
+    }
+
+    public void Reset() {
+      n = 0;
+      errorState = OnlineCalculatorError.InsufficientElementsAdded;
+      varianceErrorState = OnlineCalculatorError.InsufficientElementsAdded;
+    }
+
+    public void Add(double x) {
+      if (double.IsNaN(x) || double.IsInfinity(x) || x > 1E13 || x < -1E13 || (errorState & OnlineCalculatorError.InvalidValueAdded) > 0) {
+        errorState = errorState | OnlineCalculatorError.InvalidValueAdded;
+        varianceErrorState = errorState | OnlineCalculatorError.InvalidValueAdded;
+      } else {
+        n++;
+        // See Knuth TAOCP vol 2, 3rd edition, page 232
+        if (n == 1) {
+          m_oldM = m_newM = x;
+          m_oldS = 0.0;
+          errorState = errorState & (~OnlineCalculatorError.InsufficientElementsAdded);        // n >= 1
+        } else {
+
+          varianceErrorState = varianceErrorState & (~OnlineCalculatorError.InsufficientElementsAdded);        // n >= 2
+          m_newM = m_oldM + (x - m_oldM) / n;
+          m_newS = m_oldS + (x - m_oldM) * (x - m_newM);
+
+          // set up for next iteration
+          m_oldM = m_newM;
+          m_oldS = m_newS;
+        }
+      }
+    }
+
+    public static void Calculate(IEnumerable<double> x, out double mean, out double variance, out OnlineCalculatorError meanErrorState, out OnlineCalculatorError varianceErrorState) {
+      OnlineMeanAndVarianceCalculator meanAndVarianceCalculator = new OnlineMeanAndVarianceCalculator();
+      foreach (double xi in x) {
+        meanAndVarianceCalculator.Add(xi);
+      }
+      mean = meanAndVarianceCalculator.Mean;
+      variance = meanAndVarianceCalculator.Variance;
+      meanErrorState = meanAndVarianceCalculator.MeanErrorState;
+      varianceErrorState = meanAndVarianceCalculator.VarianceErrorState;
+    }
+  }
+}
Index: branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineMeanErrorCalculator.cs
===================================================================
--- branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineMeanErrorCalculator.cs	(revision 9073)
+++ branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineMeanErrorCalculator.cs	(revision 9073)
@@ -0,0 +1,77 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  public class OnlineMeanErrorCalculator : IOnlineCalculator {
+
+    private readonly OnlineMeanAndVarianceCalculator meanAndVarianceCalculator;
+    public double MeanError {
+      get { return meanAndVarianceCalculator.Mean; }
+    }
+
+    public OnlineMeanErrorCalculator() {
+      meanAndVarianceCalculator = new OnlineMeanAndVarianceCalculator();
+      Reset();
+    }
+
+    #region IOnlineCalculator Members
+    public OnlineCalculatorError ErrorState {
+      get { return meanAndVarianceCalculator.MeanErrorState; }
+    }
+    public double Value {
+      get { return MeanError; }
+    }
+    public void Reset() {
+      meanAndVarianceCalculator.Reset();
+    }
+
+    public void Add(double original, double estimated) {
+      meanAndVarianceCalculator.Add(estimated - original);
+    }
+    #endregion
+
+    public static double Calculate(IEnumerable<double> originalValues, IEnumerable<double> estimatedValues, out OnlineCalculatorError errorState) {
+      IEnumerator<double> originalEnumerator = originalValues.GetEnumerator();
+      IEnumerator<double> estimatedEnumerator = estimatedValues.GetEnumerator();
+      OnlineMeanErrorCalculator meCalculator = new OnlineMeanErrorCalculator();
+
+      // always move forward both enumerators (do not use short-circuit evaluation!)
+      while (originalEnumerator.MoveNext() & estimatedEnumerator.MoveNext()) {
+        double original = originalEnumerator.Current;
+        double estimated = estimatedEnumerator.Current;
+        meCalculator.Add(original, estimated);
+        if (meCalculator.ErrorState != OnlineCalculatorError.None) break;
+      }
+
+      // check if both enumerators are at the end to make sure both enumerations have the same length
+      if (meCalculator.ErrorState == OnlineCalculatorError.None &&
+         (estimatedEnumerator.MoveNext() || originalEnumerator.MoveNext())) {
+        throw new ArgumentException("Number of elements in originalValues and estimatedValues enumerations doesn't match.");
+      } else {
+        errorState = meCalculator.ErrorState;
+        return meCalculator.MeanError;
+      }
+    }
+  }
+}
Index: branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineMeanSquaredErrorCalculator.cs
===================================================================
--- branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineMeanSquaredErrorCalculator.cs	(revision 9073)
+++ branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineMeanSquaredErrorCalculator.cs	(revision 9073)
@@ -0,0 +1,90 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  public class OnlineMeanSquaredErrorCalculator : IOnlineCalculator {
+
+    private double sse;
+    private int n;
+    public double MeanSquaredError {
+      get {
+        return n > 0 ? sse / n : 0.0;
+      }
+    }
+
+    public OnlineMeanSquaredErrorCalculator() {
+      Reset();
+    }
+
+    #region IOnlineCalculator Members
+    private OnlineCalculatorError errorState;
+    public OnlineCalculatorError ErrorState {
+      get { return errorState; }
+    }
+    public double Value {
+      get { return MeanSquaredError; }
+    }
+    public void Reset() {
+      n = 0;
+      sse = 0.0;
+      errorState = OnlineCalculatorError.InsufficientElementsAdded;
+    }
+
+    public void Add(double original, double estimated) {
+      if (double.IsNaN(estimated) || double.IsInfinity(estimated) ||
+          double.IsNaN(original) || double.IsInfinity(original) || (errorState & OnlineCalculatorError.InvalidValueAdded) > 0) {
+        errorState = errorState | OnlineCalculatorError.InvalidValueAdded;
+      } else {
+        double error = estimated - original;
+        sse += error * error;
+        n++;
+        errorState = errorState & (~OnlineCalculatorError.InsufficientElementsAdded);        // n >= 1
+      }
+    }
+    #endregion
+
+    public static double Calculate(IEnumerable<double> originalValues, IEnumerable<double> estimatedValues, out OnlineCalculatorError errorState) {
+      IEnumerator<double> originalEnumerator = originalValues.GetEnumerator();
+      IEnumerator<double> estimatedEnumerator = estimatedValues.GetEnumerator();
+      OnlineMeanSquaredErrorCalculator mseCalculator = new OnlineMeanSquaredErrorCalculator();
+
+      // always move forward both enumerators (do not use short-circuit evaluation!)
+      while (originalEnumerator.MoveNext() & estimatedEnumerator.MoveNext()) {
+        double original = originalEnumerator.Current;
+        double estimated = estimatedEnumerator.Current;
+        mseCalculator.Add(original, estimated);
+        if (mseCalculator.ErrorState != OnlineCalculatorError.None) break;
+      }
+
+      // check if both enumerators are at the end to make sure both enumerations have the same length
+      if (mseCalculator.ErrorState == OnlineCalculatorError.None &&
+         (estimatedEnumerator.MoveNext() || originalEnumerator.MoveNext())) {
+        throw new ArgumentException("Number of elements in originalValues and estimatedValues enumerations doesn't match.");
+      } else {
+        errorState = mseCalculator.ErrorState;
+        return mseCalculator.MeanSquaredError;
+      }
+    }
+  }
+}
Index: branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineNormalizedMeanSquaredErrorCalculator.cs
===================================================================
--- branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineNormalizedMeanSquaredErrorCalculator.cs	(revision 9073)
+++ branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineNormalizedMeanSquaredErrorCalculator.cs	(revision 9073)
@@ -0,0 +1,95 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  public class OnlineNormalizedMeanSquaredErrorCalculator : IOnlineCalculator {
+    private OnlineMeanAndVarianceCalculator meanSquaredErrorCalculator;
+    private OnlineMeanAndVarianceCalculator originalVarianceCalculator;
+
+    public double NormalizedMeanSquaredError {
+      get {
+        double var = originalVarianceCalculator.Variance;
+        double m = meanSquaredErrorCalculator.Mean;
+        return var > 0 ? m / var : 0.0;
+      }
+    }
+
+    public OnlineNormalizedMeanSquaredErrorCalculator() {
+      meanSquaredErrorCalculator = new OnlineMeanAndVarianceCalculator();
+      originalVarianceCalculator = new OnlineMeanAndVarianceCalculator();
+      Reset();
+    }
+
+    #region IOnlineCalculator Members
+    public OnlineCalculatorError ErrorState {
+      get { return meanSquaredErrorCalculator.MeanErrorState | originalVarianceCalculator.VarianceErrorState; }
+    }
+    public double Value {
+      get { return NormalizedMeanSquaredError; }
+    }
+
+    public void Reset() {
+      meanSquaredErrorCalculator.Reset();
+      originalVarianceCalculator.Reset();
+    }
+
+    public void Add(double original, double estimated) {
+      // no need to check for validity of values explicitly as it is checked in the meanAndVariance calculator anyway
+      double error = estimated - original;
+      meanSquaredErrorCalculator.Add(error * error);
+      originalVarianceCalculator.Add(original);
+    }
+    #endregion
+
+    public static double Calculate(IEnumerable<double> originalValues, IEnumerable<double> estimatedValues, out OnlineCalculatorError errorState) {
+      IEnumerator<double> originalEnumerator = originalValues.GetEnumerator();
+      IEnumerator<double> estimatedEnumerator = estimatedValues.GetEnumerator();
+      OnlineNormalizedMeanSquaredErrorCalculator normalizedMSECalculator = new OnlineNormalizedMeanSquaredErrorCalculator();
+
+      //needed because otherwise the normalizedMSECalculator is in ErrorState.InsufficientValuesAdded
+      if (originalEnumerator.MoveNext() & estimatedEnumerator.MoveNext()) {
+        double original = originalEnumerator.Current;
+        double estimated = estimatedEnumerator.Current;
+        normalizedMSECalculator.Add(original, estimated);
+      }
+
+      // always move forward both enumerators (do not use short-circuit evaluation!)
+      while (originalEnumerator.MoveNext() & estimatedEnumerator.MoveNext()) {
+        double original = originalEnumerator.Current;
+        double estimated = estimatedEnumerator.Current;
+        normalizedMSECalculator.Add(original, estimated);
+        if (normalizedMSECalculator.ErrorState != OnlineCalculatorError.None) break;
+      }
+
+      // check if both enumerators are at the end to make sure both enumerations have the same length
+      if (normalizedMSECalculator.ErrorState == OnlineCalculatorError.None &&
+           (estimatedEnumerator.MoveNext() || originalEnumerator.MoveNext())) {
+        throw new ArgumentException("Number of elements in originalValues and estimatedValues enumeration doesn't match.");
+      } else {
+        errorState = normalizedMSECalculator.ErrorState;
+        return normalizedMSECalculator.NormalizedMeanSquaredError;
+      }
+    }
+  }
+}
Index: branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlinePearsonsRSquaredCalculator.cs
===================================================================
--- branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlinePearsonsRSquaredCalculator.cs	(revision 9073)
+++ branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlinePearsonsRSquaredCalculator.cs	(revision 9073)
@@ -0,0 +1,92 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using HeuristicLab.Common;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  public class OnlinePearsonsRSquaredCalculator : IOnlineCalculator {
+    private OnlineCovarianceCalculator covCalculator = new OnlineCovarianceCalculator();
+    private OnlineMeanAndVarianceCalculator sxCalculator = new OnlineMeanAndVarianceCalculator();
+    private OnlineMeanAndVarianceCalculator syCalculator = new OnlineMeanAndVarianceCalculator();
+
+    public double RSquared {
+      get {
+        double xVar = sxCalculator.PopulationVariance;
+        double yVar = syCalculator.PopulationVariance;
+        if (xVar.IsAlmost(0.0) || yVar.IsAlmost(0.0)) {
+          return 0.0;
+        } else {
+          double r = covCalculator.Covariance / (Math.Sqrt(xVar) * Math.Sqrt(yVar));
+          return r * r;
+        }
+      }
+    }
+
+    public OnlinePearsonsRSquaredCalculator() { }
+
+    #region IOnlineCalculator Members
+    public OnlineCalculatorError ErrorState {
+      get { return covCalculator.ErrorState | sxCalculator.PopulationVarianceErrorState | syCalculator.PopulationVarianceErrorState; }
+    }
+    public double Value {
+      get { return RSquared; }
+    }
+    public void Reset() {
+      covCalculator.Reset();
+      sxCalculator.Reset();
+      syCalculator.Reset();
+    }
+
+    public void Add(double x, double y) {
+      // no need to check validity of values explicitly here as it is checked in all three evaluators 
+      covCalculator.Add(x, y);
+      sxCalculator.Add(x);
+      syCalculator.Add(y);
+    }
+
+    #endregion
+
+    public static double Calculate(IEnumerable<double> first, IEnumerable<double> second, out OnlineCalculatorError errorState) {
+      IEnumerator<double> firstEnumerator = first.GetEnumerator();
+      IEnumerator<double> secondEnumerator = second.GetEnumerator();
+      OnlinePearsonsRSquaredCalculator rSquaredCalculator = new OnlinePearsonsRSquaredCalculator();
+
+      // always move forward both enumerators (do not use short-circuit evaluation!)
+      while (firstEnumerator.MoveNext() & secondEnumerator.MoveNext()) {
+        double original = firstEnumerator.Current;
+        double estimated = secondEnumerator.Current;
+        rSquaredCalculator.Add(original, estimated);
+        if (rSquaredCalculator.ErrorState != OnlineCalculatorError.None) break;
+      }
+
+      // check if both enumerators are at the end to make sure both enumerations have the same length
+      if (rSquaredCalculator.ErrorState == OnlineCalculatorError.None &&
+           (secondEnumerator.MoveNext() || firstEnumerator.MoveNext())) {
+        throw new ArgumentException("Number of elements in first and second enumeration doesn't match.");
+      } else {
+        errorState = rSquaredCalculator.ErrorState;
+        return rSquaredCalculator.RSquared;
+      }
+    }
+  }
+}
Index: branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineTheilsUStatisticCalculator.cs
===================================================================
--- branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineTheilsUStatisticCalculator.cs	(revision 9073)
+++ branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineTheilsUStatisticCalculator.cs	(revision 9073)
@@ -0,0 +1,128 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2011 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  public class OnlineTheilsUStatisticCalculator : IOnlineTimeSeriesCalculator {
+    private OnlineMeanAndVarianceCalculator squaredErrorMeanCalculator;
+    private OnlineMeanAndVarianceCalculator unbiasedEstimatorMeanCalculator;
+
+    public double TheilsUStatistic {
+      get {
+        return Math.Sqrt(squaredErrorMeanCalculator.Mean) / Math.Sqrt(unbiasedEstimatorMeanCalculator.Mean);
+      }
+    }
+
+    private OnlineCalculatorError errorState;
+    public OnlineCalculatorError ErrorState {
+      get { return errorState | squaredErrorMeanCalculator.MeanErrorState | unbiasedEstimatorMeanCalculator.MeanErrorState; }
+    }
+
+    public OnlineTheilsUStatisticCalculator() {
+      squaredErrorMeanCalculator = new OnlineMeanAndVarianceCalculator();
+      unbiasedEstimatorMeanCalculator = new OnlineMeanAndVarianceCalculator();
+      Reset();
+    }
+
+    #region IOnlineEvaluator Members
+    public double Value {
+      get { return TheilsUStatistic; }
+    }
+
+    public void Add(double startValue, IEnumerable<double> actualContinuation, IEnumerable<double> predictedContinuation) {
+      throw new NotSupportedException();
+    }
+
+    public void Add(double startValue, IEnumerable<double> actualContinuation, IEnumerable<double> referenceContinuation, IEnumerable<double> predictedContinuation) {
+      if (double.IsNaN(startValue) || (errorState & OnlineCalculatorError.InvalidValueAdded) > 0) {
+        errorState = errorState | OnlineCalculatorError.InvalidValueAdded;
+      } else {
+        var actualEnumerator = actualContinuation.GetEnumerator();
+        var predictedEnumerator = predictedContinuation.GetEnumerator();
+        var referenceEnumerator = referenceContinuation.GetEnumerator();
+        while (actualEnumerator.MoveNext() & predictedEnumerator.MoveNext() & referenceEnumerator.MoveNext()
+          & ErrorState != OnlineCalculatorError.InvalidValueAdded) {
+          double actual = actualEnumerator.Current;
+          double predicted = predictedEnumerator.Current;
+          double reference = referenceEnumerator.Current;
+          if (double.IsNaN(actual) || double.IsNaN(predicted) || double.IsNaN(reference)) {
+            errorState = errorState | OnlineCalculatorError.InvalidValueAdded;
+          } else {
+            // error of predicted change
+            double errorPredictedChange = (predicted - startValue) - (actual - startValue);
+            squaredErrorMeanCalculator.Add(errorPredictedChange * errorPredictedChange);
+
+            double errorReference = (reference - startValue) - (actual - startValue);
+            unbiasedEstimatorMeanCalculator.Add(errorReference * errorReference);
+          }
+        }
+        // check if both enumerators are at the end to make sure both enumerations have the same length
+        if (actualEnumerator.MoveNext() || predictedEnumerator.MoveNext() || referenceEnumerator.MoveNext()) {
+          errorState = errorState | OnlineCalculatorError.InvalidValueAdded;
+        } else {
+          errorState = errorState & (~OnlineCalculatorError.InsufficientElementsAdded); // n >= 1
+        }
+      }
+    }
+
+
+    public void Reset() {
+      squaredErrorMeanCalculator.Reset();
+      unbiasedEstimatorMeanCalculator.Reset();
+      errorState = OnlineCalculatorError.InsufficientElementsAdded;
+    }
+
+    #endregion
+
+    public static double Calculate(double startValue, IEnumerable<double> actualContinuation, IEnumerable<double> referenceContinuation, IEnumerable<double> predictedContinuation, out OnlineCalculatorError errorState) {
+      OnlineTheilsUStatisticCalculator calculator = new OnlineTheilsUStatisticCalculator();
+      calculator.Add(startValue, actualContinuation, referenceContinuation, predictedContinuation);
+      errorState = calculator.ErrorState;
+      return calculator.TheilsUStatistic;
+    }
+
+    public static double Calculate(IEnumerable<double> startValues, IEnumerable<IEnumerable<double>> actualContinuations, IEnumerable<IEnumerable<double>> referenceContinuations, IEnumerable<IEnumerable<double>> predictedContinuations, out OnlineCalculatorError errorState) {
+      IEnumerator<double> startValueEnumerator = startValues.GetEnumerator();
+      IEnumerator<IEnumerable<double>> actualContinuationsEnumerator = actualContinuations.GetEnumerator();
+      IEnumerator<IEnumerable<double>> referenceContinuationsEnumerator = referenceContinuations.GetEnumerator();
+      IEnumerator<IEnumerable<double>> predictedContinuationsEnumerator = predictedContinuations.GetEnumerator();
+
+      OnlineTheilsUStatisticCalculator calculator = new OnlineTheilsUStatisticCalculator();
+
+      // always move forward all enumerators (do not use short-circuit evaluation!)
+      while (startValueEnumerator.MoveNext() & actualContinuationsEnumerator.MoveNext() & referenceContinuationsEnumerator.MoveNext() & predictedContinuationsEnumerator.MoveNext()) {
+        calculator.Add(startValueEnumerator.Current, actualContinuationsEnumerator.Current, referenceContinuationsEnumerator.Current, predictedContinuationsEnumerator.Current);
+        if (calculator.ErrorState != OnlineCalculatorError.None) break;
+      }
+
+      // check if all enumerators are at the end to make sure both enumerations have the same length
+      if (calculator.ErrorState == OnlineCalculatorError.None &&
+          (startValueEnumerator.MoveNext() || actualContinuationsEnumerator.MoveNext() || referenceContinuationsEnumerator.MoveNext() || predictedContinuationsEnumerator.MoveNext())) {
+        throw new ArgumentException("Number of elements in startValues, actualContinuations, referenceContinuation and estimatedValues predictedContinuations doesn't match.");
+      } else {
+        errorState = calculator.ErrorState;
+        return calculator.TheilsUStatistic;
+      }
+    }
+  }
+}
Index: branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineWeightedDirectionalSymmetryCalculator.cs
===================================================================
--- branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineWeightedDirectionalSymmetryCalculator.cs	(revision 9073)
+++ branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineWeightedDirectionalSymmetryCalculator.cs	(revision 9073)
@@ -0,0 +1,121 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2011 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using HeuristicLab.Common;
+
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  public class OnlineWeightedDirectionalSymmetryCalculator : IOnlineTimeSeriesCalculator {
+    private int n;
+    private double correctSum;
+    private double incorrectSum;
+
+    public double WeightedDirectionalSymmetry {
+      get {
+        if (n <= 1) return 0.0;
+        return incorrectSum / correctSum;
+      }
+    }
+
+    public OnlineWeightedDirectionalSymmetryCalculator() {
+      Reset();
+    }
+
+    public double Value {
+      get { return WeightedDirectionalSymmetry; }
+    }
+
+    private OnlineCalculatorError errorState;
+    public OnlineCalculatorError ErrorState {
+      get { return errorState; }
+    }
+
+    public void Add(double startValue, IEnumerable<double> actualContinuation, IEnumerable<double> predictedContinuation) {
+      if (double.IsNaN(startValue) || (errorState & OnlineCalculatorError.InvalidValueAdded) > 0) {
+        errorState = errorState | OnlineCalculatorError.InvalidValueAdded;
+      } else {
+        var actualEnumerator = actualContinuation.GetEnumerator();
+        var predictedEnumerator = predictedContinuation.GetEnumerator();
+        while (actualEnumerator.MoveNext() & predictedEnumerator.MoveNext() & errorState != OnlineCalculatorError.InvalidValueAdded) {
+          double actual = actualEnumerator.Current;
+          double predicted = predictedEnumerator.Current;
+          if (double.IsNaN(actual) || double.IsNaN(predicted)) {
+            errorState = errorState | OnlineCalculatorError.InvalidValueAdded;
+          } else {
+            double err = Math.Abs(actual - predicted);
+            // count as correct only if the trend (positive/negative/no change) is predicted correctly
+            if ((actual - startValue) * (predicted - startValue) > 0.0 ||
+              (actual - startValue).IsAlmost(predicted - startValue)) {
+              correctSum += err;
+            } else {
+              incorrectSum += err;
+            }
+            n++;
+          }
+        }
+        // check if both enumerators are at the end to make sure both enumerations have the same length
+        if (actualEnumerator.MoveNext() || predictedEnumerator.MoveNext()) {
+          errorState = errorState | OnlineCalculatorError.InvalidValueAdded;
+        } else {
+          errorState = errorState & (~OnlineCalculatorError.InsufficientElementsAdded); // n >= 1
+        }
+      }
+    }
+
+    public void Reset() {
+      n = 0;
+      correctSum = 0;
+      incorrectSum = 0;
+      errorState = OnlineCalculatorError.InsufficientElementsAdded;
+    }
+
+    public static double Calculate(double startValue, IEnumerable<double> actualContinuation, IEnumerable<double> predictedContinuation, out OnlineCalculatorError errorState) {
+      OnlineWeightedDirectionalSymmetryCalculator calculator = new OnlineWeightedDirectionalSymmetryCalculator();
+      calculator.Add(startValue, actualContinuation, predictedContinuation);
+      errorState = calculator.ErrorState;
+      return calculator.WeightedDirectionalSymmetry;
+    }
+
+    public static double Calculate(IEnumerable<double> startValues, IEnumerable<IEnumerable<double>> actualContinuations, IEnumerable<IEnumerable<double>> predictedContinuations, out OnlineCalculatorError errorState) {
+      IEnumerator<double> startValueEnumerator = startValues.GetEnumerator();
+      IEnumerator<IEnumerable<double>> actualContinuationsEnumerator = actualContinuations.GetEnumerator();
+      IEnumerator<IEnumerable<double>> predictedContinuationsEnumerator = predictedContinuations.GetEnumerator();
+      OnlineWeightedDirectionalSymmetryCalculator calculator = new OnlineWeightedDirectionalSymmetryCalculator();
+
+      // always move forward all enumerators (do not use short-circuit evaluation!)
+      while (startValueEnumerator.MoveNext() & actualContinuationsEnumerator.MoveNext() & predictedContinuationsEnumerator.MoveNext()) {
+        calculator.Add(startValueEnumerator.Current, actualContinuationsEnumerator.Current, predictedContinuationsEnumerator.Current);
+        if (calculator.ErrorState != OnlineCalculatorError.None) break;
+      }
+
+      // check if all enumerators are at the end to make sure both enumerations have the same length
+      if (calculator.ErrorState == OnlineCalculatorError.None &&
+          (startValueEnumerator.MoveNext() || actualContinuationsEnumerator.MoveNext() || predictedContinuationsEnumerator.MoveNext())) {
+        throw new ArgumentException("Number of elements in startValues, actualContinuations and estimatedValues predictedContinuations doesn't match.");
+      } else {
+        errorState = calculator.ErrorState;
+        return calculator.WeightedDirectionalSymmetry;
+      }
+    }
+  }
+}
Index: branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Plugin.cs.frame
===================================================================
--- branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Plugin.cs.frame	(revision 9073)
+++ branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Plugin.cs.frame	(revision 9073)
@@ -0,0 +1,42 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using HeuristicLab.PluginInfrastructure;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  [Plugin("HeuristicLab.Problems.DataAnalysis","Provides base classes for data analysis tasks.", "3.4.3.$WCREV$")]
+  [PluginFile("HeuristicLab.Problems.DataAnalysis-3.4.dll", PluginFileType.Assembly)]
+  [PluginDependency("HeuristicLab.ALGLIB","3.6")]
+  [PluginDependency("HeuristicLab.Collections", "3.3")]
+  [PluginDependency("HeuristicLab.Common", "3.3")]
+  [PluginDependency("HeuristicLab.Common.Resources", "3.3")]
+  [PluginDependency("HeuristicLab.Core", "3.3")]
+  [PluginDependency("HeuristicLab.Data", "3.3")]
+  [PluginDependency("HeuristicLab.Optimization","3.3")]
+  [PluginDependency("HeuristicLab.Parameters", "3.3")]
+  [PluginDependency("HeuristicLab.Persistence", "3.3")]
+  [PluginDependency("HeuristicLab.Problems.Instances", "3.3")]
+  public class HeuristicLabProblemsDataAnalysisPlugin : PluginBase {
+  }
+}
Index: branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Properties/AssemblyInfo.cs.frame
===================================================================
--- branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Properties/AssemblyInfo.cs.frame	(revision 9073)
+++ branches/ClassificationModelComparison/HeuristicLab.Problems.DataAnalysis/3.4/Properties/AssemblyInfo.cs.frame	(revision 9073)
@@ -0,0 +1,55 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Reflection;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following 
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("HeuristicLab.Problems.DataAnalysis")]
+[assembly: AssemblyDescription("Provides base classes for data analysis tasks.")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("HeuristicLab")]
+[assembly: AssemblyCopyright("(c) 2002-2012 HEAL")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible 
+// to COM components.  If you need to access a type in this assembly from 
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("460C6FC6-FFBB-4286-B781-06D9F56A202D")]
+
+// Version information for an assembly consists of the following four values:
+//
+//      Major Version
+//      Minor Version 
+//      Build Number
+//      Revision
+//
+// You can specify all the values or you can default the Revision and Build Numbers 
+// by using the '*' as shown below:
+[assembly: AssemblyVersion("3.4.0.0")]
+[assembly: AssemblyFileVersion("3.4.3.$WCREV$")]
