Index: branches/HeuristicLab.Mono/HeuristicLab.Problems.DataAnalysis/3.4/HeuristicLab.Problems.DataAnalysis-3.4.csproj
===================================================================
--- branches/HeuristicLab.Mono/HeuristicLab.Problems.DataAnalysis/3.4/HeuristicLab.Problems.DataAnalysis-3.4.csproj	(revision 8440)
+++ branches/HeuristicLab.Mono/HeuristicLab.Problems.DataAnalysis/3.4/HeuristicLab.Problems.DataAnalysis-3.4.csproj	(revision 8585)
@@ -93,4 +93,12 @@
   </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">
@@ -122,4 +130,6 @@
     <Compile Include="Implementation\Clustering\ClusteringProblemData.cs" />
     <Compile Include="Implementation\Clustering\ClusteringSolution.cs" />
+    <Compile Include="Implementation\FeatureCorrelation\FeatureCorrelationCalculator.cs" />
+    <Compile Include="Implementation\FeatureCorrelation\FeatureCorrelationEnums.cs" />
     <Compile Include="Implementation\Regression\ConstantRegressionModel.cs" />
     <Compile Include="Implementation\Regression\ConstantRegressionSolution.cs" />
@@ -180,4 +190,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/HeuristicLab.Mono/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ClassificationEnsembleModel.cs
===================================================================
--- branches/HeuristicLab.Mono/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ClassificationEnsembleModel.cs	(revision 8440)
+++ branches/HeuristicLab.Mono/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ClassificationEnsembleModel.cs	(revision 8585)
@@ -95,5 +95,5 @@
 
     IClassificationSolution IClassificationModel.CreateClassificationSolution(IClassificationProblemData problemData) {
-      return new ClassificationEnsembleSolution(models, problemData);
+      return new ClassificationEnsembleSolution(models, new ClassificationEnsembleProblemData(problemData));
     }
     #endregion
Index: branches/HeuristicLab.Mono/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ClassificationEnsembleSolution.cs
===================================================================
--- branches/HeuristicLab.Mono/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ClassificationEnsembleSolution.cs	(revision 8440)
+++ branches/HeuristicLab.Mono/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ClassificationEnsembleSolution.cs	(revision 8585)
@@ -104,4 +104,7 @@
     }
 
+    public ClassificationEnsembleSolution(IClassificationProblemData problemData) :
+      this(Enumerable.Empty<IClassificationModel>(), problemData) { }
+
     public ClassificationEnsembleSolution(IEnumerable<IClassificationModel> models, IClassificationProblemData problemData)
       : this(models, problemData,
Index: branches/HeuristicLab.Mono/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ClassificationProblemData.cs
===================================================================
--- branches/HeuristicLab.Mono/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ClassificationProblemData.cs	(revision 8440)
+++ branches/HeuristicLab.Mono/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ClassificationProblemData.cs	(revision 8585)
@@ -223,38 +223,34 @@
     }
 
-    private List<double> classValues;
-    public List<double> ClassValues {
+    private List<double> classValuesCache;
+    private List<double> ClassValuesCache {
       get {
-        if (classValues == null) {
-          classValues = Dataset.GetDoubleValues(TargetVariableParameter.Value.Value).Distinct().ToList();
-          classValues.Sort();
+        if (classValuesCache == null) {
+          classValuesCache = Dataset.GetDoubleValues(TargetVariableParameter.Value.Value).Distinct().OrderBy(x => x).ToList();
         }
-        return classValues;
+        return classValuesCache;
       }
     }
-    IEnumerable<double> IClassificationProblemData.ClassValues {
-      get { return ClassValues; }
-    }
-
+    public IEnumerable<double> ClassValues {
+      get { return ClassValuesCache; }
+    }
     public int Classes {
-      get { return ClassValues.Count; }
-    }
-
-    private List<string> classNames;
-    public List<string> ClassNames {
+      get { return ClassValuesCache.Count; }
+    }
+
+    private List<string> classNamesCache;
+    private List<string> ClassNamesCache {
       get {
-        if (classNames == null) {
-          classNames = new List<string>();
+        if (classNamesCache == null) {
+          classNamesCache = new List<string>();
           for (int i = 0; i < ClassNamesParameter.Value.Rows; i++)
-            classNames.Add(ClassNamesParameter.Value[i, 0]);
+            classNamesCache.Add(ClassNamesParameter.Value[i, 0]);
         }
-        return classNames;
+        return classNamesCache;
       }
     }
-    IEnumerable<string> IClassificationProblemData.ClassNames {
-      get { return ClassNames; }
-    }
-
-    private Dictionary<Tuple<double, double>, double> classificationPenaltiesCache = new Dictionary<Tuple<double, double>, double>();
+    public IEnumerable<string> ClassNames {
+      get { return ClassNamesCache; }
+    }
     #endregion
 
@@ -277,4 +273,13 @@
 
     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;
+    }
+
     public ClassificationProblemData(Dataset dataset, IEnumerable<string> allowedInputVariables, string targetVariable)
       : base(dataset, allowedInputVariables) {
@@ -310,14 +315,11 @@
       DeregisterParameterEvents();
 
-      classNames = null;
       ((IStringConvertibleMatrix)ClassNamesParameter.Value).Columns = 1;
-      ((IStringConvertibleMatrix)ClassNamesParameter.Value).Rows = ClassValues.Count;
+      ((IStringConvertibleMatrix)ClassNamesParameter.Value).Rows = ClassValuesCache.Count;
       for (int i = 0; i < Classes; i++)
-        ClassNamesParameter.Value[i, 0] = "Class " + ClassValues[i];
+        ClassNamesParameter.Value[i, 0] = "Class " + ClassValuesCache[i];
       ClassNamesParameter.Value.ColumnNames = new List<string>() { "ClassNames" };
       ClassNamesParameter.Value.RowNames = ClassValues.Select(s => "ClassValue: " + s);
 
-      classificationPenaltiesCache.Clear();
-      ((ValueParameter<DoubleMatrix>)ClassificationPenaltiesParameter).ReactOnValueToStringChangedAndValueItemImageChanged = false;
       ((IStringConvertibleMatrix)ClassificationPenaltiesParameter.Value).Rows = Classes;
       ((IStringConvertibleMatrix)ClassificationPenaltiesParameter.Value).Columns = Classes;
@@ -330,23 +332,22 @@
         }
       }
-      ((ValueParameter<DoubleMatrix>)ClassificationPenaltiesParameter).ReactOnValueToStringChangedAndValueItemImageChanged = true;
       RegisterParameterEvents();
     }
 
     public string GetClassName(double classValue) {
-      if (!ClassValues.Contains(classValue)) throw new ArgumentException();
-      int index = ClassValues.IndexOf(classValue);
-      return ClassNames[index];
+      if (!ClassValuesCache.Contains(classValue)) throw new ArgumentException();
+      int index = ClassValuesCache.IndexOf(classValue);
+      return ClassNamesCache[index];
     }
     public double GetClassValue(string className) {
-      if (!ClassNames.Contains(className)) throw new ArgumentException();
-      int index = ClassNames.IndexOf(className);
-      return ClassValues[index];
+      if (!ClassNamesCache.Contains(className)) throw new ArgumentException();
+      int index = ClassNamesCache.IndexOf(className);
+      return ClassValuesCache[index];
     }
     public void SetClassName(double classValue, string className) {
-      if (!classValues.Contains(classValue)) throw new ArgumentException();
-      int index = ClassValues.IndexOf(classValue);
-      ClassNames[index] = 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
     }
 
@@ -355,11 +356,7 @@
     }
     public double GetClassificationPenalty(double correctClassValue, double estimatedClassValue) {
-      var key = Tuple.Create(correctClassValue, estimatedClassValue);
-      if (!classificationPenaltiesCache.ContainsKey(key)) {
-        int correctClassIndex = ClassValues.IndexOf(correctClassValue);
-        int estimatedClassIndex = ClassValues.IndexOf(estimatedClassValue);
-        classificationPenaltiesCache[key] = ClassificationPenaltiesParameter.Value[correctClassIndex, estimatedClassIndex];
-      }
-      return classificationPenaltiesCache[key];
+      int correctClassIndex = ClassValuesCache.IndexOf(correctClassValue);
+      int estimatedClassIndex = ClassValuesCache.IndexOf(estimatedClassValue);
+      return ClassificationPenaltiesParameter.Value[correctClassIndex, estimatedClassIndex];
     }
     public void SetClassificationPenalty(string correctClassName, string estimatedClassName, double penalty) {
@@ -367,7 +364,6 @@
     }
     public void SetClassificationPenalty(double correctClassValue, double estimatedClassValue, double penalty) {
-      var key = Tuple.Create(correctClassValue, estimatedClassValue);
-      int correctClassIndex = ClassValues.IndexOf(correctClassValue);
-      int estimatedClassIndex = ClassValues.IndexOf(estimatedClassValue);
+      int correctClassIndex = ClassValuesCache.IndexOf(correctClassValue);
+      int estimatedClassIndex = ClassValuesCache.IndexOf(estimatedClassValue);
 
       ClassificationPenaltiesParameter.Value[correctClassIndex, estimatedClassIndex] = penalty;
@@ -379,6 +375,4 @@
       ClassNamesParameter.Value.Reset += new EventHandler(Parameter_ValueChanged);
       ClassNamesParameter.Value.ItemChanged += new EventHandler<EventArgs<int, int>>(MatrixParameter_ItemChanged);
-      ClassificationPenaltiesParameter.Value.Reset += new EventHandler(Parameter_ValueChanged);
-      ClassificationPenaltiesParameter.Value.ItemChanged += new EventHandler<EventArgs<int, int>>(MatrixParameter_ItemChanged);
     }
     private void DeregisterParameterEvents() {
@@ -386,17 +380,18 @@
       ClassNamesParameter.Value.Reset -= new EventHandler(Parameter_ValueChanged);
       ClassNamesParameter.Value.ItemChanged -= new EventHandler<EventArgs<int, int>>(MatrixParameter_ItemChanged);
-      ClassificationPenaltiesParameter.Value.Reset -= new EventHandler(Parameter_ValueChanged);
-      ClassificationPenaltiesParameter.Value.ItemChanged -= new EventHandler<EventArgs<int, int>>(MatrixParameter_ItemChanged);
     }
 
     private void TargetVariableParameter_ValueChanged(object sender, EventArgs e) {
-      classValues = null;
+      classValuesCache = null;
+      classNamesCache = null;
       ResetTargetVariableDependentMembers();
       OnChanged();
     }
     private void Parameter_ValueChanged(object sender, EventArgs e) {
+      classNamesCache = null;
       OnChanged();
     }
     private void MatrixParameter_ItemChanged(object sender, EventArgs<int, int> e) {
+      classNamesCache = null;
       OnChanged();
     }
Index: branches/HeuristicLab.Mono/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/DiscriminantFunctionClassificationSolution.cs
===================================================================
--- branches/HeuristicLab.Mono/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/DiscriminantFunctionClassificationSolution.cs	(revision 8440)
+++ branches/HeuristicLab.Mono/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/DiscriminantFunctionClassificationSolution.cs	(revision 8585)
@@ -51,6 +51,4 @@
       valueEvaluationCache = new Dictionary<int, double>();
       classValueEvaluationCache = new Dictionary<int, double>();
-
-      SetAccuracyMaximizingThresholds();
     }
 
Index: branches/HeuristicLab.Mono/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/DiscriminantFunctionClassificationSolutionBase.cs
===================================================================
--- branches/HeuristicLab.Mono/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/DiscriminantFunctionClassificationSolutionBase.cs	(revision 8440)
+++ branches/HeuristicLab.Mono/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/DiscriminantFunctionClassificationSolutionBase.cs	(revision 8585)
@@ -94,11 +94,4 @@
     }
 
-    protected override void OnModelChanged() {
-      DeregisterEventHandler();
-      SetAccuracyMaximizingThresholds();
-      RegisterEventHandler();
-      base.OnModelChanged();
-    }
-
     protected void CalculateRegressionResults() {
       double[] estimatedTrainingValues = EstimatedTrainingValues.ToArray(); // cache values
@@ -137,25 +130,6 @@
     }
 
-    public void SetAccuracyMaximizingThresholds() {
-      double[] classValues;
-      double[] thresholds;
-      var targetClassValues = ProblemData.Dataset.GetDoubleValues(ProblemData.TargetVariable, ProblemData.TrainingIndices);
-      AccuracyMaximizationThresholdCalculator.CalculateThresholds(ProblemData, EstimatedTrainingValues, targetClassValues, out classValues, out thresholds);
-
-      Model.SetThresholdsAndClassValues(thresholds, classValues);
-    }
-
-    public void SetClassDistibutionCutPointThresholds() {
-      double[] classValues;
-      double[] thresholds;
-      var targetClassValues = ProblemData.Dataset.GetDoubleValues(ProblemData.TargetVariable, ProblemData.TrainingIndices);
-      NormalDistributionCutPointsThresholdCalculator.CalculateThresholds(ProblemData, EstimatedTrainingValues, targetClassValues, out classValues, out thresholds);
-
-      Model.SetThresholdsAndClassValues(thresholds, classValues);
-    }
-
     protected virtual void OnModelThresholdsChanged(EventArgs e) {
-      CalculateResults();
-      CalculateRegressionResults();
+      OnModelChanged();
     }
 
Index: branches/HeuristicLab.Mono/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ThresholdCalculators/AccuracyMaximizationThresholdCalculator.cs
===================================================================
--- branches/HeuristicLab.Mono/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ThresholdCalculators/AccuracyMaximizationThresholdCalculator.cs	(revision 8440)
+++ branches/HeuristicLab.Mono/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ThresholdCalculators/AccuracyMaximizationThresholdCalculator.cs	(revision 8585)
@@ -85,19 +85,24 @@
             //all positives
             if (pair.TargetClassValue.IsAlmost(classValues[i - 1])) {
-              if (pair.EstimatedValue > lowerThreshold && pair.EstimatedValue < actualThreshold)
+              if (pair.EstimatedValue > lowerThreshold && pair.EstimatedValue <= actualThreshold)
                 //true positive
-                classificationScore += problemData.GetClassificationPenalty(classValues[i - 1], classValues[i - 1]);
+                classificationScore += problemData.GetClassificationPenalty(pair.TargetClassValue, pair.TargetClassValue);
               else
                 //false negative
-                classificationScore += problemData.GetClassificationPenalty(classValues[i], classValues[i - 1]);
+                classificationScore += problemData.GetClassificationPenalty(pair.TargetClassValue, classValues[i]);
             }
               //all negatives
             else {
-              if (pair.EstimatedValue > lowerThreshold && pair.EstimatedValue < actualThreshold)
-                //false positive
-                classificationScore += problemData.GetClassificationPenalty(classValues[i - 1], classValues[i]);
-              else
-                //true negative, consider only upper class
-                classificationScore += problemData.GetClassificationPenalty(classValues[i], classValues[i]);
+              //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);
+              }
             }
           }
Index: branches/HeuristicLab.Mono/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/DataAnalysisProblemData.cs
===================================================================
--- branches/HeuristicLab.Mono/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/DataAnalysisProblemData.cs	(revision 8440)
+++ branches/HeuristicLab.Mono/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/DataAnalysisProblemData.cs	(revision 8585)
@@ -107,4 +107,5 @@
     [StorableConstructor]
     protected DataAnalysisProblemData(bool deserializing) : base(deserializing) { }
+
     [StorableHook(HookType.AfterDeserialization)]
     private void AfterDeserialization() {
Index: branches/HeuristicLab.Mono/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/FeatureCorrelation/FeatureCorrelationCalculator.cs
===================================================================
--- branches/HeuristicLab.Mono/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/FeatureCorrelation/FeatureCorrelationCalculator.cs	(revision 8585)
+++ branches/HeuristicLab.Mono/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/FeatureCorrelation/FeatureCorrelationCalculator.cs	(revision 8585)
@@ -0,0 +1,274 @@
+﻿#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.PluginInfrastructure;
+using FCE = HeuristicLab.Problems.DataAnalysis.FeatureCorrelationEnums;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  public class FeatureCorrelationCalculator : Object {
+
+    private BackgroundWorker bw;
+    private BackgroundWorkerInfo bwInfo;
+
+    private IDataAnalysisProblemData problemData;
+    public IDataAnalysisProblemData ProblemData {
+      set {
+        if (bw != null) {
+          bw.CancelAsync();
+        }
+        problemData = value;
+      }
+    }
+
+    public FeatureCorrelationCalculator()
+      : base() { }
+
+    public FeatureCorrelationCalculator(IDataAnalysisProblemData problemData)
+      : base() {
+      this.problemData = problemData;
+    }
+
+    public void CalculateElements(FCE.CorrelationCalculators calc, FCE.Partitions partition) {
+      CalculateElements(problemData.Dataset, calc, partition);
+    }
+
+    // returns if any calculation takes place
+    public bool CalculateTimeframeElements(FCE.CorrelationCalculators calc, FCE.Partitions partition, string variable, int frames, double[,] correlation = null) {
+      if (correlation == null || correlation.GetLength(1) <= frames) {
+        CalculateElements(problemData.Dataset, calc, partition, variable, frames, correlation);
+        return true;
+      } else {
+        return false;
+      }
+    }
+
+    private double[,] GetElementsOfCorrelation(double[,] corr, int frames) {
+      double[,] elements = new double[corr.GetLength(0), frames + 1];
+      for (int i = 0; i < corr.GetLength(0); i++) {
+        for (int j = 0; j <= frames; j++) {
+          elements[i, j] = corr[i, j];
+        }
+      }
+      return elements;
+    }
+
+    private void CalculateElements(Dataset dataset, FCE.CorrelationCalculators calc, FCE.Partitions partition, string variable = null, int frames = 0, double[,] alreadyCalculated = null) {
+      bwInfo = new BackgroundWorkerInfo { Dataset = dataset, Calculator = calc, Partition = partition, Variable = variable, Frames = frames, AlreadyCalculated = alreadyCalculated };
+      if (bw == null) {
+        bw = new BackgroundWorker();
+        bw.WorkerReportsProgress = true;
+        bw.WorkerSupportsCancellation = true;
+        bw.DoWork += new DoWorkEventHandler(BwDoWork);
+        bw.ProgressChanged += new ProgressChangedEventHandler(BwProgressChanged);
+        bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(BwRunWorkerCompleted);
+      }
+      if (bw.IsBusy) {
+        bw.CancelAsync();
+      } else {
+        bw.RunWorkerAsync(bwInfo);
+      }
+    }
+
+    #region backgroundworker
+    private void BwDoWork(object sender, DoWorkEventArgs e) {
+      BackgroundWorkerInfo bwInfo = (BackgroundWorkerInfo)e.Argument;
+      if (bwInfo.Variable == null) {
+        BwCalculateCorrelation(sender, e);
+      } else {
+        BwCalculateTimeframeCorrelation(sender, e);
+      }
+    }
+
+    private void BwCalculateCorrelation(object sender, DoWorkEventArgs e) {
+      BackgroundWorker worker = sender as BackgroundWorker;
+
+      BackgroundWorkerInfo bwInfo = (BackgroundWorkerInfo)e.Argument;
+      Dataset dataset = bwInfo.Dataset;
+      FCE.Partitions partition = bwInfo.Partition;
+      FCE.CorrelationCalculators 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;
+
+      worker.ReportProgress(0);
+
+      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 = GetRelevantValues(problemData, partition, doubleVariableNames[i]);
+          IEnumerable<double> var2 = GetRelevantValues(problemData, partition, doubleVariableNames[j]);
+
+          elements[i, j] = CalculateElementWithCalculator(calc, var1, var2, out error);
+
+          elements[j, i] = elements[i, j];
+          if (!error.Equals(OnlineCalculatorError.None)) {
+            worker.ReportProgress(100);
+            throw new ArgumentException("Calculator returned " + error + Environment.NewLine + "Maybe try another calculator.");
+          }
+          worker.ReportProgress((int)Math.Round((((Math.Pow(i, 2) + i) / 2 + j + 1.0) / calculations) * 100));
+        }
+      }
+      e.Result = elements;
+    }
+
+    private void BwCalculateTimeframeCorrelation(object sender, DoWorkEventArgs e) {
+      BackgroundWorker worker = sender as BackgroundWorker;
+
+      BackgroundWorkerInfo bwInfo = (BackgroundWorkerInfo)e.Argument;
+      Dataset dataset = bwInfo.Dataset;
+      FCE.Partitions partition = bwInfo.Partition;
+      FCE.CorrelationCalculators calc = bwInfo.Calculator;
+      string variable = bwInfo.Variable;
+      int frames = bwInfo.Frames;
+      double[,] alreadyCalculated = bwInfo.AlreadyCalculated;
+
+      IList<string> doubleVariableNames = dataset.DoubleVariables.ToList();
+      OnlineCalculatorError error;
+      int length = doubleVariableNames.Count;
+      double[,] elements = new double[length, frames + 1];
+      double calculations = (frames + 1) * length;
+
+      worker.ReportProgress(0);
+
+      int start = 0;
+      if (alreadyCalculated != null) {
+        for (int i = 0; i < alreadyCalculated.GetLength(0); i++) {
+          Array.Copy(alreadyCalculated, i * alreadyCalculated.GetLength(1), elements, i * elements.GetLength(1), alreadyCalculated.GetLength(1));
+        }
+        start = alreadyCalculated.GetLength(1);
+      }
+
+      for (int i = 0; i < length; i++) {
+        for (int j = start; j <= frames; j++) {
+          if (worker.CancellationPending) {
+            e.Cancel = true;
+            return;
+          }
+
+          IEnumerable<double> var1 = GetRelevantValues(problemData, partition, variable);
+          IEnumerable<double> var2 = GetRelevantValues(problemData, partition, doubleVariableNames[i]);
+
+          var valuesInFrame = var1.Take(j);
+          var help = var1.Skip(j).ToList();
+          help.AddRange(valuesInFrame);
+          var1 = help;
+
+          elements[i, j] = CalculateElementWithCalculator(calc, var1, var2, out error);
+
+          if (!error.Equals(OnlineCalculatorError.None)) {
+            worker.ReportProgress(100);
+            throw new ArgumentException("Calculator returned " + error + Environment.NewLine + "Maybe try another calculator.");
+          }
+          worker.ReportProgress((int)((100.0 / calculations) * (i * (frames + 1) + j + 1)));
+        }
+      }
+      e.Result = elements;
+    }
+
+    private IEnumerable<double> GetRelevantValues(IDataAnalysisProblemData problemData, FCE.Partitions partition, string variable) {
+      IEnumerable<double> var = problemData.Dataset.GetDoubleValues(variable);
+      if (partition.Equals(FCE.Partitions.TrainingSamples)) {
+        var = var.Skip(problemData.TrainingPartition.Start).Take(problemData.TrainingPartition.End - problemData.TrainingPartition.Start);
+      } else if (partition.Equals(FCE.Partitions.TestSamples)) {
+        var = var.Skip(problemData.TestPartition.Start).Take(problemData.TestPartition.End - problemData.TestPartition.Start);
+      }
+      return var;
+    }
+
+    private double CalculateElementWithCalculator(FCE.CorrelationCalculators calc, IEnumerable<double> var1, IEnumerable<double> var2, out OnlineCalculatorError error) {
+      if (calc.Equals(FCE.CorrelationCalculators.HoeffdingsDependence)) {
+        return HoeffdingsDependenceCalculator.Calculate(var1, var2, out error);
+      } else if (calc.Equals(FCE.CorrelationCalculators.SpearmansRank)) {
+        return SpearmansRankCorrelationCoefficientCalculator.Calculate(var1, var2, out error);
+      } else if (calc.Equals(FCE.CorrelationCalculators.PearsonsRSquared)) {
+        return OnlinePearsonsRSquaredCalculator.Calculate(var1, var2, out error);
+      } else {
+        return Math.Sqrt(OnlinePearsonsRSquaredCalculator.Calculate(var1, var2, out error));
+      }
+    }
+
+    private void BwRunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) {
+      BackgroundWorker worker = sender as BackgroundWorker;
+      if (!e.Cancelled && !worker.CancellationPending) {
+        if (!(e.Error == null)) {
+          ErrorHandling.ShowErrorDialog(e.Error);
+        } else {
+          OnCorrelationCalculationFinished((double[,])e.Result, bwInfo.Calculator, bwInfo.Partition, bwInfo.Variable);
+        }
+      } else {
+        bw.RunWorkerAsync(bwInfo);
+      }
+    }
+    #endregion
+
+    #region events
+    public class CorrelationCalculationFinishedArgs : EventArgs {
+      public double[,] Correlation { get; private set; }
+      public FCE.CorrelationCalculators Calculcator { get; private set; }
+      public FCE.Partitions Partition { get; private set; }
+      public string Variable { get; private set; }
+
+      public CorrelationCalculationFinishedArgs(double[,] correlation, FCE.CorrelationCalculators calculator, FCE.Partitions partition, string variable = null) {
+        this.Correlation = correlation;
+        this.Calculcator = calculator;
+        this.Partition = partition;
+        this.Variable = variable;
+      }
+    }
+    public delegate void CorrelationCalculationFinishedHandler(object sender, CorrelationCalculationFinishedArgs e);
+    public event CorrelationCalculationFinishedHandler CorrelationCalculationFinished;
+    protected virtual void OnCorrelationCalculationFinished(double[,] correlation, FCE.CorrelationCalculators calculator, FCE.Partitions partition, string variable = null) {
+      var handler = CorrelationCalculationFinished;
+      if (handler != null)
+        handler(this, new CorrelationCalculationFinishedArgs(correlation, calculator, partition, variable));
+    }
+
+    public delegate void ProgressCalculationHandler(object sender, ProgressChangedEventArgs e);
+    public event ProgressCalculationHandler ProgressCalculation;
+    protected void BwProgressChanged(object sender, ProgressChangedEventArgs e) {
+      BackgroundWorker worker = sender as BackgroundWorker;
+      if (!worker.CancellationPending && ProgressCalculation != null) {
+        ProgressCalculation(sender, e);
+      }
+    }
+    #endregion
+
+    protected class BackgroundWorkerInfo {
+      public Dataset Dataset { get; set; }
+      public FCE.CorrelationCalculators Calculator { get; set; }
+      public FCE.Partitions Partition { get; set; }
+      public string Variable { get; set; }
+      public int Frames { get; set; }
+      public double[,] AlreadyCalculated { get; set; }
+    }
+  }
+}
Index: branches/HeuristicLab.Mono/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/FeatureCorrelation/FeatureCorrelationEnums.cs
===================================================================
--- branches/HeuristicLab.Mono/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/FeatureCorrelation/FeatureCorrelationEnums.cs	(revision 8585)
+++ branches/HeuristicLab.Mono/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/FeatureCorrelation/FeatureCorrelationEnums.cs	(revision 8585)
@@ -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;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Linq;
+using System.Reflection;
+using HeuristicLab.Data;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  // see http://blog.spontaneouspublicity.com/associating-strings-with-enums-in-c
+  public class FeatureCorrelationEnums {
+    public enum Partitions {
+      [Description("All Samples")]
+      AllSamples,
+      [Description("Training Samples")]
+      TrainingSamples,
+      [Description("Test Samples")]
+      TestSamples
+    }
+
+    public enum CorrelationCalculators {
+      [Description("Pearsons R")]
+      PearsonsR,
+      [Description("Pearsons R Squared")]
+      PearsonsRSquared,
+      [Description("Hoeffdings Dependence")]
+      HoeffdingsDependence,
+      [Description("Spearmans Rank")]
+      SpearmansRank
+    }
+
+    public static readonly Dictionary<CorrelationCalculators, DoubleRange> calculatorInterval = new Dictionary<CorrelationCalculators, DoubleRange>(){ 
+      { CorrelationCalculators.PearsonsR, new DoubleRange(1.0, -1.0)},
+      { CorrelationCalculators.SpearmansRank, new DoubleRange(1.0, -1.0)},
+      { CorrelationCalculators.HoeffdingsDependence, new DoubleRange(1.0, -0.5)},
+      { CorrelationCalculators.PearsonsRSquared, new DoubleRange(1.0, 0.0)}
+    };
+
+    public static string GetEnumDescription(object value) {
+      FieldInfo fi = value.GetType().GetField(value.ToString());
+
+      DescriptionAttribute[] attributes =
+          (DescriptionAttribute[])fi.GetCustomAttributes(typeof(DescriptionAttribute), false);
+
+      if (attributes != null && attributes.Length > 0)
+        return attributes[0].Description;
+      else
+        return value.ToString();
+    }
+
+    public static IEnumerable<T> EnumToList<T>() {
+      Type enumType = typeof(T);
+
+      // Can't use generic type constraints on value types,
+      // so have to do check like this
+      if (enumType.BaseType != typeof(Enum)) {
+        throw new ArgumentException("T must be of type System.Enum");
+      }
+
+      Array enumValArray = Enum.GetValues(enumType);
+      return Enum.GetValues(enumType).Cast<int>().Select(x => (T)Enum.Parse(enumType, x.ToString())).ToList();
+    }
+
+    public static T GetEnumOfDescription<T>(string desc) {
+      Type enumType = typeof(T);
+
+      if (enumType.BaseType != typeof(Enum))
+        throw new ArgumentException("T must be of type System.Enum");
+
+      Array enumValArray = Enum.GetValues(enumType);
+      foreach (int val in enumValArray) {
+
+        T e = (T)Enum.Parse(enumType, val.ToString());
+        if (GetEnumDescription(e).Equals(desc)) {
+          return (T)e;
+        }
+      }
+      throw new ArgumentException("Description is not in the given type T");
+    }
+  }
+}
Index: branches/HeuristicLab.Mono/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/ConstantRegressionModel.cs
===================================================================
--- branches/HeuristicLab.Mono/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/ConstantRegressionModel.cs	(revision 8440)
+++ branches/HeuristicLab.Mono/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/ConstantRegressionModel.cs	(revision 8585)
@@ -55,5 +55,5 @@
 
     public IRegressionSolution CreateRegressionSolution(IRegressionProblemData problemData) {
-      return new ConstantRegressionSolution(this, problemData);
+      return new ConstantRegressionSolution(this, new RegressionProblemData(problemData));
     }
   }
Index: branches/HeuristicLab.Mono/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/RegressionEnsembleModel.cs
===================================================================
--- branches/HeuristicLab.Mono/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/RegressionEnsembleModel.cs	(revision 8440)
+++ branches/HeuristicLab.Mono/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/RegressionEnsembleModel.cs	(revision 8585)
@@ -102,5 +102,5 @@
 
     public RegressionEnsembleSolution CreateRegressionSolution(IRegressionProblemData problemData) {
-      return new RegressionEnsembleSolution(this.Models, problemData);
+      return new RegressionEnsembleSolution(this.Models, new RegressionEnsembleProblemData(problemData));
     }
     IRegressionSolution IRegressionModel.CreateRegressionSolution(IRegressionProblemData problemData) {
Index: branches/HeuristicLab.Mono/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/RegressionProblemData.cs
===================================================================
--- branches/HeuristicLab.Mono/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/RegressionProblemData.cs	(revision 8440)
+++ branches/HeuristicLab.Mono/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/RegressionProblemData.cs	(revision 8585)
@@ -121,4 +121,11 @@
       : 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)
Index: branches/HeuristicLab.Mono/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/HoeffdingsDependenceCalculator.cs
===================================================================
--- branches/HeuristicLab.Mono/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/HoeffdingsDependenceCalculator.cs	(revision 8440)
+++ branches/HeuristicLab.Mono/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/HoeffdingsDependenceCalculator.cs	(revision 8585)
@@ -23,5 +23,4 @@
 using System.Collections.Generic;
 using System.Linq;
-using HeuristicLab.Common;
 
 namespace HeuristicLab.Problems.DataAnalysis {
Index: branches/HeuristicLab.Mono/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/SpearmansRankCorrelationCoefficientCalculator.cs
===================================================================
--- branches/HeuristicLab.Mono/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/SpearmansRankCorrelationCoefficientCalculator.cs	(revision 8585)
+++ branches/HeuristicLab.Mono/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/SpearmansRankCorrelationCoefficientCalculator.cs	(revision 8585)
@@ -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.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 = alglib.basestat.spearmancorr2(originalValues.ToArray(), estimatedValues.ToArray(), originalValues.Count());
+      errorState = OnlineCalculatorError.None;
+      return rs;
+    }
+  }
+}
Index: branches/HeuristicLab.Mono/HeuristicLab.Problems.DataAnalysis/3.4/Plugin.cs.frame
===================================================================
--- branches/HeuristicLab.Mono/HeuristicLab.Problems.DataAnalysis/3.4/Plugin.cs.frame	(revision 8440)
+++ branches/HeuristicLab.Mono/HeuristicLab.Problems.DataAnalysis/3.4/Plugin.cs.frame	(revision 8585)
@@ -28,4 +28,5 @@
   [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")]
