Index: branches/MemPRAlgorithm/HeuristicLab 3.3.sln
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab 3.3.sln	(revision 14557)
+++ branches/MemPRAlgorithm/HeuristicLab 3.3.sln	(revision 14562)
@@ -131,5 +131,4 @@
 		{79271BC8-4446-40E2-BB89-9BE4E17174FE} = {79271BC8-4446-40E2-BB89-9BE4E17174FE}
 		{BBF2CCC8-4D87-4297-8E18-8241FF93F966} = {BBF2CCC8-4D87-4297-8E18-8241FF93F966}
-		{166507C9-EF26-4370-BB80-699742A29D4F} = {166507C9-EF26-4370-BB80-699742A29D4F}
 		{59F354CB-FE13-4253-AED2-AD86372BEC27} = {59F354CB-FE13-4253-AED2-AD86372BEC27}
 		{4B76E2CB-A990-4959-B080-1D81D418D325} = {4B76E2CB-A990-4959-B080-1D81D418D325}
@@ -423,4 +422,6 @@
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HeuristicLab.Algorithms.CMAEvolutionStrategy-3.4", "HeuristicLab.Algorithms.CMAEvolutionStrategy\3.4\HeuristicLab.Algorithms.CMAEvolutionStrategy-3.4.csproj", "{291010E4-2F4E-4D29-A795-753CFF293FDB}"
 EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HeuristicLab.Encodings.LinearLinkageEncoding-3.4", "HeuristicLab.Encodings.LinearLinkageEncoding\3.4\HeuristicLab.Encodings.LinearLinkageEncoding-3.4.csproj", "{BE698769-975A-429E-828C-72BB2B6182C8}"
+EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HeuristicLab.Problems.Orienteering-3.3", "HeuristicLab.Problems.Orienteering\3.3\HeuristicLab.Problems.Orienteering-3.3.csproj", "{D1EFA4CC-909F-41D5-9C1F-C3AF1957A372}"
 EndProject
@@ -456,6 +457,4 @@
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HeuristicLab.Problems.Instances.DIMACS-3.3", "HeuristicLab.Problems.Instances.DIMACS\3.3\HeuristicLab.Problems.Instances.DIMACS-3.3.csproj", "{9943FF23-8619-459C-B84A-E7FBDCBA04E6}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HeuristicLab.Encodings.LinearLinkageEncoding-3.4", "HeuristicLab.Encodings.LinearLinkageEncoding\3.4\HeuristicLab.Encodings.LinearLinkageEncoding-3.4.csproj", "{166507C9-EF26-4370-BB80-699742A29D4F}"
 EndProject
 Global
@@ -2017,4 +2016,16 @@
 		{291010E4-2F4E-4D29-A795-753CFF293FDB}.Release|x86.ActiveCfg = Release|x86
 		{291010E4-2F4E-4D29-A795-753CFF293FDB}.Release|x86.Build.0 = Release|x86
+		{BE698769-975A-429E-828C-72BB2B6182C8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{BE698769-975A-429E-828C-72BB2B6182C8}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{BE698769-975A-429E-828C-72BB2B6182C8}.Debug|x64.ActiveCfg = Debug|x64
+		{BE698769-975A-429E-828C-72BB2B6182C8}.Debug|x64.Build.0 = Debug|x64
+		{BE698769-975A-429E-828C-72BB2B6182C8}.Debug|x86.ActiveCfg = Debug|x86
+		{BE698769-975A-429E-828C-72BB2B6182C8}.Debug|x86.Build.0 = Debug|x86
+		{BE698769-975A-429E-828C-72BB2B6182C8}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{BE698769-975A-429E-828C-72BB2B6182C8}.Release|Any CPU.Build.0 = Release|Any CPU
+		{BE698769-975A-429E-828C-72BB2B6182C8}.Release|x64.ActiveCfg = Release|x64
+		{BE698769-975A-429E-828C-72BB2B6182C8}.Release|x64.Build.0 = Release|x64
+		{BE698769-975A-429E-828C-72BB2B6182C8}.Release|x86.ActiveCfg = Release|x86
+		{BE698769-975A-429E-828C-72BB2B6182C8}.Release|x86.Build.0 = Release|x86
 		{D1EFA4CC-909F-41D5-9C1F-C3AF1957A372}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 		{D1EFA4CC-909F-41D5-9C1F-C3AF1957A372}.Debug|Any CPU.Build.0 = Debug|Any CPU
@@ -2221,16 +2232,4 @@
 		{9943FF23-8619-459C-B84A-E7FBDCBA04E6}.Release|x86.ActiveCfg = Release|Any CPU
 		{9943FF23-8619-459C-B84A-E7FBDCBA04E6}.Release|x86.Build.0 = Release|Any CPU
-		{166507C9-EF26-4370-BB80-699742A29D4F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{166507C9-EF26-4370-BB80-699742A29D4F}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{166507C9-EF26-4370-BB80-699742A29D4F}.Debug|x64.ActiveCfg = Debug|x64
-		{166507C9-EF26-4370-BB80-699742A29D4F}.Debug|x64.Build.0 = Debug|x64
-		{166507C9-EF26-4370-BB80-699742A29D4F}.Debug|x86.ActiveCfg = Debug|x86
-		{166507C9-EF26-4370-BB80-699742A29D4F}.Debug|x86.Build.0 = Debug|x86
-		{166507C9-EF26-4370-BB80-699742A29D4F}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{166507C9-EF26-4370-BB80-699742A29D4F}.Release|Any CPU.Build.0 = Release|Any CPU
-		{166507C9-EF26-4370-BB80-699742A29D4F}.Release|x64.ActiveCfg = Release|x64
-		{166507C9-EF26-4370-BB80-699742A29D4F}.Release|x64.Build.0 = Release|x64
-		{166507C9-EF26-4370-BB80-699742A29D4F}.Release|x86.ActiveCfg = Release|x86
-		{166507C9-EF26-4370-BB80-699742A29D4F}.Release|x86.Build.0 = Release|x86
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
Index: branches/MemPRAlgorithm/HeuristicLab.Algorithms.DataAnalysis/3.4/BaselineClassifiers/OneR.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Algorithms.DataAnalysis/3.4/BaselineClassifiers/OneR.cs	(revision 14557)
+++ branches/MemPRAlgorithm/HeuristicLab.Algorithms.DataAnalysis/3.4/BaselineClassifiers/OneR.cs	(revision 14562)
@@ -22,4 +22,5 @@
 using System.Collections.Generic;
 using System.Linq;
+using System.Threading;
 using HeuristicLab.Common;
 using HeuristicLab.Core;
@@ -58,5 +59,5 @@
     }
 
-    protected override void Run() {
+    protected override void Run(CancellationToken cancellationToken) {
       var solution = CreateOneRSolution(Problem.ProblemData, MinBucketSizeParameter.Value.Value);
       Results.Add(new Result("OneR solution", "The 1R classifier.", solution));
Index: branches/MemPRAlgorithm/HeuristicLab.Algorithms.DataAnalysis/3.4/BaselineClassifiers/ZeroR.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Algorithms.DataAnalysis/3.4/BaselineClassifiers/ZeroR.cs	(revision 14557)
+++ branches/MemPRAlgorithm/HeuristicLab.Algorithms.DataAnalysis/3.4/BaselineClassifiers/ZeroR.cs	(revision 14562)
@@ -21,4 +21,5 @@
 
 using System.Linq;
+using System.Threading;
 using HeuristicLab.Common;
 using HeuristicLab.Core;
@@ -49,5 +50,5 @@
     }
 
-    protected override void Run() {
+    protected override void Run(CancellationToken cancellationToken) {
       var solution = CreateZeroRSolution(Problem.ProblemData);
       Results.Add(new Result("ZeroR solution", "The simplest possible classifier, ZeroR always predicts the majority class.", solution));
Index: branches/MemPRAlgorithm/HeuristicLab.Algorithms.DataAnalysis/3.4/FixedDataAnalysisAlgorithm.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Algorithms.DataAnalysis/3.4/FixedDataAnalysisAlgorithm.cs	(revision 14557)
+++ branches/MemPRAlgorithm/HeuristicLab.Algorithms.DataAnalysis/3.4/FixedDataAnalysisAlgorithm.cs	(revision 14562)
@@ -21,6 +21,4 @@
 
 using System;
-using System.Threading;
-using System.Threading.Tasks;
 using HeuristicLab.Common;
 using HeuristicLab.Optimization;
@@ -30,10 +28,5 @@
 namespace HeuristicLab.Algorithms.DataAnalysis {
   [StorableClass]
-  public abstract class FixedDataAnalysisAlgorithm<T> : Algorithm,
-    IDataAnalysisAlgorithm<T>,
-    IStorableContent
-    where T : class, IDataAnalysisProblem {
-    public string Filename { get; set; }
-
+  public abstract class FixedDataAnalysisAlgorithm<T> : BasicAlgorithm where T : class, IDataAnalysisProblem {
     #region Properties
     public override Type ProblemType {
@@ -44,87 +37,12 @@
       set { base.Problem = value; }
     }
-    [Storable]
-    private ResultCollection results;
-    public override ResultCollection Results {
-      get { return results; }
-    }
     #endregion
 
-    private DateTime lastUpdateTime;
+    public override bool SupportsPause { get { return false; } }
 
     [StorableConstructor]
     protected FixedDataAnalysisAlgorithm(bool deserializing) : base(deserializing) { }
-    protected FixedDataAnalysisAlgorithm(FixedDataAnalysisAlgorithm<T> original, Cloner cloner)
-      : base(original, cloner) {
-      results = cloner.Clone(original.Results);
-    }
-    public FixedDataAnalysisAlgorithm()
-      : base() {
-      results = new ResultCollection();
-    }
-
-    public override void Prepare() {
-      if (Problem != null) base.Prepare();
-      results.Clear();
-      OnPrepared();
-    }
-
-    public override void Start() {
-      base.Start();
-      var cancellationTokenSource = new CancellationTokenSource();
-
-      OnStarted();
-      Task task = Task.Factory.StartNew(Run, cancellationTokenSource.Token, cancellationTokenSource.Token);
-      task.ContinueWith(t => {
-        try {
-          t.Wait();
-        }
-        catch (AggregateException ex) {
-          try {
-            ex.Flatten().Handle(x => x is OperationCanceledException);
-          }
-          catch (AggregateException remaining) {
-            if (remaining.InnerExceptions.Count == 1) OnExceptionOccurred(remaining.InnerExceptions[0]);
-            else OnExceptionOccurred(remaining);
-          }
-        }
-        cancellationTokenSource.Dispose();
-        cancellationTokenSource = null;
-        OnStopped();
-      });
-    }
-    private void Run(object state) {
-      CancellationToken cancellationToken = (CancellationToken)state;
-      lastUpdateTime = DateTime.UtcNow;
-      System.Timers.Timer timer = new System.Timers.Timer(250);
-      timer.AutoReset = true;
-      timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed);
-      timer.Start();
-      try {
-        Run();
-      }
-      finally {
-        timer.Elapsed -= new System.Timers.ElapsedEventHandler(timer_Elapsed);
-        timer.Stop();
-        ExecutionTime += DateTime.UtcNow - lastUpdateTime;
-      }
-
-      cancellationToken.ThrowIfCancellationRequested();
-    }
-    protected abstract void Run();
-    #region Events
-    protected override void OnProblemChanged() {
-      Problem.Reset += new EventHandler(Problem_Reset);
-      base.OnProblemChanged();
-    }
-    private void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) {
-      System.Timers.Timer timer = (System.Timers.Timer)sender;
-      timer.Enabled = false;
-      DateTime now = DateTime.UtcNow;
-      ExecutionTime += now - lastUpdateTime;
-      lastUpdateTime = now;
-      timer.Enabled = true;
-    }
-    #endregion
+    protected FixedDataAnalysisAlgorithm(FixedDataAnalysisAlgorithm<T> original, Cloner cloner) : base(original, cloner) { }
+    public FixedDataAnalysisAlgorithm() : base() { }
 
   }
Index: branches/MemPRAlgorithm/HeuristicLab.Algorithms.DataAnalysis/3.4/GBM/GradientBoostingRegressionAlgorithm.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Algorithms.DataAnalysis/3.4/GBM/GradientBoostingRegressionAlgorithm.cs	(revision 14557)
+++ branches/MemPRAlgorithm/HeuristicLab.Algorithms.DataAnalysis/3.4/GBM/GradientBoostingRegressionAlgorithm.cs	(revision 14562)
@@ -44,13 +44,5 @@
   [StorableClass]
   [Creatable(CreatableAttribute.Categories.DataAnalysisRegression, Priority = 350)]
-  public class GradientBoostingRegressionAlgorithm : BasicAlgorithm {
-    public override Type ProblemType {
-      get { return typeof(IRegressionProblem); }
-    }
-
-    public new IRegressionProblem Problem {
-      get { return (IRegressionProblem)base.Problem; }
-      set { base.Problem = value; }
-    }
+  public class GradientBoostingRegressionAlgorithm : FixedDataAnalysisAlgorithm<IRegressionProblem> {
 
     #region ParameterNames
Index: branches/MemPRAlgorithm/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/GaussianProcessBase.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/GaussianProcessBase.cs	(revision 14557)
+++ branches/MemPRAlgorithm/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/GaussianProcessBase.cs	(revision 14562)
@@ -21,4 +21,5 @@
 #endregion
 
+using System.Linq;
 using HeuristicLab.Algorithms.GradientDescent;
 using HeuristicLab.Common;
@@ -119,6 +120,6 @@
 
       // necessary for BFGS
-      Parameters.Add(new ValueParameter<BoolValue>("Maximization", new BoolValue(false)));
-      Parameters["Maximization"].Hidden = true;
+      Parameters.Add(new FixedValueParameter<BoolValue>("Maximization (BFGS)", new BoolValue(false)));
+      Parameters["Maximization (BFGS)"].Hidden = true;
 
       var randomCreator = new HeuristicLab.Random.RandomCreator();
@@ -164,4 +165,5 @@
       modelCreator.Successor = updateResults;
 
+      updateResults.MaximizationParameter.ActualName = "Maximization (BFGS)";
       updateResults.StateParameter.ActualName = bfgsInitializer.StateParameter.Name;
       updateResults.QualityParameter.ActualName = NegativeLogLikelihoodParameterName;
@@ -197,7 +199,12 @@
       // BackwardsCompatibility3.4
       #region Backwards compatible code, remove with 3.5
-      if (!Parameters.ContainsKey("Maximization")) {
-        Parameters.Add(new ValueParameter<BoolValue>("Maximization", new BoolValue(false)));
-        Parameters["Maximization"].Hidden = true;
+      if (Parameters.ContainsKey("Maximization")) {
+        Parameters.Remove("Maximization");
+      }
+
+      if (!Parameters.ContainsKey("Maximization (BFGS)")) {
+        Parameters.Add(new FixedValueParameter<BoolValue>("Maximization (BFGS)", new BoolValue(false)));
+        Parameters["Maximization (BFGS)"].Hidden = true;
+        OperatorGraph.Operators.OfType<LbfgsUpdateResults>().First().MaximizationParameter.ActualName = "Maximization BFGS";
       }
 
Index: branches/MemPRAlgorithm/HeuristicLab.Algorithms.DataAnalysis/3.4/GradientBoostedTrees/GradientBoostedTreesAlgorithm.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Algorithms.DataAnalysis/3.4/GradientBoostedTrees/GradientBoostedTreesAlgorithm.cs	(revision 14557)
+++ branches/MemPRAlgorithm/HeuristicLab.Algorithms.DataAnalysis/3.4/GradientBoostedTrees/GradientBoostedTreesAlgorithm.cs	(revision 14562)
@@ -38,13 +38,5 @@
   [StorableClass]
   [Creatable(CreatableAttribute.Categories.DataAnalysisRegression, Priority = 125)]
-  public class GradientBoostedTreesAlgorithm : BasicAlgorithm {
-    public override Type ProblemType {
-      get { return typeof(IRegressionProblem); }
-    }
-    public new IRegressionProblem Problem {
-      get { return (IRegressionProblem)base.Problem; }
-      set { base.Problem = value; }
-    }
-
+  public class GradientBoostedTreesAlgorithm : FixedDataAnalysisAlgorithm<IRegressionProblem> {
     #region ParameterNames
     private const string IterationsParameterName = "Iterations";
Index: branches/MemPRAlgorithm/HeuristicLab.Algorithms.DataAnalysis/3.4/Linear/LinearDiscriminantAnalysis.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Algorithms.DataAnalysis/3.4/Linear/LinearDiscriminantAnalysis.cs	(revision 14557)
+++ branches/MemPRAlgorithm/HeuristicLab.Algorithms.DataAnalysis/3.4/Linear/LinearDiscriminantAnalysis.cs	(revision 14562)
@@ -23,4 +23,5 @@
 using System.Collections.Generic;
 using System.Linq;
+using System.Threading;
 using HeuristicLab.Common;
 using HeuristicLab.Core;
@@ -59,5 +60,5 @@
 
     #region Fisher LDA
-    protected override void Run() {
+    protected override void Run(CancellationToken cancellationToken) {
       var solution = CreateLinearDiscriminantAnalysisSolution(Problem.ProblemData);
       Results.Add(new Result(LinearDiscriminantAnalysisSolutionResultName, "The linear discriminant analysis.", solution));
Index: branches/MemPRAlgorithm/HeuristicLab.Algorithms.DataAnalysis/3.4/Linear/LinearRegression.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Algorithms.DataAnalysis/3.4/Linear/LinearRegression.cs	(revision 14557)
+++ branches/MemPRAlgorithm/HeuristicLab.Algorithms.DataAnalysis/3.4/Linear/LinearRegression.cs	(revision 14562)
@@ -23,4 +23,5 @@
 using System.Collections.Generic;
 using System.Linq;
+using System.Threading;
 using HeuristicLab.Common;
 using HeuristicLab.Core;
@@ -60,5 +61,5 @@
 
     #region linear regression
-    protected override void Run() {
+    protected override void Run(CancellationToken cancellationToken) {
       double rmsError, cvRmsError;
       var solution = CreateLinearRegressionSolution(Problem.ProblemData, out rmsError, out cvRmsError);
Index: branches/MemPRAlgorithm/HeuristicLab.Algorithms.DataAnalysis/3.4/Linear/MultinomialLogitClassification.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Algorithms.DataAnalysis/3.4/Linear/MultinomialLogitClassification.cs	(revision 14557)
+++ branches/MemPRAlgorithm/HeuristicLab.Algorithms.DataAnalysis/3.4/Linear/MultinomialLogitClassification.cs	(revision 14562)
@@ -23,4 +23,5 @@
 using System.Collections.Generic;
 using System.Linq;
+using System.Threading;
 using HeuristicLab.Common;
 using HeuristicLab.Core;
@@ -57,5 +58,5 @@
 
     #region logit classification
-    protected override void Run() {
+    protected override void Run(CancellationToken cancellationToken) {
       double rmsError, relClassError;
       var solution = CreateLogitClassificationSolution(Problem.ProblemData, out rmsError, out relClassError);
Index: branches/MemPRAlgorithm/HeuristicLab.Algorithms.DataAnalysis/3.4/MctsSymbolicRegression/MctsSymbolicRegressionAlgorithm.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Algorithms.DataAnalysis/3.4/MctsSymbolicRegression/MctsSymbolicRegressionAlgorithm.cs	(revision 14557)
+++ branches/MemPRAlgorithm/HeuristicLab.Algorithms.DataAnalysis/3.4/MctsSymbolicRegression/MctsSymbolicRegressionAlgorithm.cs	(revision 14562)
@@ -38,12 +38,5 @@
   [StorableClass]
   [Creatable(CreatableAttribute.Categories.DataAnalysisRegression, Priority = 250)]
-  public class MctsSymbolicRegressionAlgorithm : BasicAlgorithm {
-    public override Type ProblemType {
-      get { return typeof(IRegressionProblem); }
-    }
-    public new IRegressionProblem Problem {
-      get { return (IRegressionProblem)base.Problem; }
-      set { base.Problem = value; }
-    }
+  public class MctsSymbolicRegressionAlgorithm : FixedDataAnalysisAlgorithm<IRegressionProblem> {
 
     #region ParameterNames
Index: branches/MemPRAlgorithm/HeuristicLab.Algorithms.DataAnalysis/3.4/NearestNeighbour/NearestNeighbourClassification.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Algorithms.DataAnalysis/3.4/NearestNeighbour/NearestNeighbourClassification.cs	(revision 14557)
+++ branches/MemPRAlgorithm/HeuristicLab.Algorithms.DataAnalysis/3.4/NearestNeighbour/NearestNeighbourClassification.cs	(revision 14562)
@@ -22,4 +22,5 @@
 using System;
 using System.Linq;
+using System.Threading;
 using HeuristicLab.Common;
 using HeuristicLab.Core;
@@ -91,5 +92,5 @@
 
     #region nearest neighbour
-    protected override void Run() {
+    protected override void Run(CancellationToken cancellationToken) {
       double[] weights = null;
       if (Weights != null) weights = Weights.CloneAsArray();
Index: branches/MemPRAlgorithm/HeuristicLab.Algorithms.DataAnalysis/3.4/NearestNeighbour/NearestNeighbourRegression.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Algorithms.DataAnalysis/3.4/NearestNeighbour/NearestNeighbourRegression.cs	(revision 14557)
+++ branches/MemPRAlgorithm/HeuristicLab.Algorithms.DataAnalysis/3.4/NearestNeighbour/NearestNeighbourRegression.cs	(revision 14562)
@@ -21,4 +21,5 @@
 
 using System;
+using System.Threading;
 using HeuristicLab.Common;
 using HeuristicLab.Core;
@@ -92,5 +93,5 @@
 
     #region nearest neighbour
-    protected override void Run() {
+    protected override void Run(CancellationToken cancellationToken) {
       double[] weights = null;
       if (Weights != null) weights = Weights.CloneAsArray();
Index: branches/MemPRAlgorithm/HeuristicLab.Algorithms.DataAnalysis/3.4/NeuralNetwork/NeuralNetworkClassification.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Algorithms.DataAnalysis/3.4/NeuralNetwork/NeuralNetworkClassification.cs	(revision 14557)
+++ branches/MemPRAlgorithm/HeuristicLab.Algorithms.DataAnalysis/3.4/NeuralNetwork/NeuralNetworkClassification.cs	(revision 14562)
@@ -23,4 +23,5 @@
 using System.Collections.Generic;
 using System.Linq;
+using System.Threading;
 using HeuristicLab.Common;
 using HeuristicLab.Core;
@@ -168,5 +169,5 @@
 
     #region neural network
-    protected override void Run() {
+    protected override void Run(CancellationToken cancellationToken) {
       double rmsError, avgRelError, relClassError;
       var solution = CreateNeuralNetworkClassificationSolution(Problem.ProblemData, HiddenLayers, NodesInFirstHiddenLayer, NodesInSecondHiddenLayer, Decay, Restarts, out rmsError, out avgRelError, out relClassError);
Index: branches/MemPRAlgorithm/HeuristicLab.Algorithms.DataAnalysis/3.4/NeuralNetwork/NeuralNetworkEnsembleClassification.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Algorithms.DataAnalysis/3.4/NeuralNetwork/NeuralNetworkEnsembleClassification.cs	(revision 14557)
+++ branches/MemPRAlgorithm/HeuristicLab.Algorithms.DataAnalysis/3.4/NeuralNetwork/NeuralNetworkEnsembleClassification.cs	(revision 14562)
@@ -23,4 +23,5 @@
 using System.Collections.Generic;
 using System.Linq;
+using System.Threading;
 using HeuristicLab.Common;
 using HeuristicLab.Core;
@@ -154,5 +155,5 @@
 
     #region neural network ensemble
-    protected override void Run() {
+    protected override void Run(CancellationToken cancellationToken) {
       double rmsError, avgRelError, relClassError;
       var solution = CreateNeuralNetworkEnsembleClassificationSolution(Problem.ProblemData, EnsembleSize, HiddenLayers, NodesInFirstHiddenLayer, NodesInSecondHiddenLayer, Decay, Restarts, out rmsError, out avgRelError, out relClassError);
Index: branches/MemPRAlgorithm/HeuristicLab.Algorithms.DataAnalysis/3.4/NeuralNetwork/NeuralNetworkEnsembleRegression.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Algorithms.DataAnalysis/3.4/NeuralNetwork/NeuralNetworkEnsembleRegression.cs	(revision 14557)
+++ branches/MemPRAlgorithm/HeuristicLab.Algorithms.DataAnalysis/3.4/NeuralNetwork/NeuralNetworkEnsembleRegression.cs	(revision 14562)
@@ -23,4 +23,5 @@
 using System.Collections.Generic;
 using System.Linq;
+using System.Threading;
 using HeuristicLab.Common;
 using HeuristicLab.Core;
@@ -154,5 +155,5 @@
 
     #region neural network ensemble
-    protected override void Run() {
+    protected override void Run(CancellationToken cancellationToken) {
       double rmsError, avgRelError;
       var solution = CreateNeuralNetworkEnsembleRegressionSolution(Problem.ProblemData, EnsembleSize, HiddenLayers, NodesInFirstHiddenLayer, NodesInSecondHiddenLayer, Decay, Restarts, out rmsError, out avgRelError);
Index: branches/MemPRAlgorithm/HeuristicLab.Algorithms.DataAnalysis/3.4/NeuralNetwork/NeuralNetworkRegression.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Algorithms.DataAnalysis/3.4/NeuralNetwork/NeuralNetworkRegression.cs	(revision 14557)
+++ branches/MemPRAlgorithm/HeuristicLab.Algorithms.DataAnalysis/3.4/NeuralNetwork/NeuralNetworkRegression.cs	(revision 14562)
@@ -23,4 +23,5 @@
 using System.Collections.Generic;
 using System.Linq;
+using System.Threading;
 using HeuristicLab.Common;
 using HeuristicLab.Core;
@@ -170,5 +171,5 @@
 
     #region neural network
-    protected override void Run() {
+    protected override void Run(CancellationToken cancellationToken) {
       double rmsError, avgRelError;
       var solution = CreateNeuralNetworkRegressionSolution(Problem.ProblemData, HiddenLayers, NodesInFirstHiddenLayer, NodesInSecondHiddenLayer, Decay, Restarts, out rmsError, out avgRelError);
Index: branches/MemPRAlgorithm/HeuristicLab.Algorithms.DataAnalysis/3.4/NonlinearRegression/NonlinearRegression.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Algorithms.DataAnalysis/3.4/NonlinearRegression/NonlinearRegression.cs	(revision 14557)
+++ branches/MemPRAlgorithm/HeuristicLab.Algorithms.DataAnalysis/3.4/NonlinearRegression/NonlinearRegression.cs	(revision 14562)
@@ -22,4 +22,5 @@
 using System;
 using System.Linq;
+using System.Threading;
 using HeuristicLab.Analysis;
 using HeuristicLab.Common;
@@ -157,5 +158,5 @@
 
     #region nonlinear regression
-    protected override void Run() {
+    protected override void Run(CancellationToken cancellationToken) {
       IRegressionSolution bestSolution = null;
       if (InitializeParametersRandomly) {
Index: branches/MemPRAlgorithm/HeuristicLab.Algorithms.DataAnalysis/3.4/RandomForest/RandomForestClassification.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Algorithms.DataAnalysis/3.4/RandomForest/RandomForestClassification.cs	(revision 14557)
+++ branches/MemPRAlgorithm/HeuristicLab.Algorithms.DataAnalysis/3.4/RandomForest/RandomForestClassification.cs	(revision 14562)
@@ -20,4 +20,5 @@
 #endregion
 
+using System.Threading;
 using HeuristicLab.Common;
 using HeuristicLab.Core;
@@ -132,5 +133,5 @@
 
     #region random forest
-    protected override void Run() {
+    protected override void Run(CancellationToken cancellationToken) {
       double rmsError, relClassificationError, outOfBagRmsError, outOfBagRelClassificationError;
       if (SetSeedRandomly) Seed = new System.Random().Next();
Index: branches/MemPRAlgorithm/HeuristicLab.Algorithms.DataAnalysis/3.4/RandomForest/RandomForestRegression.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Algorithms.DataAnalysis/3.4/RandomForest/RandomForestRegression.cs	(revision 14557)
+++ branches/MemPRAlgorithm/HeuristicLab.Algorithms.DataAnalysis/3.4/RandomForest/RandomForestRegression.cs	(revision 14562)
@@ -20,4 +20,5 @@
 #endregion
 
+using System.Threading;
 using HeuristicLab.Common;
 using HeuristicLab.Core;
@@ -131,5 +132,5 @@
 
     #region random forest
-    protected override void Run() {
+    protected override void Run(CancellationToken cancellationToken) {
       double rmsError, avgRelError, outOfBagRmsError, outOfBagAvgRelError;
       if (SetSeedRandomly) Seed = new System.Random().Next();
Index: branches/MemPRAlgorithm/HeuristicLab.Algorithms.DataAnalysis/3.4/SupportVectorMachine/SupportVectorClassification.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Algorithms.DataAnalysis/3.4/SupportVectorMachine/SupportVectorClassification.cs	(revision 14557)
+++ branches/MemPRAlgorithm/HeuristicLab.Algorithms.DataAnalysis/3.4/SupportVectorMachine/SupportVectorClassification.cs	(revision 14562)
@@ -23,4 +23,5 @@
 using System.Collections.Generic;
 using System.Linq;
+using System.Threading;
 using HeuristicLab.Common;
 using HeuristicLab.Core;
@@ -143,5 +144,5 @@
 
     #region support vector classification
-    protected override void Run() {
+    protected override void Run(CancellationToken cancellationToken) {
       IClassificationProblemData problemData = Problem.ProblemData;
       IEnumerable<string> selectedInputVariables = problemData.AllowedInputVariables;
Index: branches/MemPRAlgorithm/HeuristicLab.Algorithms.DataAnalysis/3.4/SupportVectorMachine/SupportVectorRegression.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Algorithms.DataAnalysis/3.4/SupportVectorMachine/SupportVectorRegression.cs	(revision 14557)
+++ branches/MemPRAlgorithm/HeuristicLab.Algorithms.DataAnalysis/3.4/SupportVectorMachine/SupportVectorRegression.cs	(revision 14562)
@@ -23,4 +23,5 @@
 using System.Collections.Generic;
 using System.Linq;
+using System.Threading;
 using HeuristicLab.Common;
 using HeuristicLab.Core;
@@ -151,5 +152,5 @@
 
     #region support vector regression
-    protected override void Run() {
+    protected override void Run(CancellationToken cancellationToken) {
       IRegressionProblemData problemData = Problem.ProblemData;
       IEnumerable<string> selectedInputVariables = problemData.AllowedInputVariables;
Index: branches/MemPRAlgorithm/HeuristicLab.Algorithms.DataAnalysis/3.4/TimeSeries/AutoregressiveModeling.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Algorithms.DataAnalysis/3.4/TimeSeries/AutoregressiveModeling.cs	(revision 14557)
+++ branches/MemPRAlgorithm/HeuristicLab.Algorithms.DataAnalysis/3.4/TimeSeries/AutoregressiveModeling.cs	(revision 14562)
@@ -22,4 +22,5 @@
 using System;
 using System.Linq;
+using System.Threading;
 using HeuristicLab.Common;
 using HeuristicLab.Core;
@@ -63,5 +64,5 @@
     }
 
-    protected override void Run() {
+    protected override void Run(CancellationToken cancellationToken) {
       double rmsError, cvRmsError;
       var solution = CreateAutoRegressiveSolution(Problem.ProblemData, TimeOffset, out rmsError, out cvRmsError);
Index: branches/MemPRAlgorithm/HeuristicLab.Algorithms.DataAnalysis/3.4/kMeans/KMeansClustering.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Algorithms.DataAnalysis/3.4/kMeans/KMeansClustering.cs	(revision 14557)
+++ branches/MemPRAlgorithm/HeuristicLab.Algorithms.DataAnalysis/3.4/kMeans/KMeansClustering.cs	(revision 14562)
@@ -23,4 +23,5 @@
 using System.Collections.Generic;
 using System.Linq;
+using System.Threading;
 using HeuristicLab.Common;
 using HeuristicLab.Core;
@@ -77,5 +78,5 @@
 
     #region k-Means clustering
-    protected override void Run() {
+    protected override void Run(CancellationToken cancellationToken) {
       var solution = CreateKMeansSolution(Problem.ProblemData, K.Value, Restarts.Value);
       Results.Add(new Result(KMeansSolutionResultName, "The k-Means clustering solution.", solution));
Index: branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/MemPRAlgorithm.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/MemPRAlgorithm.cs	(revision 14557)
+++ branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/MemPRAlgorithm.cs	(revision 14562)
@@ -51,4 +51,8 @@
       get { return (TProblem)base.Problem; }
       set { base.Problem = value; }
+    }
+
+    public override bool SupportsPause {
+      get { return true; }
     }
 
Index: branches/MemPRAlgorithm/HeuristicLab.Algorithms.ParameterlessPopulationPyramid/3.3/HillClimber.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Algorithms.ParameterlessPopulationPyramid/3.3/HillClimber.cs	(revision 14557)
+++ branches/MemPRAlgorithm/HeuristicLab.Algorithms.ParameterlessPopulationPyramid/3.3/HillClimber.cs	(revision 14562)
@@ -48,8 +48,13 @@
 
     private const string IterationsParameterName = "Iterations";
+    private const string BestQualityResultName = "Best quality";
+    private const string IterationsResultName = "Iterations";
 
     public override Type ProblemType {
       get { return typeof(BinaryProblem); }
     }
+
+    public override bool SupportsPause { get { return false; } }
+
     public new BinaryProblem Problem {
       get { return (BinaryProblem)base.Problem; }
@@ -65,4 +70,15 @@
       set { IterationsParameter.Value.Value = value; }
     }
+
+    #region ResultsProperties
+    private double ResultsBestQuality {
+      get { return ((DoubleValue)Results[BestQualityResultName].Value).Value; }
+      set { ((DoubleValue)Results[BestQualityResultName].Value).Value = value; }
+    }
+    private int ResultsIterations {
+      get { return ((IntValue)Results[IterationsResultName].Value).Value; }
+      set { ((IntValue)Results[IterationsResultName].Value).Value = value; }
+    }
+    #endregion
 
     [StorableConstructor]
@@ -80,8 +96,15 @@
       Parameters.Add(new FixedValueParameter<IntValue>(IterationsParameterName, "", new IntValue(100)));
     }
+
+
+    protected override void Initialize(CancellationToken cancellationToken) {
+      Results.Add(new Result(BestQualityResultName, new DoubleValue(double.NaN)));
+      Results.Add(new Result(IterationsResultName, new IntValue(0)));
+      base.Initialize(cancellationToken);
+    }
     protected override void Run(CancellationToken cancellationToken) {
-      var BestQuality = new DoubleValue(double.NaN);
-      Results.Add(new Result("Best quality", BestQuality));
-      for (int iteration = 0; iteration < Iterations; iteration++) {
+      while (ResultsIterations < Iterations) {
+        cancellationToken.ThrowIfCancellationRequested();
+
         var solution = new BinaryVector(Problem.Length);
         for (int i = 0; i < solution.Length; i++) {
@@ -92,7 +115,9 @@
 
         fitness = ImproveToLocalOptimum(Problem, solution, fitness, random);
-        if (double.IsNaN(BestQuality.Value) || Problem.IsBetter(fitness, BestQuality.Value)) {
-          BestQuality.Value = fitness;
+        if (double.IsNaN(ResultsBestQuality) || Problem.IsBetter(fitness, ResultsBestQuality)) {
+          ResultsBestQuality = fitness;
         }
+
+        ResultsIterations++;
       }
     }
Index: branches/MemPRAlgorithm/HeuristicLab.Algorithms.ParameterlessPopulationPyramid/3.3/ParameterlessPopulationPyramid.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Algorithms.ParameterlessPopulationPyramid/3.3/ParameterlessPopulationPyramid.cs	(revision 14557)
+++ branches/MemPRAlgorithm/HeuristicLab.Algorithms.ParameterlessPopulationPyramid/3.3/ParameterlessPopulationPyramid.cs	(revision 14562)
@@ -56,5 +56,5 @@
 
     // Tracks all solutions in Pyramid for quick membership checks
-    private HashSet<BinaryVector> seen = new HashSet<BinaryVector>(new EnumerableBoolEqualityComparer());
+    private readonly HashSet<BinaryVector> seen = new HashSet<BinaryVector>(new EnumerableBoolEqualityComparer());
 
     #region ParameterNames
@@ -152,4 +152,6 @@
     }
     #endregion
+
+    public override bool SupportsPause { get { return true; } }
 
     [StorableConstructor]
@@ -213,5 +215,5 @@
     }
 
-    protected override void Run(CancellationToken cancellationToken) {
+    protected override void Initialize(CancellationToken cancellationToken) {
       // Set up the algorithm
       if (SetSeedRandomly) Seed = new System.Random().Next();
@@ -242,10 +244,15 @@
       Results.Add(new Result("Stored Solutions", table));
 
+      base.Initialize(cancellationToken);
+    }
+
+    protected override void Run(CancellationToken cancellationToken) {
       // Loop until iteration limit reached or canceled.
-      for (ResultsIterations = 0; ResultsIterations < MaximumIterations; ResultsIterations++) {
+      while (ResultsIterations < MaximumIterations) {
         double fitness = double.NaN;
 
         try {
           fitness = iterate();
+          ResultsIterations++;
           cancellationToken.ThrowIfCancellationRequested();
         } finally {
Index: branches/MemPRAlgorithm/HeuristicLab.Analysis.Views/3.3/DataRowVisualPropertiesControl.Designer.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Analysis.Views/3.3/DataRowVisualPropertiesControl.Designer.cs	(revision 14557)
+++ branches/MemPRAlgorithm/HeuristicLab.Analysis.Views/3.3/DataRowVisualPropertiesControl.Designer.cs	(revision 14562)
@@ -54,11 +54,15 @@
       this.label3 = new System.Windows.Forms.Label();
       this.commonGroupBox = new System.Windows.Forms.GroupBox();
+      this.isVisibleInLegendCheckBox = new System.Windows.Forms.CheckBox();
+      this.label10 = new System.Windows.Forms.Label();
       this.displayNameTextBox = new System.Windows.Forms.TextBox();
       this.axisGroupBox = new System.Windows.Forms.GroupBox();
+      this.panel2 = new System.Windows.Forms.Panel();
       this.yAxisSecondaryRadioButton = new System.Windows.Forms.RadioButton();
+      this.yAxisPrimaryRadioButton = new System.Windows.Forms.RadioButton();
+      this.panel1 = new System.Windows.Forms.Panel();
       this.xAxisPrimaryRadioButton = new System.Windows.Forms.RadioButton();
-      this.yAxisPrimaryRadioButton = new System.Windows.Forms.RadioButton();
+      this.xAxisSecondaryRadioButton = new System.Windows.Forms.RadioButton();
       this.label5 = new System.Windows.Forms.Label();
-      this.xAxisSecondaryRadioButton = new System.Windows.Forms.RadioButton();
       this.label6 = new System.Windows.Forms.Label();
       this.label9 = new System.Windows.Forms.Label();
@@ -72,14 +76,12 @@
       this.lineStyleComboBox = new System.Windows.Forms.ComboBox();
       this.label8 = new System.Windows.Forms.Label();
-      this.panel1 = new System.Windows.Forms.Panel();
-      this.panel2 = new System.Windows.Forms.Panel();
       ((System.ComponentModel.ISupportInitialize)(this.binsNumericUpDown)).BeginInit();
       this.commonGroupBox.SuspendLayout();
       this.axisGroupBox.SuspendLayout();
+      this.panel2.SuspendLayout();
+      this.panel1.SuspendLayout();
       this.histoGramGroupBox.SuspendLayout();
       this.lineChartGroupBox.SuspendLayout();
       ((System.ComponentModel.ISupportInitialize)(this.lineWidthNumericUpDown)).BeginInit();
-      this.panel1.SuspendLayout();
-      this.panel2.SuspendLayout();
       this.SuspendLayout();
       // 
@@ -90,7 +92,7 @@
       this.chartTypeComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
       this.chartTypeComboBox.FormattingEnabled = true;
-      this.chartTypeComboBox.Location = new System.Drawing.Point(57, 45);
+      this.chartTypeComboBox.Location = new System.Drawing.Point(102, 45);
       this.chartTypeComboBox.Name = "chartTypeComboBox";
-      this.chartTypeComboBox.Size = new System.Drawing.Size(264, 21);
+      this.chartTypeComboBox.Size = new System.Drawing.Size(219, 21);
       this.chartTypeComboBox.TabIndex = 3;
       this.chartTypeComboBox.SelectedValueChanged += new System.EventHandler(this.chartTypeComboBox_SelectedValueChanged);
@@ -103,5 +105,5 @@
       // 
       this.colorButton.BackColor = System.Drawing.SystemColors.Control;
-      this.colorButton.Location = new System.Drawing.Point(56, 72);
+      this.colorButton.Location = new System.Drawing.Point(102, 72);
       this.colorButton.Name = "colorButton";
       this.colorButton.Size = new System.Drawing.Size(23, 23);
@@ -172,4 +174,6 @@
       this.commonGroupBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
             | System.Windows.Forms.AnchorStyles.Right)));
+      this.commonGroupBox.Controls.Add(this.isVisibleInLegendCheckBox);
+      this.commonGroupBox.Controls.Add(this.label10);
       this.commonGroupBox.Controls.Add(this.displayNameTextBox);
       this.commonGroupBox.Controls.Add(this.axisGroupBox);
@@ -181,16 +185,36 @@
       this.commonGroupBox.Location = new System.Drawing.Point(0, 0);
       this.commonGroupBox.Name = "commonGroupBox";
-      this.commonGroupBox.Size = new System.Drawing.Size(327, 174);
+      this.commonGroupBox.Size = new System.Drawing.Size(327, 199);
       this.commonGroupBox.TabIndex = 0;
       this.commonGroupBox.TabStop = false;
       this.commonGroupBox.Text = "Common";
       // 
+      // isVisibleInLegendCheckBox
+      // 
+      this.isVisibleInLegendCheckBox.AutoSize = true;
+      this.isVisibleInLegendCheckBox.CheckAlign = System.Drawing.ContentAlignment.MiddleRight;
+      this.isVisibleInLegendCheckBox.Location = new System.Drawing.Point(102, 104);
+      this.isVisibleInLegendCheckBox.Name = "isVisibleInLegendCheckBox";
+      this.isVisibleInLegendCheckBox.Size = new System.Drawing.Size(15, 14);
+      this.isVisibleInLegendCheckBox.TabIndex = 8;
+      this.isVisibleInLegendCheckBox.UseVisualStyleBackColor = true;
+      this.isVisibleInLegendCheckBox.CheckedChanged += new System.EventHandler(this.isVisibleInLegendCheckBox_CheckedChanged);
+      // 
+      // label10
+      // 
+      this.label10.AutoSize = true;
+      this.label10.Location = new System.Drawing.Point(6, 104);
+      this.label10.Name = "label10";
+      this.label10.Size = new System.Drawing.Size(90, 13);
+      this.label10.TabIndex = 7;
+      this.label10.Text = "&Visible in Legend:";
+      // 
       // displayNameTextBox
       // 
       this.displayNameTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
             | System.Windows.Forms.AnchorStyles.Right)));
-      this.displayNameTextBox.Location = new System.Drawing.Point(57, 19);
+      this.displayNameTextBox.Location = new System.Drawing.Point(102, 19);
       this.displayNameTextBox.Name = "displayNameTextBox";
-      this.displayNameTextBox.Size = new System.Drawing.Size(264, 20);
+      this.displayNameTextBox.Size = new System.Drawing.Size(219, 20);
       this.displayNameTextBox.TabIndex = 1;
       this.displayNameTextBox.Validated += new System.EventHandler(this.displayNameTextBox_Validated);
@@ -205,5 +229,5 @@
       this.axisGroupBox.Controls.Add(this.label5);
       this.axisGroupBox.Controls.Add(this.label6);
-      this.axisGroupBox.Location = new System.Drawing.Point(6, 101);
+      this.axisGroupBox.Location = new System.Drawing.Point(6, 126);
       this.axisGroupBox.Name = "axisGroupBox";
       this.axisGroupBox.Size = new System.Drawing.Size(315, 67);
@@ -211,4 +235,15 @@
       this.axisGroupBox.TabStop = false;
       this.axisGroupBox.Text = "Axes";
+      // 
+      // panel2
+      // 
+      this.panel2.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
+            | System.Windows.Forms.AnchorStyles.Right)));
+      this.panel2.Controls.Add(this.yAxisSecondaryRadioButton);
+      this.panel2.Controls.Add(this.yAxisPrimaryRadioButton);
+      this.panel2.Location = new System.Drawing.Point(51, 42);
+      this.panel2.Name = "panel2";
+      this.panel2.Size = new System.Drawing.Size(258, 17);
+      this.panel2.TabIndex = 7;
       // 
       // yAxisSecondaryRadioButton
@@ -224,4 +259,27 @@
       this.yAxisSecondaryRadioButton.CheckedChanged += new System.EventHandler(this.yAxisRadioButton_CheckedChanged);
       // 
+      // yAxisPrimaryRadioButton
+      // 
+      this.yAxisPrimaryRadioButton.AutoSize = true;
+      this.yAxisPrimaryRadioButton.Location = new System.Drawing.Point(0, 0);
+      this.yAxisPrimaryRadioButton.Name = "yAxisPrimaryRadioButton";
+      this.yAxisPrimaryRadioButton.Size = new System.Drawing.Size(59, 17);
+      this.yAxisPrimaryRadioButton.TabIndex = 4;
+      this.yAxisPrimaryRadioButton.TabStop = true;
+      this.yAxisPrimaryRadioButton.Text = "&Primary";
+      this.yAxisPrimaryRadioButton.UseVisualStyleBackColor = true;
+      this.yAxisPrimaryRadioButton.CheckedChanged += new System.EventHandler(this.yAxisRadioButton_CheckedChanged);
+      // 
+      // panel1
+      // 
+      this.panel1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
+            | System.Windows.Forms.AnchorStyles.Right)));
+      this.panel1.Controls.Add(this.xAxisPrimaryRadioButton);
+      this.panel1.Controls.Add(this.xAxisSecondaryRadioButton);
+      this.panel1.Location = new System.Drawing.Point(51, 19);
+      this.panel1.Name = "panel1";
+      this.panel1.Size = new System.Drawing.Size(258, 17);
+      this.panel1.TabIndex = 6;
+      // 
       // xAxisPrimaryRadioButton
       // 
@@ -236,25 +294,4 @@
       this.xAxisPrimaryRadioButton.CheckedChanged += new System.EventHandler(this.xAxisRadioButton_CheckedChanged);
       // 
-      // yAxisPrimaryRadioButton
-      // 
-      this.yAxisPrimaryRadioButton.AutoSize = true;
-      this.yAxisPrimaryRadioButton.Location = new System.Drawing.Point(0, 0);
-      this.yAxisPrimaryRadioButton.Name = "yAxisPrimaryRadioButton";
-      this.yAxisPrimaryRadioButton.Size = new System.Drawing.Size(59, 17);
-      this.yAxisPrimaryRadioButton.TabIndex = 4;
-      this.yAxisPrimaryRadioButton.TabStop = true;
-      this.yAxisPrimaryRadioButton.Text = "&Primary";
-      this.yAxisPrimaryRadioButton.UseVisualStyleBackColor = true;
-      this.yAxisPrimaryRadioButton.CheckedChanged += new System.EventHandler(this.yAxisRadioButton_CheckedChanged);
-      // 
-      // label5
-      // 
-      this.label5.AutoSize = true;
-      this.label5.Location = new System.Drawing.Point(6, 44);
-      this.label5.Name = "label5";
-      this.label5.Size = new System.Drawing.Size(39, 13);
-      this.label5.TabIndex = 3;
-      this.label5.Text = "&Y-Axis:";
-      // 
       // xAxisSecondaryRadioButton
       // 
@@ -269,4 +306,13 @@
       this.xAxisSecondaryRadioButton.CheckedChanged += new System.EventHandler(this.xAxisRadioButton_CheckedChanged);
       // 
+      // label5
+      // 
+      this.label5.AutoSize = true;
+      this.label5.Location = new System.Drawing.Point(6, 44);
+      this.label5.Name = "label5";
+      this.label5.Size = new System.Drawing.Size(39, 13);
+      this.label5.TabIndex = 3;
+      this.label5.Text = "&Y-Axis:";
+      // 
       // label6
       // 
@@ -295,5 +341,5 @@
       this.histoGramGroupBox.Controls.Add(this.binsNumericUpDown);
       this.histoGramGroupBox.Controls.Add(this.label3);
-      this.histoGramGroupBox.Location = new System.Drawing.Point(0, 280);
+      this.histoGramGroupBox.Location = new System.Drawing.Point(0, 305);
       this.histoGramGroupBox.Name = "histoGramGroupBox";
       this.histoGramGroupBox.Size = new System.Drawing.Size(327, 47);
@@ -338,5 +384,5 @@
       this.lineChartGroupBox.Controls.Add(this.lineStyleComboBox);
       this.lineChartGroupBox.Controls.Add(this.label8);
-      this.lineChartGroupBox.Location = new System.Drawing.Point(0, 180);
+      this.lineChartGroupBox.Location = new System.Drawing.Point(0, 205);
       this.lineChartGroupBox.Name = "lineChartGroupBox";
       this.lineChartGroupBox.Size = new System.Drawing.Size(327, 94);
@@ -404,29 +450,6 @@
       this.label8.Text = "&Style:";
       // 
-      // panel1
-      // 
-      this.panel1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
-            | System.Windows.Forms.AnchorStyles.Right)));
-      this.panel1.Controls.Add(this.xAxisPrimaryRadioButton);
-      this.panel1.Controls.Add(this.xAxisSecondaryRadioButton);
-      this.panel1.Location = new System.Drawing.Point(51, 19);
-      this.panel1.Name = "panel1";
-      this.panel1.Size = new System.Drawing.Size(258, 17);
-      this.panel1.TabIndex = 6;
-      // 
-      // panel2
-      // 
-      this.panel2.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
-            | System.Windows.Forms.AnchorStyles.Right)));
-      this.panel2.Controls.Add(this.yAxisSecondaryRadioButton);
-      this.panel2.Controls.Add(this.yAxisPrimaryRadioButton);
-      this.panel2.Location = new System.Drawing.Point(51, 42);
-      this.panel2.Name = "panel2";
-      this.panel2.Size = new System.Drawing.Size(258, 17);
-      this.panel2.TabIndex = 7;
-      // 
       // DataRowVisualPropertiesControl
       // 
-      this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
       this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Inherit;
       this.Controls.Add(this.lineChartGroupBox);
@@ -434,5 +457,5 @@
       this.Controls.Add(this.commonGroupBox);
       this.Name = "DataRowVisualPropertiesControl";
-      this.Size = new System.Drawing.Size(327, 331);
+      this.Size = new System.Drawing.Size(327, 356);
       ((System.ComponentModel.ISupportInitialize)(this.binsNumericUpDown)).EndInit();
       this.commonGroupBox.ResumeLayout(false);
@@ -440,4 +463,8 @@
       this.axisGroupBox.ResumeLayout(false);
       this.axisGroupBox.PerformLayout();
+      this.panel2.ResumeLayout(false);
+      this.panel2.PerformLayout();
+      this.panel1.ResumeLayout(false);
+      this.panel1.PerformLayout();
       this.histoGramGroupBox.ResumeLayout(false);
       this.histoGramGroupBox.PerformLayout();
@@ -445,8 +472,4 @@
       this.lineChartGroupBox.PerformLayout();
       ((System.ComponentModel.ISupportInitialize)(this.lineWidthNumericUpDown)).EndInit();
-      this.panel1.ResumeLayout(false);
-      this.panel1.PerformLayout();
-      this.panel2.ResumeLayout(false);
-      this.panel2.PerformLayout();
       this.ResumeLayout(false);
 
@@ -484,4 +507,6 @@
     private System.Windows.Forms.Panel panel2;
     private System.Windows.Forms.Panel panel1;
+    private System.Windows.Forms.Label label10;
+    private System.Windows.Forms.CheckBox isVisibleInLegendCheckBox;
   }
 }
Index: branches/MemPRAlgorithm/HeuristicLab.Analysis.Views/3.3/DataRowVisualPropertiesControl.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Analysis.Views/3.3/DataRowVisualPropertiesControl.cs	(revision 14557)
+++ branches/MemPRAlgorithm/HeuristicLab.Analysis.Views/3.3/DataRowVisualPropertiesControl.cs	(revision 14562)
@@ -94,4 +94,5 @@
           binsExactRadioButton.Checked = Content.ExactBins;
           displayNameTextBox.Text = Content.DisplayName;
+          isVisibleInLegendCheckBox.Checked = Content.IsVisibleInLegend;
         }
       } finally { SuppressEvents = false; }
@@ -103,4 +104,5 @@
       lineChartGroupBox.Enabled = Content != null && Content.ChartType == DataRowVisualProperties.DataRowChartType.Line;
       histoGramGroupBox.Enabled = Content != null && Content.ChartType == DataRowVisualProperties.DataRowChartType.Histogram;
+      isVisibleInLegendCheckBox.Enabled = Content != null;
     }
 
@@ -188,4 +190,10 @@
       }
     }
+
+    private void isVisibleInLegendCheckBox_CheckedChanged(object sender, EventArgs e) {
+      if (!SuppressEvents && Content != null) {
+        Content.IsVisibleInLegend = isVisibleInLegendCheckBox.Checked;
+      }
+    }
     #endregion
   }
Index: branches/MemPRAlgorithm/HeuristicLab.Analysis.Views/3.3/DataTableControl.Designer.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Analysis.Views/3.3/DataTableControl.Designer.cs	(revision 14562)
+++ branches/MemPRAlgorithm/HeuristicLab.Analysis.Views/3.3/DataTableControl.Designer.cs	(revision 14562)
@@ -0,0 +1,115 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2016 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+namespace HeuristicLab.Analysis.Views {
+  partial class DataTableControl {
+    /// <summary> 
+    /// Required designer variable.
+    /// </summary>
+    private System.ComponentModel.IContainer components = null;
+
+    /// <summary> 
+    /// Clean up any resources being used.
+    /// </summary>
+    /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
+    protected override void Dispose(bool disposing) {
+      if (disposing) {
+        if (components != null) components.Dispose();
+      }
+      base.Dispose(disposing);
+    }
+
+    #region Component Designer generated code
+
+    /// <summary> 
+    /// Required method for Designer support - do not modify 
+    /// the contents of this method with the code editor.
+    /// </summary>
+    private void InitializeComponent() {
+      this.components = new System.ComponentModel.Container();
+      System.Windows.Forms.DataVisualization.Charting.ChartArea chartArea1 = new System.Windows.Forms.DataVisualization.Charting.ChartArea();
+      System.Windows.Forms.DataVisualization.Charting.Legend legend1 = new System.Windows.Forms.DataVisualization.Charting.Legend();
+      System.Windows.Forms.DataVisualization.Charting.Series series1 = new System.Windows.Forms.DataVisualization.Charting.Series();
+      System.Windows.Forms.DataVisualization.Charting.Title title1 = new System.Windows.Forms.DataVisualization.Charting.Title();
+      this.chart = new HeuristicLab.Visualization.ChartControlsExtensions.EnhancedChart();
+      this.configureToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
+      ((System.ComponentModel.ISupportInitialize)(this.chart)).BeginInit();
+      this.SuspendLayout();
+      // 
+      // chart
+      // 
+      this.chart.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) 
+            | System.Windows.Forms.AnchorStyles.Left) 
+            | System.Windows.Forms.AnchorStyles.Right)));
+      this.chart.BorderlineColor = System.Drawing.Color.Black;
+      this.chart.BorderlineDashStyle = System.Windows.Forms.DataVisualization.Charting.ChartDashStyle.Solid;
+      chartArea1.AxisX.Minimum = 0D;
+      chartArea1.CursorX.IsUserEnabled = true;
+      chartArea1.CursorX.IsUserSelectionEnabled = true;
+      chartArea1.CursorY.IsUserEnabled = true;
+      chartArea1.CursorY.IsUserSelectionEnabled = true;
+      chartArea1.Name = "Default";
+      this.chart.ChartAreas.Add(chartArea1);
+      legend1.Alignment = System.Drawing.StringAlignment.Center;
+      legend1.Docking = System.Windows.Forms.DataVisualization.Charting.Docking.Top;
+      legend1.Name = "Default";
+      this.chart.Legends.Add(legend1);
+      this.chart.Location = new System.Drawing.Point(0, 0);
+      this.chart.Name = "chart";
+      series1.ChartArea = "Default";
+      series1.Legend = "Default";
+      series1.Name = "Default";
+      this.chart.Series.Add(series1);
+      this.chart.Size = new System.Drawing.Size(359, 274);
+      this.chart.TabIndex = 3;
+      this.chart.Text = "chart";
+      title1.Font = new System.Drawing.Font("Microsoft Sans Serif", 12F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+      title1.Name = "Default";
+      title1.Text = "Title";
+      this.chart.Titles.Add(title1);
+      this.chart.CustomizeLegend += new System.EventHandler<System.Windows.Forms.DataVisualization.Charting.CustomizeLegendEventArgs>(this.chart_CustomizeLegend);
+      this.chart.MouseDown += new System.Windows.Forms.MouseEventHandler(this.chart_MouseDown);
+      this.chart.MouseMove += new System.Windows.Forms.MouseEventHandler(this.chart_MouseMove);
+      // 
+      // configureToolStripMenuItem
+      // 
+      this.configureToolStripMenuItem.Name = "configureToolStripMenuItem";
+      this.configureToolStripMenuItem.Size = new System.Drawing.Size(256, 22);
+      this.configureToolStripMenuItem.Text = "Configure Chart";
+      this.configureToolStripMenuItem.Click += new System.EventHandler(this.configureToolStripMenuItem_Click);
+      // 
+      // DataTableControl
+      // 
+      this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Inherit;
+      this.Controls.Add(this.chart);
+      this.Name = "DataTableControl";
+      this.Size = new System.Drawing.Size(359, 274);
+      ((System.ComponentModel.ISupportInitialize)(this.chart)).EndInit();
+      this.ResumeLayout(false);
+
+    }
+
+    #endregion
+
+    protected HeuristicLab.Visualization.ChartControlsExtensions.EnhancedChart chart;
+    private System.Windows.Forms.ToolStripMenuItem configureToolStripMenuItem;
+  }
+}
Index: branches/MemPRAlgorithm/HeuristicLab.Analysis.Views/3.3/DataTableControl.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Analysis.Views/3.3/DataTableControl.cs	(revision 14562)
+++ branches/MemPRAlgorithm/HeuristicLab.Analysis.Views/3.3/DataTableControl.cs	(revision 14562)
@@ -0,0 +1,667 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2016 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.Drawing;
+using System.Linq;
+using System.Windows.Forms;
+using System.Windows.Forms.DataVisualization.Charting;
+using HeuristicLab.Collections;
+using HeuristicLab.MainForm.WindowsForms;
+
+namespace HeuristicLab.Analysis.Views {
+  public partial class DataTableControl : AsynchronousContentView {
+    protected List<Series> invisibleSeries;
+    protected Dictionary<IObservableList<double>, DataRow> valuesRowsTable;
+
+    public new DataTable Content {
+      get { return (DataTable)base.Content; }
+      set { base.Content = value; }
+    }
+
+    public DataTableControl() {
+      InitializeComponent();
+      valuesRowsTable = new Dictionary<IObservableList<double>, DataRow>();
+      invisibleSeries = new List<Series>();
+      chart.CustomizeAllChartAreas();
+      chart.ChartAreas[0].CursorX.Interval = 1;
+      chart.ContextMenuStrip.Items.Add(configureToolStripMenuItem);
+    }
+
+    #region Event Handler Registration
+    protected override void DeregisterContentEvents() {
+      foreach (DataRow row in Content.Rows)
+        DeregisterDataRowEvents(row);
+      Content.VisualPropertiesChanged -= new EventHandler(Content_VisualPropertiesChanged);
+      Content.Rows.ItemsAdded -= new CollectionItemsChangedEventHandler<DataRow>(Rows_ItemsAdded);
+      Content.Rows.ItemsRemoved -= new CollectionItemsChangedEventHandler<DataRow>(Rows_ItemsRemoved);
+      Content.Rows.ItemsReplaced -= new CollectionItemsChangedEventHandler<DataRow>(Rows_ItemsReplaced);
+      Content.Rows.CollectionReset -= new CollectionItemsChangedEventHandler<DataRow>(Rows_CollectionReset);
+    }
+    protected override void RegisterContentEvents() {
+      Content.VisualPropertiesChanged += new EventHandler(Content_VisualPropertiesChanged);
+      Content.Rows.ItemsAdded += new CollectionItemsChangedEventHandler<DataRow>(Rows_ItemsAdded);
+      Content.Rows.ItemsRemoved += new CollectionItemsChangedEventHandler<DataRow>(Rows_ItemsRemoved);
+      Content.Rows.ItemsReplaced += new CollectionItemsChangedEventHandler<DataRow>(Rows_ItemsReplaced);
+      Content.Rows.CollectionReset += new CollectionItemsChangedEventHandler<DataRow>(Rows_CollectionReset);
+    }
+
+    protected virtual void RegisterDataRowEvents(DataRow row) {
+      row.NameChanged += new EventHandler(Row_NameChanged);
+      row.VisualPropertiesChanged += new EventHandler(Row_VisualPropertiesChanged);
+      valuesRowsTable.Add(row.Values, row);
+      row.Values.ItemsAdded += new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_ItemsAdded);
+      row.Values.ItemsRemoved += new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_ItemsRemoved);
+      row.Values.ItemsReplaced += new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_ItemsReplaced);
+      row.Values.ItemsMoved += new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_ItemsMoved);
+      row.Values.CollectionReset += new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_CollectionReset);
+    }
+    protected virtual void DeregisterDataRowEvents(DataRow row) {
+      row.Values.ItemsAdded -= new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_ItemsAdded);
+      row.Values.ItemsRemoved -= new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_ItemsRemoved);
+      row.Values.ItemsReplaced -= new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_ItemsReplaced);
+      row.Values.ItemsMoved -= new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_ItemsMoved);
+      row.Values.CollectionReset -= new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_CollectionReset);
+      valuesRowsTable.Remove(row.Values);
+      row.VisualPropertiesChanged -= new EventHandler(Row_VisualPropertiesChanged);
+      row.NameChanged -= new EventHandler(Row_NameChanged);
+    }
+    #endregion
+
+    protected override void OnContentChanged() {
+      invisibleSeries.Clear();
+      chart.Titles[0].Text = string.Empty;
+      chart.ChartAreas[0].AxisX.Title = string.Empty;
+      chart.ChartAreas[0].AxisY.Title = string.Empty;
+      chart.ChartAreas[0].AxisY2.Title = string.Empty;
+      chart.Series.Clear();
+      if (Content != null) {
+        chart.Titles[0].Text = Content.Name;
+        chart.Titles[0].Visible = !string.IsNullOrEmpty(Content.Name);
+        AddDataRows(Content.Rows);
+        ConfigureChartArea(chart.ChartAreas[0]);
+        RecalculateAxesScale(chart.ChartAreas[0]);
+      }
+    }
+
+    protected override void SetEnabledStateOfControls() {
+      chart.Enabled = Content != null;
+    }
+
+    public void ShowConfiguration() {
+      if (Content != null) {
+        using (var dialog = new DataTableVisualPropertiesDialog(Content)) {
+          dialog.ShowDialog(this);
+        }
+      } else MessageBox.Show("Nothing to configure.");
+    }
+    protected virtual void AddDataRows(IEnumerable<DataRow> rows) {
+      foreach (var row in rows) {
+        RegisterDataRowEvents(row);
+        var series = new Series(row.Name);
+        if (row.VisualProperties.DisplayName.Trim() != String.Empty) series.LegendText = row.VisualProperties.DisplayName;
+        else series.LegendText = row.Name;
+        ConfigureSeries(series, row);
+        FillSeriesWithRowValues(series, row);
+        chart.Series.Add(series);
+      }
+      ConfigureChartArea(chart.ChartAreas[0]);
+      RecalculateAxesScale(chart.ChartAreas[0]);
+      UpdateYCursorInterval();
+    }
+
+    protected virtual void RemoveDataRows(IEnumerable<DataRow> rows) {
+      foreach (var row in rows) {
+        DeregisterDataRowEvents(row);
+        Series series = chart.Series[row.Name];
+        chart.Series.Remove(series);
+        if (invisibleSeries.Contains(series))
+          invisibleSeries.Remove(series);
+      }
+      RecalculateAxesScale(chart.ChartAreas[0]);
+    }
+
+    private void ConfigureSeries(Series series, DataRow row) {
+      RemoveCustomPropertyIfExists(series, "PointWidth");
+      series.BorderWidth = 1;
+      series.BorderDashStyle = ChartDashStyle.Solid;
+      series.BorderColor = Color.Empty;
+
+      if (row.VisualProperties.Color != Color.Empty)
+        series.Color = row.VisualProperties.Color;
+      else series.Color = Color.Empty;
+      series.IsVisibleInLegend = row.VisualProperties.IsVisibleInLegend;
+
+      switch (row.VisualProperties.ChartType) {
+        case DataRowVisualProperties.DataRowChartType.Line:
+          series.ChartType = SeriesChartType.FastLine;
+          series.BorderWidth = row.VisualProperties.LineWidth;
+          series.BorderDashStyle = ConvertLineStyle(row.VisualProperties.LineStyle);
+          break;
+        case DataRowVisualProperties.DataRowChartType.Bars:
+          // Bar is incompatible with anything but Bar and StackedBar*
+          if (!chart.Series.Any(x => x.ChartType != SeriesChartType.Bar && x.ChartType != SeriesChartType.StackedBar && x.ChartType != SeriesChartType.StackedBar100))
+            series.ChartType = SeriesChartType.Bar;
+          else {
+            series.ChartType = SeriesChartType.FastPoint; //default
+            row.VisualProperties.ChartType = DataRowVisualProperties.DataRowChartType.Points;
+          }
+          break;
+        case DataRowVisualProperties.DataRowChartType.Columns:
+          series.ChartType = SeriesChartType.Column;
+          break;
+        case DataRowVisualProperties.DataRowChartType.Points:
+          series.ChartType = SeriesChartType.FastPoint;
+          break;
+        case DataRowVisualProperties.DataRowChartType.Histogram:
+          series.ChartType = SeriesChartType.StackedColumn;
+          series.SetCustomProperty("PointWidth", "1");
+          if (!series.Color.IsEmpty && series.Color.GetBrightness() < 0.25)
+            series.BorderColor = Color.White;
+          else series.BorderColor = Color.Black;
+          break;
+        case DataRowVisualProperties.DataRowChartType.StepLine:
+          series.ChartType = SeriesChartType.StepLine;
+          series.BorderWidth = row.VisualProperties.LineWidth;
+          series.BorderDashStyle = ConvertLineStyle(row.VisualProperties.LineStyle);
+          break;
+        default:
+          series.ChartType = SeriesChartType.FastPoint;
+          break;
+      }
+      series.YAxisType = row.VisualProperties.SecondYAxis ? AxisType.Secondary : AxisType.Primary;
+      series.XAxisType = row.VisualProperties.SecondXAxis ? AxisType.Secondary : AxisType.Primary;
+      if (row.VisualProperties.DisplayName.Trim() != String.Empty) series.LegendText = row.VisualProperties.DisplayName;
+      else series.LegendText = row.Name;
+
+      string xAxisTitle = string.IsNullOrEmpty(Content.VisualProperties.XAxisTitle)
+                      ? "X"
+                      : Content.VisualProperties.XAxisTitle;
+      string yAxisTitle = string.IsNullOrEmpty(Content.VisualProperties.YAxisTitle)
+                            ? "Y"
+                            : Content.VisualProperties.YAxisTitle;
+      series.ToolTip =
+        series.LegendText + Environment.NewLine +
+        xAxisTitle + " = " + "#INDEX," + Environment.NewLine +
+        yAxisTitle + " = " + "#VAL";
+    }
+
+    private void ConfigureChartArea(ChartArea area) {
+      if (Content.VisualProperties.TitleFont != null) chart.Titles[0].Font = Content.VisualProperties.TitleFont;
+      if (!Content.VisualProperties.TitleColor.IsEmpty) chart.Titles[0].ForeColor = Content.VisualProperties.TitleColor;
+      chart.Titles[0].Text = Content.VisualProperties.Title;
+      chart.Titles[0].Visible = !string.IsNullOrEmpty(Content.VisualProperties.Title);
+
+      if (Content.VisualProperties.AxisTitleFont != null) area.AxisX.TitleFont = Content.VisualProperties.AxisTitleFont;
+      if (!Content.VisualProperties.AxisTitleColor.IsEmpty) area.AxisX.TitleForeColor = Content.VisualProperties.AxisTitleColor;
+      area.AxisX.Title = Content.VisualProperties.XAxisTitle;
+
+      if (Content.VisualProperties.AxisTitleFont != null) area.AxisX2.TitleFont = Content.VisualProperties.AxisTitleFont;
+      if (!Content.VisualProperties.AxisTitleColor.IsEmpty) area.AxisX2.TitleForeColor = Content.VisualProperties.AxisTitleColor;
+      area.AxisX2.Title = Content.VisualProperties.SecondXAxisTitle;
+
+      if (Content.VisualProperties.AxisTitleFont != null) area.AxisY.TitleFont = Content.VisualProperties.AxisTitleFont;
+      if (!Content.VisualProperties.AxisTitleColor.IsEmpty) area.AxisY.TitleForeColor = Content.VisualProperties.AxisTitleColor;
+      area.AxisY.Title = Content.VisualProperties.YAxisTitle;
+
+      if (Content.VisualProperties.AxisTitleFont != null) area.AxisY2.TitleFont = Content.VisualProperties.AxisTitleFont;
+      if (!Content.VisualProperties.AxisTitleColor.IsEmpty) area.AxisY2.TitleForeColor = Content.VisualProperties.AxisTitleColor;
+      area.AxisY2.Title = Content.VisualProperties.SecondYAxisTitle;
+
+      area.AxisX.IsLogarithmic = Content.VisualProperties.XAxisLogScale;
+      area.AxisX2.IsLogarithmic = Content.VisualProperties.SecondXAxisLogScale;
+      area.AxisY.IsLogarithmic = Content.VisualProperties.YAxisLogScale;
+      area.AxisY2.IsLogarithmic = Content.VisualProperties.SecondYAxisLogScale;
+    }
+
+    private void RecalculateAxesScale(ChartArea area) {
+      // Reset the axes bounds so that RecalculateAxesScale() will assign new bounds
+      foreach (Axis a in area.Axes) {
+        a.Minimum = double.NaN;
+        a.Maximum = double.NaN;
+      }
+      area.RecalculateAxesScale();
+      area.AxisX.IsMarginVisible = false;
+      area.AxisX2.IsMarginVisible = false;
+
+      if (!Content.VisualProperties.XAxisMinimumAuto && !double.IsNaN(Content.VisualProperties.XAxisMinimumFixedValue)) area.AxisX.Minimum = Content.VisualProperties.XAxisMinimumFixedValue;
+      if (!Content.VisualProperties.XAxisMaximumAuto && !double.IsNaN(Content.VisualProperties.XAxisMaximumFixedValue)) area.AxisX.Maximum = Content.VisualProperties.XAxisMaximumFixedValue;
+      if (!Content.VisualProperties.SecondXAxisMinimumAuto && !double.IsNaN(Content.VisualProperties.SecondXAxisMinimumFixedValue)) area.AxisX2.Minimum = Content.VisualProperties.SecondXAxisMinimumFixedValue;
+      if (!Content.VisualProperties.SecondXAxisMaximumAuto && !double.IsNaN(Content.VisualProperties.SecondXAxisMaximumFixedValue)) area.AxisX2.Maximum = Content.VisualProperties.SecondXAxisMaximumFixedValue;
+      if (!Content.VisualProperties.YAxisMinimumAuto && !double.IsNaN(Content.VisualProperties.YAxisMinimumFixedValue)) area.AxisY.Minimum = Content.VisualProperties.YAxisMinimumFixedValue;
+      if (!Content.VisualProperties.YAxisMaximumAuto && !double.IsNaN(Content.VisualProperties.YAxisMaximumFixedValue)) area.AxisY.Maximum = Content.VisualProperties.YAxisMaximumFixedValue;
+      if (!Content.VisualProperties.SecondYAxisMinimumAuto && !double.IsNaN(Content.VisualProperties.SecondYAxisMinimumFixedValue)) area.AxisY2.Minimum = Content.VisualProperties.SecondYAxisMinimumFixedValue;
+      if (!Content.VisualProperties.SecondYAxisMaximumAuto && !double.IsNaN(Content.VisualProperties.SecondYAxisMaximumFixedValue)) area.AxisY2.Maximum = Content.VisualProperties.SecondYAxisMaximumFixedValue;
+      if (area.AxisX.Minimum >= area.AxisX.Maximum) area.AxisX.Maximum = area.AxisX.Minimum + 1;
+      if (area.AxisX2.Minimum >= area.AxisX2.Maximum) area.AxisX2.Maximum = area.AxisX2.Minimum + 1;
+      if (area.AxisY.Minimum >= area.AxisY.Maximum) area.AxisY.Maximum = area.AxisY.Minimum + 1;
+      if (area.AxisY2.Minimum >= area.AxisY2.Maximum) area.AxisY2.Maximum = area.AxisY2.Minimum + 1;
+    }
+
+    protected virtual void UpdateYCursorInterval() {
+      double interestingValuesRange = (
+        from series in chart.Series
+        where series.Enabled
+        let values = (from point in series.Points
+                      where !point.IsEmpty
+                      select point.YValues[0]).DefaultIfEmpty(1.0)
+        let range = values.Max() - values.Min()
+        where range > 0.0
+        select range
+        ).DefaultIfEmpty(1.0).Min();
+
+      double digits = (int)Math.Log10(interestingValuesRange) - 3;
+      double yZoomInterval = Math.Pow(10, digits);
+      this.chart.ChartAreas[0].CursorY.Interval = yZoomInterval;
+    }
+
+    #region Event Handlers
+    #region Content Event Handlers
+    private void Content_VisualPropertiesChanged(object sender, EventArgs e) {
+      if (InvokeRequired)
+        Invoke(new EventHandler(Content_VisualPropertiesChanged), sender, e);
+      else {
+        ConfigureChartArea(chart.ChartAreas[0]);
+        RecalculateAxesScale(chart.ChartAreas[0]); // axes min/max could have changed
+      }
+    }
+    #endregion
+    #region Rows Event Handlers
+    private void Rows_ItemsAdded(object sender, CollectionItemsChangedEventArgs<DataRow> e) {
+      if (InvokeRequired)
+        Invoke(new CollectionItemsChangedEventHandler<DataRow>(Rows_ItemsAdded), sender, e);
+      else {
+        AddDataRows(e.Items);
+      }
+    }
+    private void Rows_ItemsRemoved(object sender, CollectionItemsChangedEventArgs<DataRow> e) {
+      if (InvokeRequired)
+        Invoke(new CollectionItemsChangedEventHandler<DataRow>(Rows_ItemsRemoved), sender, e);
+      else {
+        RemoveDataRows(e.Items);
+      }
+    }
+    private void Rows_ItemsReplaced(object sender, CollectionItemsChangedEventArgs<DataRow> e) {
+      if (InvokeRequired)
+        Invoke(new CollectionItemsChangedEventHandler<DataRow>(Rows_ItemsReplaced), sender, e);
+      else {
+        RemoveDataRows(e.OldItems);
+        AddDataRows(e.Items);
+      }
+    }
+    private void Rows_CollectionReset(object sender, CollectionItemsChangedEventArgs<DataRow> e) {
+      if (InvokeRequired)
+        Invoke(new CollectionItemsChangedEventHandler<DataRow>(Rows_CollectionReset), sender, e);
+      else {
+        RemoveDataRows(e.OldItems);
+        AddDataRows(e.Items);
+      }
+    }
+    #endregion
+    #region Row Event Handlers
+    private void Row_VisualPropertiesChanged(object sender, EventArgs e) {
+      if (InvokeRequired)
+        Invoke(new EventHandler(Row_VisualPropertiesChanged), sender, e);
+      else {
+        DataRow row = (DataRow)sender;
+        Series series = chart.Series[row.Name];
+        series.Points.Clear();
+        ConfigureSeries(series, row);
+        FillSeriesWithRowValues(series, row);
+        RecalculateAxesScale(chart.ChartAreas[0]);
+      }
+    }
+    private void Row_NameChanged(object sender, EventArgs e) {
+      if (InvokeRequired)
+        Invoke(new EventHandler(Row_NameChanged), sender, e);
+      else {
+        DataRow row = (DataRow)sender;
+        chart.Series[row.Name].Name = row.Name;
+      }
+    }
+    #endregion
+    #region Values Event Handlers
+    private void Values_ItemsAdded(object sender, CollectionItemsChangedEventArgs<IndexedItem<double>> e) {
+      if (InvokeRequired)
+        Invoke(new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_ItemsAdded), sender, e);
+      else {
+        DataRow row = null;
+        valuesRowsTable.TryGetValue((IObservableList<double>)sender, out row);
+        if (row != null) {
+          Series rowSeries = chart.Series[row.Name];
+          if (!invisibleSeries.Contains(rowSeries)) {
+            rowSeries.Points.Clear();
+            FillSeriesWithRowValues(rowSeries, row);
+            RecalculateAxesScale(chart.ChartAreas[0]);
+            UpdateYCursorInterval();
+          }
+        }
+      }
+    }
+    private void Values_ItemsRemoved(object sender, CollectionItemsChangedEventArgs<IndexedItem<double>> e) {
+      if (InvokeRequired)
+        Invoke(new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_ItemsRemoved), sender, e);
+      else {
+        DataRow row = null;
+        valuesRowsTable.TryGetValue((IObservableList<double>)sender, out row);
+        if (row != null) {
+          Series rowSeries = chart.Series[row.Name];
+          if (!invisibleSeries.Contains(rowSeries)) {
+            rowSeries.Points.Clear();
+            FillSeriesWithRowValues(rowSeries, row);
+            RecalculateAxesScale(chart.ChartAreas[0]);
+            UpdateYCursorInterval();
+          }
+        }
+      }
+    }
+    private void Values_ItemsReplaced(object sender, CollectionItemsChangedEventArgs<IndexedItem<double>> e) {
+      if (InvokeRequired)
+        Invoke(new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_ItemsReplaced), sender, e);
+      else {
+        DataRow row = null;
+        valuesRowsTable.TryGetValue((IObservableList<double>)sender, out row);
+        if (row != null) {
+          Series rowSeries = chart.Series[row.Name];
+          if (!invisibleSeries.Contains(rowSeries)) {
+            if (row.VisualProperties.ChartType == DataRowVisualProperties.DataRowChartType.Histogram) {
+              rowSeries.Points.Clear();
+              FillSeriesWithRowValues(rowSeries, row);
+            } else {
+              foreach (IndexedItem<double> item in e.Items) {
+                if (IsInvalidValue(item.Value))
+                  rowSeries.Points[item.Index].IsEmpty = true;
+                else {
+                  rowSeries.Points[item.Index].YValues = new double[] { item.Value };
+                  rowSeries.Points[item.Index].IsEmpty = false;
+                }
+              }
+            }
+            RecalculateAxesScale(chart.ChartAreas[0]);
+            UpdateYCursorInterval();
+          }
+        }
+      }
+    }
+    private void Values_ItemsMoved(object sender, CollectionItemsChangedEventArgs<IndexedItem<double>> e) {
+      if (InvokeRequired)
+        Invoke(new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_ItemsMoved), sender, e);
+      else {
+        DataRow row = null;
+        valuesRowsTable.TryGetValue((IObservableList<double>)sender, out row);
+        if (row != null) {
+          Series rowSeries = chart.Series[row.Name];
+          if (!invisibleSeries.Contains(rowSeries)) {
+            rowSeries.Points.Clear();
+            FillSeriesWithRowValues(rowSeries, row);
+            RecalculateAxesScale(chart.ChartAreas[0]);
+            UpdateYCursorInterval();
+          }
+        }
+      }
+    }
+
+    private void Values_CollectionReset(object sender, CollectionItemsChangedEventArgs<IndexedItem<double>> e) {
+      if (InvokeRequired)
+        Invoke(new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_CollectionReset), sender, e);
+      else {
+        DataRow row = null;
+        valuesRowsTable.TryGetValue((IObservableList<double>)sender, out row);
+        if (row != null) {
+          Series rowSeries = chart.Series[row.Name];
+          if (!invisibleSeries.Contains(rowSeries)) {
+            rowSeries.Points.Clear();
+            FillSeriesWithRowValues(rowSeries, row);
+            RecalculateAxesScale(chart.ChartAreas[0]);
+            UpdateYCursorInterval();
+          }
+        }
+      }
+    }
+    #endregion
+    private void configureToolStripMenuItem_Click(object sender, EventArgs e) {
+      ShowConfiguration();
+    }
+    #endregion
+
+    #region Chart Event Handlers
+    private void chart_MouseDown(object sender, MouseEventArgs e) {
+      HitTestResult result = chart.HitTest(e.X, e.Y);
+      if (result.ChartElementType == ChartElementType.LegendItem) {
+        ToggleSeriesVisible(result.Series);
+      }
+    }
+    private void chart_MouseMove(object sender, MouseEventArgs e) {
+      HitTestResult result = chart.HitTest(e.X, e.Y);
+      if (result.ChartElementType == ChartElementType.LegendItem)
+        this.Cursor = Cursors.Hand;
+      else
+        this.Cursor = Cursors.Default;
+    }
+    private void chart_CustomizeLegend(object sender, CustomizeLegendEventArgs e) {
+      foreach (LegendItem legendItem in e.LegendItems) {
+        var series = chart.Series[legendItem.SeriesName];
+        if (series != null) {
+          bool seriesIsInvisible = invisibleSeries.Contains(series);
+          foreach (LegendCell cell in legendItem.Cells) {
+            cell.ForeColor = seriesIsInvisible ? Color.Gray : Color.Black;
+          }
+        }
+      }
+    }
+    #endregion
+
+    private void ToggleSeriesVisible(Series series) {
+      if (!invisibleSeries.Contains(series)) {
+        series.Points.Clear();
+        invisibleSeries.Add(series);
+      } else {
+        invisibleSeries.Remove(series);
+        if (Content != null) {
+
+          var row = (from r in Content.Rows
+                     where r.Name == series.Name
+                     select r).Single();
+          FillSeriesWithRowValues(series, row);
+          this.chart.Legends[series.Legend].ForeColor = Color.Black;
+          RecalculateAxesScale(chart.ChartAreas[0]);
+          UpdateYCursorInterval();
+        }
+      }
+    }
+
+    private void FillSeriesWithRowValues(Series series, DataRow row) {
+      switch (row.VisualProperties.ChartType) {
+        case DataRowVisualProperties.DataRowChartType.Histogram:
+          // when a single histogram is updated, all histograms must be updated. otherwise the value ranges and bin sizes may not be equal.
+          var histograms = Content.Rows
+            .Where(r => r.VisualProperties.ChartType == DataRowVisualProperties.DataRowChartType.Histogram)
+            .ToList();
+          CalculateHistogram(series, row, histograms);
+          foreach (var h in from r in histograms
+                            where r != row
+                            let s = chart.Series.FindByName(r.Name)
+                            where s != null
+                            where !invisibleSeries.Contains(s)
+                            select new { row = r, series = s }) {
+            h.series.Points.Clear();
+            CalculateHistogram(h.series, h.row, histograms);
+          }
+          break;
+        default: {
+            bool yLogarithmic = series.YAxisType == AxisType.Primary
+                                  ? Content.VisualProperties.YAxisLogScale
+                                  : Content.VisualProperties.SecondYAxisLogScale;
+            bool xLogarithmic = series.XAxisType == AxisType.Primary
+                                  ? Content.VisualProperties.XAxisLogScale
+                                  : Content.VisualProperties.SecondXAxisLogScale;
+            for (int i = 0; i < row.Values.Count; i++) {
+              var value = row.Values[i];
+              var point = new DataPoint();
+              point.XValue = row.VisualProperties.StartIndexZero && !xLogarithmic ? i : i + 1;
+              if (IsInvalidValue(value) || (yLogarithmic && value <= 0))
+                point.IsEmpty = true;
+              else
+                point.YValues = new double[] { value };
+              series.Points.Add(point);
+            }
+          }
+          break;
+      }
+    }
+
+    protected virtual void CalculateHistogram(Series series, DataRow row, IEnumerable<DataRow> histogramRows) {
+      series.Points.Clear();
+      if (!row.Values.Any()) return;
+
+      var validValues = histogramRows.SelectMany(r => r.Values).Where(x => !IsInvalidValue(x)).ToList();
+      if (!validValues.Any()) return;
+
+      int bins = histogramRows.Max(r => r.VisualProperties.Bins);
+      decimal minValue = (decimal)validValues.Min();
+      decimal maxValue = (decimal)validValues.Max();
+      decimal intervalWidth = (maxValue - minValue) / bins;
+      if (intervalWidth < 0) return;
+      if (intervalWidth == 0) {
+        series.Points.AddXY(minValue, row.Values.Count);
+        return;
+      }
+
+      if (!histogramRows.Any(r => r.VisualProperties.ExactBins)) {
+        intervalWidth = (decimal)HumanRoundRange((double)intervalWidth);
+        minValue = Math.Floor(minValue / intervalWidth) * intervalWidth;
+        maxValue = Math.Ceiling(maxValue / intervalWidth) * intervalWidth;
+      }
+
+      decimal intervalCenter = intervalWidth / 2;
+
+      decimal min = 0.0m, max = 0.0m;
+      if (!Double.IsNaN(Content.VisualProperties.XAxisMinimumFixedValue) && !Content.VisualProperties.XAxisMinimumAuto)
+        min = (decimal)Content.VisualProperties.XAxisMinimumFixedValue;
+      else min = minValue;
+      if (!Double.IsNaN(Content.VisualProperties.XAxisMaximumFixedValue) && !Content.VisualProperties.XAxisMaximumAuto)
+        max = (decimal)Content.VisualProperties.XAxisMaximumFixedValue;
+      else max = maxValue + intervalWidth;
+
+      double axisInterval = (double)intervalWidth / row.VisualProperties.ScaleFactor;
+
+      var area = chart.ChartAreas[0];
+      area.AxisX.Interval = axisInterval;
+
+      series.SetCustomProperty("PointWidth", "1"); // 0.8 is the default value
+
+      // get the range or intervals which define the grouping of the frequency values
+      var range = Range(min, max, intervalWidth).Skip(1).ToList();
+
+      // aggregate the row values by unique key and frequency value
+      var valueFrequencies = (from v in row.Values
+                              where !IsInvalidValue(v)
+                              orderby v
+                              group v by v into g
+                              select new Tuple<double, double>(g.First(), g.Count())).ToList();
+
+      // ensure that each column is displayed completely on the chart by adding two dummy datapoints on the upper and lower range
+      series.Points.Add(new DataPoint((double)(min - intervalWidth), 0));
+      series.Points.Add(new DataPoint((double)(max + intervalWidth), 0));
+
+      // add data points
+      int j = 0;
+      foreach (var d in range) {
+        double sum = 0.0;
+        // sum the frequency values that fall within the same interval
+        while (j < valueFrequencies.Count && (decimal)valueFrequencies[j].Item1 < d) {
+          sum += valueFrequencies[j].Item2;
+          ++j;
+        }
+        string xAxisTitle = string.IsNullOrEmpty(Content.VisualProperties.XAxisTitle)
+                              ? "X"
+                              : Content.VisualProperties.XAxisTitle;
+        string yAxisTitle = string.IsNullOrEmpty(Content.VisualProperties.YAxisTitle)
+                              ? "Y"
+                              : Content.VisualProperties.YAxisTitle;
+        series.Points.Add(new DataPoint((double)(d - intervalCenter), sum) {
+          ToolTip =
+            xAxisTitle + ": [" + (d - intervalWidth) + "-" + d + ")" + Environment.NewLine +
+            yAxisTitle + ": " + sum
+        });
+      }
+    }
+
+    #region Helpers
+    public static IEnumerable<decimal> Range(decimal min, decimal max, decimal step) {
+      decimal i;
+      for (i = min; i <= max; i += step)
+        yield return i;
+
+      if (i != max + step)
+        yield return i;
+    }
+
+    protected void RemoveCustomPropertyIfExists(Series series, string property) {
+      if (series.IsCustomPropertySet(property)) series.DeleteCustomProperty(property);
+    }
+
+    private double HumanRoundRange(double range) {
+      double base10 = Math.Pow(10.0, Math.Floor(Math.Log10(range)));
+      double rounding = range / base10;
+      if (rounding <= 1.5) rounding = 1;
+      else if (rounding <= 2.25) rounding = 2;
+      else if (rounding <= 3.75) rounding = 2.5;
+      else if (rounding <= 7.5) rounding = 5;
+      else rounding = 10;
+      return rounding * base10;
+    }
+
+    private double HumanRoundMax(double max) {
+      double base10;
+      if (max > 0) base10 = Math.Pow(10.0, Math.Floor(Math.Log10(max)));
+      else base10 = Math.Pow(10.0, Math.Ceiling(Math.Log10(-max)));
+      double rounding = (max > 0) ? base10 : -base10;
+      while (rounding < max) rounding += base10;
+      return rounding;
+    }
+
+    private ChartDashStyle ConvertLineStyle(DataRowVisualProperties.DataRowLineStyle dataRowLineStyle) {
+      switch (dataRowLineStyle) {
+        case DataRowVisualProperties.DataRowLineStyle.Dash:
+          return ChartDashStyle.Dash;
+        case DataRowVisualProperties.DataRowLineStyle.DashDot:
+          return ChartDashStyle.DashDot;
+        case DataRowVisualProperties.DataRowLineStyle.DashDotDot:
+          return ChartDashStyle.DashDotDot;
+        case DataRowVisualProperties.DataRowLineStyle.Dot:
+          return ChartDashStyle.Dot;
+        case DataRowVisualProperties.DataRowLineStyle.NotSet:
+          return ChartDashStyle.NotSet;
+        case DataRowVisualProperties.DataRowLineStyle.Solid:
+          return ChartDashStyle.Solid;
+        default:
+          return ChartDashStyle.NotSet;
+      }
+    }
+
+    protected static bool IsInvalidValue(double x) {
+      return double.IsNaN(x) || x < (double)decimal.MinValue || x > (double)decimal.MaxValue;
+    }
+    #endregion
+  }
+}
Index: branches/MemPRAlgorithm/HeuristicLab.Analysis.Views/3.3/DataTableView.Designer.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Analysis.Views/3.3/DataTableView.Designer.cs	(revision 14557)
+++ branches/MemPRAlgorithm/HeuristicLab.Analysis.Views/3.3/DataTableView.Designer.cs	(revision 14562)
@@ -45,11 +45,6 @@
     /// </summary>
     private void InitializeComponent() {
-      System.Windows.Forms.DataVisualization.Charting.ChartArea chartArea1 = new System.Windows.Forms.DataVisualization.Charting.ChartArea();
-      System.Windows.Forms.DataVisualization.Charting.Legend legend1 = new System.Windows.Forms.DataVisualization.Charting.Legend();
-      System.Windows.Forms.DataVisualization.Charting.Series series1 = new System.Windows.Forms.DataVisualization.Charting.Series();
-      System.Windows.Forms.DataVisualization.Charting.Title title1 = new System.Windows.Forms.DataVisualization.Charting.Title();
-      this.chart = new HeuristicLab.Visualization.ChartControlsExtensions.EnhancedChart();
+      this.chart = new HeuristicLab.Analysis.Views.DataTableControl();
       ((System.ComponentModel.ISupportInitialize)(this.errorProvider)).BeginInit();
-      ((System.ComponentModel.ISupportInitialize)(this.chart)).BeginInit();
       this.SuspendLayout();
       // 
@@ -70,33 +65,9 @@
                   | System.Windows.Forms.AnchorStyles.Left)
                   | System.Windows.Forms.AnchorStyles.Right)));
-      this.chart.BorderlineColor = System.Drawing.Color.Black;
-      this.chart.BorderlineDashStyle = System.Windows.Forms.DataVisualization.Charting.ChartDashStyle.Solid;
-      chartArea1.AxisX.Minimum = 0D;
-      chartArea1.CursorX.IsUserEnabled = true;
-      chartArea1.CursorX.IsUserSelectionEnabled = true;
-      chartArea1.CursorY.IsUserEnabled = true;
-      chartArea1.CursorY.IsUserSelectionEnabled = true;
-      chartArea1.Name = "Default";
-      this.chart.ChartAreas.Add(chartArea1);
-      legend1.Alignment = System.Drawing.StringAlignment.Center;
-      legend1.Docking = System.Windows.Forms.DataVisualization.Charting.Docking.Top;
-      legend1.Name = "Default";
-      this.chart.Legends.Add(legend1);
       this.chart.Location = new System.Drawing.Point(0, 26);
       this.chart.Name = "chart";
-      series1.ChartArea = "Default";
-      series1.Legend = "Default";
-      series1.Name = "Default";
-      this.chart.Series.Add(series1);
       this.chart.Size = new System.Drawing.Size(359, 248);
       this.chart.TabIndex = 3;
       this.chart.Text = "chart";
-      title1.Font = new System.Drawing.Font("Microsoft Sans Serif", 12F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
-      title1.Name = "Default";
-      title1.Text = "Title";
-      this.chart.Titles.Add(title1);
-      this.chart.CustomizeLegend += new System.EventHandler<System.Windows.Forms.DataVisualization.Charting.CustomizeLegendEventArgs>(this.chart_CustomizeLegend);
-      this.chart.MouseDown += new System.Windows.Forms.MouseEventHandler(this.chart_MouseDown);
-      this.chart.MouseMove += new System.Windows.Forms.MouseEventHandler(this.chart_MouseMove);
       // 
       // DataTableView
@@ -112,14 +83,11 @@
       this.Controls.SetChildIndex(this.nameTextBox, 0);
       ((System.ComponentModel.ISupportInitialize)(this.errorProvider)).EndInit();
-      ((System.ComponentModel.ISupportInitialize)(this.chart)).EndInit();
       this.ResumeLayout(false);
       this.PerformLayout();
-
     }
 
     #endregion
 
-    protected HeuristicLab.Visualization.ChartControlsExtensions.EnhancedChart chart;
-
+    protected HeuristicLab.Analysis.Views.DataTableControl chart;
   }
 }
Index: branches/MemPRAlgorithm/HeuristicLab.Analysis.Views/3.3/DataTableView.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Analysis.Views/3.3/DataTableView.cs	(revision 14557)
+++ branches/MemPRAlgorithm/HeuristicLab.Analysis.Views/3.3/DataTableView.cs	(revision 14562)
@@ -20,13 +20,7 @@
 #endregion
 
-using HeuristicLab.Collections;
+using System;
 using HeuristicLab.Core.Views;
 using HeuristicLab.MainForm;
-using System;
-using System.Collections.Generic;
-using System.Drawing;
-using System.Linq;
-using System.Windows.Forms;
-using System.Windows.Forms.DataVisualization.Charting;
 
 namespace HeuristicLab.Analysis.Views {
@@ -34,6 +28,4 @@
   [Content(typeof(DataTable), true)]
   public partial class DataTableView : NamedItemView, IConfigureableView {
-    protected List<Series> invisibleSeries;
-    protected Dictionary<IObservableList<double>, DataRow> valuesRowsTable;
 
     public new DataTable Content {
@@ -44,66 +36,9 @@
     public DataTableView() {
       InitializeComponent();
-      valuesRowsTable = new Dictionary<IObservableList<double>, DataRow>();
-      invisibleSeries = new List<Series>();
-      chart.CustomizeAllChartAreas();
-      chart.ChartAreas[0].CursorX.Interval = 1;
     }
-
-    #region Event Handler Registration
-    protected override void DeregisterContentEvents() {
-      foreach (DataRow row in Content.Rows)
-        DeregisterDataRowEvents(row);
-      Content.VisualPropertiesChanged -= new EventHandler(Content_VisualPropertiesChanged);
-      Content.Rows.ItemsAdded -= new CollectionItemsChangedEventHandler<DataRow>(Rows_ItemsAdded);
-      Content.Rows.ItemsRemoved -= new CollectionItemsChangedEventHandler<DataRow>(Rows_ItemsRemoved);
-      Content.Rows.ItemsReplaced -= new CollectionItemsChangedEventHandler<DataRow>(Rows_ItemsReplaced);
-      Content.Rows.CollectionReset -= new CollectionItemsChangedEventHandler<DataRow>(Rows_CollectionReset);
-      base.DeregisterContentEvents();
-    }
-    protected override void RegisterContentEvents() {
-      base.RegisterContentEvents();
-      Content.VisualPropertiesChanged += new EventHandler(Content_VisualPropertiesChanged);
-      Content.Rows.ItemsAdded += new CollectionItemsChangedEventHandler<DataRow>(Rows_ItemsAdded);
-      Content.Rows.ItemsRemoved += new CollectionItemsChangedEventHandler<DataRow>(Rows_ItemsRemoved);
-      Content.Rows.ItemsReplaced += new CollectionItemsChangedEventHandler<DataRow>(Rows_ItemsReplaced);
-      Content.Rows.CollectionReset += new CollectionItemsChangedEventHandler<DataRow>(Rows_CollectionReset);
-    }
-
-    protected virtual void RegisterDataRowEvents(DataRow row) {
-      row.NameChanged += new EventHandler(Row_NameChanged);
-      row.VisualPropertiesChanged += new EventHandler(Row_VisualPropertiesChanged);
-      valuesRowsTable.Add(row.Values, row);
-      row.Values.ItemsAdded += new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_ItemsAdded);
-      row.Values.ItemsRemoved += new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_ItemsRemoved);
-      row.Values.ItemsReplaced += new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_ItemsReplaced);
-      row.Values.ItemsMoved += new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_ItemsMoved);
-      row.Values.CollectionReset += new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_CollectionReset);
-    }
-    protected virtual void DeregisterDataRowEvents(DataRow row) {
-      row.Values.ItemsAdded -= new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_ItemsAdded);
-      row.Values.ItemsRemoved -= new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_ItemsRemoved);
-      row.Values.ItemsReplaced -= new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_ItemsReplaced);
-      row.Values.ItemsMoved -= new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_ItemsMoved);
-      row.Values.CollectionReset -= new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_CollectionReset);
-      valuesRowsTable.Remove(row.Values);
-      row.VisualPropertiesChanged -= new EventHandler(Row_VisualPropertiesChanged);
-      row.NameChanged -= new EventHandler(Row_NameChanged);
-    }
-    #endregion
 
     protected override void OnContentChanged() {
       base.OnContentChanged();
-      invisibleSeries.Clear();
-      chart.Titles[0].Text = string.Empty;
-      chart.ChartAreas[0].AxisX.Title = string.Empty;
-      chart.ChartAreas[0].AxisY.Title = string.Empty;
-      chart.ChartAreas[0].AxisY2.Title = string.Empty;
-      chart.Series.Clear();
-      if (Content != null) {
-        chart.Titles[0].Text = Content.Name;
-        AddDataRows(Content.Rows);
-        ConfigureChartArea(chart.ChartAreas[0]);
-        RecalculateAxesScale(chart.ChartAreas[0]);
-      }
+      chart.Content = Content;
     }
 
@@ -113,171 +48,4 @@
     }
 
-    public void ShowConfiguration() {
-      if (Content != null) {
-        using (var dialog = new DataTableVisualPropertiesDialog(Content)) {
-          dialog.ShowDialog(this);
-        }
-      } else MessageBox.Show("Nothing to configure.");
-    }
-    protected virtual void AddDataRows(IEnumerable<DataRow> rows) {
-      foreach (var row in rows) {
-        RegisterDataRowEvents(row);
-        var series = new Series(row.Name);
-        if (row.VisualProperties.DisplayName.Trim() != String.Empty) series.LegendText = row.VisualProperties.DisplayName;
-        else series.LegendText = row.Name;
-        ConfigureSeries(series, row);
-        FillSeriesWithRowValues(series, row);
-        chart.Series.Add(series);
-      }
-      ConfigureChartArea(chart.ChartAreas[0]);
-      RecalculateAxesScale(chart.ChartAreas[0]);
-      UpdateYCursorInterval();
-    }
-
-    protected virtual void RemoveDataRows(IEnumerable<DataRow> rows) {
-      foreach (var row in rows) {
-        DeregisterDataRowEvents(row);
-        Series series = chart.Series[row.Name];
-        chart.Series.Remove(series);
-        if (invisibleSeries.Contains(series))
-          invisibleSeries.Remove(series);
-      }
-      RecalculateAxesScale(chart.ChartAreas[0]);
-    }
-
-    private void ConfigureSeries(Series series, DataRow row) {
-      RemoveCustomPropertyIfExists(series, "PointWidth");
-      series.BorderWidth = 1;
-      series.BorderDashStyle = ChartDashStyle.Solid;
-      series.BorderColor = Color.Empty;
-
-      if (row.VisualProperties.Color != Color.Empty)
-        series.Color = row.VisualProperties.Color;
-      else series.Color = Color.Empty;
-      series.IsVisibleInLegend = row.VisualProperties.IsVisibleInLegend;
-
-      switch (row.VisualProperties.ChartType) {
-        case DataRowVisualProperties.DataRowChartType.Line:
-          series.ChartType = SeriesChartType.FastLine;
-          series.BorderWidth = row.VisualProperties.LineWidth;
-          series.BorderDashStyle = ConvertLineStyle(row.VisualProperties.LineStyle);
-          break;
-        case DataRowVisualProperties.DataRowChartType.Bars:
-          // Bar is incompatible with anything but Bar and StackedBar*
-          if (!chart.Series.Any(x => x.ChartType != SeriesChartType.Bar && x.ChartType != SeriesChartType.StackedBar && x.ChartType != SeriesChartType.StackedBar100))
-            series.ChartType = SeriesChartType.Bar;
-          else {
-            series.ChartType = SeriesChartType.FastPoint; //default
-            row.VisualProperties.ChartType = DataRowVisualProperties.DataRowChartType.Points;
-          }
-          break;
-        case DataRowVisualProperties.DataRowChartType.Columns:
-          series.ChartType = SeriesChartType.Column;
-          break;
-        case DataRowVisualProperties.DataRowChartType.Points:
-          series.ChartType = SeriesChartType.FastPoint;
-          break;
-        case DataRowVisualProperties.DataRowChartType.Histogram:
-          series.ChartType = SeriesChartType.Column;
-          series.SetCustomProperty("PointWidth", "1");
-          if (!series.Color.IsEmpty && series.Color.GetBrightness() < 0.25)
-            series.BorderColor = Color.White;
-          else series.BorderColor = Color.Black;
-          break;
-        case DataRowVisualProperties.DataRowChartType.StepLine:
-          series.ChartType = SeriesChartType.StepLine;
-          series.BorderWidth = row.VisualProperties.LineWidth;
-          series.BorderDashStyle = ConvertLineStyle(row.VisualProperties.LineStyle);
-          break;
-        default:
-          series.ChartType = SeriesChartType.FastPoint;
-          break;
-      }
-      series.YAxisType = row.VisualProperties.SecondYAxis ? AxisType.Secondary : AxisType.Primary;
-      series.XAxisType = row.VisualProperties.SecondXAxis ? AxisType.Secondary : AxisType.Primary;
-      if (row.VisualProperties.DisplayName.Trim() != String.Empty) series.LegendText = row.VisualProperties.DisplayName;
-      else series.LegendText = row.Name;
-
-      string xAxisTitle = string.IsNullOrEmpty(Content.VisualProperties.XAxisTitle)
-                      ? "X"
-                      : Content.VisualProperties.XAxisTitle;
-      string yAxisTitle = string.IsNullOrEmpty(Content.VisualProperties.YAxisTitle)
-                            ? "Y"
-                            : Content.VisualProperties.YAxisTitle;
-      series.ToolTip =
-        series.LegendText + Environment.NewLine +
-        xAxisTitle + " = " + "#INDEX," + Environment.NewLine +
-        yAxisTitle + " = " + "#VAL";
-    }
-
-    private void ConfigureChartArea(ChartArea area) {
-      if (Content.VisualProperties.TitleFont != null) chart.Titles[0].Font = Content.VisualProperties.TitleFont;
-      if (!Content.VisualProperties.TitleColor.IsEmpty) chart.Titles[0].ForeColor = Content.VisualProperties.TitleColor;
-      chart.Titles[0].Text = Content.VisualProperties.Title;
-
-      if (Content.VisualProperties.AxisTitleFont != null) area.AxisX.TitleFont = Content.VisualProperties.AxisTitleFont;
-      if (!Content.VisualProperties.AxisTitleColor.IsEmpty) area.AxisX.TitleForeColor = Content.VisualProperties.AxisTitleColor;
-      area.AxisX.Title = Content.VisualProperties.XAxisTitle;
-
-      if (Content.VisualProperties.AxisTitleFont != null) area.AxisX2.TitleFont = Content.VisualProperties.AxisTitleFont;
-      if (!Content.VisualProperties.AxisTitleColor.IsEmpty) area.AxisX2.TitleForeColor = Content.VisualProperties.AxisTitleColor;
-      area.AxisX2.Title = Content.VisualProperties.SecondXAxisTitle;
-
-      if (Content.VisualProperties.AxisTitleFont != null) area.AxisY.TitleFont = Content.VisualProperties.AxisTitleFont;
-      if (!Content.VisualProperties.AxisTitleColor.IsEmpty) area.AxisY.TitleForeColor = Content.VisualProperties.AxisTitleColor;
-      area.AxisY.Title = Content.VisualProperties.YAxisTitle;
-
-      if (Content.VisualProperties.AxisTitleFont != null) area.AxisY2.TitleFont = Content.VisualProperties.AxisTitleFont;
-      if (!Content.VisualProperties.AxisTitleColor.IsEmpty) area.AxisY2.TitleForeColor = Content.VisualProperties.AxisTitleColor;
-      area.AxisY2.Title = Content.VisualProperties.SecondYAxisTitle;
-
-      area.AxisX.IsLogarithmic = Content.VisualProperties.XAxisLogScale;
-      area.AxisX2.IsLogarithmic = Content.VisualProperties.SecondXAxisLogScale;
-      area.AxisY.IsLogarithmic = Content.VisualProperties.YAxisLogScale;
-      area.AxisY2.IsLogarithmic = Content.VisualProperties.SecondYAxisLogScale;
-    }
-
-    private void RecalculateAxesScale(ChartArea area) {
-      // Reset the axes bounds so that RecalculateAxesScale() will assign new bounds
-      foreach (Axis a in area.Axes) {
-        a.Minimum = double.NaN;
-        a.Maximum = double.NaN;
-      }
-      area.RecalculateAxesScale();
-      area.AxisX.IsMarginVisible = false;
-      area.AxisX2.IsMarginVisible = false;
-
-      if (!Content.VisualProperties.XAxisMinimumAuto && !double.IsNaN(Content.VisualProperties.XAxisMinimumFixedValue)) area.AxisX.Minimum = Content.VisualProperties.XAxisMinimumFixedValue;
-      if (!Content.VisualProperties.XAxisMaximumAuto && !double.IsNaN(Content.VisualProperties.XAxisMaximumFixedValue)) area.AxisX.Maximum = Content.VisualProperties.XAxisMaximumFixedValue;
-      if (!Content.VisualProperties.SecondXAxisMinimumAuto && !double.IsNaN(Content.VisualProperties.SecondXAxisMinimumFixedValue)) area.AxisX2.Minimum = Content.VisualProperties.SecondXAxisMinimumFixedValue;
-      if (!Content.VisualProperties.SecondXAxisMaximumAuto && !double.IsNaN(Content.VisualProperties.SecondXAxisMaximumFixedValue)) area.AxisX2.Maximum = Content.VisualProperties.SecondXAxisMaximumFixedValue;
-      if (!Content.VisualProperties.YAxisMinimumAuto && !double.IsNaN(Content.VisualProperties.YAxisMinimumFixedValue)) area.AxisY.Minimum = Content.VisualProperties.YAxisMinimumFixedValue;
-      if (!Content.VisualProperties.YAxisMaximumAuto && !double.IsNaN(Content.VisualProperties.YAxisMaximumFixedValue)) area.AxisY.Maximum = Content.VisualProperties.YAxisMaximumFixedValue;
-      if (!Content.VisualProperties.SecondYAxisMinimumAuto && !double.IsNaN(Content.VisualProperties.SecondYAxisMinimumFixedValue)) area.AxisY2.Minimum = Content.VisualProperties.SecondYAxisMinimumFixedValue;
-      if (!Content.VisualProperties.SecondYAxisMaximumAuto && !double.IsNaN(Content.VisualProperties.SecondYAxisMaximumFixedValue)) area.AxisY2.Maximum = Content.VisualProperties.SecondYAxisMaximumFixedValue;
-      if (area.AxisX.Minimum >= area.AxisX.Maximum) area.AxisX.Maximum = area.AxisX.Minimum + 1;
-      if (area.AxisX2.Minimum >= area.AxisX2.Maximum) area.AxisX2.Maximum = area.AxisX2.Minimum + 1;
-      if (area.AxisY.Minimum >= area.AxisY.Maximum) area.AxisY.Maximum = area.AxisY.Minimum + 1;
-      if (area.AxisY2.Minimum >= area.AxisY2.Maximum) area.AxisY2.Maximum = area.AxisY2.Minimum + 1;
-    }
-
-    protected virtual void UpdateYCursorInterval() {
-      double interestingValuesRange = (
-        from series in chart.Series
-        where series.Enabled
-        let values = (from point in series.Points
-                      where !point.IsEmpty
-                      select point.YValues[0]).DefaultIfEmpty(1.0)
-        let range = values.Max() - values.Min()
-        where range > 0.0
-        select range
-        ).DefaultIfEmpty(1.0).Min();
-
-      double digits = (int)Math.Log10(interestingValuesRange) - 3;
-      double yZoomInterval = Math.Pow(10, digits);
-      this.chart.ChartAreas[0].CursorY.Interval = yZoomInterval;
-    }
-
-    #region Event Handlers
     #region Content Event Handlers
     protected override void Content_NameChanged(object sender, EventArgs e) {
@@ -285,376 +53,13 @@
         Invoke(new EventHandler(Content_NameChanged), sender, e);
       else {
-        chart.Titles[0].Text = Content.Name;
+        Content.VisualProperties.Title = Content.Name;
         base.Content_NameChanged(sender, e);
-      }
-    }
-    private void Content_VisualPropertiesChanged(object sender, EventArgs e) {
-      if (InvokeRequired)
-        Invoke(new EventHandler(Content_VisualPropertiesChanged), sender, e);
-      else {
-        ConfigureChartArea(chart.ChartAreas[0]);
-        RecalculateAxesScale(chart.ChartAreas[0]); // axes min/max could have changed
-      }
-    }
-    #endregion
-    #region Rows Event Handlers
-    private void Rows_ItemsAdded(object sender, CollectionItemsChangedEventArgs<DataRow> e) {
-      if (InvokeRequired)
-        Invoke(new CollectionItemsChangedEventHandler<DataRow>(Rows_ItemsAdded), sender, e);
-      else {
-        AddDataRows(e.Items);
-      }
-    }
-    private void Rows_ItemsRemoved(object sender, CollectionItemsChangedEventArgs<DataRow> e) {
-      if (InvokeRequired)
-        Invoke(new CollectionItemsChangedEventHandler<DataRow>(Rows_ItemsRemoved), sender, e);
-      else {
-        RemoveDataRows(e.Items);
-      }
-    }
-    private void Rows_ItemsReplaced(object sender, CollectionItemsChangedEventArgs<DataRow> e) {
-      if (InvokeRequired)
-        Invoke(new CollectionItemsChangedEventHandler<DataRow>(Rows_ItemsReplaced), sender, e);
-      else {
-        RemoveDataRows(e.OldItems);
-        AddDataRows(e.Items);
-      }
-    }
-    private void Rows_CollectionReset(object sender, CollectionItemsChangedEventArgs<DataRow> e) {
-      if (InvokeRequired)
-        Invoke(new CollectionItemsChangedEventHandler<DataRow>(Rows_CollectionReset), sender, e);
-      else {
-        RemoveDataRows(e.OldItems);
-        AddDataRows(e.Items);
-      }
-    }
-    #endregion
-    #region Row Event Handlers
-    private void Row_VisualPropertiesChanged(object sender, EventArgs e) {
-      if (InvokeRequired)
-        Invoke(new EventHandler(Row_VisualPropertiesChanged), sender, e);
-      else {
-        DataRow row = (DataRow)sender;
-        Series series = chart.Series[row.Name];
-        series.Points.Clear();
-        ConfigureSeries(series, row);
-        FillSeriesWithRowValues(series, row);
-        RecalculateAxesScale(chart.ChartAreas[0]);
-      }
-    }
-    private void Row_NameChanged(object sender, EventArgs e) {
-      if (InvokeRequired)
-        Invoke(new EventHandler(Row_NameChanged), sender, e);
-      else {
-        DataRow row = (DataRow)sender;
-        chart.Series[row.Name].Name = row.Name;
-      }
-    }
-    #endregion
-    #region Values Event Handlers
-    private void Values_ItemsAdded(object sender, CollectionItemsChangedEventArgs<IndexedItem<double>> e) {
-      if (InvokeRequired)
-        Invoke(new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_ItemsAdded), sender, e);
-      else {
-        DataRow row = null;
-        valuesRowsTable.TryGetValue((IObservableList<double>)sender, out row);
-        if (row != null) {
-          Series rowSeries = chart.Series[row.Name];
-          if (!invisibleSeries.Contains(rowSeries)) {
-            rowSeries.Points.Clear();
-            FillSeriesWithRowValues(rowSeries, row);
-            RecalculateAxesScale(chart.ChartAreas[0]);
-            UpdateYCursorInterval();
-          }
-        }
-      }
-    }
-    private void Values_ItemsRemoved(object sender, CollectionItemsChangedEventArgs<IndexedItem<double>> e) {
-      if (InvokeRequired)
-        Invoke(new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_ItemsRemoved), sender, e);
-      else {
-        DataRow row = null;
-        valuesRowsTable.TryGetValue((IObservableList<double>)sender, out row);
-        if (row != null) {
-          Series rowSeries = chart.Series[row.Name];
-          if (!invisibleSeries.Contains(rowSeries)) {
-            rowSeries.Points.Clear();
-            FillSeriesWithRowValues(rowSeries, row);
-            RecalculateAxesScale(chart.ChartAreas[0]);
-            UpdateYCursorInterval();
-          }
-        }
-      }
-    }
-    private void Values_ItemsReplaced(object sender, CollectionItemsChangedEventArgs<IndexedItem<double>> e) {
-      if (InvokeRequired)
-        Invoke(new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_ItemsReplaced), sender, e);
-      else {
-        DataRow row = null;
-        valuesRowsTable.TryGetValue((IObservableList<double>)sender, out row);
-        if (row != null) {
-          Series rowSeries = chart.Series[row.Name];
-          if (!invisibleSeries.Contains(rowSeries)) {
-            if (row.VisualProperties.ChartType == DataRowVisualProperties.DataRowChartType.Histogram) {
-              rowSeries.Points.Clear();
-              FillSeriesWithRowValues(rowSeries, row);
-            } else {
-              foreach (IndexedItem<double> item in e.Items) {
-                if (IsInvalidValue(item.Value))
-                  rowSeries.Points[item.Index].IsEmpty = true;
-                else {
-                  rowSeries.Points[item.Index].YValues = new double[] { item.Value };
-                  rowSeries.Points[item.Index].IsEmpty = false;
-                }
-              }
-            }
-            RecalculateAxesScale(chart.ChartAreas[0]);
-            UpdateYCursorInterval();
-          }
-        }
-      }
-    }
-    private void Values_ItemsMoved(object sender, CollectionItemsChangedEventArgs<IndexedItem<double>> e) {
-      if (InvokeRequired)
-        Invoke(new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_ItemsMoved), sender, e);
-      else {
-        DataRow row = null;
-        valuesRowsTable.TryGetValue((IObservableList<double>)sender, out row);
-        if (row != null) {
-          Series rowSeries = chart.Series[row.Name];
-          if (!invisibleSeries.Contains(rowSeries)) {
-            rowSeries.Points.Clear();
-            FillSeriesWithRowValues(rowSeries, row);
-            RecalculateAxesScale(chart.ChartAreas[0]);
-            UpdateYCursorInterval();
-          }
-        }
-      }
-    }
-
-    private void Values_CollectionReset(object sender, CollectionItemsChangedEventArgs<IndexedItem<double>> e) {
-      if (InvokeRequired)
-        Invoke(new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_CollectionReset), sender, e);
-      else {
-        DataRow row = null;
-        valuesRowsTable.TryGetValue((IObservableList<double>)sender, out row);
-        if (row != null) {
-          Series rowSeries = chart.Series[row.Name];
-          if (!invisibleSeries.Contains(rowSeries)) {
-            rowSeries.Points.Clear();
-            FillSeriesWithRowValues(rowSeries, row);
-            RecalculateAxesScale(chart.ChartAreas[0]);
-            UpdateYCursorInterval();
-          }
-        }
-      }
-    }
-    #endregion
-    #endregion
-
-    #region Chart Event Handlers
-    private void chart_MouseDown(object sender, MouseEventArgs e) {
-      HitTestResult result = chart.HitTest(e.X, e.Y);
-      if (result.ChartElementType == ChartElementType.LegendItem) {
-        ToggleSeriesVisible(result.Series);
-      }
-    }
-    private void chart_MouseMove(object sender, MouseEventArgs e) {
-      HitTestResult result = chart.HitTest(e.X, e.Y);
-      if (result.ChartElementType == ChartElementType.LegendItem)
-        this.Cursor = Cursors.Hand;
-      else
-        this.Cursor = Cursors.Default;
-    }
-    private void chart_CustomizeLegend(object sender, CustomizeLegendEventArgs e) {
-      foreach (LegendItem legendItem in e.LegendItems) {
-        var series = chart.Series[legendItem.SeriesName];
-        if (series != null) {
-          bool seriesIsInvisible = invisibleSeries.Contains(series);
-          foreach (LegendCell cell in legendItem.Cells) {
-            cell.ForeColor = seriesIsInvisible ? Color.Gray : Color.Black;
-          }
-        }
       }
     }
     #endregion
 
-    private void ToggleSeriesVisible(Series series) {
-      if (!invisibleSeries.Contains(series)) {
-        series.Points.Clear();
-        invisibleSeries.Add(series);
-      } else {
-        invisibleSeries.Remove(series);
-        if (Content != null) {
-
-          var row = (from r in Content.Rows
-                     where r.Name == series.Name
-                     select r).Single();
-          FillSeriesWithRowValues(series, row);
-          this.chart.Legends[series.Legend].ForeColor = Color.Black;
-          RecalculateAxesScale(chart.ChartAreas[0]);
-          UpdateYCursorInterval();
-        }
-      }
+    public void ShowConfiguration() {
+      chart.ShowConfiguration();
     }
-
-    private void FillSeriesWithRowValues(Series series, DataRow row) {
-      switch (row.VisualProperties.ChartType) {
-        case DataRowVisualProperties.DataRowChartType.Histogram:
-          CalculateHistogram(series, row);
-          break;
-        default: {
-            bool yLogarithmic = series.YAxisType == AxisType.Primary
-                                  ? Content.VisualProperties.YAxisLogScale
-                                  : Content.VisualProperties.SecondYAxisLogScale;
-            bool xLogarithmic = series.XAxisType == AxisType.Primary
-                                  ? Content.VisualProperties.XAxisLogScale
-                                  : Content.VisualProperties.SecondXAxisLogScale;
-            for (int i = 0; i < row.Values.Count; i++) {
-              var value = row.Values[i];
-              var point = new DataPoint();
-              point.XValue = row.VisualProperties.StartIndexZero && !xLogarithmic ? i : i + 1;
-              if (IsInvalidValue(value) || (yLogarithmic && value <= 0))
-                point.IsEmpty = true;
-              else
-                point.YValues = new double[] { value };
-              series.Points.Add(point);
-            }
-          }
-          break;
-      }
-    }
-
-    protected virtual void CalculateHistogram(Series series, DataRow row) {
-      series.Points.Clear();
-      if (!row.Values.Any()) return;
-      int bins = row.VisualProperties.Bins;
-
-      double minValue = row.Values.Min();
-      double maxValue = row.Values.Max();
-      double intervalWidth = (maxValue - minValue) / bins;
-      if (intervalWidth < 0) return;
-      if (intervalWidth == 0) {
-        series.Points.AddXY(minValue, row.Values.Count);
-        return;
-      }
-
-      if (!row.VisualProperties.ExactBins) {
-        intervalWidth = HumanRoundRange(intervalWidth);
-        minValue = Math.Floor(minValue / intervalWidth) * intervalWidth;
-        maxValue = Math.Ceiling(maxValue / intervalWidth) * intervalWidth;
-      }
-
-      double intervalCenter = intervalWidth / 2;
-
-      double min = 0.0, max = 0.0;
-      if (!Double.IsNaN(Content.VisualProperties.XAxisMinimumFixedValue) && !Content.VisualProperties.XAxisMinimumAuto)
-        min = Content.VisualProperties.XAxisMinimumFixedValue;
-      else min = minValue;
-      if (!Double.IsNaN(Content.VisualProperties.XAxisMaximumFixedValue) && !Content.VisualProperties.XAxisMaximumAuto)
-        max = Content.VisualProperties.XAxisMaximumFixedValue;
-      else max = maxValue + intervalWidth;
-
-      double axisInterval = intervalWidth / row.VisualProperties.ScaleFactor;
-
-      var area = chart.ChartAreas[0];
-      area.AxisX.Interval = axisInterval;
-
-      series.SetCustomProperty("PointWidth", "1"); // 0.8 is the default value
-
-      // get the range or intervals which define the grouping of the frequency values
-      var doubleRange = DoubleRange(min, max, intervalWidth).Skip(1).ToList();
-
-      // aggregate the row values by unique key and frequency value
-      var valueFrequencies = (from v in row.Values
-                              where !IsInvalidValue(v)
-                              orderby v
-                              group v by v into g
-                              select new Tuple<double, double>(g.First(), g.Count())).ToList();
-
-      // shift the chart to the left so the bars are placed on the intervals
-      if (valueFrequencies.First().Item1 < doubleRange.First())
-        series.Points.Add(new DataPoint(min - intervalWidth, 0));
-
-      // add data points
-      int j = 0;
-      foreach (var d in doubleRange) {
-        double sum = 0.0;
-        // sum the frequency values that fall within the same interval
-        while (j < valueFrequencies.Count && valueFrequencies[j].Item1 < d) {
-          sum += valueFrequencies[j].Item2;
-          ++j;
-        }
-        string xAxisTitle = string.IsNullOrEmpty(Content.VisualProperties.XAxisTitle)
-                              ? "X"
-                              : Content.VisualProperties.XAxisTitle;
-        string yAxisTitle = string.IsNullOrEmpty(Content.VisualProperties.YAxisTitle)
-                              ? "Y"
-                              : Content.VisualProperties.YAxisTitle;
-        series.Points.Add(new DataPoint(d - intervalCenter, sum) {
-          ToolTip =
-            xAxisTitle + ": [" + (d - intervalWidth) + "-" + d + ")" + Environment.NewLine +
-            yAxisTitle + ": " + sum
-        });
-      }
-    }
-
-    #region Helpers
-    public static IEnumerable<double> DoubleRange(double min, double max, double step) {
-      double i;
-      for (i = min; i <= max; i += step)
-        yield return i;
-
-      if (i != max + step)
-        yield return i;
-    }
-
-    protected void RemoveCustomPropertyIfExists(Series series, string property) {
-      if (series.IsCustomPropertySet(property)) series.DeleteCustomProperty(property);
-    }
-
-    private double HumanRoundRange(double range) {
-      double base10 = Math.Pow(10.0, Math.Floor(Math.Log10(range)));
-      double rounding = range / base10;
-      if (rounding <= 1.5) rounding = 1;
-      else if (rounding <= 2.25) rounding = 2;
-      else if (rounding <= 3.75) rounding = 2.5;
-      else if (rounding <= 7.5) rounding = 5;
-      else rounding = 10;
-      return rounding * base10;
-    }
-
-    private double HumanRoundMax(double max) {
-      double base10;
-      if (max > 0) base10 = Math.Pow(10.0, Math.Floor(Math.Log10(max)));
-      else base10 = Math.Pow(10.0, Math.Ceiling(Math.Log10(-max)));
-      double rounding = (max > 0) ? base10 : -base10;
-      while (rounding < max) rounding += base10;
-      return rounding;
-    }
-
-    private ChartDashStyle ConvertLineStyle(DataRowVisualProperties.DataRowLineStyle dataRowLineStyle) {
-      switch (dataRowLineStyle) {
-        case DataRowVisualProperties.DataRowLineStyle.Dash:
-          return ChartDashStyle.Dash;
-        case DataRowVisualProperties.DataRowLineStyle.DashDot:
-          return ChartDashStyle.DashDot;
-        case DataRowVisualProperties.DataRowLineStyle.DashDotDot:
-          return ChartDashStyle.DashDotDot;
-        case DataRowVisualProperties.DataRowLineStyle.Dot:
-          return ChartDashStyle.Dot;
-        case DataRowVisualProperties.DataRowLineStyle.NotSet:
-          return ChartDashStyle.NotSet;
-        case DataRowVisualProperties.DataRowLineStyle.Solid:
-          return ChartDashStyle.Solid;
-        default:
-          return ChartDashStyle.NotSet;
-      }
-    }
-
-    protected static bool IsInvalidValue(double x) {
-      return double.IsNaN(x) || x < (double)decimal.MinValue || x > (double)decimal.MaxValue;
-    }
-    #endregion
   }
 }
Index: branches/MemPRAlgorithm/HeuristicLab.Analysis.Views/3.3/HeuristicLab.Analysis.Views-3.3.csproj
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Analysis.Views/3.3/HeuristicLab.Analysis.Views-3.3.csproj	(revision 14557)
+++ branches/MemPRAlgorithm/HeuristicLab.Analysis.Views/3.3/HeuristicLab.Analysis.Views-3.3.csproj	(revision 14562)
@@ -105,4 +105,8 @@
   </PropertyGroup>
   <ItemGroup>
+    <Reference Include="ALGLIB-3.7.0, Version=3.7.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <HintPath>..\..\bin\ALGLIB-3.7.0.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
     <Reference Include="System" />
     <Reference Include="System.Core">
@@ -122,4 +126,10 @@
   </ItemGroup>
   <ItemGroup>
+    <Compile Include="DataTableControl.cs">
+      <SubType>UserControl</SubType>
+    </Compile>
+    <Compile Include="DataTableControl.Designer.cs">
+      <DependentUpon>DataTableControl.cs</DependentUpon>
+    </Compile>
     <Compile Include="IndexedDataTableView.cs">
       <SubType>UserControl</SubType>
@@ -127,4 +137,10 @@
     <Compile Include="IndexedDataTableView.Designer.cs">
       <DependentUpon>IndexedDataTableView.cs</DependentUpon>
+    </Compile>
+    <Compile Include="ScatterPlotControl.cs">
+      <SubType>UserControl</SubType>
+    </Compile>
+    <Compile Include="ScatterPlotControl.Designer.cs">
+      <DependentUpon>ScatterPlotControl.cs</DependentUpon>
     </Compile>
     <Compile Include="ScatterPlotVisualPropertiesDialog.cs">
Index: branches/MemPRAlgorithm/HeuristicLab.Analysis.Views/3.3/Plugin.cs.frame
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Analysis.Views/3.3/Plugin.cs.frame	(revision 14557)
+++ branches/MemPRAlgorithm/HeuristicLab.Analysis.Views/3.3/Plugin.cs.frame	(revision 14562)
@@ -28,4 +28,5 @@
   [Plugin("HeuristicLab.Analysis.Views", "3.3.14.$WCREV$")]
   [PluginFile("HeuristicLab.Analysis.Views-3.3.dll", PluginFileType.Assembly)]
+  [PluginDependency("HeuristicLab.ALGLIB", "3.7.0")]
   [PluginDependency("HeuristicLab.Analysis", "3.3")]
   [PluginDependency("HeuristicLab.Collections", "3.3")]
Index: branches/MemPRAlgorithm/HeuristicLab.Analysis.Views/3.3/ScatterPlotControl.Designer.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Analysis.Views/3.3/ScatterPlotControl.Designer.cs	(revision 14562)
+++ branches/MemPRAlgorithm/HeuristicLab.Analysis.Views/3.3/ScatterPlotControl.Designer.cs	(revision 14562)
@@ -0,0 +1,114 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2016 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+namespace HeuristicLab.Analysis.Views {
+  partial class ScatterPlotControl {
+    /// <summary> 
+    /// Required designer variable.
+    /// </summary>
+    private System.ComponentModel.IContainer components = null;
+
+    /// <summary> 
+    /// Clean up any resources being used.
+    /// </summary>
+    /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
+    protected override void Dispose(bool disposing) {
+      if (disposing) {
+        if (components != null) components.Dispose();
+      }
+      base.Dispose(disposing);
+    }
+
+    #region Component Designer generated code
+
+    /// <summary> 
+    /// Required method for Designer support - do not modify 
+    /// the contents of this method with the code editor.
+    /// </summary>
+    private void InitializeComponent() {
+      this.components = new System.ComponentModel.Container();
+      System.Windows.Forms.DataVisualization.Charting.ChartArea chartArea1 = new System.Windows.Forms.DataVisualization.Charting.ChartArea();
+      System.Windows.Forms.DataVisualization.Charting.Legend legend1 = new System.Windows.Forms.DataVisualization.Charting.Legend();
+      System.Windows.Forms.DataVisualization.Charting.Series series1 = new System.Windows.Forms.DataVisualization.Charting.Series();
+      System.Windows.Forms.DataVisualization.Charting.Title title1 = new System.Windows.Forms.DataVisualization.Charting.Title();
+      this.chart = new HeuristicLab.Visualization.ChartControlsExtensions.EnhancedChart();
+      this.configureToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
+      ((System.ComponentModel.ISupportInitialize)(this.chart)).BeginInit();
+      this.SuspendLayout();
+      // 
+      // chart
+      // 
+      this.chart.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) 
+            | System.Windows.Forms.AnchorStyles.Left) 
+            | System.Windows.Forms.AnchorStyles.Right)));
+      this.chart.BorderlineColor = System.Drawing.Color.Black;
+      this.chart.BorderlineDashStyle = System.Windows.Forms.DataVisualization.Charting.ChartDashStyle.Solid;
+      chartArea1.AxisX.Minimum = 0D;
+      chartArea1.CursorX.IsUserEnabled = true;
+      chartArea1.CursorX.IsUserSelectionEnabled = true;
+      chartArea1.CursorY.IsUserEnabled = true;
+      chartArea1.CursorY.IsUserSelectionEnabled = true;
+      chartArea1.Name = "Default";
+      this.chart.ChartAreas.Add(chartArea1);
+      legend1.Alignment = System.Drawing.StringAlignment.Center;
+      legend1.Docking = System.Windows.Forms.DataVisualization.Charting.Docking.Top;
+      legend1.Name = "Default";
+      this.chart.Legends.Add(legend1);
+      this.chart.Location = new System.Drawing.Point(0, 0);
+      this.chart.Name = "chart";
+      series1.ChartArea = "Default";
+      series1.Legend = "Default";
+      series1.Name = "Default";
+      this.chart.Series.Add(series1);
+      this.chart.Size = new System.Drawing.Size(359, 274);
+      this.chart.TabIndex = 3;
+      this.chart.Text = "chart";
+      title1.Font = new System.Drawing.Font("Microsoft Sans Serif", 12F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+      title1.Name = "Default";
+      title1.Text = "Title";
+      this.chart.Titles.Add(title1);
+      this.chart.CustomizeLegend += new System.EventHandler<System.Windows.Forms.DataVisualization.Charting.CustomizeLegendEventArgs>(this.chart_CustomizeLegend);
+      this.chart.MouseDown += new System.Windows.Forms.MouseEventHandler(this.chart_MouseDown);
+      this.chart.MouseMove += new System.Windows.Forms.MouseEventHandler(this.chart_MouseMove);
+      // 
+      // configureToolStripMenuItem
+      // 
+      this.configureToolStripMenuItem.Name = "configureToolStripMenuItem";
+      this.configureToolStripMenuItem.Size = new System.Drawing.Size(256, 22);
+      this.configureToolStripMenuItem.Text = "Configure Chart";
+      this.configureToolStripMenuItem.Click += new System.EventHandler(this.configureToolStripMenuItem_Click);
+      // 
+      // ScatterPlotControl
+      // 
+      this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Inherit;
+      this.Controls.Add(this.chart);
+      this.Name = "ScatterPlotControl";
+      this.Size = new System.Drawing.Size(359, 274);
+      ((System.ComponentModel.ISupportInitialize)(this.chart)).EndInit();
+      this.ResumeLayout(false);
+
+    }
+    #endregion
+
+    protected HeuristicLab.Visualization.ChartControlsExtensions.EnhancedChart chart;
+    private System.Windows.Forms.ToolStripMenuItem configureToolStripMenuItem;
+  }
+}
Index: branches/MemPRAlgorithm/HeuristicLab.Analysis.Views/3.3/ScatterPlotControl.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Analysis.Views/3.3/ScatterPlotControl.cs	(revision 14562)
+++ branches/MemPRAlgorithm/HeuristicLab.Analysis.Views/3.3/ScatterPlotControl.cs	(revision 14562)
@@ -0,0 +1,746 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2016 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.Drawing;
+using System.Linq;
+using System.Text;
+using System.Windows.Forms;
+using System.Windows.Forms.DataVisualization.Charting;
+using HeuristicLab.Collections;
+using HeuristicLab.Common;
+using HeuristicLab.MainForm.WindowsForms;
+
+namespace HeuristicLab.Analysis.Views {
+  public partial class ScatterPlotControl : AsynchronousContentView {
+    protected List<Series> invisibleSeries;
+    protected Dictionary<IObservableList<Point2D<double>>, ScatterPlotDataRow> pointsRowsTable;
+    protected Dictionary<Series, Series> seriesToRegressionSeriesTable;
+    private double xMin, xMax, yMin, yMax;
+
+    public new ScatterPlot Content {
+      get { return (ScatterPlot)base.Content; }
+      set { base.Content = value; }
+    }
+
+    public ScatterPlotControl() {
+      InitializeComponent();
+      pointsRowsTable = new Dictionary<IObservableList<Point2D<double>>, ScatterPlotDataRow>();
+      seriesToRegressionSeriesTable = new Dictionary<Series, Series>();
+      invisibleSeries = new List<Series>();
+      chart.CustomizeAllChartAreas();
+      chart.ChartAreas[0].CursorX.Interval = 1;
+      chart.ContextMenuStrip.Items.Add(configureToolStripMenuItem);
+    }
+
+    #region Event Handler Registration
+    protected override void DeregisterContentEvents() {
+      foreach (ScatterPlotDataRow row in Content.Rows)
+        DeregisterScatterPlotDataRowEvents(row);
+      Content.VisualPropertiesChanged -= new EventHandler(Content_VisualPropertiesChanged);
+      Content.Rows.ItemsAdded -= new CollectionItemsChangedEventHandler<ScatterPlotDataRow>(Rows_ItemsAdded);
+      Content.Rows.ItemsRemoved -= new CollectionItemsChangedEventHandler<ScatterPlotDataRow>(Rows_ItemsRemoved);
+      Content.Rows.ItemsReplaced -= new CollectionItemsChangedEventHandler<ScatterPlotDataRow>(Rows_ItemsReplaced);
+      Content.Rows.CollectionReset -= new CollectionItemsChangedEventHandler<ScatterPlotDataRow>(Rows_CollectionReset);
+    }
+    protected override void RegisterContentEvents() {
+      Content.VisualPropertiesChanged += new EventHandler(Content_VisualPropertiesChanged);
+      Content.Rows.ItemsAdded += new CollectionItemsChangedEventHandler<ScatterPlotDataRow>(Rows_ItemsAdded);
+      Content.Rows.ItemsRemoved += new CollectionItemsChangedEventHandler<ScatterPlotDataRow>(Rows_ItemsRemoved);
+      Content.Rows.ItemsReplaced += new CollectionItemsChangedEventHandler<ScatterPlotDataRow>(Rows_ItemsReplaced);
+      Content.Rows.CollectionReset += new CollectionItemsChangedEventHandler<ScatterPlotDataRow>(Rows_CollectionReset);
+    }
+
+    protected virtual void RegisterScatterPlotDataRowEvents(ScatterPlotDataRow row) {
+      row.NameChanged += new EventHandler(Row_NameChanged);
+      row.VisualPropertiesChanged += new EventHandler(Row_VisualPropertiesChanged);
+      pointsRowsTable.Add(row.Points, row);
+      row.Points.ItemsAdded += new CollectionItemsChangedEventHandler<IndexedItem<Point2D<double>>>(Points_ItemsAdded);
+      row.Points.ItemsRemoved += new CollectionItemsChangedEventHandler<IndexedItem<Point2D<double>>>(Points_ItemsRemoved);
+      row.Points.ItemsReplaced += new CollectionItemsChangedEventHandler<IndexedItem<Point2D<double>>>(Points_ItemsReplaced);
+      row.Points.CollectionReset += new CollectionItemsChangedEventHandler<IndexedItem<Point2D<double>>>(Points_CollectionReset);
+    }
+    protected virtual void DeregisterScatterPlotDataRowEvents(ScatterPlotDataRow row) {
+      row.Points.ItemsAdded -= new CollectionItemsChangedEventHandler<IndexedItem<Point2D<double>>>(Points_ItemsAdded);
+      row.Points.ItemsRemoved -= new CollectionItemsChangedEventHandler<IndexedItem<Point2D<double>>>(Points_ItemsRemoved);
+      row.Points.ItemsReplaced -= new CollectionItemsChangedEventHandler<IndexedItem<Point2D<double>>>(Points_ItemsReplaced);
+      row.Points.CollectionReset -= new CollectionItemsChangedEventHandler<IndexedItem<Point2D<double>>>(Points_CollectionReset);
+      pointsRowsTable.Remove(row.Points);
+      row.VisualPropertiesChanged -= new EventHandler(Row_VisualPropertiesChanged);
+      row.NameChanged -= new EventHandler(Row_NameChanged);
+    }
+    #endregion
+
+    protected override void OnContentChanged() {
+      invisibleSeries.Clear();
+      chart.Titles[0].Text = string.Empty;
+      chart.ChartAreas[0].AxisX.Title = string.Empty;
+      chart.ChartAreas[0].AxisY.Title = string.Empty;
+      chart.Series.Clear();
+      if (Content != null) {
+        chart.Titles[0].Text = Content.Name;
+        chart.Titles[0].Visible = !string.IsNullOrEmpty(Content.Name);
+        AddScatterPlotDataRows(Content.Rows);
+        ConfigureChartArea(chart.ChartAreas[0]);
+        RecalculateMinMaxPointValues();
+        RecalculateAxesScale(chart.ChartAreas[0]);
+      }
+    }
+
+    protected override void SetEnabledStateOfControls() {
+      chart.Enabled = Content != null;
+    }
+
+    public void ShowConfiguration() {
+      if (Content != null) {
+        using (ScatterPlotVisualPropertiesDialog dialog = new ScatterPlotVisualPropertiesDialog(Content)) {
+          dialog.ShowDialog(this);
+        }
+      } else MessageBox.Show("Nothing to configure.");
+    }
+
+    protected virtual void AddScatterPlotDataRows(IEnumerable<ScatterPlotDataRow> rows) {
+      foreach (var row in rows) {
+        RegisterScatterPlotDataRowEvents(row);
+        Series series = new Series(row.Name) {
+          Tag = row
+        };
+        if (row.VisualProperties.DisplayName.Trim() != String.Empty) series.LegendText = row.VisualProperties.DisplayName;
+        else series.LegendText = row.Name;
+        var regressionSeries = new Series(row.Name + "_Regression") {
+          Tag = row,
+          ChartType = SeriesChartType.Line,
+          BorderDashStyle = ChartDashStyle.Dot,
+          IsVisibleInLegend = false,
+          Color = Color.Transparent // to avoid auto color assignment via color palette 
+        };
+        seriesToRegressionSeriesTable.Add(series, regressionSeries);
+        ConfigureSeries(series, regressionSeries, row);
+        FillSeriesWithRowValues(series, row);
+        chart.Series.Add(series);
+        chart.Series.Add(regressionSeries);
+        FillRegressionSeries(regressionSeries, row);
+      }
+      ConfigureChartArea(chart.ChartAreas[0]);
+      RecalculateMinMaxPointValues();
+      RecalculateAxesScale(chart.ChartAreas[0]);
+      UpdateYCursorInterval();
+      UpdateRegressionSeriesColors();
+    }
+
+    protected virtual void RemoveScatterPlotDataRows(IEnumerable<ScatterPlotDataRow> rows) {
+      foreach (var row in rows) {
+        DeregisterScatterPlotDataRowEvents(row);
+        Series series = chart.Series[row.Name];
+        chart.Series.Remove(series);
+        if (invisibleSeries.Contains(series))
+          invisibleSeries.Remove(series);
+        chart.Series.Remove(seriesToRegressionSeriesTable[series]);
+        seriesToRegressionSeriesTable.Remove(series);
+      }
+      RecalculateMinMaxPointValues();
+      RecalculateAxesScale(chart.ChartAreas[0]);
+    }
+
+    private void ConfigureSeries(Series series, Series regressionSeries, ScatterPlotDataRow row) {
+      series.BorderWidth = 1;
+      series.BorderDashStyle = ChartDashStyle.Solid;
+      series.BorderColor = Color.Empty;
+
+      if (row.VisualProperties.Color != Color.Empty)
+        series.Color = row.VisualProperties.Color;
+      else series.Color = Color.Empty;
+      series.IsVisibleInLegend = row.VisualProperties.IsVisibleInLegend;
+      series.ChartType = SeriesChartType.FastPoint;
+      series.MarkerSize = row.VisualProperties.PointSize;
+      series.MarkerStyle = ConvertPointStyle(row.VisualProperties.PointStyle);
+      series.XAxisType = AxisType.Primary;
+      series.YAxisType = AxisType.Primary;
+
+      if (row.VisualProperties.DisplayName.Trim() != String.Empty) series.LegendText = row.VisualProperties.DisplayName;
+      else series.LegendText = row.Name;
+
+      string xAxisTitle = string.IsNullOrEmpty(Content.VisualProperties.XAxisTitle)
+                      ? "X"
+                      : Content.VisualProperties.XAxisTitle;
+      string yAxisTitle = string.IsNullOrEmpty(Content.VisualProperties.YAxisTitle)
+                            ? "Y"
+                            : Content.VisualProperties.YAxisTitle;
+      series.ToolTip =
+        series.LegendText + Environment.NewLine +
+        xAxisTitle + " = " + "#VALX," + Environment.NewLine +
+        yAxisTitle + " = " + "#VAL";
+
+      regressionSeries.BorderWidth = Math.Max(1, row.VisualProperties.PointSize / 2);
+      regressionSeries.IsVisibleInLegend = row.VisualProperties.IsRegressionVisibleInLegend &&
+        row.VisualProperties.RegressionType != ScatterPlotDataRowVisualProperties.ScatterPlotDataRowRegressionType.None;
+      regressionSeries.LegendText = string.IsNullOrEmpty(row.VisualProperties.RegressionDisplayName)
+        ? string.Format("{0}({1})", row.VisualProperties.RegressionType, row.Name)
+        : row.VisualProperties.RegressionDisplayName;
+    }
+
+    private void ConfigureChartArea(ChartArea area) {
+      if (Content.VisualProperties.TitleFont != null) chart.Titles[0].Font = Content.VisualProperties.TitleFont;
+      if (!Content.VisualProperties.TitleColor.IsEmpty) chart.Titles[0].ForeColor = Content.VisualProperties.TitleColor;
+      chart.Titles[0].Text = Content.VisualProperties.Title;
+      chart.Titles[0].Visible = !string.IsNullOrEmpty(Content.VisualProperties.Title);
+
+      if (Content.VisualProperties.AxisTitleFont != null) area.AxisX.TitleFont = Content.VisualProperties.AxisTitleFont;
+      if (!Content.VisualProperties.AxisTitleColor.IsEmpty) area.AxisX.TitleForeColor = Content.VisualProperties.AxisTitleColor;
+      area.AxisX.Title = Content.VisualProperties.XAxisTitle;
+      area.AxisX.MajorGrid.Enabled = Content.VisualProperties.XAxisGrid;
+
+      if (Content.VisualProperties.AxisTitleFont != null) area.AxisY.TitleFont = Content.VisualProperties.AxisTitleFont;
+      if (!Content.VisualProperties.AxisTitleColor.IsEmpty) area.AxisY.TitleForeColor = Content.VisualProperties.AxisTitleColor;
+      area.AxisY.Title = Content.VisualProperties.YAxisTitle;
+      area.AxisY.MajorGrid.Enabled = Content.VisualProperties.YAxisGrid;
+    }
+
+    private void RecalculateAxesScale(ChartArea area) {
+      area.AxisX.Minimum = CalculateMinBound(xMin);
+      area.AxisX.Maximum = CalculateMaxBound(xMax);
+      if (area.AxisX.Minimum == area.AxisX.Maximum) {
+        area.AxisX.Minimum = xMin - 0.5;
+        area.AxisX.Maximum = xMax + 0.5;
+      }
+      area.AxisY.Minimum = CalculateMinBound(yMin);
+      area.AxisY.Maximum = CalculateMaxBound(yMax);
+      if (area.AxisY.Minimum == area.AxisY.Maximum) {
+        area.AxisY.Minimum = yMin - 0.5;
+        area.AxisY.Maximum = yMax + 0.5;
+      }
+      if (xMax - xMin > 0) area.CursorX.Interval = Math.Pow(10, Math.Floor(Math.Log10(area.AxisX.Maximum - area.AxisX.Minimum) - 3));
+      else area.CursorX.Interval = 1;
+      area.AxisX.IsMarginVisible = false;
+
+      if (!Content.VisualProperties.XAxisMinimumAuto && !double.IsNaN(Content.VisualProperties.XAxisMinimumFixedValue)) area.AxisX.Minimum = Content.VisualProperties.XAxisMinimumFixedValue;
+      if (!Content.VisualProperties.XAxisMaximumAuto && !double.IsNaN(Content.VisualProperties.XAxisMaximumFixedValue)) area.AxisX.Maximum = Content.VisualProperties.XAxisMaximumFixedValue;
+      if (!Content.VisualProperties.YAxisMinimumAuto && !double.IsNaN(Content.VisualProperties.YAxisMinimumFixedValue)) area.AxisY.Minimum = Content.VisualProperties.YAxisMinimumFixedValue;
+      if (!Content.VisualProperties.YAxisMaximumAuto && !double.IsNaN(Content.VisualProperties.YAxisMaximumFixedValue)) area.AxisY.Maximum = Content.VisualProperties.YAxisMaximumFixedValue;
+    }
+
+    private static double CalculateMinBound(double min) {
+      if (min == 0) return 0;
+      var scale = Math.Pow(10, Math.Floor(Math.Log10(Math.Abs(min))));
+      return scale * (Math.Floor(min / scale));
+    }
+
+    private static double CalculateMaxBound(double max) {
+      if (max == 0) return 0;
+      var scale = Math.Pow(10, Math.Floor(Math.Log10(Math.Abs(max))));
+      return scale * (Math.Ceiling(max / scale));
+    }
+
+    protected virtual void UpdateYCursorInterval() {
+      double interestingValuesRange = (
+        from series in chart.Series
+        where series.Enabled
+        let values = (from point in series.Points
+                      where !point.IsEmpty
+                      select point.YValues[0]).DefaultIfEmpty(1.0)
+        let range = values.Max() - values.Min()
+        where range > 0.0
+        select range
+        ).DefaultIfEmpty(1.0).Min();
+
+      double digits = (int)Math.Log10(interestingValuesRange) - 3;
+      double yZoomInterval = Math.Pow(10, digits);
+      this.chart.ChartAreas[0].CursorY.Interval = yZoomInterval;
+    }
+
+    protected void UpdateRegressionSeriesColors() {
+      chart.ApplyPaletteColors();
+      foreach (var row in Content.Rows) {
+        var series = chart.Series[row.Name];
+        var regressionSeries = seriesToRegressionSeriesTable[series];
+        regressionSeries.Color = series.Color;
+      }
+    }
+
+    #region Event Handlers
+    #region Content Event Handlers
+    private void Content_VisualPropertiesChanged(object sender, EventArgs e) {
+      if (InvokeRequired)
+        Invoke(new EventHandler(Content_VisualPropertiesChanged), sender, e);
+      else {
+        ConfigureChartArea(chart.ChartAreas[0]);
+        RecalculateAxesScale(chart.ChartAreas[0]); // axes min/max could have changed
+      }
+    }
+    #endregion
+    #region Rows Event Handlers
+    private void Rows_ItemsAdded(object sender, CollectionItemsChangedEventArgs<ScatterPlotDataRow> e) {
+      if (InvokeRequired)
+        Invoke(new CollectionItemsChangedEventHandler<ScatterPlotDataRow>(Rows_ItemsAdded), sender, e);
+      else {
+        AddScatterPlotDataRows(e.Items);
+      }
+    }
+    private void Rows_ItemsRemoved(object sender, CollectionItemsChangedEventArgs<ScatterPlotDataRow> e) {
+      if (InvokeRequired)
+        Invoke(new CollectionItemsChangedEventHandler<ScatterPlotDataRow>(Rows_ItemsRemoved), sender, e);
+      else {
+        RemoveScatterPlotDataRows(e.Items);
+      }
+    }
+    private void Rows_ItemsReplaced(object sender, CollectionItemsChangedEventArgs<ScatterPlotDataRow> e) {
+      if (InvokeRequired)
+        Invoke(new CollectionItemsChangedEventHandler<ScatterPlotDataRow>(Rows_ItemsReplaced), sender, e);
+      else {
+        RemoveScatterPlotDataRows(e.OldItems);
+        AddScatterPlotDataRows(e.Items);
+      }
+    }
+    private void Rows_CollectionReset(object sender, CollectionItemsChangedEventArgs<ScatterPlotDataRow> e) {
+      if (InvokeRequired)
+        Invoke(new CollectionItemsChangedEventHandler<ScatterPlotDataRow>(Rows_CollectionReset), sender, e);
+      else {
+        RemoveScatterPlotDataRows(e.OldItems);
+        AddScatterPlotDataRows(e.Items);
+      }
+    }
+    #endregion
+    #region Row Event Handlers
+    private void Row_VisualPropertiesChanged(object sender, EventArgs e) {
+      if (InvokeRequired)
+        Invoke(new EventHandler(Row_VisualPropertiesChanged), sender, e);
+      else {
+        ScatterPlotDataRow row = (ScatterPlotDataRow)sender;
+        Series series = chart.Series[row.Name];
+        Series regressionSeries = seriesToRegressionSeriesTable[series];
+        series.Points.Clear();
+        regressionSeries.Points.Clear();
+        ConfigureSeries(series, regressionSeries, row);
+        FillSeriesWithRowValues(series, row);
+        FillRegressionSeries(regressionSeries, row);
+        RecalculateMinMaxPointValues();
+        RecalculateAxesScale(chart.ChartAreas[0]);
+        UpdateRegressionSeriesColors();
+      }
+    }
+    private void Row_NameChanged(object sender, EventArgs e) {
+      if (InvokeRequired)
+        Invoke(new EventHandler(Row_NameChanged), sender, e);
+      else {
+        ScatterPlotDataRow row = (ScatterPlotDataRow)sender;
+        chart.Series[row.Name].Name = row.Name;
+      }
+    }
+    #endregion
+    #region Points Event Handlers
+    private void Points_ItemsAdded(object sender, CollectionItemsChangedEventArgs<IndexedItem<Point2D<double>>> e) {
+      if (InvokeRequired)
+        Invoke(new CollectionItemsChangedEventHandler<IndexedItem<Point2D<double>>>(Points_ItemsAdded), sender, e);
+      else {
+        ScatterPlotDataRow row = null;
+        pointsRowsTable.TryGetValue((IObservableList<Point2D<double>>)sender, out row);
+        if (row != null) {
+          Series rowSeries = chart.Series[row.Name];
+          Series regressionSeries = seriesToRegressionSeriesTable[rowSeries];
+          if (!invisibleSeries.Contains(rowSeries)) {
+            rowSeries.Points.Clear();
+            regressionSeries.Points.Clear();
+            FillSeriesWithRowValues(rowSeries, row);
+            FillRegressionSeries(regressionSeries, row);
+            RecalculateMinMaxPointValues();
+            RecalculateAxesScale(chart.ChartAreas[0]);
+            UpdateYCursorInterval();
+          }
+        }
+      }
+    }
+    private void Points_ItemsRemoved(object sender, CollectionItemsChangedEventArgs<IndexedItem<Point2D<double>>> e) {
+      if (InvokeRequired)
+        Invoke(new CollectionItemsChangedEventHandler<IndexedItem<Point2D<double>>>(Points_ItemsRemoved), sender, e);
+      else {
+        ScatterPlotDataRow row = null;
+        pointsRowsTable.TryGetValue((IObservableList<Point2D<double>>)sender, out row);
+        if (row != null) {
+          Series rowSeries = chart.Series[row.Name];
+          Series regressionSeries = seriesToRegressionSeriesTable[rowSeries];
+          if (!invisibleSeries.Contains(rowSeries)) {
+            rowSeries.Points.Clear();
+            regressionSeries.Points.Clear();
+            FillSeriesWithRowValues(rowSeries, row);
+            FillRegressionSeries(regressionSeries, row);
+            RecalculateMinMaxPointValues();
+            RecalculateAxesScale(chart.ChartAreas[0]);
+            UpdateYCursorInterval();
+          }
+        }
+      }
+    }
+    private void Points_ItemsReplaced(object sender, CollectionItemsChangedEventArgs<IndexedItem<Point2D<double>>> e) {
+      if (InvokeRequired)
+        Invoke(new CollectionItemsChangedEventHandler<IndexedItem<Point2D<double>>>(Points_ItemsReplaced), sender, e);
+      else {
+        ScatterPlotDataRow row = null;
+        pointsRowsTable.TryGetValue((IObservableList<Point2D<double>>)sender, out row);
+        if (row != null) {
+          Series rowSeries = chart.Series[row.Name];
+          Series regressionSeries = seriesToRegressionSeriesTable[rowSeries];
+          if (!invisibleSeries.Contains(rowSeries)) {
+            rowSeries.Points.Clear();
+            regressionSeries.Points.Clear();
+            FillSeriesWithRowValues(rowSeries, row);
+            FillRegressionSeries(regressionSeries, row);
+            RecalculateMinMaxPointValues();
+            RecalculateAxesScale(chart.ChartAreas[0]);
+            UpdateYCursorInterval();
+          }
+        }
+      }
+    }
+    private void Points_CollectionReset(object sender, CollectionItemsChangedEventArgs<IndexedItem<Point2D<double>>> e) {
+      if (InvokeRequired)
+        Invoke(new CollectionItemsChangedEventHandler<IndexedItem<Point2D<double>>>(Points_CollectionReset), sender, e);
+      else {
+        ScatterPlotDataRow row = null;
+        pointsRowsTable.TryGetValue((IObservableList<Point2D<double>>)sender, out row);
+        if (row != null) {
+          Series rowSeries = chart.Series[row.Name];
+          Series regressionSeries = seriesToRegressionSeriesTable[rowSeries];
+          if (!invisibleSeries.Contains(rowSeries)) {
+            rowSeries.Points.Clear();
+            regressionSeries.Points.Clear();
+            FillSeriesWithRowValues(rowSeries, row);
+            FillRegressionSeries(regressionSeries, row);
+            RecalculateMinMaxPointValues();
+            RecalculateAxesScale(chart.ChartAreas[0]);
+            UpdateYCursorInterval();
+          }
+        }
+      }
+    }
+    #endregion
+    private void configureToolStripMenuItem_Click(object sender, System.EventArgs e) {
+      ShowConfiguration();
+    }
+    #endregion
+
+    #region Chart Event Handlers
+    private void chart_MouseDown(object sender, MouseEventArgs e) {
+      HitTestResult result = chart.HitTest(e.X, e.Y);
+      if (result.ChartElementType == ChartElementType.LegendItem) {
+        ToggleSeriesVisible(result.Series);
+      }
+    }
+    private void chart_MouseMove(object sender, MouseEventArgs e) {
+      HitTestResult result = chart.HitTest(e.X, e.Y);
+      if (result.ChartElementType == ChartElementType.LegendItem)
+        this.Cursor = Cursors.Hand;
+      else
+        this.Cursor = Cursors.Default;
+    }
+    private void chart_CustomizeLegend(object sender, CustomizeLegendEventArgs e) {
+      foreach (LegendItem legendItem in e.LegendItems) {
+        var series = chart.Series[legendItem.SeriesName];
+        if (series != null) {
+          bool seriesIsInvisible = invisibleSeries.Contains(series);
+          foreach (LegendCell cell in legendItem.Cells) {
+            cell.ForeColor = seriesIsInvisible ? Color.Gray : Color.Black;
+          }
+        }
+      }
+    }
+    #endregion
+
+    private void ToggleSeriesVisible(Series series) {
+      if (!invisibleSeries.Contains(series)) {
+        series.Points.Clear();
+        invisibleSeries.Add(series);
+        RecalculateMinMaxPointValues();
+      } else {
+        invisibleSeries.Remove(series);
+        if (Content != null) {
+          var row = (ScatterPlotDataRow)series.Tag;
+          if (seriesToRegressionSeriesTable.ContainsKey(series))
+            FillSeriesWithRowValues(series, row);
+          else
+            FillRegressionSeries(series, row);
+          RecalculateMinMaxPointValues();
+          this.chart.Legends[series.Legend].ForeColor = Color.Black;
+          RecalculateAxesScale(chart.ChartAreas[0]);
+          UpdateYCursorInterval();
+        }
+      }
+    }
+
+    private void RecalculateMinMaxPointValues() {
+      yMin = xMin = double.MaxValue;
+      yMax = xMax = double.MinValue;
+      foreach (var s in chart.Series.Where(x => x.Enabled)) {
+        foreach (var p in s.Points) {
+          double x = p.XValue, y = p.YValues[0];
+          if (xMin > x) xMin = x;
+          if (xMax < x) xMax = x;
+          if (yMin > y) yMin = y;
+          if (yMax < y) yMax = y;
+        }
+      }
+    }
+
+    private void FillSeriesWithRowValues(Series series, ScatterPlotDataRow row) {
+      bool zerosOnly = true;
+      for (int i = 0; i < row.Points.Count; i++) {
+        var value = row.Points[i];
+        DataPoint point = new DataPoint();
+        if (IsInvalidValue(value.X) || IsInvalidValue(value.Y))
+          point.IsEmpty = true;
+        else {
+          point.XValue = value.X;
+          point.YValues = new double[] { value.Y };
+        }
+        series.Points.Add(point);
+        if (value.X != 0.0f)
+          zerosOnly = false;
+      }
+      if (zerosOnly) // if all x-values are zero, the x-values are interpreted as 1, 2, 3, ...
+        series.Points.Add(new DataPoint(1, 1) { IsEmpty = true });
+      double correlation = Correlation(row.Points);
+      series.LegendToolTip = string.Format("Correlation (R²) = {0:G4}", correlation * correlation);
+    }
+
+    private void FillRegressionSeries(Series regressionSeries, ScatterPlotDataRow row) {
+      if (row.VisualProperties.RegressionType == ScatterPlotDataRowVisualProperties.ScatterPlotDataRowRegressionType.None
+        || invisibleSeries.Contains(regressionSeries))
+        return;
+
+      double[] coefficients;
+      if (!Fitting(row, out coefficients))
+        return;
+
+      // Fill regrssion series
+      var validPoints = row.Points.Where(p => !IsInvalidValue(p.X));
+      double min = validPoints.Min(p => p.X), max = validPoints.Max(p => p.X);
+      double range = max - min, delta = range / row.Points.Count;
+      for (double x = min; x < max; x += delta) {
+        regressionSeries.Points.AddXY(x, Estimate(x, row, coefficients));
+      }
+
+      // Correlation
+      var data = row.Points.Select(p => new Point2D<double>(p.Y, Estimate(p.X, row, coefficients)));
+      double correlation = Correlation(data.ToList());
+      regressionSeries.LegendToolTip = GetStringFormula(row, coefficients) + Environment.NewLine +
+                                       string.Format("Correlation (R²) = {0:G4}", correlation * correlation);
+      regressionSeries.ToolTip = GetStringFormula(row, coefficients);
+    }
+
+    #region Helpers
+    private MarkerStyle ConvertPointStyle(ScatterPlotDataRowVisualProperties.ScatterPlotDataRowPointStyle pointStyle) {
+      switch (pointStyle) {
+        case ScatterPlotDataRowVisualProperties.ScatterPlotDataRowPointStyle.Circle:
+          return MarkerStyle.Circle;
+        case ScatterPlotDataRowVisualProperties.ScatterPlotDataRowPointStyle.Cross:
+          return MarkerStyle.Cross;
+        case ScatterPlotDataRowVisualProperties.ScatterPlotDataRowPointStyle.Diamond:
+          return MarkerStyle.Diamond;
+        case ScatterPlotDataRowVisualProperties.ScatterPlotDataRowPointStyle.Square:
+          return MarkerStyle.Square;
+        case ScatterPlotDataRowVisualProperties.ScatterPlotDataRowPointStyle.Star4:
+          return MarkerStyle.Star4;
+        case ScatterPlotDataRowVisualProperties.ScatterPlotDataRowPointStyle.Star5:
+          return MarkerStyle.Star5;
+        case ScatterPlotDataRowVisualProperties.ScatterPlotDataRowPointStyle.Star6:
+          return MarkerStyle.Star6;
+        case ScatterPlotDataRowVisualProperties.ScatterPlotDataRowPointStyle.Star10:
+          return MarkerStyle.Star10;
+        case ScatterPlotDataRowVisualProperties.ScatterPlotDataRowPointStyle.Triangle:
+          return MarkerStyle.Triangle;
+        default:
+          return MarkerStyle.None;
+      }
+    }
+
+    protected static bool IsInvalidValue(double x) {
+      return double.IsNaN(x) || x < (double)decimal.MinValue || x > (double)decimal.MaxValue;
+    }
+    #endregion
+
+    #region Correlation and Fitting Helper
+    protected static double Correlation(IList<Point2D<double>> values) {
+      // sums of x, y, x squared etc.
+      double sx = 0.0;
+      double sy = 0.0;
+      double sxx = 0.0;
+      double syy = 0.0;
+      double sxy = 0.0;
+
+      int n = 0;
+      for (int i = 0; i < values.Count; i++) {
+        double x = values[i].X;
+        double y = values[i].Y;
+        if (IsInvalidValue(x) || IsInvalidValue(y))
+          continue;
+
+        sx += x;
+        sy += y;
+        sxx += x * x;
+        syy += y * y;
+        sxy += x * y;
+        n++;
+      }
+
+      // covariation
+      double cov = sxy / n - sx * sy / n / n;
+      // standard error of x
+      double sigmaX = Math.Sqrt(sxx / n -  sx * sx / n / n);
+      // standard error of y
+      double sigmaY = Math.Sqrt(syy / n -  sy * sy / n / n);
+
+      // correlation
+      return cov / sigmaX / sigmaY;
+    }
+
+    protected static bool Fitting(ScatterPlotDataRow row, out double[] coefficients) {
+      var xs = row.Points.Select(p => p.X).ToList();
+      var ys = row.Points.Select(p => p.Y).ToList();
+
+      // Input transformations
+      double[,] matrix;
+      int nRows;
+      switch (row.VisualProperties.RegressionType) {
+        case ScatterPlotDataRowVisualProperties.ScatterPlotDataRowRegressionType.Linear:
+          matrix = CreateMatrix(out nRows, ys, xs);
+          break;
+        case ScatterPlotDataRowVisualProperties.ScatterPlotDataRowRegressionType.Polynomial:
+          var xss = Enumerable.Range(1, row.VisualProperties.PolynomialRegressionOrder)
+            .Select(o => xs.Select(x => Math.Pow(x, o)).ToList())
+            .Reverse(); // higher order first
+          matrix = CreateMatrix(out nRows, ys, xss.ToArray());
+          break;
+        case ScatterPlotDataRowVisualProperties.ScatterPlotDataRowRegressionType.Exponential:
+          matrix = CreateMatrix(out nRows, ys.Select(y => Math.Log(y)).ToList(), xs);
+          break;
+        case ScatterPlotDataRowVisualProperties.ScatterPlotDataRowRegressionType.Power:
+          matrix = CreateMatrix(out nRows, ys.Select(y => Math.Log(y)).ToList(), xs.Select(x => Math.Log(x)).ToList());
+          break;
+        case ScatterPlotDataRowVisualProperties.ScatterPlotDataRowRegressionType.Logarithmic:
+          matrix = CreateMatrix(out nRows, ys, xs.Select(x => Math.Log(x)).ToList());
+          break;
+        default:
+          throw new ArgumentException("Unknown RegressionType: " + row.VisualProperties.RegressionType);
+      }
+
+      // Linear fitting
+      bool success = LinearFitting(matrix, nRows, out coefficients);
+      if (!success) return success;
+
+      // Output transformation
+      switch (row.VisualProperties.RegressionType) {
+        case ScatterPlotDataRowVisualProperties.ScatterPlotDataRowRegressionType.Exponential:
+        case ScatterPlotDataRowVisualProperties.ScatterPlotDataRowRegressionType.Power:
+          coefficients[1] = Math.Exp(coefficients[1]);
+          break;
+      }
+
+      return true;
+    }
+    protected static double[,] CreateMatrix(out int nRows, IList<double> ys, params IList<double>[] xss) {
+      var matrix = new double[ys.Count, xss.Length + 1];
+      int rowIdx = 0;
+      for (int i = 0; i < ys.Count; i++) {
+        if (IsInvalidValue(ys[i]) || xss.Any(xs => IsInvalidValue(xs[i])))
+          continue;
+        for (int j = 0; j < xss.Length; j++) {
+          matrix[rowIdx, j] = xss[j][i];
+        }
+        matrix[rowIdx, xss.Length] = ys[i];
+        rowIdx++;
+      }
+      nRows = rowIdx;
+      return matrix;
+    }
+
+    protected static bool LinearFitting(double[,] xsy, int nRows, out double[] coefficients) {
+      int nFeatures = xsy.GetLength(1) - 1;
+
+      alglib.linearmodel lm;
+      alglib.lrreport ar;
+      int retVal;
+      alglib.lrbuild(xsy, nRows, nFeatures, out retVal, out lm, out ar);
+      if (retVal != 1) {
+        coefficients = new double[0];
+        return false;
+      }
+
+      alglib.lrunpack(lm, out coefficients, out nFeatures);
+      return true;
+    }
+
+    protected static double Estimate(double x, ScatterPlotDataRow row, double[] coefficients) {
+      switch (row.VisualProperties.RegressionType) {
+        case ScatterPlotDataRowVisualProperties.ScatterPlotDataRowRegressionType.Linear:
+          return coefficients[0] * x + coefficients[1];
+        case ScatterPlotDataRowVisualProperties.ScatterPlotDataRowRegressionType.Polynomial:
+          return coefficients
+            .Reverse() // to match index and order
+            .Select((c, o) => c * Math.Pow(x, o))
+            .Sum();
+        case ScatterPlotDataRowVisualProperties.ScatterPlotDataRowRegressionType.Exponential:
+          return coefficients[1] * Math.Exp(coefficients[0] * x);
+        case ScatterPlotDataRowVisualProperties.ScatterPlotDataRowRegressionType.Power:
+          return coefficients[1] * Math.Pow(x, coefficients[0]);
+        case ScatterPlotDataRowVisualProperties.ScatterPlotDataRowRegressionType.Logarithmic:
+          return coefficients[0] * Math.Log(x) + coefficients[1];
+        default:
+          throw new ArgumentException("Unknown RegressionType: " + row.VisualProperties.RegressionType);
+      }
+    }
+
+    protected static string GetStringFormula(ScatterPlotDataRow row, double[] coefficients) {
+      switch (row.VisualProperties.RegressionType) {
+        case ScatterPlotDataRowVisualProperties.ScatterPlotDataRowRegressionType.Linear:
+          return string.Format("{0:G4} x {1} {2:G4}", coefficients[0], Sign(coefficients[1]), Math.Abs(coefficients[1]));
+        case ScatterPlotDataRowVisualProperties.ScatterPlotDataRowRegressionType.Polynomial:
+          var sb = new StringBuilder();
+          sb.AppendFormat("{0:G4}{1}", coefficients[0], PolyFactor(coefficients.Length - 1));
+          foreach (var x in coefficients
+            .Reverse() // match index and order
+            .Select((c, o) => new { c, o })
+            .Reverse() // higher order first
+            .Skip(1)) // highest order poly already added
+            sb.AppendFormat(" {0} {1:G4}{2}", Sign(x.c), Math.Abs(x.c), PolyFactor(x.o));
+          return sb.ToString();
+        case ScatterPlotDataRowVisualProperties.ScatterPlotDataRowRegressionType.Exponential:
+          return string.Format("{0:G4} e^({1:G4} x)", coefficients[1], coefficients[0]);
+        case ScatterPlotDataRowVisualProperties.ScatterPlotDataRowRegressionType.Power:
+          return string.Format("{0:G4} x^({1:G4})", coefficients[1], coefficients[0]);
+        case ScatterPlotDataRowVisualProperties.ScatterPlotDataRowRegressionType.Logarithmic:
+          return string.Format("{0:G4} ln(x) {1} {2:G4}", coefficients[0], Sign(coefficients[1]), Math.Abs(coefficients[1]));
+        default:
+          throw new ArgumentException("Unknown RegressionType: " + row.VisualProperties.RegressionType);
+      }
+    }
+    private static string Sign(double value) {
+      return value >= 0 ? "+" : "-";
+    }
+    private static string PolyFactor(int order) {
+      if (order == 0) return "";
+      if (order == 1) return " x";
+      if (order == 2) return " x²";
+      if (order == 3) return " x³";
+      return " x^" + order;
+    }
+    #endregion
+  }
+}
Index: branches/MemPRAlgorithm/HeuristicLab.Analysis.Views/3.3/ScatterPlotDataRowVisualPropertiesControl.Designer.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Analysis.Views/3.3/ScatterPlotDataRowVisualPropertiesControl.Designer.cs	(revision 14557)
+++ branches/MemPRAlgorithm/HeuristicLab.Analysis.Views/3.3/ScatterPlotDataRowVisualPropertiesControl.Designer.cs	(revision 14562)
@@ -45,4 +45,5 @@
     /// </summary>
     private void InitializeComponent() {
+      this.components = new System.ComponentModel.Container();
       this.pointStyleComboBox = new System.Windows.Forms.ComboBox();
       this.colorDialog = new System.Windows.Forms.ColorDialog();
@@ -56,5 +57,15 @@
       this.label9 = new System.Windows.Forms.Label();
       this.label7 = new System.Windows.Forms.Label();
+      this.label4 = new System.Windows.Forms.Label();
+      this.regressionTypeComboBox = new System.Windows.Forms.ComboBox();
+      this.regressionGroupBox = new System.Windows.Forms.GroupBox();
+      this.isRegressionVisibleInLegendCheckBox = new System.Windows.Forms.CheckBox();
+      this.polynomialRegressionOrderNumericUpDown = new System.Windows.Forms.NumericUpDown();
+      this.orderLabel = new System.Windows.Forms.Label();
+      this.regressionLegendTextBox = new System.Windows.Forms.TextBox();
+      this.toolTip = new System.Windows.Forms.ToolTip(this.components);
       ((System.ComponentModel.ISupportInitialize)(this.pointSizeNumericUpDown)).BeginInit();
+      this.regressionGroupBox.SuspendLayout();
+      ((System.ComponentModel.ISupportInitialize)(this.polynomialRegressionOrderNumericUpDown)).BeginInit();
       this.SuspendLayout();
       // 
@@ -171,7 +182,104 @@
       this.label7.Text = "&Visible in Legend:";
       // 
+      // label4
+      // 
+      this.label4.AutoSize = true;
+      this.label4.Location = new System.Drawing.Point(6, 22);
+      this.label4.Name = "label4";
+      this.label4.Size = new System.Drawing.Size(34, 13);
+      this.label4.TabIndex = 7;
+      this.label4.Text = "Type:";
+      // 
+      // regressionTypeComboBox
+      // 
+      this.regressionTypeComboBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
+            | System.Windows.Forms.AnchorStyles.Right)));
+      this.regressionTypeComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
+      this.regressionTypeComboBox.FormattingEnabled = true;
+      this.regressionTypeComboBox.Location = new System.Drawing.Point(93, 19);
+      this.regressionTypeComboBox.Name = "regressionTypeComboBox";
+      this.regressionTypeComboBox.Size = new System.Drawing.Size(147, 21);
+      this.regressionTypeComboBox.TabIndex = 8;
+      this.regressionTypeComboBox.SelectedValueChanged += new System.EventHandler(this.regressionTypeComboBox_SelectedValueChanged);
+      // 
+      // regressionGroupBox
+      // 
+      this.regressionGroupBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
+            | System.Windows.Forms.AnchorStyles.Right)));
+      this.regressionGroupBox.Controls.Add(this.isRegressionVisibleInLegendCheckBox);
+      this.regressionGroupBox.Controls.Add(this.regressionTypeComboBox);
+      this.regressionGroupBox.Controls.Add(this.polynomialRegressionOrderNumericUpDown);
+      this.regressionGroupBox.Controls.Add(this.orderLabel);
+      this.regressionGroupBox.Controls.Add(this.regressionLegendTextBox);
+      this.regressionGroupBox.Controls.Add(this.label4);
+      this.regressionGroupBox.Location = new System.Drawing.Point(3, 136);
+      this.regressionGroupBox.Name = "regressionGroupBox";
+      this.regressionGroupBox.Size = new System.Drawing.Size(336, 74);
+      this.regressionGroupBox.TabIndex = 9;
+      this.regressionGroupBox.TabStop = false;
+      this.regressionGroupBox.Text = "&Regression";
+      // 
+      // isRegressionVisibleInLegendCheckBox
+      // 
+      this.isRegressionVisibleInLegendCheckBox.AutoSize = true;
+      this.isRegressionVisibleInLegendCheckBox.CheckAlign = System.Drawing.ContentAlignment.MiddleRight;
+      this.isRegressionVisibleInLegendCheckBox.Location = new System.Drawing.Point(6, 48);
+      this.isRegressionVisibleInLegendCheckBox.Name = "isRegressionVisibleInLegendCheckBox";
+      this.isRegressionVisibleInLegendCheckBox.Size = new System.Drawing.Size(68, 17);
+      this.isRegressionVisibleInLegendCheckBox.TabIndex = 13;
+      this.isRegressionVisibleInLegendCheckBox.Text = "Legend: ";
+      this.isRegressionVisibleInLegendCheckBox.UseVisualStyleBackColor = true;
+      this.isRegressionVisibleInLegendCheckBox.CheckedChanged += new System.EventHandler(this.isRegressionVisibleInLegendCheckBox_CheckedChanged);
+      // 
+      // polynomialRegressionOrderNumericUpDown
+      // 
+      this.polynomialRegressionOrderNumericUpDown.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
+      this.polynomialRegressionOrderNumericUpDown.Location = new System.Drawing.Point(285, 20);
+      this.polynomialRegressionOrderNumericUpDown.Margin = new System.Windows.Forms.Padding(9, 3, 3, 3);
+      this.polynomialRegressionOrderNumericUpDown.Maximum = new decimal(new int[] {
+            6,
+            0,
+            0,
+            0});
+      this.polynomialRegressionOrderNumericUpDown.Minimum = new decimal(new int[] {
+            2,
+            0,
+            0,
+            0});
+      this.polynomialRegressionOrderNumericUpDown.Name = "polynomialRegressionOrderNumericUpDown";
+      this.polynomialRegressionOrderNumericUpDown.Size = new System.Drawing.Size(45, 20);
+      this.polynomialRegressionOrderNumericUpDown.TabIndex = 11;
+      this.toolTip.SetToolTip(this.polynomialRegressionOrderNumericUpDown, "Order only available for Polynomial");
+      this.polynomialRegressionOrderNumericUpDown.Value = new decimal(new int[] {
+            2,
+            0,
+            0,
+            0});
+      this.polynomialRegressionOrderNumericUpDown.ValueChanged += new System.EventHandler(this.polynomialRegressionOrderNumericUpDown_ValueChanged);
+      // 
+      // orderLabel
+      // 
+      this.orderLabel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
+      this.orderLabel.AutoSize = true;
+      this.orderLabel.Location = new System.Drawing.Point(246, 22);
+      this.orderLabel.Name = "orderLabel";
+      this.orderLabel.Size = new System.Drawing.Size(36, 13);
+      this.orderLabel.TabIndex = 12;
+      this.orderLabel.Text = "Order:";
+      // 
+      // regressionLegendTextBox
+      // 
+      this.regressionLegendTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
+            | System.Windows.Forms.AnchorStyles.Right)));
+      this.regressionLegendTextBox.Location = new System.Drawing.Point(93, 46);
+      this.regressionLegendTextBox.Name = "regressionLegendTextBox";
+      this.regressionLegendTextBox.Size = new System.Drawing.Size(237, 20);
+      this.regressionLegendTextBox.TabIndex = 10;
+      this.regressionLegendTextBox.Validated += new System.EventHandler(this.regressionLegendTextBox_Validated);
+      // 
       // ScatterPlotDataRowVisualPropertiesControl
       // 
       this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Inherit;
+      this.Controls.Add(this.regressionGroupBox);
       this.Controls.Add(this.pointSizeNumericUpDown);
       this.Controls.Add(this.isVisibleInLegendCheckBox);
@@ -185,6 +293,9 @@
       this.Controls.Add(this.colorButton);
       this.Name = "ScatterPlotDataRowVisualPropertiesControl";
-      this.Size = new System.Drawing.Size(342, 135);
+      this.Size = new System.Drawing.Size(342, 215);
       ((System.ComponentModel.ISupportInitialize)(this.pointSizeNumericUpDown)).EndInit();
+      this.regressionGroupBox.ResumeLayout(false);
+      this.regressionGroupBox.PerformLayout();
+      ((System.ComponentModel.ISupportInitialize)(this.polynomialRegressionOrderNumericUpDown)).EndInit();
       this.ResumeLayout(false);
       this.PerformLayout();
@@ -205,4 +316,12 @@
     private System.Windows.Forms.Label label9;
     private System.Windows.Forms.Label label3;
+    private System.Windows.Forms.Label label4;
+    private System.Windows.Forms.ComboBox regressionTypeComboBox;
+    private System.Windows.Forms.GroupBox regressionGroupBox;
+    private System.Windows.Forms.TextBox regressionLegendTextBox;
+    private System.Windows.Forms.NumericUpDown polynomialRegressionOrderNumericUpDown;
+    private System.Windows.Forms.Label orderLabel;
+    private System.Windows.Forms.ToolTip toolTip;
+    private System.Windows.Forms.CheckBox isRegressionVisibleInLegendCheckBox;
   }
 }
Index: branches/MemPRAlgorithm/HeuristicLab.Analysis.Views/3.3/ScatterPlotDataRowVisualPropertiesControl.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Analysis.Views/3.3/ScatterPlotDataRowVisualPropertiesControl.cs	(revision 14557)
+++ branches/MemPRAlgorithm/HeuristicLab.Analysis.Views/3.3/ScatterPlotDataRowVisualPropertiesControl.cs	(revision 14562)
@@ -44,4 +44,5 @@
       InitializeComponent();
       pointStyleComboBox.DataSource = Enum.GetValues(typeof(ScatterPlotDataRowVisualProperties.ScatterPlotDataRowPointStyle));
+      regressionTypeComboBox.DataSource = Enum.GetValues(typeof(ScatterPlotDataRowVisualProperties.ScatterPlotDataRowRegressionType));
       SetEnabledStateOfControls();
     }
@@ -57,4 +58,8 @@
           pointSizeNumericUpDown.Value = 1;
           displayNameTextBox.Text = String.Empty;
+          regressionTypeComboBox.SelectedIndex = -1;
+          polynomialRegressionOrderNumericUpDown.Value = 2;
+          isRegressionVisibleInLegendCheckBox.Checked = false;
+          regressionLegendTextBox.Text = string.Empty;
         } else {
           displayNameTextBox.Text = Content.DisplayName;
@@ -69,4 +74,8 @@
           pointSizeNumericUpDown.Value = Content.PointSize;
           isVisibleInLegendCheckBox.Checked = Content.IsVisibleInLegend;
+          regressionTypeComboBox.SelectedItem = Content.RegressionType;
+          polynomialRegressionOrderNumericUpDown.Value = Content.PolynomialRegressionOrder;
+          isRegressionVisibleInLegendCheckBox.Checked = Content.IsRegressionVisibleInLegend;
+          regressionLegendTextBox.Text = content.RegressionDisplayName;
         }
       }
@@ -82,4 +91,9 @@
       pointSizeNumericUpDown.Enabled = Content != null;
       displayNameTextBox.Enabled = Content != null;
+      regressionTypeComboBox.Enabled = Content != null;
+      polynomialRegressionOrderNumericUpDown.Enabled = Content != null && Content.RegressionType == ScatterPlotDataRowVisualProperties.ScatterPlotDataRowRegressionType.Polynomial;
+      orderLabel.Enabled = polynomialRegressionOrderNumericUpDown.Enabled;
+      isRegressionVisibleInLegendCheckBox.Enabled = Content != null && Content.RegressionType != ScatterPlotDataRowVisualProperties.ScatterPlotDataRowRegressionType.None;
+      regressionLegendTextBox.Enabled = Content != null && Content.RegressionType != ScatterPlotDataRowVisualProperties.ScatterPlotDataRowRegressionType.None;
     }
 
@@ -87,5 +101,5 @@
     private void pointStyleComboBox_SelectedValueChanged(object sender, EventArgs e) {
       if (!SuppressEvents && Content != null) {
-        ScatterPlotDataRowVisualProperties.ScatterPlotDataRowPointStyle selected = (ScatterPlotDataRowVisualProperties.ScatterPlotDataRowPointStyle)pointStyleComboBox.SelectedValue;
+        var selected = (ScatterPlotDataRowVisualProperties.ScatterPlotDataRowPointStyle)pointStyleComboBox.SelectedValue;
         Content.PointStyle = selected;
       }
@@ -121,4 +135,30 @@
       }
     }
+
+    private void regressionTypeComboBox_SelectedValueChanged(object sender, EventArgs e) {
+      if (!SuppressEvents && Content != null) {
+        var selected = (ScatterPlotDataRowVisualProperties.ScatterPlotDataRowRegressionType)regressionTypeComboBox.SelectedValue;
+        Content.RegressionType = selected;
+        SetEnabledStateOfControls();
+      }
+    }
+
+    private void polynomialRegressionOrderNumericUpDown_ValueChanged(object sender, EventArgs e) {
+      if (!SuppressEvents && Content != null) {
+        Content.PolynomialRegressionOrder = (int)polynomialRegressionOrderNumericUpDown.Value;
+      }
+    }
+
+    private void isRegressionVisibleInLegendCheckBox_CheckedChanged(object sender, EventArgs e) {
+      if (!SuppressEvents && Content != null) {
+        Content.IsRegressionVisibleInLegend = isRegressionVisibleInLegendCheckBox.Checked;
+      }
+    }
+
+    private void regressionLegendTextBox_Validated(object sender, EventArgs e) {
+      if (!SuppressEvents && Content != null) {
+        Content.RegressionDisplayName = regressionLegendTextBox.Text;
+      }
+    }
     #endregion
   }
Index: branches/MemPRAlgorithm/HeuristicLab.Analysis.Views/3.3/ScatterPlotView.Designer.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Analysis.Views/3.3/ScatterPlotView.Designer.cs	(revision 14557)
+++ branches/MemPRAlgorithm/HeuristicLab.Analysis.Views/3.3/ScatterPlotView.Designer.cs	(revision 14562)
@@ -45,11 +45,6 @@
     /// </summary>
     private void InitializeComponent() {
-      System.Windows.Forms.DataVisualization.Charting.ChartArea chartArea1 = new System.Windows.Forms.DataVisualization.Charting.ChartArea();
-      System.Windows.Forms.DataVisualization.Charting.Legend legend1 = new System.Windows.Forms.DataVisualization.Charting.Legend();
-      System.Windows.Forms.DataVisualization.Charting.Series series1 = new System.Windows.Forms.DataVisualization.Charting.Series();
-      System.Windows.Forms.DataVisualization.Charting.Title title1 = new System.Windows.Forms.DataVisualization.Charting.Title();
-      this.chart = new HeuristicLab.Visualization.ChartControlsExtensions.EnhancedChart();
+      this.chart = new HeuristicLab.Analysis.Views.ScatterPlotControl();
       ((System.ComponentModel.ISupportInitialize)(this.errorProvider)).BeginInit();
-      ((System.ComponentModel.ISupportInitialize)(this.chart)).BeginInit();
       this.SuspendLayout();
       // 
@@ -70,33 +65,9 @@
                   | System.Windows.Forms.AnchorStyles.Left)
                   | System.Windows.Forms.AnchorStyles.Right)));
-      this.chart.BorderlineColor = System.Drawing.Color.Black;
-      this.chart.BorderlineDashStyle = System.Windows.Forms.DataVisualization.Charting.ChartDashStyle.Solid;
-      chartArea1.AxisX.Minimum = 0D;
-      chartArea1.CursorX.IsUserEnabled = true;
-      chartArea1.CursorX.IsUserSelectionEnabled = true;
-      chartArea1.CursorY.IsUserEnabled = true;
-      chartArea1.CursorY.IsUserSelectionEnabled = true;
-      chartArea1.Name = "Default";
-      this.chart.ChartAreas.Add(chartArea1);
-      legend1.Alignment = System.Drawing.StringAlignment.Center;
-      legend1.Docking = System.Windows.Forms.DataVisualization.Charting.Docking.Top;
-      legend1.Name = "Default";
-      this.chart.Legends.Add(legend1);
       this.chart.Location = new System.Drawing.Point(0, 26);
       this.chart.Name = "chart";
-      series1.ChartArea = "Default";
-      series1.Legend = "Default";
-      series1.Name = "Default";
-      this.chart.Series.Add(series1);
       this.chart.Size = new System.Drawing.Size(359, 248);
       this.chart.TabIndex = 3;
       this.chart.Text = "chart";
-      title1.Font = new System.Drawing.Font("Microsoft Sans Serif", 12F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
-      title1.Name = "Default";
-      title1.Text = "Title";
-      this.chart.Titles.Add(title1);
-      this.chart.CustomizeLegend += new System.EventHandler<System.Windows.Forms.DataVisualization.Charting.CustomizeLegendEventArgs>(this.chart_CustomizeLegend);
-      this.chart.MouseDown += new System.Windows.Forms.MouseEventHandler(this.chart_MouseDown);
-      this.chart.MouseMove += new System.Windows.Forms.MouseEventHandler(this.chart_MouseMove);
       // 
       // ScatterPlotView
@@ -112,14 +83,11 @@
       this.Controls.SetChildIndex(this.nameTextBox, 0);
       ((System.ComponentModel.ISupportInitialize)(this.errorProvider)).EndInit();
-      ((System.ComponentModel.ISupportInitialize)(this.chart)).EndInit();
       this.ResumeLayout(false);
       this.PerformLayout();
 
     }
-
     #endregion
 
-    protected HeuristicLab.Visualization.ChartControlsExtensions.EnhancedChart chart;
-
+    protected HeuristicLab.Analysis.Views.ScatterPlotControl chart;
   }
 }
Index: branches/MemPRAlgorithm/HeuristicLab.Analysis.Views/3.3/ScatterPlotView.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Analysis.Views/3.3/ScatterPlotView.cs	(revision 14557)
+++ branches/MemPRAlgorithm/HeuristicLab.Analysis.Views/3.3/ScatterPlotView.cs	(revision 14562)
@@ -21,11 +21,5 @@
 
 using System;
-using System.Collections.Generic;
-using System.Drawing;
-using System.Linq;
 using System.Windows.Forms;
-using System.Windows.Forms.DataVisualization.Charting;
-using HeuristicLab.Collections;
-using HeuristicLab.Common;
 using HeuristicLab.Core.Views;
 using HeuristicLab.MainForm;
@@ -35,7 +29,4 @@
   [Content(typeof(ScatterPlot), true)]
   public partial class ScatterPlotView : NamedItemView, IConfigureableView {
-    protected List<Series> invisibleSeries;
-    protected Dictionary<IObservableList<Point2D<double>>, ScatterPlotDataRow> pointsRowsTable;
-    private double xMin, xMax, yMin, yMax;
 
     public new ScatterPlot Content {
@@ -46,64 +37,9 @@
     public ScatterPlotView() {
       InitializeComponent();
-      pointsRowsTable = new Dictionary<IObservableList<Point2D<double>>, ScatterPlotDataRow>();
-      invisibleSeries = new List<Series>();
-      chart.CustomizeAllChartAreas();
-      chart.ChartAreas[0].CursorX.Interval = 1;
     }
-
-    #region Event Handler Registration
-    protected override void DeregisterContentEvents() {
-      foreach (ScatterPlotDataRow row in Content.Rows)
-        DeregisterScatterPlotDataRowEvents(row);
-      Content.VisualPropertiesChanged -= new EventHandler(Content_VisualPropertiesChanged);
-      Content.Rows.ItemsAdded -= new CollectionItemsChangedEventHandler<ScatterPlotDataRow>(Rows_ItemsAdded);
-      Content.Rows.ItemsRemoved -= new CollectionItemsChangedEventHandler<ScatterPlotDataRow>(Rows_ItemsRemoved);
-      Content.Rows.ItemsReplaced -= new CollectionItemsChangedEventHandler<ScatterPlotDataRow>(Rows_ItemsReplaced);
-      Content.Rows.CollectionReset -= new CollectionItemsChangedEventHandler<ScatterPlotDataRow>(Rows_CollectionReset);
-      base.DeregisterContentEvents();
-    }
-    protected override void RegisterContentEvents() {
-      base.RegisterContentEvents();
-      Content.VisualPropertiesChanged += new EventHandler(Content_VisualPropertiesChanged);
-      Content.Rows.ItemsAdded += new CollectionItemsChangedEventHandler<ScatterPlotDataRow>(Rows_ItemsAdded);
-      Content.Rows.ItemsRemoved += new CollectionItemsChangedEventHandler<ScatterPlotDataRow>(Rows_ItemsRemoved);
-      Content.Rows.ItemsReplaced += new CollectionItemsChangedEventHandler<ScatterPlotDataRow>(Rows_ItemsReplaced);
-      Content.Rows.CollectionReset += new CollectionItemsChangedEventHandler<ScatterPlotDataRow>(Rows_CollectionReset);
-    }
-
-    protected virtual void RegisterScatterPlotDataRowEvents(ScatterPlotDataRow row) {
-      row.NameChanged += new EventHandler(Row_NameChanged);
-      row.VisualPropertiesChanged += new EventHandler(Row_VisualPropertiesChanged);
-      pointsRowsTable.Add(row.Points, row);
-      row.Points.ItemsAdded += new CollectionItemsChangedEventHandler<IndexedItem<Point2D<double>>>(Points_ItemsAdded);
-      row.Points.ItemsRemoved += new CollectionItemsChangedEventHandler<IndexedItem<Point2D<double>>>(Points_ItemsRemoved);
-      row.Points.ItemsReplaced += new CollectionItemsChangedEventHandler<IndexedItem<Point2D<double>>>(Points_ItemsReplaced);
-      row.Points.CollectionReset += new CollectionItemsChangedEventHandler<IndexedItem<Point2D<double>>>(Points_CollectionReset);
-    }
-    protected virtual void DeregisterScatterPlotDataRowEvents(ScatterPlotDataRow row) {
-      row.Points.ItemsAdded -= new CollectionItemsChangedEventHandler<IndexedItem<Point2D<double>>>(Points_ItemsAdded);
-      row.Points.ItemsRemoved -= new CollectionItemsChangedEventHandler<IndexedItem<Point2D<double>>>(Points_ItemsRemoved);
-      row.Points.ItemsReplaced -= new CollectionItemsChangedEventHandler<IndexedItem<Point2D<double>>>(Points_ItemsReplaced);
-      row.Points.CollectionReset -= new CollectionItemsChangedEventHandler<IndexedItem<Point2D<double>>>(Points_CollectionReset);
-      pointsRowsTable.Remove(row.Points);
-      row.VisualPropertiesChanged -= new EventHandler(Row_VisualPropertiesChanged);
-      row.NameChanged -= new EventHandler(Row_NameChanged);
-    }
-    #endregion
 
     protected override void OnContentChanged() {
       base.OnContentChanged();
-      invisibleSeries.Clear();
-      chart.Titles[0].Text = string.Empty;
-      chart.ChartAreas[0].AxisX.Title = string.Empty;
-      chart.ChartAreas[0].AxisY.Title = string.Empty;
-      chart.Series.Clear();
-      if (Content != null) {
-        chart.Titles[0].Text = Content.Name;
-        AddScatterPlotDataRows(Content.Rows);
-        ConfigureChartArea(chart.ChartAreas[0]);
-        RecalculateMinMaxPointValues();
-        RecalculateAxesScale(chart.ChartAreas[0]);
-      }
+      chart.Content = Content;
     }
 
@@ -114,138 +50,7 @@
 
     public void ShowConfiguration() {
-      if (Content != null) {
-        using (ScatterPlotVisualPropertiesDialog dialog = new ScatterPlotVisualPropertiesDialog(Content)) {
-          dialog.ShowDialog(this);
-        }
-      } else MessageBox.Show("Nothing to configure.");
+      chart.ShowConfiguration();
     }
 
-    protected virtual void AddScatterPlotDataRows(IEnumerable<ScatterPlotDataRow> rows) {
-      foreach (var row in rows) {
-        RegisterScatterPlotDataRowEvents(row);
-        Series series = new Series(row.Name);
-        if (row.VisualProperties.DisplayName.Trim() != String.Empty) series.LegendText = row.VisualProperties.DisplayName;
-        else series.LegendText = row.Name;
-        ConfigureSeries(series, row);
-        FillSeriesWithRowValues(series, row);
-        chart.Series.Add(series);
-      }
-      ConfigureChartArea(chart.ChartAreas[0]);
-      RecalculateMinMaxPointValues();
-      RecalculateAxesScale(chart.ChartAreas[0]);
-      UpdateYCursorInterval();
-    }
-
-    protected virtual void RemoveScatterPlotDataRows(IEnumerable<ScatterPlotDataRow> rows) {
-      foreach (var row in rows) {
-        DeregisterScatterPlotDataRowEvents(row);
-        Series series = chart.Series[row.Name];
-        chart.Series.Remove(series);
-        if (invisibleSeries.Contains(series))
-          invisibleSeries.Remove(series);
-      }
-      RecalculateMinMaxPointValues();
-      RecalculateAxesScale(chart.ChartAreas[0]);
-    }
-
-    private void ConfigureSeries(Series series, ScatterPlotDataRow row) {
-      series.BorderWidth = 1;
-      series.BorderDashStyle = ChartDashStyle.Solid;
-      series.BorderColor = Color.Empty;
-
-      if (row.VisualProperties.Color != Color.Empty)
-        series.Color = row.VisualProperties.Color;
-      else series.Color = Color.Empty;
-      series.IsVisibleInLegend = row.VisualProperties.IsVisibleInLegend;
-      series.ChartType = SeriesChartType.FastPoint;
-      series.MarkerSize = row.VisualProperties.PointSize;
-      series.MarkerStyle = ConvertPointStyle(row.VisualProperties.PointStyle);
-      series.XAxisType = AxisType.Primary;
-      series.YAxisType = AxisType.Primary;
-
-      if (row.VisualProperties.DisplayName.Trim() != String.Empty) series.LegendText = row.VisualProperties.DisplayName;
-      else series.LegendText = row.Name;
-
-      string xAxisTitle = string.IsNullOrEmpty(Content.VisualProperties.XAxisTitle)
-                      ? "X"
-                      : Content.VisualProperties.XAxisTitle;
-      string yAxisTitle = string.IsNullOrEmpty(Content.VisualProperties.YAxisTitle)
-                            ? "Y"
-                            : Content.VisualProperties.YAxisTitle;
-      series.ToolTip =
-        series.LegendText + Environment.NewLine +
-        xAxisTitle + " = " + "#VALX," + Environment.NewLine +
-        yAxisTitle + " = " + "#VAL";
-    }
-
-    private void ConfigureChartArea(ChartArea area) {
-      if (Content.VisualProperties.TitleFont != null) chart.Titles[0].Font = Content.VisualProperties.TitleFont;
-      if (!Content.VisualProperties.TitleColor.IsEmpty) chart.Titles[0].ForeColor = Content.VisualProperties.TitleColor;
-      chart.Titles[0].Text = Content.VisualProperties.Title;
-
-      if (Content.VisualProperties.AxisTitleFont != null) area.AxisX.TitleFont = Content.VisualProperties.AxisTitleFont;
-      if (!Content.VisualProperties.AxisTitleColor.IsEmpty) area.AxisX.TitleForeColor = Content.VisualProperties.AxisTitleColor;
-      area.AxisX.Title = Content.VisualProperties.XAxisTitle;
-      area.AxisX.MajorGrid.Enabled = Content.VisualProperties.XAxisGrid;
-
-      if (Content.VisualProperties.AxisTitleFont != null) area.AxisY.TitleFont = Content.VisualProperties.AxisTitleFont;
-      if (!Content.VisualProperties.AxisTitleColor.IsEmpty) area.AxisY.TitleForeColor = Content.VisualProperties.AxisTitleColor;
-      area.AxisY.Title = Content.VisualProperties.YAxisTitle;
-      area.AxisY.MajorGrid.Enabled = Content.VisualProperties.YAxisGrid;
-    }
-
-    private void RecalculateAxesScale(ChartArea area) {
-      area.AxisX.Minimum = CalculateMinBound(xMin);
-      area.AxisX.Maximum = CalculateMaxBound(xMax);
-      if (area.AxisX.Minimum == area.AxisX.Maximum) {
-        area.AxisX.Minimum = xMin - 0.5;
-        area.AxisX.Maximum = xMax + 0.5;
-      }
-      area.AxisY.Minimum = CalculateMinBound(yMin);
-      area.AxisY.Maximum = CalculateMaxBound(yMax);
-      if (area.AxisY.Minimum == area.AxisY.Maximum) {
-        area.AxisY.Minimum = yMin - 0.5;
-        area.AxisY.Maximum = yMax + 0.5;
-      }
-      if (xMax - xMin > 0) area.CursorX.Interval = Math.Pow(10, Math.Floor(Math.Log10(area.AxisX.Maximum - area.AxisX.Minimum) - 3));
-      else area.CursorX.Interval = 1;
-      area.AxisX.IsMarginVisible = false;
-
-      if (!Content.VisualProperties.XAxisMinimumAuto && !double.IsNaN(Content.VisualProperties.XAxisMinimumFixedValue)) area.AxisX.Minimum = Content.VisualProperties.XAxisMinimumFixedValue;
-      if (!Content.VisualProperties.XAxisMaximumAuto && !double.IsNaN(Content.VisualProperties.XAxisMaximumFixedValue)) area.AxisX.Maximum = Content.VisualProperties.XAxisMaximumFixedValue;
-      if (!Content.VisualProperties.YAxisMinimumAuto && !double.IsNaN(Content.VisualProperties.YAxisMinimumFixedValue)) area.AxisY.Minimum = Content.VisualProperties.YAxisMinimumFixedValue;
-      if (!Content.VisualProperties.YAxisMaximumAuto && !double.IsNaN(Content.VisualProperties.YAxisMaximumFixedValue)) area.AxisY.Maximum = Content.VisualProperties.YAxisMaximumFixedValue;
-    }
-
-    private static double CalculateMinBound(double min) {
-      if (min == 0) return 0;
-      var scale = Math.Pow(10, Math.Floor(Math.Log10(Math.Abs(min))));
-      return scale * (Math.Floor(min / scale));
-    }
-
-    private static double CalculateMaxBound(double max) {
-      if (max == 0) return 0;
-      var scale = Math.Pow(10, Math.Floor(Math.Log10(Math.Abs(max))));
-      return scale * (Math.Ceiling(max / scale));
-    }
-
-    protected virtual void UpdateYCursorInterval() {
-      double interestingValuesRange = (
-        from series in chart.Series
-        where series.Enabled
-        let values = (from point in series.Points
-                      where !point.IsEmpty
-                      select point.YValues[0]).DefaultIfEmpty(1.0)
-        let range = values.Max() - values.Min()
-        where range > 0.0
-        select range
-        ).DefaultIfEmpty(1.0).Min();
-
-      double digits = (int)Math.Log10(interestingValuesRange) - 3;
-      double yZoomInterval = Math.Pow(10, digits);
-      this.chart.ChartAreas[0].CursorY.Interval = yZoomInterval;
-    }
-
-    #region Event Handlers
     #region Content Event Handlers
     protected override void Content_NameChanged(object sender, EventArgs e) {
@@ -253,252 +58,7 @@
         Invoke(new EventHandler(Content_NameChanged), sender, e);
       else {
-        chart.Titles[0].Text = Content.Name;
+        Content.VisualProperties.Title = Content.Name;
         base.Content_NameChanged(sender, e);
       }
-    }
-    private void Content_VisualPropertiesChanged(object sender, EventArgs e) {
-      if (InvokeRequired)
-        Invoke(new EventHandler(Content_VisualPropertiesChanged), sender, e);
-      else {
-        ConfigureChartArea(chart.ChartAreas[0]);
-        RecalculateAxesScale(chart.ChartAreas[0]); // axes min/max could have changed
-      }
-    }
-    #endregion
-    #region Rows Event Handlers
-    private void Rows_ItemsAdded(object sender, CollectionItemsChangedEventArgs<ScatterPlotDataRow> e) {
-      if (InvokeRequired)
-        Invoke(new CollectionItemsChangedEventHandler<ScatterPlotDataRow>(Rows_ItemsAdded), sender, e);
-      else {
-        AddScatterPlotDataRows(e.Items);
-      }
-    }
-    private void Rows_ItemsRemoved(object sender, CollectionItemsChangedEventArgs<ScatterPlotDataRow> e) {
-      if (InvokeRequired)
-        Invoke(new CollectionItemsChangedEventHandler<ScatterPlotDataRow>(Rows_ItemsRemoved), sender, e);
-      else {
-        RemoveScatterPlotDataRows(e.Items);
-      }
-    }
-    private void Rows_ItemsReplaced(object sender, CollectionItemsChangedEventArgs<ScatterPlotDataRow> e) {
-      if (InvokeRequired)
-        Invoke(new CollectionItemsChangedEventHandler<ScatterPlotDataRow>(Rows_ItemsReplaced), sender, e);
-      else {
-        RemoveScatterPlotDataRows(e.OldItems);
-        AddScatterPlotDataRows(e.Items);
-      }
-    }
-    private void Rows_CollectionReset(object sender, CollectionItemsChangedEventArgs<ScatterPlotDataRow> e) {
-      if (InvokeRequired)
-        Invoke(new CollectionItemsChangedEventHandler<ScatterPlotDataRow>(Rows_CollectionReset), sender, e);
-      else {
-        RemoveScatterPlotDataRows(e.OldItems);
-        AddScatterPlotDataRows(e.Items);
-      }
-    }
-    #endregion
-    #region Row Event Handlers
-    private void Row_VisualPropertiesChanged(object sender, EventArgs e) {
-      if (InvokeRequired)
-        Invoke(new EventHandler(Row_VisualPropertiesChanged), sender, e);
-      else {
-        ScatterPlotDataRow row = (ScatterPlotDataRow)sender;
-        Series series = chart.Series[row.Name];
-        series.Points.Clear();
-        ConfigureSeries(series, row);
-        FillSeriesWithRowValues(series, row);
-        RecalculateMinMaxPointValues();
-        RecalculateAxesScale(chart.ChartAreas[0]);
-      }
-    }
-    private void Row_NameChanged(object sender, EventArgs e) {
-      if (InvokeRequired)
-        Invoke(new EventHandler(Row_NameChanged), sender, e);
-      else {
-        ScatterPlotDataRow row = (ScatterPlotDataRow)sender;
-        chart.Series[row.Name].Name = row.Name;
-      }
-    }
-    #endregion
-    #region Points Event Handlers
-    private void Points_ItemsAdded(object sender, CollectionItemsChangedEventArgs<IndexedItem<Point2D<double>>> e) {
-      if (InvokeRequired)
-        Invoke(new CollectionItemsChangedEventHandler<IndexedItem<Point2D<double>>>(Points_ItemsAdded), sender, e);
-      else {
-        ScatterPlotDataRow row = null;
-        pointsRowsTable.TryGetValue((IObservableList<Point2D<double>>)sender, out row);
-        if (row != null) {
-          Series rowSeries = chart.Series[row.Name];
-          if (!invisibleSeries.Contains(rowSeries)) {
-            rowSeries.Points.Clear();
-            FillSeriesWithRowValues(rowSeries, row);
-            RecalculateMinMaxPointValues();
-            RecalculateAxesScale(chart.ChartAreas[0]);
-            UpdateYCursorInterval();
-          }
-        }
-      }
-    }
-    private void Points_ItemsRemoved(object sender, CollectionItemsChangedEventArgs<IndexedItem<Point2D<double>>> e) {
-      if (InvokeRequired)
-        Invoke(new CollectionItemsChangedEventHandler<IndexedItem<Point2D<double>>>(Points_ItemsRemoved), sender, e);
-      else {
-        ScatterPlotDataRow row = null;
-        pointsRowsTable.TryGetValue((IObservableList<Point2D<double>>)sender, out row);
-        if (row != null) {
-          Series rowSeries = chart.Series[row.Name];
-          if (!invisibleSeries.Contains(rowSeries)) {
-            rowSeries.Points.Clear();
-            FillSeriesWithRowValues(rowSeries, row);
-            RecalculateMinMaxPointValues();
-            RecalculateAxesScale(chart.ChartAreas[0]);
-            UpdateYCursorInterval();
-          }
-        }
-      }
-    }
-    private void Points_ItemsReplaced(object sender, CollectionItemsChangedEventArgs<IndexedItem<Point2D<double>>> e) {
-      if (InvokeRequired)
-        Invoke(new CollectionItemsChangedEventHandler<IndexedItem<Point2D<double>>>(Points_ItemsReplaced), sender, e);
-      else {
-        ScatterPlotDataRow row = null;
-        pointsRowsTable.TryGetValue((IObservableList<Point2D<double>>)sender, out row);
-        if (row != null) {
-          Series rowSeries = chart.Series[row.Name];
-          if (!invisibleSeries.Contains(rowSeries)) {
-            rowSeries.Points.Clear();
-            FillSeriesWithRowValues(rowSeries, row);
-            RecalculateMinMaxPointValues();
-            RecalculateAxesScale(chart.ChartAreas[0]);
-            UpdateYCursorInterval();
-          }
-        }
-      }
-    }
-    private void Points_CollectionReset(object sender, CollectionItemsChangedEventArgs<IndexedItem<Point2D<double>>> e) {
-      if (InvokeRequired)
-        Invoke(new CollectionItemsChangedEventHandler<IndexedItem<Point2D<double>>>(Points_CollectionReset), sender, e);
-      else {
-        ScatterPlotDataRow row = null;
-        pointsRowsTable.TryGetValue((IObservableList<Point2D<double>>)sender, out row);
-        if (row != null) {
-          Series rowSeries = chart.Series[row.Name];
-          if (!invisibleSeries.Contains(rowSeries)) {
-            rowSeries.Points.Clear();
-            FillSeriesWithRowValues(rowSeries, row);
-            RecalculateMinMaxPointValues();
-            RecalculateAxesScale(chart.ChartAreas[0]);
-            UpdateYCursorInterval();
-          }
-        }
-      }
-    }
-    #endregion
-    #endregion
-
-    #region Chart Event Handlers
-    private void chart_MouseDown(object sender, MouseEventArgs e) {
-      HitTestResult result = chart.HitTest(e.X, e.Y);
-      if (result.ChartElementType == ChartElementType.LegendItem) {
-        ToggleSeriesVisible(result.Series);
-      }
-    }
-    private void chart_MouseMove(object sender, MouseEventArgs e) {
-      HitTestResult result = chart.HitTest(e.X, e.Y);
-      if (result.ChartElementType == ChartElementType.LegendItem)
-        this.Cursor = Cursors.Hand;
-      else
-        this.Cursor = Cursors.Default;
-    }
-    private void chart_CustomizeLegend(object sender, CustomizeLegendEventArgs e) {
-      foreach (LegendItem legendItem in e.LegendItems) {
-        var series = chart.Series[legendItem.SeriesName];
-        if (series != null) {
-          bool seriesIsInvisible = invisibleSeries.Contains(series);
-          foreach (LegendCell cell in legendItem.Cells) {
-            cell.ForeColor = seriesIsInvisible ? Color.Gray : Color.Black;
-          }
-        }
-      }
-    }
-    #endregion
-
-    private void ToggleSeriesVisible(Series series) {
-      if (!invisibleSeries.Contains(series)) {
-        series.Points.Clear();
-        invisibleSeries.Add(series);
-        RecalculateMinMaxPointValues();
-      } else {
-        invisibleSeries.Remove(series);
-        if (Content != null) {
-
-          var row = (from r in Content.Rows
-                     where r.Name == series.Name
-                     select r).Single();
-          FillSeriesWithRowValues(series, row);
-          RecalculateMinMaxPointValues();
-          this.chart.Legends[series.Legend].ForeColor = Color.Black;
-          RecalculateAxesScale(chart.ChartAreas[0]);
-          UpdateYCursorInterval();
-        }
-      }
-    }
-
-    private void RecalculateMinMaxPointValues() {
-      yMin = xMin = double.MaxValue;
-      yMax = xMax = double.MinValue;
-      foreach (var s in chart.Series.Where(x => x.Enabled)) {
-        foreach (var p in s.Points) {
-          double x = p.XValue, y = p.YValues[0];
-          if (xMin > x) xMin = x;
-          if (xMax < x) xMax = x;
-          if (yMin > y) yMin = y;
-          if (yMax < y) yMax = y;
-        }
-      }
-    }
-
-    private void FillSeriesWithRowValues(Series series, ScatterPlotDataRow row) {
-      for (int i = 0; i < row.Points.Count; i++) {
-        var value = row.Points[i];
-        DataPoint point = new DataPoint();
-        if (IsInvalidValue(value.X) || IsInvalidValue(value.Y))
-          point.IsEmpty = true;
-        else {
-          point.XValue = value.X;
-          point.YValues = new double[] { value.Y };
-        }
-        series.Points.Add(point);
-      }
-    }
-
-    #region Helpers
-    private MarkerStyle ConvertPointStyle(ScatterPlotDataRowVisualProperties.ScatterPlotDataRowPointStyle pointStyle) {
-      switch (pointStyle) {
-        case ScatterPlotDataRowVisualProperties.ScatterPlotDataRowPointStyle.Circle:
-          return MarkerStyle.Circle;
-        case ScatterPlotDataRowVisualProperties.ScatterPlotDataRowPointStyle.Cross:
-          return MarkerStyle.Cross;
-        case ScatterPlotDataRowVisualProperties.ScatterPlotDataRowPointStyle.Diamond:
-          return MarkerStyle.Diamond;
-        case ScatterPlotDataRowVisualProperties.ScatterPlotDataRowPointStyle.Square:
-          return MarkerStyle.Square;
-        case ScatterPlotDataRowVisualProperties.ScatterPlotDataRowPointStyle.Star4:
-          return MarkerStyle.Star4;
-        case ScatterPlotDataRowVisualProperties.ScatterPlotDataRowPointStyle.Star5:
-          return MarkerStyle.Star5;
-        case ScatterPlotDataRowVisualProperties.ScatterPlotDataRowPointStyle.Star6:
-          return MarkerStyle.Star6;
-        case ScatterPlotDataRowVisualProperties.ScatterPlotDataRowPointStyle.Star10:
-          return MarkerStyle.Star10;
-        case ScatterPlotDataRowVisualProperties.ScatterPlotDataRowPointStyle.Triangle:
-          return MarkerStyle.Triangle;
-        default:
-          return MarkerStyle.None;
-      }
-    }
-
-    protected static bool IsInvalidValue(double x) {
-      return double.IsNaN(x) || x < (double)decimal.MinValue || x > (double)decimal.MaxValue;
     }
     #endregion
Index: branches/MemPRAlgorithm/HeuristicLab.Analysis/3.3/DataVisualization/ScatterPlotDataRowVisualProperties.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Analysis/3.3/DataVisualization/ScatterPlotDataRowVisualProperties.cs	(revision 14557)
+++ branches/MemPRAlgorithm/HeuristicLab.Analysis/3.3/DataVisualization/ScatterPlotDataRowVisualProperties.cs	(revision 14562)
@@ -45,4 +45,14 @@
     }
     #endregion
+    #region
+    public enum ScatterPlotDataRowRegressionType {
+      None,
+      Linear,
+      Polynomial,
+      Exponential,
+      Logarithmic,
+      Power
+    }
+    #endregion
 
     private Color color;
@@ -101,4 +111,49 @@
       }
     }
+    private ScatterPlotDataRowRegressionType regressionType;
+    public ScatterPlotDataRowRegressionType RegressionType {
+      get { return regressionType; }
+      set {
+        if (regressionType != value) {
+          regressionType = value;
+          OnPropertyChanged("RegressionType");
+        }
+      }
+    }
+    private int polynomialRegressionOrder;
+    public int PolynomialRegressionOrder {
+      get { return polynomialRegressionOrder; }
+      set {
+        if (polynomialRegressionOrder != value) {
+          polynomialRegressionOrder = value;
+          OnPropertyChanged("PolynomialRegressionOrder");
+        }
+      }
+    }
+    private bool isRegressionVisibleInLegend;
+    public bool IsRegressionVisibleInLegend {
+      get { return isRegressionVisibleInLegend; }
+      set {
+        if (isRegressionVisibleInLegend != value) {
+          isRegressionVisibleInLegend = value;
+          OnPropertyChanged("IsRegressionVisibleInLegend");
+        }
+      }
+    }
+    private string regressionDisplayName;
+    public string RegressionDisplayName {
+      get { return regressionDisplayName ?? string.Empty; }
+      set {
+        if (regressionDisplayName != value) {
+          if (value == null && regressionDisplayName != string.Empty) {
+            regressionDisplayName = string.Empty;
+            OnPropertyChanged("RegressionDisplayName");
+          } else if (value != null) {
+            regressionDisplayName = value;
+            OnPropertyChanged("RegressionDisplayName");
+          }
+        }
+      }
+    }
 
     #region Persistence Properties
@@ -127,4 +182,24 @@
       get { return displayName; }
       set { displayName = value; }
+    }
+    [Storable(Name = "RegressionType")]
+    private ScatterPlotDataRowRegressionType StorableRegressionType {
+      get { return regressionType; }
+      set { regressionType = value; }
+    }
+    [Storable(Name = "PolynomialRegressionOrder", DefaultValue = 2)]
+    private int StorablePolynomialRegressionOrder {
+      get { return polynomialRegressionOrder; }
+      set { polynomialRegressionOrder = value; }
+    }
+    [Storable(Name = "IsRegressionVisibleInLegend", DefaultValue = true)]
+    private bool StorableIsRegressionVisibleInLegend {
+      get { return isRegressionVisibleInLegend; }
+      set { isRegressionVisibleInLegend = value; }
+    }
+    [Storable(Name = "RegressionDisplayName")]
+    private string StorableRegressionDisplayName {
+      get { return regressionDisplayName; }
+      set { regressionDisplayName = value; }
     }
     #endregion
@@ -139,4 +214,8 @@
       this.displayName = original.displayName;
       this.isVisibleInLegend = original.isVisibleInLegend;
+      this.regressionType = original.regressionType;
+      this.polynomialRegressionOrder = original.polynomialRegressionOrder;
+      this.isRegressionVisibleInLegend = original.isRegressionVisibleInLegend;
+      this.regressionDisplayName = original.regressionDisplayName;
     }
     public ScatterPlotDataRowVisualProperties() {
@@ -146,4 +225,8 @@
       displayName = String.Empty;
       isVisibleInLegend = true;
+      regressionType = ScatterPlotDataRowRegressionType.None;
+      polynomialRegressionOrder = 2;
+      isRegressionVisibleInLegend = true;
+      regressionDisplayName = string.Empty;
     }
     public ScatterPlotDataRowVisualProperties(string displayName)
Index: branches/MemPRAlgorithm/HeuristicLab.Data.Views/3.3/StringConvertibleArrayView.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Data.Views/3.3/StringConvertibleArrayView.cs	(revision 14557)
+++ branches/MemPRAlgorithm/HeuristicLab.Data.Views/3.3/StringConvertibleArrayView.cs	(revision 14562)
@@ -21,4 +21,5 @@
 
 using System;
+using System.Collections.Generic;
 using System.ComponentModel;
 using System.Drawing;
@@ -200,10 +201,16 @@
       }
 
+      var elementNames = Content.ElementNames.ToList();
       for (int i = minRowIndex; i <= maxRowIndex; i++) {
         DataGridViewColumn column = dataGridView.Columns.GetFirstColumn(DataGridViewElementStates.Visible);
         DataGridViewCell cell = dataGridView[column.Index, i];
         if (cell.Selected) {
-          s.Append(Content.ElementNames.ElementAt(i));
-          s.Append("\t");
+          if (i < elementNames.Count) {
+            s.Append(elementNames[i]);
+            s.Append("\t");
+          } else if (elementNames.Count > 0) {
+            s.Append("Index " + i);
+            s.Append("\t");
+          }
           s.Append(Content.GetValue(i));
           s.Append(Environment.NewLine);
@@ -213,5 +220,11 @@
     }
     private void PasteValuesToDataGridView() {
-      string[] values = SplitClipboardString(Clipboard.GetText());
+      Tuple<string, string>[] values = null;
+      try {
+        values = SplitClipboardString(Clipboard.GetText()).ToArray();
+      } catch (ArgumentException ex) {
+        MessageBox.Show(this, ex.Message, "Error while parsing clipboard text.", MessageBoxButtons.OK, MessageBoxIcon.Error);
+        return;
+      }
       int rowIndex = 0;
       if (dataGridView.CurrentCell != null)
@@ -219,11 +232,55 @@
 
       if (Content.Length < rowIndex + values.Length) Content.Length = rowIndex + values.Length;
-      for (int row = 0; row < values.Length; row++)
-        Content.SetValue(values[row], row + rowIndex);
-    }
-    private string[] SplitClipboardString(string clipboardText) {
+      for (int row = 0; row < values.Length; row++) {
+        Content.SetValue(values[row].Item2, row + rowIndex);
+      }
+      if (values.Any(x => !string.IsNullOrEmpty(x.Item1))) {
+        var elementNames = Content.ElementNames.ToList();
+        for (int row = 0; row < values.Length; row++) {
+          if (row + rowIndex < elementNames.Count)
+            elementNames[row + rowIndex] = values[row].Item1;
+          else elementNames.Add(values[row].Item1);
+        }
+        Content.ElementNames = elementNames;
+      }
+    }
+    private IEnumerable<Tuple<string, string>> SplitClipboardString(string clipboardText) {
       if (clipboardText.EndsWith(Environment.NewLine))
         clipboardText = clipboardText.Remove(clipboardText.Length - Environment.NewLine.Length);  //remove last newline constant
-      return clipboardText.Split(new string[] { Environment.NewLine, "\t" }, StringSplitOptions.None);
+
+      var lines = clipboardText.Split(new [] { Environment.NewLine }, StringSplitOptions.None);
+      var tabSep = new[] { '\t' };
+      if (lines.Length > 2) {
+        // Case 1: Each line contains either "elementName \t value" or just "value" (one or two vertical vectors)
+        foreach (var l in lines) {
+          var row = l.Split(tabSep, StringSplitOptions.RemoveEmptyEntries);
+          if (row.Length > 2) throw new ArgumentException("Clipboard may have either at most two rows or at most two columns.");
+          if (row.Length == 2) yield return Tuple.Create(row[0], row[1]);
+          else if (row.Length == 1) yield return Tuple.Create(string.Empty, row[0]);
+          else yield return Tuple.Create(string.Empty, string.Empty);
+        }
+      } else if (lines.Length == 2) {
+        var firstLine = lines[0].Split(tabSep, StringSplitOptions.None);
+        var secondLine = lines[1].Split(tabSep, StringSplitOptions.None);
+        if (firstLine.Length <= 2 && secondLine.Length <= 2) {
+          // Case 2a: The two lines contain either "elementName \t value" or just "value" (one or two vertical vectors)
+          yield return firstLine.Length >= 2 ? Tuple.Create(firstLine[0], firstLine[1]) : Tuple.Create(string.Empty, firstLine[0]);
+          yield return secondLine.Length >= 2 ? Tuple.Create(secondLine[0], secondLine[1]) : Tuple.Create(string.Empty, secondLine[0]);
+        } else {
+          // Case 2b: The first line contains the elementNames, the second line contains the values (two horizontal vectors)
+          var max = Math.Max(firstLine.Length, secondLine.Length);
+          for (var i = 0; i < max; i++) {
+            var elemName = i < firstLine.Length ? firstLine[i] : string.Empty;
+            var value = i < secondLine.Length ? secondLine[i] : string.Empty;
+            yield return Tuple.Create(elemName, value);
+          }
+        }
+      } else if (lines.Length == 1) {
+        // Case 3: The line contains the values (one horizontal vector)
+        var entries = lines[0].Split(tabSep, StringSplitOptions.None);
+        foreach (var e in entries) {
+          yield return Tuple.Create(string.Empty, e);
+        }
+      }
     }
     #endregion
Index: branches/MemPRAlgorithm/HeuristicLab.Data.Views/3.3/StringConvertibleMatrixView.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Data.Views/3.3/StringConvertibleMatrixView.cs	(revision 14557)
+++ branches/MemPRAlgorithm/HeuristicLab.Data.Views/3.3/StringConvertibleMatrixView.cs	(revision 14562)
@@ -137,4 +137,5 @@
         for (int i = 0; i < columns.Length; ++i) {
           var column = new DataGridViewTextBoxColumn();
+          column.SortMode = DataGridViewColumnSortMode.Programmatic;
           column.FillWeight = 1;
           columns[i] = column;
Index: branches/MemPRAlgorithm/HeuristicLab.DataPreprocessing.Views/3.4/DataGridContentView.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.DataPreprocessing.Views/3.4/DataGridContentView.cs	(revision 14557)
+++ branches/MemPRAlgorithm/HeuristicLab.DataPreprocessing.Views/3.4/DataGridContentView.cs	(revision 14562)
@@ -58,7 +58,7 @@
     public DataGridContentView() {
       InitializeComponent();
+      dataGridView.MouseDown += dataGridView_MouseDown;
       dataGridView.CellMouseClick += dataGridView_CellMouseClick;
       dataGridView.RowHeaderMouseClick += dataGridView_RowHeaderMouseClick;
-      dataGridView.KeyDown += dataGridView_KeyDown;
       dataGridView.MouseUp += dataGridView_MouseUp;
       contextMenuCell.Items.Add(ShowHideColumns);
@@ -204,22 +204,32 @@
     }
 
+    //Necessary so that dataGridView.SelectedRows and SelectedColumns are populated correctly
+    //further information: https://msdn.microsoft.com/en-us/library/system.windows.forms.datagridview.selectedcolumns.aspx
+    private void dataGridView_MouseDown(object sender, MouseEventArgs e) {
+      var hitTestInfo = dataGridView.HitTest(e.X, e.Y);
+      // row header click
+      if (hitTestInfo.ColumnIndex == -1 && hitTestInfo.RowIndex >= 0) {
+        if (dataGridView.SelectionMode != DataGridViewSelectionMode.RowHeaderSelect) {
+          dataGridView.SelectionMode = DataGridViewSelectionMode.RowHeaderSelect;
+        }
+      }
+      // column header click
+      if (hitTestInfo.RowIndex == -1 && hitTestInfo.ColumnIndex >= 0) {
+        if (dataGridView.SelectionMode != DataGridViewSelectionMode.ColumnHeaderSelect) {
+          dataGridView.SelectionMode = DataGridViewSelectionMode.ColumnHeaderSelect;
+        }
+      }
+    }
+
     protected override void dataGridView_ColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e) {
-      if (Content != null) {
-        if (e.Button == MouseButtons.Left) {
-          dataGridView.Focus();
-          dataGridView.ClearSelection();
-          dataGridView.SelectionChanged -= dataGridView_SelectionChanged;
-          for (int i = 0; i < dataGridView.RowCount; i++) {
-            if (i + 1 == dataGridView.RowCount)
-              dataGridView.SelectionChanged += dataGridView_SelectionChanged;
-            dataGridView[e.ColumnIndex, i].Selected = true;
-          }
-        } else if (e.Button == MouseButtons.Middle) {
-          int newIndex = e.ColumnIndex >= 0 ? e.ColumnIndex : 0;
-          Content.PreProcessingData.InsertColumn<double>(newIndex.ToString(), newIndex);
-        } else if (e.Button == MouseButtons.Right && Content.SortableView) {
-          SortColumn(e.ColumnIndex);
-        }
-      }
+      if (Content == null) return;
+
+      if (e.Button == MouseButtons.Middle) {
+        int newIndex = e.ColumnIndex >= 0 ? e.ColumnIndex : 0;
+        Content.PreProcessingData.InsertColumn<double>(newIndex.ToString(), newIndex);
+      } else if (e.Button == MouseButtons.Right && Content.SortableView) {
+        SortColumn(e.ColumnIndex);
+      }
+
       searchIterator = null;
     }
@@ -538,24 +548,27 @@
 
     protected override void dataGridView_KeyDown(object sender, KeyEventArgs e) {
-      var selectedRows = dataGridView.SelectedRows;
-      var selectedCells = dataGridView.SelectedCells;
-      if (!Content.FilterLogic.IsFiltered) { //data is in read only mode....
-        if (e.KeyCode == Keys.Delete && selectedCells.Count == Content.Rows && selectedCells.Count > 0) {
-          Content.DeleteColumn(selectedCells[0].ColumnIndex);
-        } else if (e.KeyCode == Keys.Delete && selectedRows.Count > 0) {
-          List<int> rows = new List<int>();
-          for (int i = 0; i < selectedRows.Count; ++i) {
-            int index = (sortedColumnIndices.Count != 0) ? (Convert.ToInt32(selectedRows[i].HeaderCell.Value) - 1) :
-              selectedRows[i].Index;
-            rows.Add(index);
-          }
-          Content.DeleteRows(rows);
-        } else if (e.Control && e.KeyCode == Keys.F) {
-          CreateFindAndReplaceDialog();
-          findAndReplaceDialog.ActivateSearch();
-        } else if (e.Control && e.KeyCode == Keys.R) {
-          CreateFindAndReplaceDialog();
-          findAndReplaceDialog.ActivateReplace();
-        }
+      base.dataGridView_KeyDown(sender, e);
+      //data is in read only mode....
+      if (Content.FilterLogic.IsFiltered) return;
+
+      if (e.KeyCode == Keys.Delete) {
+        //Delete column
+        if (dataGridView.SelectedColumns.Count > 0) {
+          var columnsToDelete = dataGridView.SelectedColumns.Cast<DataGridViewColumn>().OrderByDescending(col => col.Index).ToList();
+          foreach (var col in columnsToDelete)
+            Content.DeleteColumn(col.Index);
+        }
+        //Delete row
+        if (dataGridView.SelectedRows.Count > 0) {
+          //necessary if columns are sorted to translate the selected row index
+          var rowIndexes = dataGridView.SelectedRows.Cast<DataGridViewRow>().Select(row => GetRowIndex(row.Index)).ToList();
+          Content.DeleteRows(rowIndexes);
+        }
+      } else if (e.Control && e.KeyCode == Keys.F) {
+        CreateFindAndReplaceDialog();
+        findAndReplaceDialog.ActivateSearch();
+      } else if (e.Control && e.KeyCode == Keys.R) {
+        CreateFindAndReplaceDialog();
+        findAndReplaceDialog.ActivateReplace();
       }
     }
Index: branches/MemPRAlgorithm/HeuristicLab.DataPreprocessing.Views/3.4/PreprocessingCheckedVariablesView.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.DataPreprocessing.Views/3.4/PreprocessingCheckedVariablesView.cs	(revision 14557)
+++ branches/MemPRAlgorithm/HeuristicLab.DataPreprocessing.Views/3.4/PreprocessingCheckedVariablesView.cs	(revision 14562)
@@ -58,5 +58,5 @@
         IList<string> inputs = Content.PreprocessingData.InputVariables;
         if (Content.PreprocessingData.TargetVariable != null)
-          inputs = inputs.Union(new[] {Content.PreprocessingData.TargetVariable}).ToList();
+          inputs = inputs.Union(new[] { Content.PreprocessingData.TargetVariable }).ToList();
         Content.VariableItemList = Content.CreateVariableItemList(inputs);
       } else {
@@ -70,5 +70,5 @@
       var inputAndTarget = Content.PreprocessingData.InputVariables.Union(target != null ? new[] { target } : new string[] { });
       foreach (var col in Content.PreprocessingData.GetDoubleVariableNames().Except(inputAndTarget)) {
-        var listViewItem = checkedItemList.ItemsListView.FindItemWithText(col);
+        var listViewItem = checkedItemList.ItemsListView.FindItemWithText(col, false, 0, false);
         listViewItem.ForeColor = Color.LightGray;
       }
@@ -109,5 +109,5 @@
       Content.VariableItemList.Add(new StringValue(name));
       if (!Content.PreprocessingData.InputVariables.Contains(name) && Content.PreprocessingData.TargetVariable != name) {
-        var listViewItem = checkedItemList.ItemsListView.FindItemWithText(name);
+        var listViewItem = checkedItemList.ItemsListView.FindItemWithText(name, false, 0, false);
         listViewItem.ForeColor = Color.LightGray;
       }
Index: branches/MemPRAlgorithm/HeuristicLab.Encodings.LinearLinkageEncoding/3.4/HeuristicLab.Encodings.LinearLinkageEncoding-3.4.csproj
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Encodings.LinearLinkageEncoding/3.4/HeuristicLab.Encodings.LinearLinkageEncoding-3.4.csproj	(revision 14557)
+++ branches/MemPRAlgorithm/HeuristicLab.Encodings.LinearLinkageEncoding/3.4/HeuristicLab.Encodings.LinearLinkageEncoding-3.4.csproj	(revision 14562)
@@ -5,5 +5,5 @@
     <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
     <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
-    <ProjectGuid>{166507C9-EF26-4370-BB80-699742A29D4F}</ProjectGuid>
+    <ProjectGuid>{BE698769-975A-429E-828C-72BB2B6182C8}</ProjectGuid>
     <OutputType>Library</OutputType>
     <AppDesignerFolder>Properties</AppDesignerFolder>
Index: branches/MemPRAlgorithm/HeuristicLab.Optimization.Views/3.3/BasicAlgorithmView.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Optimization.Views/3.3/BasicAlgorithmView.cs	(revision 14557)
+++ branches/MemPRAlgorithm/HeuristicLab.Optimization.Views/3.3/BasicAlgorithmView.cs	(revision 14562)
@@ -36,10 +36,10 @@
     protected override void SetEnabledStateOfControls() {
       base.SetEnabledStateOfControls();
-      pauseButton.Enabled = false;
+      pauseButton.Enabled &= Content != null && Content.SupportsPause;
     }
 
     protected override void SetEnabledStateOfExecutableButtons() {
       base.SetEnabledStateOfExecutableButtons();
-      pauseButton.Enabled = false;
+      pauseButton.Enabled &= Content != null && Content.SupportsPause;
     }
   }
Index: branches/MemPRAlgorithm/HeuristicLab.Optimization/3.3/Algorithms/Algorithm.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Optimization/3.3/Algorithms/Algorithm.cs	(revision 14557)
+++ branches/MemPRAlgorithm/HeuristicLab.Optimization/3.3/Algorithms/Algorithm.cs	(revision 14562)
@@ -289,12 +289,23 @@
     public event EventHandler Stopped;
     protected virtual void OnStopped() {
-      foreach (IStatefulItem statefulObject in this.GetObjectGraphObjects(new HashSet<object>() { Runs }).OfType<IStatefulItem>()) {
-        statefulObject.ClearState();
-      }
-      runsCounter++;
-      runs.Add(new Run(string.Format("{0} Run {1}", Name, runsCounter), this));
-      ExecutionState = ExecutionState.Stopped;
-      EventHandler handler = Stopped;
-      if (handler != null) handler(this, EventArgs.Empty);
+      try {
+        foreach (
+          IStatefulItem statefulObject in
+          this.GetObjectGraphObjects(new HashSet<object>() {Runs}).OfType<IStatefulItem>()) {
+          statefulObject.ClearState();
+        }
+        runsCounter++;
+        try {
+          runs.Add(new Run(string.Format("{0} Run {1}", Name, runsCounter), this));
+        }
+        catch (ArgumentException e) {
+          OnExceptionOccurred(new InvalidOperationException("Run creation failed.", e));
+        }
+      }    
+      finally {
+        ExecutionState = ExecutionState.Stopped;
+        EventHandler handler = Stopped;
+        if (handler != null) handler(this, EventArgs.Empty);
+      }
     }
     public event EventHandler<EventArgs<Exception>> ExceptionOccurred;
Index: branches/MemPRAlgorithm/HeuristicLab.Optimization/3.3/Algorithms/BasicAlgorithm.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Optimization/3.3/Algorithms/BasicAlgorithm.cs	(revision 14557)
+++ branches/MemPRAlgorithm/HeuristicLab.Optimization/3.3/Algorithms/BasicAlgorithm.cs	(revision 14562)
@@ -24,4 +24,5 @@
 using System.Threading.Tasks;
 using HeuristicLab.Common;
+using HeuristicLab.Core;
 using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
 
@@ -29,8 +30,16 @@
   [StorableClass]
   public abstract class BasicAlgorithm : Algorithm, IStorableContent {
+
+    private bool pausePending;
+    private DateTime lastUpdateTime;
+
     public string Filename { get; set; }
 
+    public abstract bool SupportsPause { get; }
+
     [Storable]
-    private ResultCollection results;
+    private bool initialized;
+    [Storable]
+    private readonly ResultCollection results;
     public override ResultCollection Results {
       get { return results; }
@@ -58,4 +67,5 @@
       base.Prepare();
       results.Clear();
+      initialized = false;
       OnPrepared();
     }
@@ -64,14 +74,17 @@
       base.Start();
       CancellationTokenSource = new CancellationTokenSource();
+      pausePending = false;
+      OnStarted();
 
-      OnStarted();
-      Task task = Task.Factory.StartNew(Run, cancellationTokenSource.Token, cancellationTokenSource.Token);
+      Task task = Task.Factory.StartNew(Run, CancellationTokenSource.Token, CancellationTokenSource.Token);
       task.ContinueWith(t => {
         try {
           t.Wait();
-        } catch (AggregateException ex) {
+        }
+        catch (AggregateException ex) {
           try {
             ex.Flatten().Handle(x => x is OperationCanceledException);
-          } catch (AggregateException remaining) {
+          }
+          catch (AggregateException remaining) {
             if (remaining.InnerExceptions.Count == 1) OnExceptionOccurred(remaining.InnerExceptions[0]);
             else OnExceptionOccurred(remaining);
@@ -80,10 +93,18 @@
         CancellationTokenSource.Dispose();
         CancellationTokenSource = null;
-        OnStopped();
+        if (pausePending) OnPaused();
+        else OnStopped();
       });
     }
 
     public override void Pause() {
-      throw new NotSupportedException("Pause is not supported in basic algorithms.");
+      // CancellationToken.ThrowIfCancellationRequested() must be called from within the Run method, otherwise pause does nothing
+      // alternatively check the IsCancellationRequested property of the cancellation token
+      if (!SupportsPause)
+        throw new NotSupportedException("Pause is not supported by this algorithm.");
+
+      base.Pause();
+      pausePending = true;
+      CancellationTokenSource.Cancel();
     }
 
@@ -92,9 +113,8 @@
       // alternatively check the IsCancellationRequested property of the cancellation token
       base.Stop();
-      CancellationTokenSource.Cancel();
+      if (ExecutionState == ExecutionState.Paused) OnStopped();
+      else CancellationTokenSource.Cancel();
     }
 
-
-    private DateTime lastUpdateTime;
     private void Run(object state) {
       CancellationToken cancellationToken = (CancellationToken)state;
@@ -105,6 +125,10 @@
       timer.Start();
       try {
+        if (!initialized)
+          Initialize(cancellationToken);
+        initialized = true;
         Run(cancellationToken);
-      } finally {
+      }
+      finally {
         timer.Elapsed -= new System.Timers.ElapsedEventHandler(timer_Elapsed);
         timer.Stop();
@@ -113,4 +137,5 @@
     }
 
+    protected virtual void Initialize(CancellationToken cancellationToken) { }
     protected abstract void Run(CancellationToken cancellationToken);
 
Index: branches/MemPRAlgorithm/HeuristicLab.Optimization/3.3/Termination/MultiTerminator.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Optimization/3.3/Termination/MultiTerminator.cs	(revision 14557)
+++ branches/MemPRAlgorithm/HeuristicLab.Optimization/3.3/Termination/MultiTerminator.cs	(revision 14562)
@@ -38,5 +38,5 @@
       get { return HeuristicLab.Common.Resources.VSImageLibrary.FlagRed; }
     }
-
+    
     public ILookupParameter<BoolValue> TerminateParameter {
       get { return (ILookupParameter<BoolValue>)Parameters["Terminate"]; }
Index: branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis.Symbolic.Regression/3.4/HeuristicLab.Problems.DataAnalysis.Symbolic.Regression-3.4.csproj
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis.Symbolic.Regression/3.4/HeuristicLab.Problems.DataAnalysis.Symbolic.Regression-3.4.csproj	(revision 14557)
+++ branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis.Symbolic.Regression/3.4/HeuristicLab.Problems.DataAnalysis.Symbolic.Regression-3.4.csproj	(revision 14562)
@@ -129,4 +129,5 @@
     <Compile Include="Plugin.cs" />
     <Compile Include="SingleObjective\ConstantOptimizationAnalyzer.cs" />
+    <Compile Include="SingleObjective\Evaluators\SymbolicRegressionVarianceModelEvaluator.cs" />
     <Compile Include="SingleObjective\Evaluators\SymbolicRegressionMeanRelativeErrorEvaluator.cs" />
     <Compile Include="SingleObjective\SymbolicRegressionSolutionsAnalyzer.cs" />
Index: branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis.Symbolic.Regression/3.4/SingleObjective/Evaluators/SymbolicRegressionVarianceModelEvaluator.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis.Symbolic.Regression/3.4/SingleObjective/Evaluators/SymbolicRegressionVarianceModelEvaluator.cs	(revision 14562)
+++ branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis.Symbolic.Regression/3.4/SingleObjective/Evaluators/SymbolicRegressionVarianceModelEvaluator.cs	(revision 14562)
@@ -0,0 +1,90 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2016 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.DataAnalysis.Symbolic.Regression {
+  [Item("Variance Model Evaluator", "Can be used for modeling variance of a variable. Assumes that the variable values are sampled from a zero mean Gaussian. Use a model for the target variable to calculate the residuals. In a second step use the residuals as the target variable and use this evaluator to create the model for the conditional variance.")]
+  [StorableClass]
+  public class SymbolicRegressionVarianceModelEvaluator : SymbolicRegressionSingleObjectiveEvaluator {
+    [StorableConstructor]
+    protected SymbolicRegressionVarianceModelEvaluator(bool deserializing) : base(deserializing) { }
+    protected SymbolicRegressionVarianceModelEvaluator(SymbolicRegressionVarianceModelEvaluator original, Cloner cloner)
+      : base(original, cloner) {
+    }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new SymbolicRegressionVarianceModelEvaluator(this, cloner);
+    }
+
+    public SymbolicRegressionVarianceModelEvaluator() : base() { }
+
+    public override bool Maximization { get { return true; } }
+
+    public override IOperation InstrumentedApply() {
+      var solution = SymbolicExpressionTreeParameter.ActualValue;
+      IEnumerable<int> rows = GenerateRowsToEvaluate();
+
+      double quality = Calculate(SymbolicDataAnalysisTreeInterpreterParameter.ActualValue, solution, EstimationLimitsParameter.ActualValue.Lower, EstimationLimitsParameter.ActualValue.Upper, ProblemDataParameter.ActualValue, rows);
+      QualityParameter.ActualValue = new DoubleValue(quality);
+
+      return base.InstrumentedApply();
+    }
+
+    public static double Calculate(ISymbolicDataAnalysisExpressionTreeInterpreter interpreter, ISymbolicExpressionTree solution, double lowerEstimationLimit, double upperEstimationLimit, IRegressionProblemData problemData, IEnumerable<int> rows) {
+      IEnumerable<double> estimatedValues = interpreter.GetSymbolicExpressionTreeValues(solution, problemData.Dataset, rows);
+      IEnumerable<double> targetValues = problemData.Dataset.GetDoubleValues(problemData.TargetVariable, rows);
+      IEnumerable<double> boundedEstimatedValues = estimatedValues.LimitToRange(lowerEstimationLimit, upperEstimationLimit);
+
+      // assumes residuals follow a zero-mean Gaussian distribution where the variance is a function of the inputs
+
+      // boundedEstimatedValues is the estimator for std.dev.
+      // log likelihood for N(target_i | 0, boundesEstimatedValues)
+      var l2pi = Math.Log(2.0 * Math.PI);
+      var ll = -0.5 *
+               boundedEstimatedValues.Zip(targetValues, (s, t) =>
+                 +l2pi
+                 + Math.Log(s * s)
+                 + (t * t) / (s * s)
+                 ).Sum();
+
+      return ll;
+    }
+
+    public override double Evaluate(IExecutionContext context, ISymbolicExpressionTree tree, IRegressionProblemData problemData, IEnumerable<int> rows) {
+      SymbolicDataAnalysisTreeInterpreterParameter.ExecutionContext = context;
+      EstimationLimitsParameter.ExecutionContext = context;
+
+      double ll = Calculate(SymbolicDataAnalysisTreeInterpreterParameter.ActualValue, tree, EstimationLimitsParameter.ActualValue.Lower, EstimationLimitsParameter.ActualValue.Upper, problemData, rows);
+
+      SymbolicDataAnalysisTreeInterpreterParameter.ExecutionContext = null;
+      EstimationLimitsParameter.ExecutionContext = null;
+
+      return ll;
+    }
+  }
+}
Index: branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis.Symbolic.TimeSeriesPrognosis/3.4/SymbolicTimeSeriesPrognosisExpressionTreeInterpreter.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis.Symbolic.TimeSeriesPrognosis/3.4/SymbolicTimeSeriesPrognosisExpressionTreeInterpreter.cs	(revision 14557)
+++ branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis.Symbolic.TimeSeriesPrognosis/3.4/SymbolicTimeSeriesPrognosisExpressionTreeInterpreter.cs	(revision 14562)
@@ -45,9 +45,4 @@
     }
 
-    [ThreadStatic]
-    private static double[] targetVariableCache;
-    [ThreadStatic]
-    private static List<int> invalidateCacheIndexes;
-
     [StorableConstructor]
     private SymbolicTimeSeriesPrognosisExpressionTreeInterpreter(bool deserializing) : base(deserializing) { }
@@ -77,10 +72,7 @@
       if (CheckExpressionsWithIntervalArithmetic)
         throw new NotSupportedException("Interval arithmetic is not yet supported in the symbolic data analysis interpreter.");
-      if (targetVariableCache == null || targetVariableCache.GetLength(0) < dataset.Rows)
-        targetVariableCache = dataset.GetDoubleValues(TargetVariable).ToArray();
-      if (invalidateCacheIndexes == null)
-        invalidateCacheIndexes = new List<int>(10);
 
       string targetVariable = TargetVariable;
+      double[] targetVariableCache = dataset.GetDoubleValues(targetVariable).ToArray();
       lock (syncRoot) {
         EvaluatedSolutions++; // increment the evaluated solutions counter
@@ -100,15 +92,7 @@
           vProgs[i] = Evaluate(dataset, ref localRow, state);
           targetVariableCache[localRow] = vProgs[i];
-          invalidateCacheIndexes.Add(localRow);
           state.Reset();
         }
         yield return vProgs;
-
-        int j = 0;
-        foreach (var targetValue in dataset.GetDoubleValues(targetVariable, invalidateCacheIndexes)) {
-          targetVariableCache[invalidateCacheIndexes[j]] = targetValue;
-          j++;
-        }
-        invalidateCacheIndexes.Clear();
       }
 
Index: branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis.Symbolic.Views/3.4/InteractiveSymbolicDataAnalysisSolutionSimplifierView.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis.Symbolic.Views/3.4/InteractiveSymbolicDataAnalysisSolutionSimplifierView.cs	(revision 14557)
+++ branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis.Symbolic.Views/3.4/InteractiveSymbolicDataAnalysisSolutionSimplifierView.cs	(revision 14562)
@@ -112,5 +112,14 @@
       treeChart.Tree = tree;
       treeChart.Repaint();
-      bool valid = !tree.IterateNodesPostfix().Any(node => node.SubtreeCount < GetMinArity(node.Symbol) || node.SubtreeCount > node.Symbol.MaximumArity);
+      // check if all nodes have a legal arity
+      var nodes = tree.IterateNodesPostfix().ToList();
+      bool valid = !nodes.Any(node => node.SubtreeCount < GetMinArity(node.Symbol) || node.SubtreeCount > node.Symbol.MaximumArity);
+
+      if (valid) {
+        // check if all variables are contained in the dataset
+        var variables = new HashSet<string>(Content.ProblemData.Dataset.DoubleVariables);
+        valid = nodes.OfType<VariableTreeNode>().All(x => variables.Contains(x.VariableName));
+      }
+
       if (valid) {
         btnOptimizeConstants.Enabled = true;
Index: branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis.Symbolic.Views/3.4/InteractiveSymbolicExpressionTreeChart.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis.Symbolic.Views/3.4/InteractiveSymbolicExpressionTreeChart.cs	(revision 14557)
+++ branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis.Symbolic.Views/3.4/InteractiveSymbolicExpressionTreeChart.cs	(revision 14562)
@@ -102,5 +102,5 @@
         if (dialog.DialogResult != DialogResult.OK) return;
 
-        var symbol = dialog.SelectedSymbol();
+        var symbol = dialog.SelectedSymbol;
         var node = symbol.CreateTreeNode();
         if (node is ConstantTreeNode) {
@@ -110,5 +110,5 @@
           var variable = node as VariableTreeNode;
           variable.Weight = double.Parse(dialog.variableWeightTextBox.Text);
-          variable.VariableName = dialog.variableNamesCombo.Text;
+          variable.VariableName = dialog.SelectedVariableName;
         } else if (node.Symbol.MinimumArity <= parent.SubtreeCount && node.Symbol.MaximumArity >= parent.SubtreeCount) {
           for (int i = parent.SubtreeCount - 1; i >= 0; --i) {
Index: branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis.Symbolic.Views/3.4/TreeEditDialogs/SymbolicExpressionTreeNodeInsertDialog.Designer.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis.Symbolic.Views/3.4/TreeEditDialogs/SymbolicExpressionTreeNodeInsertDialog.Designer.cs	(revision 14557)
+++ branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis.Symbolic.Views/3.4/TreeEditDialogs/SymbolicExpressionTreeNodeInsertDialog.Designer.cs	(revision 14562)
@@ -57,4 +57,5 @@
       this.okButton = new System.Windows.Forms.Button();
       this.cancelButton = new System.Windows.Forms.Button();
+      this.variableNameTextBox = new System.Windows.Forms.TextBox();
       ((System.ComponentModel.ISupportInitialize)(this.errorProvider)).BeginInit();
       this.SuspendLayout();
@@ -168,4 +169,12 @@
       this.cancelButton.Click += new System.EventHandler(this.cancelButton_Click);
       // 
+      // variableNameTextBox
+      // 
+      this.variableNameTextBox.Location = new System.Drawing.Point(101, 63);
+      this.variableNameTextBox.Name = "variableNameTextBox";
+      this.variableNameTextBox.Size = new System.Drawing.Size(127, 20);
+      this.variableNameTextBox.TabIndex = 11;
+      this.variableNameTextBox.Visible = false;
+      // 
       // InsertNodeDialog
       // 
@@ -175,4 +184,5 @@
       this.ClientSize = new System.Drawing.Size(241, 133);
       this.ControlBox = false;
+      this.Controls.Add(this.variableNameTextBox);
       this.Controls.Add(this.cancelButton);
       this.Controls.Add(this.okButton);
@@ -208,4 +218,5 @@
     private System.Windows.Forms.Button cancelButton;
     private System.Windows.Forms.Button okButton;
+    private System.Windows.Forms.TextBox variableNameTextBox;
   }
 }
Index: branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis.Symbolic.Views/3.4/TreeEditDialogs/SymbolicExpressionTreeNodeInsertDialog.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis.Symbolic.Views/3.4/TreeEditDialogs/SymbolicExpressionTreeNodeInsertDialog.cs	(revision 14557)
+++ branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis.Symbolic.Views/3.4/TreeEditDialogs/SymbolicExpressionTreeNodeInsertDialog.cs	(revision 14562)
@@ -23,4 +23,5 @@
 using System.Collections.Generic;
 using System.ComponentModel;
+using System.Linq;
 using System.Text;
 using System.Windows.Forms;
@@ -30,4 +31,13 @@
 namespace HeuristicLab.Problems.DataAnalysis.Symbolic.Views {
   public partial class InsertNodeDialog : Form {
+    public string SelectedVariableName {
+      get {
+        var variable = SelectedSymbol as Variable;
+        if (variable == null)
+          return string.Empty;
+        return variable.VariableNames.Any() ? variableNamesCombo.Text : variableNameTextBox.Text;
+      }
+    }
+
     public InsertNodeDialog() {
       InitializeComponent();
@@ -40,6 +50,6 @@
     }
 
-    public ISymbol SelectedSymbol() {
-      return (ISymbol)allowedSymbolsCombo.SelectedItem;
+    public ISymbol SelectedSymbol {
+      get { return (ISymbol)allowedSymbolsCombo.SelectedItem; }
     }
 
@@ -56,9 +66,16 @@
         constantValueTextBox.Visible = true;
       } else if (symbol is Variable) {
-        var variable = (Variable)symbol;
-        foreach (var name in variable.VariableNames) variableNamesCombo.Items.Add(name);
-        variableNamesCombo.SelectedIndex = 0;
+        var variableSymbol = (Variable)symbol;
+        if (variableSymbol.VariableNames.Any()) {
+          foreach (var name in variableSymbol.VariableNames)
+            variableNamesCombo.Items.Add(name);
+          variableNamesCombo.SelectedIndex = 0;
+          variableNamesCombo.Visible = true;
+          variableNameTextBox.Visible = false;
+        } else {
+          variableNamesCombo.Visible = false;
+          variableNameTextBox.Visible = true;
+        }
         variableNameLabel.Visible = true;
-        variableNamesCombo.Visible = true;
         variableWeightLabel.Visible = true;
         variableWeightTextBox.Visible = true;
Index: branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis.Symbolic.Views/3.4/TreeEditDialogs/SymbolicExpressionTreeVariableNodeEditDialog.Designer.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis.Symbolic.Views/3.4/TreeEditDialogs/SymbolicExpressionTreeVariableNodeEditDialog.Designer.cs	(revision 14557)
+++ branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis.Symbolic.Views/3.4/TreeEditDialogs/SymbolicExpressionTreeVariableNodeEditDialog.Designer.cs	(revision 14562)
@@ -55,4 +55,5 @@
       this.okButton = new System.Windows.Forms.Button();
       this.cancelButton = new System.Windows.Forms.Button();
+      this.variableNameTextBox = new System.Windows.Forms.TextBox();
       ((System.ComponentModel.ISupportInitialize)(this.errorProvider)).BeginInit();
       this.SuspendLayout();
@@ -146,4 +147,12 @@
       this.cancelButton.Click += new System.EventHandler(this.cancelButton_Click);
       // 
+      // variableNameTextBox
+      // 
+      this.variableNameTextBox.Location = new System.Drawing.Point(101, 12);
+      this.variableNameTextBox.Name = "variableNameTextBox";
+      this.variableNameTextBox.Size = new System.Drawing.Size(131, 20);
+      this.variableNameTextBox.TabIndex = 12;
+      this.variableNameTextBox.Visible = false;
+      // 
       // VariableNodeEditDialog
       // 
@@ -154,4 +163,5 @@
       this.ClientSize = new System.Drawing.Size(244, 134);
       this.ControlBox = false;
+      this.Controls.Add(this.variableNameTextBox);
       this.Controls.Add(this.cancelButton);
       this.Controls.Add(this.okButton);
@@ -188,4 +198,5 @@
     public System.Windows.Forms.TextBox newValueTextBox;
     public System.Windows.Forms.ComboBox variableNamesCombo;
+    private System.Windows.Forms.TextBox variableNameTextBox;
   }
 }
Index: branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis.Symbolic.Views/3.4/TreeEditDialogs/SymbolicExpressionTreeVariableNodeEditDialog.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis.Symbolic.Views/3.4/TreeEditDialogs/SymbolicExpressionTreeVariableNodeEditDialog.cs	(revision 14557)
+++ branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis.Symbolic.Views/3.4/TreeEditDialogs/SymbolicExpressionTreeVariableNodeEditDialog.cs	(revision 14562)
@@ -22,4 +22,5 @@
 using System;
 using System.ComponentModel;
+using System.Linq;
 using System.Text;
 using System.Windows.Forms;
@@ -40,8 +41,11 @@
     }
 
+    public string SelectedVariableName {
+      get { return variableNamesCombo.Visible ? variableNamesCombo.Text : variableNameTextBox.Text; }
+    }
+
     public VariableNodeEditDialog(ISymbolicExpressionTreeNode node) {
       InitializeComponent();
       oldValueTextBox.TabStop = false; // cannot receive focus using tab key
-
       NewNode = (VariableTreeNode)node; // will throw an invalid cast exception if node is not of the correct type
       InitializeFields();
@@ -57,6 +61,14 @@
         variableNameLabel.Visible = true;
         variableNamesCombo.Visible = true;
-        foreach (var name in variableTreeNode.Symbol.VariableNames) variableNamesCombo.Items.Add(name);
-        variableNamesCombo.SelectedIndex = variableNamesCombo.Items.IndexOf(variableTreeNode.VariableName);
+        if (variableTreeNode.Symbol.VariableNames.Any()) {
+          foreach (var name in variableTreeNode.Symbol.VariableNames)
+            variableNamesCombo.Items.Add(name);
+          variableNamesCombo.SelectedIndex = variableNamesCombo.Items.IndexOf(variableTreeNode.VariableName);
+          variableNamesCombo.Visible = true;
+          variableNameTextBox.Visible = false;
+        } else {
+          variableNamesCombo.Visible = false;
+          variableNameTextBox.Visible = true;
+        }
       }
     }
@@ -93,4 +105,5 @@
     #region combo box validation and events
     private void variableNamesCombo_Validating(object sender, CancelEventArgs e) {
+      if (variableNamesCombo.Items.Count == 0) return;
       if (variableNamesCombo.Items.Contains(variableNamesCombo.SelectedItem)) return;
       e.Cancel = true;
@@ -119,6 +132,6 @@
     private void OnDialogValidated(object sender, EventArgs e) {
       double weight = double.Parse(newValueTextBox.Text);
-      var variableName = (string)variableNamesCombo.SelectedItem;
       // we impose an extra validation condition: that the weight/value be different than the original ones
+      var variableName = SelectedVariableName;
       if (variableTreeNode.Weight.Equals(weight) && variableTreeNode.VariableName.Equals(variableName)) return;
       variableTreeNode.Weight = weight;
Index: branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis.Views/3.4/FeatureCorrelation/FeatureCorrelationCalculator.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis.Views/3.4/FeatureCorrelation/FeatureCorrelationCalculator.cs	(revision 14557)
+++ branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis.Views/3.4/FeatureCorrelation/FeatureCorrelationCalculator.cs	(revision 14562)
@@ -50,5 +50,5 @@
 
       IList<string> doubleVariableNames = dataset.DoubleVariables.ToList();
-      OnlineCalculatorError error = OnlineCalculatorError.None;
+
       int length = doubleVariableNames.Count;
       double[,] elements = new double[length, length];
@@ -68,4 +68,5 @@
           var var2 = dataset.GetDoubleValues(doubleVariableNames[j], indices);
 
+          OnlineCalculatorError error = OnlineCalculatorError.None;
           if (bwInfo.IgnoreMissingValues) {
             var filtered = FilterNaNValues(var1, var2);
@@ -78,8 +79,8 @@
           }
           elements[j, i] = elements[i, j];
-
         });
         worker.ReportProgress((int)(((double)counter) / length * 100));
       }
+
       e.Result = elements;
       worker.ReportProgress(100);
Index: branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis.Views/3.4/HeuristicLab.Problems.DataAnalysis.Views-3.4.csproj
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis.Views/3.4/HeuristicLab.Problems.DataAnalysis.Views-3.4.csproj	(revision 14557)
+++ branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis.Views/3.4/HeuristicLab.Problems.DataAnalysis.Views-3.4.csproj	(revision 14562)
@@ -246,4 +246,16 @@
       <DependentUpon>RegressionFeatureCorrelationView.cs</DependentUpon>
     </Compile>
+    <Compile Include="Regression\RegressionSolutionLineChartViewBase.cs">
+      <SubType>UserControl</SubType>
+    </Compile>
+    <Compile Include="Regression\RegressionSolutionLineChartViewBase.Designer.cs">
+      <DependentUpon>RegressionSolutionLineChartViewBase.cs</DependentUpon>
+    </Compile>
+    <Compile Include="Regression\RegressionSolutionResidualsLineChartView.cs">
+      <SubType>UserControl</SubType>
+    </Compile>
+    <Compile Include="Regression\RegressionSolutionResidualsLineChartView.Designer.cs">
+      <DependentUpon>RegressionSolutionResidualsLineChartView.cs</DependentUpon>
+    </Compile>
     <Compile Include="Regression\RegressionSolutionVariableImpactsView.cs">
       <SubType>UserControl</SubType>
@@ -409,4 +421,16 @@
     <Compile Include="Solution Views\TimeSeriesPrognosisSolutionView.Designer.cs">
       <DependentUpon>TimeSeriesPrognosisSolutionView.cs</DependentUpon>
+    </Compile>
+    <Compile Include="TimeSeriesPrognosis\TimeSeriesPrognosisResidualsLineChartView.cs">
+      <SubType>UserControl</SubType>
+    </Compile>
+    <Compile Include="TimeSeriesPrognosis\TimeSeriesPrognosisResidualsLineChartView.Designer.cs">
+      <DependentUpon>TimeSeriesPrognosisResidualsLineChartView.cs</DependentUpon>
+    </Compile>
+    <Compile Include="TimeSeriesPrognosis\TimeSeriesPrognosisLineChartView.cs">
+      <SubType>UserControl</SubType>
+    </Compile>
+    <Compile Include="TimeSeriesPrognosis\TimeSeriesPrognosisLineChartView.Designer.cs">
+      <DependentUpon>TimeSeriesPrognosisLineChartView.cs</DependentUpon>
     </Compile>
     <Compile Include="TimeSeriesPrognosis\TimeSeriesPrognosisResultsView.cs">
Index: branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis.Views/3.4/Regression/RegressionSolutionLineChartView.Designer.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis.Views/3.4/Regression/RegressionSolutionLineChartView.Designer.cs	(revision 14557)
+++ branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis.Views/3.4/Regression/RegressionSolutionLineChartView.Designer.cs	(revision 14562)
@@ -44,38 +44,4 @@
     /// </summary>
     private void InitializeComponent() {
-      System.Windows.Forms.DataVisualization.Charting.ChartArea chartArea1 = new System.Windows.Forms.DataVisualization.Charting.ChartArea();
-      System.Windows.Forms.DataVisualization.Charting.Legend legend1 = new System.Windows.Forms.DataVisualization.Charting.Legend();
-      this.chart = new HeuristicLab.Visualization.ChartControlsExtensions.EnhancedChart();
-      ((System.ComponentModel.ISupportInitialize)(this.chart)).BeginInit();
-      this.SuspendLayout();
-      // 
-      // chart
-      // 
-      chartArea1.Name = "ChartArea";
-      this.chart.ChartAreas.Add(chartArea1);
-      this.chart.Dock = System.Windows.Forms.DockStyle.Fill;
-      legend1.Alignment = System.Drawing.StringAlignment.Center;
-      legend1.Docking = System.Windows.Forms.DataVisualization.Charting.Docking.Top;
-      legend1.Name = "Default";
-      this.chart.Legends.Add(legend1);
-      this.chart.Location = new System.Drawing.Point(0, 0);
-      this.chart.Name = "chart";
-      this.chart.Size = new System.Drawing.Size(358, 225);
-      this.chart.TabIndex = 0;
-      this.chart.CustomizeLegend += new System.EventHandler<System.Windows.Forms.DataVisualization.Charting.CustomizeLegendEventArgs>(this.chart_CustomizeLegend);
-      this.chart.MouseDoubleClick += new System.Windows.Forms.MouseEventHandler(this.Chart_MouseDoubleClick);
-      this.chart.MouseDown += new System.Windows.Forms.MouseEventHandler(this.chart_MouseDown);
-      this.chart.MouseMove += new System.Windows.Forms.MouseEventHandler(this.chart_MouseMove);
-      // 
-      // RegressionSolutionLineChartView
-      // 
-      this.AllowDrop = true;
-      this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
-      this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Inherit;
-      this.Controls.Add(this.chart);
-      this.Name = "RegressionSolutionLineChartView";
-      this.Size = new System.Drawing.Size(358, 225);
-      ((System.ComponentModel.ISupportInitialize)(this.chart)).EndInit();
-      this.ResumeLayout(false);
 
     }
@@ -83,5 +49,4 @@
     #endregion
 
-    private HeuristicLab.Visualization.ChartControlsExtensions.EnhancedChart chart;
   }
 }
Index: branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis.Views/3.4/Regression/RegressionSolutionLineChartView.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis.Views/3.4/Regression/RegressionSolutionLineChartView.cs	(revision 14557)
+++ branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis.Views/3.4/Regression/RegressionSolutionLineChartView.cs	(revision 14562)
@@ -19,286 +19,35 @@
  */
 #endregion
+
 using System;
-using System.Collections.Generic;
-using System.Drawing;
 using System.Linq;
-using System.Windows.Forms;
 using System.Windows.Forms.DataVisualization.Charting;
 using HeuristicLab.MainForm;
-using HeuristicLab.Visualization.ChartControlsExtensions;
+
 
 namespace HeuristicLab.Problems.DataAnalysis.Views {
   [View("Line Chart")]
   [Content(typeof(IRegressionSolution))]
-  public partial class RegressionSolutionLineChartView : DataAnalysisSolutionEvaluationView {
-    private const string TARGETVARIABLE_SERIES_NAME = "Target Variable";
-    private const string ESTIMATEDVALUES_TRAINING_SERIES_NAME = "Estimated Values (training)";
-    private const string ESTIMATEDVALUES_TEST_SERIES_NAME = "Estimated Values (test)";
-    private const string ESTIMATEDVALUES_ALL_SERIES_NAME = "Estimated Values (all samples)";
+  public partial class RegressionSolutionLineChartView : RegressionSolutionLineChartViewBase {
 
-    public new IRegressionSolution Content {
-      get { return (IRegressionSolution)base.Content; }
-      set { base.Content = value; }
-    }
 
     public RegressionSolutionLineChartView()
       : base() {
       InitializeComponent();
-      //configure axis
-      this.chart.CustomizeAllChartAreas();
-      this.chart.ChartAreas[0].CursorX.IsUserSelectionEnabled = true;
-      this.chart.ChartAreas[0].AxisX.ScaleView.Zoomable = true;
-      this.chart.ChartAreas[0].AxisX.IsStartedFromZero = true;
-      this.chart.ChartAreas[0].CursorX.Interval = 1;
-
-      this.chart.ChartAreas[0].CursorY.IsUserSelectionEnabled = true;
-      this.chart.ChartAreas[0].AxisY.ScaleView.Zoomable = true;
-      this.chart.ChartAreas[0].CursorY.Interval = 0;
     }
 
-    private void RedrawChart() {
-      this.chart.Series.Clear();
-      if (Content != null) {
-        this.chart.ChartAreas[0].AxisX.Minimum = 0;
-        this.chart.ChartAreas[0].AxisX.Maximum = Content.ProblemData.Dataset.Rows - 1;
-
-        this.chart.Series.Add(TARGETVARIABLE_SERIES_NAME);
-        this.chart.Series[TARGETVARIABLE_SERIES_NAME].LegendText = TARGETVARIABLE_SERIES_NAME;
-        this.chart.Series[TARGETVARIABLE_SERIES_NAME].ChartType = SeriesChartType.FastLine;
-        this.chart.Series[TARGETVARIABLE_SERIES_NAME].Points.DataBindXY(Enumerable.Range(0, Content.ProblemData.Dataset.Rows).ToArray(),
-          Content.ProblemData.Dataset.GetDoubleValues(Content.ProblemData.TargetVariable).ToArray());
-        // training series
-        this.chart.Series.Add(ESTIMATEDVALUES_TRAINING_SERIES_NAME);
-        this.chart.Series[ESTIMATEDVALUES_TRAINING_SERIES_NAME].LegendText = ESTIMATEDVALUES_TRAINING_SERIES_NAME;
-        this.chart.Series[ESTIMATEDVALUES_TRAINING_SERIES_NAME].ChartType = SeriesChartType.FastLine;
-        this.chart.Series[ESTIMATEDVALUES_TRAINING_SERIES_NAME].EmptyPointStyle.Color = this.chart.Series[ESTIMATEDVALUES_TRAINING_SERIES_NAME].Color;
-        this.chart.Series[ESTIMATEDVALUES_TRAINING_SERIES_NAME].Points.DataBindXY(Content.ProblemData.TrainingIndices.ToArray(), Content.EstimatedTrainingValues.ToArray());
-        this.InsertEmptyPoints(this.chart.Series[ESTIMATEDVALUES_TRAINING_SERIES_NAME]);
-        this.chart.Series[ESTIMATEDVALUES_TRAINING_SERIES_NAME].Tag = Content;
-        // test series
-        this.chart.Series.Add(ESTIMATEDVALUES_TEST_SERIES_NAME);
-        this.chart.Series[ESTIMATEDVALUES_TEST_SERIES_NAME].LegendText = ESTIMATEDVALUES_TEST_SERIES_NAME;
-        this.chart.Series[ESTIMATEDVALUES_TEST_SERIES_NAME].ChartType = SeriesChartType.FastLine;
-        this.chart.Series[ESTIMATEDVALUES_TEST_SERIES_NAME].Points.DataBindXY(Content.ProblemData.TestIndices.ToArray(), Content.EstimatedTestValues.ToArray());
-        this.InsertEmptyPoints(this.chart.Series[ESTIMATEDVALUES_TEST_SERIES_NAME]);
-        this.chart.Series[ESTIMATEDVALUES_TEST_SERIES_NAME].Tag = Content;
-        // series of remaining points
-        int[] allIndices = Enumerable.Range(0, Content.ProblemData.Dataset.Rows).Except(Content.ProblemData.TrainingIndices).Except(Content.ProblemData.TestIndices).ToArray();
-        var estimatedValues = Content.EstimatedValues.ToArray();
-        List<double> allEstimatedValues = allIndices.Select(index => estimatedValues[index]).ToList();
-        this.chart.Series.Add(ESTIMATEDVALUES_ALL_SERIES_NAME);
-        this.chart.Series[ESTIMATEDVALUES_ALL_SERIES_NAME].LegendText = ESTIMATEDVALUES_ALL_SERIES_NAME;
-        this.chart.Series[ESTIMATEDVALUES_ALL_SERIES_NAME].ChartType = SeriesChartType.FastLine;
-        if (allEstimatedValues.Count > 0) {
-          this.chart.Series[ESTIMATEDVALUES_ALL_SERIES_NAME].Points.DataBindXY(allIndices, allEstimatedValues);
-          this.InsertEmptyPoints(this.chart.Series[ESTIMATEDVALUES_ALL_SERIES_NAME]);
-        }
-        this.chart.Series[ESTIMATEDVALUES_ALL_SERIES_NAME].Tag = Content;
-        this.ToggleSeriesData(this.chart.Series[ESTIMATEDVALUES_ALL_SERIES_NAME]);
-
-        // set the y-axis
-        var axisY = this.chart.ChartAreas[0].AxisY;
-        axisY.Title = Content.ProblemData.TargetVariable;
-        double min = double.MaxValue, max = double.MinValue;
-        foreach (var point in chart.Series.SelectMany(x => x.Points)) {
-          if (!point.YValues.Any() || double.IsInfinity(point.YValues[0]) || double.IsNaN(point.YValues[0]))
-            continue;
-          var y = point.YValues[0];
-          if (y < min)
-            min = y;
-          if (y > max)
-            max = y;
-        }
-
-        double axisMin, axisMax, axisInterval;
-        ChartUtil.CalculateOptimalAxisInterval(min, max, out axisMin, out axisMax, out axisInterval);
-        axisY.Minimum = axisMin;
-        axisY.Maximum = axisMax;
-        axisY.Interval = axisInterval;
-
-        UpdateCursorInterval();
-        this.UpdateStripLines();
-      }
+    protected override void GetTrainingSeries(out int[] idx, out double[] y) {
+      idx = Content.ProblemData.TrainingIndices.ToArray();
+      y = Content.EstimatedTrainingValues.ToArray();
     }
 
-    private void InsertEmptyPoints(Series series) {
-      int i = 0;
-      while (i < series.Points.Count - 1) {
-        if (series.Points[i].IsEmpty) {
-          ++i;
-          continue;
-        }
-
-        var p1 = series.Points[i];
-        var p2 = series.Points[i + 1];
-        // check for consecutive indices
-        if ((int)p2.XValue - (int)p1.XValue != 1) {
-          // insert an empty point between p1 and p2 so that the line will be invisible (transparent)
-          var p = new DataPoint((int)((p1.XValue + p2.XValue) / 2), 0.0) { IsEmpty = true };
-          series.Points.Insert(i + 1, p);
-        }
-        ++i;
-      }
+    protected override void GetTestSeries(out int[] idx, out double[] y) {
+      idx = Content.ProblemData.TestIndices.ToArray();
+      y = Content.EstimatedTestValues.ToArray();
     }
 
-    private void UpdateCursorInterval() {
-      var estimatedValues = this.chart.Series[ESTIMATEDVALUES_TRAINING_SERIES_NAME].Points.Select(x => x.YValues[0]).DefaultIfEmpty(1.0);
-      var targetValues = this.chart.Series[TARGETVARIABLE_SERIES_NAME].Points.Select(x => x.YValues[0]).DefaultIfEmpty(1.0);
-      double estimatedValuesRange = estimatedValues.Max() - estimatedValues.Min();
-      double targetValuesRange = targetValues.Max() - targetValues.Min();
-      double interestingValuesRange = Math.Min(Math.Max(targetValuesRange, 1.0), Math.Max(estimatedValuesRange, 1.0));
-      double digits = (int)Math.Log10(interestingValuesRange) - 3;
-      double yZoomInterval = Math.Max(Math.Pow(10, digits), 10E-5);
-      this.chart.ChartAreas[0].CursorY.Interval = yZoomInterval;
-    }
-
-    #region events
-    protected override void RegisterContentEvents() {
-      base.RegisterContentEvents();
-      Content.ModelChanged += new EventHandler(Content_ModelChanged);
-      Content.ProblemDataChanged += new EventHandler(Content_ProblemDataChanged);
-    }
-    protected override void DeregisterContentEvents() {
-      base.DeregisterContentEvents();
-      Content.ModelChanged -= new EventHandler(Content_ModelChanged);
-      Content.ProblemDataChanged -= new EventHandler(Content_ProblemDataChanged);
-    }
-
-    protected override void OnContentChanged() {
-      base.OnContentChanged();
-      RedrawChart();
-    }
-    private void Content_ProblemDataChanged(object sender, EventArgs e) {
-      RedrawChart();
-    }
-    private void Content_ModelChanged(object sender, EventArgs e) {
-      RedrawChart();
-    }
-
-
-
-    private void Chart_MouseDoubleClick(object sender, MouseEventArgs e) {
-      HitTestResult result = chart.HitTest(e.X, e.Y);
-      if (result.ChartArea != null && (result.ChartElementType == ChartElementType.PlottingArea ||
-                                       result.ChartElementType == ChartElementType.Gridlines) ||
-                                       result.ChartElementType == ChartElementType.StripLines) {
-        foreach (var axis in result.ChartArea.Axes)
-          axis.ScaleView.ZoomReset(int.MaxValue);
-      }
-    }
-    #endregion
-
-    private void UpdateStripLines() {
-      this.chart.ChartAreas[0].AxisX.StripLines.Clear();
-
-      int[] attr = new int[Content.ProblemData.Dataset.Rows + 1]; // add a virtual last row that is again empty to simplify loop further down
-      foreach (var row in Content.ProblemData.TrainingIndices) {
-        attr[row] += 1;
-      }
-      foreach (var row in Content.ProblemData.TestIndices) {
-        attr[row] += 2;
-      }
-      int start = 0;
-      int curAttr = attr[start];
-      for (int row = 0; row < attr.Length; row++) {
-        if (attr[row] != curAttr) {
-          switch (curAttr) {
-            case 0: break;
-            case 1:
-              this.CreateAndAddStripLine("Training", start, row, Color.FromArgb(40, Color.Green), Color.Transparent);
-              break;
-            case 2:
-              this.CreateAndAddStripLine("Test", start, row, Color.FromArgb(40, Color.Red), Color.Transparent);
-              break;
-            case 3:
-              this.CreateAndAddStripLine("Training and Test", start, row, Color.FromArgb(40, Color.Green), Color.FromArgb(40, Color.Red), ChartHatchStyle.WideUpwardDiagonal);
-              break;
-            default:
-              // should not happen
-              break;
-          }
-          curAttr = attr[row];
-          start = row;
-        }
-      }
-    }
-
-    private void CreateAndAddStripLine(string title, int start, int end, Color color, Color secondColor, ChartHatchStyle hatchStyle = ChartHatchStyle.None) {
-      StripLine stripLine = new StripLine();
-      stripLine.BackColor = color;
-      stripLine.BackSecondaryColor = secondColor;
-      stripLine.BackHatchStyle = hatchStyle;
-      stripLine.Text = title;
-      stripLine.Font = new Font("Times New Roman", 12, FontStyle.Bold);
-      // strip range is [start .. end] inclusive, but we evaluate [start..end[ (end is exclusive)
-      // the strip should be by one longer (starting at start - 0.5 and ending at end + 0.5)
-      stripLine.StripWidth = end - start;
-      stripLine.IntervalOffset = start - 0.5; // start slightly to the left of the first point to clearly indicate the first point in the partition
-      this.chart.ChartAreas[0].AxisX.StripLines.Add(stripLine);
-    }
-
-    private void ToggleSeriesData(Series series) {
-      if (series.Points.Count > 0) {  //checks if series is shown
-        if (this.chart.Series.Any(s => s != series && s.Points.Count > 0)) {
-          ClearPointsQuick(series.Points);
-        }
-      } else if (Content != null) {
-        string targetVariableName = Content.ProblemData.TargetVariable;
-
-        IEnumerable<int> indices = null;
-        double[] predictedValues = null;
-        switch (series.Name) {
-          case ESTIMATEDVALUES_ALL_SERIES_NAME:
-            indices = Enumerable.Range(0, Content.ProblemData.Dataset.Rows).Except(Content.ProblemData.TrainingIndices).Except(Content.ProblemData.TestIndices).ToArray();
-            var estimatedValues = Content.EstimatedValues.ToArray();
-            predictedValues = indices.Select(index => estimatedValues[index]).ToArray();
-            break;
-          case ESTIMATEDVALUES_TRAINING_SERIES_NAME:
-            indices = Content.ProblemData.TrainingIndices.ToArray();
-            predictedValues = Content.EstimatedTrainingValues.ToArray();
-            break;
-          case ESTIMATEDVALUES_TEST_SERIES_NAME:
-            indices = Content.ProblemData.TestIndices.ToArray();
-            predictedValues = Content.EstimatedTestValues.ToArray();
-            break;
-        }
-        if (predictedValues.Length > 0) {
-          series.Points.DataBindXY(indices, predictedValues);
-          this.InsertEmptyPoints(series);
-        }
-        chart.Legends[series.Legend].ForeColor = Color.Black;
-        UpdateCursorInterval();
-        chart.Refresh();
-      }
-    }
-
-    // workaround as per http://stackoverflow.com/questions/5744930/datapointcollection-clear-performance
-    private static void ClearPointsQuick(DataPointCollection points) {
-      points.SuspendUpdates();
-      while (points.Count > 0)
-        points.RemoveAt(points.Count - 1);
-      points.ResumeUpdates();
-    }
-
-    private void chart_MouseMove(object sender, MouseEventArgs e) {
-      HitTestResult result = chart.HitTest(e.X, e.Y);
-      if (result.ChartElementType == ChartElementType.LegendItem && result.Series.Name != TARGETVARIABLE_SERIES_NAME)
-        Cursor = Cursors.Hand;
-      else
-        Cursor = Cursors.Default;
-    }
-    private void chart_MouseDown(object sender, MouseEventArgs e) {
-      HitTestResult result = chart.HitTest(e.X, e.Y);
-      if (result.ChartElementType == ChartElementType.LegendItem && result.Series.Name != TARGETVARIABLE_SERIES_NAME) {
-        ToggleSeriesData(result.Series);
-      }
-    }
-
-    private void chart_CustomizeLegend(object sender, CustomizeLegendEventArgs e) {
-      if (chart.Series.Count != 4) return;
-      e.LegendItems[0].Cells[1].ForeColor = this.chart.Series[TARGETVARIABLE_SERIES_NAME].Points.Count == 0 ? Color.Gray : Color.Black;
-      e.LegendItems[1].Cells[1].ForeColor = this.chart.Series[ESTIMATEDVALUES_TRAINING_SERIES_NAME].Points.Count == 0 ? Color.Gray : Color.Black;
-      e.LegendItems[2].Cells[1].ForeColor = this.chart.Series[ESTIMATEDVALUES_TEST_SERIES_NAME].Points.Count == 0 ? Color.Gray : Color.Black;
-      e.LegendItems[3].Cells[1].ForeColor = this.chart.Series[ESTIMATEDVALUES_ALL_SERIES_NAME].Points.Count == 0 ? Color.Gray : Color.Black;
+    protected override void GetAllValuesSeries(out int[] idx, out double[] y) {
+      idx = Content.ProblemData.AllIndices.ToArray();
+      y = Content.EstimatedValues.ToArray();
     }
   }
Index: branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis.Views/3.4/Regression/RegressionSolutionLineChartViewBase.Designer.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis.Views/3.4/Regression/RegressionSolutionLineChartViewBase.Designer.cs	(revision 14562)
+++ branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis.Views/3.4/Regression/RegressionSolutionLineChartViewBase.Designer.cs	(revision 14562)
@@ -0,0 +1,87 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2016 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+namespace HeuristicLab.Problems.DataAnalysis.Views {
+  partial class RegressionSolutionLineChartViewBase {
+    /// <summary> 
+    /// Required designer variable.
+    /// </summary>
+    private System.ComponentModel.IContainer components = null;
+
+    /// <summary> 
+    /// Clean up any resources being used.
+    /// </summary>
+    /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
+    protected override void Dispose(bool disposing) {
+      if (disposing && (components != null)) {
+        components.Dispose();
+      }
+      base.Dispose(disposing);
+    }
+
+    #region Component Designer generated code
+
+    /// <summary> 
+    /// Required method for Designer support - do not modify 
+    /// the contents of this method with the code editor.
+    /// </summary>
+    private void InitializeComponent() {
+      System.Windows.Forms.DataVisualization.Charting.ChartArea chartArea1 = new System.Windows.Forms.DataVisualization.Charting.ChartArea();
+      System.Windows.Forms.DataVisualization.Charting.Legend legend1 = new System.Windows.Forms.DataVisualization.Charting.Legend();
+      this.chart = new HeuristicLab.Visualization.ChartControlsExtensions.EnhancedChart();
+      ((System.ComponentModel.ISupportInitialize)(this.chart)).BeginInit();
+      this.SuspendLayout();
+      // 
+      // chart
+      // 
+      chartArea1.Name = "ChartArea";
+      this.chart.ChartAreas.Add(chartArea1);
+      this.chart.Dock = System.Windows.Forms.DockStyle.Fill;
+      legend1.Alignment = System.Drawing.StringAlignment.Center;
+      legend1.Docking = System.Windows.Forms.DataVisualization.Charting.Docking.Top;
+      legend1.Name = "Default";
+      this.chart.Legends.Add(legend1);
+      this.chart.Location = new System.Drawing.Point(0, 0);
+      this.chart.Name = "chart";
+      this.chart.Size = new System.Drawing.Size(358, 225);
+      this.chart.TabIndex = 0;
+      this.chart.CustomizeLegend += new System.EventHandler<System.Windows.Forms.DataVisualization.Charting.CustomizeLegendEventArgs>(this.chart_CustomizeLegend);
+      this.chart.MouseDoubleClick += new System.Windows.Forms.MouseEventHandler(this.Chart_MouseDoubleClick);
+      this.chart.MouseDown += new System.Windows.Forms.MouseEventHandler(this.chart_MouseDown);
+      this.chart.MouseMove += new System.Windows.Forms.MouseEventHandler(this.chart_MouseMove);
+      // 
+      // RegressionSolutionLineChartView
+      // 
+      this.AllowDrop = true;
+      this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+      this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Inherit;
+      this.Controls.Add(this.chart);
+      this.Name = "RegressionSolutionLineChartView";
+      this.Size = new System.Drawing.Size(358, 225);
+      ((System.ComponentModel.ISupportInitialize)(this.chart)).EndInit();
+      this.ResumeLayout(false);
+
+    }
+
+    #endregion
+
+    protected HeuristicLab.Visualization.ChartControlsExtensions.EnhancedChart chart;
+  }
+}
Index: branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis.Views/3.4/Regression/RegressionSolutionLineChartViewBase.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis.Views/3.4/Regression/RegressionSolutionLineChartViewBase.cs	(revision 14562)
+++ branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis.Views/3.4/Regression/RegressionSolutionLineChartViewBase.cs	(revision 14562)
@@ -0,0 +1,315 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2016 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.Drawing;
+using System.Linq;
+using System.Windows.Forms;
+using System.Windows.Forms.DataVisualization.Charting;
+using HeuristicLab.MainForm;
+using HeuristicLab.Visualization.ChartControlsExtensions;
+
+namespace HeuristicLab.Problems.DataAnalysis.Views {
+  [View("Line Chart")]
+  [Content(typeof(IRegressionSolution))]
+  public abstract partial class RegressionSolutionLineChartViewBase : DataAnalysisSolutionEvaluationView {
+    protected const string TARGETVARIABLE_SERIES_NAME = "Target Variable";
+    protected const string ESTIMATEDVALUES_TRAINING_SERIES_NAME = "Estimated Values (training)";
+    protected const string ESTIMATEDVALUES_TEST_SERIES_NAME = "Estimated Values (test)";
+    protected const string ESTIMATEDVALUES_ALL_SERIES_NAME = "Estimated Values (all samples)";
+
+    public new IRegressionSolution Content {
+      get { return (IRegressionSolution)base.Content; }
+      set { base.Content = value; }
+    }
+
+    protected RegressionSolutionLineChartViewBase()
+      : base() {
+      InitializeComponent();
+      //configure axis
+      this.chart.CustomizeAllChartAreas();
+      this.chart.ChartAreas[0].CursorX.IsUserSelectionEnabled = true;
+      this.chart.ChartAreas[0].AxisX.ScaleView.Zoomable = true;
+      this.chart.ChartAreas[0].AxisX.IsStartedFromZero = true;
+      this.chart.ChartAreas[0].CursorX.Interval = 1;
+
+      this.chart.ChartAreas[0].CursorY.IsUserSelectionEnabled = true;
+      this.chart.ChartAreas[0].AxisY.ScaleView.Zoomable = true;
+      this.chart.ChartAreas[0].CursorY.Interval = 0;
+    }
+
+    protected abstract void GetTrainingSeries(out int[] idx, out double[] y);
+
+    protected abstract void GetTestSeries(out int[] x, out double[] y);
+
+    protected abstract void GetAllValuesSeries(out int[] x, out double[] y);
+
+    protected virtual void RedrawChart() {
+      this.chart.Series.Clear();
+      if (Content != null) {
+        this.chart.ChartAreas[0].AxisX.Minimum = 0;
+        this.chart.ChartAreas[0].AxisX.Maximum = Content.ProblemData.Dataset.Rows - 1;
+
+        this.chart.Series.Add(TARGETVARIABLE_SERIES_NAME);
+        this.chart.Series[TARGETVARIABLE_SERIES_NAME].LegendText = TARGETVARIABLE_SERIES_NAME;
+        this.chart.Series[TARGETVARIABLE_SERIES_NAME].ChartType = SeriesChartType.FastLine;
+        this.chart.Series[TARGETVARIABLE_SERIES_NAME].Points.DataBindXY(Enumerable.Range(0, Content.ProblemData.Dataset.Rows).ToArray(),
+          Content.ProblemData.Dataset.GetDoubleValues(Content.ProblemData.TargetVariable).ToArray());
+        // training series
+        this.chart.Series.Add(ESTIMATEDVALUES_TRAINING_SERIES_NAME);
+        this.chart.Series[ESTIMATEDVALUES_TRAINING_SERIES_NAME].LegendText = ESTIMATEDVALUES_TRAINING_SERIES_NAME;
+        this.chart.Series[ESTIMATEDVALUES_TRAINING_SERIES_NAME].ChartType = SeriesChartType.FastLine;
+        this.chart.Series[ESTIMATEDVALUES_TRAINING_SERIES_NAME].EmptyPointStyle.Color = this.chart.Series[ESTIMATEDVALUES_TRAINING_SERIES_NAME].Color;
+        int[] trainingIdx;
+        double[] trainingY;
+        GetTrainingSeries(out trainingIdx, out trainingY);
+        this.chart.Series[ESTIMATEDVALUES_TRAINING_SERIES_NAME].Points.DataBindXY(trainingIdx, trainingY);
+        this.InsertEmptyPoints(this.chart.Series[ESTIMATEDVALUES_TRAINING_SERIES_NAME]);
+        this.chart.Series[ESTIMATEDVALUES_TRAINING_SERIES_NAME].Tag = Content;
+
+        // test series
+        this.chart.Series.Add(ESTIMATEDVALUES_TEST_SERIES_NAME);
+        this.chart.Series[ESTIMATEDVALUES_TEST_SERIES_NAME].LegendText = ESTIMATEDVALUES_TEST_SERIES_NAME;
+        this.chart.Series[ESTIMATEDVALUES_TEST_SERIES_NAME].ChartType = SeriesChartType.FastLine;
+        int[] testIdx;
+        double[] testY;
+        GetTestSeries(out testIdx, out testY);
+        this.chart.Series[ESTIMATEDVALUES_TEST_SERIES_NAME].Points.DataBindXY(testIdx, testY);
+        this.InsertEmptyPoints(this.chart.Series[ESTIMATEDVALUES_TEST_SERIES_NAME]);
+        this.chart.Series[ESTIMATEDVALUES_TEST_SERIES_NAME].Tag = Content;
+
+        // series of remaining points
+        int[] allIdx;
+        double[] allEstimatedValues;
+        GetAllValuesSeries(out allIdx, out allEstimatedValues);
+
+        this.chart.Series.Add(ESTIMATEDVALUES_ALL_SERIES_NAME);
+        this.chart.Series[ESTIMATEDVALUES_ALL_SERIES_NAME].LegendText = ESTIMATEDVALUES_ALL_SERIES_NAME;
+        this.chart.Series[ESTIMATEDVALUES_ALL_SERIES_NAME].ChartType = SeriesChartType.FastLine;
+        if (allEstimatedValues.Length > 0) {
+          this.chart.Series[ESTIMATEDVALUES_ALL_SERIES_NAME].Points.DataBindXY(allIdx, allEstimatedValues);
+          this.InsertEmptyPoints(this.chart.Series[ESTIMATEDVALUES_ALL_SERIES_NAME]);
+        }
+        this.chart.Series[ESTIMATEDVALUES_ALL_SERIES_NAME].Tag = Content;
+        this.ToggleSeriesData(this.chart.Series[ESTIMATEDVALUES_ALL_SERIES_NAME]);
+
+        // set the y-axis
+        var axisY = this.chart.ChartAreas[0].AxisY;
+        axisY.Title = Content.ProblemData.TargetVariable;
+        double min = double.MaxValue, max = double.MinValue;
+        foreach (var point in chart.Series.SelectMany(x => x.Points)) {
+          if (!point.YValues.Any() || double.IsInfinity(point.YValues[0]) || double.IsNaN(point.YValues[0]))
+            continue;
+          var y = point.YValues[0];
+          if (y < min)
+            min = y;
+          if (y > max)
+            max = y;
+        }
+
+        double axisMin, axisMax, axisInterval;
+        ChartUtil.CalculateOptimalAxisInterval(min, max, out axisMin, out axisMax, out axisInterval);
+        axisY.Minimum = axisMin;
+        axisY.Maximum = axisMax;
+        axisY.Interval = axisInterval;
+
+        UpdateCursorInterval();
+        this.UpdateStripLines();
+      }
+    }
+
+    private void InsertEmptyPoints(Series series) {
+      int i = 0;
+      while (i < series.Points.Count - 1) {
+        if (series.Points[i].IsEmpty) {
+          ++i;
+          continue;
+        }
+
+        var p1 = series.Points[i];
+        var p2 = series.Points[i + 1];
+        // check for consecutive indices
+        if ((int)p2.XValue - (int)p1.XValue != 1) {
+          // insert an empty point between p1 and p2 so that the line will be invisible (transparent)
+          var p = new DataPoint((int)((p1.XValue + p2.XValue) / 2), 0.0) { IsEmpty = true };
+          series.Points.Insert(i + 1, p);
+        }
+        ++i;
+      }
+    }
+
+    private void UpdateCursorInterval() {
+      var estimatedValues = this.chart.Series[ESTIMATEDVALUES_TRAINING_SERIES_NAME].Points.Select(x => x.YValues[0]).DefaultIfEmpty(1.0);
+      var targetValues = this.chart.Series[TARGETVARIABLE_SERIES_NAME].Points.Select(x => x.YValues[0]).DefaultIfEmpty(1.0);
+      double estimatedValuesRange = estimatedValues.Max() - estimatedValues.Min();
+      double targetValuesRange = targetValues.Max() - targetValues.Min();
+      double interestingValuesRange = Math.Min(Math.Max(targetValuesRange, 1.0), Math.Max(estimatedValuesRange, 1.0));
+      double digits = (int)Math.Log10(interestingValuesRange) - 3;
+      double yZoomInterval = Math.Max(Math.Pow(10, digits), 10E-5);
+      this.chart.ChartAreas[0].CursorY.Interval = yZoomInterval;
+    }
+
+    #region events
+    protected override void RegisterContentEvents() {
+      base.RegisterContentEvents();
+      Content.ModelChanged += new EventHandler(Content_ModelChanged);
+      Content.ProblemDataChanged += new EventHandler(Content_ProblemDataChanged);
+    }
+    protected override void DeregisterContentEvents() {
+      base.DeregisterContentEvents();
+      Content.ModelChanged -= new EventHandler(Content_ModelChanged);
+      Content.ProblemDataChanged -= new EventHandler(Content_ProblemDataChanged);
+    }
+
+    protected override void OnContentChanged() {
+      base.OnContentChanged();
+      RedrawChart();
+    }
+    private void Content_ProblemDataChanged(object sender, EventArgs e) {
+      RedrawChart();
+    }
+    private void Content_ModelChanged(object sender, EventArgs e) {
+      RedrawChart();
+    }
+
+
+
+    private void Chart_MouseDoubleClick(object sender, MouseEventArgs e) {
+      HitTestResult result = chart.HitTest(e.X, e.Y);
+      if (result.ChartArea != null && (result.ChartElementType == ChartElementType.PlottingArea ||
+                                       result.ChartElementType == ChartElementType.Gridlines) ||
+                                       result.ChartElementType == ChartElementType.StripLines) {
+        foreach (var axis in result.ChartArea.Axes)
+          axis.ScaleView.ZoomReset(int.MaxValue);
+      }
+    }
+    #endregion
+
+    private void UpdateStripLines() {
+      this.chart.ChartAreas[0].AxisX.StripLines.Clear();
+
+      int[] attr = new int[Content.ProblemData.Dataset.Rows + 1]; // add a virtual last row that is again empty to simplify loop further down
+      foreach (var row in Content.ProblemData.TrainingIndices) {
+        attr[row] += 1;
+      }
+      foreach (var row in Content.ProblemData.TestIndices) {
+        attr[row] += 2;
+      }
+      int start = 0;
+      int curAttr = attr[start];
+      for (int row = 0; row < attr.Length; row++) {
+        if (attr[row] != curAttr) {
+          switch (curAttr) {
+            case 0: break;
+            case 1:
+              this.CreateAndAddStripLine("Training", start, row, Color.FromArgb(40, Color.Green), Color.Transparent);
+              break;
+            case 2:
+              this.CreateAndAddStripLine("Test", start, row, Color.FromArgb(40, Color.Red), Color.Transparent);
+              break;
+            case 3:
+              this.CreateAndAddStripLine("Training and Test", start, row, Color.FromArgb(40, Color.Green), Color.FromArgb(40, Color.Red), ChartHatchStyle.WideUpwardDiagonal);
+              break;
+            default:
+              // should not happen
+              break;
+          }
+          curAttr = attr[row];
+          start = row;
+        }
+      }
+    }
+
+    private void CreateAndAddStripLine(string title, int start, int end, Color color, Color secondColor, ChartHatchStyle hatchStyle = ChartHatchStyle.None) {
+      StripLine stripLine = new StripLine();
+      stripLine.BackColor = color;
+      stripLine.BackSecondaryColor = secondColor;
+      stripLine.BackHatchStyle = hatchStyle;
+      stripLine.Text = title;
+      stripLine.Font = new Font("Times New Roman", 12, FontStyle.Bold);
+      // strip range is [start .. end] inclusive, but we evaluate [start..end[ (end is exclusive)
+      // the strip should be by one longer (starting at start - 0.5 and ending at end + 0.5)
+      stripLine.StripWidth = end - start;
+      stripLine.IntervalOffset = start - 0.5; // start slightly to the left of the first point to clearly indicate the first point in the partition
+      this.chart.ChartAreas[0].AxisX.StripLines.Add(stripLine);
+    }
+
+    public void ToggleSeriesData(Series series) {
+      if (series.Points.Count > 0) {  //checks if series is shown
+        if (this.chart.Series.Any(s => s != series && s.Points.Count > 0)) {
+          ClearPointsQuick(series.Points);
+        }
+      } else if (Content != null) {
+
+        int[] indices = null;
+        double[] predictedValues = null;
+        switch (series.Name) {
+          case ESTIMATEDVALUES_ALL_SERIES_NAME:
+            GetAllValuesSeries(out indices, out predictedValues);
+            break;
+          case ESTIMATEDVALUES_TRAINING_SERIES_NAME:
+            GetTrainingSeries(out indices, out predictedValues);
+            break;
+          case ESTIMATEDVALUES_TEST_SERIES_NAME:
+            GetTestSeries(out indices, out predictedValues);
+            break;
+        }
+        if (predictedValues.Length > 0) {
+          series.Points.DataBindXY(indices, predictedValues);
+          this.InsertEmptyPoints(series);
+        }
+        chart.Legends[series.Legend].ForeColor = Color.Black;
+        UpdateCursorInterval();
+        chart.Refresh();
+      }
+    }
+
+    // workaround as per http://stackoverflow.com/questions/5744930/datapointcollection-clear-performance
+    private static void ClearPointsQuick(DataPointCollection points) {
+      points.SuspendUpdates();
+      while (points.Count > 0)
+        points.RemoveAt(points.Count - 1);
+      points.ResumeUpdates();
+    }
+
+    private void chart_MouseMove(object sender, MouseEventArgs e) {
+      HitTestResult result = chart.HitTest(e.X, e.Y);
+      if (result.ChartElementType == ChartElementType.LegendItem && result.Series.Name != TARGETVARIABLE_SERIES_NAME)
+        Cursor = Cursors.Hand;
+      else
+        Cursor = Cursors.Default;
+    }
+    private void chart_MouseDown(object sender, MouseEventArgs e) {
+      HitTestResult result = chart.HitTest(e.X, e.Y);
+      if (result.ChartElementType == ChartElementType.LegendItem && result.Series.Name != TARGETVARIABLE_SERIES_NAME) {
+        ToggleSeriesData(result.Series);
+      }
+    }
+
+    private void chart_CustomizeLegend(object sender, CustomizeLegendEventArgs e) {
+      if (chart.Series.Count != 4) return;
+      e.LegendItems[0].Cells[1].ForeColor = this.chart.Series[TARGETVARIABLE_SERIES_NAME].Points.Count == 0 ? Color.Gray : Color.Black;
+      e.LegendItems[1].Cells[1].ForeColor = this.chart.Series[ESTIMATEDVALUES_TRAINING_SERIES_NAME].Points.Count == 0 ? Color.Gray : Color.Black;
+      e.LegendItems[2].Cells[1].ForeColor = this.chart.Series[ESTIMATEDVALUES_TEST_SERIES_NAME].Points.Count == 0 ? Color.Gray : Color.Black;
+      e.LegendItems[3].Cells[1].ForeColor = this.chart.Series[ESTIMATEDVALUES_ALL_SERIES_NAME].Points.Count == 0 ? Color.Gray : Color.Black;
+    }
+  }
+}
Index: branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis.Views/3.4/Regression/RegressionSolutionResidualsLineChartView.Designer.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis.Views/3.4/Regression/RegressionSolutionResidualsLineChartView.Designer.cs	(revision 14562)
+++ branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis.Views/3.4/Regression/RegressionSolutionResidualsLineChartView.Designer.cs	(revision 14562)
@@ -0,0 +1,52 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2016 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+namespace HeuristicLab.Problems.DataAnalysis.Views {
+  partial class RegressionSolutionResidualsLineChartView {
+    /// <summary> 
+    /// Required designer variable.
+    /// </summary>
+    private System.ComponentModel.IContainer components = null;
+
+    /// <summary> 
+    /// Clean up any resources being used.
+    /// </summary>
+    /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
+    protected override void Dispose(bool disposing) {
+      if (disposing && (components != null)) {
+        components.Dispose();
+      }
+      base.Dispose(disposing);
+    }
+
+    #region Component Designer generated code
+
+    /// <summary> 
+    /// Required method for Designer support - do not modify 
+    /// the contents of this method with the code editor.
+    /// </summary>
+    private void InitializeComponent() {
+
+    }
+
+    #endregion
+
+  }
+}
Index: branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis.Views/3.4/Regression/RegressionSolutionResidualsLineChartView.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis.Views/3.4/Regression/RegressionSolutionResidualsLineChartView.cs	(revision 14562)
+++ branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis.Views/3.4/Regression/RegressionSolutionResidualsLineChartView.cs	(revision 14562)
@@ -0,0 +1,95 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2016 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.Linq;
+using System.Windows.Forms.DataVisualization.Charting;
+using HeuristicLab.MainForm;
+
+
+namespace HeuristicLab.Problems.DataAnalysis.Views {
+  [View("Residuals Line Chart")]
+  [Content(typeof(IRegressionSolution))]
+  public partial class RegressionSolutionResidualsLineChartView : RegressionSolutionLineChartViewBase, IDataAnalysisSolutionEvaluationView {
+
+
+    public RegressionSolutionResidualsLineChartView()
+      : base() {
+      InitializeComponent();
+    }
+
+    protected override void GetTrainingSeries(out int[] idx, out double[] y) {
+      idx = Content.ProblemData.TrainingIndices.ToArray();
+      y = Content.EstimatedTrainingValues.ToArray();
+      CalcResiduals(idx, y);
+    }
+
+    protected void CalcResiduals(int[] idx, double[] x) {
+      var problemData = Content.ProblemData;
+      var target = problemData.Dataset.GetDoubleValues(problemData.TargetVariable, idx).ToArray();
+      for (int i = 0; i < idx.Length; i++) {
+        x[i] -= target[i];
+      }
+    }
+
+    protected override void GetTestSeries(out int[] idx, out double[] y) {
+      idx = Content.ProblemData.TestIndices.ToArray();
+      y = Content.EstimatedTestValues.ToArray();
+      CalcResiduals(idx, y);
+    }
+
+    protected override void GetAllValuesSeries(out int[] idx, out double[] y) {
+      idx = Content.ProblemData.AllIndices.ToArray();
+      y = Content.EstimatedValues.ToArray();
+      CalcResiduals(idx, y);
+    }
+
+    protected override void RedrawChart() {
+      base.RedrawChart();
+      UpdateSeriesStyle();
+    }
+
+    private void UpdateSeriesStyle() {
+      if (InvokeRequired) Invoke((Action)UpdateSeriesStyle);
+      else {
+        if (Content == null) return;
+        double[] res;
+        int[] idx;
+        GetTrainingSeries(out idx, out res);
+        base.chart.Series[RegressionSolutionLineChartView.ESTIMATEDVALUES_TRAINING_SERIES_NAME].YAxisType = AxisType.Secondary;
+        base.chart.Series[RegressionSolutionLineChartView.ESTIMATEDVALUES_TRAINING_SERIES_NAME].ChartType = SeriesChartType.RangeColumn;
+        base.chart.Series[RegressionSolutionLineChartView.ESTIMATEDVALUES_TRAINING_SERIES_NAME].Points.DataBindXY(idx, res.Select(_ => 0.0).ToArray(), res);
+
+        GetTestSeries(out idx, out res);
+        base.chart.Series[RegressionSolutionLineChartView.ESTIMATEDVALUES_TEST_SERIES_NAME].YAxisType = AxisType.Secondary;
+        base.chart.Series[RegressionSolutionLineChartView.ESTIMATEDVALUES_TEST_SERIES_NAME].ChartType = SeriesChartType.RangeColumn;
+        base.chart.Series[RegressionSolutionLineChartView.ESTIMATEDVALUES_TEST_SERIES_NAME].Points.DataBindXY(idx, res.Select(_ => 0.0).ToArray(), res);
+
+        GetAllValuesSeries(out idx, out res);
+        base.chart.Series[RegressionSolutionLineChartView.ESTIMATEDVALUES_ALL_SERIES_NAME].YAxisType = AxisType.Secondary;
+        base.chart.Series[RegressionSolutionLineChartView.ESTIMATEDVALUES_ALL_SERIES_NAME].ChartType = SeriesChartType.RangeColumn;
+        base.chart.Series[RegressionSolutionLineChartView.ESTIMATEDVALUES_ALL_SERIES_NAME].Points.DataBindXY(idx, res.Select(_ => 0.0).ToArray(), res);
+        ToggleSeriesData(base.chart.Series[RegressionSolutionLineChartView.ESTIMATEDVALUES_ALL_SERIES_NAME]); // don't show by default
+      }
+    }
+
+  }
+}
Index: branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis.Views/3.4/Regression/RegressionSolutionTargetResponseGradientView.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis.Views/3.4/Regression/RegressionSolutionTargetResponseGradientView.cs	(revision 14557)
+++ branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis.Views/3.4/Regression/RegressionSolutionTargetResponseGradientView.cs	(revision 14562)
@@ -112,6 +112,12 @@
       limitView.Content.Upper = axisMax;
 
-      // create dataset
-      var allowedInputVariables = Content.ProblemData.AllowedInputVariables;
+      // create dataset of problemData input variables and model input variables
+      // necessary workaround to have the variables in the occuring order
+      var inputvariables =
+        new HashSet<string>(Content.ProblemData.AllowedInputVariables.Union(Content.Model.VariablesUsedForPrediction));
+      var allowedInputVariables =
+        Content.ProblemData.Dataset.VariableNames.Where(v => inputvariables.Contains(v)).ToList();
+
+
       var variableValues = allowedInputVariables.Select(x => new List<double> { problemData.Dataset.GetDoubleValues(x, problemData.TrainingIndices).Median() });
       if (sharedFixedVariables != null)
Index: branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis.Views/3.4/TimeSeriesPrognosis/TimeSeriesPrognosisLineChartView.Designer.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis.Views/3.4/TimeSeriesPrognosis/TimeSeriesPrognosisLineChartView.Designer.cs	(revision 14562)
+++ branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis.Views/3.4/TimeSeriesPrognosis/TimeSeriesPrognosisLineChartView.Designer.cs	(revision 14562)
@@ -0,0 +1,52 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2016 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+namespace HeuristicLab.Problems.DataAnalysis.Views {
+  partial class TimeSeriesPrognosisLineChartView {
+    /// <summary> 
+    /// Required designer variable.
+    /// </summary>
+    private System.ComponentModel.IContainer components = null;
+
+    /// <summary> 
+    /// Clean up any resources being used.
+    /// </summary>
+    /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
+    protected override void Dispose(bool disposing) {
+      if (disposing && (components != null)) {
+        components.Dispose();
+      }
+      base.Dispose(disposing);
+    }
+
+    #region Component Designer generated code
+
+    /// <summary> 
+    /// Required method for Designer support - do not modify 
+    /// the contents of this method with the code editor.
+    /// </summary>
+    private void InitializeComponent() {
+
+    }
+
+    #endregion
+
+  }
+}
Index: branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis.Views/3.4/TimeSeriesPrognosis/TimeSeriesPrognosisLineChartView.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis.Views/3.4/TimeSeriesPrognosis/TimeSeriesPrognosisLineChartView.cs	(revision 14562)
+++ branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis.Views/3.4/TimeSeriesPrognosis/TimeSeriesPrognosisLineChartView.cs	(revision 14562)
@@ -0,0 +1,59 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2016 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+using System.Linq;
+using HeuristicLab.MainForm;
+
+
+namespace HeuristicLab.Problems.DataAnalysis.Views {
+  [View("Line Chart (prognosis)")]
+  [Content(typeof(ITimeSeriesPrognosisSolution))]
+  public partial class TimeSeriesPrognosisLineChartView : RegressionSolutionLineChartView {
+
+
+    public new ITimeSeriesPrognosisSolution Content {
+      get { return (ITimeSeriesPrognosisSolution)base.Content; }
+      set { base.Content = value; }
+    }
+
+    public TimeSeriesPrognosisLineChartView()
+      : base() {
+      InitializeComponent();
+
+    }
+
+    protected override void GetTrainingSeries(out int[] idx, out double[] y) {
+      idx = Content.ProblemData.TrainingIndices.ToArray();
+      y = Content.EstimatedTrainingValues.ToArray();
+    }
+
+    protected override void GetTestSeries(out int[] idx, out double[] y) {
+      // treat the whole test partition as prognosis horizon
+      idx = Content.ProblemData.TestIndices.ToArray();
+      y = Content.PrognosedTestValues.ToArray();
+    }
+
+    protected override void GetAllValuesSeries(out int[] idx, out double[] y) {
+      // not supported
+      idx = new int[0];
+      y = new double[0];
+    }
+  }
+}
Index: branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis.Views/3.4/TimeSeriesPrognosis/TimeSeriesPrognosisResidualsLineChartView.Designer.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis.Views/3.4/TimeSeriesPrognosis/TimeSeriesPrognosisResidualsLineChartView.Designer.cs	(revision 14562)
+++ branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis.Views/3.4/TimeSeriesPrognosis/TimeSeriesPrognosisResidualsLineChartView.Designer.cs	(revision 14562)
@@ -0,0 +1,52 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2016 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+namespace HeuristicLab.Problems.DataAnalysis.Views {
+  partial class TimeSeriesPrognosisResidualsLineChartView {
+    /// <summary> 
+    /// Required designer variable.
+    /// </summary>
+    private System.ComponentModel.IContainer components = null;
+
+    /// <summary> 
+    /// Clean up any resources being used.
+    /// </summary>
+    /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
+    protected override void Dispose(bool disposing) {
+      if (disposing && (components != null)) {
+        components.Dispose();
+      }
+      base.Dispose(disposing);
+    }
+
+    #region Component Designer generated code
+
+    /// <summary> 
+    /// Required method for Designer support - do not modify 
+    /// the contents of this method with the code editor.
+    /// </summary>
+    private void InitializeComponent() {
+
+    }
+
+    #endregion
+
+  }
+}
Index: branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis.Views/3.4/TimeSeriesPrognosis/TimeSeriesPrognosisResidualsLineChartView.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis.Views/3.4/TimeSeriesPrognosis/TimeSeriesPrognosisResidualsLineChartView.cs	(revision 14562)
+++ branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis.Views/3.4/TimeSeriesPrognosis/TimeSeriesPrognosisResidualsLineChartView.cs	(revision 14562)
@@ -0,0 +1,55 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2016 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.Linq;
+using System.Windows.Forms.DataVisualization.Charting;
+using HeuristicLab.MainForm;
+
+
+namespace HeuristicLab.Problems.DataAnalysis.Views {
+  [View("Residuals Line Chart (prognosis)")]
+  [Content(typeof(ITimeSeriesPrognosisSolution))]
+  public partial class TimeSeriesPrognosisResidualsLineChartView : RegressionSolutionResidualsLineChartView, IDataAnalysisSolutionEvaluationView {
+
+    public new ITimeSeriesPrognosisSolution Content {
+      get { return (ITimeSeriesPrognosisSolution)base.Content; }
+      set { base.Content = value; }
+    }
+
+    public TimeSeriesPrognosisResidualsLineChartView()
+      : base() {
+      InitializeComponent();
+    }                                                                                                      
+
+    protected override void GetTestSeries(out int[] idx, out double[] y) {
+      idx = Content.ProblemData.TestIndices.ToArray();
+      y = Content.PrognosedTestValues.ToArray();
+      CalcResiduals(idx, y);
+    }
+
+    protected override void GetAllValuesSeries(out int[] idx, out double[] y) {
+      // not supported
+      idx = new int[0];
+      y = new double[0];
+    }                                                                                     
+  }
+}
Index: branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/DataAnalysisProblemData.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/DataAnalysisProblemData.cs	(revision 14557)
+++ branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/DataAnalysisProblemData.cs	(revision 14562)
@@ -41,16 +41,37 @@
 
     #region parameter properites
+    //mkommend: inserted parameter caching due to performance reasons
+    private IFixedValueParameter<Dataset> datasetParameter;
     public IFixedValueParameter<Dataset> DatasetParameter {
-      get { return (IFixedValueParameter<Dataset>)Parameters[DatasetParameterName]; }
-    }
+      get {
+        if (datasetParameter == null) datasetParameter = (IFixedValueParameter<Dataset>)Parameters[DatasetParameterName];
+        return datasetParameter;
+      }
+    }
+
+    private IFixedValueParameter<ReadOnlyCheckedItemList<StringValue>> inputVariablesParameter;
     public IFixedValueParameter<ReadOnlyCheckedItemList<StringValue>> InputVariablesParameter {
-      get { return (IFixedValueParameter<ReadOnlyCheckedItemList<StringValue>>)Parameters[InputVariablesParameterName]; }
-    }
+      get {
+        if (inputVariablesParameter == null) inputVariablesParameter = (IFixedValueParameter<ReadOnlyCheckedItemList<StringValue>>)Parameters[InputVariablesParameterName];
+        return inputVariablesParameter;
+      }
+    }
+
+    private IFixedValueParameter<IntRange> trainingPartitionParameter;
     public IFixedValueParameter<IntRange> TrainingPartitionParameter {
-      get { return (IFixedValueParameter<IntRange>)Parameters[TrainingPartitionParameterName]; }
-    }
+      get {
+        if (trainingPartitionParameter == null) trainingPartitionParameter = (IFixedValueParameter<IntRange>)Parameters[TrainingPartitionParameterName];
+        return trainingPartitionParameter;
+      }
+    }
+
+    private IFixedValueParameter<IntRange> testPartitionParameter;
     public IFixedValueParameter<IntRange> TestPartitionParameter {
-      get { return (IFixedValueParameter<IntRange>)Parameters[TestPartitionParameterName]; }
-    }
+      get {
+        if (testPartitionParameter == null) testPartitionParameter = (IFixedValueParameter<IntRange>)Parameters[TestPartitionParameterName];
+        return testPartitionParameter;
+      }
+    }
+
     public IFixedValueParameter<ReadOnlyItemList<ITransformation>> TransformationsParameter {
       get { return (IFixedValueParameter<ReadOnlyItemList<ITransformation>>)Parameters[TransformationsParameterName]; }
@@ -102,6 +123,6 @@
     public virtual bool IsTrainingSample(int index) {
       return index >= 0 && index < Dataset.Rows &&
-        TrainingPartition.Start <= index && index < TrainingPartition.End &&
-        (index < TestPartition.Start || TestPartition.End <= index);
+             TrainingPartition.Start <= index && index < TrainingPartition.End &&
+             (index < TestPartition.Start || TestPartition.End <= index);
     }
 
@@ -214,8 +235,4 @@
         InputVariables.SetItemCheckedState(inputVariable, variable != null && data.InputVariables.ItemChecked(variable));
       }
-
-      TrainingPartition.Start = TrainingPartition.End = 0;
-      TestPartition.Start = 0;
-      TestPartition.End = Dataset.Rows;
     }
   }
Index: branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/RegressionSolutionVariableImpactsCalculator.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/RegressionSolutionVariableImpactsCalculator.cs	(revision 14557)
+++ branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/RegressionSolutionVariableImpactsCalculator.cs	(revision 14562)
@@ -122,9 +122,11 @@
       }
 
-
       var impacts = new Dictionary<string, double>();
       var modifiableDataset = ((Dataset)dataset).ToModifiable();
 
-      foreach (var inputVariable in problemData.AllowedInputVariables) {
+      var inputvariables = new HashSet<string>(problemData.AllowedInputVariables.Union(solution.Model.VariablesUsedForPrediction));
+      var allowedInputVariables = dataset.VariableNames.Where(v => inputvariables.Contains(v)).ToList();
+
+      foreach (var inputVariable in allowedInputVariables) {
         var newEstimates = EvaluateModelWithReplacedVariable(solution.Model, inputVariable, modifiableDataset, rows, replacement);
         var newR2 = OnlinePearsonsRCalculator.Calculate(targetValues, newEstimates, out error);
Index: branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/TimeSeriesPrognosis/TimeSeriesPrognosisSolution.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/TimeSeriesPrognosis/TimeSeriesPrognosisSolution.cs	(revision 14557)
+++ branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/TimeSeriesPrognosis/TimeSeriesPrognosisSolution.cs	(revision 14562)
@@ -21,4 +21,5 @@
 
 using System.Collections.Generic;
+using System.Linq;
 using HeuristicLab.Common;
 using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
@@ -43,4 +44,11 @@
       return Model.GetPrognosedValues(ProblemData.Dataset, rows, horizons);
     }
+
+    public override IEnumerable<double> PrognosedTestValues {
+      get {
+        return Model.GetPrognosedValues(ProblemData.Dataset, ProblemData.TestIndices.Take(1),
+          new int[] { ProblemData.TestIndices.Count() }).First();
+      }
+    }
   }
 }
Index: branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/TimeSeriesPrognosis/TimeSeriesPrognosisSolutionBase.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/TimeSeriesPrognosis/TimeSeriesPrognosisSolutionBase.cs	(revision 14557)
+++ branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/TimeSeriesPrognosis/TimeSeriesPrognosisSolutionBase.cs	(revision 14562)
@@ -64,4 +64,5 @@
     }
 
+    public abstract IEnumerable<double> PrognosedTestValues { get; }
     public abstract IEnumerable<IEnumerable<double>> GetPrognosedValues(IEnumerable<int> rows, IEnumerable<int> horizon);
 
@@ -150,5 +151,5 @@
       OnlineCalculatorError errorState;
       double trainingMean = ProblemData.TrainingIndices.Any() ? ProblemData.Dataset.GetDoubleValues(ProblemData.TargetVariable, ProblemData.TrainingIndices).Average() : double.NaN;
-      var meanModel = new ConstantModel(trainingMean,ProblemData.TargetVariable);
+      var meanModel = new ConstantModel(trainingMean, ProblemData.TargetVariable);
 
       double alpha, beta;
Index: branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/TimeSeriesPrognosis/ITimeSeriesPrognosisSolution.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/TimeSeriesPrognosis/ITimeSeriesPrognosisSolution.cs	(revision 14557)
+++ branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/TimeSeriesPrognosis/ITimeSeriesPrognosisSolution.cs	(revision 14562)
@@ -28,4 +28,6 @@
     IEnumerable<IEnumerable<double>> GetPrognosedValues(IEnumerable<int> rows, IEnumerable<int> horizon);
 
+    IEnumerable<double> PrognosedTestValues { get; }
+
     double TrainingTheilsUStatisticAR1 { get; }
     double TestTheilsUStatisticAR1 { get; }
Index: branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/ClassificationPerformanceMeasuresCalculator.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/ClassificationPerformanceMeasuresCalculator.cs	(revision 14557)
+++ branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/ClassificationPerformanceMeasuresCalculator.cs	(revision 14562)
@@ -33,5 +33,6 @@
     }
 
-    protected ClassificationPerformanceMeasuresCalculator(ClassificationPerformanceMeasuresCalculator original, Cloner cloner) {
+    protected ClassificationPerformanceMeasuresCalculator(ClassificationPerformanceMeasuresCalculator original, Cloner cloner)
+      : base(original, cloner) {
       positiveClassName = original.positiveClassName;
       positiveClassValue = original.positiveClassValue;
@@ -41,4 +42,7 @@
       falseNegativeCount = original.falseNegativeCount;
       errorState = original.errorState;
+    }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new ClassificationPerformanceMeasuresCalculator(this, cloner);
     }
 
@@ -147,8 +151,4 @@
       errorState = ErrorState;
     }
-
-    public override IDeepCloneable Clone(Cloner cloner) {
-      return new ClassificationPerformanceMeasuresCalculator(this, cloner);
-    }
   }
 }
Index: branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineBoundedMeanSquaredErrorCalculator.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineBoundedMeanSquaredErrorCalculator.cs	(revision 14557)
+++ branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineBoundedMeanSquaredErrorCalculator.cs	(revision 14562)
@@ -45,5 +45,6 @@
     }
 
-    protected OnlineBoundedMeanSquaredErrorCalculator(OnlineBoundedMeanSquaredErrorCalculator original, Cloner cloner) {
+    protected OnlineBoundedMeanSquaredErrorCalculator(OnlineBoundedMeanSquaredErrorCalculator original, Cloner cloner)
+      : base(original, cloner) {
       LowerBound = original.LowerBound;
       UpperBound = original.UpperBound;
@@ -51,4 +52,7 @@
       errorSum = original.errorSum;
       errorState = original.ErrorState;
+    }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new OnlineBoundedMeanSquaredErrorCalculator(this, cloner);
     }
 
@@ -105,9 +109,4 @@
       }
     }
-
-    // IDeepCloneable interface members
-    public override IDeepCloneable Clone(Cloner cloner) {
-      return new OnlineBoundedMeanSquaredErrorCalculator(this, cloner);
-    }
   }
 }
Index: branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineCovarianceCalculator.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineCovarianceCalculator.cs	(revision 14557)
+++ branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineCovarianceCalculator.cs	(revision 14562)
@@ -39,10 +39,15 @@
     }
 
-    protected OnlineCovarianceCalculator(OnlineCovarianceCalculator other, Cloner cloner) {
-      Cn = other.Cn;
-      xMean = other.xMean;
-      yMean = other.yMean;
-      n = other.n;
-      errorState = other.errorState;
+    protected OnlineCovarianceCalculator(OnlineCovarianceCalculator original, Cloner cloner)
+      : base(original, cloner) {
+      Cn = original.Cn;
+      xMean = original.xMean;
+      yMean = original.yMean;
+      n = original.n;
+      errorState = original.errorState;
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new OnlineCovarianceCalculator(this, cloner);
     }
 
@@ -103,8 +108,4 @@
       }
     }
-
-    public override IDeepCloneable Clone(Cloner cloner) {
-      return new OnlineCovarianceCalculator(this, cloner);
-    }
   }
 }
Index: branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineDirectionalSymmetryCalculator.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineDirectionalSymmetryCalculator.cs	(revision 14557)
+++ branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineDirectionalSymmetryCalculator.cs	(revision 14562)
@@ -41,8 +41,13 @@
     }
 
-    protected OnlineDirectionalSymmetryCalculator(OnlineDirectionalSymmetryCalculator other, Cloner cloner = null) {
-      n = other.n;
-      nCorrect = other.nCorrect;
-      errorState = other.errorState;
+    protected OnlineDirectionalSymmetryCalculator(OnlineDirectionalSymmetryCalculator original, Cloner cloner = null)
+      : base(original, cloner) {
+      n = original.n;
+      nCorrect = original.nCorrect;
+      errorState = original.errorState;
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new OnlineDirectionalSymmetryCalculator(this, cloner);
     }
 
@@ -122,8 +127,4 @@
       }
     }
-
-    public override IDeepCloneable Clone(Cloner cloner) {
-      return new OnlineDirectionalSymmetryCalculator(this, cloner);
-    }
   }
 }
Index: branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineLinearScalingParameterCalculator.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineLinearScalingParameterCalculator.cs	(revision 14557)
+++ branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineLinearScalingParameterCalculator.cs	(revision 14562)
@@ -55,7 +55,7 @@
     }
 
-    private OnlineMeanAndVarianceCalculator targetMeanCalculator;
-    private OnlineMeanAndVarianceCalculator originalMeanAndVarianceCalculator;
-    private OnlineCovarianceCalculator originalTargetCovarianceCalculator;
+    private readonly OnlineMeanAndVarianceCalculator targetMeanCalculator;
+    private readonly OnlineMeanAndVarianceCalculator originalMeanAndVarianceCalculator;
+    private readonly OnlineCovarianceCalculator originalTargetCovarianceCalculator;
 
     public OnlineLinearScalingParameterCalculator() {
@@ -66,9 +66,13 @@
     }
 
-    protected OnlineLinearScalingParameterCalculator(OnlineLinearScalingParameterCalculator other, Cloner cloner) {
-      targetMeanCalculator = (OnlineMeanAndVarianceCalculator)other.targetMeanCalculator.Clone(cloner);
-      originalMeanAndVarianceCalculator = (OnlineMeanAndVarianceCalculator)other.originalMeanAndVarianceCalculator.Clone(cloner);
-      originalTargetCovarianceCalculator = (OnlineCovarianceCalculator)other.originalTargetCovarianceCalculator.Clone(cloner);
+    protected OnlineLinearScalingParameterCalculator(OnlineLinearScalingParameterCalculator original, Cloner cloner)
+      : base(original, cloner) {
+      targetMeanCalculator = cloner.Clone(original.targetMeanCalculator);
+      originalMeanAndVarianceCalculator = cloner.Clone(original.originalMeanAndVarianceCalculator);
+      originalTargetCovarianceCalculator = cloner.Clone(original.originalTargetCovarianceCalculator);
       // do not reset the calculators here
+    }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new OnlineLinearScalingParameterCalculator(this, cloner);
     }
 
@@ -125,8 +129,4 @@
       }
     }
-
-    public override IDeepCloneable Clone(Cloner cloner) {
-      return new OnlineLinearScalingParameterCalculator(this, cloner);
-    }
   }
 }
Index: branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineMaxAbsoluteErrorCalculator.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineMaxAbsoluteErrorCalculator.cs	(revision 14557)
+++ branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineMaxAbsoluteErrorCalculator.cs	(revision 14562)
@@ -39,8 +39,12 @@
     }
 
-    protected OnlineMaxAbsoluteErrorCalculator(OnlineMaxAbsoluteErrorCalculator other, Cloner cloner = null) {
-      mae = other.mae;
-      n = other.n;
-      errorState = other.errorState;
+    protected OnlineMaxAbsoluteErrorCalculator(OnlineMaxAbsoluteErrorCalculator original, Cloner cloner = null)
+      : base(original, cloner) {
+      mae = original.mae;
+      n = original.n;
+      errorState = original.errorState;
+    }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new OnlineMaxAbsoluteErrorCalculator(this, cloner);
     }
 
@@ -95,8 +99,4 @@
       }
     }
-
-    public override IDeepCloneable Clone(Cloner cloner) {
-      return new OnlineMaxAbsoluteErrorCalculator(this, cloner);
-    }
   }
 }
Index: branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineMeanAbsoluteErrorCalculator.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineMeanAbsoluteErrorCalculator.cs	(revision 14557)
+++ branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineMeanAbsoluteErrorCalculator.cs	(revision 14562)
@@ -39,8 +39,12 @@
     }
 
-    protected OnlineMeanAbsoluteErrorCalculator(OnlineMeanAbsoluteErrorCalculator other, Cloner cloner = null) {
-      sae = other.sae;
-      n = other.n;
-      errorState = other.errorState;
+    protected OnlineMeanAbsoluteErrorCalculator(OnlineMeanAbsoluteErrorCalculator original, Cloner cloner = null)
+      : base(original, cloner) {
+      sae = original.sae;
+      n = original.n;
+      errorState = original.errorState;
+    }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new OnlineMeanAbsoluteErrorCalculator(this, cloner);
     }
 
@@ -94,8 +98,4 @@
       }
     }
-
-    public override IDeepCloneable Clone(Cloner cloner) {
-      return new OnlineMeanAbsoluteErrorCalculator(this, cloner);
-    }
   }
 }
Index: branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineMeanAbsolutePercentageErrorCalculator.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineMeanAbsolutePercentageErrorCalculator.cs	(revision 14557)
+++ branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineMeanAbsolutePercentageErrorCalculator.cs	(revision 14562)
@@ -39,8 +39,13 @@
     }
 
-    protected OnlineMeanAbsolutePercentageErrorCalculator(OnlineMeanAbsolutePercentageErrorCalculator other, Cloner cloner = null) {
-      sre = other.sre;
-      n = other.n;
-      errorState = other.errorState;
+    protected OnlineMeanAbsolutePercentageErrorCalculator(OnlineMeanAbsolutePercentageErrorCalculator original, Cloner cloner = null)
+      : base(original, cloner) {
+      sre = original.sre;
+      n = original.n;
+      errorState = original.errorState;
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new OnlineMeanAbsolutePercentageErrorCalculator(this, cloner);
     }
 
@@ -95,8 +100,4 @@
       }
     }
-
-    public override IDeepCloneable Clone(Cloner cloner) {
-      return new OnlineMeanAbsolutePercentageErrorCalculator(this, cloner);
-    }
   }
 }
Index: branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineMeanAndVarianceCalculator.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineMeanAndVarianceCalculator.cs	(revision 14557)
+++ branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineMeanAndVarianceCalculator.cs	(revision 14562)
@@ -67,12 +67,16 @@
     }
 
-    protected OnlineMeanAndVarianceCalculator(OnlineMeanAndVarianceCalculator other, Cloner cloner = null) {
-      m_oldS = other.m_oldS;
-      m_oldM = other.m_oldM;
-      m_newS = other.m_newS;
-      m_newM = other.m_newM;
-      n = other.n;
-      errorState = other.errorState;
-      varianceErrorState = other.varianceErrorState;
+    protected OnlineMeanAndVarianceCalculator(OnlineMeanAndVarianceCalculator original, Cloner cloner = null)
+      : base(original, cloner) {
+      m_oldS = original.m_oldS;
+      m_oldM = original.m_oldM;
+      m_newS = original.m_newS;
+      m_newM = original.m_newM;
+      n = original.n;
+      errorState = original.errorState;
+      varianceErrorState = original.varianceErrorState;
+    }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new OnlineMeanAndVarianceCalculator(this, cloner);
     }
 
@@ -117,8 +121,4 @@
       varianceErrorState = meanAndVarianceCalculator.VarianceErrorState;
     }
-
-    public override IDeepCloneable Clone(Cloner cloner) {
-      return new OnlineMeanAndVarianceCalculator(this, cloner);
-    }
   }
 }
Index: branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineMeanErrorCalculator.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineMeanErrorCalculator.cs	(revision 14557)
+++ branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineMeanErrorCalculator.cs	(revision 14562)
@@ -37,6 +37,10 @@
     }
 
-    protected OnlineMeanErrorCalculator(OnlineMeanErrorCalculator other, Cloner cloner) {
-      meanAndVarianceCalculator = (OnlineMeanAndVarianceCalculator)other.meanAndVarianceCalculator.Clone(cloner);
+    protected OnlineMeanErrorCalculator(OnlineMeanErrorCalculator original, Cloner cloner)
+      : base(original, cloner) {
+      meanAndVarianceCalculator = cloner.Clone(original.meanAndVarianceCalculator);
+    }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new OnlineMeanErrorCalculator(this, cloner);
     }
 
@@ -79,8 +83,4 @@
       }
     }
-
-    public override IDeepCloneable Clone(Cloner cloner) {
-      return new OnlineMeanErrorCalculator(this, cloner);
-    }
   }
 }
Index: branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineMeanSquaredErrorCalculator.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineMeanSquaredErrorCalculator.cs	(revision 14557)
+++ branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineMeanSquaredErrorCalculator.cs	(revision 14562)
@@ -39,8 +39,12 @@
     }
 
-    protected OnlineMeanSquaredErrorCalculator(OnlineMeanSquaredErrorCalculator other, Cloner cloner = null) {
-      sse = other.sse;
-      n = other.n;
-      errorState = other.errorState;
+    protected OnlineMeanSquaredErrorCalculator(OnlineMeanSquaredErrorCalculator original, Cloner cloner)
+      : base(original, cloner) {
+      sse = original.sse;
+      n = original.n;
+      errorState = original.errorState;
+    }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new OnlineMeanSquaredErrorCalculator(this, cloner);
     }
 
@@ -94,8 +98,4 @@
       }
     }
-
-    public override IDeepCloneable Clone(Cloner cloner) {
-      return new OnlineMeanSquaredErrorCalculator(this, cloner);
-    }
   }
 }
Index: branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineNormalizedMeanSquaredErrorCalculator.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineNormalizedMeanSquaredErrorCalculator.cs	(revision 14557)
+++ branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineNormalizedMeanSquaredErrorCalculator.cs	(revision 14562)
@@ -43,7 +43,11 @@
     }
 
-    protected OnlineNormalizedMeanSquaredErrorCalculator(OnlineNormalizedMeanSquaredErrorCalculator other, Cloner cloner) {
-      meanSquaredErrorCalculator = (OnlineMeanAndVarianceCalculator)other.meanSquaredErrorCalculator.Clone(cloner);
-      originalVarianceCalculator = (OnlineMeanAndVarianceCalculator)other.originalVarianceCalculator.Clone(cloner);
+    protected OnlineNormalizedMeanSquaredErrorCalculator(OnlineNormalizedMeanSquaredErrorCalculator original, Cloner cloner)
+      : base(original, cloner) {
+      meanSquaredErrorCalculator = cloner.Clone(original.meanSquaredErrorCalculator);
+      originalVarianceCalculator = cloner.Clone(original.originalVarianceCalculator);
+    }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new OnlineNormalizedMeanSquaredErrorCalculator(this, cloner);
     }
 
@@ -99,7 +103,5 @@
     }
 
-    public override IDeepCloneable Clone(Cloner cloner) {
-      return new OnlineNormalizedMeanSquaredErrorCalculator(this, cloner);
-    }
+
   }
 }
Index: branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlinePearsonsRCalculator.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlinePearsonsRCalculator.cs	(revision 14557)
+++ branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlinePearsonsRCalculator.cs	(revision 14562)
@@ -47,8 +47,12 @@
     public OnlinePearsonsRCalculator() { }
 
-    protected OnlinePearsonsRCalculator(OnlinePearsonsRCalculator other, Cloner cloner) {
-      covCalculator = (OnlineCovarianceCalculator)other.covCalculator.Clone(cloner);
-      sxCalculator = (OnlineMeanAndVarianceCalculator)other.sxCalculator.Clone(cloner);
-      syCalculator = (OnlineMeanAndVarianceCalculator)other.syCalculator.Clone(cloner);
+    protected OnlinePearsonsRCalculator(OnlinePearsonsRCalculator original, Cloner cloner)
+      : base(original, cloner) {
+      covCalculator = cloner.Clone(original.covCalculator);
+      sxCalculator = cloner.Clone(original.sxCalculator);
+      syCalculator = cloner.Clone(original.syCalculator);
+    }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new OnlinePearsonsRCalculator(this, cloner);
     }
 
@@ -97,8 +101,4 @@
       }
     }
-
-    public override IDeepCloneable Clone(Cloner cloner) {
-      return new OnlinePearsonsRCalculator(this, cloner);
-    }
   }
 }
Index: branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlinePearsonsRSquaredCalculator.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlinePearsonsRSquaredCalculator.cs	(revision 14557)
+++ branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlinePearsonsRSquaredCalculator.cs	(revision 14562)
@@ -38,6 +38,10 @@
     public OnlinePearsonsRSquaredCalculator() { }
 
-    protected OnlinePearsonsRSquaredCalculator(OnlinePearsonsRSquaredCalculator other, Cloner cloner) {
-      this.rCalculator = (OnlinePearsonsRCalculator)other.rCalculator.Clone(cloner);
+    protected OnlinePearsonsRSquaredCalculator(OnlinePearsonsRSquaredCalculator original, Cloner cloner)
+      : base(original, cloner) {
+      rCalculator = cloner.Clone(original.rCalculator);
+    }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new OnlinePearsonsRSquaredCalculator(this, cloner);
     }
 
@@ -64,7 +68,5 @@
     }
 
-    public override IDeepCloneable Clone(Cloner cloner) {
-      return new OnlinePearsonsRSquaredCalculator(this, cloner);
-    }
+
   }
 }
Index: branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineTheilsUStatisticCalculator.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineTheilsUStatisticCalculator.cs	(revision 14557)
+++ branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineTheilsUStatisticCalculator.cs	(revision 14562)
@@ -26,6 +26,6 @@
 namespace HeuristicLab.Problems.DataAnalysis {
   public class OnlineTheilsUStatisticCalculator : DeepCloneable, IOnlineTimeSeriesCalculator {
-    private OnlineMeanAndVarianceCalculator squaredErrorMeanCalculator;
-    private OnlineMeanAndVarianceCalculator unbiasedEstimatorMeanCalculator;
+    private readonly OnlineMeanAndVarianceCalculator squaredErrorMeanCalculator;
+    private readonly OnlineMeanAndVarianceCalculator unbiasedEstimatorMeanCalculator;
 
     public double TheilsUStatistic {
@@ -46,7 +46,11 @@
     }
 
-    protected OnlineTheilsUStatisticCalculator(OnlineTheilsUStatisticCalculator other, Cloner cloner) {
-      squaredErrorMeanCalculator = (OnlineMeanAndVarianceCalculator)other.squaredErrorMeanCalculator.Clone(cloner);
-      unbiasedEstimatorMeanCalculator = (OnlineMeanAndVarianceCalculator)other.unbiasedEstimatorMeanCalculator.Clone(cloner);
+    protected OnlineTheilsUStatisticCalculator(OnlineTheilsUStatisticCalculator original, Cloner cloner)
+      : base(original, cloner) {
+      squaredErrorMeanCalculator = cloner.Clone(original.squaredErrorMeanCalculator);
+      unbiasedEstimatorMeanCalculator = cloner.Clone(original.unbiasedEstimatorMeanCalculator);
+    }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new OnlineTheilsUStatisticCalculator(this, cloner);
     }
 
@@ -131,8 +135,4 @@
       }
     }
-
-    public override IDeepCloneable Clone(Cloner cloner) {
-      return new OnlineTheilsUStatisticCalculator(this, cloner);
-    }
   }
 }
Index: branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineWeightedDirectionalSymmetryCalculator.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineWeightedDirectionalSymmetryCalculator.cs	(revision 14557)
+++ branches/MemPRAlgorithm/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineWeightedDirectionalSymmetryCalculator.cs	(revision 14562)
@@ -42,9 +42,14 @@
     }
 
-    protected OnlineWeightedDirectionalSymmetryCalculator(OnlineWeightedDirectionalSymmetryCalculator other, Cloner cloner) {
-      n = other.n;
-      correctSum = other.correctSum;
-      incorrectSum = other.incorrectSum;
-      errorState = other.errorState;
+    protected OnlineWeightedDirectionalSymmetryCalculator(OnlineWeightedDirectionalSymmetryCalculator original, Cloner cloner)
+      : base(original, cloner) {
+      n = original.n;
+      correctSum = original.correctSum;
+      incorrectSum = original.incorrectSum;
+      errorState = original.errorState;
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new OnlineWeightedDirectionalSymmetryCalculator(this, cloner);
     }
 
@@ -125,8 +130,4 @@
       }
     }
-
-    public override IDeepCloneable Clone(Cloner cloner) {
-      return new OnlineWeightedDirectionalSymmetryCalculator(this, cloner);
-    }
   }
 }
Index: branches/MemPRAlgorithm/HeuristicLab.Problems.Instances.Scheduling/3.3/JSSPORLIBInstanceProvider.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Problems.Instances.Scheduling/3.3/JSSPORLIBInstanceProvider.cs	(revision 14557)
+++ branches/MemPRAlgorithm/HeuristicLab.Problems.Instances.Scheduling/3.3/JSSPORLIBInstanceProvider.cs	(revision 14562)
@@ -67,9 +67,5 @@
           var parser = new JSSPORLIBParser();
           parser.Parse(stream);
-          var instance = Load(parser);
-          instance.Name = id.Name;
-          instance.Description = id.Description;
-
-          return instance;
+          return Load(parser);
         }
       }
@@ -82,12 +78,11 @@
       var parser = new JSSPORLIBParser();
       parser.Parse(path);
-      var instance = Load(parser);
-      instance.Name = Path.GetFileName(path);
-      instance.Description = "Loaded from file \"" + path + "\" on " + DateTime.Now.ToString();
-      return instance;
+      return Load(parser);
     }
 
     private JSSPData Load(JSSPORLIBParser parser) {
       var instance = new JSSPData {
+        Name = parser.Name,
+        Description = parser.Description,
         Jobs = parser.Jobs,
         Resources = parser.Resources,
Index: branches/MemPRAlgorithm/HeuristicLab.Problems.Instances.Scheduling/3.3/JSSPORLIBParser.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Problems.Instances.Scheduling/3.3/JSSPORLIBParser.cs	(revision 14557)
+++ branches/MemPRAlgorithm/HeuristicLab.Problems.Instances.Scheduling/3.3/JSSPORLIBParser.cs	(revision 14562)
@@ -24,4 +24,5 @@
 using System.IO;
 using System.Linq;
+using System.Text;
 
 namespace HeuristicLab.Problems.Instances.Scheduling {
@@ -53,5 +54,5 @@
 
     public void Export(string file) {
-      using (Stream stream = new FileStream(file, FileMode.Open, FileAccess.Read)) {
+      using (Stream stream = new FileStream(file, FileMode.Create, FileAccess.ReadWrite)) {
         Export(stream);
       }
@@ -65,48 +66,55 @@
     /// </remarks>
     /// <param name="stream">The stream to read data from.</param>
-    /// <returns>True if the file was successfully read or false otherwise.</returns>
     public void Parse(Stream stream) {
-      var reader = new StreamReader(stream);
-      Name = reader.ReadLine().Trim();
-      Description = reader.ReadLine().Trim();
-      var delim = new char[] { ' ', '\t' };
+      using (var reader = new StreamReader(stream, Encoding.UTF8, true, 4092, true)) {
+        Name = reader.ReadLine().Trim();
+        Description = reader.ReadLine().Trim();
+        var delim = new char[] {' ', '\t'};
 
-      var info = reader.ReadLine().Split(delim, StringSplitOptions.RemoveEmptyEntries);
-      Jobs = int.Parse(info[0]);
-      Resources = int.Parse(info[1]);
-      ProcessingTimes = new double[Jobs, Resources];
-      Demands = new int[Jobs, Resources];
+        var info = reader.ReadLine().Split(delim, StringSplitOptions.RemoveEmptyEntries);
+        Jobs = int.Parse(info[0]);
+        Resources = int.Parse(info[1]);
+        ProcessingTimes = new double[Jobs, Resources];
+        Demands = new int[Jobs, Resources];
 
-      for (int k = 0; k < Jobs; k++) {
-        if (reader.EndOfStream) throw new InvalidDataException("Unexpected End of Stream.");
-        var valLine = reader.ReadLine();
-        while (String.IsNullOrWhiteSpace(valLine)) valLine = reader.ReadLine();
-        var vals = valLine.Split(delim, StringSplitOptions.RemoveEmptyEntries);
-        if (vals.Length > 2 * Resources) {
-          if (DueDates == null) DueDates = new double[Jobs];
-          DueDates[k] = double.Parse(vals.Last(), CultureInfo.InvariantCulture.NumberFormat);
-        }
+        for (int k = 0; k < Jobs; k++) {
+          if (reader.EndOfStream) throw new InvalidDataException("Unexpected End of Stream.");
+          var valLine = reader.ReadLine();
+          while (String.IsNullOrWhiteSpace(valLine)) valLine = reader.ReadLine();
+          var vals = valLine.Split(delim, StringSplitOptions.RemoveEmptyEntries);
+          if (vals.Length > 2 * Resources) {
+            if (DueDates == null) DueDates = new double[Jobs];
+            DueDates[k] = double.Parse(vals.Last(), CultureInfo.InvariantCulture.NumberFormat);
+          }
 
-        for (int i = 0; i < Resources; i++) {
-          Demands[k, i] = int.Parse(vals[2 * i]);
-          ProcessingTimes[k, i] = double.Parse(vals[2 * i + 1], CultureInfo.InvariantCulture.NumberFormat);
+          for (int i = 0; i < Resources; i++) {
+            Demands[k, i] = int.Parse(vals[2 * i]);
+            ProcessingTimes[k, i] = double.Parse(vals[2 * i + 1], CultureInfo.InvariantCulture.NumberFormat);
+          }
         }
       }
-
     }
 
+    /// <summary>
+    /// Writes to the given stream data which is expected to be in the JSSP ORLIB format.
+    /// </summary>
+    /// <remarks>
+    /// The stream is not closed or disposed. The caller has to take care of that.
+    /// </remarks>
+    /// <param name="stream">The stream to write data to.</param>
     public void Export(Stream stream) {
-      var writer = new StreamWriter(stream);
-      writer.WriteLine(Name);
-      writer.WriteLine(Description);
-      writer.WriteLine(Jobs.ToString(CultureInfo.InvariantCulture.NumberFormat) + " " + Resources.ToString(CultureInfo.InvariantCulture.NumberFormat));
-      for (int i = 0; i < Jobs; i++) {
-        for (int j = 0; j < Resources; j++) {
-          writer.Write(Demands[i, j] + " " + ProcessingTimes[i, j] + " ");
+      using (var writer = new StreamWriter(stream, Encoding.UTF8, 4092, true)) {
+        writer.WriteLine(Name);
+        writer.WriteLine(Description);
+        writer.WriteLine(Jobs.ToString(CultureInfo.InvariantCulture.NumberFormat) + " " + Resources.ToString(CultureInfo.InvariantCulture.NumberFormat));
+        for (int i = 0; i < Jobs; i++) {
+          for (int j = 0; j < Resources; j++) {
+            writer.Write(Demands[i, j] + " " + ProcessingTimes[i, j] + " ");
+          }
+          if (DueDates != null) writer.Write(DueDates[i].ToString("r", CultureInfo.InvariantCulture.NumberFormat));
+          writer.WriteLine();
         }
-        if (DueDates != null) writer.Write(DueDates[i].ToString(CultureInfo.InvariantCulture.NumberFormat));
-        writer.WriteLine();
+        writer.Flush();
       }
-      writer.Flush();
     }
 
Index: branches/MemPRAlgorithm/HeuristicLab.Problems.Instances.VehicleRouting/3.4/GoldenFormat/GoldenParser.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Problems.Instances.VehicleRouting/3.4/GoldenFormat/GoldenParser.cs	(revision 14557)
+++ branches/MemPRAlgorithm/HeuristicLab.Problems.Instances.VehicleRouting/3.4/GoldenFormat/GoldenParser.cs	(revision 14562)
@@ -366,5 +366,5 @@
 
           int index = int.Parse(tokens[0]);
-          double value = double.Parse(tokens[1]);
+          double value = double.Parse(tokens[1], System.Globalization.CultureInfo.InvariantCulture);
 
           demands[index] = value;
Index: branches/MemPRAlgorithm/HeuristicLab.Problems.Instances.VehicleRouting/3.4/HeuristicLab.Problems.Instances.VehicleRouting-3.4.csproj
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Problems.Instances.VehicleRouting/3.4/HeuristicLab.Problems.Instances.VehicleRouting-3.4.csproj	(revision 14557)
+++ branches/MemPRAlgorithm/HeuristicLab.Problems.Instances.VehicleRouting/3.4/HeuristicLab.Problems.Instances.VehicleRouting-3.4.csproj	(revision 14562)
@@ -158,4 +158,5 @@
     <EmbeddedResource Include="Data\CordeauMDTW.opt.zip" />
     <EmbeddedResource Include="Data\Homberger.opt.zip" />
+    <EmbeddedResource Include="Data\Solomon.opt.zip" />
     <None Include="Plugin.cs.frame" />
     <Compile Include="Plugin.cs" />
Index: branches/MemPRAlgorithm/HeuristicLab.Problems.Instances.VehicleRouting/3.4/LiLimFormat/LiLimParser.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Problems.Instances.VehicleRouting/3.4/LiLimFormat/LiLimParser.cs	(revision 14557)
+++ branches/MemPRAlgorithm/HeuristicLab.Problems.Instances.VehicleRouting/3.4/LiLimFormat/LiLimParser.cs	(revision 14562)
@@ -149,5 +149,5 @@
 
         vehicles = int.Parse(m[0].Value);
-        capacity = double.Parse(m[1].Value);
+        capacity = double.Parse(m[1].Value, System.Globalization.CultureInfo.InvariantCulture);
 
         line = reader.ReadLine();
Index: branches/MemPRAlgorithm/HeuristicLab.Problems.Instances.VehicleRouting/3.4/SolomonFormat/SolomonFormatInstanceProvider.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Problems.Instances.VehicleRouting/3.4/SolomonFormat/SolomonFormatInstanceProvider.cs	(revision 14557)
+++ branches/MemPRAlgorithm/HeuristicLab.Problems.Instances.VehicleRouting/3.4/SolomonFormat/SolomonFormatInstanceProvider.cs	(revision 14562)
@@ -21,5 +21,5 @@
 
 using System;
-using System.Collections.Generic;
+using System.Globalization;
 using System.IO;
 using System.Linq;
@@ -64,16 +64,19 @@
         string date = ExtractValue(reader.ReadLine());
         string reference = ExtractValue(reader.ReadLine());
-        reader.ReadLine(); // Solution
-
-        var routesQuery =
-          from line in reader.ReadAllLines()
-          where !string.IsNullOrEmpty(line)
-          let tokens = ExtractValue(line).Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries)
-          let stops = tokens.Select(int.Parse).Select(s => s - 1)
-          select stops;
-
-        var routes = routesQuery.Select(s => s.ToArray()).ToArray();
-
-        instance.BestKnownTour = routes;
+        switch (reader.ReadLine().Trim()) { // "Solution" or "Distance"
+          case "Solution":
+            var routesQuery = from line in reader.ReadAllLines()
+                              where !string.IsNullOrEmpty(line)
+                              let tokens = ExtractValue(line).Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries)
+                              let stops = tokens.Select(int.Parse).Select(s => s - 1)
+                              select stops;
+            var routes = routesQuery.Select(s => s.ToArray()).ToArray();
+            instance.BestKnownTour = routes;
+            break;
+          case "Distance":
+            double quality = double.Parse(reader.ReadLine(), CultureInfo.InvariantCulture);
+            instance.BestKnownQuality = quality;
+            break;
+        }
       }
     }
Index: branches/MemPRAlgorithm/HeuristicLab.Problems.Instances.VehicleRouting/3.4/SolomonFormat/SolomonParser.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Problems.Instances.VehicleRouting/3.4/SolomonFormat/SolomonParser.cs	(revision 14557)
+++ branches/MemPRAlgorithm/HeuristicLab.Problems.Instances.VehicleRouting/3.4/SolomonFormat/SolomonParser.cs	(revision 14562)
@@ -143,5 +143,5 @@
 
         vehicles = int.Parse(m[0].Value);
-        capacity = double.Parse(m[1].Value);
+        capacity = double.Parse(m[1].Value, System.Globalization.CultureInfo.InvariantCulture);
 
         for (int i = 0; i < 4; i++) {
Index: branches/MemPRAlgorithm/HeuristicLab.Problems.Programmable/3.3/HeuristicLab.Problems.Programmable-3.3.csproj
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Problems.Programmable/3.3/HeuristicLab.Problems.Programmable-3.3.csproj	(revision 14557)
+++ branches/MemPRAlgorithm/HeuristicLab.Problems.Programmable/3.3/HeuristicLab.Problems.Programmable-3.3.csproj	(revision 14562)
@@ -150,6 +150,7 @@
     </ProjectReference>
     <ProjectReference Include="..\..\HeuristicLab.Encodings.LinearLinkageEncoding\3.4\HeuristicLab.Encodings.LinearLinkageEncoding-3.4.csproj">
-      <Project>{166507c9-ef26-4370-bb80-699742a29d4f}</Project>
+      <Project>{be698769-975a-429e-828c-72bb2b6182c8}</Project>
       <Name>HeuristicLab.Encodings.LinearLinkageEncoding-3.4</Name>
+      <Private>False</Private>
     </ProjectReference>
     <ProjectReference Include="..\..\HeuristicLab.Encodings.PermutationEncoding\3.3\HeuristicLab.Encodings.PermutationEncoding-3.3.csproj">
Index: branches/MemPRAlgorithm/HeuristicLab.Problems.Scheduling/3.3/JobShopSchedulingProblem.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Problems.Scheduling/3.3/JobShopSchedulingProblem.cs	(revision 14557)
+++ branches/MemPRAlgorithm/HeuristicLab.Problems.Scheduling/3.3/JobShopSchedulingProblem.cs	(revision 14562)
@@ -43,4 +43,6 @@
     #region Default Instance
     private static readonly JSSPData DefaultInstance = new JSSPData() {
+      Name = "Job Shop Scheduling Problem (JSSP)",
+      Description = "The default instance of the JSSP problem in HeuristicLab",
       Jobs = 10,
       Resources = 10,
@@ -225,5 +227,6 @@
           BestKnownQuality = new DoubleValue(MakespanEvaluator.GetMakespan(BestKnownSolution));
       }
-
+      Name = data.Name;
+      Description = data.Description;
       JobData = jobData;
       Jobs = data.Jobs;
Index: branches/MemPRAlgorithm/HeuristicLab.Problems.VehicleRouting/3.4/ProblemInstances/VRPProblemInstance.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Problems.VehicleRouting/3.4/ProblemInstances/VRPProblemInstance.cs	(revision 14557)
+++ branches/MemPRAlgorithm/HeuristicLab.Problems.VehicleRouting/3.4/ProblemInstances/VRPProblemInstance.cs	(revision 14562)
@@ -190,6 +190,5 @@
     public virtual double GetDistance(int start, int end, IVRPEncoding solution) {
       if (distanceMatrix == null && UseDistanceMatrix.Value) {
-        if (DistanceMatrix == null) DistanceMatrix = CreateDistanceMatrix();
-        distanceMatrix = DistanceMatrix;
+        distanceMatrix = DistanceMatrix ?? CreateDistanceMatrix();
       }
 
Index: branches/MemPRAlgorithm/HeuristicLab.Problems.VehicleRouting/3.4/VehicleRoutingProblem.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Problems.VehicleRouting/3.4/VehicleRoutingProblem.cs	(revision 14557)
+++ branches/MemPRAlgorithm/HeuristicLab.Problems.VehicleRouting/3.4/VehicleRoutingProblem.cs	(revision 14562)
@@ -198,6 +198,4 @@
         BestKnownQuality = new DoubleValue(ProblemInstance.Evaluate(BestKnownSolution.Solution).Quality);
         BestKnownSolution.Quality = BestKnownQuality;
-      } else {
-        BestKnownQuality = null;
       }
     }
@@ -208,4 +206,5 @@
 
     void ProblemInstance_EvaluationChanged(object sender, EventArgs e) {
+      BestKnownQuality = null;
       EvalBestKnownSolution();
     }
Index: branches/MemPRAlgorithm/HeuristicLab.Tests/HeuristicLab-3.3/Samples/GAGroupingProblemSampleTest.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Tests/HeuristicLab-3.3/Samples/GAGroupingProblemSampleTest.cs	(revision 14557)
+++ branches/MemPRAlgorithm/HeuristicLab.Tests/HeuristicLab-3.3/Samples/GAGroupingProblemSampleTest.cs	(revision 14562)
@@ -49,13 +49,13 @@
     public bool Maximization { get { return false; } }
 
-    private bool[,] allowedTogether;
+    private bool[,] adjacencyMatrix;
       
     public override void Initialize() {
       var encoding = new LinearLinkageEncoding(""lle"", length: ProblemSize);
-      allowedTogether = new bool[encoding.Length, encoding.Length];
+      adjacencyMatrix = new bool[encoding.Length, encoding.Length];
       var random = new System.Random(13);
       for (var i = 0; i < encoding.Length - 1; i++)
         for (var j = i + 1; j < encoding.Length; j++)
-          allowedTogether[i, j] = allowedTogether[j, i] = random.Next(2) == 0;
+          adjacencyMatrix[i, j] = adjacencyMatrix[j, i] = random.Next(2) == 0;
       
       Encoding = encoding;
@@ -68,8 +68,9 @@
         for (var j = 0; j < groups[i].Count; j++)
           for (var k = j + 1; k < groups[i].Count; k++)
-            if (!allowedTogether[groups[i][j], groups[i][k]]) penalty++;
+            if (!adjacencyMatrix[groups[i][j], groups[i][k]]) penalty++;
       }
-      if (penalty > 0) return penalty + ProblemSize;
-      else return groups.Count;
+      var result = groups.Count;
+      if (penalty > 0) result += penalty + ProblemSize;
+      return result;
     }
 
@@ -105,7 +106,7 @@
       ga.SetSeedRandomly.Value = false;
       SamplesUtils.RunAlgorithm(ga);
-      Assert.AreEqual(26, SamplesUtils.GetDoubleResult(ga, "BestQuality"));
-      Assert.AreEqual(27.58, SamplesUtils.GetDoubleResult(ga, "CurrentAverageQuality"));
-      Assert.AreEqual(105, SamplesUtils.GetDoubleResult(ga, "CurrentWorstQuality"));
+      Assert.AreEqual(127, SamplesUtils.GetDoubleResult(ga, "BestQuality"));
+      Assert.AreEqual(129,38, SamplesUtils.GetDoubleResult(ga, "CurrentAverageQuality"));
+      Assert.AreEqual(132, SamplesUtils.GetDoubleResult(ga, "CurrentWorstQuality"));
       Assert.AreEqual(99100, SamplesUtils.GetIntResult(ga, "EvaluatedSolutions"));
     }
@@ -121,6 +122,6 @@
       #endregion
       #region Algorithm Configuration
-      ga.Name = "Genetic Algorithm - Grouping Problem";
-      ga.Description = "A genetic algorithm which solves a grouping problem using the linear linkage encoding.";
+      ga.Name = "Genetic Algorithm - Graph Coloring";
+      ga.Description = "A genetic algorithm which solves a graph coloring problem using the linear linkage encoding.";
       ga.Problem = problem;
       SamplesUtils.ConfigureGeneticAlgorithmParameters<TournamentSelector, MultiLinearLinkageCrossover, MultiLinearLinkageManipulator>(
Index: branches/MemPRAlgorithm/HeuristicLab.Tests/HeuristicLab-3.3/Samples/GPTimeSeriesSampleTest.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Tests/HeuristicLab-3.3/Samples/GPTimeSeriesSampleTest.cs	(revision 14557)
+++ branches/MemPRAlgorithm/HeuristicLab.Tests/HeuristicLab-3.3/Samples/GPTimeSeriesSampleTest.cs	(revision 14562)
@@ -50,8 +50,8 @@
       SamplesUtils.RunAlgorithm(osga);
 
-      Assert.AreEqual(0.020952753415199643, SamplesUtils.GetDoubleResult(osga, "BestQuality"), 1E-8);
-      Assert.AreEqual(0.023220938866319357, SamplesUtils.GetDoubleResult(osga, "CurrentAverageQuality"), 1E-8);
-      Assert.AreEqual(0.023716788824595391, SamplesUtils.GetDoubleResult(osga, "CurrentWorstQuality"), 1E-8);
-      Assert.AreEqual(48200, SamplesUtils.GetIntResult(osga, "EvaluatedSolutions"));
+      Assert.AreEqual(0.015441526903606416, SamplesUtils.GetDoubleResult(osga, "BestQuality"), 1E-8);
+      Assert.AreEqual(0.017420834241279298, SamplesUtils.GetDoubleResult(osga, "CurrentAverageQuality"), 1E-8);
+      Assert.AreEqual(0.065195703753298972, SamplesUtils.GetDoubleResult(osga, "CurrentWorstQuality"), 1E-8);
+      Assert.AreEqual(92000, SamplesUtils.GetIntResult(osga, "EvaluatedSolutions"));
     }
 
@@ -63,4 +63,5 @@
       problem.MaximumSymbolicExpressionTreeDepth.Value = 12;
       problem.EvaluatorParameter.Value.HorizonParameter.Value.Value = 10;
+      problem.ApplyLinearScaling.Value = true;
 
       foreach (var symbol in problem.SymbolicExpressionTreeGrammar.Symbols) {
Index: branches/MemPRAlgorithm/HeuristicLab.Tests/HeuristicLab.Algorithms.ParameterlessPopulationPyramid-3.3/ParameterlessPopulationPyramidTest.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Tests/HeuristicLab.Algorithms.ParameterlessPopulationPyramid-3.3/ParameterlessPopulationPyramidTest.cs	(revision 14557)
+++ branches/MemPRAlgorithm/HeuristicLab.Tests/HeuristicLab.Algorithms.ParameterlessPopulationPyramid-3.3/ParameterlessPopulationPyramidTest.cs	(revision 14562)
@@ -39,5 +39,7 @@
       PrivateObject hidden = new PrivateObject(solver);
       try {
-        hidden.Invoke("Run", new CancellationToken());
+        var ct = new CancellationToken();
+        hidden.Invoke("Initialize", ct);
+        hidden.Invoke("Run", ct);
       } catch (OperationCanceledException) {
         // Ignore
Index: branches/MemPRAlgorithm/HeuristicLab.Tests/HeuristicLab.Encodings.LinearLinkageEncoding-3.4/Auxiliary.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Tests/HeuristicLab.Encodings.LinearLinkageEncoding-3.4/Auxiliary.cs	(revision 14562)
+++ branches/MemPRAlgorithm/HeuristicLab.Tests/HeuristicLab.Encodings.LinearLinkageEncoding-3.4/Auxiliary.cs	(revision 14562)
@@ -0,0 +1,37 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2016 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+namespace HeuristicLab.Encodings.LinearLinkageEncoding.Tests {
+  public static class Auxiliary {
+    public static bool LinearLinkageIsEqualByPosition(LinearLinkage p1, LinearLinkage p2) {
+      bool equal = (p1.Length == p2.Length);
+      if (equal) {
+        for (int i = 0; i < p1.Length; i++) {
+          if (!p1[i].Equals(p2[i])) {
+            equal = false;
+            break;
+          }
+        }
+      }
+      return equal;
+    }
+  }
+}
Index: branches/MemPRAlgorithm/HeuristicLab.Tests/HeuristicLab.Encodings.LinearLinkageEncoding-3.4/ConversionsTest.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Tests/HeuristicLab.Encodings.LinearLinkageEncoding-3.4/ConversionsTest.cs	(revision 14562)
+++ branches/MemPRAlgorithm/HeuristicLab.Tests/HeuristicLab.Encodings.LinearLinkageEncoding-3.4/ConversionsTest.cs	(revision 14562)
@@ -0,0 +1,98 @@
+﻿using System;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+namespace HeuristicLab.Encodings.LinearLinkageEncoding.Tests {
+  [TestClass()]
+  public class ConversionsTest {
+    private readonly int[][] validForwardEncoding = new[]{
+      new int[0], new[] {0},
+      new[] {0, 1}, new[] {1, 1},
+      new[] {0, 1, 2}, new[] {1, 1, 2}, new[] {2, 1, 2},
+      new[] {0, 2, 2}, new[] {1, 2, 2},
+      new[] {0, 1, 2, 3}, new[] {1, 1, 2, 3}, new[] {2, 1, 2, 3}, new[] {3, 1, 2, 3},
+      new[] {0, 1, 3, 3}, new[] {1, 2, 2, 3}, new[] {2, 1, 3, 3}, new[] {3, 2, 2, 3},
+      new[] {0, 2, 2, 3}, new[] {1, 3, 2, 3},
+      new[] {0, 2, 3, 3}
+    };
+    private readonly int[][] invalidForwardEncoding = new[]{
+      new [] {-1}, new [] {1}, new [] {1, 0},
+      new [] {0, 0, 0}, new [] {0, 0, 1}, new [] {0, 0, 2},
+      new [] {0, 1, 0},
+      new [] {0, 2, 0}, new [] {0, 2, 1},
+      new [] {1, 0, 0}, new [] {1, 0, 1}, new [] {1, 0, 2},
+      new [] {1, 1, 0}, new [] {1, 1, 1},
+      new [] {1, 2, 0}, new [] {1, 2, 1},
+      new [] {2, 0, 0}, new [] {2, 0, 1}, new [] {2, 0, 2},
+      new [] {2, 1, 0}, new [] {2, 1, 1},
+      new [] {2, 2, 0}, new [] {2, 2, 1}, new [] {2, 2, 2},
+    };
+    private readonly int[][] invalidEndEncoding = new[]{
+      new [] {-1}, new [] {1}, new [] {1, 0},
+      new [] {0, 0, 1}, new [] {0, 0, 2},
+      new [] {0, 1, 0},
+      new [] {0, 2, 0}, new [] {0, 2, 1},
+      new [] {1, 0, 0}, new [] {1, 0, 1}, new [] {1, 0, 2},
+      new [] {1, 1, 0}, new [] {1, 1, 1},
+      new [] {1, 2, 0}, new [] {1, 2, 1},
+      new [] {2, 0, 0}, new [] {2, 0, 1}, new [] {2, 0, 2},
+      new [] {2, 1, 0}, new [] {2, 1, 1},
+      new [] {2, 2, 0}, new [] {2, 2, 1},
+    };
+
+    [TestMethod()]
+    [TestCategory("Encodings.LinearLinkage")]
+    [TestProperty("Time", "short")]
+    public void EndLinksRoundtripTest() {
+      foreach (var values in validForwardEncoding) {
+        var expected = LinearLinkage.FromForwardLinks(values);
+        var llee = expected.ToEndLinks();
+        var actual = LinearLinkage.FromEndLinks(llee);
+        Assert.IsTrue(Auxiliary.LinearLinkageIsEqualByPosition(expected, actual),
+          "[{0}] did not roundtrip successfully!", string.Join(", ", values));
+      }
+    }
+
+    [TestMethod()]
+    [TestCategory("Encodings.LinearLinkage")]
+    [TestProperty("Time", "short")]
+    public void GroupsRoundtripTest() {
+      foreach (var values in validForwardEncoding) {
+        var expected = LinearLinkage.FromForwardLinks(values);
+        var groups = expected.GetGroups();
+        var actual = LinearLinkage.FromGroups(expected.Length, groups);
+        Assert.IsTrue(Auxiliary.LinearLinkageIsEqualByPosition(expected, actual),
+          "[{0}] did not roundtrip successfully!", string.Join(", ", values));
+      }
+    }
+
+    [TestMethod()]
+    [TestCategory("Encodings.LinearLinkage")]
+    [TestProperty("Time", "short")]
+    public void InvalidForwardLinksTest() {
+      foreach (var values in invalidForwardEncoding) {
+        var isValid = true;
+        try {
+          var lle = LinearLinkage.FromForwardLinks(values);
+        } catch (ArgumentException e) {
+          isValid = false;
+        }
+        Assert.IsFalse(isValid, "[{0}] is invalid and should throw ArgumentException!", string.Join(", ", values));
+      }
+    }
+
+    [TestMethod()]
+    [TestCategory("Encodings.LinearLinkage")]
+    [TestProperty("Time", "short")]
+    public void InvalidEndLinksTest() {
+      foreach (var values in invalidEndEncoding) {
+        var isValid = true;
+        try {
+          var lle = LinearLinkage.FromEndLinks(values);
+        } catch (ArgumentException e) {
+          isValid = false;
+        }
+        Assert.IsFalse(isValid, "{0} should be invalid", string.Join(", ", values));
+      }
+    }
+  }
+}
Index: branches/MemPRAlgorithm/HeuristicLab.Tests/HeuristicLab.Encodings.LinearLinkageEncoding-3.4/GroupCrossoverTest.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Tests/HeuristicLab.Encodings.LinearLinkageEncoding-3.4/GroupCrossoverTest.cs	(revision 14562)
+++ branches/MemPRAlgorithm/HeuristicLab.Tests/HeuristicLab.Encodings.LinearLinkageEncoding-3.4/GroupCrossoverTest.cs	(revision 14562)
@@ -0,0 +1,53 @@
+﻿using System;
+using HeuristicLab.Random;
+using HeuristicLab.Tests;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+namespace HeuristicLab.Encodings.LinearLinkageEncoding.Tests {
+  [TestClass()]
+  public class GroupCrossoverTest {
+    [TestMethod()]
+    [TestCategory("Encodings.LinearLinkage")]
+    [TestProperty("Time", "short")]
+    public void EqualParentsTest() {
+      var random = new FastRandom(0);
+      var parent = LinearLinkage.SingleElementGroups(10);
+      var child = GroupCrossover.Apply(random, parent, parent);
+      Assert.IsTrue(Auxiliary.LinearLinkageIsEqualByPosition(parent, child));
+
+      parent = RandomLinearLinkageCreator.Apply(random, 10);
+      child = GroupCrossover.Apply(random, parent, parent);
+      Assert.IsTrue(Auxiliary.LinearLinkageIsEqualByPosition(parent, child));
+    }
+
+    // Example from paper:
+    // Multi-objective Genetic Algorithms for grouping problems. Korkmaz, E.E. Applied Intelligence (2010) 33: 179. 
+    [TestMethod()]
+    [TestCategory("Encodings.LinearLinkage")]
+    [TestProperty("Time", "short")]
+    public void ExampleFromPaperTest() {
+      var parent1 = LinearLinkage.FromEndLinks(new[] { 3, 4, 3, 3, 4 });
+
+      var parent2 = LinearLinkage.FromEndLinks(new[] { 2, 2, 2, 4, 4 });
+
+      CheckGroupCrossover(parent1, parent2, new[] { 3, 4, 2, 3, 4 }, new[] { 0.0, 0.0, 0.0, 0.0 }); // (i)
+      CheckGroupCrossover(parent1, parent2, new[] { 2, 4, 2, 3, 4 }, new[] { 0.0, 0.0, 0.0, 0.9 }); // (iv)
+      CheckGroupCrossover(parent1, parent2, new[] { 3, 2, 2, 3, 4 }, new[] { 0.0, 0.0, 0.9, 0.0 }); // (iii)
+      CheckGroupCrossover(parent1, parent2, new[] { 2, 2, 2, 3, 4 }, new[] { 0.0, 0.0, 0.9, 0.9 }); // (ii)
+      CheckGroupCrossover(parent1, parent2, new[] { 3, 4, 3, 3, 4 }, new[] { 0.0, 0.9 });
+      CheckGroupCrossover(parent1, parent2, new[] { 2, 4, 2, 4, 4 }, new[] { 0.9, 0.0, 0.0 });
+      CheckGroupCrossover(parent1, parent2, new[] { 2, 2, 2, 4, 4 }, new[] { 0.9, 0.0, 0.9 });
+      CheckGroupCrossover(parent1, parent2, new[] { 4, 4, 4, 4, 4 }, new[] { 0.9, 0.9, 0.0, 0.0 });
+      CheckGroupCrossover(parent1, parent2, new[] { 4, 4, 4, 4, 4 }, new[] { 0.9, 0.9, 0.0, 0.9 });
+      CheckGroupCrossover(parent1, parent2, new[] { 2, 4, 2, 4, 4 }, new[] { 0.9, 0.9, 0.9, 0.0 });
+      CheckGroupCrossover(parent1, parent2, new[] { 4, 4, 2, 4, 4 }, new[] { 0.9, 0.9, 0.9, 0.9 });
+    }
+
+    private void CheckGroupCrossover(LinearLinkage parent1, LinearLinkage parent2, int[] expectedllee, double[] randomNumbers) {
+      var expected = LinearLinkage.FromEndLinks(expectedllee);
+      var random = new TestRandom() { DoubleNumbers = randomNumbers };
+      var child = GroupCrossover.Apply(random, parent1, parent2);
+      Assert.IsTrue(Auxiliary.LinearLinkageIsEqualByPosition(expected, child), "Expected [{0}] but was [{1}]!", string.Join(", ", expected), string.Join(", ", child));
+    }
+  }
+}
Index: branches/MemPRAlgorithm/HeuristicLab.Tests/HeuristicLab.Tests.csproj
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Tests/HeuristicLab.Tests.csproj	(revision 14557)
+++ branches/MemPRAlgorithm/HeuristicLab.Tests/HeuristicLab.Tests.csproj	(revision 14562)
@@ -511,5 +511,7 @@
     <Compile Include="HeuristicLab.Encodings.IntegerVectorEncoding-3.3\UniformOnePositionManipulatorTest.cs" />
     <Compile Include="HeuristicLab.Encodings.LinearLinkageEncoding-3.3\MoveTests.cs" />
-    <Compile Include="HeuristicLab.Encodings.LinearLinkageEncoding-3.3\ConversionTests.cs" />
+    <Compile Include="HeuristicLab.Encodings.LinearLinkageEncoding-3.4\Auxiliary.cs" />
+    <Compile Include="HeuristicLab.Encodings.LinearLinkageEncoding-3.4\ConversionsTest.cs" />
+    <Compile Include="HeuristicLab.Encodings.LinearLinkageEncoding-3.4\GroupCrossoverTest.cs" />
     <Compile Include="HeuristicLab.Encodings.PermutationEncoding-3.3\Auxiliary.cs" />
     <Compile Include="HeuristicLab.Encodings.PermutationEncoding-3.3\CosaCrossoverTest.cs" />
