Index: branches/DatasetFeatureCorrelation/HeuristicLab.Problems.DataAnalysis/3.4/HeuristicLab.Problems.DataAnalysis-3.4.csproj
===================================================================
--- branches/DatasetFeatureCorrelation/HeuristicLab.Problems.DataAnalysis/3.4/HeuristicLab.Problems.DataAnalysis-3.4.csproj	(revision 8038)
+++ branches/DatasetFeatureCorrelation/HeuristicLab.Problems.DataAnalysis/3.4/HeuristicLab.Problems.DataAnalysis-3.4.csproj	(revision 8276)
@@ -155,4 +155,5 @@
     <Compile Include="Implementation\Clustering\ClusteringProblemData.cs" />
     <Compile Include="Implementation\Clustering\ClusteringSolution.cs" />
+    <Compile Include="Implementation\ExtendedHeatMap.cs" />
     <Compile Include="Implementation\Regression\ConstantRegressionModel.cs" />
     <Compile Include="Implementation\Regression\ConstantRegressionSolution.cs" />
@@ -213,4 +214,5 @@
     <Compile Include="OnlineCalculators\OnlinePearsonsRSquaredCalculator.cs" />
     <Compile Include="Implementation\Regression\RegressionSolution.cs" />
+    <Compile Include="OnlineCalculators\SpearmansRankCorrelationCoefficientCalculator.cs" />
     <Compile Include="Plugin.cs" />
     <Compile Include="Implementation\Classification\ThresholdCalculators\AccuracyMaximizationThresholdCalculator.cs" />
Index: branches/DatasetFeatureCorrelation/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ClassificationEnsembleSolution.cs
===================================================================
--- branches/DatasetFeatureCorrelation/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ClassificationEnsembleSolution.cs	(revision 8038)
+++ branches/DatasetFeatureCorrelation/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ClassificationEnsembleSolution.cs	(revision 8276)
@@ -37,4 +37,7 @@
   [Creatable("Data Analysis - Ensembles")]
   public sealed class ClassificationEnsembleSolution : ClassificationSolution, IClassificationEnsembleSolution {
+    private readonly Dictionary<int, double> trainingEvaluationCache = new Dictionary<int, double>();
+    private readonly Dictionary<int, double> testEvaluationCache = new Dictionary<int, double>();
+
     public new IClassificationEnsembleModel Model {
       get { return (IClassificationEnsembleModel)base.Model; }
@@ -85,4 +88,7 @@
       }
 
+      trainingEvaluationCache = new Dictionary<int, double>(original.ProblemData.TrainingIndices.Count());
+      testEvaluationCache = new Dictionary<int, double>(original.ProblemData.TestIndices.Count());
+
       classificationSolutions = cloner.Clone(original.classificationSolutions);
       RegisterClassificationSolutionsEventHandler();
@@ -128,4 +134,7 @@
       }
 
+      trainingEvaluationCache = new Dictionary<int, double>(problemData.TrainingIndices.Count());
+      testEvaluationCache = new Dictionary<int, double>(problemData.TestIndices.Count());
+
       RegisterClassificationSolutionsEventHandler();
       classificationSolutions.AddRange(solutions);
@@ -148,18 +157,14 @@
     public override IEnumerable<double> EstimatedTrainingClassValues {
       get {
-        var rows = ProblemData.TrainingIndizes;
-        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 RowIsTrainingForModel(currentRow, pair.Model) && !RowIsTestForModel(currentRow, pair.Model)
-                                    select pair.EstimatedValuesEnumerator;
-          yield return AggregateEstimatedClassValues(selectedEnumerators.Select(x => x.Current));
+        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]);
       }
     }
@@ -167,19 +172,31 @@
     public override IEnumerable<double> EstimatedTestClassValues {
       get {
-        var rows = ProblemData.TestIndizes;
-        var estimatedValuesEnumerators = (from model in Model.Models
-                                          select new { Model = model, EstimatedValuesEnumerator = model.GetEstimatedClassValues(ProblemData.Dataset, rows).GetEnumerator() })
-                                         .ToList();
-        var rowsEnumerator = ProblemData.TestIndizes.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 RowIsTestForModel(currentRow, pair.Model)
-                                    select pair.EstimatedValuesEnumerator;
-
-          yield return AggregateEstimatedClassValues(selectedEnumerators.Select(x => x.Current));
+        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));
       }
     }
@@ -196,6 +213,15 @@
 
     public override IEnumerable<double> GetEstimatedClassValues(IEnumerable<int> rows) {
-      return from xs in GetEstimatedClassValueVectors(ProblemData.Dataset, rows)
-             select AggregateEstimatedClassValues(xs);
+      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]);
     }
 
@@ -223,4 +249,8 @@
 
     protected override void OnProblemDataChanged() {
+      trainingEvaluationCache.Clear();
+      testEvaluationCache.Clear();
+      evaluationCache.Clear();
+
       IClassificationProblemData problemData = new ClassificationProblemData(ProblemData.Dataset,
                                                                      ProblemData.AllowedInputVariables,
@@ -251,7 +281,15 @@
     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();
     }
 
@@ -275,4 +313,8 @@
       trainingPartitions[solution.Model] = solution.ProblemData.TrainingPartition;
       testPartitions[solution.Model] = solution.ProblemData.TestPartition;
+
+      trainingEvaluationCache.Clear();
+      testEvaluationCache.Clear();
+      evaluationCache.Clear();
     }
 
@@ -282,4 +324,8 @@
       trainingPartitions.Remove(solution.Model);
       testPartitions.Remove(solution.Model);
+
+      trainingEvaluationCache.Clear();
+      testEvaluationCache.Clear();
+      evaluationCache.Clear();
     }
   }
Index: branches/DatasetFeatureCorrelation/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ClassificationProblemData.cs
===================================================================
--- branches/DatasetFeatureCorrelation/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ClassificationProblemData.cs	(revision 8038)
+++ branches/DatasetFeatureCorrelation/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ClassificationProblemData.cs	(revision 8276)
@@ -207,6 +207,6 @@
 
     #region parameter properties
-    public ConstrainedValueParameter<StringValue> TargetVariableParameter {
-      get { return (ConstrainedValueParameter<StringValue>)Parameters[TargetVariableParameterName]; }
+    public IConstrainedValueParameter<StringValue> TargetVariableParameter {
+      get { return (IConstrainedValueParameter<StringValue>)Parameters[TargetVariableParameterName]; }
     }
     public IFixedValueParameter<StringMatrix> ClassNamesParameter {
Index: branches/DatasetFeatureCorrelation/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ClassificationSolution.cs
===================================================================
--- branches/DatasetFeatureCorrelation/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ClassificationSolution.cs	(revision 8038)
+++ branches/DatasetFeatureCorrelation/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ClassificationSolution.cs	(revision 8276)
@@ -44,5 +44,5 @@
     public ClassificationSolution(IClassificationModel model, IClassificationProblemData problemData)
       : base(model, problemData) {
-      evaluationCache = new Dictionary<int, double>();
+      evaluationCache = new Dictionary<int, double>(problemData.Dataset.Rows);
     }
 
@@ -51,8 +51,8 @@
     }
     public override IEnumerable<double> EstimatedTrainingClassValues {
-      get { return GetEstimatedClassValues(ProblemData.TrainingIndizes); }
+      get { return GetEstimatedClassValues(ProblemData.TrainingIndices); }
     }
     public override IEnumerable<double> EstimatedTestClassValues {
-      get { return GetEstimatedClassValues(ProblemData.TestIndizes); }
+      get { return GetEstimatedClassValues(ProblemData.TestIndices); }
     }
 
Index: branches/DatasetFeatureCorrelation/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ClassificationSolutionBase.cs
===================================================================
--- branches/DatasetFeatureCorrelation/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ClassificationSolutionBase.cs	(revision 8038)
+++ branches/DatasetFeatureCorrelation/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ClassificationSolutionBase.cs	(revision 8276)
@@ -87,7 +87,7 @@
     protected void CalculateResults() {
       double[] estimatedTrainingClassValues = EstimatedTrainingClassValues.ToArray(); // cache values
-      double[] originalTrainingClassValues = ProblemData.Dataset.GetDoubleValues(ProblemData.TargetVariable, ProblemData.TrainingIndizes).ToArray();
+      double[] originalTrainingClassValues = ProblemData.Dataset.GetDoubleValues(ProblemData.TargetVariable, ProblemData.TrainingIndices).ToArray();
       double[] estimatedTestClassValues = EstimatedTestClassValues.ToArray(); // cache values
-      double[] originalTestClassValues = ProblemData.Dataset.GetDoubleValues(ProblemData.TargetVariable, ProblemData.TestIndizes).ToArray();
+      double[] originalTestClassValues = ProblemData.Dataset.GetDoubleValues(ProblemData.TargetVariable, ProblemData.TestIndices).ToArray();
 
       OnlineCalculatorError errorState;
Index: branches/DatasetFeatureCorrelation/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/DiscriminantFunctionClassificationSolution.cs
===================================================================
--- branches/DatasetFeatureCorrelation/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/DiscriminantFunctionClassificationSolution.cs	(revision 8038)
+++ branches/DatasetFeatureCorrelation/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/DiscriminantFunctionClassificationSolution.cs	(revision 8276)
@@ -59,8 +59,8 @@
     }
     public override IEnumerable<double> EstimatedTrainingClassValues {
-      get { return GetEstimatedClassValues(ProblemData.TrainingIndizes); }
+      get { return GetEstimatedClassValues(ProblemData.TrainingIndices); }
     }
     public override IEnumerable<double> EstimatedTestClassValues {
-      get { return GetEstimatedClassValues(ProblemData.TestIndizes); }
+      get { return GetEstimatedClassValues(ProblemData.TestIndices); }
     }
 
@@ -82,8 +82,8 @@
     }
     public override IEnumerable<double> EstimatedTrainingValues {
-      get { return GetEstimatedValues(ProblemData.TrainingIndizes); }
+      get { return GetEstimatedValues(ProblemData.TrainingIndices); }
     }
     public override IEnumerable<double> EstimatedTestValues {
-      get { return GetEstimatedValues(ProblemData.TestIndizes); }
+      get { return GetEstimatedValues(ProblemData.TestIndices); }
     }
 
Index: branches/DatasetFeatureCorrelation/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/DiscriminantFunctionClassificationSolutionBase.cs
===================================================================
--- branches/DatasetFeatureCorrelation/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/DiscriminantFunctionClassificationSolutionBase.cs	(revision 8038)
+++ branches/DatasetFeatureCorrelation/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/DiscriminantFunctionClassificationSolutionBase.cs	(revision 8276)
@@ -103,7 +103,7 @@
     protected void CalculateRegressionResults() {
       double[] estimatedTrainingValues = EstimatedTrainingValues.ToArray(); // cache values
-      double[] originalTrainingValues = ProblemData.Dataset.GetDoubleValues(ProblemData.TargetVariable, ProblemData.TrainingIndizes).ToArray();
+      double[] originalTrainingValues = ProblemData.Dataset.GetDoubleValues(ProblemData.TargetVariable, ProblemData.TrainingIndices).ToArray();
       double[] estimatedTestValues = EstimatedTestValues.ToArray(); // cache values
-      double[] originalTestValues = ProblemData.Dataset.GetDoubleValues(ProblemData.TargetVariable, ProblemData.TestIndizes).ToArray();
+      double[] originalTestValues = ProblemData.Dataset.GetDoubleValues(ProblemData.TargetVariable, ProblemData.TestIndices).ToArray();
 
       OnlineCalculatorError errorState;
@@ -140,5 +140,5 @@
       double[] classValues;
       double[] thresholds;
-      var targetClassValues = ProblemData.Dataset.GetDoubleValues(ProblemData.TargetVariable, ProblemData.TrainingIndizes);
+      var targetClassValues = ProblemData.Dataset.GetDoubleValues(ProblemData.TargetVariable, ProblemData.TrainingIndices);
       AccuracyMaximizationThresholdCalculator.CalculateThresholds(ProblemData, EstimatedTrainingValues, targetClassValues, out classValues, out thresholds);
 
@@ -149,5 +149,5 @@
       double[] classValues;
       double[] thresholds;
-      var targetClassValues = ProblemData.Dataset.GetDoubleValues(ProblemData.TargetVariable, ProblemData.TrainingIndizes);
+      var targetClassValues = ProblemData.Dataset.GetDoubleValues(ProblemData.TargetVariable, ProblemData.TrainingIndices);
       NormalDistributionCutPointsThresholdCalculator.CalculateThresholds(ProblemData, EstimatedTrainingValues, targetClassValues, out classValues, out thresholds);
 
Index: branches/DatasetFeatureCorrelation/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ThresholdCalculators/AccuracyMaximizationThresholdCalculator.cs
===================================================================
--- branches/DatasetFeatureCorrelation/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ThresholdCalculators/AccuracyMaximizationThresholdCalculator.cs	(revision 8038)
+++ branches/DatasetFeatureCorrelation/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ThresholdCalculators/AccuracyMaximizationThresholdCalculator.cs	(revision 8276)
@@ -54,8 +54,9 @@
     public static void CalculateThresholds(IClassificationProblemData problemData, IEnumerable<double> estimatedValues, IEnumerable<double> targetClassValues, out double[] classValues, out double[] thresholds) {
       int slices = 100;
+      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 = (maxEstimatedValue - minEstimatedValue) / slices;
+      double thresholdIncrement = Math.Max((maxEstimatedValue - minEstimatedValue) / slices, minThresholdInc);
       var estimatedAndTargetValuePairs =
         estimatedValuesList.Zip(targetClassValues, (x, y) => new { EstimatedValue = x, TargetClassValue = y })
@@ -70,6 +71,4 @@
 
       // incrementally calculate accuracy of all possible thresholds
-      int[,] confusionMatrix = new int[nClasses, nClasses];
-
       for (int i = 1; i < thresholds.Length; i++) {
         double lowerThreshold = thresholds[i - 1];
Index: branches/DatasetFeatureCorrelation/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Clustering/ClusteringSolution.cs
===================================================================
--- branches/DatasetFeatureCorrelation/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Clustering/ClusteringSolution.cs	(revision 8038)
+++ branches/DatasetFeatureCorrelation/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Clustering/ClusteringSolution.cs	(revision 8276)
@@ -68,5 +68,5 @@
     public virtual IEnumerable<int> TrainingClusterValues {
       get {
-        return GetClusterValues(ProblemData.TrainingIndizes);
+        return GetClusterValues(ProblemData.TrainingIndices);
       }
     }
@@ -74,5 +74,5 @@
     public virtual IEnumerable<int> TestClusterValues {
       get {
-        return GetClusterValues(ProblemData.TestIndizes);
+        return GetClusterValues(ProblemData.TestIndices);
       }
     }
Index: branches/DatasetFeatureCorrelation/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/DataAnalysisProblemData.cs
===================================================================
--- branches/DatasetFeatureCorrelation/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/DataAnalysisProblemData.cs	(revision 8038)
+++ branches/DatasetFeatureCorrelation/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/DataAnalysisProblemData.cs	(revision 8276)
@@ -23,5 +23,4 @@
 using System.Collections.Generic;
 using System.Linq;
-using HeuristicLab.Analysis;
 using HeuristicLab.Collections;
 using HeuristicLab.Common;
@@ -53,6 +52,6 @@
       get { return (IFixedValueParameter<IntRange>)Parameters[TestPartitionParameterName]; }
     }
-    public IFixedValueParameter<HeatMap> DatasetHeatMapParameter {
-      get { return (IFixedValueParameter<HeatMap>)Parameters[DatasetHeatMapParameterName]; }
+    public IFixedValueParameter<ExtendedHeatMap> DatasetHeatMapParameter {
+      get { return (IFixedValueParameter<ExtendedHeatMap>)Parameters[DatasetHeatMapParameterName]; }
     }
     #endregion
@@ -79,9 +78,9 @@
       get { return TestPartitionParameter.Value; }
     }
-    public HeatMap DatasetHeatMap {
+    public ExtendedHeatMap DatasetHeatMap {
       get { return DatasetHeatMapParameter.Value; }
     }
 
-    public virtual IEnumerable<int> TrainingIndizes {
+    public virtual IEnumerable<int> TrainingIndices {
       get {
         return Enumerable.Range(TrainingPartition.Start, Math.Max(0, TrainingPartition.End - TrainingPartition.Start))
@@ -89,5 +88,5 @@
       }
     }
-    public virtual IEnumerable<int> TestIndizes {
+    public virtual IEnumerable<int> TestIndices {
       get {
         return Enumerable.Range(TestPartition.Start, Math.Max(0, TestPartition.End - TestPartition.Start))
@@ -140,26 +139,8 @@
       Parameters.Add(new FixedValueParameter<IntRange>(TrainingPartitionParameterName, "", new IntRange(trainingPartitionStart, trainingPartitionEnd)));
       Parameters.Add(new FixedValueParameter<IntRange>(TestPartitionParameterName, "", new IntRange(testPartitionStart, testPartitionEnd)));
-      Parameters.Add(new FixedValueParameter<HeatMap>(DatasetHeatMapParameterName, "", CalculateHeatMap(dataset)));
+      Parameters.Add(new FixedValueParameter<ExtendedHeatMap>(DatasetHeatMapParameterName, "", new ExtendedHeatMap(this)));
 
       ((ValueParameter<Dataset>)DatasetParameter).ReactOnValueToStringChangedAndValueItemImageChanged = false;
       RegisterEventHandlers();
-    }
-
-    private HeatMap CalculateHeatMap(Dataset dataset) {
-      IList<string> doubleVariableNames = dataset.DoubleVariables.ToList();
-      OnlineCalculatorError error;
-      int length = doubleVariableNames.Count;
-      double[,] elements = new double[length, length];
-
-      for (int i = 0; i < length; i++) {
-        for (int j = 0; j < i + 1; j++) {
-          elements[i, j] = OnlinePearsonsRSquaredCalculator.Calculate(dataset.GetDoubleValues(doubleVariableNames[length - 1 - i]), dataset.GetDoubleValues(doubleVariableNames[j]), out error);
-          elements[j, i] = elements[i, j];
-          if (!error.Equals(OnlineCalculatorError.None)) {
-            throw new ArgumentException("Calculator returned " + error);
-          }
-        }
-      }
-      return new HeatMap(elements, "Hoeffdings Dependence");
     }
 
Index: branches/DatasetFeatureCorrelation/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/ExtendedHeatMap.cs
===================================================================
--- branches/DatasetFeatureCorrelation/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/ExtendedHeatMap.cs	(revision 8276)
+++ branches/DatasetFeatureCorrelation/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/ExtendedHeatMap.cs	(revision 8276)
@@ -0,0 +1,166 @@
+﻿#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.ComponentModel;
+using System.Linq;
+using HeuristicLab.Analysis;
+using HeuristicLab.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.PluginInfrastructure;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  [Item("HeatMap", "Represents a heat map of double values.")]
+  [StorableClass]
+  public class ExtendedHeatMap : HeatMap {
+
+    private IDataAnalysisProblemData problemData;
+
+    private BackgroundWorker bw;
+
+    public delegate void ProgressCalculationHandler(object sender, ProgressChangedEventArgs e);
+    public event ProgressCalculationHandler ProgressCalculation;
+
+    public ExtendedHeatMap()
+      : base() {
+      columnNames = Enumerable.Range(1, 2).Select(x => x.ToString()).ToList();
+      rowNames = Enumerable.Range(1, 2).Select(x => x.ToString()).ToList();
+    }
+
+    public ExtendedHeatMap(IDataAnalysisProblemData problemData) {
+      this.problemData = problemData;
+      this.Title = "Feature Correlation";
+      this.columnNames = problemData.Dataset.DoubleVariables.ToList();
+      this.rowNames = problemData.Dataset.DoubleVariables.ToList();
+
+      CalculateElements(problemData.Dataset);
+    }
+
+    public IEnumerable<string> CorrelationCalculators {
+      get { return new List<string>() { "OnlinePearsonsRSquaredCalculator", "HoeffdingsDependenceCalculator", "SpearmansRankCorrelationCoefficientCalculator" }; }
+    }
+
+    public IEnumerable<string> Partitions {
+      get { return new List<string>() { "All Samples", "Training Partition", "Test Partition" }; }
+    }
+
+    public void Recalculate(string calc, string partition) {
+      CalculateElements(problemData.Dataset, calc, partition);
+    }
+
+    private void CalculateElements(Dataset dataset) {
+      CalculateElements(dataset, CorrelationCalculators.First(), Partitions.First());
+    }
+
+    private void CalculateElements(Dataset dataset, string calc, string partition) {
+      if (bw == null || bw.IsBusy) {
+        if (bw != null) {
+          bw.CancelAsync();
+        }
+        bw = new BackgroundWorker();
+        bw.WorkerReportsProgress = true;
+        bw.WorkerSupportsCancellation = true;
+        bw.DoWork += new DoWorkEventHandler(bw_DoWork);
+        bw.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged);
+        bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
+      }
+      bw.RunWorkerAsync(new BackgroundWorkerInfo { Dataset = dataset, Calculator = calc, Partition = partition });
+    }
+
+    private void bw_DoWork(object sender, DoWorkEventArgs e) {
+      BackgroundWorker worker = sender as BackgroundWorker;
+
+      BackgroundWorkerInfo bwInfo = (BackgroundWorkerInfo)e.Argument;
+      Dataset dataset = bwInfo.Dataset;
+      string partition = bwInfo.Partition;
+      string calc = bwInfo.Calculator;
+
+      IList<string> doubleVariableNames = dataset.DoubleVariables.ToList();
+      OnlineCalculatorError error;
+      int length = doubleVariableNames.Count;
+      double[,] elements = new double[length, length];
+
+      double calculations = (Math.Pow(length, 2) + length) / 2;
+
+      for (int i = 0; i < length; i++) {
+        for (int j = 0; j < i + 1; j++) {
+          if (worker.CancellationPending) {
+            e.Cancel = true;
+            return;
+          }
+
+          IEnumerable<double> var1 = dataset.GetDoubleValues(doubleVariableNames[i]);
+          IEnumerable<double> var2 = dataset.GetDoubleValues(doubleVariableNames[j]);
+          if (partition.Equals(Partitions.ElementAt(1))) {
+            var1 = var1.Skip(problemData.TrainingPartition.Start).Take(problemData.TrainingPartition.End - problemData.TrainingPartition.Start);
+            var2 = var2.Skip(problemData.TrainingPartition.Start).Take(problemData.TrainingPartition.End - problemData.TrainingPartition.Start);
+          } else if (partition.Equals(Partitions.ElementAt(2))) {
+            var1 = var1.Skip(problemData.TestPartition.Start).Take(problemData.TestPartition.End - problemData.TestPartition.Start);
+            var2 = var2.Skip(problemData.TestPartition.Start).Take(problemData.TestPartition.End - problemData.TestPartition.Start);
+          }
+
+          if (calc.Equals(CorrelationCalculators.ElementAt(1))) {
+            elements[i, j] = HoeffdingsDependenceCalculator.Calculate(var1, var2, out error);
+          } else if (calc.Equals(CorrelationCalculators.ElementAt(2))) {
+            elements[i, j] = SpearmansRankCorrelationCoefficientCalculator.Calculate(var1, var2, out error);
+          } else {
+            elements[i, j] = OnlinePearsonsRSquaredCalculator.Calculate(var1, var2, out error);
+          }
+          elements[j, i] = elements[i, j];
+          if (!error.Equals(OnlineCalculatorError.None)) {
+            throw new ArgumentException("Calculator returned " + error);
+          }
+          worker.ReportProgress((int)Math.Round((((Math.Pow(i, 2) + i) / 2 + j + 1.0) / calculations) * 100));
+        }
+      }
+      e.Result = elements;
+    }
+
+    private void bw_ProgressChanged(object sender, ProgressChangedEventArgs e) {
+      BackgroundWorker worker = sender as BackgroundWorker;
+      if (!worker.CancellationPending && ProgressCalculation != null) {
+        ProgressCalculation(sender, e);
+      }
+    }
+
+    private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) {
+      BackgroundWorker worker = sender as BackgroundWorker;
+      if (!e.Cancelled && !worker.CancellationPending) {
+        if (!(e.Error == null)) {
+          ErrorHandling.ShowErrorDialog(e.Error);
+        } else {
+          matrix = (double[,])e.Result;
+          OnReset();
+        }
+      } else {
+        Console.WriteLine("Backgroundworker canceled");
+      }
+    }
+
+    private class BackgroundWorkerInfo {
+      public Dataset Dataset { get; set; }
+      public string Calculator { get; set; }
+      public string Partition { get; set; }
+    }
+  }
+}
Index: branches/DatasetFeatureCorrelation/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/RegressionEnsembleSolution.cs
===================================================================
--- branches/DatasetFeatureCorrelation/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/RegressionEnsembleSolution.cs	(revision 8038)
+++ branches/DatasetFeatureCorrelation/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/RegressionEnsembleSolution.cs	(revision 8276)
@@ -37,4 +37,7 @@
   [Creatable("Data Analysis - Ensembles")]
   public sealed class RegressionEnsembleSolution : RegressionSolution, IRegressionEnsembleSolution {
+    private readonly Dictionary<int, double> trainingEvaluationCache = new Dictionary<int, double>();
+    private readonly Dictionary<int, double> testEvaluationCache = new Dictionary<int, double>();
+
     public new IRegressionEnsembleModel Model {
       get { return (IRegressionEnsembleModel)base.Model; }
@@ -52,7 +55,7 @@
 
     [Storable]
-    private Dictionary<IRegressionModel, IntRange> trainingPartitions;
+    private readonly Dictionary<IRegressionModel, IntRange> trainingPartitions;
     [Storable]
-    private Dictionary<IRegressionModel, IntRange> testPartitions;
+    private readonly Dictionary<IRegressionModel, IntRange> testPartitions;
 
     [StorableConstructor]
@@ -86,4 +89,7 @@
       }
 
+      trainingEvaluationCache = new Dictionary<int, double>(original.ProblemData.TrainingIndices.Count());
+      testEvaluationCache = new Dictionary<int, double>(original.ProblemData.TestIndices.Count());
+
       regressionSolutions = cloner.Clone(original.regressionSolutions);
       RegisterRegressionSolutionsEventHandler();
@@ -133,4 +139,7 @@
       }
 
+      trainingEvaluationCache = new Dictionary<int, double>(problemData.TrainingIndices.Count());
+      testEvaluationCache = new Dictionary<int, double>(problemData.TestIndices.Count());
+
       RegisterRegressionSolutionsEventHandler();
       regressionSolutions.AddRange(solutions);
@@ -153,18 +162,14 @@
     public override IEnumerable<double> EstimatedTrainingValues {
       get {
-        var rows = ProblemData.TrainingIndizes;
-        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 RowIsTrainingForModel(currentRow, pair.Model) && !RowIsTestForModel(currentRow, pair.Model)
-                                    select pair.EstimatedValuesEnumerator;
-          yield return AggregateEstimatedValues(selectedEnumerators.Select(x => x.Current));
+        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]);
       }
     }
@@ -172,19 +177,31 @@
     public override IEnumerable<double> EstimatedTestValues {
       get {
-        var rows = ProblemData.TestIndizes;
-        var estimatedValuesEnumerators = (from model in Model.Models
-                                          select new { Model = model, EstimatedValuesEnumerator = model.GetEstimatedValues(ProblemData.Dataset, rows).GetEnumerator() })
-                                         .ToList();
-        var rowsEnumerator = ProblemData.TestIndizes.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 RowIsTestForModel(currentRow, pair.Model)
-                                    select pair.EstimatedValuesEnumerator;
-
-          yield return AggregateEstimatedValues(selectedEnumerators.Select(x => x.Current));
+        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));
       }
     }
@@ -201,6 +218,15 @@
 
     public override IEnumerable<double> GetEstimatedValues(IEnumerable<int> rows) {
-      return from xs in GetEstimatedValueVectors(ProblemData.Dataset, rows)
-             select AggregateEstimatedValues(xs);
+      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]);
     }
 
@@ -223,4 +249,7 @@
 
     protected override void OnProblemDataChanged() {
+      trainingEvaluationCache.Clear();
+      testEvaluationCache.Clear();
+      evaluationCache.Clear();
       IRegressionProblemData problemData = new RegressionProblemData(ProblemData.Dataset,
                                                                      ProblemData.AllowedInputVariables,
@@ -251,7 +280,15 @@
     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();
     }
 
@@ -275,4 +312,8 @@
       trainingPartitions[solution.Model] = solution.ProblemData.TrainingPartition;
       testPartitions[solution.Model] = solution.ProblemData.TestPartition;
+
+      trainingEvaluationCache.Clear();
+      testEvaluationCache.Clear();
+      evaluationCache.Clear();
     }
 
@@ -282,4 +323,8 @@
       trainingPartitions.Remove(solution.Model);
       testPartitions.Remove(solution.Model);
+
+      trainingEvaluationCache.Clear();
+      testEvaluationCache.Clear();
+      evaluationCache.Clear();
     }
   }
Index: branches/DatasetFeatureCorrelation/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/RegressionProblemData.cs
===================================================================
--- branches/DatasetFeatureCorrelation/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/RegressionProblemData.cs	(revision 8038)
+++ branches/DatasetFeatureCorrelation/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/RegressionProblemData.cs	(revision 8276)
@@ -95,6 +95,6 @@
     #endregion
 
-    public ConstrainedValueParameter<StringValue> TargetVariableParameter {
-      get { return (ConstrainedValueParameter<StringValue>)Parameters[TargetVariableParameterName]; }
+    public IConstrainedValueParameter<StringValue> TargetVariableParameter {
+      get { return (IConstrainedValueParameter<StringValue>)Parameters[TargetVariableParameterName]; }
     }
     public string TargetVariable {
Index: branches/DatasetFeatureCorrelation/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/RegressionSolution.cs
===================================================================
--- branches/DatasetFeatureCorrelation/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/RegressionSolution.cs	(revision 8038)
+++ branches/DatasetFeatureCorrelation/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/RegressionSolution.cs	(revision 8276)
@@ -55,8 +55,8 @@
     }
     public override IEnumerable<double> EstimatedTrainingValues {
-      get { return GetEstimatedValues(ProblemData.TrainingIndizes); }
+      get { return GetEstimatedValues(ProblemData.TrainingIndices); }
     }
     public override IEnumerable<double> EstimatedTestValues {
-      get { return GetEstimatedValues(ProblemData.TestIndizes); }
+      get { return GetEstimatedValues(ProblemData.TestIndices); }
     }
 
Index: branches/DatasetFeatureCorrelation/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/RegressionSolutionBase.cs
===================================================================
--- branches/DatasetFeatureCorrelation/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/RegressionSolutionBase.cs	(revision 8038)
+++ branches/DatasetFeatureCorrelation/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/RegressionSolutionBase.cs	(revision 8276)
@@ -138,5 +138,5 @@
         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.TrainingIndizes), out errorState);
+        double trainingMAE = OnlineMeanAbsoluteErrorCalculator.Calculate(EstimatedTrainingValues, ProblemData.Dataset.GetDoubleValues(ProblemData.TargetVariable, ProblemData.TrainingIndices), out errorState);
         TrainingMeanAbsoluteError = errorState == OnlineCalculatorError.None ? trainingMAE : double.NaN;
       }
@@ -145,5 +145,5 @@
         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.TestIndizes), out errorState);
+        double testMAE = OnlineMeanAbsoluteErrorCalculator.Calculate(EstimatedTestValues, ProblemData.Dataset.GetDoubleValues(ProblemData.TargetVariable, ProblemData.TestIndices), out errorState);
         TestMeanAbsoluteError = errorState == OnlineCalculatorError.None ? testMAE : double.NaN;
       }
@@ -152,5 +152,5 @@
         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.TrainingIndizes), out errorState);
+        double trainingME = OnlineMeanErrorCalculator.Calculate(EstimatedTrainingValues, ProblemData.Dataset.GetDoubleValues(ProblemData.TargetVariable, ProblemData.TrainingIndices), out errorState);
         TrainingMeanError = errorState == OnlineCalculatorError.None ? trainingME : double.NaN;
       }
@@ -158,5 +158,5 @@
         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.TestIndizes), out errorState);
+        double testME = OnlineMeanErrorCalculator.Calculate(EstimatedTestValues, ProblemData.Dataset.GetDoubleValues(ProblemData.TargetVariable, ProblemData.TestIndices), out errorState);
         TestMeanError = errorState == OnlineCalculatorError.None ? testME : double.NaN;
       }
@@ -166,7 +166,7 @@
     protected void CalculateResults() {
       IEnumerable<double> estimatedTrainingValues = EstimatedTrainingValues; // cache values
-      IEnumerable<double> originalTrainingValues = ProblemData.Dataset.GetDoubleValues(ProblemData.TargetVariable, ProblemData.TrainingIndizes);
+      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.TestIndizes);
+      IEnumerable<double> originalTestValues = ProblemData.Dataset.GetDoubleValues(ProblemData.TargetVariable, ProblemData.TestIndices);
 
       OnlineCalculatorError errorState;
Index: branches/DatasetFeatureCorrelation/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/IDataAnalysisProblemData.cs
===================================================================
--- branches/DatasetFeatureCorrelation/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/IDataAnalysisProblemData.cs	(revision 8038)
+++ branches/DatasetFeatureCorrelation/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/IDataAnalysisProblemData.cs	(revision 8276)
@@ -36,6 +36,6 @@
     IntRange TestPartition { get; }
 
-    IEnumerable<int> TrainingIndizes { get; }
-    IEnumerable<int> TestIndizes { get; }
+    IEnumerable<int> TrainingIndices { get; }
+    IEnumerable<int> TestIndices { get; }
 
     bool IsTrainingSample(int index);
Index: branches/DatasetFeatureCorrelation/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/IOnlineCalculator.cs
===================================================================
--- branches/DatasetFeatureCorrelation/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/IOnlineCalculator.cs	(revision 8038)
+++ branches/DatasetFeatureCorrelation/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/IOnlineCalculator.cs	(revision 8276)
@@ -24,13 +24,13 @@
 namespace HeuristicLab.Problems.DataAnalysis {
   [Flags]
-  public enum OnlineCalculatorError { 
+  public enum OnlineCalculatorError {
     /// <summary>
     /// No error occurred
     /// </summary>
-    None = 0, 
+    None = 0,
     /// <summary>
     /// An invalid value has been added (often +/- Infinity and NaN are invalid values)
     /// </summary>
-    InvalidValueAdded = 1, 
+    InvalidValueAdded = 1,
     /// <summary>
     /// The number of elements added to the evaluator is not sufficient to calculate the result value
Index: branches/DatasetFeatureCorrelation/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/HoeffdingsDependenceCalculator.cs
===================================================================
--- branches/DatasetFeatureCorrelation/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/HoeffdingsDependenceCalculator.cs	(revision 8038)
+++ branches/DatasetFeatureCorrelation/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/HoeffdingsDependenceCalculator.cs	(revision 8276)
@@ -23,5 +23,4 @@
 using System.Collections.Generic;
 using System.Linq;
-using HeuristicLab.Common;
 
 namespace HeuristicLab.Problems.DataAnalysis {
Index: branches/DatasetFeatureCorrelation/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineLinearScalingParameterCalculator.cs
===================================================================
--- branches/DatasetFeatureCorrelation/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineLinearScalingParameterCalculator.cs	(revision 8038)
+++ branches/DatasetFeatureCorrelation/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineLinearScalingParameterCalculator.cs	(revision 8276)
@@ -55,5 +55,4 @@
     }
 
-    private int cnt;
     private OnlineMeanAndVarianceCalculator targetMeanCalculator;
     private OnlineMeanAndVarianceCalculator originalMeanAndVarianceCalculator;
@@ -68,5 +67,4 @@
 
     public void Reset() {
-      cnt = 0;
       targetMeanCalculator.Reset();
       originalMeanAndVarianceCalculator.Reset();
@@ -85,5 +83,4 @@
       originalTargetCovarianceCalculator.Add(original, target);
 
-      cnt++;
     }
 
Index: branches/DatasetFeatureCorrelation/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/SpearmansRankCorrelationCoefficientCalculator.cs
===================================================================
--- branches/DatasetFeatureCorrelation/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/SpearmansRankCorrelationCoefficientCalculator.cs	(revision 8276)
+++ branches/DatasetFeatureCorrelation/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/SpearmansRankCorrelationCoefficientCalculator.cs	(revision 8276)
@@ -0,0 +1,105 @@
+﻿#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 SpearmansRankCorrelationCoefficientCalculator {
+
+    public static double Calculate(IEnumerable<double> originalValues, IEnumerable<double> estimatedValues, out OnlineCalculatorError errorState) {
+      double rs = Math.Abs(Spear(originalValues, estimatedValues, out errorState));
+      if (errorState != OnlineCalculatorError.None) return double.NaN;
+      return rs;
+    }
+
+    /// <summary>
+    /// Calculates Spearmans Rank Correlation Coefficient. Source: Numerical Recipes in C.
+    /// </summary>
+    private static double Spear(IEnumerable<double> xs, IEnumerable<double> ys, out OnlineCalculatorError errorState) {
+      double[] xsArr = xs.ToArray();
+      double[] ysArr = ys.ToArray();
+      if (xsArr.Length != ysArr.Length) throw new ArgumentException("The number of elements in xs and ys does not match");
+
+      int n = xsArr.Length;
+      Array.Sort(xsArr, ysArr);
+      double sf = CRank(xsArr);
+      Array.Sort(ysArr, xsArr);
+      double sg = CRank(ysArr);
+
+      double d = 0.0;
+      for (int j = 0; j < n; j++) //Sum the squared difference of ranks.
+        d += Math.Pow(xsArr[j] - ysArr[j], 2);
+
+      double en, en3n, aved, fac, rs; // vard, zd, t, df, probd, probrs;
+      en = n;
+      en3n = en * en * en - en;
+      aved = en3n / 6.0 - (sf + sg) / 12.0;
+      fac = (1.0 - sf / en3n) * (1.0 - sg / en3n);
+      //vard = ((en - 1.0) * en * en * Math.Pow(en + 1.0, 2) / 36.0) * fac;
+      //zd = (d - aved) / Math.Sqrt(vard);
+      //probd = erfcc(Math.Abs(zd) / 1.4142136);
+      rs = (1.0 - (6.0 / en3n) * (d + (sf + sg) / 12.0)) / Math.Sqrt(fac);
+      //fac = (rs + 1.0) * (1.0 - rs);
+      //if (fac > 0.0) {
+      //  t = rs * Math.Sqrt((en - 2.0) / fac);
+      //  df = en - 2.0;
+      //  probrs = betai(0.5 * df, 0.5, df / (df + t * t));
+      //} else {
+      //  probrs = 0.0;
+      //}
+      errorState = OnlineCalculatorError.None;
+      return rs;
+    }
+
+    /// <summary>
+    /// Calculates midranks. Source: Numerical Recipes in C.
+    /// </summary>
+    /// <param name="w">Sorted array of elements, replaces the elements by their rank, including midranking of ties</param>
+    /// <returns></returns>
+    private static double CRank(double[] w) {
+      int i = 0;
+      int n = w.Length;
+      double s = 0.0;
+      double t;
+      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)
+          double rank = 0.5 * (i + j - 1);
+          int k;
+          for (k = i; k <= j - 1; k++) w[k] = rank; // set the rank for all tied entries
+          t = j - i;
+          s += t * t * t - t;
+          i = j;
+        }
+      }
+
+      if (i == n - 1) w[n - 1] = n - 1;   // if the last element was not tied, this is its rank
+      return s;
+    }
+  }
+}
