Index: /branches/HeuristicLab.RegressionSolutionGradientView/Build.cmd
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/Build.cmd	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/Build.cmd	(revision 13819)
@@ -0,0 +1,104 @@
+@ECHO OFF
+
+SET CLEANBEFOREBUILD=
+
+SET SELECTED=
+SET CONFIGURATION=
+SET PLATFORM=
+
+IF "%~1"=="" GOTO :prompt_solution
+
+SET SELECTED=%1
+IF NOT EXIST %SELECTED% (
+  ECHO Solution file %SELECTED% could not be found.
+  GOTO :end
+)
+ECHO Building solution %SELECTED% ...
+GOTO :config_selection
+
+:prompt_solution
+SET /A COUNT=0
+FOR /F "tokens=*" %%A IN ('dir /B *.sln') DO (
+  CALL :forloopbody "%%A"
+)
+
+IF "%COUNT%"=="1" (
+  SET SELECTED=%SOLUTIONS.1%
+  ECHO Building %SOLUTIONS.1% as it is the only solution that was found ...
+  GOTO :config_selection
+)
+
+ECHO Found the following solutions:
+FOR /F "tokens=2* delims=.=" %%A IN ('SET SOLUTIONS.') DO ECHO %%A = %%B
+ECHO.
+SET /P SOLUTIONINDEX=Which solution to build? Type the number: 
+
+SET SELECTED=""
+FOR /F "tokens=2* delims=.=" %%A IN ('SET SOLUTIONS.') DO (
+  IF "%%A"=="%SOLUTIONINDEX%" SET SELECTED=%%B
+)
+
+IF %SELECTED%=="" GOTO :eof
+
+:config_selection
+IF "%~2"==""  GOTO :prompt_config
+
+SET CONFIGURATION=%~2
+ECHO Building configuration %CONFIGURATION% ...
+GOTO :platform_selection
+
+:prompt_config
+SET /P CONFIGURATION=Which configuration to build [Release]: 
+IF "%CONFIGURATION%"=="" SET CONFIGURATION=Release
+
+:platform_selection
+IF "%~3"=="" GOTO :prompt_platform
+  
+SET PLATFORM=%~3
+ECHO Building platform %PLATFORM% ...
+GOTO :clean
+
+:prompt_platform
+SET /P PLATFORM=Which platform to build [Any CPU]: 
+IF "%PLATFORM%"=="" SET PLATFORM=Any CPU
+
+:clean
+IF "%~4"=="" GOTO :prompt_clean
+
+SET CLEANBEFOREBUILD=%~4
+GOTO :main
+
+:prompt_clean
+SET /P CLEANBEFOREBUILD=Would you like to clean before building [n]: 
+IF "%CLEANBEFOREBUILD%"=="" SET CLEANBEFOREBUILD=n
+
+:main
+REM First find the path to the msbuild.exe by performing a registry query
+FOR /F "tokens=1,3 delims=	 " %%A IN ('REG QUERY "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\MSBuild\ToolsVersions\4.0"') DO (
+  IF "%%A"=="MSBuildToolsPath" SET MSBUILDPATH=%%B)
+
+REM Then execute msbuild to clean and build the solution
+REM Disable that msbuild creates a cache file of the solution
+SET MSBuildUseNoSolutionCache=1
+REM Run msbuild to clean and then build
+IF "%CLEANBEFOREBUILD%" NEQ "n" (
+  ECHO Cleaning ...
+  %MSBUILDPATH%msbuild.exe %SELECTED% /target:Clean /p:Configuration="%CONFIGURATION%",Platform="%PLATFORM%" /m:2 /nologo /verbosity:q /clp:ErrorsOnly
+)
+ECHO Building ...
+%MSBUILDPATH%msbuild.exe %SELECTED% /target:Build /p:Configuration="%CONFIGURATION%",Platform="%PLATFORM%" /m:2 /nologo /verbosity:q /clp:ErrorsOnly
+
+ECHO.
+ECHO DONE.
+
+:end
+
+PAUSE
+
+GOTO :eof
+
+REM This workaround is necessary so that COUNT gets reevaluated
+:forloopbody
+SET /A COUNT+=1
+SET SOLUTIONS.%COUNT%=%1
+GOTO :eof
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/BaselineClassifiers/OneR.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/BaselineClassifiers/OneR.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/BaselineClassifiers/OneR.cs	(revision 13819)
@@ -0,0 +1,169 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Optimization;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Problems.DataAnalysis;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  /// <summary>
+  /// 1R classification algorithm.
+  /// </summary>
+  [Item("OneR Classification", "A simple classification algorithm the searches the best single-variable split (does not support categorical features correctly). See R.C. Holte (1993). Very simple classification rules perform well on most commonly used datasets. Machine Learning. 11:63-91.")]
+  [StorableClass]
+  public sealed class OneR : FixedDataAnalysisAlgorithm<IClassificationProblem> {
+
+    public IValueParameter<IntValue> MinBucketSizeParameter {
+      get { return (IValueParameter<IntValue>)Parameters["MinBucketSize"]; }
+    }
+
+    [StorableConstructor]
+    private OneR(bool deserializing) : base(deserializing) { }
+
+    private OneR(OneR original, Cloner cloner)
+      : base(original, cloner) { }
+
+    public OneR()
+      : base() {
+      Parameters.Add(new ValueParameter<IntValue>("MinBucketSize", "Minimum size of a bucket for numerical values. (Except for the rightmost bucket)", new IntValue(6)));
+      Problem = new ClassificationProblem();
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new OneR(this, cloner);
+    }
+
+    protected override void Run() {
+      var solution = CreateOneRSolution(Problem.ProblemData, MinBucketSizeParameter.Value.Value);
+      Results.Add(new Result("OneR solution", "The 1R classifier.", solution));
+    }
+
+    public static IClassificationSolution CreateOneRSolution(IClassificationProblemData problemData, int minBucketSize = 6) {
+      var bestClassified = 0;
+      List<Split> bestSplits = null;
+      string bestVariable = string.Empty;
+      double bestMissingValuesClass = double.NaN;
+      var classValues = problemData.Dataset.GetDoubleValues(problemData.TargetVariable, problemData.TrainingIndices);
+
+      foreach (var variable in problemData.AllowedInputVariables) {
+        var inputValues = problemData.Dataset.GetDoubleValues(variable, problemData.TrainingIndices);
+        var samples = inputValues.Zip(classValues, (i, v) => new Sample(i, v)).OrderBy(s => s.inputValue);
+
+        var missingValuesDistribution = samples.Where(s => double.IsNaN(s.inputValue)).GroupBy(s => s.classValue).ToDictionary(s => s.Key, s => s.Count()).MaxItems(s => s.Value).FirstOrDefault();
+
+        //calculate class distributions for all distinct inputValues
+        List<Dictionary<double, int>> classDistributions = new List<Dictionary<double, int>>();
+        List<double> thresholds = new List<double>();
+        double lastValue = double.NaN;
+        foreach (var sample in samples.Where(s => !double.IsNaN(s.inputValue))) {
+          if (sample.inputValue > lastValue || double.IsNaN(lastValue)) {
+            if (!double.IsNaN(lastValue)) thresholds.Add((lastValue + sample.inputValue) / 2);
+            lastValue = sample.inputValue;
+            classDistributions.Add(new Dictionary<double, int>());
+            foreach (var classValue in problemData.ClassValues)
+              classDistributions[classDistributions.Count - 1][classValue] = 0;
+
+          }
+          classDistributions[classDistributions.Count - 1][sample.classValue]++;
+        }
+        thresholds.Add(double.PositiveInfinity);
+
+        var distribution = classDistributions[0];
+        var threshold = thresholds[0];
+        var splits = new List<Split>();
+
+        for (int i = 1; i < classDistributions.Count; i++) {
+          var samplesInSplit = distribution.Max(d => d.Value);
+          //join splits if there are too few samples in the split or the distributions has the same maximum class value as the current split
+          if (samplesInSplit < minBucketSize ||
+            classDistributions[i].MaxItems(d => d.Value).Select(d => d.Key).Contains(
+              distribution.MaxItems(d => d.Value).Select(d => d.Key).First())) {
+            foreach (var classValue in classDistributions[i])
+              distribution[classValue.Key] += classValue.Value;
+            threshold = thresholds[i];
+          } else {
+            splits.Add(new Split(threshold, distribution.MaxItems(d => d.Value).Select(d => d.Key).First()));
+            distribution = classDistributions[i];
+            threshold = thresholds[i];
+          }
+        }
+        splits.Add(new Split(double.PositiveInfinity, distribution.MaxItems(d => d.Value).Select(d => d.Key).First()));
+
+        int correctClassified = 0;
+        int splitIndex = 0;
+        foreach (var sample in samples.Where(s => !double.IsNaN(s.inputValue))) {
+          while (sample.inputValue >= splits[splitIndex].thresholdValue)
+            splitIndex++;
+          correctClassified += sample.classValue == splits[splitIndex].classValue ? 1 : 0;
+        }
+        correctClassified += missingValuesDistribution.Value;
+
+        if (correctClassified > bestClassified) {
+          bestClassified = correctClassified;
+          bestSplits = splits;
+          bestVariable = variable;
+          bestMissingValuesClass = missingValuesDistribution.Value == 0 ? double.NaN : missingValuesDistribution.Key;
+        }
+      }
+
+      //remove neighboring splits with the same class value
+      for (int i = 0; i < bestSplits.Count - 1; i++) {
+        if (bestSplits[i].classValue == bestSplits[i + 1].classValue) {
+          bestSplits.Remove(bestSplits[i]);
+          i--;
+        }
+      }
+
+      var model = new OneRClassificationModel(bestVariable, bestSplits.Select(s => s.thresholdValue).ToArray(), bestSplits.Select(s => s.classValue).ToArray(), bestMissingValuesClass);
+      var solution = new OneRClassificationSolution(model, (IClassificationProblemData)problemData.Clone());
+
+      return solution;
+    }
+
+    #region helper classes
+    private class Split {
+      public double thresholdValue;
+      public double classValue;
+
+      public Split(double thresholdValue, double classValue) {
+        this.thresholdValue = thresholdValue;
+        this.classValue = classValue;
+      }
+    }
+
+    private class Sample {
+      public double inputValue;
+      public double classValue;
+
+      public Sample(double inputValue, double classValue) {
+        this.inputValue = inputValue;
+        this.classValue = classValue;
+      }
+    }
+    #endregion
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/BaselineClassifiers/OneRClassificationModel.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/BaselineClassifiers/OneRClassificationModel.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/BaselineClassifiers/OneRClassificationModel.cs	(revision 13819)
@@ -0,0 +1,115 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Problems.DataAnalysis;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  [StorableClass]
+  [Item("OneR Classification Model", "A model that uses intervals for one variable to determine the class.")]
+  public class OneRClassificationModel : NamedItem, IClassificationModel {
+    [Storable]
+    protected string variable;
+    public string Variable {
+      get { return variable; }
+    }
+
+    [Storable]
+    protected double[] splits;
+    public double[] Splits {
+      get { return splits; }
+    }
+
+    [Storable]
+    protected double[] classes;
+    public double[] Classes {
+      get { return classes; }
+    }
+
+    [Storable]
+    protected double missingValuesClass;
+    public double MissingValuesClass {
+      get { return missingValuesClass; }
+    }
+
+    [StorableConstructor]
+    protected OneRClassificationModel(bool deserializing) : base(deserializing) { }
+    protected OneRClassificationModel(OneRClassificationModel original, Cloner cloner)
+      : base(original, cloner) {
+      this.variable = (string)original.variable;
+      this.splits = (double[])original.splits.Clone();
+      this.classes = (double[])original.classes.Clone();
+    }
+    public override IDeepCloneable Clone(Cloner cloner) { return new OneRClassificationModel(this, cloner); }
+
+    public OneRClassificationModel(string variable, double[] splits, double[] classes, double missingValuesClass = double.NaN)
+      : base() {
+      if (splits.Length != classes.Length) {
+        throw new ArgumentException("Number of splits and classes has to be equal.");
+      }
+      if (!Double.IsPositiveInfinity(splits[splits.Length - 1])) {
+        throw new ArgumentException("Last split has to be double.PositiveInfinity, so that all values are covered.");
+      }
+      this.name = ItemName;
+      this.description = ItemDescription;
+      this.variable = variable;
+      this.splits = splits;
+      this.classes = classes;
+      this.missingValuesClass = missingValuesClass;
+    }
+
+    // uses sorting to return the values in the order of rows, instead of using nested for loops
+    // to avoid O(n²) runtime
+    public IEnumerable<double> GetEstimatedClassValues(IDataset dataset, IEnumerable<int> rows) {
+      var values = dataset.GetDoubleValues(Variable, rows).ToArray();
+      var rowsArray = rows.ToArray();
+      var order = Enumerable.Range(0, rowsArray.Length).ToArray();
+      double[] estimated = new double[rowsArray.Length];
+      Array.Sort(rowsArray, order);
+      Array.Sort(values, rowsArray);
+      int curSplit = 0, curIndex = 0;
+      while (curIndex < values.Length && Double.IsNaN(values[curIndex])) {
+        estimated[curIndex] = MissingValuesClass;
+        curIndex++;
+      }
+      while (curSplit < Splits.Length) {
+        while (curIndex < values.Length && Splits[curSplit] > values[curIndex]) {
+          estimated[curIndex] = classes[curSplit];
+          curIndex++;
+        }
+        curSplit++;
+      }
+      Array.Sort(rowsArray, estimated);
+      Array.Sort(order, estimated);
+      return estimated;
+    }
+
+    public IClassificationSolution CreateClassificationSolution(IClassificationProblemData problemData) {
+      return new OneRClassificationSolution(this, new ClassificationProblemData(problemData));
+    }
+
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/BaselineClassifiers/OneRClassificationSolution.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/BaselineClassifiers/OneRClassificationSolution.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/BaselineClassifiers/OneRClassificationSolution.cs	(revision 13819)
@@ -0,0 +1,48 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Problems.DataAnalysis;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  [StorableClass]
+  [Item(Name = "OneR Classification Solution", Description = "Represents a OneR classification solution which uses only a single feature with potentially multiple thresholds for class prediction.")]
+  public class OneRClassificationSolution : ClassificationSolution {
+    public new OneRClassificationModel Model {
+      get { return (OneRClassificationModel)base.Model; }
+      set { base.Model = value; }
+    }
+
+    [StorableConstructor]
+    protected OneRClassificationSolution(bool deserializing) : base(deserializing) { }
+    protected OneRClassificationSolution(OneRClassificationSolution original, Cloner cloner) : base(original, cloner) { }
+    public OneRClassificationSolution(OneRClassificationModel model, IClassificationProblemData problemData)
+      : base(model, problemData) {
+      RecalculateResults();
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new OneRClassificationSolution(this, cloner);
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/BaselineClassifiers/ZeroR.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/BaselineClassifiers/ZeroR.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/BaselineClassifiers/ZeroR.cs	(revision 13819)
@@ -0,0 +1,71 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Optimization;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Problems.DataAnalysis;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  /// <summary>
+  /// 0R classification algorithm.
+  /// </summary>
+  [Item("ZeroR Classification", "The simplest possible classifier, ZeroR always predicts the majority class.")]
+  [StorableClass]
+  public sealed class ZeroR : FixedDataAnalysisAlgorithm<IClassificationProblem> {
+
+    [StorableConstructor]
+    private ZeroR(bool deserializing) : base(deserializing) { }
+    private ZeroR(ZeroR original, Cloner cloner)
+      : base(original, cloner) {
+    }
+    public ZeroR()
+      : base() {
+      Problem = new ClassificationProblem();
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new ZeroR(this, cloner);
+    }
+
+    protected override void Run() {
+      var solution = CreateZeroRSolution(Problem.ProblemData);
+      Results.Add(new Result("ZeroR solution", "The simplest possible classifier, ZeroR always predicts the majority class.", solution));
+    }
+
+    public static IClassificationSolution CreateZeroRSolution(IClassificationProblemData problemData) {
+      var dataset = problemData.Dataset;
+      string target = problemData.TargetVariable;
+      var targetValues = dataset.GetDoubleValues(target, problemData.TrainingIndices);
+
+
+      // if multiple classes have the same number of observations then simply take the first one
+      var dominantClass = targetValues.GroupBy(x => x).ToDictionary(g => g.Key, g => g.Count())
+        .MaxItems(kvp => kvp.Value).Select(x => x.Key).First();
+
+      var model = new ConstantModel(dominantClass);
+      var solution = model.CreateClassificationSolution(problemData);
+      return solution;
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/CrossValidation.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/CrossValidation.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/CrossValidation.cs	(revision 13819)
@@ -0,0 +1,743 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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.Threading;
+using HeuristicLab.Collections;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Optimization;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Problems.DataAnalysis;
+using HeuristicLab.Problems.DataAnalysis.Symbolic;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  [Item("Cross Validation (CV)", "Cross-validation wrapper for data analysis algorithms.")]
+  [Creatable(CreatableAttribute.Categories.DataAnalysis, Priority = 100)]
+  [StorableClass]
+  public sealed class CrossValidation : ParameterizedNamedItem, IAlgorithm, IStorableContent {
+    public CrossValidation()
+      : base() {
+      name = ItemName;
+      description = ItemDescription;
+
+      executionState = ExecutionState.Stopped;
+      runs = new RunCollection { OptimizerName = name };
+      runsCounter = 0;
+
+      algorithm = null;
+      clonedAlgorithms = new ItemCollection<IAlgorithm>();
+      results = new ResultCollection();
+
+      folds = new IntValue(2);
+      numberOfWorkers = new IntValue(1);
+      samplesStart = new IntValue(0);
+      samplesEnd = new IntValue(0);
+      storeAlgorithmInEachRun = false;
+
+      RegisterEvents();
+      if (Algorithm != null) RegisterAlgorithmEvents();
+    }
+
+    public string Filename { get; set; }
+
+    #region persistence and cloning
+    [StorableConstructor]
+    private CrossValidation(bool deserializing)
+      : base(deserializing) {
+    }
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() {
+      RegisterEvents();
+      if (Algorithm != null) RegisterAlgorithmEvents();
+    }
+
+    private CrossValidation(CrossValidation original, Cloner cloner)
+      : base(original, cloner) {
+      executionState = original.executionState;
+      storeAlgorithmInEachRun = original.storeAlgorithmInEachRun;
+      runs = cloner.Clone(original.runs);
+      runsCounter = original.runsCounter;
+      algorithm = cloner.Clone(original.algorithm);
+      clonedAlgorithms = cloner.Clone(original.clonedAlgorithms);
+      results = cloner.Clone(original.results);
+
+      folds = cloner.Clone(original.folds);
+      numberOfWorkers = cloner.Clone(original.numberOfWorkers);
+      samplesStart = cloner.Clone(original.samplesStart);
+      samplesEnd = cloner.Clone(original.samplesEnd);
+      RegisterEvents();
+      if (Algorithm != null) RegisterAlgorithmEvents();
+    }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new CrossValidation(this, cloner);
+    }
+
+    #endregion
+
+    #region properties
+    [Storable]
+    private IAlgorithm algorithm;
+    public IAlgorithm Algorithm {
+      get { return algorithm; }
+      set {
+        if (ExecutionState != ExecutionState.Prepared && ExecutionState != ExecutionState.Stopped)
+          throw new InvalidOperationException("Changing the algorithm is only allowed if the CrossValidation is stopped or prepared.");
+        if (algorithm != value) {
+          if (value != null && value.Problem != null && !(value.Problem is IDataAnalysisProblem))
+            throw new ArgumentException("Only algorithms with a DataAnalysisProblem could be used for the cross validation.");
+          if (algorithm != null) DeregisterAlgorithmEvents();
+          algorithm = value;
+          Parameters.Clear();
+
+          if (algorithm != null) {
+            algorithm.StoreAlgorithmInEachRun = false;
+            RegisterAlgorithmEvents();
+            algorithm.Prepare(true);
+            Parameters.AddRange(algorithm.Parameters);
+          }
+          OnAlgorithmChanged();
+          Prepare();
+        }
+      }
+    }
+
+
+    [Storable]
+    private IDataAnalysisProblem problem;
+    public IDataAnalysisProblem Problem {
+      get {
+        if (algorithm == null)
+          return null;
+        return (IDataAnalysisProblem)algorithm.Problem;
+      }
+      set {
+        if (ExecutionState != ExecutionState.Prepared && ExecutionState != ExecutionState.Stopped)
+          throw new InvalidOperationException("Changing the problem is only allowed if the CrossValidation is stopped or prepared.");
+        if (algorithm == null) throw new ArgumentNullException("Could not set a problem before an algorithm was set.");
+        algorithm.Problem = value;
+        problem = value;
+      }
+    }
+
+    IProblem IAlgorithm.Problem {
+      get { return Problem; }
+      set {
+        if (value != null && !ProblemType.IsInstanceOfType(value))
+          throw new ArgumentException("Only DataAnalysisProblems could be used for the cross validation.");
+        Problem = (IDataAnalysisProblem)value;
+      }
+    }
+    public Type ProblemType {
+      get { return typeof(IDataAnalysisProblem); }
+    }
+
+    [Storable]
+    private ItemCollection<IAlgorithm> clonedAlgorithms;
+
+    public IEnumerable<IOptimizer> NestedOptimizers {
+      get {
+        if (Algorithm == null) yield break;
+        yield return Algorithm;
+      }
+    }
+
+    [Storable]
+    private ResultCollection results;
+    public ResultCollection Results {
+      get { return results; }
+    }
+
+    [Storable]
+    private IntValue folds;
+    public IntValue Folds {
+      get { return folds; }
+    }
+    [Storable]
+    private IntValue samplesStart;
+    public IntValue SamplesStart {
+      get { return samplesStart; }
+    }
+    [Storable]
+    private IntValue samplesEnd;
+    public IntValue SamplesEnd {
+      get { return samplesEnd; }
+    }
+    [Storable]
+    private IntValue numberOfWorkers;
+    public IntValue NumberOfWorkers {
+      get { return numberOfWorkers; }
+    }
+
+    [Storable]
+    private bool storeAlgorithmInEachRun;
+    public bool StoreAlgorithmInEachRun {
+      get { return storeAlgorithmInEachRun; }
+      set {
+        if (storeAlgorithmInEachRun != value) {
+          storeAlgorithmInEachRun = value;
+          OnStoreAlgorithmInEachRunChanged();
+        }
+      }
+    }
+
+    [Storable]
+    private int runsCounter;
+    [Storable]
+    private RunCollection runs;
+    public RunCollection Runs {
+      get { return runs; }
+    }
+
+    [Storable]
+    private ExecutionState executionState;
+    public ExecutionState ExecutionState {
+      get { return executionState; }
+      private set {
+        if (executionState != value) {
+          executionState = value;
+          OnExecutionStateChanged();
+          OnItemImageChanged();
+        }
+      }
+    }
+    public static new Image StaticItemImage {
+      get { return HeuristicLab.Common.Resources.VSImageLibrary.Event; }
+    }
+    public override Image ItemImage {
+      get {
+        if (ExecutionState == ExecutionState.Prepared) return HeuristicLab.Common.Resources.VSImageLibrary.ExecutablePrepared;
+        else if (ExecutionState == ExecutionState.Started) return HeuristicLab.Common.Resources.VSImageLibrary.ExecutableStarted;
+        else if (ExecutionState == ExecutionState.Paused) return HeuristicLab.Common.Resources.VSImageLibrary.ExecutablePaused;
+        else if (ExecutionState == ExecutionState.Stopped) return HeuristicLab.Common.Resources.VSImageLibrary.ExecutableStopped;
+        else return base.ItemImage;
+      }
+    }
+
+    public TimeSpan ExecutionTime {
+      get {
+        if (ExecutionState != ExecutionState.Prepared)
+          return TimeSpan.FromMilliseconds(clonedAlgorithms.Select(x => x.ExecutionTime.TotalMilliseconds).Sum());
+        return TimeSpan.Zero;
+      }
+    }
+    #endregion
+
+    protected override void OnNameChanged() {
+      base.OnNameChanged();
+      Runs.OptimizerName = Name;
+    }
+
+    public void Prepare() {
+      if (ExecutionState == ExecutionState.Started)
+        throw new InvalidOperationException(string.Format("Prepare not allowed in execution state \"{0}\".", ExecutionState));
+      results.Clear();
+      clonedAlgorithms.Clear();
+      if (Algorithm != null) {
+        Algorithm.Prepare();
+        if (Algorithm.ExecutionState == ExecutionState.Prepared) OnPrepared();
+      }
+    }
+    public void Prepare(bool clearRuns) {
+      if (clearRuns) runs.Clear();
+      Prepare();
+    }
+
+    public void Start() {
+      if ((ExecutionState != ExecutionState.Prepared) && (ExecutionState != ExecutionState.Paused))
+        throw new InvalidOperationException(string.Format("Start not allowed in execution state \"{0}\".", ExecutionState));
+
+      if (Algorithm != null) {
+        //create cloned algorithms
+        if (clonedAlgorithms.Count == 0) {
+          int testSamplesCount = (SamplesEnd.Value - SamplesStart.Value) / Folds.Value;
+
+          for (int i = 0; i < Folds.Value; i++) {
+            IAlgorithm clonedAlgorithm = (IAlgorithm)algorithm.Clone();
+            clonedAlgorithm.Name = algorithm.Name + " Fold " + i;
+            IDataAnalysisProblem problem = clonedAlgorithm.Problem as IDataAnalysisProblem;
+            ISymbolicDataAnalysisProblem symbolicProblem = problem as ISymbolicDataAnalysisProblem;
+
+            int testStart = (i * testSamplesCount) + SamplesStart.Value;
+            int testEnd = (i + 1) == Folds.Value ? SamplesEnd.Value : (i + 1) * testSamplesCount + SamplesStart.Value;
+
+            problem.ProblemData.TrainingPartition.Start = SamplesStart.Value;
+            problem.ProblemData.TrainingPartition.End = SamplesEnd.Value;
+            problem.ProblemData.TestPartition.Start = testStart;
+            problem.ProblemData.TestPartition.End = testEnd;
+            DataAnalysisProblemData problemData = problem.ProblemData as DataAnalysisProblemData;
+            if (problemData != null) {
+              problemData.TrainingPartitionParameter.Hidden = false;
+              problemData.TestPartitionParameter.Hidden = false;
+            }
+
+            if (symbolicProblem != null) {
+              symbolicProblem.FitnessCalculationPartition.Start = SamplesStart.Value;
+              symbolicProblem.FitnessCalculationPartition.End = SamplesEnd.Value;
+            }
+            clonedAlgorithm.Prepare();
+            clonedAlgorithms.Add(clonedAlgorithm);
+          }
+        }
+
+        //start prepared or paused cloned algorithms
+        int startedAlgorithms = 0;
+        foreach (IAlgorithm clonedAlgorithm in clonedAlgorithms) {
+          if (startedAlgorithms < NumberOfWorkers.Value) {
+            if (clonedAlgorithm.ExecutionState == ExecutionState.Prepared ||
+                clonedAlgorithm.ExecutionState == ExecutionState.Paused) {
+
+              // start and wait until the alg is started 
+              using (var signal = new ManualResetEvent(false)) {
+                EventHandler signalSetter = (sender, args) => { signal.Set(); };
+                clonedAlgorithm.Started += signalSetter;
+                clonedAlgorithm.Start();
+                signal.WaitOne();
+                clonedAlgorithm.Started -= signalSetter;
+
+                startedAlgorithms++;
+              }
+            }
+          }
+        }
+        OnStarted();
+      }
+    }
+
+    private bool pausePending;
+    public void Pause() {
+      if (ExecutionState != ExecutionState.Started)
+        throw new InvalidOperationException(string.Format("Pause not allowed in execution state \"{0}\".", ExecutionState));
+      if (!pausePending) {
+        pausePending = true;
+        PauseAllClonedAlgorithms();
+      }
+    }
+    private void PauseAllClonedAlgorithms() {
+      foreach (IAlgorithm clonedAlgorithm in clonedAlgorithms) {
+        if (clonedAlgorithm.ExecutionState == ExecutionState.Started)
+          clonedAlgorithm.Pause();
+      }
+    }
+
+    private bool stopPending;
+    public void Stop() {
+      if ((ExecutionState != ExecutionState.Started) && (ExecutionState != ExecutionState.Paused))
+        throw new InvalidOperationException(string.Format("Stop not allowed in execution state \"{0}\".",
+                                                          ExecutionState));
+      if (!stopPending) {
+        stopPending = true;
+        StopAllClonedAlgorithms();
+      }
+    }
+    private void StopAllClonedAlgorithms() {
+      foreach (IAlgorithm clonedAlgorithm in clonedAlgorithms) {
+        if (clonedAlgorithm.ExecutionState == ExecutionState.Started ||
+            clonedAlgorithm.ExecutionState == ExecutionState.Paused)
+          clonedAlgorithm.Stop();
+      }
+    }
+
+    #region collect parameters and results
+    public override void CollectParameterValues(IDictionary<string, IItem> values) {
+      values.Add("Algorithm Name", new StringValue(Name));
+      values.Add("Algorithm Type", new StringValue(GetType().GetPrettyName()));
+      values.Add("Folds", new IntValue(Folds.Value));
+
+      if (algorithm != null) {
+        values.Add("CrossValidation Algorithm Name", new StringValue(Algorithm.Name));
+        values.Add("CrossValidation Algorithm Type", new StringValue(Algorithm.GetType().GetPrettyName()));
+        base.CollectParameterValues(values);
+      }
+      if (Problem != null) {
+        values.Add("Problem Name", new StringValue(Problem.Name));
+        values.Add("Problem Type", new StringValue(Problem.GetType().GetPrettyName()));
+        Problem.CollectParameterValues(values);
+      }
+    }
+
+    public void CollectResultValues(IDictionary<string, IItem> results) {
+      var clonedResults = (ResultCollection)this.results.Clone();
+      foreach (var result in clonedResults) {
+        results.Add(result.Name, result.Value);
+      }
+    }
+
+    private void AggregateResultValues(IDictionary<string, IItem> results) {
+      IEnumerable<IRun> runs = clonedAlgorithms.Select(alg => alg.Runs.FirstOrDefault()).Where(run => run != null);
+      IEnumerable<KeyValuePair<string, IItem>> resultCollections = runs.Where(x => x != null).SelectMany(x => x.Results).ToList();
+
+      foreach (IResult result in ExtractAndAggregateResults<IntValue>(resultCollections))
+        results.Add(result.Name, result.Value);
+      foreach (IResult result in ExtractAndAggregateResults<DoubleValue>(resultCollections))
+        results.Add(result.Name, result.Value);
+      foreach (IResult result in ExtractAndAggregateResults<PercentValue>(resultCollections))
+        results.Add(result.Name, result.Value);
+      foreach (IResult result in ExtractAndAggregateRegressionSolutions(resultCollections)) {
+        results.Add(result.Name, result.Value);
+      }
+      foreach (IResult result in ExtractAndAggregateClassificationSolutions(resultCollections)) {
+        results.Add(result.Name, result.Value);
+      }
+      results.Add("Execution Time", new TimeSpanValue(this.ExecutionTime));
+      results.Add("CrossValidation Folds", new RunCollection(runs));
+    }
+
+    private IEnumerable<IResult> ExtractAndAggregateRegressionSolutions(IEnumerable<KeyValuePair<string, IItem>> resultCollections) {
+      Dictionary<string, List<IRegressionSolution>> resultSolutions = new Dictionary<string, List<IRegressionSolution>>();
+      foreach (var result in resultCollections) {
+        var regressionSolution = result.Value as IRegressionSolution;
+        if (regressionSolution != null) {
+          if (resultSolutions.ContainsKey(result.Key)) {
+            resultSolutions[result.Key].Add(regressionSolution);
+          } else {
+            resultSolutions.Add(result.Key, new List<IRegressionSolution>() { regressionSolution });
+          }
+        }
+      }
+      List<IResult> aggregatedResults = new List<IResult>();
+      foreach (KeyValuePair<string, List<IRegressionSolution>> solutions in resultSolutions) {
+        // clone manually to correctly clone references between cloned root objects 
+        Cloner cloner = new Cloner();
+        var problemDataClone = (IRegressionProblemData)cloner.Clone(Problem.ProblemData);
+        // set partitions of problem data clone correctly
+        problemDataClone.TrainingPartition.Start = SamplesStart.Value; problemDataClone.TrainingPartition.End = SamplesEnd.Value;
+        problemDataClone.TestPartition.Start = SamplesStart.Value; problemDataClone.TestPartition.End = SamplesEnd.Value;
+        // clone models
+        var ensembleSolution = new RegressionEnsembleSolution(problemDataClone);
+        ensembleSolution.AddRegressionSolutions(solutions.Value);
+
+        aggregatedResults.Add(new Result(solutions.Key + " (ensemble)", ensembleSolution));
+      }
+      List<IResult> flattenedResults = new List<IResult>();
+      CollectResultsRecursively("", aggregatedResults, flattenedResults);
+      return flattenedResults;
+    }
+
+    private IEnumerable<IResult> ExtractAndAggregateClassificationSolutions(IEnumerable<KeyValuePair<string, IItem>> resultCollections) {
+      Dictionary<string, List<IClassificationSolution>> resultSolutions = new Dictionary<string, List<IClassificationSolution>>();
+      foreach (var result in resultCollections) {
+        var classificationSolution = result.Value as IClassificationSolution;
+        if (classificationSolution != null) {
+          if (resultSolutions.ContainsKey(result.Key)) {
+            resultSolutions[result.Key].Add(classificationSolution);
+          } else {
+            resultSolutions.Add(result.Key, new List<IClassificationSolution>() { classificationSolution });
+          }
+        }
+      }
+      var aggregatedResults = new List<IResult>();
+      foreach (KeyValuePair<string, List<IClassificationSolution>> solutions in resultSolutions) {
+        // clone manually to correctly clone references between cloned root objects 
+        Cloner cloner = new Cloner();
+        var problemDataClone = (IClassificationProblemData)cloner.Clone(Problem.ProblemData);
+        // set partitions of problem data clone correctly
+        problemDataClone.TrainingPartition.Start = SamplesStart.Value; problemDataClone.TrainingPartition.End = SamplesEnd.Value;
+        problemDataClone.TestPartition.Start = SamplesStart.Value; problemDataClone.TestPartition.End = SamplesEnd.Value;
+        // clone models
+        var ensembleSolution = new ClassificationEnsembleSolution(problemDataClone);
+        ensembleSolution.AddClassificationSolutions(solutions.Value);
+
+        aggregatedResults.Add(new Result(solutions.Key + " (ensemble)", ensembleSolution));
+      }
+      List<IResult> flattenedResults = new List<IResult>();
+      CollectResultsRecursively("", aggregatedResults, flattenedResults);
+      return flattenedResults;
+    }
+
+    private void CollectResultsRecursively(string path, IEnumerable<IResult> results, IList<IResult> flattenedResults) {
+      foreach (IResult result in results) {
+        flattenedResults.Add(new Result(path + result.Name, result.Value));
+        ResultCollection childCollection = result.Value as ResultCollection;
+        if (childCollection != null) {
+          CollectResultsRecursively(path + result.Name + ".", childCollection, flattenedResults);
+        }
+      }
+    }
+
+    private static IEnumerable<IResult> ExtractAndAggregateResults<T>(IEnumerable<KeyValuePair<string, IItem>> results)
+  where T : class, IItem, new() {
+      Dictionary<string, List<double>> resultValues = new Dictionary<string, List<double>>();
+      foreach (var resultValue in results.Where(r => r.Value.GetType() == typeof(T))) {
+        if (!resultValues.ContainsKey(resultValue.Key))
+          resultValues[resultValue.Key] = new List<double>();
+        resultValues[resultValue.Key].Add(ConvertToDouble(resultValue.Value));
+      }
+
+      DoubleValue doubleValue;
+      if (typeof(T) == typeof(PercentValue))
+        doubleValue = new PercentValue();
+      else if (typeof(T) == typeof(DoubleValue))
+        doubleValue = new DoubleValue();
+      else if (typeof(T) == typeof(IntValue))
+        doubleValue = new DoubleValue();
+      else
+        throw new NotSupportedException();
+
+      List<IResult> aggregatedResults = new List<IResult>();
+      foreach (KeyValuePair<string, List<double>> resultValue in resultValues) {
+        doubleValue.Value = resultValue.Value.Average();
+        aggregatedResults.Add(new Result(resultValue.Key + " (average)", (IItem)doubleValue.Clone()));
+        doubleValue.Value = resultValue.Value.StandardDeviation();
+        aggregatedResults.Add(new Result(resultValue.Key + " (std.dev.)", (IItem)doubleValue.Clone()));
+      }
+      return aggregatedResults;
+    }
+
+    private static double ConvertToDouble(IItem item) {
+      if (item is DoubleValue) return ((DoubleValue)item).Value;
+      else if (item is IntValue) return ((IntValue)item).Value;
+      else throw new NotSupportedException("Could not convert any item type to double");
+    }
+    #endregion
+
+    #region events
+    private void RegisterEvents() {
+      Folds.ValueChanged += new EventHandler(Folds_ValueChanged);
+      RegisterClonedAlgorithmsEvents();
+    }
+    private void Folds_ValueChanged(object sender, EventArgs e) {
+      if (ExecutionState != ExecutionState.Prepared)
+        throw new InvalidOperationException("Can not change number of folds if the execution state is not prepared.");
+    }
+
+
+    #region template algorithms events
+    public event EventHandler AlgorithmChanged;
+    private void OnAlgorithmChanged() {
+      EventHandler handler = AlgorithmChanged;
+      if (handler != null) handler(this, EventArgs.Empty);
+      OnProblemChanged();
+      if (Problem == null) ExecutionState = ExecutionState.Stopped;
+    }
+    private void RegisterAlgorithmEvents() {
+      algorithm.ProblemChanged += new EventHandler(Algorithm_ProblemChanged);
+      algorithm.ExecutionStateChanged += new EventHandler(Algorithm_ExecutionStateChanged);
+      if (Problem != null) Problem.Reset += new EventHandler(Problem_Reset);
+    }
+    private void DeregisterAlgorithmEvents() {
+      algorithm.ProblemChanged -= new EventHandler(Algorithm_ProblemChanged);
+      algorithm.ExecutionStateChanged -= new EventHandler(Algorithm_ExecutionStateChanged);
+      if (Problem != null) Problem.Reset -= new EventHandler(Problem_Reset);
+    }
+    private void Algorithm_ProblemChanged(object sender, EventArgs e) {
+      if (algorithm.Problem != null && !(algorithm.Problem is IDataAnalysisProblem)) {
+        algorithm.Problem = problem;
+        throw new ArgumentException("A cross validation algorithm can only contain DataAnalysisProblems.");
+      }
+      if (problem != null) problem.Reset -= new EventHandler(Problem_Reset);
+      problem = (IDataAnalysisProblem)algorithm.Problem;
+      if (problem != null) problem.Reset += new EventHandler(Problem_Reset);
+      OnProblemChanged();
+    }
+    public event EventHandler ProblemChanged;
+    private void OnProblemChanged() {
+      EventHandler handler = ProblemChanged;
+      if (handler != null) handler(this, EventArgs.Empty);
+      ConfigureProblem();
+    }
+
+    private void Problem_Reset(object sender, EventArgs e) {
+      ConfigureProblem();
+    }
+
+    private void ConfigureProblem() {
+      SamplesStart.Value = 0;
+      if (Problem != null) {
+        SamplesEnd.Value = Problem.ProblemData.Dataset.Rows;
+
+        DataAnalysisProblemData problemData = Problem.ProblemData as DataAnalysisProblemData;
+        if (problemData != null) {
+          problemData.TrainingPartitionParameter.Hidden = true;
+          problemData.TestPartitionParameter.Hidden = true;
+        }
+        ISymbolicDataAnalysisProblem symbolicProblem = Problem as ISymbolicDataAnalysisProblem;
+        if (symbolicProblem != null) {
+          symbolicProblem.FitnessCalculationPartitionParameter.Hidden = true;
+          symbolicProblem.FitnessCalculationPartition.Start = SamplesStart.Value;
+          symbolicProblem.FitnessCalculationPartition.End = SamplesEnd.Value;
+          symbolicProblem.ValidationPartitionParameter.Hidden = true;
+          symbolicProblem.ValidationPartition.Start = 0;
+          symbolicProblem.ValidationPartition.End = 0;
+        }
+      } else
+        SamplesEnd.Value = 0;
+    }
+
+    private void Algorithm_ExecutionStateChanged(object sender, EventArgs e) {
+      switch (Algorithm.ExecutionState) {
+        case ExecutionState.Prepared: OnPrepared();
+          break;
+        case ExecutionState.Started: throw new InvalidOperationException("Algorithm template can not be started.");
+        case ExecutionState.Paused: throw new InvalidOperationException("Algorithm template can not be paused.");
+        case ExecutionState.Stopped: OnStopped();
+          break;
+      }
+    }
+    #endregion
+
+    #region clonedAlgorithms events
+    private void RegisterClonedAlgorithmsEvents() {
+      clonedAlgorithms.ItemsAdded += new CollectionItemsChangedEventHandler<IAlgorithm>(ClonedAlgorithms_ItemsAdded);
+      clonedAlgorithms.ItemsRemoved += new CollectionItemsChangedEventHandler<IAlgorithm>(ClonedAlgorithms_ItemsRemoved);
+      clonedAlgorithms.CollectionReset += new CollectionItemsChangedEventHandler<IAlgorithm>(ClonedAlgorithms_CollectionReset);
+      foreach (IAlgorithm algorithm in clonedAlgorithms)
+        RegisterClonedAlgorithmEvents(algorithm);
+    }
+    private void DeregisterClonedAlgorithmsEvents() {
+      clonedAlgorithms.ItemsAdded -= new CollectionItemsChangedEventHandler<IAlgorithm>(ClonedAlgorithms_ItemsAdded);
+      clonedAlgorithms.ItemsRemoved -= new CollectionItemsChangedEventHandler<IAlgorithm>(ClonedAlgorithms_ItemsRemoved);
+      clonedAlgorithms.CollectionReset -= new CollectionItemsChangedEventHandler<IAlgorithm>(ClonedAlgorithms_CollectionReset);
+      foreach (IAlgorithm algorithm in clonedAlgorithms)
+        DeregisterClonedAlgorithmEvents(algorithm);
+    }
+    private void ClonedAlgorithms_ItemsAdded(object sender, CollectionItemsChangedEventArgs<IAlgorithm> e) {
+      foreach (IAlgorithm algorithm in e.Items)
+        RegisterClonedAlgorithmEvents(algorithm);
+    }
+    private void ClonedAlgorithms_ItemsRemoved(object sender, CollectionItemsChangedEventArgs<IAlgorithm> e) {
+      foreach (IAlgorithm algorithm in e.Items)
+        DeregisterClonedAlgorithmEvents(algorithm);
+    }
+    private void ClonedAlgorithms_CollectionReset(object sender, CollectionItemsChangedEventArgs<IAlgorithm> e) {
+      foreach (IAlgorithm algorithm in e.OldItems)
+        DeregisterClonedAlgorithmEvents(algorithm);
+      foreach (IAlgorithm algorithm in e.Items)
+        RegisterClonedAlgorithmEvents(algorithm);
+    }
+    private void RegisterClonedAlgorithmEvents(IAlgorithm algorithm) {
+      algorithm.ExceptionOccurred += new EventHandler<EventArgs<Exception>>(ClonedAlgorithm_ExceptionOccurred);
+      algorithm.ExecutionTimeChanged += new EventHandler(ClonedAlgorithm_ExecutionTimeChanged);
+      algorithm.Started += new EventHandler(ClonedAlgorithm_Started);
+      algorithm.Paused += new EventHandler(ClonedAlgorithm_Paused);
+      algorithm.Stopped += new EventHandler(ClonedAlgorithm_Stopped);
+    }
+    private void DeregisterClonedAlgorithmEvents(IAlgorithm algorithm) {
+      algorithm.ExceptionOccurred -= new EventHandler<EventArgs<Exception>>(ClonedAlgorithm_ExceptionOccurred);
+      algorithm.ExecutionTimeChanged -= new EventHandler(ClonedAlgorithm_ExecutionTimeChanged);
+      algorithm.Started -= new EventHandler(ClonedAlgorithm_Started);
+      algorithm.Paused -= new EventHandler(ClonedAlgorithm_Paused);
+      algorithm.Stopped -= new EventHandler(ClonedAlgorithm_Stopped);
+    }
+    private void ClonedAlgorithm_ExceptionOccurred(object sender, EventArgs<Exception> e) {
+      OnExceptionOccurred(e.Value);
+    }
+    private void ClonedAlgorithm_ExecutionTimeChanged(object sender, EventArgs e) {
+      OnExecutionTimeChanged();
+    }
+
+    private readonly object locker = new object();
+    private readonly object resultLocker = new object();
+    private void ClonedAlgorithm_Started(object sender, EventArgs e) {
+      IAlgorithm algorithm = sender as IAlgorithm;
+      lock (resultLocker) {
+        if (algorithm != null && !results.ContainsKey(algorithm.Name))
+          results.Add(new Result(algorithm.Name, "Contains results for the specific fold.", algorithm.Results));
+      }
+    }
+
+    private void ClonedAlgorithm_Paused(object sender, EventArgs e) {
+      lock (locker) {
+        if (pausePending && clonedAlgorithms.All(alg => alg.ExecutionState != ExecutionState.Started))
+          OnPaused();
+      }
+    }
+
+    private void ClonedAlgorithm_Stopped(object sender, EventArgs e) {
+      lock (locker) {
+        if (!stopPending && ExecutionState == ExecutionState.Started) {
+          IAlgorithm preparedAlgorithm = clonedAlgorithms.FirstOrDefault(alg => alg.ExecutionState == ExecutionState.Prepared ||
+                                                                                alg.ExecutionState == ExecutionState.Paused);
+          if (preparedAlgorithm != null) preparedAlgorithm.Start();
+        }
+        if (ExecutionState != ExecutionState.Stopped) {
+          if (clonedAlgorithms.All(alg => alg.ExecutionState == ExecutionState.Stopped))
+            OnStopped();
+          else if (stopPending &&
+                   clonedAlgorithms.All(
+                     alg => alg.ExecutionState == ExecutionState.Prepared || alg.ExecutionState == ExecutionState.Stopped))
+            OnStopped();
+        }
+      }
+    }
+    #endregion
+    #endregion
+
+    #region event firing
+    public event EventHandler ExecutionStateChanged;
+    private void OnExecutionStateChanged() {
+      EventHandler handler = ExecutionStateChanged;
+      if (handler != null) handler(this, EventArgs.Empty);
+    }
+    public event EventHandler ExecutionTimeChanged;
+    private void OnExecutionTimeChanged() {
+      EventHandler handler = ExecutionTimeChanged;
+      if (handler != null) handler(this, EventArgs.Empty);
+    }
+    public event EventHandler Prepared;
+    private void OnPrepared() {
+      ExecutionState = ExecutionState.Prepared;
+      EventHandler handler = Prepared;
+      if (handler != null) handler(this, EventArgs.Empty);
+      OnExecutionTimeChanged();
+    }
+    public event EventHandler Started;
+    private void OnStarted() {
+      ExecutionState = ExecutionState.Started;
+      EventHandler handler = Started;
+      if (handler != null) handler(this, EventArgs.Empty);
+    }
+    public event EventHandler Paused;
+    private void OnPaused() {
+      pausePending = false;
+      ExecutionState = ExecutionState.Paused;
+      EventHandler handler = Paused;
+      if (handler != null) handler(this, EventArgs.Empty);
+    }
+    public event EventHandler Stopped;
+    private void OnStopped() {
+      stopPending = false;
+      Dictionary<string, IItem> collectedResults = new Dictionary<string, IItem>();
+      AggregateResultValues(collectedResults);
+      results.AddRange(collectedResults.Select(x => new Result(x.Key, x.Value)).Cast<IResult>().ToArray());
+      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);
+    }
+    public event EventHandler<EventArgs<Exception>> ExceptionOccurred;
+    private void OnExceptionOccurred(Exception exception) {
+      EventHandler<EventArgs<Exception>> handler = ExceptionOccurred;
+      if (handler != null) handler(this, new EventArgs<Exception>(exception));
+    }
+    public event EventHandler StoreAlgorithmInEachRunChanged;
+    private void OnStoreAlgorithmInEachRunChanged() {
+      EventHandler handler = StoreAlgorithmInEachRunChanged;
+      if (handler != null) handler(this, EventArgs.Empty);
+    }
+    #endregion
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/FixedDataAnalysisAlgorithm.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/FixedDataAnalysisAlgorithm.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/FixedDataAnalysisAlgorithm.cs	(revision 13819)
@@ -0,0 +1,131 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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.Threading;
+using System.Threading.Tasks;
+using HeuristicLab.Common;
+using HeuristicLab.Optimization;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Problems.DataAnalysis;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  [StorableClass]
+  public abstract class FixedDataAnalysisAlgorithm<T> : Algorithm,
+    IDataAnalysisAlgorithm<T>,
+    IStorableContent
+    where T : class, IDataAnalysisProblem {
+    public string Filename { get; set; }
+
+    #region Properties
+    public override Type ProblemType {
+      get { return typeof(T); }
+    }
+    public new T Problem {
+      get { return (T)base.Problem; }
+      set { base.Problem = value; }
+    }
+    [Storable]
+    private ResultCollection results;
+    public override ResultCollection Results {
+      get { return results; }
+    }
+    #endregion
+
+    private DateTime lastUpdateTime;
+
+    [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
+
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GBM/GradientBoostingRegressionAlgorithm.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GBM/GradientBoostingRegressionAlgorithm.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GBM/GradientBoostingRegressionAlgorithm.cs	(revision 13819)
@@ -0,0 +1,447 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ * and the BEACON Center for the Study of Evolution in Action.
+ * 
+ * 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 System.Threading;
+using HeuristicLab.Analysis;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
+using HeuristicLab.Optimization;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Problems.DataAnalysis;
+using HeuristicLab.Problems.DataAnalysis.Symbolic;
+using HeuristicLab.Problems.DataAnalysis.Symbolic.Regression;
+using HeuristicLab.Random;
+using HeuristicLab.Selection;
+
+namespace HeuristicLab.Algorithms.DataAnalysis.MctsSymbolicRegression {
+  [Item("Gradient Boosting Machine Regression (GBM)",
+    "Gradient boosting for any regression base learner (e.g. MCTS symbolic regression)")]
+  [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; }
+    }
+
+    #region ParameterNames
+
+    private const string IterationsParameterName = "Iterations";
+    private const string NuParameterName = "Nu";
+    private const string MParameterName = "M";
+    private const string RParameterName = "R";
+    private const string RegressionAlgorithmParameterName = "RegressionAlgorithm";
+    private const string SeedParameterName = "Seed";
+    private const string SetSeedRandomlyParameterName = "SetSeedRandomly";
+    private const string CreateSolutionParameterName = "CreateSolution";
+    private const string RegressionAlgorithmSolutionResultParameterName = "RegressionAlgorithmResult";
+
+    #endregion
+
+    #region ParameterProperties
+
+    public IFixedValueParameter<IntValue> IterationsParameter {
+      get { return (IFixedValueParameter<IntValue>)Parameters[IterationsParameterName]; }
+    }
+
+    public IFixedValueParameter<DoubleValue> NuParameter {
+      get { return (IFixedValueParameter<DoubleValue>)Parameters[NuParameterName]; }
+    }
+
+    public IFixedValueParameter<DoubleValue> RParameter {
+      get { return (IFixedValueParameter<DoubleValue>)Parameters[RParameterName]; }
+    }
+
+    public IFixedValueParameter<DoubleValue> MParameter {
+      get { return (IFixedValueParameter<DoubleValue>)Parameters[MParameterName]; }
+    }
+
+    // regression algorithms are currently: DataAnalysisAlgorithms, BasicAlgorithms and engine algorithms with no common interface
+    public IConstrainedValueParameter<IAlgorithm> RegressionAlgorithmParameter {
+      get { return (IConstrainedValueParameter<IAlgorithm>)Parameters[RegressionAlgorithmParameterName]; }
+    }
+
+    public IFixedValueParameter<StringValue> RegressionAlgorithmSolutionResultParameter {
+      get { return (IFixedValueParameter<StringValue>)Parameters[RegressionAlgorithmSolutionResultParameterName]; }
+    }
+
+    public IFixedValueParameter<IntValue> SeedParameter {
+      get { return (IFixedValueParameter<IntValue>)Parameters[SeedParameterName]; }
+    }
+
+    public FixedValueParameter<BoolValue> SetSeedRandomlyParameter {
+      get { return (FixedValueParameter<BoolValue>)Parameters[SetSeedRandomlyParameterName]; }
+    }
+
+    public IFixedValueParameter<BoolValue> CreateSolutionParameter {
+      get { return (IFixedValueParameter<BoolValue>)Parameters[CreateSolutionParameterName]; }
+    }
+
+    #endregion
+
+    #region Properties
+
+    public int Iterations {
+      get { return IterationsParameter.Value.Value; }
+      set { IterationsParameter.Value.Value = value; }
+    }
+
+    public int Seed {
+      get { return SeedParameter.Value.Value; }
+      set { SeedParameter.Value.Value = value; }
+    }
+
+    public bool SetSeedRandomly {
+      get { return SetSeedRandomlyParameter.Value.Value; }
+      set { SetSeedRandomlyParameter.Value.Value = value; }
+    }
+
+    public double Nu {
+      get { return NuParameter.Value.Value; }
+      set { NuParameter.Value.Value = value; }
+    }
+
+    public double R {
+      get { return RParameter.Value.Value; }
+      set { RParameter.Value.Value = value; }
+    }
+
+    public double M {
+      get { return MParameter.Value.Value; }
+      set { MParameter.Value.Value = value; }
+    }
+
+    public bool CreateSolution {
+      get { return CreateSolutionParameter.Value.Value; }
+      set { CreateSolutionParameter.Value.Value = value; }
+    }
+
+    public IAlgorithm RegressionAlgorithm {
+      get { return RegressionAlgorithmParameter.Value; }
+    }
+
+    public string RegressionAlgorithmResult {
+      get { return RegressionAlgorithmSolutionResultParameter.Value.Value; }
+      set { RegressionAlgorithmSolutionResultParameter.Value.Value = value; }
+    }
+
+    #endregion
+
+    [StorableConstructor]
+    protected GradientBoostingRegressionAlgorithm(bool deserializing)
+      : base(deserializing) {
+    }
+
+    protected GradientBoostingRegressionAlgorithm(GradientBoostingRegressionAlgorithm original, Cloner cloner)
+      : base(original, cloner) {
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new GradientBoostingRegressionAlgorithm(this, cloner);
+    }
+
+    public GradientBoostingRegressionAlgorithm() {
+      Problem = new RegressionProblem(); // default problem
+      var mctsSymbReg = new MctsSymbolicRegressionAlgorithm();
+      mctsSymbReg.Iterations = 10000;
+      mctsSymbReg.StoreAlgorithmInEachRun = false;
+      var sgp = CreateOSGP();
+      var regressionAlgs = new ItemSet<IAlgorithm>(new IAlgorithm[] {
+        new RandomForestRegression(),
+        sgp, 
+        mctsSymbReg
+      });
+      foreach (var alg in regressionAlgs) alg.Prepare();
+
+
+      Parameters.Add(new FixedValueParameter<IntValue>(IterationsParameterName,
+        "Number of iterations", new IntValue(100)));
+      Parameters.Add(new FixedValueParameter<IntValue>(SeedParameterName,
+        "The random seed used to initialize the new pseudo random number generator.", new IntValue(0)));
+      Parameters.Add(new FixedValueParameter<BoolValue>(SetSeedRandomlyParameterName,
+        "True if the random seed should be set to a random value, otherwise false.", new BoolValue(true)));
+      Parameters.Add(new FixedValueParameter<DoubleValue>(NuParameterName,
+        "The learning rate nu when updating predictions in GBM (0 < nu <= 1)", new DoubleValue(0.5)));
+      Parameters.Add(new FixedValueParameter<DoubleValue>(RParameterName,
+        "The fraction of rows that are sampled randomly for the base learner in each iteration (0 < r <= 1)",
+        new DoubleValue(1)));
+      Parameters.Add(new FixedValueParameter<DoubleValue>(MParameterName,
+        "The fraction of variables that are sampled randomly for the base learner in each iteration (0 < m <= 1)",
+        new DoubleValue(0.5)));
+      Parameters.Add(new ConstrainedValueParameter<IAlgorithm>(RegressionAlgorithmParameterName,
+        "The regression algorithm to use as a base learner", regressionAlgs, mctsSymbReg));
+      Parameters.Add(new FixedValueParameter<StringValue>(RegressionAlgorithmSolutionResultParameterName,
+        "The name of the solution produced by the regression algorithm", new StringValue("Solution")));
+      Parameters[RegressionAlgorithmSolutionResultParameterName].Hidden = true;
+      Parameters.Add(new FixedValueParameter<BoolValue>(CreateSolutionParameterName,
+        "Flag that indicates if a solution should be produced at the end of the run", new BoolValue(true)));
+      Parameters[CreateSolutionParameterName].Hidden = true;
+    }
+
+    protected override void Run(CancellationToken cancellationToken) {
+      // Set up the algorithm
+      if (SetSeedRandomly) Seed = new System.Random().Next();
+      var rand = new MersenneTwister((uint)Seed);
+
+      // Set up the results display
+      var iterations = new IntValue(0);
+      Results.Add(new Result("Iterations", iterations));
+
+      var table = new DataTable("Qualities");
+      table.Rows.Add(new DataRow("Loss (train)"));
+      table.Rows.Add(new DataRow("Loss (test)"));
+      Results.Add(new Result("Qualities", table));
+      var curLoss = new DoubleValue();
+      var curTestLoss = new DoubleValue();
+      Results.Add(new Result("Loss (train)", curLoss));
+      Results.Add(new Result("Loss (test)", curTestLoss));
+      var runCollection = new RunCollection();
+      Results.Add(new Result("Runs", runCollection));
+
+      // init
+      var problemData = Problem.ProblemData;
+      var targetVarName = Problem.ProblemData.TargetVariable;
+      var activeVariables = problemData.AllowedInputVariables.Concat(new string[] { problemData.TargetVariable });
+      var modifiableDataset = new ModifiableDataset(
+        activeVariables,
+        activeVariables.Select(v => problemData.Dataset.GetDoubleValues(v).ToList()));
+
+      var trainingRows = problemData.TrainingIndices;
+      var testRows = problemData.TestIndices;
+      var yPred = new double[trainingRows.Count()];
+      var yPredTest = new double[testRows.Count()];
+      var y = problemData.Dataset.GetDoubleValues(problemData.TargetVariable, problemData.TrainingIndices).ToArray();
+      var curY = problemData.Dataset.GetDoubleValues(problemData.TargetVariable, problemData.TrainingIndices).ToArray();
+
+      var yTest = problemData.Dataset.GetDoubleValues(problemData.TargetVariable, problemData.TestIndices).ToArray();
+      var curYTest = problemData.Dataset.GetDoubleValues(problemData.TargetVariable, problemData.TestIndices).ToArray();
+      var nu = Nu;
+      var mVars = (int)Math.Ceiling(M * problemData.AllowedInputVariables.Count());
+      var rRows = (int)Math.Ceiling(R * problemData.TrainingIndices.Count());
+      var alg = RegressionAlgorithm;
+      List<IRegressionModel> models = new List<IRegressionModel>();
+      try {
+
+        // Loop until iteration limit reached or canceled.
+        for (int i = 0; i < Iterations; i++) {
+          cancellationToken.ThrowIfCancellationRequested();
+
+          modifiableDataset.RemoveVariable(targetVarName);
+          modifiableDataset.AddVariable(targetVarName, curY.Concat(curYTest));
+
+          SampleTrainingData(rand, modifiableDataset, rRows, problemData.Dataset, curY, problemData.TargetVariable, problemData.TrainingIndices); // all training indices from the original problem data are allowed 
+          var modifiableProblemData = new RegressionProblemData(modifiableDataset,
+            problemData.AllowedInputVariables.SampleRandomWithoutRepetition(rand, mVars),
+            problemData.TargetVariable);
+          modifiableProblemData.TrainingPartition.Start = 0;
+          modifiableProblemData.TrainingPartition.End = rRows;
+          modifiableProblemData.TestPartition.Start = problemData.TestPartition.Start;
+          modifiableProblemData.TestPartition.End = problemData.TestPartition.End;
+
+          if (!TrySetProblemData(alg, modifiableProblemData))
+            throw new NotSupportedException("The algorithm cannot be used with GBM.");
+
+          IRegressionModel model;
+          IRun run;
+          // try to find a model. The algorithm might fail to produce a model. In this case we just retry until the iterations are exhausted
+          if (TryExecute(alg, RegressionAlgorithmResult, out model, out run)) {
+            int row = 0;
+            // update predictions for training and test
+            // update new targets (in the case of squared error loss we simply use negative residuals)
+            foreach (var pred in model.GetEstimatedValues(problemData.Dataset, trainingRows)) {
+              yPred[row] = yPred[row] + nu * pred;
+              curY[row] = y[row] - yPred[row];
+              row++;
+            }
+            row = 0;
+            foreach (var pred in model.GetEstimatedValues(problemData.Dataset, testRows)) {
+              yPredTest[row] = yPredTest[row] + nu * pred;
+              curYTest[row] = yTest[row] - yPredTest[row];
+              row++;
+            }
+            // determine quality
+            OnlineCalculatorError error;
+            var trainR = OnlinePearsonsRCalculator.Calculate(yPred, y, out error);
+            var testR = OnlinePearsonsRCalculator.Calculate(yPredTest, yTest, out error);
+
+            // iteration results
+            curLoss.Value = error == OnlineCalculatorError.None ? trainR * trainR : 0.0;
+            curTestLoss.Value = error == OnlineCalculatorError.None ? testR * testR : 0.0;
+
+            models.Add(model);
+
+
+          }
+
+          runCollection.Add(run);
+          table.Rows["Loss (train)"].Values.Add(curLoss.Value);
+          table.Rows["Loss (test)"].Values.Add(curTestLoss.Value);
+          iterations.Value = i + 1;
+        }
+
+        // produce solution 
+        if (CreateSolution) {
+          // when all our models are symbolic models we can easily combine them to a single model
+          if (models.All(m => m is ISymbolicRegressionModel)) {
+            Results.Add(new Result("Solution", CreateSymbolicSolution(models, Nu, (IRegressionProblemData)problemData.Clone())));
+          }
+          // just produce an ensemble solution for now (TODO: correct scaling or linear regression for ensemble model weights)
+
+          var ensembleModel = new RegressionEnsembleModel(models) { AverageModelEstimates = false };
+          var ensembleSolution = ensembleModel.CreateRegressionSolution((IRegressionProblemData)problemData.Clone());
+          Results.Add(new Result("EnsembleSolution", ensembleSolution));
+        }
+      }
+      finally {
+        // reset everything
+        alg.Prepare(true);
+      }
+    }
+
+
+    private IAlgorithm CreateOSGP() {
+      // configure strict osgp
+      var alg = new OffspringSelectionGeneticAlgorithm.OffspringSelectionGeneticAlgorithm();
+      var prob = new SymbolicRegressionSingleObjectiveProblem();
+      prob.MaximumSymbolicExpressionTreeDepth.Value = 7;
+      prob.MaximumSymbolicExpressionTreeLength.Value = 15;
+      alg.Problem = prob;
+      alg.SuccessRatio.Value = 1.0;
+      alg.ComparisonFactorLowerBound.Value = 1.0;
+      alg.ComparisonFactorUpperBound.Value = 1.0;
+      alg.MutationProbability.Value = 0.15;
+      alg.PopulationSize.Value = 200;
+      alg.MaximumSelectionPressure.Value = 100;
+      alg.MaximumEvaluatedSolutions.Value = 20000;
+      alg.SelectorParameter.Value = alg.SelectorParameter.ValidValues.OfType<GenderSpecificSelector>().First();
+      alg.MutatorParameter.Value = alg.MutatorParameter.ValidValues.OfType<MultiSymbolicExpressionTreeManipulator>().First();
+      alg.StoreAlgorithmInEachRun = false;
+      return alg;
+    }
+
+    private void SampleTrainingData(MersenneTwister rand, ModifiableDataset ds, int rRows,
+      IDataset sourceDs, double[] curTarget, string targetVarName, IEnumerable<int> trainingIndices) {
+      var selectedRows = trainingIndices.SampleRandomWithoutRepetition(rand, rRows).ToArray();
+      int t = 0;
+      object[] srcRow = new object[ds.Columns];
+      var varNames = ds.DoubleVariables.ToArray();
+      foreach (var r in selectedRows) {
+        // take all values from the original dataset
+        for (int c = 0; c < srcRow.Length; c++) {
+          var col = sourceDs.GetReadOnlyDoubleValues(varNames[c]);
+          srcRow[c] = col[r];
+        }
+        ds.ReplaceRow(t, srcRow);
+        // but use the updated target values
+        ds.SetVariableValue(curTarget[r], targetVarName, t);
+        t++;
+      }
+    }
+
+    private static ISymbolicRegressionSolution CreateSymbolicSolution(List<IRegressionModel> models, double nu, IRegressionProblemData problemData) {
+      var symbModels = models.OfType<ISymbolicRegressionModel>();
+      var lowerLimit = symbModels.Min(m => m.LowerEstimationLimit);
+      var upperLimit = symbModels.Max(m => m.UpperEstimationLimit);
+      var interpreter = new SymbolicDataAnalysisExpressionTreeLinearInterpreter();
+      var progRootNode = new ProgramRootSymbol().CreateTreeNode();
+      var startNode = new StartSymbol().CreateTreeNode();
+
+      var addNode = new Addition().CreateTreeNode();
+      var mulNode = new Multiplication().CreateTreeNode();
+      var scaleNode = (ConstantTreeNode)new Constant().CreateTreeNode(); // all models are scaled using the same nu
+      scaleNode.Value = nu;
+
+      foreach (var m in symbModels) {
+        var relevantPart = m.SymbolicExpressionTree.Root.GetSubtree(0).GetSubtree(0); // skip root and start
+        addNode.AddSubtree((ISymbolicExpressionTreeNode)relevantPart.Clone());
+      }
+
+      mulNode.AddSubtree(addNode);
+      mulNode.AddSubtree(scaleNode);
+      startNode.AddSubtree(mulNode);
+      progRootNode.AddSubtree(startNode);
+      var t = new SymbolicExpressionTree(progRootNode);
+      var combinedModel = new SymbolicRegressionModel(t, interpreter, lowerLimit, upperLimit);
+      var sol = new SymbolicRegressionSolution(combinedModel, problemData);
+      return sol;
+    }
+
+    private static bool TrySetProblemData(IAlgorithm alg, IRegressionProblemData problemData) {
+      var prob = alg.Problem as IRegressionProblem;
+      // there is already a problem and it is compatible -> just set problem data
+      if (prob != null) {
+        prob.ProblemDataParameter.Value = problemData;
+        return true;
+      } else return false;
+    }
+
+    private static bool TryExecute(IAlgorithm alg, string regressionAlgorithmResultName, out IRegressionModel model, out IRun run) {
+      model = null;
+      using (var wh = new AutoResetEvent(false)) {
+        EventHandler<EventArgs<Exception>> handler = (sender, args) => wh.Set();
+        EventHandler handler2 = (sender, args) => wh.Set();
+        alg.ExceptionOccurred += handler;
+        alg.Stopped += handler2;
+        try {
+          alg.Prepare();
+          alg.Start();
+          wh.WaitOne();
+
+          run = alg.Runs.Last();
+          var sols = alg.Results.Select(r => r.Value).OfType<IRegressionSolution>();
+          if (!sols.Any()) return false;
+          var sol = sols.First();
+          if (sols.Skip(1).Any()) {
+            // more than one solution => use regressionAlgorithmResult
+            if (alg.Results.ContainsKey(regressionAlgorithmResultName)) {
+              sol = (IRegressionSolution)alg.Results[regressionAlgorithmResultName].Value;
+            }
+          }
+          var symbRegSol = sol as SymbolicRegressionSolution;
+          // only accept symb reg solutions that do not hit the estimation limits
+          // NaN evaluations would not be critical but are problematic if we want to combine all symbolic models into a single symbolic model 
+          if (symbRegSol == null ||
+            (symbRegSol.TrainingLowerEstimationLimitHits == 0 && symbRegSol.TrainingUpperEstimationLimitHits == 0 &&
+             symbRegSol.TestLowerEstimationLimitHits == 0 && symbRegSol.TestUpperEstimationLimitHits == 0) &&
+            symbRegSol.TrainingNaNEvaluations == 0 && symbRegSol.TestNaNEvaluations == 0) {
+            model = sol.Model;
+          }
+        }
+        finally {
+          alg.ExceptionOccurred -= handler;
+          alg.Stopped -= handler2;
+        }
+      }
+      return model != null;
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/CovarianceFunctions/CovarianceConst.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/CovarianceFunctions/CovarianceConst.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/CovarianceFunctions/CovarianceConst.cs	(revision 13819)
@@ -0,0 +1,98 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  [StorableClass]
+  [Item(Name = "CovarianceConst",
+    Description = "Constant covariance function for Gaussian processes.")]
+  public sealed class CovarianceConst : ParameterizedNamedItem, ICovarianceFunction {
+    public IValueParameter<DoubleValue> ScaleParameter {
+      get { return (IValueParameter<DoubleValue>)Parameters["Scale"]; }
+    }
+    private bool HasFixedScaleParameter {
+      get { return ScaleParameter.Value != null; }
+    }
+    [StorableConstructor]
+    private CovarianceConst(bool deserializing)
+      : base(deserializing) {
+    }
+
+    private CovarianceConst(CovarianceConst original, Cloner cloner)
+      : base(original, cloner) {
+    }
+
+    public CovarianceConst()
+      : base() {
+      Name = ItemName;
+      Description = ItemDescription;
+
+      Parameters.Add(new OptionalValueParameter<DoubleValue>("Scale", "The scale of the constant covariance function."));
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new CovarianceConst(this, cloner);
+    }
+
+    public int GetNumberOfParameters(int numberOfVariables) {
+      return HasFixedScaleParameter ? 0 : 1;
+    }
+
+    public void SetParameter(double[] p) {
+      double scale;
+      GetParameterValues(p, out scale);
+      ScaleParameter.Value = new DoubleValue(scale);
+    }
+
+    private void GetParameterValues(double[] p, out double scale) {
+      int c = 0;
+      // gather parameter values
+      if (HasFixedScaleParameter) {
+        scale = ScaleParameter.Value.Value;
+      } else {
+        scale = Math.Exp(2 * p[c]);
+        c++;
+      }
+      if (p.Length != c) throw new ArgumentException("The length of the parameter vector does not match the number of free parameters for CovarianceConst", "p");
+    }
+
+    public ParameterizedCovarianceFunction GetParameterizedCovarianceFunction(double[] p, int[] columnIndices) {
+      double scale;
+      GetParameterValues(p, out scale);
+      // create functions
+      var cov = new ParameterizedCovarianceFunction();
+      cov.Covariance = (x, i, j) => scale;
+      cov.CrossCovariance = (x, xt, i, j) => scale;
+      if (HasFixedScaleParameter) {
+        cov.CovarianceGradient = (x, i, j) => new double[0];
+      } else {
+        cov.CovarianceGradient = (x, i, j) => new[] { 2.0 * scale };
+      }
+      return cov;
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/CovarianceFunctions/CovarianceLinear.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/CovarianceFunctions/CovarianceLinear.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/CovarianceFunctions/CovarianceLinear.cs	(revision 13819)
@@ -0,0 +1,62 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  [StorableClass]
+  [Item(Name = "CovarianceLinear", Description = "Linear covariance function for Gaussian processes.")]
+  public sealed class CovarianceLinear : Item, ICovarianceFunction {
+    [StorableConstructor]
+    private CovarianceLinear(bool deserializing) : base(deserializing) { }
+    private CovarianceLinear(CovarianceLinear original, Cloner cloner)
+      : base(original, cloner) {
+    }
+    public CovarianceLinear()
+      : base() {
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new CovarianceLinear(this, cloner);
+    }
+
+    public int GetNumberOfParameters(int numberOfVariables) {
+      return 0;
+    }
+
+    public void SetParameter(double[] p) {
+      if (p.Length > 0) throw new ArgumentException("No parameters are allowed for the linear covariance function.");
+    }
+
+    public ParameterizedCovarianceFunction GetParameterizedCovarianceFunction(double[] p, int[] columnIndices) {
+      if (p.Length > 0) throw new ArgumentException("No parameters are allowed for the linear covariance function.");
+      // create functions
+      var cov = new ParameterizedCovarianceFunction();
+      cov.Covariance = (x, i, j) => Util.ScalarProd(x, i, j, columnIndices, 1.0);
+      cov.CrossCovariance = (x, xt, i, j) => Util.ScalarProd(x, i, xt, j, columnIndices, 1.0);
+      cov.CovarianceGradient = (x, i, j) => new double[0];
+      return cov;
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/CovarianceFunctions/CovarianceLinearArd.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/CovarianceFunctions/CovarianceLinearArd.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/CovarianceFunctions/CovarianceLinearArd.cs	(revision 13819)
@@ -0,0 +1,109 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  [StorableClass]
+  [Item(Name = "CovarianceLinearArd",
+    Description = "Linear covariance function with automatic relevance determination for Gaussian processes.")]
+  public sealed class CovarianceLinearArd : ParameterizedNamedItem, ICovarianceFunction {
+    public IValueParameter<DoubleArray> InverseLengthParameter {
+      get { return (IValueParameter<DoubleArray>)Parameters["InverseLength"]; }
+    }
+    private bool HasFixedInverseLengthParameter {
+      get { return InverseLengthParameter.Value != null; }
+    }
+
+    [StorableConstructor]
+    private CovarianceLinearArd(bool deserializing) : base(deserializing) { }
+    private CovarianceLinearArd(CovarianceLinearArd original, Cloner cloner)
+      : base(original, cloner) {
+    }
+    public CovarianceLinearArd()
+      : base() {
+      Name = ItemName;
+      Description = ItemDescription;
+
+      Parameters.Add(new OptionalValueParameter<DoubleArray>("InverseLength",
+                                                             "The inverse length parameter for ARD."));
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new CovarianceLinearArd(this, cloner);
+    }
+
+    public int GetNumberOfParameters(int numberOfVariables) {
+      if (HasFixedInverseLengthParameter)
+        return 0;
+      else
+        return numberOfVariables;
+    }
+
+    public void SetParameter(double[] p) {
+      double[] inverseLength;
+      GetParameterValues(p, out inverseLength);
+      InverseLengthParameter.Value = new DoubleArray(inverseLength);
+    }
+
+    private void GetParameterValues(double[] p, out double[] inverseLength) {
+      // gather parameter values
+      if (HasFixedInverseLengthParameter) {
+        inverseLength = InverseLengthParameter.Value.ToArray();
+      } else {
+        inverseLength = p.Select(e => 1.0 / Math.Exp(e)).ToArray();
+      }
+    }
+
+    public ParameterizedCovarianceFunction GetParameterizedCovarianceFunction(double[] p, int[] columnIndices) {
+      double[] inverseLength;
+      GetParameterValues(p, out inverseLength);
+      var fixedInverseLength = HasFixedInverseLengthParameter;
+      // create functions
+      var cov = new ParameterizedCovarianceFunction();
+      cov.Covariance = (x, i, j) => Util.ScalarProd(x, i, j, inverseLength, columnIndices);
+      cov.CrossCovariance = (x, xt, i, j) => Util.ScalarProd(x, i, xt, j, inverseLength, columnIndices);
+      if (fixedInverseLength)
+        cov.CovarianceGradient = (x, i, j) => new double[0];
+      else
+        cov.CovarianceGradient = (x, i, j) => GetGradient(x, i, j, inverseLength, columnIndices);
+      return cov;
+    }
+
+    private static IList<double> GetGradient(double[,] x, int i, int j, double[] inverseLength, int[] columnIndices) {
+      int k = 0;
+      var g = new List<double>(columnIndices.Length);
+      for (int c = 0; c < columnIndices.Length; c++) {
+        var columnIndex = columnIndices[c];
+        g.Add(-2.0 * x[i, columnIndex] * x[j, columnIndex] * inverseLength[k] * inverseLength[k]);
+        k++;
+      }
+      return g;
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/CovarianceFunctions/CovarianceMask.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/CovarianceFunctions/CovarianceMask.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/CovarianceFunctions/CovarianceMask.cs	(revision 13819)
@@ -0,0 +1,79 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  [StorableClass]
+  [Item(Name = "CovarianceMask",
+    Description = "Masking covariance function for dimension selection can be used to apply a covariance function only on certain input dimensions.")]
+  public sealed class CovarianceMask : ParameterizedNamedItem, ICovarianceFunction {
+    public IValueParameter<IntArray> SelectedDimensionsParameter {
+      get { return (IValueParameter<IntArray>)Parameters["SelectedDimensions"]; }
+    }
+    public IValueParameter<ICovarianceFunction> CovarianceFunctionParameter {
+      get { return (IValueParameter<ICovarianceFunction>)Parameters["CovarianceFunction"]; }
+    }
+
+    [StorableConstructor]
+    private CovarianceMask(bool deserializing)
+      : base(deserializing) {
+    }
+
+    private CovarianceMask(CovarianceMask original, Cloner cloner)
+      : base(original, cloner) {
+    }
+
+    public CovarianceMask()
+      : base() {
+      Name = ItemName;
+      Description = ItemDescription;
+
+      Parameters.Add(new OptionalValueParameter<IntArray>("SelectedDimensions", "The dimensions on which the specified covariance function should be applied to."));
+      Parameters.Add(new ValueParameter<ICovarianceFunction>("CovarianceFunction", "The covariance function that should be scaled.", new CovarianceSquaredExponentialIso()));
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new CovarianceMask(this, cloner);
+    }
+
+    public int GetNumberOfParameters(int numberOfVariables) {
+      if (SelectedDimensionsParameter.Value == null) return CovarianceFunctionParameter.Value.GetNumberOfParameters(numberOfVariables);
+      else return CovarianceFunctionParameter.Value.GetNumberOfParameters(SelectedDimensionsParameter.Value.Length);
+    }
+
+    public void SetParameter(double[] p) {
+      CovarianceFunctionParameter.Value.SetParameter(p);
+    }
+
+    public ParameterizedCovarianceFunction GetParameterizedCovarianceFunction(double[] p, int[] columnIndices) {
+      var cov = CovarianceFunctionParameter.Value;
+      var selectedDimensions = SelectedDimensionsParameter.Value;
+
+      return cov.GetParameterizedCovarianceFunction(p, selectedDimensions.Intersect(columnIndices).ToArray());
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/CovarianceFunctions/CovarianceMaternIso.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/CovarianceFunctions/CovarianceMaternIso.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/CovarianceFunctions/CovarianceMaternIso.cs	(revision 13819)
@@ -0,0 +1,169 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  [StorableClass]
+  [Item(Name = "CovarianceMaternIso",
+    Description = "Matern covariance function for Gaussian processes.")]
+  public sealed class CovarianceMaternIso : ParameterizedNamedItem, ICovarianceFunction {
+    public IValueParameter<DoubleValue> InverseLengthParameter {
+      get { return (IValueParameter<DoubleValue>)Parameters["InverseLength"]; }
+    }
+
+    public IValueParameter<DoubleValue> ScaleParameter {
+      get { return (IValueParameter<DoubleValue>)Parameters["Scale"]; }
+    }
+
+    public IConstrainedValueParameter<IntValue> DParameter {
+      get { return (IConstrainedValueParameter<IntValue>)Parameters["D"]; }
+    }
+    private bool HasFixedScaleParameter {
+      get { return ScaleParameter.Value != null; }
+    }
+    private bool HasFixedInverseLengthParameter {
+      get { return InverseLengthParameter.Value != null; }
+    }
+
+    [StorableConstructor]
+    private CovarianceMaternIso(bool deserializing)
+      : base(deserializing) {
+    }
+
+    private CovarianceMaternIso(CovarianceMaternIso original, Cloner cloner)
+      : base(original, cloner) {
+    }
+
+    public CovarianceMaternIso()
+      : base() {
+      Name = ItemName;
+      Description = ItemDescription;
+
+      Parameters.Add(new OptionalValueParameter<DoubleValue>("InverseLength", "The inverse length parameter of the isometric Matern covariance function."));
+      Parameters.Add(new OptionalValueParameter<DoubleValue>("Scale", "The scale parameter of the isometric Matern covariance function."));
+      var validDValues = new ItemSet<IntValue>();
+      validDValues.Add((IntValue)new IntValue(1).AsReadOnly());
+      validDValues.Add((IntValue)new IntValue(3).AsReadOnly());
+      validDValues.Add((IntValue)new IntValue(5).AsReadOnly());
+      Parameters.Add(new ConstrainedValueParameter<IntValue>("D", "The d parameter (allowed values: 1, 3, or 5) of the isometric Matern covariance function.", validDValues, validDValues.First()));
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new CovarianceMaternIso(this, cloner);
+    }
+
+    public int GetNumberOfParameters(int numberOfVariables) {
+      return
+        (HasFixedInverseLengthParameter ? 0 : 1) +
+        (HasFixedScaleParameter ? 0 : 1);
+    }
+
+    public void SetParameter(double[] p) {
+      double inverseLength, scale;
+      GetParameterValues(p, out scale, out inverseLength);
+      InverseLengthParameter.Value = new DoubleValue(inverseLength);
+      ScaleParameter.Value = new DoubleValue(scale);
+    }
+
+    private void GetParameterValues(double[] p, out double scale, out double inverseLength) {
+      // gather parameter values
+      int c = 0;
+      if (HasFixedInverseLengthParameter) {
+        inverseLength = InverseLengthParameter.Value.Value;
+      } else {
+        inverseLength = 1.0 / Math.Exp(p[c]);
+        c++;
+      }
+
+      if (HasFixedScaleParameter) {
+        scale = ScaleParameter.Value.Value;
+      } else {
+        scale = Math.Exp(2 * p[c]);
+        c++;
+      }
+      if (p.Length != c) throw new ArgumentException("The length of the parameter vector does not match the number of free parameters for CovarianceMaternIso", "p");
+    }
+
+    public ParameterizedCovarianceFunction GetParameterizedCovarianceFunction(double[] p, int[] columnIndices) {
+      double inverseLength, scale;
+      int d = DParameter.Value.Value;
+      GetParameterValues(p, out scale, out inverseLength);
+      var fixedInverseLength = HasFixedInverseLengthParameter;
+      var fixedScale = HasFixedScaleParameter;
+      // create functions
+      var cov = new ParameterizedCovarianceFunction();
+      cov.Covariance = (x, i, j) => {
+        double dist = i == j
+                       ? 0.0
+                       : Math.Sqrt(Util.SqrDist(x, i, j, columnIndices, Math.Sqrt(d) * inverseLength));
+        return scale * m(d, dist);
+      };
+      cov.CrossCovariance = (x, xt, i, j) => {
+        double dist = Math.Sqrt(Util.SqrDist(x, i, xt, j, columnIndices, Math.Sqrt(d) * inverseLength));
+        return scale * m(d, dist);
+      };
+      cov.CovarianceGradient = (x, i, j) => GetGradient(x, i, j, d, scale, inverseLength, columnIndices, fixedInverseLength, fixedScale);
+      return cov;
+    }
+
+    private static double m(int d, double t) {
+      double f;
+      switch (d) {
+        case 1: { f = 1; break; }
+        case 3: { f = 1 + t; break; }
+        case 5: { f = 1 + t * (1 + t / 3.0); break; }
+        default: throw new InvalidOperationException();
+      }
+      return f * Math.Exp(-t);
+    }
+
+    private static double dm(int d, double t) {
+      double df;
+      switch (d) {
+        case 1: { df = 1; break; }
+        case 3: { df = t; break; }
+        case 5: { df = t * (1 + t) / 3.0; break; }
+        default: throw new InvalidOperationException();
+      }
+      return df * t * Math.Exp(-t);
+    }
+
+    private static IList<double> GetGradient(double[,] x, int i, int j, int d, double scale, double inverseLength, int[] columnIndices,
+      bool fixedInverseLength, bool fixedScale) {
+      double dist = i == j
+                   ? 0.0
+                   : Math.Sqrt(Util.SqrDist(x, i, j, columnIndices, Math.Sqrt(d) * inverseLength));
+
+      var g = new List<double>(2);
+      if (!fixedInverseLength) g.Add(scale * dm(d, dist));
+      if (!fixedScale) g.Add(2 * scale * m(d, dist));
+      return g;
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/CovarianceFunctions/CovarianceNeuralNetwork.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/CovarianceFunctions/CovarianceNeuralNetwork.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/CovarianceFunctions/CovarianceNeuralNetwork.cs	(revision 13819)
@@ -0,0 +1,162 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  [StorableClass]
+  [Item(Name = "CovarianceNeuralNetwork",
+    Description = "Neural network covariance function for Gaussian processes.")]
+  public sealed class CovarianceNeuralNetwork : ParameterizedNamedItem, ICovarianceFunction {
+    public IValueParameter<DoubleValue> ScaleParameter {
+      get { return (IValueParameter<DoubleValue>)Parameters["Scale"]; }
+    }
+
+    public IValueParameter<DoubleValue> LengthParameter {
+      get { return (IValueParameter<DoubleValue>)Parameters["Length"]; }
+    }
+    private bool HasFixedScaleParameter {
+      get { return ScaleParameter.Value != null; }
+    }
+    private bool HasFixedLengthParameter {
+      get { return LengthParameter.Value != null; }
+    }
+
+    [StorableConstructor]
+    private CovarianceNeuralNetwork(bool deserializing)
+      : base(deserializing) {
+    }
+
+    private CovarianceNeuralNetwork(CovarianceNeuralNetwork original, Cloner cloner)
+      : base(original, cloner) {
+    }
+
+    public CovarianceNeuralNetwork()
+      : base() {
+      Name = ItemName;
+      Description = ItemDescription;
+
+      Parameters.Add(new OptionalValueParameter<DoubleValue>("Scale", "The scale parameter."));
+      Parameters.Add(new OptionalValueParameter<DoubleValue>("Length", "The length parameter."));
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new CovarianceNeuralNetwork(this, cloner);
+    }
+
+    public int GetNumberOfParameters(int numberOfVariables) {
+      return
+        (HasFixedScaleParameter ? 0 : 1) +
+        (HasFixedLengthParameter ? 0 : 1);
+    }
+
+    public void SetParameter(double[] p) {
+      double scale, length;
+      GetParameterValues(p, out scale, out length);
+      ScaleParameter.Value = new DoubleValue(scale);
+      LengthParameter.Value = new DoubleValue(length);
+    }
+
+
+    private void GetParameterValues(double[] p, out double scale, out double length) {
+      // gather parameter values
+      int c = 0;
+      if (HasFixedLengthParameter) {
+        length = LengthParameter.Value.Value;
+      } else {
+        length = Math.Exp(2 * p[c]);
+        c++;
+      }
+
+      if (HasFixedScaleParameter) {
+        scale = ScaleParameter.Value.Value;
+      } else {
+        scale = Math.Exp(2 * p[c]);
+        c++;
+      }
+      if (p.Length != c) throw new ArgumentException("The length of the parameter vector does not match the number of free parameters for CovarianceNeuralNetwork", "p");
+    }
+
+    public ParameterizedCovarianceFunction GetParameterizedCovarianceFunction(double[] p, int[] columnIndices) {
+      double length, scale;
+      GetParameterValues(p, out scale, out length);
+      var fixedLength = HasFixedLengthParameter;
+      var fixedScale = HasFixedScaleParameter;
+
+      var cov = new ParameterizedCovarianceFunction();
+      cov.Covariance = (x, i, j) => {
+        double sx = 1.0;
+        double s1 = 1.0;
+        double s2 = 1.0;
+        for (int c = 0; c < columnIndices.Length; c++) {
+          var col = columnIndices[c];
+          sx += x[i, col] * x[j, col];
+          s1 += x[i, col] * x[i, col];
+          s2 += x[j, col] * x[j, col];
+        }
+
+        return (scale * Math.Asin(sx / (Math.Sqrt((length + s1) * (length + s2)))));
+      };
+      cov.CrossCovariance = (x, xt, i, j) => {
+        double sx = 1.0;
+        double s1 = 1.0;
+        double s2 = 1.0;
+        for (int c = 0; c < columnIndices.Length; c++) {
+          var col = columnIndices[c];
+          sx += x[i, col] * xt[j, col];
+          s1 += x[i, col] * x[i, col];
+          s2 += xt[j, col] * xt[j, col];
+        }
+
+        return (scale * Math.Asin(sx / (Math.Sqrt((length + s1) * (length + s2)))));
+      };
+      cov.CovarianceGradient = (x, i, j) => GetGradient(x, i, j, length, scale, columnIndices, fixedLength, fixedScale);
+      return cov;
+    }
+
+    // order of returned gradients must match the order in GetParameterValues!
+    private static IList<double> GetGradient(double[,] x, int i, int j, double length, double scale, int[] columnIndices,
+      bool fixedLength, bool fixedScale) {
+      double sx = 1.0;
+      double s1 = 1.0;
+      double s2 = 1.0;
+      for (int c = 0; c < columnIndices.Length; c++) {
+        var col = columnIndices[c];
+        sx += x[i, col] * x[j, col];
+        s1 += x[i, col] * x[i, col];
+        s2 += x[j, col] * x[j, col];
+      }
+      var h = (length + s1) * (length + s2);
+      var f = sx / Math.Sqrt(h);
+
+      var g = new List<double>(2);
+      if (!fixedLength) g.Add(-scale / Math.Sqrt(1.0 - f * f) * ((length * sx * (2.0 * length + s1 + s2)) / Math.Pow(h, 3.0 / 2.0)));
+      if (!fixedScale) g.Add(2.0 * scale * Math.Asin(f));
+      return g;
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/CovarianceFunctions/CovarianceNoise.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/CovarianceFunctions/CovarianceNoise.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/CovarianceFunctions/CovarianceNoise.cs	(revision 13819)
@@ -0,0 +1,99 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  [StorableClass]
+  [Item(Name = "CovarianceNoise",
+    Description = "Noise covariance function for Gaussian processes.")]
+  public sealed class CovarianceNoise : ParameterizedNamedItem, ICovarianceFunction {
+    public IValueParameter<DoubleValue> ScaleParameter {
+      get { return (IValueParameter<DoubleValue>)Parameters["Scale"]; }
+    }
+    private bool HasFixedScaleParameter {
+      get { return ScaleParameter.Value != null; }
+    }
+
+    [StorableConstructor]
+    private CovarianceNoise(bool deserializing)
+      : base(deserializing) {
+    }
+
+    private CovarianceNoise(CovarianceNoise original, Cloner cloner)
+      : base(original, cloner) {
+    }
+
+    public CovarianceNoise()
+      : base() {
+      Name = ItemName;
+      Description = ItemDescription;
+
+      Parameters.Add(new OptionalValueParameter<DoubleValue>("Scale", "The scale of noise."));
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new CovarianceNoise(this, cloner);
+    }
+
+    public int GetNumberOfParameters(int numberOfVariables) {
+      return HasFixedScaleParameter ? 0 : 1;
+    }
+
+    public void SetParameter(double[] p) {
+      double scale;
+      GetParameterValues(p, out scale);
+      ScaleParameter.Value = new DoubleValue(scale);
+    }
+
+    private void GetParameterValues(double[] p, out double scale) {
+      int c = 0;
+      // gather parameter values
+      if (HasFixedScaleParameter) {
+        scale = ScaleParameter.Value.Value;
+      } else {
+        scale = Math.Exp(2 * p[c]);
+        c++;
+      }
+      if (p.Length != c) throw new ArgumentException("The length of the parameter vector does not match the number of free parameters for CovarianceNoise", "p");
+    }
+
+    public ParameterizedCovarianceFunction GetParameterizedCovarianceFunction(double[] p, int[] columnIndices) {
+      double scale;
+      GetParameterValues(p, out scale);
+      var fixedScale = HasFixedScaleParameter;
+      // create functions
+      var cov = new ParameterizedCovarianceFunction();
+      cov.Covariance = (x, i, j) => i == j ? scale : 0.0;
+      cov.CrossCovariance = (x, xt, i, j) => Util.SqrDist(x, i, xt, j, columnIndices, 1.0) < 1e-9 ? scale : 0.0;
+      if (fixedScale)
+        cov.CovarianceGradient = (x, i, j) => new double[0];
+      else
+        cov.CovarianceGradient = (x, i, j) => new double[1] { i == j ? 2.0 * scale : 0.0 };
+      return cov;
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/CovarianceFunctions/CovariancePeriodic.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/CovarianceFunctions/CovariancePeriodic.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/CovarianceFunctions/CovariancePeriodic.cs	(revision 13819)
@@ -0,0 +1,167 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  [StorableClass]
+  [Item(Name = "CovariancePeriodic", Description = "Periodic covariance function for Gaussian processes.")]
+  public sealed class CovariancePeriodic : ParameterizedNamedItem, ICovarianceFunction {
+
+    public IValueParameter<DoubleValue> ScaleParameter {
+      get { return (IValueParameter<DoubleValue>)Parameters["Scale"]; }
+    }
+
+    public IValueParameter<DoubleValue> InverseLengthParameter {
+      get { return (IValueParameter<DoubleValue>)Parameters["InverseLength"]; }
+    }
+
+    public IValueParameter<DoubleValue> PeriodParameter {
+      get { return (IValueParameter<DoubleValue>)Parameters["Period"]; }
+    }
+
+    private bool HasFixedScaleParameter {
+      get { return ScaleParameter.Value != null; }
+    }
+    private bool HasFixedInverseLengthParameter {
+      get { return InverseLengthParameter.Value != null; }
+    }
+    private bool HasFixedPeriodParameter {
+      get { return PeriodParameter.Value != null; }
+    }
+
+
+    [StorableConstructor]
+    private CovariancePeriodic(bool deserializing) : base(deserializing) { }
+    private CovariancePeriodic(CovariancePeriodic original, Cloner cloner)
+      : base(original, cloner) {
+    }
+
+    public CovariancePeriodic()
+      : base() {
+      Name = ItemName;
+      Description = ItemDescription;
+
+      Parameters.Add(new OptionalValueParameter<DoubleValue>("Scale", "The scale of the periodic covariance function."));
+      Parameters.Add(new OptionalValueParameter<DoubleValue>("InverseLength", "The inverse length parameter for the periodic covariance function."));
+      Parameters.Add(new OptionalValueParameter<DoubleValue>("Period", "The period parameter for the periodic covariance function."));
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new CovariancePeriodic(this, cloner);
+    }
+
+    public int GetNumberOfParameters(int numberOfVariables) {
+      return (HasFixedScaleParameter ? 0 : 1) +
+       (HasFixedPeriodParameter ? 0 : 1) +
+       (HasFixedInverseLengthParameter ? 0 : 1);
+    }
+
+    public void SetParameter(double[] p) {
+      double scale, inverseLength, period;
+      GetParameterValues(p, out scale, out period, out inverseLength);
+      ScaleParameter.Value = new DoubleValue(scale);
+      PeriodParameter.Value = new DoubleValue(period);
+      InverseLengthParameter.Value = new DoubleValue(inverseLength);
+    }
+
+
+    private void GetParameterValues(double[]
+      p, out double scale, out double period, out double inverseLength) {
+      // gather parameter values
+      int c = 0;
+      if (HasFixedInverseLengthParameter) {
+        inverseLength = InverseLengthParameter.Value.Value;
+      } else {
+        inverseLength = 1.0 / Math.Exp(p[c]);
+        c++;
+      }
+      if (HasFixedPeriodParameter) {
+        period = PeriodParameter.Value.Value;
+      } else {
+        period = Math.Exp(p[c]);
+        c++;
+      }
+      if (HasFixedScaleParameter) {
+        scale = ScaleParameter.Value.Value;
+      } else {
+        scale = Math.Exp(2 * p[c]);
+        c++;
+      }
+      if (p.Length != c) throw new ArgumentException("The length of the parameter vector does not match the number of free parameters for CovariancePeriodic", "p");
+    }
+
+    public ParameterizedCovarianceFunction GetParameterizedCovarianceFunction(double[] p, int[] columnIndices) {
+      double inverseLength, period, scale;
+      GetParameterValues(p, out scale, out period, out inverseLength);
+      var fixedInverseLength = HasFixedInverseLengthParameter;
+      var fixedPeriod = HasFixedPeriodParameter;
+      var fixedScale = HasFixedScaleParameter;
+      // create functions
+      var cov = new ParameterizedCovarianceFunction();
+      cov.Covariance = (x, i, j) => {
+        double k = i == j ? 0.0 : GetDistance(x, x, i, j, columnIndices);
+        k = Math.PI * k / period;
+        k = Math.Sin(k) * inverseLength;
+        k = k * k;
+
+        return scale * Math.Exp(-2.0 * k);
+      };
+      cov.CrossCovariance = (x, xt, i, j) => {
+        double k = GetDistance(x, xt, i, j, columnIndices);
+        k = Math.PI * k / period;
+        k = Math.Sin(k) * inverseLength;
+        k = k * k;
+
+        return scale * Math.Exp(-2.0 * k);
+      };
+      cov.CovarianceGradient = (x, i, j) => GetGradient(x, i, j, columnIndices, scale, period, inverseLength, fixedInverseLength, fixedPeriod, fixedScale);
+      return cov;
+    }
+
+    private static IList<double> GetGradient(double[,] x, int i, int j, int[] columnIndices, double scale, double period, double inverseLength,
+      bool fixedInverseLength, bool fixedPeriod, bool fixedScale) {
+      double k = i == j ? 0.0 : Math.PI * GetDistance(x, x, i, j, columnIndices) / period;
+      double gradient = Math.Sin(k) * inverseLength;
+      gradient *= gradient;
+      var g = new List<double>(3);
+      if (!fixedInverseLength) 
+        g.Add(4.0 * scale * Math.Exp(-2.0 * gradient) * gradient);
+      if (!fixedPeriod) {
+        double r = Math.Sin(k) * inverseLength;
+        g.Add(2.0 * k * scale * Math.Exp(-2 * r * r) * Math.Sin(2 * k) * inverseLength * inverseLength);
+      }
+      if (!fixedScale)
+        g.Add(2.0 * scale * Math.Exp(-2 * gradient));
+      return g;
+    }
+
+    private static double GetDistance(double[,] x, double[,] xt, int i, int j, int[] columnIndices) {
+      return Math.Sqrt(Util.SqrDist(x, i, xt, j, columnIndices, 1));
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/CovarianceFunctions/CovariancePiecewisePolynomial.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/CovarianceFunctions/CovariancePiecewisePolynomial.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/CovarianceFunctions/CovariancePiecewisePolynomial.cs	(revision 13819)
@@ -0,0 +1,170 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  [StorableClass]
+  [Item(Name = "CovariancePiecewisePolynomial",
+    Description = "Piecewise polynomial covariance function with compact support for Gaussian processes.")]
+  public sealed class CovariancePiecewisePolynomial : ParameterizedNamedItem, ICovarianceFunction {
+    public IValueParameter<DoubleValue> LengthParameter {
+      get { return (IValueParameter<DoubleValue>)Parameters["Length"]; }
+    }
+
+    public IValueParameter<DoubleValue> ScaleParameter {
+      get { return (IValueParameter<DoubleValue>)Parameters["Scale"]; }
+    }
+
+    public IConstrainedValueParameter<IntValue> VParameter {
+      get { return (IConstrainedValueParameter<IntValue>)Parameters["V"]; }
+    }
+    private bool HasFixedLengthParameter {
+      get { return LengthParameter.Value != null; }
+    }
+    private bool HasFixedScaleParameter {
+      get { return ScaleParameter.Value != null; }
+    }
+
+    [StorableConstructor]
+    private CovariancePiecewisePolynomial(bool deserializing)
+      : base(deserializing) {
+    }
+
+    private CovariancePiecewisePolynomial(CovariancePiecewisePolynomial original, Cloner cloner)
+      : base(original, cloner) {
+    }
+
+    public CovariancePiecewisePolynomial()
+      : base() {
+      Name = ItemName;
+      Description = ItemDescription;
+
+      Parameters.Add(new OptionalValueParameter<DoubleValue>("Length", "The length parameter of the isometric piecewise polynomial covariance function."));
+      Parameters.Add(new OptionalValueParameter<DoubleValue>("Scale", "The scale parameter of the piecewise polynomial covariance function."));
+
+      var validValues = new ItemSet<IntValue>(new IntValue[] {
+        (IntValue)(new IntValue().AsReadOnly()),
+        (IntValue)(new IntValue(1).AsReadOnly()),
+        (IntValue)(new IntValue(2).AsReadOnly()),
+        (IntValue)(new IntValue(3).AsReadOnly()) });
+      Parameters.Add(new ConstrainedValueParameter<IntValue>("V", "The v parameter of the piecewise polynomial function (allowed values 0, 1, 2, 3).", validValues, validValues.First()));
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new CovariancePiecewisePolynomial(this, cloner);
+    }
+
+    public int GetNumberOfParameters(int numberOfVariables) {
+      return
+        (HasFixedLengthParameter ? 0 : 1) +
+        (HasFixedScaleParameter ? 0 : 1);
+    }
+
+    public void SetParameter(double[] p) {
+      double @const, scale;
+      GetParameterValues(p, out @const, out scale);
+      LengthParameter.Value = new DoubleValue(@const);
+      ScaleParameter.Value = new DoubleValue(scale);
+    }
+
+    private void GetParameterValues(double[] p, out double length, out double scale) {
+      // gather parameter values
+      int n = 0;
+      if (HasFixedLengthParameter) {
+        length = LengthParameter.Value.Value;
+      } else {
+        length = Math.Exp(p[n]);
+        n++;
+      }
+
+      if (HasFixedScaleParameter) {
+        scale = ScaleParameter.Value.Value;
+      } else {
+        scale = Math.Exp(2 * p[n]);
+        n++;
+      }
+      if (p.Length != n) throw new ArgumentException("The length of the parameter vector does not match the number of free parameters for CovariancePiecewisePolynomial", "p");
+    }
+
+    public ParameterizedCovarianceFunction GetParameterizedCovarianceFunction(double[] p, int[] columnIndices) {
+      double length, scale;
+      int v = VParameter.Value.Value;
+      GetParameterValues(p, out length, out scale);
+      var fixedLength = HasFixedLengthParameter;
+      var fixedScale = HasFixedScaleParameter;
+      int exp = (int)Math.Floor(columnIndices.Count() / 2.0) + v + 1;
+
+      Func<double, double> f;
+      Func<double, double> df;
+      switch (v) {
+        case 0:
+          f = (r) => 1.0;
+          df = (r) => 0.0;
+          break;
+        case 1:
+          f = (r) => 1 + (exp + 1) * r;
+          df = (r) => exp + 1;
+          break;
+        case 2:
+          f = (r) => 1 + (exp + 2) * r + (exp * exp + 4.0 * exp + 3) / 3.0 * r * r;
+          df = (r) => (exp + 2) + 2 * (exp * exp + 4.0 * exp + 3) / 3.0 * r;
+          break;
+        case 3:
+          f = (r) => 1 + (exp + 3) * r + (6.0 * exp * exp + 36 * exp + 45) / 15.0 * r * r +
+                     (exp * exp * exp + 9 * exp * exp + 23 * exp + 45) / 15.0 * r * r * r;
+          df = (r) => (exp + 3) + 2 * (6.0 * exp * exp + 36 * exp + 45) / 15.0 * r +
+                      (exp * exp * exp + 9 * exp * exp + 23 * exp + 45) / 5.0 * r * r;
+          break;
+        default: throw new ArgumentException();
+      }
+
+      // create functions
+      var cov = new ParameterizedCovarianceFunction();
+      cov.Covariance = (x, i, j) => {
+        double k = Math.Sqrt(Util.SqrDist(x, i, x, j, columnIndices, 1.0 / length));
+        return scale * Math.Pow(Math.Max(1 - k, 0), exp + v) * f(k);
+      };
+      cov.CrossCovariance = (x, xt, i, j) => {
+        double k = Math.Sqrt(Util.SqrDist(x, i, xt, j, columnIndices, 1.0 / length));
+        return scale * Math.Pow(Math.Max(1 - k, 0), exp + v) * f(k);
+      };
+      cov.CovarianceGradient = (x, i, j) => GetGradient(x, i, j, length, scale, v, exp, f, df, columnIndices, fixedLength, fixedScale);
+      return cov;
+    }
+
+    private static IList<double> GetGradient(double[,] x, int i, int j, double length, double scale, int v, double exp, Func<double, double> f, Func<double, double> df, int[] columnIndices,
+      bool fixedLength, bool fixedScale) {
+      double k = Math.Sqrt(Util.SqrDist(x, i, x, j, columnIndices, 1.0 / length));
+      var g = new List<double>(2);
+      if (!fixedLength) g.Add(scale * Math.Pow(Math.Max(1.0 - k, 0), exp + v - 1) * k * ((exp + v) * f(k) - Math.Max(1 - k, 0) * df(k)));
+      if (!fixedScale) g.Add(2.0 * scale * Math.Pow(Math.Max(1 - k, 0), exp + v) * f(k));
+      return g;
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/CovarianceFunctions/CovariancePolynomial.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/CovarianceFunctions/CovariancePolynomial.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/CovarianceFunctions/CovariancePolynomial.cs	(revision 13819)
@@ -0,0 +1,132 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  [StorableClass]
+  [Item(Name = "CovariancePolynomial",
+    Description = "Polynomial covariance function for Gaussian processes.")]
+  public sealed class CovariancePolynomial : ParameterizedNamedItem, ICovarianceFunction {
+    public IValueParameter<DoubleValue> ConstParameter {
+      get { return (IValueParameter<DoubleValue>)Parameters["Const"]; }
+    }
+
+    public IValueParameter<DoubleValue> ScaleParameter {
+      get { return (IValueParameter<DoubleValue>)Parameters["Scale"]; }
+    }
+
+    public IValueParameter<IntValue> DegreeParameter {
+      get { return (IValueParameter<IntValue>)Parameters["Degree"]; }
+    }
+    private bool HasFixedConstParameter {
+      get { return ConstParameter.Value != null; }
+    }
+    private bool HasFixedScaleParameter {
+      get { return ScaleParameter.Value != null; }
+    }
+
+    [StorableConstructor]
+    private CovariancePolynomial(bool deserializing)
+      : base(deserializing) {
+    }
+
+    private CovariancePolynomial(CovariancePolynomial original, Cloner cloner)
+      : base(original, cloner) {
+    }
+
+    public CovariancePolynomial()
+      : base() {
+      Name = ItemName;
+      Description = ItemDescription;
+
+      Parameters.Add(new OptionalValueParameter<DoubleValue>("Const", "Additive constant in the polymomial."));
+      Parameters.Add(new OptionalValueParameter<DoubleValue>("Scale", "The scale parameter of the polynomial covariance function."));
+      Parameters.Add(new ValueParameter<IntValue>("Degree", "The degree of the polynomial (only non-zero positive values allowed).", new IntValue(2)));
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new CovariancePolynomial(this, cloner);
+    }
+
+    public int GetNumberOfParameters(int numberOfVariables) {
+      return
+        (HasFixedConstParameter ? 0 : 1) +
+        (HasFixedScaleParameter ? 0 : 1);
+    }
+
+    public void SetParameter(double[] p) {
+      double @const, scale;
+      GetParameterValues(p, out @const, out scale);
+      ConstParameter.Value = new DoubleValue(@const);
+      ScaleParameter.Value = new DoubleValue(scale);
+    }
+
+    private void GetParameterValues(double[] p, out double @const, out double scale) {
+      // gather parameter values
+      int n = 0;
+      if (HasFixedConstParameter) {
+        @const = ConstParameter.Value.Value;
+      } else {
+        @const = Math.Exp(p[n]);
+        n++;
+      }
+
+      if (HasFixedScaleParameter) {
+        scale = ScaleParameter.Value.Value;
+      } else {
+        scale = Math.Exp(2 * p[n]);
+        n++;
+      }
+      if (p.Length != n) throw new ArgumentException("The length of the parameter vector does not match the number of free parameters for CovariancePolynomial", "p");
+    }
+
+    public ParameterizedCovarianceFunction GetParameterizedCovarianceFunction(double[] p, int[] columnIndices) {
+      double @const, scale;
+      int degree = DegreeParameter.Value.Value;
+      if (degree <= 0) throw new ArgumentException("The degree parameter for CovariancePolynomial must be greater than zero.");
+      GetParameterValues(p, out @const, out scale);
+      var fixedConst = HasFixedConstParameter;
+      var fixedScale = HasFixedScaleParameter;
+      // create functions
+      var cov = new ParameterizedCovarianceFunction();
+      cov.Covariance = (x, i, j) => scale * Math.Pow(@const + Util.ScalarProd(x, i, j, columnIndices, 1.0), degree);
+      cov.CrossCovariance = (x, xt, i, j) => scale * Math.Pow(@const + Util.ScalarProd(x, i, xt, j, columnIndices, 1.0), degree);
+      cov.CovarianceGradient = (x, i, j) => GetGradient(x, i, j, @const, scale, degree, columnIndices, fixedConst, fixedScale);
+      return cov;
+    }
+
+    private static IList<double> GetGradient(double[,] x, int i, int j, double c, double scale, int degree, int[] columnIndices,
+      bool fixedConst, bool fixedScale) {
+      double s = Util.ScalarProd(x, i, j, columnIndices, 1.0);
+      var g = new List<double>(2);
+      if (!fixedConst) g.Add(c * degree * scale * Math.Pow(c + s, degree - 1));
+      if (!fixedScale) g.Add(2 * scale * Math.Pow(c + s, degree));
+      return g;
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/CovarianceFunctions/CovarianceProduct.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/CovarianceFunctions/CovarianceProduct.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/CovarianceFunctions/CovarianceProduct.cs	(revision 13819)
@@ -0,0 +1,108 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  [StorableClass]
+  [Item(Name = "CovarianceProduct",
+    Description = "Product covariance function for Gaussian processes.")]
+  public sealed class CovarianceProduct : Item, ICovarianceFunction {
+    [Storable]
+    private ItemList<ICovarianceFunction> factors;
+
+    [Storable]
+    private int numberOfVariables;
+    public ItemList<ICovarianceFunction> Factors {
+      get { return factors; }
+    }
+
+    [StorableConstructor]
+    private CovarianceProduct(bool deserializing)
+      : base(deserializing) {
+    }
+
+    private CovarianceProduct(CovarianceProduct original, Cloner cloner)
+      : base(original, cloner) {
+      this.factors = cloner.Clone(original.factors);
+      this.numberOfVariables = original.numberOfVariables;
+    }
+
+    public CovarianceProduct()
+      : base() {
+      this.factors = new ItemList<ICovarianceFunction>();
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new CovarianceProduct(this, cloner);
+    }
+
+    public int GetNumberOfParameters(int numberOfVariables) {
+      this.numberOfVariables = numberOfVariables;
+      return factors.Select(f => f.GetNumberOfParameters(numberOfVariables)).Sum();
+    }
+
+    public void SetParameter(double[] p) {
+      int offset = 0;
+      foreach (var f in factors) {
+        var numberOfParameters = f.GetNumberOfParameters(numberOfVariables);
+        f.SetParameter(p.Skip(offset).Take(numberOfParameters).ToArray());
+        offset += numberOfParameters;
+      }
+    }
+
+    public ParameterizedCovarianceFunction GetParameterizedCovarianceFunction(double[] p, int[] columnIndices) {
+      if (factors.Count == 0) throw new ArgumentException("at least one factor is necessary for the product covariance function.");
+      var functions = new List<ParameterizedCovarianceFunction>();
+      foreach (var f in factors) {
+        int numberOfParameters = f.GetNumberOfParameters(numberOfVariables);
+        functions.Add(f.GetParameterizedCovarianceFunction(p.Take(numberOfParameters).ToArray(), columnIndices));
+        p = p.Skip(numberOfParameters).ToArray();
+      }
+
+
+      var product = new ParameterizedCovarianceFunction();
+      product.Covariance = (x, i, j) => functions.Select(e => e.Covariance(x, i, j)).Aggregate((a, b) => a * b);
+      product.CrossCovariance = (x, xt, i, j) => functions.Select(e => e.CrossCovariance(x, xt, i, j)).Aggregate((a, b) => a * b);
+      product.CovarianceGradient = (x, i, j) => GetGradient(x, i, j, functions);
+      return product;
+    }
+
+    public static IList<double> GetGradient(double[,] x, int i, int j, List<ParameterizedCovarianceFunction> factorFunctions) {
+      var covariances = factorFunctions.Select(f => f.Covariance(x, i, j)).ToArray();
+      var gr = new List<double>(factorFunctions.Sum(f => f.CovarianceGradient(x, i, j).Count));
+      for (int ii = 0; ii < factorFunctions.Count; ii++) {
+        foreach (var g in factorFunctions[ii].CovarianceGradient(x, i, j)) {
+          double res = g;
+          for (int jj = 0; jj < covariances.Length; jj++)
+            if (ii != jj) res *= covariances[jj];
+          gr.Add(res);
+        }
+      }
+      return gr;
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/CovarianceFunctions/CovarianceRationalQuadraticArd.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/CovarianceFunctions/CovarianceRationalQuadraticArd.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/CovarianceFunctions/CovarianceRationalQuadraticArd.cs	(revision 13819)
@@ -0,0 +1,167 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  [StorableClass]
+  [Item(Name = "CovarianceRationalQuadraticArd",
+    Description = "Rational quadratic covariance function with automatic relevance determination for Gaussian processes.")]
+  public sealed class CovarianceRationalQuadraticArd : ParameterizedNamedItem, ICovarianceFunction {
+    public IValueParameter<DoubleValue> ScaleParameter {
+      get { return (IValueParameter<DoubleValue>)Parameters["Scale"]; }
+    }
+
+    public IValueParameter<DoubleArray> InverseLengthParameter {
+      get { return (IValueParameter<DoubleArray>)Parameters["InverseLength"]; }
+    }
+
+    public IValueParameter<DoubleValue> ShapeParameter {
+      get { return (IValueParameter<DoubleValue>)Parameters["Shape"]; }
+    }
+    private bool HasFixedScaleParameter {
+      get { return ScaleParameter.Value != null; }
+    }
+    private bool HasFixedInverseLengthParameter {
+      get { return InverseLengthParameter.Value != null; }
+    }
+    private bool HasFixedShapeParameter {
+      get { return ShapeParameter.Value != null; }
+    }
+
+    [StorableConstructor]
+    private CovarianceRationalQuadraticArd(bool deserializing)
+      : base(deserializing) {
+    }
+
+    private CovarianceRationalQuadraticArd(CovarianceRationalQuadraticArd original, Cloner cloner)
+      : base(original, cloner) {
+    }
+
+    public CovarianceRationalQuadraticArd()
+      : base() {
+      Name = ItemName;
+      Description = ItemDescription;
+
+      Parameters.Add(new OptionalValueParameter<DoubleValue>("Scale", "The scale parameter of the rational quadratic covariance function with ARD."));
+      Parameters.Add(new OptionalValueParameter<DoubleArray>("InverseLength", "The inverse length parameter for automatic relevance determination."));
+      Parameters.Add(new OptionalValueParameter<DoubleValue>("Shape", "The shape parameter (alpha) of the rational quadratic covariance function with ARD."));
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new CovarianceRationalQuadraticArd(this, cloner);
+    }
+
+    public int GetNumberOfParameters(int numberOfVariables) {
+      return
+        (HasFixedScaleParameter ? 0 : 1) +
+        (HasFixedShapeParameter ? 0 : 1) +
+        (HasFixedInverseLengthParameter ? 0 : numberOfVariables);
+    }
+
+    public void SetParameter(double[] p) {
+      double scale, shape;
+      double[] inverseLength;
+      GetParameterValues(p, out scale, out shape, out inverseLength);
+      ScaleParameter.Value = new DoubleValue(scale);
+      ShapeParameter.Value = new DoubleValue(shape);
+      InverseLengthParameter.Value = new DoubleArray(inverseLength);
+    }
+
+    private void GetParameterValues(double[] p, out double scale, out double shape, out double[] inverseLength) {
+      int c = 0;
+      // gather parameter values
+      if (HasFixedInverseLengthParameter) {
+        inverseLength = InverseLengthParameter.Value.ToArray();
+      } else {
+        int length = p.Length;
+        if (!HasFixedScaleParameter) length--;
+        if (!HasFixedShapeParameter) length--;
+        inverseLength = p.Select(e => 1.0 / Math.Exp(e)).Take(length).ToArray();
+        c += inverseLength.Length;
+      }
+      if (HasFixedScaleParameter) {
+        scale = ScaleParameter.Value.Value;
+      } else {
+        scale = Math.Exp(2 * p[c]);
+        c++;
+      }
+      if (HasFixedShapeParameter) {
+        shape = ShapeParameter.Value.Value;
+      } else {
+        shape = Math.Exp(p[c]);
+        c++;
+      }
+      if (p.Length != c) throw new ArgumentException("The length of the parameter vector does not match the number of free parameters for CovarianceRationalQuadraticArd", "p");
+    }
+
+    public ParameterizedCovarianceFunction GetParameterizedCovarianceFunction(double[] p, int[] columnIndices) {
+      double scale, shape;
+      double[] inverseLength;
+      GetParameterValues(p, out scale, out shape, out inverseLength);
+      var fixedInverseLength = HasFixedInverseLengthParameter;
+      var fixedScale = HasFixedScaleParameter;
+      var fixedShape = HasFixedShapeParameter;
+      // create functions
+      var cov = new ParameterizedCovarianceFunction();
+      cov.Covariance = (x, i, j) => {
+        double d = i == j
+                    ? 0.0
+                    : Util.SqrDist(x, i, j, inverseLength, columnIndices);
+        return scale * Math.Pow(1 + 0.5 * d / shape, -shape);
+      };
+      cov.CrossCovariance = (x, xt, i, j) => {
+        double d = Util.SqrDist(x, i, xt, j, inverseLength, columnIndices);
+        return scale * Math.Pow(1 + 0.5 * d / shape, -shape);
+      };
+      cov.CovarianceGradient = (x, i, j) => GetGradient(x, i, j, columnIndices, scale, shape, inverseLength, fixedInverseLength, fixedScale, fixedShape);
+      return cov;
+    }
+
+    private static IList<double> GetGradient(double[,] x, int i, int j, int[] columnIndices, double scale, double shape, double[] inverseLength,
+      bool fixedInverseLength, bool fixedScale, bool fixedShape) {
+      double d = i == j
+                   ? 0.0
+                   : Util.SqrDist(x, i, j, inverseLength, columnIndices);
+      double b = 1 + 0.5 * d / shape;
+      int k = 0;
+      var g = new List<double>(columnIndices.Length + 2);
+      if (!fixedInverseLength) {
+        foreach (var columnIndex in columnIndices) {
+          g.Add(
+            scale * Math.Pow(b, -shape - 1) *
+            Util.SqrDist(x[i, columnIndex] * inverseLength[k], x[j, columnIndex] * inverseLength[k]));
+          k++;
+        }
+      }
+      if (!fixedScale) g.Add(2 * scale * Math.Pow(b, -shape));
+      if (!fixedShape) g.Add(scale * Math.Pow(b, -shape) * (0.5 * d / b - shape * Math.Log(b)));
+      return g;
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/CovarianceFunctions/CovarianceRationalQuadraticIso.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/CovarianceFunctions/CovarianceRationalQuadraticIso.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/CovarianceFunctions/CovarianceRationalQuadraticIso.cs	(revision 13819)
@@ -0,0 +1,155 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  [StorableClass]
+  [Item(Name = "CovarianceRationalQuadraticIso",
+    Description = "Isotropic rational quadratic covariance function for Gaussian processes.")]
+  public sealed class CovarianceRationalQuadraticIso : ParameterizedNamedItem, ICovarianceFunction {
+    public IValueParameter<DoubleValue> ScaleParameter {
+      get { return (IValueParameter<DoubleValue>)Parameters["Scale"]; }
+    }
+
+    public IValueParameter<DoubleValue> InverseLengthParameter {
+      get { return (IValueParameter<DoubleValue>)Parameters["InverseLength"]; }
+    }
+
+    public IValueParameter<DoubleValue> ShapeParameter {
+      get { return (IValueParameter<DoubleValue>)Parameters["Shape"]; }
+    }
+
+    private bool HasFixedScaleParameter {
+      get { return ScaleParameter.Value != null; }
+    }
+    private bool HasFixedInverseLengthParameter {
+      get { return InverseLengthParameter.Value != null; }
+    }
+    private bool HasFixedShapeParameter {
+      get { return ShapeParameter.Value != null; }
+    }
+
+
+    [StorableConstructor]
+    private CovarianceRationalQuadraticIso(bool deserializing)
+      : base(deserializing) {
+    }
+
+    private CovarianceRationalQuadraticIso(CovarianceRationalQuadraticIso original, Cloner cloner)
+      : base(original, cloner) {
+    }
+
+    public CovarianceRationalQuadraticIso()
+      : base() {
+      Name = ItemName;
+      Description = ItemDescription;
+
+      Parameters.Add(new OptionalValueParameter<DoubleValue>("Scale", "The scale parameter of the isometric rational quadratic covariance function."));
+      Parameters.Add(new OptionalValueParameter<DoubleValue>("InverseLength", "The inverse length parameter of the isometric rational quadratic covariance function."));
+      Parameters.Add(new OptionalValueParameter<DoubleValue>("Shape", "The shape parameter (alpha) of the isometric rational quadratic covariance function."));
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new CovarianceRationalQuadraticIso(this, cloner);
+    }
+
+    public int GetNumberOfParameters(int numberOfVariables) {
+      return (HasFixedScaleParameter ? 0 : 1) +
+        (HasFixedShapeParameter ? 0 : 1) +
+        (HasFixedInverseLengthParameter ? 0 : 1);
+    }
+
+    public void SetParameter(double[] p) {
+      double scale, shape, inverseLength;
+      GetParameterValues(p, out scale, out shape, out inverseLength);
+      ScaleParameter.Value = new DoubleValue(scale);
+      ShapeParameter.Value = new DoubleValue(shape);
+      InverseLengthParameter.Value = new DoubleValue(inverseLength);
+    }
+
+    private void GetParameterValues(double[] p, out double scale, out double shape, out double inverseLength) {
+      int c = 0;
+      // gather parameter values
+      if (HasFixedInverseLengthParameter) {
+        inverseLength = InverseLengthParameter.Value.Value;
+      } else {
+        inverseLength = 1.0 / Math.Exp(p[c]);
+        c++;
+      }
+      if (HasFixedScaleParameter) {
+        scale = ScaleParameter.Value.Value;
+      } else {
+        scale = Math.Exp(2 * p[c]);
+        c++;
+      }
+      if (HasFixedShapeParameter) {
+        shape = ShapeParameter.Value.Value;
+      } else {
+        shape = Math.Exp(p[c]);
+        c++;
+      }
+      if (p.Length != c) throw new ArgumentException("The length of the parameter vector does not match the number of free parameters for CovarianceRationalQuadraticIso", "p");
+    }
+
+    public ParameterizedCovarianceFunction GetParameterizedCovarianceFunction(double[] p, int[] columnIndices) {
+      double scale, shape, inverseLength;
+      GetParameterValues(p, out scale, out shape, out inverseLength);
+      var fixedInverseLength = HasFixedInverseLengthParameter;
+      var fixedScale = HasFixedScaleParameter;
+      var fixedShape = HasFixedShapeParameter;
+      // create functions
+      var cov = new ParameterizedCovarianceFunction();
+      cov.Covariance = (x, i, j) => {
+        double d = i == j
+                    ? 0.0
+                    : Util.SqrDist(x, i, j, columnIndices, inverseLength);
+        return scale * Math.Pow(1 + 0.5 * d / shape, -shape);
+      };
+      cov.CrossCovariance = (x, xt, i, j) => {
+        double d = Util.SqrDist(x, i, xt, j, columnIndices, inverseLength);
+        return scale * Math.Pow(1 + 0.5 * d / shape, -shape);
+      };
+      cov.CovarianceGradient = (x, i, j) => GetGradient(x, i, j, columnIndices, scale, shape, inverseLength, fixedInverseLength, fixedScale, fixedShape);
+      return cov;
+    }
+
+    private static IList<double> GetGradient(double[,] x, int i, int j, int[] columnIndices, double scale, double shape, double inverseLength,
+      bool fixedInverseLength, bool fixedScale, bool fixedShape) {
+      double d = i == j
+                   ? 0.0
+                   : Util.SqrDist(x, i, j, columnIndices, inverseLength);
+
+      double b = 1 + 0.5 * d / shape;
+      var g = new List<double>(3);
+      if (!fixedInverseLength) g.Add(scale * Math.Pow(b, -shape - 1) * d);
+      if (!fixedScale) g.Add(2 * scale * Math.Pow(b, -shape));
+      if (!fixedShape) g.Add(scale * Math.Pow(b, -shape) * (0.5 * d / b - shape * Math.Log(b)));
+      return g;
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/CovarianceFunctions/CovarianceScale.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/CovarianceFunctions/CovarianceScale.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/CovarianceFunctions/CovarianceScale.cs	(revision 13819)
@@ -0,0 +1,113 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  [StorableClass]
+  [Item(Name = "CovarianceScale",
+    Description = "Scale covariance function for Gaussian processes.")]
+  public sealed class CovarianceScale : ParameterizedNamedItem, ICovarianceFunction {
+    public IValueParameter<DoubleValue> ScaleParameter {
+      get { return (IValueParameter<DoubleValue>)Parameters["Scale"]; }
+    }
+    private bool HasFixedScaleParameter {
+      get { return ScaleParameter.Value != null; }
+    }
+
+    public IValueParameter<ICovarianceFunction> CovarianceFunctionParameter {
+      get { return (IValueParameter<ICovarianceFunction>)Parameters["CovarianceFunction"]; }
+    }
+
+    [StorableConstructor]
+    private CovarianceScale(bool deserializing)
+      : base(deserializing) {
+    }
+
+    private CovarianceScale(CovarianceScale original, Cloner cloner)
+      : base(original, cloner) {
+    }
+
+    public CovarianceScale()
+      : base() {
+      Name = ItemName;
+      Description = ItemDescription;
+
+      Parameters.Add(new OptionalValueParameter<DoubleValue>("Scale", "The scale parameter."));
+      Parameters.Add(new ValueParameter<ICovarianceFunction>("CovarianceFunction", "The covariance function that should be scaled.", new CovarianceSquaredExponentialIso()));
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new CovarianceScale(this, cloner);
+    }
+
+    public int GetNumberOfParameters(int numberOfVariables) {
+      return (HasFixedScaleParameter ? 0 : 1) + CovarianceFunctionParameter.Value.GetNumberOfParameters(numberOfVariables);
+    }
+
+    public void SetParameter(double[] p) {
+      double scale;
+      GetParameterValues(p, out scale);
+      ScaleParameter.Value = new DoubleValue(scale);
+      CovarianceFunctionParameter.Value.SetParameter(p.Skip(1).ToArray());
+    }
+
+    private void GetParameterValues(double[] p, out double scale) {
+      // gather parameter values
+      if (HasFixedScaleParameter) {
+        scale = ScaleParameter.Value.Value;
+      } else {
+        scale = Math.Exp(2 * p[0]);
+      }
+    }
+
+    public ParameterizedCovarianceFunction GetParameterizedCovarianceFunction(double[] p, int[] columnIndices) {
+      double scale;
+      GetParameterValues(p, out scale);
+      var fixedScale = HasFixedScaleParameter;
+      var subCov = CovarianceFunctionParameter.Value.GetParameterizedCovarianceFunction(p.Skip(1).ToArray(), columnIndices);
+      // create functions
+      var cov = new ParameterizedCovarianceFunction();
+      cov.Covariance = (x, i, j) => scale * subCov.Covariance(x, i, j);
+      cov.CrossCovariance = (x, xt, i, j) => scale * subCov.CrossCovariance(x, xt, i, j);
+      cov.CovarianceGradient = (x, i, j) => GetGradient(x, i, j, columnIndices, scale, subCov, fixedScale);
+      return cov;
+    }
+
+    private static IList<double> GetGradient(double[,] x, int i, int j, int[] columnIndices, double scale, ParameterizedCovarianceFunction cov,
+      bool fixedScale) {
+      var gr = new List<double>((!fixedScale ? 1 : 0) + cov.CovarianceGradient(x, i, j).Count);
+      if (!fixedScale) {
+        gr.Add(2 * scale * cov.Covariance(x, i, j));
+      }
+      foreach (var g in cov.CovarianceGradient(x, i, j))
+        gr.Add(scale * g);
+      return gr;
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/CovarianceFunctions/CovarianceSpectralMixture.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/CovarianceFunctions/CovarianceSpectralMixture.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/CovarianceFunctions/CovarianceSpectralMixture.cs	(revision 13819)
@@ -0,0 +1,240 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  [StorableClass]
+  [Item(Name = "CovarianceSpectralMixture",
+    Description = "The spectral mixture kernel described in Wilson A. G. and Adams R.P., Gaussian Process Kernels for Pattern Discovery and Exptrapolation, ICML 2013.")]
+  public sealed class CovarianceSpectralMixture : ParameterizedNamedItem, ICovarianceFunction {
+    public const string QParameterName = "Number of components (Q)";
+    public const string WeightParameterName = "Weight";
+    public const string FrequencyParameterName = "Component frequency (mu)";
+    public const string LengthScaleParameterName = "Length scale (nu)";
+    public IValueParameter<IntValue> QParameter {
+      get { return (IValueParameter<IntValue>)Parameters[QParameterName]; }
+    }
+
+    public IValueParameter<DoubleArray> WeightParameter {
+      get { return (IValueParameter<DoubleArray>)Parameters[WeightParameterName]; }
+    }
+    public IValueParameter<DoubleArray> FrequencyParameter {
+      get { return (IValueParameter<DoubleArray>)Parameters[FrequencyParameterName]; }
+    }
+
+    public IValueParameter<DoubleArray> LengthScaleParameter {
+      get { return (IValueParameter<DoubleArray>)Parameters[LengthScaleParameterName]; }
+    }
+
+    private bool HasFixedWeightParameter {
+      get { return WeightParameter.Value != null; }
+    }
+    private bool HasFixedFrequencyParameter {
+      get { return FrequencyParameter.Value != null; }
+    }
+    private bool HasFixedLengthScaleParameter {
+      get { return LengthScaleParameter.Value != null; }
+    }
+
+    [StorableConstructor]
+    private CovarianceSpectralMixture(bool deserializing)
+      : base(deserializing) {
+    }
+
+    private CovarianceSpectralMixture(CovarianceSpectralMixture original, Cloner cloner)
+      : base(original, cloner) {
+    }
+
+    public CovarianceSpectralMixture()
+      : base() {
+      Name = ItemName;
+      Description = ItemDescription;
+      Parameters.Add(new ValueParameter<IntValue>(QParameterName, "The number of Gaussians (Q) to use for the spectral mixture.", new IntValue(10)));
+      Parameters.Add(new OptionalValueParameter<DoubleArray>(WeightParameterName, "The weight of the component w (peak height of the Gaussian in spectrum)."));
+      Parameters.Add(new OptionalValueParameter<DoubleArray>(FrequencyParameterName, "The inverse component period parameter mu_q (location of the Gaussian in spectrum)."));
+      Parameters.Add(new OptionalValueParameter<DoubleArray>(LengthScaleParameterName, "The length scale parameter (nu_q) (variance of the Gaussian in the spectrum)."));
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new CovarianceSpectralMixture(this, cloner);
+    }
+
+    public int GetNumberOfParameters(int numberOfVariables) {
+      var q = QParameter.Value.Value;
+      return
+        (HasFixedWeightParameter ? 0 : q) +
+        (HasFixedFrequencyParameter ? 0 : q * numberOfVariables) +
+        (HasFixedLengthScaleParameter ? 0 : q * numberOfVariables);
+    }
+
+    public void SetParameter(double[] p) {
+      double[] weight, frequency, lengthScale;
+      GetParameterValues(p, out weight, out frequency, out lengthScale);
+      WeightParameter.Value = new DoubleArray(weight);
+      FrequencyParameter.Value = new DoubleArray(frequency);
+      LengthScaleParameter.Value = new DoubleArray(lengthScale);
+    }
+
+
+    private void GetParameterValues(double[] p, out double[] weight, out double[] frequency, out double[] lengthScale) {
+      // gather parameter values
+      int c = 0;
+      int q = QParameter.Value.Value;
+      // guess number of elements for frequency and length (=q * numberOfVariables)
+      int n = WeightParameter.Value == null ? ((p.Length - q) / 2) : (p.Length / 2);
+      if (HasFixedWeightParameter) {
+        weight = WeightParameter.Value.ToArray();
+      } else {
+        weight = p.Skip(c).Select(Math.Exp).Take(q).ToArray();
+        c += q;
+      }
+      if (HasFixedFrequencyParameter) {
+        frequency = FrequencyParameter.Value.ToArray();
+      } else {
+        frequency = p.Skip(c).Select(Math.Exp).Take(n).ToArray();
+        c += n;
+      }
+      if (HasFixedLengthScaleParameter) {
+        lengthScale = LengthScaleParameter.Value.ToArray();
+      } else {
+        lengthScale = p.Skip(c).Select(Math.Exp).Take(n).ToArray();
+        c += n;
+      }
+      if (p.Length != c) throw new ArgumentException("The length of the parameter vector does not match the number of free parameters for CovarianceSpectralMixture", "p");
+    }
+
+    public ParameterizedCovarianceFunction GetParameterizedCovarianceFunction(double[] p, int[] columnIndices) {
+      double[] weight, frequency, lengthScale;
+      GetParameterValues(p, out weight, out frequency, out lengthScale);
+      var fixedWeight = HasFixedWeightParameter;
+      var fixedFrequency = HasFixedFrequencyParameter;
+      var fixedLengthScale = HasFixedLengthScaleParameter;
+      // create functions
+      var cov = new ParameterizedCovarianceFunction();
+      cov.Covariance = (x, i, j) => {
+        return GetCovariance(x, x, i, j, QParameter.Value.Value, weight, frequency,
+                             lengthScale, columnIndices);
+      };
+      cov.CrossCovariance = (x, xt, i, j) => {
+        return GetCovariance(x, xt, i, j, QParameter.Value.Value, weight, frequency,
+                             lengthScale, columnIndices);
+      };
+      cov.CovarianceGradient = (x, i, j) => GetGradient(x, i, j, QParameter.Value.Value, weight, frequency,
+                             lengthScale, columnIndices, fixedWeight, fixedFrequency, fixedLengthScale);
+      return cov;
+    }
+
+    private static double GetCovariance(double[,] x, double[,] xt, int i, int j, int maxQ, double[] weight, double[] frequency, double[] lengthScale, int[] columnIndices) {
+      // tau = x - x' (only for selected variables)
+      double[] tau =
+        Util.GetRow(x, i, columnIndices).Zip(Util.GetRow(xt, j, columnIndices), (xi, xj) => xi - xj).ToArray();
+      int numberOfVariables = lengthScale.Length / maxQ;
+      double k = 0;
+      // for each component
+      for (int q = 0; q < maxQ; q++) {
+        double kc = weight[q]; // weighted kernel component
+
+        int idx = 0; // helper index for tau
+        // for each selected variable
+        for (int c = 0; c < columnIndices.Length; c++) {
+          var col = columnIndices[c];
+          kc *= f1(tau[idx], lengthScale[q * numberOfVariables + col]) * f2(tau[idx], frequency[q * numberOfVariables + col]);
+          idx++;
+        }
+        k += kc;
+      }
+      return k;
+    }
+
+    public static double f1(double tau, double lengthScale) {
+      return Math.Exp(-2 * Math.PI * Math.PI * tau * tau * lengthScale);
+    }
+    public static double f2(double tau, double frequency) {
+      return Math.Cos(2 * Math.PI * tau * frequency);
+    }
+
+    // order of returned gradients must match the order in GetParameterValues!
+    private static IList<double> GetGradient(double[,] x, int i, int j, int maxQ, double[] weight, double[] frequency, double[] lengthScale, int[] columnIndices,
+      bool fixedWeight, bool fixedFrequency, bool fixedLengthScale) {
+      double[] tau = Util.GetRow(x, i, columnIndices).Zip(Util.GetRow(x, j, columnIndices), (xi, xj) => xi - xj).ToArray();
+      int numberOfVariables = lengthScale.Length / maxQ;
+
+      var g = new List<double>((!fixedWeight ? maxQ : 0) + (!fixedFrequency ? maxQ * columnIndices.Length : 0) + (!fixedLengthScale ? maxQ * columnIndices.Length : 0));
+      if (!fixedWeight) {
+        // weight
+        // for each component
+        for (int q = 0; q < maxQ; q++) {
+          double k = weight[q];
+          int idx = 0; // helper index for tau
+          // for each selected variable
+          for (int c = 0; c < columnIndices.Length; c++) {
+            var col = columnIndices[c];
+            k *= f1(tau[idx], lengthScale[q * numberOfVariables + col]) * f2(tau[idx], frequency[q * numberOfVariables + col]);
+            idx++;
+          }
+          g.Add(k);
+        }
+      }
+
+      if (!fixedFrequency) {
+        // frequency
+        // for each component
+        for (int q = 0; q < maxQ; q++) {
+          int idx = 0; // helper index for tau
+          // for each selected variable
+          foreach (var c in columnIndices) {
+            double k = f1(tau[idx], lengthScale[q * numberOfVariables + c]) *
+                       -2 * Math.PI * tau[idx] * frequency[q * numberOfVariables + c] *
+                       Math.Sin(2 * Math.PI * tau[idx] * frequency[q * numberOfVariables + c]);
+            idx++;
+            g.Add(weight[q] * k);
+          }
+        }
+      }
+
+      if (!fixedLengthScale) {
+        // length scale
+        // for each component
+        for (int q = 0; q < maxQ; q++) {
+          int idx = 0; // helper index for tau
+          // for each selected variable
+          foreach (var c in columnIndices) {
+            double k = -2 * Math.PI * Math.PI * tau[idx] * tau[idx] * lengthScale[q * numberOfVariables + c] *
+                       f1(tau[idx], lengthScale[q * numberOfVariables + c]) *
+                       f2(tau[idx], frequency[q * numberOfVariables + c]);
+            idx++;
+            g.Add(weight[q] * k);
+          }
+        }
+      }
+
+      return g;
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/CovarianceFunctions/CovarianceSquaredExponentialArd.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/CovarianceFunctions/CovarianceSquaredExponentialArd.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/CovarianceFunctions/CovarianceSquaredExponentialArd.cs	(revision 13819)
@@ -0,0 +1,144 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  [StorableClass]
+  [Item(Name = "CovarianceSquaredExponentialArd", Description = "Squared exponential covariance function with automatic relevance determination for Gaussian processes.")]
+  public sealed class CovarianceSquaredExponentialArd : ParameterizedNamedItem, ICovarianceFunction {
+    public IValueParameter<DoubleValue> ScaleParameter {
+      get { return (IValueParameter<DoubleValue>)Parameters["Scale"]; }
+    }
+
+    public IValueParameter<DoubleArray> InverseLengthParameter {
+      get { return (IValueParameter<DoubleArray>)Parameters["InverseLength"]; }
+    }
+    private bool HasFixedInverseLengthParameter {
+      get { return InverseLengthParameter.Value != null; }
+    }
+    private bool HasFixedScaleParameter {
+      get { return ScaleParameter.Value != null; }
+    }
+
+    [StorableConstructor]
+    private CovarianceSquaredExponentialArd(bool deserializing) : base(deserializing) { }
+    private CovarianceSquaredExponentialArd(CovarianceSquaredExponentialArd original, Cloner cloner)
+      : base(original, cloner) {
+    }
+    public CovarianceSquaredExponentialArd()
+      : base() {
+      Name = ItemName;
+      Description = ItemDescription;
+
+      Parameters.Add(new OptionalValueParameter<DoubleValue>("Scale", "The scale parameter of the squared exponential covariance function with ARD."));
+      Parameters.Add(new OptionalValueParameter<DoubleArray>("InverseLength", "The inverse length parameter for automatic relevance determination."));
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new CovarianceSquaredExponentialArd(this, cloner);
+    }
+
+    public int GetNumberOfParameters(int numberOfVariables) {
+      return
+        (HasFixedScaleParameter ? 0 : 1) +
+        (HasFixedInverseLengthParameter ? 0 : numberOfVariables);
+    }
+
+    public void SetParameter(double[] p) {
+      double scale;
+      double[] inverseLength;
+      GetParameterValues(p, out scale, out inverseLength);
+      ScaleParameter.Value = new DoubleValue(scale);
+      InverseLengthParameter.Value = new DoubleArray(inverseLength);
+    }
+
+    private void GetParameterValues(double[] p, out double scale, out double[] inverseLength) {
+      int c = 0;
+      // gather parameter values
+      if (HasFixedInverseLengthParameter) {
+        inverseLength = InverseLengthParameter.Value.ToArray();
+      } else {
+        int length = p.Length;
+        if (!HasFixedScaleParameter) length--;
+        inverseLength = p.Select(e => 1.0 / Math.Exp(e)).Take(length).ToArray();
+        c += inverseLength.Length;
+      }
+      if (HasFixedScaleParameter) {
+        scale = ScaleParameter.Value.Value;
+      } else {
+        scale = Math.Exp(2 * p[c]);
+        c++;
+      }
+      if (p.Length != c) throw new ArgumentException("The length of the parameter vector does not match the number of free parameters for CovarianceSquaredExponentialArd", "p");
+    }
+
+    public ParameterizedCovarianceFunction GetParameterizedCovarianceFunction(double[] p, int[] columnIndices) {
+      double scale;
+      double[] inverseLength;
+      GetParameterValues(p, out scale, out inverseLength);
+      var fixedInverseLength = HasFixedInverseLengthParameter;
+      var fixedScale = HasFixedScaleParameter;
+      // create functions
+      var cov = new ParameterizedCovarianceFunction();
+      cov.Covariance = (x, i, j) => {
+        double d = i == j
+                 ? 0.0
+                 : Util.SqrDist(x, i, j, inverseLength, columnIndices);
+        return scale * Math.Exp(-d / 2.0);
+      };
+      cov.CrossCovariance = (x, xt, i, j) => {
+        double d = Util.SqrDist(x, i, xt, j, inverseLength, columnIndices);
+        return scale * Math.Exp(-d / 2.0);
+      };
+      cov.CovarianceGradient = (x, i, j) => GetGradient(x, i, j, columnIndices, scale, inverseLength, fixedInverseLength, fixedScale);
+      return cov;
+    }
+
+    // order of returned gradients must match the order in GetParameterValues!
+    private static IList<double> GetGradient(double[,] x, int i, int j, int[] columnIndices, double scale, double[] inverseLength,
+      bool fixedInverseLength, bool fixedScale) {
+      double d = i == j
+                   ? 0.0
+                   : Util.SqrDist(x, i, j, inverseLength, columnIndices);
+
+      int k = 0;
+      var g = new List<double>((!fixedInverseLength ? columnIndices.Length : 0) + (!fixedScale ? 1 : 0));
+      if (!fixedInverseLength) {
+        for (int c = 0; c < columnIndices.Length; c++) {
+          var columnIndex = columnIndices[c];
+          double sqrDist = Util.SqrDist(x[i, columnIndex] * inverseLength[k], x[j, columnIndex] * inverseLength[k]);
+          g.Add(scale * Math.Exp(-d / 2.0) * sqrDist);
+          k++;
+        }
+      }
+      if (!fixedScale) g.Add(2.0 * scale * Math.Exp(-d / 2.0));
+      return g;
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/CovarianceFunctions/CovarianceSquaredExponentialIso.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/CovarianceFunctions/CovarianceSquaredExponentialIso.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/CovarianceFunctions/CovarianceSquaredExponentialIso.cs	(revision 13819)
@@ -0,0 +1,140 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  [StorableClass]
+  [Item(Name = "CovarianceSquaredExponentialIso",
+    Description = "Isotropic squared exponential covariance function for Gaussian processes.")]
+  public sealed class CovarianceSquaredExponentialIso : ParameterizedNamedItem, ICovarianceFunction {
+    public IValueParameter<DoubleValue> ScaleParameter {
+      get { return (IValueParameter<DoubleValue>)Parameters["Scale"]; }
+    }
+
+    public IValueParameter<DoubleValue> InverseLengthParameter {
+      get { return (IValueParameter<DoubleValue>)Parameters["InverseLength"]; }
+    }
+
+    private bool HasFixedInverseLengthParameter {
+      get { return InverseLengthParameter.Value != null; }
+    }
+    private bool HasFixedScaleParameter {
+      get { return ScaleParameter.Value != null; }
+    }
+
+    [StorableConstructor]
+    private CovarianceSquaredExponentialIso(bool deserializing)
+      : base(deserializing) {
+    }
+
+    private CovarianceSquaredExponentialIso(CovarianceSquaredExponentialIso original, Cloner cloner)
+      : base(original, cloner) {
+    }
+
+    public CovarianceSquaredExponentialIso()
+      : base() {
+      Name = ItemName;
+      Description = ItemDescription;
+
+      Parameters.Add(new OptionalValueParameter<DoubleValue>("Scale", "The scale parameter of the isometric squared exponential covariance function."));
+      Parameters.Add(new OptionalValueParameter<DoubleValue>("InverseLength", "The inverse length parameter of the isometric squared exponential covariance function."));
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new CovarianceSquaredExponentialIso(this, cloner);
+    }
+
+    public int GetNumberOfParameters(int numberOfVariables) {
+      return
+        (HasFixedScaleParameter ? 0 : 1) +
+        (HasFixedInverseLengthParameter ? 0 : 1);
+    }
+
+    public void SetParameter(double[] p) {
+      double scale, inverseLength;
+      GetParameterValues(p, out scale, out inverseLength);
+      ScaleParameter.Value = new DoubleValue(scale);
+      InverseLengthParameter.Value = new DoubleValue(inverseLength);
+    }
+
+
+    private void GetParameterValues(double[] p, out double scale, out double inverseLength) {
+      // gather parameter values
+      int c = 0;
+      if (HasFixedInverseLengthParameter) {
+        inverseLength = InverseLengthParameter.Value.Value;
+      } else {
+        inverseLength = 1.0 / Math.Exp(p[c]);
+        c++;
+      }
+
+      if (HasFixedScaleParameter) {
+        scale = ScaleParameter.Value.Value;
+      } else {
+        scale = Math.Exp(2 * p[c]);
+        c++;
+      }
+      if (p.Length != c) throw new ArgumentException("The length of the parameter vector does not match the number of free parameters for CovarianceSquaredExponentialIso", "p");
+    }
+
+    public ParameterizedCovarianceFunction GetParameterizedCovarianceFunction(double[] p, int[] columnIndices) {
+      double inverseLength, scale;
+      GetParameterValues(p, out scale, out inverseLength);
+      var fixedInverseLength = HasFixedInverseLengthParameter;
+      var fixedScale = HasFixedScaleParameter;
+      // create functions
+      var cov = new ParameterizedCovarianceFunction();
+      cov.Covariance = (x, i, j) => {
+        double d = i == j
+                ? 0.0
+                : Util.SqrDist(x, i, j, columnIndices, inverseLength);
+        return scale * Math.Exp(-d / 2.0);
+      };
+      cov.CrossCovariance = (x, xt, i, j) => {
+        double d = Util.SqrDist(x, i, xt, j, columnIndices, inverseLength);
+        return scale * Math.Exp(-d / 2.0);
+      };
+      cov.CovarianceGradient = (x, i, j) => GetGradient(x, i, j, scale, inverseLength, columnIndices,
+        fixedInverseLength, fixedScale);
+      return cov;
+    }
+
+    // order of returned gradients must match the order in GetParameterValues!
+    private static IList<double> GetGradient(double[,] x, int i, int j, double sf2, double inverseLength, int[] columnIndices,
+      bool fixedInverseLength, bool fixedScale) {
+      double d = i == j
+                   ? 0.0
+                   : Util.SqrDist(x, i, j, columnIndices, inverseLength);
+      double g = Math.Exp(-d / 2.0);
+      var gr = new List<double>(2);
+      if (!fixedInverseLength) gr.Add(sf2 * g * d);
+      if (!fixedScale) gr.Add(2.0 * sf2 * g);
+      return gr;
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/CovarianceFunctions/CovarianceSum.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/CovarianceFunctions/CovarianceSum.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/CovarianceFunctions/CovarianceSum.cs	(revision 13819)
@@ -0,0 +1,98 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  [StorableClass]
+  [Item(Name = "CovarianceSum",
+    Description = "Sum covariance function for Gaussian processes.")]
+  public sealed class CovarianceSum : Item, ICovarianceFunction {
+    [Storable]
+    private ItemList<ICovarianceFunction> terms;
+
+    [Storable]
+    private int numberOfVariables;
+    public ItemList<ICovarianceFunction> Terms {
+      get { return terms; }
+    }
+
+    [StorableConstructor]
+    private CovarianceSum(bool deserializing)
+      : base(deserializing) {
+    }
+
+    private CovarianceSum(CovarianceSum original, Cloner cloner)
+      : base(original, cloner) {
+      this.terms = cloner.Clone(original.terms);
+      this.numberOfVariables = original.numberOfVariables;
+    }
+
+    public CovarianceSum()
+      : base() {
+      this.terms = new ItemList<ICovarianceFunction>();
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new CovarianceSum(this, cloner);
+    }
+
+    public int GetNumberOfParameters(int numberOfVariables) {
+      this.numberOfVariables = numberOfVariables;
+      return terms.Select(t => t.GetNumberOfParameters(numberOfVariables)).Sum();
+    }
+
+    public void SetParameter(double[] p) {
+      int offset = 0;
+      foreach (var t in terms) {
+        var numberOfParameters = t.GetNumberOfParameters(numberOfVariables);
+        t.SetParameter(p.Skip(offset).Take(numberOfParameters).ToArray());
+        offset += numberOfParameters;
+      }
+    }
+
+    public ParameterizedCovarianceFunction GetParameterizedCovarianceFunction(double[] p, int[] columnIndices) {
+      if (terms.Count == 0) throw new ArgumentException("at least one term is necessary for the product covariance function.");
+      var functions = new List<ParameterizedCovarianceFunction>();
+      foreach (var t in terms) {
+        var numberOfParameters = t.GetNumberOfParameters(numberOfVariables);
+        functions.Add(t.GetParameterizedCovarianceFunction(p.Take(numberOfParameters).ToArray(), columnIndices));
+        p = p.Skip(numberOfParameters).ToArray();
+      }
+
+      var sum = new ParameterizedCovarianceFunction();
+      sum.Covariance = (x, i, j) => functions.Select(e => e.Covariance(x, i, j)).Sum();
+      sum.CrossCovariance = (x, xt, i, j) => functions.Select(e => e.CrossCovariance(x, xt, i, j)).Sum();
+      sum.CovarianceGradient = (x, i, j) => {
+        var g = new List<double>(functions.Sum(e => e.CovarianceGradient(x, i, j).Count));
+        foreach (var e in functions)
+          g.AddRange(e.CovarianceGradient(x, i, j));
+        return g;
+      };
+      return sum;
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/GaussianProcessBase.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/GaussianProcessBase.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/GaussianProcessBase.cs	(revision 13819)
@@ -0,0 +1,212 @@
+
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using HeuristicLab.Algorithms.GradientDescent;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Operators;
+using HeuristicLab.Optimization;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Problems.DataAnalysis;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  /// <summary>
+  /// Base class for Gaussian process data analysis algorithms (regression and classification).
+  /// </summary>
+  [StorableClass]
+  public abstract class GaussianProcessBase : EngineAlgorithm {
+    protected const string MeanFunctionParameterName = "MeanFunction";
+    protected const string CovarianceFunctionParameterName = "CovarianceFunction";
+    protected const string MinimizationIterationsParameterName = "Iterations";
+    protected const string ApproximateGradientsParameterName = "ApproximateGradients";
+    protected const string SeedParameterName = "Seed";
+    protected const string SetSeedRandomlyParameterName = "SetSeedRandomly";
+    protected const string ModelCreatorParameterName = "GaussianProcessModelCreator";
+    protected const string NegativeLogLikelihoodParameterName = "NegativeLogLikelihood";
+    protected const string HyperparameterParameterName = "Hyperparameter";
+    protected const string HyperparameterGradientsParameterName = "HyperparameterGradients";
+    protected const string SolutionCreatorParameterName = "GaussianProcessSolutionCreator";
+    protected const string ScaleInputValuesParameterName = "ScaleInputValues";
+
+    public new IDataAnalysisProblem Problem {
+      get { return (IDataAnalysisProblem)base.Problem; }
+      set { base.Problem = value; }
+    }
+
+    #region parameter properties
+    public IValueParameter<IMeanFunction> MeanFunctionParameter {
+      get { return (IValueParameter<IMeanFunction>)Parameters[MeanFunctionParameterName]; }
+    }
+    public IValueParameter<ICovarianceFunction> CovarianceFunctionParameter {
+      get { return (IValueParameter<ICovarianceFunction>)Parameters[CovarianceFunctionParameterName]; }
+    }
+    public IValueParameter<IntValue> MinimizationIterationsParameter {
+      get { return (IValueParameter<IntValue>)Parameters[MinimizationIterationsParameterName]; }
+    }
+    public IValueParameter<IntValue> SeedParameter {
+      get { return (IValueParameter<IntValue>)Parameters[SeedParameterName]; }
+    }
+    public IValueParameter<BoolValue> SetSeedRandomlyParameter {
+      get { return (IValueParameter<BoolValue>)Parameters[SetSeedRandomlyParameterName]; }
+    }
+    public IFixedValueParameter<BoolValue> ScaleInputValuesParameter {
+      get { return (IFixedValueParameter<BoolValue>)Parameters[ScaleInputValuesParameterName]; }
+    }
+    #endregion
+    #region properties
+    public IMeanFunction MeanFunction {
+      set { MeanFunctionParameter.Value = value; }
+      get { return MeanFunctionParameter.Value; }
+    }
+    public ICovarianceFunction CovarianceFunction {
+      set { CovarianceFunctionParameter.Value = value; }
+      get { return CovarianceFunctionParameter.Value; }
+    }
+    public int MinimizationIterations {
+      set { MinimizationIterationsParameter.Value.Value = value; }
+      get { return MinimizationIterationsParameter.Value.Value; }
+    }
+    public int Seed { get { return SeedParameter.Value.Value; } set { SeedParameter.Value.Value = value; } }
+    public bool SetSeedRandomly { get { return SetSeedRandomlyParameter.Value.Value; } set { SetSeedRandomlyParameter.Value.Value = value; } }
+
+    public bool ScaleInputValues {
+      get { return ScaleInputValuesParameter.Value.Value; }
+      set { ScaleInputValuesParameter.Value.Value = value; }
+    }
+    #endregion
+
+    [StorableConstructor]
+    protected GaussianProcessBase(bool deserializing) : base(deserializing) { }
+    protected GaussianProcessBase(GaussianProcessBase original, Cloner cloner)
+      : base(original, cloner) {
+    }
+    protected GaussianProcessBase(IDataAnalysisProblem problem)
+      : base() {
+      Problem = problem;
+      Parameters.Add(new ValueParameter<IMeanFunction>(MeanFunctionParameterName, "The mean function to use.", new MeanConst()));
+      Parameters.Add(new ValueParameter<ICovarianceFunction>(CovarianceFunctionParameterName, "The covariance function to use.", new CovarianceSquaredExponentialIso()));
+      Parameters.Add(new ValueParameter<IntValue>(MinimizationIterationsParameterName, "The number of iterations for likelihood optimization with LM-BFGS.", new IntValue(20)));
+      Parameters.Add(new ValueParameter<IntValue>(SeedParameterName, "The random seed used to initialize the new pseudo random number generator.", new IntValue(0)));
+      Parameters.Add(new ValueParameter<BoolValue>(SetSeedRandomlyParameterName, "True if the random seed should be set to a random value, otherwise false.", new BoolValue(true)));
+
+      Parameters.Add(new ValueParameter<BoolValue>(ApproximateGradientsParameterName, "Indicates that gradients should not be approximated (necessary for LM-BFGS).", new BoolValue(false)));
+      Parameters[ApproximateGradientsParameterName].Hidden = true; // should not be changed
+
+      Parameters.Add(new FixedValueParameter<BoolValue>(ScaleInputValuesParameterName,
+        "Determines if the input variable values are scaled to the range [0..1] for training.", new BoolValue(true)));
+      Parameters[ScaleInputValuesParameterName].Hidden = true;
+
+      // necessary for BFGS
+      Parameters.Add(new ValueParameter<BoolValue>("Maximization", new BoolValue(false)));
+      Parameters["Maximization"].Hidden = true;
+
+      var randomCreator = new HeuristicLab.Random.RandomCreator();
+      var gpInitializer = new GaussianProcessHyperparameterInitializer();
+      var bfgsInitializer = new LbfgsInitializer();
+      var makeStep = new LbfgsMakeStep();
+      var branch = new ConditionalBranch();
+      var modelCreator = new Placeholder();
+      var updateResults = new LbfgsUpdateResults();
+      var analyzer = new LbfgsAnalyzer();
+      var finalModelCreator = new Placeholder();
+      var finalAnalyzer = new LbfgsAnalyzer();
+      var solutionCreator = new Placeholder();
+
+      OperatorGraph.InitialOperator = randomCreator;
+      randomCreator.SeedParameter.ActualName = SeedParameterName;
+      randomCreator.SeedParameter.Value = null;
+      randomCreator.SetSeedRandomlyParameter.ActualName = SetSeedRandomlyParameterName;
+      randomCreator.SetSeedRandomlyParameter.Value = null;
+      randomCreator.Successor = gpInitializer;
+
+      gpInitializer.CovarianceFunctionParameter.ActualName = CovarianceFunctionParameterName;
+      gpInitializer.MeanFunctionParameter.ActualName = MeanFunctionParameterName;
+      gpInitializer.ProblemDataParameter.ActualName = Problem.ProblemDataParameter.Name;
+      gpInitializer.HyperparameterParameter.ActualName = HyperparameterParameterName;
+      gpInitializer.RandomParameter.ActualName = randomCreator.RandomParameter.Name;
+      gpInitializer.Successor = bfgsInitializer;
+
+      bfgsInitializer.IterationsParameter.ActualName = MinimizationIterationsParameterName;
+      bfgsInitializer.PointParameter.ActualName = HyperparameterParameterName;
+      bfgsInitializer.ApproximateGradientsParameter.ActualName = ApproximateGradientsParameterName;
+      bfgsInitializer.Successor = makeStep;
+
+      makeStep.StateParameter.ActualName = bfgsInitializer.StateParameter.Name;
+      makeStep.PointParameter.ActualName = HyperparameterParameterName;
+      makeStep.Successor = branch;
+
+      branch.ConditionParameter.ActualName = makeStep.TerminationCriterionParameter.Name;
+      branch.FalseBranch = modelCreator;
+      branch.TrueBranch = finalModelCreator;
+
+      modelCreator.OperatorParameter.ActualName = ModelCreatorParameterName;
+      modelCreator.Successor = updateResults;
+
+      updateResults.StateParameter.ActualName = bfgsInitializer.StateParameter.Name;
+      updateResults.QualityParameter.ActualName = NegativeLogLikelihoodParameterName;
+      updateResults.QualityGradientsParameter.ActualName = HyperparameterGradientsParameterName;
+      updateResults.ApproximateGradientsParameter.ActualName = ApproximateGradientsParameterName;
+      updateResults.Successor = analyzer;
+
+      analyzer.QualityParameter.ActualName = NegativeLogLikelihoodParameterName;
+      analyzer.PointParameter.ActualName = HyperparameterParameterName;
+      analyzer.QualityGradientsParameter.ActualName = HyperparameterGradientsParameterName;
+      analyzer.StateParameter.ActualName = bfgsInitializer.StateParameter.Name;
+      analyzer.PointsTableParameter.ActualName = "Hyperparameter table";
+      analyzer.QualityGradientsTableParameter.ActualName = "Gradients table";
+      analyzer.QualitiesTableParameter.ActualName = "Negative log likelihood table";
+      analyzer.Successor = makeStep;
+
+      finalModelCreator.OperatorParameter.ActualName = ModelCreatorParameterName;
+      finalModelCreator.Successor = finalAnalyzer;
+
+      finalAnalyzer.QualityParameter.ActualName = NegativeLogLikelihoodParameterName;
+      finalAnalyzer.PointParameter.ActualName = HyperparameterParameterName;
+      finalAnalyzer.QualityGradientsParameter.ActualName = HyperparameterGradientsParameterName;
+      finalAnalyzer.PointsTableParameter.ActualName = analyzer.PointsTableParameter.ActualName;
+      finalAnalyzer.QualityGradientsTableParameter.ActualName = analyzer.QualityGradientsTableParameter.ActualName;
+      finalAnalyzer.QualitiesTableParameter.ActualName = analyzer.QualitiesTableParameter.ActualName;
+      finalAnalyzer.Successor = solutionCreator;
+
+      solutionCreator.OperatorParameter.ActualName = SolutionCreatorParameterName;
+    }
+
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() {
+      // 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(ScaleInputValuesParameterName)) {
+        Parameters.Add(new FixedValueParameter<BoolValue>(ScaleInputValuesParameterName,
+          "Determines if the input variable values are scaled to the range [0..1] for training.", new BoolValue(true)));
+        Parameters[ScaleInputValuesParameterName].Hidden = true;
+      }
+      #endregion
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/GaussianProcessClassification.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/GaussianProcessClassification.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/GaussianProcessClassification.cs	(revision 13819)
@@ -0,0 +1,154 @@
+
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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 HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Optimization;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.PluginInfrastructure;
+using HeuristicLab.Problems.DataAnalysis;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  /// <summary>
+  /// Gaussian process least-squares classification data analysis algorithm.
+  /// </summary>
+  [Item("Gaussian Process Least-Squares Classification", "Gaussian process least-squares classification data analysis algorithm.")]
+  [Creatable(CreatableAttribute.Categories.DataAnalysisClassification, Priority = 160)]
+  [StorableClass]
+  public sealed class GaussianProcessClassification : GaussianProcessBase, IStorableContent {
+    public string Filename { get; set; }
+
+    public override Type ProblemType { get { return typeof(IClassificationProblem); } }
+    public new IClassificationProblem Problem {
+      get { return (IClassificationProblem)base.Problem; }
+      set { base.Problem = value; }
+    }
+
+    private const string ModelParameterName = "Model";
+    private const string CreateSolutionParameterName = "CreateSolution";
+
+    #region parameter properties
+    public IConstrainedValueParameter<IGaussianProcessClassificationModelCreator> GaussianProcessModelCreatorParameter {
+      get { return (IConstrainedValueParameter<IGaussianProcessClassificationModelCreator>)Parameters[ModelCreatorParameterName]; }
+    }
+    public IFixedValueParameter<GaussianProcessClassificationSolutionCreator> GaussianProcessSolutionCreatorParameter {
+      get { return (IFixedValueParameter<GaussianProcessClassificationSolutionCreator>)Parameters[SolutionCreatorParameterName]; }
+    }
+    public IFixedValueParameter<BoolValue> CreateSolutionParameter {
+      get { return (IFixedValueParameter<BoolValue>)Parameters[CreateSolutionParameterName]; }
+    }
+    #endregion
+    #region properties
+    public bool CreateSolution {
+      get { return CreateSolutionParameter.Value.Value; }
+      set { CreateSolutionParameter.Value.Value = value; }
+    }
+    #endregion
+
+    [StorableConstructor]
+    private GaussianProcessClassification(bool deserializing) : base(deserializing) { }
+    private GaussianProcessClassification(GaussianProcessClassification original, Cloner cloner)
+      : base(original, cloner) {
+      RegisterEventHandlers();
+    }
+    public GaussianProcessClassification()
+      : base(new ClassificationProblem()) {
+      this.name = ItemName;
+      this.description = ItemDescription;
+
+      var modelCreators = ApplicationManager.Manager.GetInstances<IGaussianProcessClassificationModelCreator>();
+      var defaultModelCreator = modelCreators.First(c => c is GaussianProcessClassificationModelCreator);
+
+      // GP regression and classification algorithms only differ in the model and solution creators,
+      // thus we use a common base class and use operator parameters to implement the specific versions.
+      // Different model creators can be implemented,
+      // but the solution creator is implemented in a generic fashion already and we don't allow derived solution creators
+      Parameters.Add(new ConstrainedValueParameter<IGaussianProcessClassificationModelCreator>(ModelCreatorParameterName, "The operator to create the Gaussian process model.",
+        new ItemSet<IGaussianProcessClassificationModelCreator>(modelCreators), defaultModelCreator));
+      // this parameter is not intended to be changed, 
+      Parameters.Add(new FixedValueParameter<GaussianProcessClassificationSolutionCreator>(SolutionCreatorParameterName, "The solution creator for the algorithm",
+        new GaussianProcessClassificationSolutionCreator()));
+      Parameters[SolutionCreatorParameterName].Hidden = true;
+      // TODO: it would be better to deactivate the solution creator when this parameter is changed
+      Parameters.Add(new FixedValueParameter<BoolValue>(CreateSolutionParameterName, "Flag that indicates if a solution should be produced at the end of the run", new BoolValue(true)));
+      Parameters[CreateSolutionParameterName].Hidden = true;
+
+      ParameterizedModelCreators();
+      ParameterizeSolutionCreator(GaussianProcessSolutionCreatorParameter.Value);
+      RegisterEventHandlers();
+    }
+
+
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() {
+      // BackwardsCompatibility3.3
+      #region Backwards compatible code, remove with 3.4
+      if (!Parameters.ContainsKey(CreateSolutionParameterName)) {
+        Parameters.Add(new FixedValueParameter<BoolValue>(CreateSolutionParameterName, "Flag that indicates if a solution should be produced at the end of the run", new BoolValue(true)));
+        Parameters[CreateSolutionParameterName].Hidden = true;
+      }
+      #endregion
+      RegisterEventHandlers();
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new GaussianProcessClassification(this, cloner);
+    }
+
+    #region events
+    private void RegisterEventHandlers() {
+      GaussianProcessModelCreatorParameter.ValueChanged += ModelCreatorParameter_ValueChanged;
+    }
+
+    private void ModelCreatorParameter_ValueChanged(object sender, EventArgs e) {
+      ParameterizedModelCreator(GaussianProcessModelCreatorParameter.Value);
+    }
+    #endregion
+
+    private void ParameterizedModelCreators() {
+      foreach (var creator in GaussianProcessModelCreatorParameter.ValidValues) {
+        ParameterizedModelCreator(creator);
+      }
+    }
+
+    private void ParameterizedModelCreator(IGaussianProcessClassificationModelCreator modelCreator) {
+      modelCreator.ProblemDataParameter.ActualName = Problem.ProblemDataParameter.Name;
+      modelCreator.MeanFunctionParameter.ActualName = MeanFunctionParameterName;
+      modelCreator.CovarianceFunctionParameter.ActualName = CovarianceFunctionParameterName;
+
+      // parameter names fixed by the algorithm
+      modelCreator.ModelParameter.ActualName = ModelParameterName;
+      modelCreator.HyperparameterParameter.ActualName = HyperparameterParameterName;
+      modelCreator.HyperparameterGradientsParameter.ActualName = HyperparameterGradientsParameterName;
+      modelCreator.NegativeLogLikelihoodParameter.ActualName = NegativeLogLikelihoodParameterName;
+    }
+
+    private void ParameterizeSolutionCreator(GaussianProcessClassificationSolutionCreator solutionCreator) {
+      solutionCreator.ModelParameter.ActualName = ModelParameterName;
+      solutionCreator.ProblemDataParameter.ActualName = Problem.ProblemDataParameter.Name;
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/GaussianProcessClassificationModelCreator.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/GaussianProcessClassificationModelCreator.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/GaussianProcessClassificationModelCreator.cs	(revision 13819)
@@ -0,0 +1,79 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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 HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Encodings.RealVectorEncoding;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Problems.DataAnalysis;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  [StorableClass]
+  [Item(Name = "GaussianProcessClassificationModelCreator",
+    Description = "Creates a Gaussian process model for least-squares classification given the data, the hyperparameters, a mean function, and a covariance function.")]
+  public sealed class GaussianProcessClassificationModelCreator : GaussianProcessModelCreator, IGaussianProcessClassificationModelCreator {
+    private const string ProblemDataParameterName = "ProblemData";
+
+    #region Parameter Properties
+    public ILookupParameter<IClassificationProblemData> ProblemDataParameter {
+      get { return (ILookupParameter<IClassificationProblemData>)Parameters[ProblemDataParameterName]; }
+    }
+    #endregion
+
+    #region Properties
+    private IClassificationProblemData ProblemData {
+      get { return ProblemDataParameter.ActualValue; }
+    }
+    #endregion
+    [StorableConstructor]
+    private GaussianProcessClassificationModelCreator(bool deserializing) : base(deserializing) { }
+    private GaussianProcessClassificationModelCreator(GaussianProcessClassificationModelCreator original, Cloner cloner) : base(original, cloner) { }
+    public GaussianProcessClassificationModelCreator()
+      : base() {
+      Parameters.Add(new LookupParameter<IClassificationProblemData>(ProblemDataParameterName, "The classification problem data for the Gaussian process model."));
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new GaussianProcessClassificationModelCreator(this, cloner);
+    }
+
+    public override IOperation Apply() {
+      try {
+        var model = Create(ProblemData, Hyperparameter.ToArray(), MeanFunction, CovarianceFunction, ScaleInputValues);
+        ModelParameter.ActualValue = model;
+        NegativeLogLikelihoodParameter.ActualValue = new DoubleValue(model.NegativeLogLikelihood);
+        HyperparameterGradientsParameter.ActualValue = new RealVector(model.HyperparameterGradients);
+        return base.Apply();
+      } catch (ArgumentException) { } catch (alglib.alglibexception) { }
+      NegativeLogLikelihoodParameter.ActualValue = new DoubleValue(1E300);
+      HyperparameterGradientsParameter.ActualValue = new RealVector(Hyperparameter.Count());
+      return base.Apply();
+    }
+
+    public static IGaussianProcessModel Create(IClassificationProblemData problemData, double[] hyperparameter, IMeanFunction meanFunction, ICovarianceFunction covarianceFunction, bool scaleInputs = true) {
+      return new GaussianProcessModel(problemData.Dataset, problemData.TargetVariable, problemData.AllowedInputVariables, problemData.TrainingIndices, hyperparameter, meanFunction, covarianceFunction, scaleInputs);
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/GaussianProcessClassificationSolutionCreator.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/GaussianProcessClassificationSolutionCreator.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/GaussianProcessClassificationSolutionCreator.cs	(revision 13819)
@@ -0,0 +1,120 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Operators;
+using HeuristicLab.Optimization;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Problems.DataAnalysis;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  [StorableClass]
+  [Item(Name = "GaussianProcessClassificationSolutionCreator",
+    Description = "Creates a Gaussian process solution from a trained model.")]
+  public sealed class GaussianProcessClassificationSolutionCreator : SingleSuccessorOperator {
+    private const string ProblemDataParameterName = "ProblemData";
+    private const string ModelParameterName = "GaussianProcessClassificationModel";
+    private const string SolutionParameterName = "Solution";
+    private const string ResultsParameterName = "Results";
+    private const string TrainingAccuracyResultName = "Accuracy (training)";
+    private const string TestAccuracyResultName = "Accuracy (test)";
+    private const string CreateSolutionParameterName = "CreateSolution";
+
+    #region Parameter Properties
+    public ILookupParameter<IClassificationProblemData> ProblemDataParameter {
+      get { return (ILookupParameter<IClassificationProblemData>)Parameters[ProblemDataParameterName]; }
+    }
+    public ILookupParameter<IDiscriminantFunctionClassificationSolution> SolutionParameter {
+      get { return (ILookupParameter<IDiscriminantFunctionClassificationSolution>)Parameters[SolutionParameterName]; }
+    }
+    public ILookupParameter<IGaussianProcessModel> ModelParameter {
+      get { return (ILookupParameter<IGaussianProcessModel>)Parameters[ModelParameterName]; }
+    }
+    public ILookupParameter<ResultCollection> ResultsParameter {
+      get { return (ILookupParameter<ResultCollection>)Parameters[ResultsParameterName]; }
+    }
+    public ILookupParameter<BoolValue> CreateSolutionParameter {
+      get { return (ILookupParameter<BoolValue>)Parameters[CreateSolutionParameterName]; }
+    }
+    #endregion
+
+    [StorableConstructor]
+    private GaussianProcessClassificationSolutionCreator(bool deserializing) : base(deserializing) { }
+    private GaussianProcessClassificationSolutionCreator(GaussianProcessClassificationSolutionCreator original, Cloner cloner) : base(original, cloner) { }
+    public GaussianProcessClassificationSolutionCreator()
+      : base() {
+      // in
+      Parameters.Add(new LookupParameter<IClassificationProblemData>(ProblemDataParameterName, "The classification problem data for the Gaussian process solution."));
+      Parameters.Add(new LookupParameter<IGaussianProcessModel>(ModelParameterName, "The Gaussian process classification model to use for the solution."));
+      Parameters.Add(new LookupParameter<BoolValue>(CreateSolutionParameterName, "Flag that indicates if a solution should be produced at the end of the run"));
+
+      // in & out
+      Parameters.Add(new LookupParameter<ResultCollection>(ResultsParameterName, "The result collection of the algorithm."));
+      // out
+      Parameters.Add(new LookupParameter<IDiscriminantFunctionClassificationSolution>(SolutionParameterName, "The produced Gaussian process solution."));
+    }
+
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() {
+      // BackwardsCompatibility3.3
+      #region Backwards compatible code, remove with 3.4
+      if (!Parameters.ContainsKey(CreateSolutionParameterName)) {
+        Parameters.Add(new LookupParameter<BoolValue>(CreateSolutionParameterName, "Flag that indicates if a solution should be produced at the end of the run"));
+      }
+      #endregion
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new GaussianProcessClassificationSolutionCreator(this, cloner);
+    }
+
+    public override IOperation Apply() {
+      if (ModelParameter.ActualValue != null && CreateSolutionParameter.ActualValue.Value == true) {
+        var m = (IGaussianProcessModel)ModelParameter.ActualValue.Clone();
+        m.FixParameters();
+        var data = (IClassificationProblemData)ProblemDataParameter.ActualValue.Clone();
+        var model = new DiscriminantFunctionClassificationModel(m, new NormalDistributionCutPointsThresholdCalculator());
+        model.RecalculateModelParameters(data, data.TrainingIndices);
+        var s = model.CreateDiscriminantFunctionClassificationSolution(data);
+
+        SolutionParameter.ActualValue = s;
+        var results = ResultsParameter.ActualValue;
+        if (!results.ContainsKey(SolutionParameterName)) {
+          results.Add(new Result(SolutionParameterName, "The Gaussian process classification solution", s));
+          results.Add(new Result(TrainingAccuracyResultName,
+                                 "The accuracy of the Gaussian process solution on the training partition.",
+                                 new DoubleValue(s.TrainingAccuracy)));
+          results.Add(new Result(TestAccuracyResultName,
+                                 "The accuracy of the Gaussian process solution on the test partition.",
+                                 new DoubleValue(s.TestAccuracy)));
+        } else {
+          results[SolutionParameterName].Value = s;
+          results[TrainingAccuracyResultName].Value = new DoubleValue(s.TrainingAccuracy);
+          results[TestAccuracyResultName].Value = new DoubleValue(s.TestAccuracy);
+        }
+      }
+      return base.Apply();
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/GaussianProcessCovarianceOptimizationProblem.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/GaussianProcessCovarianceOptimizationProblem.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/GaussianProcessCovarianceOptimizationProblem.cs	(revision 13819)
@@ -0,0 +1,424 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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 HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
+using HeuristicLab.Optimization;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Problems.DataAnalysis;
+using HeuristicLab.Problems.Instances;
+
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  [Item("Gaussian Process Covariance Optimization Problem", "")]
+  [Creatable(CreatableAttribute.Categories.GeneticProgrammingProblems, Priority = 300)]
+  [StorableClass]
+  public sealed class GaussianProcessCovarianceOptimizationProblem : SymbolicExpressionTreeProblem, IStatefulItem, IRegressionProblem, IProblemInstanceConsumer<IRegressionProblemData>, IProblemInstanceExporter<IRegressionProblemData> {
+    #region static variables and ctor
+    private static readonly CovarianceMaternIso maternIso1;
+    private static readonly CovarianceMaternIso maternIso3;
+    private static readonly CovarianceMaternIso maternIso5;
+    private static readonly CovariancePiecewisePolynomial piecewisePoly0;
+    private static readonly CovariancePiecewisePolynomial piecewisePoly1;
+    private static readonly CovariancePiecewisePolynomial piecewisePoly2;
+    private static readonly CovariancePiecewisePolynomial piecewisePoly3;
+    private static readonly CovariancePolynomial poly2;
+    private static readonly CovariancePolynomial poly3;
+    private static readonly CovarianceSpectralMixture spectralMixture1;
+    private static readonly CovarianceSpectralMixture spectralMixture3;
+    private static readonly CovarianceSpectralMixture spectralMixture5;
+    private static readonly CovarianceLinear linear;
+    private static readonly CovarianceLinearArd linearArd;
+    private static readonly CovarianceNeuralNetwork neuralNetwork;
+    private static readonly CovariancePeriodic periodic;
+    private static readonly CovarianceRationalQuadraticIso ratQuadraticIso;
+    private static readonly CovarianceRationalQuadraticArd ratQuadraticArd;
+    private static readonly CovarianceSquaredExponentialArd sqrExpArd;
+    private static readonly CovarianceSquaredExponentialIso sqrExpIso;
+
+    static GaussianProcessCovarianceOptimizationProblem() {
+      // cumbersome initialization because of ConstrainedValueParameters
+      maternIso1 = new CovarianceMaternIso(); SetConstrainedValueParameter(maternIso1.DParameter, 1);
+      maternIso3 = new CovarianceMaternIso(); SetConstrainedValueParameter(maternIso3.DParameter, 3);
+      maternIso5 = new CovarianceMaternIso(); SetConstrainedValueParameter(maternIso5.DParameter, 5);
+
+      piecewisePoly0 = new CovariancePiecewisePolynomial(); SetConstrainedValueParameter(piecewisePoly0.VParameter, 0);
+      piecewisePoly1 = new CovariancePiecewisePolynomial(); SetConstrainedValueParameter(piecewisePoly1.VParameter, 1);
+      piecewisePoly2 = new CovariancePiecewisePolynomial(); SetConstrainedValueParameter(piecewisePoly2.VParameter, 2);
+      piecewisePoly3 = new CovariancePiecewisePolynomial(); SetConstrainedValueParameter(piecewisePoly3.VParameter, 3);
+
+      poly2 = new CovariancePolynomial(); poly2.DegreeParameter.Value.Value = 2;
+      poly3 = new CovariancePolynomial(); poly3.DegreeParameter.Value.Value = 3;
+
+      spectralMixture1 = new CovarianceSpectralMixture(); spectralMixture1.QParameter.Value.Value = 1;
+      spectralMixture3 = new CovarianceSpectralMixture(); spectralMixture3.QParameter.Value.Value = 3;
+      spectralMixture5 = new CovarianceSpectralMixture(); spectralMixture5.QParameter.Value.Value = 5;
+
+      linear = new CovarianceLinear();
+      linearArd = new CovarianceLinearArd();
+      neuralNetwork = new CovarianceNeuralNetwork();
+      periodic = new CovariancePeriodic();
+      ratQuadraticArd = new CovarianceRationalQuadraticArd();
+      ratQuadraticIso = new CovarianceRationalQuadraticIso();
+      sqrExpArd = new CovarianceSquaredExponentialArd();
+      sqrExpIso = new CovarianceSquaredExponentialIso();
+    }
+
+    private static void SetConstrainedValueParameter(IConstrainedValueParameter<IntValue> param, int val) {
+      param.Value = param.ValidValues.Single(v => v.Value == val);
+    }
+
+    #endregion
+
+    #region parameter names
+
+    private const string ProblemDataParameterName = "ProblemData";
+    private const string ConstantOptIterationsParameterName = "Constant optimization steps";
+    private const string RestartsParameterName = "Restarts";
+
+    #endregion
+
+    #region Parameter Properties
+    IParameter IDataAnalysisProblem.ProblemDataParameter { get { return ProblemDataParameter; } }
+
+    public IValueParameter<IRegressionProblemData> ProblemDataParameter {
+      get { return (IValueParameter<IRegressionProblemData>)Parameters[ProblemDataParameterName]; }
+    }
+    public IFixedValueParameter<IntValue> ConstantOptIterationsParameter {
+      get { return (IFixedValueParameter<IntValue>)Parameters[ConstantOptIterationsParameterName]; }
+    }
+    public IFixedValueParameter<IntValue> RestartsParameter {
+      get { return (IFixedValueParameter<IntValue>)Parameters[RestartsParameterName]; }
+    }
+    #endregion
+
+    #region Properties
+
+    public IRegressionProblemData ProblemData {
+      get { return ProblemDataParameter.Value; }
+      set { ProblemDataParameter.Value = value; }
+    }
+    IDataAnalysisProblemData IDataAnalysisProblem.ProblemData { get { return ProblemData; } }
+
+    public int ConstantOptIterations {
+      get { return ConstantOptIterationsParameter.Value.Value; }
+      set { ConstantOptIterationsParameter.Value.Value = value; }
+    }
+
+    public int Restarts {
+      get { return RestartsParameter.Value.Value; }
+      set { RestartsParameter.Value.Value = value; }
+    }
+    #endregion
+
+    public override bool Maximization {
+      get { return true; } // return log likelihood (instead of negative log likelihood as in GPR
+    }
+
+    // problem stores a few variables for information exchange from Evaluate() to Analyze()
+    private readonly object problemStateLocker = new object();
+    [Storable]
+    private double bestQ;
+    [Storable]
+    private double[] bestHyperParameters;
+    [Storable]
+    private IMeanFunction meanFunc;
+    [Storable]
+    private ICovarianceFunction covFunc;
+
+    public GaussianProcessCovarianceOptimizationProblem()
+      : base() {
+      Parameters.Add(new ValueParameter<IRegressionProblemData>(ProblemDataParameterName, "The data for the regression problem", new RegressionProblemData()));
+      Parameters.Add(new FixedValueParameter<IntValue>(ConstantOptIterationsParameterName, "Number of optimization steps for hyperparameter values", new IntValue(50)));
+      Parameters.Add(new FixedValueParameter<IntValue>(RestartsParameterName, "The number of random restarts for constant optimization.", new IntValue(10)));
+      Parameters["Restarts"].Hidden = true;
+      var g = new SimpleSymbolicExpressionGrammar();
+      g.AddSymbols(new string[] { "Sum", "Product" }, 2, 2);
+      g.AddTerminalSymbols(new string[]
+      {
+        "Linear",
+        "LinearArd",
+        "MaternIso1",
+        "MaternIso3",
+        "MaternIso5",
+        "NeuralNetwork",
+        "Periodic",
+        "PiecewisePolynomial0",
+        "PiecewisePolynomial1",
+        "PiecewisePolynomial2",
+        "PiecewisePolynomial3",
+        "Polynomial2",
+        "Polynomial3",
+        "RationalQuadraticArd",
+        "RationalQuadraticIso",
+        "SpectralMixture1",
+        "SpectralMixture3",
+        "SpectralMixture5",
+        "SquaredExponentialArd",
+        "SquaredExponentialIso"
+      });
+      base.Encoding = new SymbolicExpressionTreeEncoding(g, 10, 5);
+    }
+
+    public void InitializeState() { ClearState(); }
+    public void ClearState() {
+      meanFunc = null;
+      covFunc = null;
+      bestQ = double.NegativeInfinity;
+      bestHyperParameters = null;
+    }
+
+    private readonly object syncRoot = new object();
+    // Does not produce the same result for the same seed when using parallel engine (see below)!
+    public override double Evaluate(ISymbolicExpressionTree tree, IRandom random) {
+      var meanFunction = new MeanConst();
+      var problemData = ProblemData;
+      var ds = problemData.Dataset;
+      var targetVariable = problemData.TargetVariable;
+      var allowedInputVariables = problemData.AllowedInputVariables.ToArray();
+      var nVars = allowedInputVariables.Length;
+      var trainingRows = problemData.TrainingIndices.ToArray();
+
+      // use the same covariance function for each restart
+      var covarianceFunction = TreeToCovarianceFunction(tree);
+
+      // allocate hyperparameters
+      var hyperParameters = new double[meanFunction.GetNumberOfParameters(nVars) + covarianceFunction.GetNumberOfParameters(nVars) + 1]; // mean + cov + noise
+      double[] bestHyperParameters = new double[hyperParameters.Length];
+      var bestObjValue = new double[1] { double.MinValue };
+
+      // data that is necessary for the objective function
+      var data = Tuple.Create(ds, targetVariable, allowedInputVariables, trainingRows, (IMeanFunction)meanFunction, covarianceFunction, bestObjValue);
+
+      for (int t = 0; t < Restarts; t++) {
+        var prevBest = bestObjValue[0];
+        var prevBestHyperParameters = new double[hyperParameters.Length];
+        Array.Copy(bestHyperParameters, prevBestHyperParameters, bestHyperParameters.Length);
+
+        // initialize hyperparameters
+        hyperParameters[0] = ds.GetDoubleValues(targetVariable).Average(); // mean const
+
+        // Evaluate might be called concurrently therefore access to random has to be synchronized.
+        // However, results of multiple runs with the same seed will be different when using the parallel engine.
+        lock (syncRoot) {
+          for (int i = 0; i < covarianceFunction.GetNumberOfParameters(nVars); i++) {
+            hyperParameters[1 + i] = random.NextDouble() * 2.0 - 1.0;
+          }
+        }
+        hyperParameters[hyperParameters.Length - 1] = 1.0; // s² = exp(2), TODO: other inits better?
+
+        // use alglib.bfgs for hyper-parameter optimization ...
+        double epsg = 0;
+        double epsf = 0.00001;
+        double epsx = 0;
+        double stpmax = 1;
+        int maxits = ConstantOptIterations;
+        alglib.mincgstate state;
+        alglib.mincgreport rep;
+
+        alglib.mincgcreate(hyperParameters, out state);
+        alglib.mincgsetcond(state, epsg, epsf, epsx, maxits);
+        alglib.mincgsetstpmax(state, stpmax);
+        alglib.mincgoptimize(state, ObjectiveFunction, null, data);
+
+        alglib.mincgresults(state, out bestHyperParameters, out rep);
+
+        if (rep.terminationtype < 0) {
+          // error -> restore previous best quality
+          bestObjValue[0] = prevBest;
+          Array.Copy(prevBestHyperParameters, bestHyperParameters, prevBestHyperParameters.Length);
+        }
+      }
+
+      UpdateBestSoFar(bestObjValue[0], bestHyperParameters, meanFunction, covarianceFunction);
+
+      return bestObjValue[0];
+    }
+
+    // updates the overall best quality and overall best model for Analyze()
+    private void UpdateBestSoFar(double bestQ, double[] bestHyperParameters, IMeanFunction meanFunc, ICovarianceFunction covFunc) {
+      lock (problemStateLocker) {
+        if (bestQ > this.bestQ) {
+          this.bestQ = bestQ;
+          this.bestHyperParameters = new double[bestHyperParameters.Length];
+          Array.Copy(bestHyperParameters, this.bestHyperParameters, this.bestHyperParameters.Length);
+          this.meanFunc = meanFunc;
+          this.covFunc = covFunc;
+        }
+      }
+    }
+
+    public override void Analyze(ISymbolicExpressionTree[] trees, double[] qualities, ResultCollection results, IRandom random) {
+      if (!results.ContainsKey("Best Solution Quality")) {
+        results.Add(new Result("Best Solution Quality", typeof(DoubleValue)));
+      }
+      if (!results.ContainsKey("Best Tree")) {
+        results.Add(new Result("Best Tree", typeof(ISymbolicExpressionTree)));
+      }
+      if (!results.ContainsKey("Best Solution")) {
+        results.Add(new Result("Best Solution", typeof(GaussianProcessRegressionSolution)));
+      }
+
+      var bestQuality = qualities.Max();
+
+      if (results["Best Solution Quality"].Value == null || bestQuality > ((DoubleValue)results["Best Solution Quality"].Value).Value) {
+        var bestIdx = Array.IndexOf(qualities, bestQuality);
+        var bestClone = (ISymbolicExpressionTree)trees[bestIdx].Clone();
+        results["Best Tree"].Value = bestClone;
+        results["Best Solution Quality"].Value = new DoubleValue(bestQuality);
+        results["Best Solution"].Value = CreateSolution();
+      }
+    }
+
+    private IItem CreateSolution() {
+      var problemData = ProblemData;
+      var ds = problemData.Dataset;
+      var targetVariable = problemData.TargetVariable;
+      var allowedInputVariables = problemData.AllowedInputVariables.ToArray();
+      var trainingRows = problemData.TrainingIndices.ToArray();
+
+      lock (problemStateLocker) {
+        var model = new GaussianProcessModel(ds, targetVariable, allowedInputVariables, trainingRows, bestHyperParameters, (IMeanFunction)meanFunc.Clone(), (ICovarianceFunction)covFunc.Clone());
+        model.FixParameters();
+        return model.CreateRegressionSolution((IRegressionProblemData)ProblemData.Clone());
+      }
+    }
+
+    private void ObjectiveFunction(double[] x, ref double func, double[] grad, object obj) {
+      // we want to optimize the model likelihood by changing the hyperparameters and also return the gradient for each hyperparameter
+      var data = (Tuple<IDataset, string, string[], int[], IMeanFunction, ICovarianceFunction, double[]>)obj;
+      var ds = data.Item1;
+      var targetVariable = data.Item2;
+      var allowedInputVariables = data.Item3;
+      var trainingRows = data.Item4;
+      var meanFunction = data.Item5;
+      var covarianceFunction = data.Item6;
+      var bestObjValue = data.Item7;
+      var hyperParameters = x; // the decision variable vector
+
+      try {
+        var model = new GaussianProcessModel(ds, targetVariable, allowedInputVariables, trainingRows, hyperParameters, meanFunction, covarianceFunction);
+
+        func = model.NegativeLogLikelihood; // mincgoptimize, so we return negative likelihood
+        bestObjValue[0] = Math.Max(bestObjValue[0], -func); // problem itself is a maximization problem
+        var gradients = model.HyperparameterGradients;
+        Array.Copy(gradients, grad, gradients.Length);
+      }
+      catch (ArgumentException) {
+        // building the GaussianProcessModel might fail, in this case we return the worst possible objective value
+        func = 1.0E+300;
+        Array.Clear(grad, 0, grad.Length);
+      }
+    }
+
+    private ICovarianceFunction TreeToCovarianceFunction(ISymbolicExpressionTree tree) {
+      return TreeToCovarianceFunction(tree.Root.GetSubtree(0).GetSubtree(0)); // skip programroot and startsymbol
+    }
+
+    private ICovarianceFunction TreeToCovarianceFunction(ISymbolicExpressionTreeNode node) {
+      switch (node.Symbol.Name) {
+        case "Sum": {
+            var sum = new CovarianceSum();
+            sum.Terms.Add(TreeToCovarianceFunction(node.GetSubtree(0)));
+            sum.Terms.Add(TreeToCovarianceFunction(node.GetSubtree(1)));
+            return sum;
+          }
+        case "Product": {
+            var prod = new CovarianceProduct();
+            prod.Factors.Add(TreeToCovarianceFunction(node.GetSubtree(0)));
+            prod.Factors.Add(TreeToCovarianceFunction(node.GetSubtree(1)));
+            return prod;
+          }
+        // covFunction is cloned by the model so we can reuse instances of terminal covariance functions
+        case "Linear": return linear;
+        case "LinearArd": return linearArd;
+        case "MaternIso1": return maternIso1;
+        case "MaternIso3": return maternIso3;
+        case "MaternIso5": return maternIso5;
+        case "NeuralNetwork": return neuralNetwork;
+        case "Periodic": return periodic;
+        case "PiecewisePolynomial0": return piecewisePoly0;
+        case "PiecewisePolynomial1": return piecewisePoly1;
+        case "PiecewisePolynomial2": return piecewisePoly2;
+        case "PiecewisePolynomial3": return piecewisePoly3;
+        case "Polynomial2": return poly2;
+        case "Polynomial3": return poly3;
+        case "RationalQuadraticArd": return ratQuadraticArd;
+        case "RationalQuadraticIso": return ratQuadraticIso;
+        case "SpectralMixture1": return spectralMixture1;
+        case "SpectralMixture3": return spectralMixture3;
+        case "SpectralMixture5": return spectralMixture5;
+        case "SquaredExponentialArd": return sqrExpArd;
+        case "SquaredExponentialIso": return sqrExpIso;
+        default: throw new InvalidProgramException(string.Format("Found invalid symbol {0}", node.Symbol.Name));
+      }
+    }
+
+
+    // persistence
+    [StorableConstructor]
+    private GaussianProcessCovarianceOptimizationProblem(bool deserializing) : base(deserializing) { }
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() {
+    }
+
+    // cloning 
+    private GaussianProcessCovarianceOptimizationProblem(GaussianProcessCovarianceOptimizationProblem original, Cloner cloner)
+      : base(original, cloner) {
+      bestQ = original.bestQ;
+      meanFunc = cloner.Clone(original.meanFunc);
+      covFunc = cloner.Clone(original.covFunc);
+      if (bestHyperParameters != null) {
+        bestHyperParameters = new double[original.bestHyperParameters.Length];
+        Array.Copy(original.bestHyperParameters, bestHyperParameters, bestHyperParameters.Length);
+      }
+    }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new GaussianProcessCovarianceOptimizationProblem(this, cloner);
+    }
+
+    public void Load(IRegressionProblemData data) {
+      this.ProblemData = data;
+      OnProblemDataChanged();
+    }
+
+    public IRegressionProblemData Export() {
+      return ProblemData;
+    }
+
+    #region events
+    public event EventHandler ProblemDataChanged;
+
+
+    private void OnProblemDataChanged() {
+      var handler = ProblemDataChanged;
+      if (handler != null)
+        handler(this, EventArgs.Empty);
+    }
+    #endregion
+
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/GaussianProcessHyperparameterInitializer.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/GaussianProcessHyperparameterInitializer.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/GaussianProcessHyperparameterInitializer.cs	(revision 13819)
@@ -0,0 +1,99 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Encodings.RealVectorEncoding;
+using HeuristicLab.Operators;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Problems.DataAnalysis;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  [StorableClass]
+  [Item(Name = "GaussianProcessHyperparameterInitializer",
+    Description = "Initializers the hyperparameter vector based on the mean function, covariance function, and number of allowed input variables.")]
+  public sealed class GaussianProcessHyperparameterInitializer : SingleSuccessorOperator {
+    private const string MeanFunctionParameterName = "MeanFunction";
+    private const string CovarianceFunctionParameterName = "CovarianceFunction";
+    private const string ProblemDataParameterName = "ProblemData";
+    private const string HyperparameterParameterName = "Hyperparameter";
+    private const string RandomParameterName = "Random";
+
+    #region Parameter Properties
+    // in
+    public ILookupParameter<IMeanFunction> MeanFunctionParameter {
+      get { return (ILookupParameter<IMeanFunction>)Parameters[MeanFunctionParameterName]; }
+    }
+    public ILookupParameter<ICovarianceFunction> CovarianceFunctionParameter {
+      get { return (ILookupParameter<ICovarianceFunction>)Parameters[CovarianceFunctionParameterName]; }
+    }
+    public ILookupParameter<IDataAnalysisProblemData> ProblemDataParameter {
+      get { return (ILookupParameter<IDataAnalysisProblemData>)Parameters[ProblemDataParameterName]; }
+    }
+    public ILookupParameter<IRandom> RandomParameter {
+      get { return (ILookupParameter<IRandom>)Parameters[RandomParameterName]; }
+    }
+    // out
+    public ILookupParameter<RealVector> HyperparameterParameter {
+      get { return (ILookupParameter<RealVector>)Parameters[HyperparameterParameterName]; }
+    }
+    #endregion
+
+    #region Properties
+    private IMeanFunction MeanFunction { get { return MeanFunctionParameter.ActualValue; } }
+    private ICovarianceFunction CovarianceFunction { get { return CovarianceFunctionParameter.ActualValue; } }
+    private IDataAnalysisProblemData ProblemData { get { return ProblemDataParameter.ActualValue; } }
+    #endregion
+
+    [StorableConstructor]
+    private GaussianProcessHyperparameterInitializer(bool deserializing) : base(deserializing) { }
+    private GaussianProcessHyperparameterInitializer(GaussianProcessHyperparameterInitializer original, Cloner cloner) : base(original, cloner) { }
+    public GaussianProcessHyperparameterInitializer()
+      : base() {
+      // in
+      Parameters.Add(new LookupParameter<IMeanFunction>(MeanFunctionParameterName, "The mean function for the Gaussian process model."));
+      Parameters.Add(new LookupParameter<ICovarianceFunction>(CovarianceFunctionParameterName, "The covariance function for the Gaussian process model."));
+      Parameters.Add(new LookupParameter<IDataAnalysisProblemData>(ProblemDataParameterName, "The input data for the Gaussian process."));
+      Parameters.Add(new LookupParameter<IRandom>(RandomParameterName, "The pseudo random number generator to use for initializing the hyperparameter vector."));
+      // out
+      Parameters.Add(new LookupParameter<RealVector>(HyperparameterParameterName, "The initial hyperparameter vector for the Gaussian process model."));
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new GaussianProcessHyperparameterInitializer(this, cloner);
+    }
+
+    public override IOperation Apply() {
+      var inputVariablesCount = ProblemData.AllowedInputVariables.Count();
+      int l = 1 + MeanFunction.GetNumberOfParameters(inputVariablesCount) +
+              CovarianceFunction.GetNumberOfParameters(inputVariablesCount);
+      var r = new RealVector(l);
+      var rand = RandomParameter.ActualValue;
+      for (int i = 0; i < r.Length; i++)
+        r[i] = rand.NextDouble() * 10 - 5;
+
+      HyperparameterParameter.ActualValue = r;
+      return base.Apply();
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/GaussianProcessModel.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/GaussianProcessModel.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/GaussianProcessModel.cs	(revision 13819)
@@ -0,0 +1,395 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Problems.DataAnalysis;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  /// <summary>
+  /// Represents a Gaussian process model.
+  /// </summary>
+  [StorableClass]
+  [Item("GaussianProcessModel", "Represents a Gaussian process posterior.")]
+  public sealed class GaussianProcessModel : NamedItem, IGaussianProcessModel {
+    [Storable]
+    private double negativeLogLikelihood;
+    public double NegativeLogLikelihood {
+      get { return negativeLogLikelihood; }
+    }
+
+    [Storable]
+    private double[] hyperparameterGradients;
+    public double[] HyperparameterGradients {
+      get {
+        var copy = new double[hyperparameterGradients.Length];
+        Array.Copy(hyperparameterGradients, copy, copy.Length);
+        return copy;
+      }
+    }
+
+    [Storable]
+    private ICovarianceFunction covarianceFunction;
+    public ICovarianceFunction CovarianceFunction {
+      get { return covarianceFunction; }
+    }
+    [Storable]
+    private IMeanFunction meanFunction;
+    public IMeanFunction MeanFunction {
+      get { return meanFunction; }
+    }
+    [Storable]
+    private string targetVariable;
+    public string TargetVariable {
+      get { return targetVariable; }
+    }
+    [Storable]
+    private string[] allowedInputVariables;
+    public string[] AllowedInputVariables {
+      get { return allowedInputVariables; }
+    }
+
+    [Storable]
+    private double[] alpha;
+    [Storable]
+    private double sqrSigmaNoise;
+    public double SigmaNoise {
+      get { return Math.Sqrt(sqrSigmaNoise); }
+    }
+
+    [Storable]
+    private double[] meanParameter;
+    [Storable]
+    private double[] covarianceParameter;
+
+    private double[,] l; // used to be storable in previous versions (is calculated lazily now)
+    private double[,] x; // scaled training dataset, used to be storable in previous versions (is calculated lazily now)
+
+    // BackwardsCompatibility3.4
+    #region Backwards compatible code, remove with 3.5
+    [Storable(Name = "l")] // restore if available but don't store anymore
+    private double[,] l_storable {
+      set { this.l = value; }
+      get {
+        if (trainingDataset == null) return l; // this model has been created with an old version 
+        else return null; // if the training dataset is available l should not be serialized
+      }
+    }
+    [Storable(Name = "x")] // restore if available but don't store anymore
+    private double[,] x_storable {
+      set { this.x = value; }
+      get {
+        if (trainingDataset == null) return x; // this model has been created with an old version 
+        else return null; // if the training dataset is available x should not be serialized
+      }
+    }
+    #endregion
+
+
+    [Storable]
+    private IDataset trainingDataset; // it is better to store the original training dataset completely because this is more efficient in persistence
+    [Storable]
+    private int[] trainingRows;
+
+    [Storable]
+    private Scaling inputScaling;
+
+
+    [StorableConstructor]
+    private GaussianProcessModel(bool deserializing) : base(deserializing) { }
+    private GaussianProcessModel(GaussianProcessModel original, Cloner cloner)
+      : base(original, cloner) {
+      this.meanFunction = cloner.Clone(original.meanFunction);
+      this.covarianceFunction = cloner.Clone(original.covarianceFunction);
+      if (original.inputScaling != null)
+        this.inputScaling = cloner.Clone(original.inputScaling);
+      this.trainingDataset = cloner.Clone(original.trainingDataset);
+      this.negativeLogLikelihood = original.negativeLogLikelihood;
+      this.targetVariable = original.targetVariable;
+      this.sqrSigmaNoise = original.sqrSigmaNoise;
+      if (original.meanParameter != null) {
+        this.meanParameter = (double[])original.meanParameter.Clone();
+      }
+      if (original.covarianceParameter != null) {
+        this.covarianceParameter = (double[])original.covarianceParameter.Clone();
+      }
+
+      // shallow copies of arrays because they cannot be modified
+      this.trainingRows = original.trainingRows;
+      this.allowedInputVariables = original.allowedInputVariables;
+      this.alpha = original.alpha;
+      this.l = original.l;
+      this.x = original.x;
+    }
+    public GaussianProcessModel(IDataset ds, string targetVariable, IEnumerable<string> allowedInputVariables, IEnumerable<int> rows,
+      IEnumerable<double> hyp, IMeanFunction meanFunction, ICovarianceFunction covarianceFunction,
+      bool scaleInputs = true)
+      : base() {
+      this.name = ItemName;
+      this.description = ItemDescription;
+      this.meanFunction = (IMeanFunction)meanFunction.Clone();
+      this.covarianceFunction = (ICovarianceFunction)covarianceFunction.Clone();
+      this.targetVariable = targetVariable;
+      this.allowedInputVariables = allowedInputVariables.ToArray();
+
+
+      int nVariables = this.allowedInputVariables.Length;
+      meanParameter = hyp
+        .Take(this.meanFunction.GetNumberOfParameters(nVariables))
+        .ToArray();
+
+      covarianceParameter = hyp.Skip(this.meanFunction.GetNumberOfParameters(nVariables))
+                                             .Take(this.covarianceFunction.GetNumberOfParameters(nVariables))
+                                             .ToArray();
+      sqrSigmaNoise = Math.Exp(2.0 * hyp.Last());
+      try {
+        CalculateModel(ds, rows, scaleInputs);
+      }
+      catch (alglib.alglibexception ae) {
+        // wrap exception so that calling code doesn't have to know about alglib implementation
+        throw new ArgumentException("There was a problem in the calculation of the Gaussian process model", ae);
+      }
+    }
+
+    private void CalculateModel(IDataset ds, IEnumerable<int> rows, bool scaleInputs = true) {
+      this.trainingDataset = (IDataset)ds.Clone();
+      this.trainingRows = rows.ToArray();
+      this.inputScaling = scaleInputs ? new Scaling(ds, allowedInputVariables, rows) : null;
+
+      x = GetData(ds, this.allowedInputVariables, this.trainingRows, this.inputScaling);
+
+      IEnumerable<double> y;
+      y = ds.GetDoubleValues(targetVariable, rows);
+
+      int n = x.GetLength(0);
+
+      var columns = Enumerable.Range(0, x.GetLength(1)).ToArray();
+      // calculate cholesky decomposed (lower triangular) covariance matrix
+      var cov = covarianceFunction.GetParameterizedCovarianceFunction(covarianceParameter, columns);
+      this.l = CalculateL(x, cov, sqrSigmaNoise);
+
+      // calculate mean
+      var mean = meanFunction.GetParameterizedMeanFunction(meanParameter, columns);
+      double[] m = Enumerable.Range(0, x.GetLength(0))
+        .Select(r => mean.Mean(x, r))
+        .ToArray();
+
+      // calculate sum of diagonal elements for likelihood
+      double diagSum = Enumerable.Range(0, n).Select(i => Math.Log(l[i, i])).Sum();
+
+      // solve for alpha
+      double[] ym = y.Zip(m, (a, b) => a - b).ToArray();
+
+      int info;
+      alglib.densesolverreport denseSolveRep;
+
+      alglib.spdmatrixcholeskysolve(l, n, false, ym, out info, out denseSolveRep, out alpha);
+      for (int i = 0; i < alpha.Length; i++)
+        alpha[i] = alpha[i] / sqrSigmaNoise;
+      negativeLogLikelihood = 0.5 * Util.ScalarProd(ym, alpha) + diagSum + (n / 2.0) * Math.Log(2.0 * Math.PI * sqrSigmaNoise);
+
+      // derivatives
+      int nAllowedVariables = x.GetLength(1);
+
+      alglib.matinvreport matInvRep;
+      double[,] lCopy = new double[l.GetLength(0), l.GetLength(1)];
+      Array.Copy(l, lCopy, lCopy.Length);
+
+      alglib.spdmatrixcholeskyinverse(ref lCopy, n, false, out info, out matInvRep);
+      if (info != 1) throw new ArgumentException("Can't invert matrix to calculate gradients.");
+      for (int i = 0; i < n; i++) {
+        for (int j = 0; j <= i; j++)
+          lCopy[i, j] = lCopy[i, j] / sqrSigmaNoise - alpha[i] * alpha[j];
+      }
+
+      double noiseGradient = sqrSigmaNoise * Enumerable.Range(0, n).Select(i => lCopy[i, i]).Sum();
+
+      double[] meanGradients = new double[meanFunction.GetNumberOfParameters(nAllowedVariables)];
+      for (int k = 0; k < meanGradients.Length; k++) {
+        var meanGrad = new double[alpha.Length];
+        for (int g = 0; g < meanGrad.Length; g++)
+          meanGrad[g] = mean.Gradient(x, g, k);
+        meanGradients[k] = -Util.ScalarProd(meanGrad, alpha);
+      }
+
+      double[] covGradients = new double[covarianceFunction.GetNumberOfParameters(nAllowedVariables)];
+      if (covGradients.Length > 0) {
+        for (int i = 0; i < n; i++) {
+          for (int j = 0; j < i; j++) {
+            var g = cov.CovarianceGradient(x, i, j);
+            for (int k = 0; k < covGradients.Length; k++) {
+              covGradients[k] += lCopy[i, j] * g[k];
+            }
+          }
+
+          var gDiag = cov.CovarianceGradient(x, i, i);
+          for (int k = 0; k < covGradients.Length; k++) {
+            // diag
+            covGradients[k] += 0.5 * lCopy[i, i] * gDiag[k];
+          }
+        }
+      }
+
+      hyperparameterGradients =
+        meanGradients
+        .Concat(covGradients)
+        .Concat(new double[] { noiseGradient }).ToArray();
+
+    }
+
+    private static double[,] GetData(IDataset ds, IEnumerable<string> allowedInputs, IEnumerable<int> rows, Scaling scaling) {
+      if (scaling != null) {
+        return AlglibUtil.PrepareAndScaleInputMatrix(ds, allowedInputs, rows, scaling);
+      } else {
+        return AlglibUtil.PrepareInputMatrix(ds, allowedInputs, rows);
+      }
+    }
+
+    private static double[,] CalculateL(double[,] x, ParameterizedCovarianceFunction cov, double sqrSigmaNoise) {
+      int n = x.GetLength(0);
+      var l = new double[n, n];
+
+      // calculate covariances
+      for (int i = 0; i < n; i++) {
+        for (int j = i; j < n; j++) {
+          l[j, i] = cov.Covariance(x, i, j) / sqrSigmaNoise;
+          if (j == i) l[j, i] += 1.0;
+        }
+      }
+
+      // cholesky decomposition
+      var res = alglib.trfac.spdmatrixcholesky(ref l, n, false);
+      if (!res) throw new ArgumentException("Matrix is not positive semidefinite");
+      return l;
+    }
+
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new GaussianProcessModel(this, cloner);
+    }
+
+    // is called by the solution creator to set all parameter values of the covariance and mean function
+    // to the optimized values (necessary to make the values visible in the GUI)
+    public void FixParameters() {
+      covarianceFunction.SetParameter(covarianceParameter);
+      meanFunction.SetParameter(meanParameter);
+      covarianceParameter = new double[0];
+      meanParameter = new double[0];
+    }
+
+    #region IRegressionModel Members
+    public IEnumerable<double> GetEstimatedValues(IDataset dataset, IEnumerable<int> rows) {
+      return GetEstimatedValuesHelper(dataset, rows);
+    }
+    public GaussianProcessRegressionSolution CreateRegressionSolution(IRegressionProblemData problemData) {
+      return new GaussianProcessRegressionSolution(this, new RegressionProblemData(problemData));
+    }
+    IRegressionSolution IRegressionModel.CreateRegressionSolution(IRegressionProblemData problemData) {
+      return CreateRegressionSolution(problemData);
+    }
+    #endregion
+
+
+    private IEnumerable<double> GetEstimatedValuesHelper(IDataset dataset, IEnumerable<int> rows) {
+      try {
+        if (x == null) {
+          x = GetData(trainingDataset, allowedInputVariables, trainingRows, inputScaling);
+        }
+        int n = x.GetLength(0);
+
+        double[,] newX = GetData(dataset, allowedInputVariables, rows, inputScaling);
+        int newN = newX.GetLength(0);
+
+        var Ks = new double[newN][];
+        var columns = Enumerable.Range(0, newX.GetLength(1)).ToArray();
+        var mean = meanFunction.GetParameterizedMeanFunction(meanParameter, columns);
+        var ms = Enumerable.Range(0, newX.GetLength(0))
+        .Select(r => mean.Mean(newX, r))
+        .ToArray();
+        var cov = covarianceFunction.GetParameterizedCovarianceFunction(covarianceParameter, columns);
+        for (int i = 0; i < newN; i++) {
+          Ks[i] = new double[n];
+          for (int j = 0; j < n; j++) {
+            Ks[i][j] = cov.CrossCovariance(x, newX, j, i);
+          }
+        }
+
+        return Enumerable.Range(0, newN)
+          .Select(i => ms[i] + Util.ScalarProd(Ks[i], alpha));
+      }
+      catch (alglib.alglibexception ae) {
+        // wrap exception so that calling code doesn't have to know about alglib implementation
+        throw new ArgumentException("There was a problem in the calculation of the Gaussian process model", ae);
+      }
+    }
+
+    public IEnumerable<double> GetEstimatedVariance(IDataset dataset, IEnumerable<int> rows) {
+      try {
+        if (x == null) {
+          x = GetData(trainingDataset, allowedInputVariables, trainingRows, inputScaling);
+        }
+        int n = x.GetLength(0);
+
+        var newX = GetData(dataset, allowedInputVariables, rows, inputScaling);
+        int newN = newX.GetLength(0);
+
+        var kss = new double[newN];
+        double[,] sWKs = new double[n, newN];
+        var columns = Enumerable.Range(0, newX.GetLength(1)).ToArray();
+        var cov = covarianceFunction.GetParameterizedCovarianceFunction(covarianceParameter, columns);
+
+        if (l == null) {
+          l = CalculateL(x, cov, sqrSigmaNoise);
+        }
+
+        // for stddev 
+        for (int i = 0; i < newN; i++)
+          kss[i] = cov.Covariance(newX, i, i);
+
+        for (int i = 0; i < newN; i++) {
+          for (int j = 0; j < n; j++) {
+            sWKs[j, i] = cov.CrossCovariance(x, newX, j, i) / Math.Sqrt(sqrSigmaNoise);
+          }
+        }
+
+        // for stddev 
+        alglib.ablas.rmatrixlefttrsm(n, newN, l, 0, 0, false, false, 0, ref sWKs, 0, 0);
+
+        for (int i = 0; i < newN; i++) {
+          var col = Util.GetCol(sWKs, i).ToArray();
+          var sumV = Util.ScalarProd(col, col);
+          kss[i] += sqrSigmaNoise; // kss is V(f), add noise variance of predictive distibution to get V(y)
+          kss[i] -= sumV;
+          if (kss[i] < 0) kss[i] = 0;
+        }
+        return kss;
+      }
+      catch (alglib.alglibexception ae) {
+        // wrap exception so that calling code doesn't have to know about alglib implementation
+        throw new ArgumentException("There was a problem in the calculation of the Gaussian process model", ae);
+      }
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/GaussianProcessModelCreator.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/GaussianProcessModelCreator.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/GaussianProcessModelCreator.cs	(revision 13819)
@@ -0,0 +1,104 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Encodings.RealVectorEncoding;
+using HeuristicLab.Operators;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  [StorableClass]
+  // base class for GaussianProcessModelCreators (specific for classification and regression)
+  public abstract class GaussianProcessModelCreator : SingleSuccessorOperator {
+    private const string HyperparameterParameterName = "Hyperparameter";
+    private const string MeanFunctionParameterName = "MeanFunction";
+    private const string CovarianceFunctionParameterName = "CovarianceFunction";
+    private const string ModelParameterName = "Model";
+    private const string NegativeLogLikelihoodParameterName = "NegativeLogLikelihood";
+    private const string HyperparameterGradientsParameterName = "HyperparameterGradients";
+    protected const string ScaleInputValuesParameterName = "ScaleInputValues";
+
+    #region Parameter Properties
+    // in
+    public ILookupParameter<RealVector> HyperparameterParameter {
+      get { return (ILookupParameter<RealVector>)Parameters[HyperparameterParameterName]; }
+    }
+    public ILookupParameter<IMeanFunction> MeanFunctionParameter {
+      get { return (ILookupParameter<IMeanFunction>)Parameters[MeanFunctionParameterName]; }
+    }
+    public ILookupParameter<ICovarianceFunction> CovarianceFunctionParameter {
+      get { return (ILookupParameter<ICovarianceFunction>)Parameters[CovarianceFunctionParameterName]; }
+    }
+    // out
+    public ILookupParameter<IGaussianProcessModel> ModelParameter {
+      get { return (ILookupParameter<IGaussianProcessModel>)Parameters[ModelParameterName]; }
+    }
+    public ILookupParameter<RealVector> HyperparameterGradientsParameter {
+      get { return (ILookupParameter<RealVector>)Parameters[HyperparameterGradientsParameterName]; }
+    }
+    public ILookupParameter<DoubleValue> NegativeLogLikelihoodParameter {
+      get { return (ILookupParameter<DoubleValue>)Parameters[NegativeLogLikelihoodParameterName]; }
+    }
+    public ILookupParameter<BoolValue> ScaleInputValuesParameter {
+      get { return (ILookupParameter<BoolValue>)Parameters[ScaleInputValuesParameterName]; }
+    }
+    #endregion
+
+    #region Properties
+    protected RealVector Hyperparameter { get { return HyperparameterParameter.ActualValue; } }
+    protected IMeanFunction MeanFunction { get { return MeanFunctionParameter.ActualValue; } }
+    protected ICovarianceFunction CovarianceFunction { get { return CovarianceFunctionParameter.ActualValue; } }
+    public bool ScaleInputValues { get { return ScaleInputValuesParameter.ActualValue.Value; } }
+    #endregion
+
+    [StorableConstructor]
+    protected GaussianProcessModelCreator(bool deserializing) : base(deserializing) { }
+    protected GaussianProcessModelCreator(GaussianProcessModelCreator original, Cloner cloner) : base(original, cloner) { }
+    protected GaussianProcessModelCreator()
+      : base() {
+      // in
+      Parameters.Add(new LookupParameter<RealVector>(HyperparameterParameterName, "The hyperparameters for the Gaussian process model."));
+      Parameters.Add(new LookupParameter<IMeanFunction>(MeanFunctionParameterName, "The mean function for the Gaussian process model."));
+      Parameters.Add(new LookupParameter<ICovarianceFunction>(CovarianceFunctionParameterName, "The covariance function for the Gaussian process model."));
+      // out
+      Parameters.Add(new LookupParameter<IGaussianProcessModel>(ModelParameterName, "The resulting Gaussian process model"));
+      Parameters.Add(new LookupParameter<RealVector>(HyperparameterGradientsParameterName, "The gradients of the hyperparameters for the produced Gaussian process model (necessary for hyperparameter optimization)"));
+      Parameters.Add(new LookupParameter<DoubleValue>(NegativeLogLikelihoodParameterName, "The negative log-likelihood of the produced Gaussian process model given the data."));
+
+
+      Parameters.Add(new LookupParameter<BoolValue>(ScaleInputValuesParameterName,
+        "Determines if the input variable values are scaled to the range [0..1] for training."));
+      Parameters[ScaleInputValuesParameterName].Hidden = true;
+    }
+
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() {
+      if (!Parameters.ContainsKey(ScaleInputValuesParameterName)) {
+        Parameters.Add(new LookupParameter<BoolValue>(ScaleInputValuesParameterName,
+          "Determines if the input variable values are scaled to the range [0..1] for training."));
+        Parameters[ScaleInputValuesParameterName].Hidden = true;
+      }
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/GaussianProcessRegression.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/GaussianProcessRegression.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/GaussianProcessRegression.cs	(revision 13819)
@@ -0,0 +1,155 @@
+
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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 HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Optimization;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.PluginInfrastructure;
+using HeuristicLab.Problems.DataAnalysis;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  /// <summary>
+  ///Gaussian process regression data analysis algorithm.
+  /// </summary>
+  [Item("Gaussian Process Regression", "Gaussian process regression data analysis algorithm.")]
+  [Creatable(CreatableAttribute.Categories.DataAnalysisRegression, Priority = 160)]
+  [StorableClass]
+  public sealed class GaussianProcessRegression : GaussianProcessBase, IStorableContent {
+    public string Filename { get; set; }
+
+    public override Type ProblemType { get { return typeof(IRegressionProblem); } }
+    public new IRegressionProblem Problem {
+      get { return (IRegressionProblem)base.Problem; }
+      set { base.Problem = value; }
+    }
+
+    private const string ModelParameterName = "Model";
+    private const string CreateSolutionParameterName = "CreateSolution";
+
+
+    #region parameter properties
+    public IConstrainedValueParameter<IGaussianProcessRegressionModelCreator> GaussianProcessModelCreatorParameter {
+      get { return (IConstrainedValueParameter<IGaussianProcessRegressionModelCreator>)Parameters[ModelCreatorParameterName]; }
+    }
+    public IFixedValueParameter<GaussianProcessRegressionSolutionCreator> GaussianProcessSolutionCreatorParameter {
+      get { return (IFixedValueParameter<GaussianProcessRegressionSolutionCreator>)Parameters[SolutionCreatorParameterName]; }
+    }
+    public IFixedValueParameter<BoolValue> CreateSolutionParameter {
+      get { return (IFixedValueParameter<BoolValue>)Parameters[CreateSolutionParameterName]; }
+    }
+    #endregion
+    #region properties
+    public bool CreateSolution {
+      get { return CreateSolutionParameter.Value.Value; }
+      set { CreateSolutionParameter.Value.Value = value; }
+    }
+    #endregion
+
+    [StorableConstructor]
+    private GaussianProcessRegression(bool deserializing) : base(deserializing) { }
+    private GaussianProcessRegression(GaussianProcessRegression original, Cloner cloner)
+      : base(original, cloner) {
+      RegisterEventHandlers();
+    }
+    public GaussianProcessRegression()
+      : base(new RegressionProblem()) {
+      this.name = ItemName;
+      this.description = ItemDescription;
+
+      var modelCreators = ApplicationManager.Manager.GetInstances<IGaussianProcessRegressionModelCreator>();
+      var defaultModelCreator = modelCreators.First(c => c is GaussianProcessRegressionModelCreator);
+
+      // GP regression and classification algorithms only differ in the model and solution creators,
+      // thus we use a common base class and use operator parameters to implement the specific versions.
+      // Different model creators can be implemented,
+      // but the solution creator is implemented in a generic fashion already and we don't allow derived solution creators
+      Parameters.Add(new ConstrainedValueParameter<IGaussianProcessRegressionModelCreator>(ModelCreatorParameterName, "The operator to create the Gaussian process model.",
+        new ItemSet<IGaussianProcessRegressionModelCreator>(modelCreators), defaultModelCreator));
+      // the solution creator cannot be changed
+      Parameters.Add(new FixedValueParameter<GaussianProcessRegressionSolutionCreator>(SolutionCreatorParameterName, "The solution creator for the algorithm",
+        new GaussianProcessRegressionSolutionCreator()));
+      Parameters[SolutionCreatorParameterName].Hidden = true;
+      // TODO: it would be better to deactivate the solution creator when this parameter is changed
+      Parameters.Add(new FixedValueParameter<BoolValue>(CreateSolutionParameterName, "Flag that indicates if a solution should be produced at the end of the run", new BoolValue(true)));
+      Parameters[CreateSolutionParameterName].Hidden = true;
+
+      ParameterizedModelCreators();
+      ParameterizeSolutionCreator(GaussianProcessSolutionCreatorParameter.Value);
+      RegisterEventHandlers();
+    }
+
+
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() {
+      // BackwardsCompatibility3.3
+      #region Backwards compatible code, remove with 3.4
+      if (!Parameters.ContainsKey(CreateSolutionParameterName)) {
+        Parameters.Add(new FixedValueParameter<BoolValue>(CreateSolutionParameterName, "Flag that indicates if a solution should be produced at the end of the run", new BoolValue(true)));
+        Parameters[CreateSolutionParameterName].Hidden = true;
+      }
+      #endregion
+      RegisterEventHandlers();
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new GaussianProcessRegression(this, cloner);
+    }
+
+    #region events
+    private void RegisterEventHandlers() {
+      GaussianProcessModelCreatorParameter.ValueChanged += ModelCreatorParameter_ValueChanged;
+    }
+
+    private void ModelCreatorParameter_ValueChanged(object sender, EventArgs e) {
+      ParameterizedModelCreator(GaussianProcessModelCreatorParameter.Value);
+    }
+    #endregion
+
+    private void ParameterizedModelCreators() {
+      foreach (var creator in GaussianProcessModelCreatorParameter.ValidValues) {
+        ParameterizedModelCreator(creator);
+      }
+    }
+
+    private void ParameterizedModelCreator(IGaussianProcessRegressionModelCreator modelCreator) {
+      modelCreator.ProblemDataParameter.ActualName = Problem.ProblemDataParameter.Name;
+      modelCreator.MeanFunctionParameter.ActualName = MeanFunctionParameterName;
+      modelCreator.CovarianceFunctionParameter.ActualName = CovarianceFunctionParameterName;
+
+      // parameter names fixed by the algorithm
+      modelCreator.ModelParameter.ActualName = ModelParameterName;
+      modelCreator.HyperparameterParameter.ActualName = HyperparameterParameterName;
+      modelCreator.HyperparameterGradientsParameter.ActualName = HyperparameterGradientsParameterName;
+      modelCreator.NegativeLogLikelihoodParameter.ActualName = NegativeLogLikelihoodParameterName;
+    }
+
+    private void ParameterizeSolutionCreator(GaussianProcessRegressionSolutionCreator solutionCreator) {
+      solutionCreator.ModelParameter.ActualName = ModelParameterName;
+      solutionCreator.ProblemDataParameter.ActualName = Problem.ProblemDataParameter.Name;
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/GaussianProcessRegressionModelCreator.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/GaussianProcessRegressionModelCreator.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/GaussianProcessRegressionModelCreator.cs	(revision 13819)
@@ -0,0 +1,81 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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 HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Encodings.RealVectorEncoding;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Problems.DataAnalysis;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  [StorableClass]
+  [Item(Name = "GaussianProcessRegressionModelCreator",
+    Description = "Creates a Gaussian process model for regression given the data, the hyperparameters, a mean function, and a covariance function.")]
+  public sealed class GaussianProcessRegressionModelCreator : GaussianProcessModelCreator, IGaussianProcessRegressionModelCreator {
+    private const string ProblemDataParameterName = "ProblemData";
+
+    #region Parameter Properties
+    public ILookupParameter<IRegressionProblemData> ProblemDataParameter {
+      get { return (ILookupParameter<IRegressionProblemData>)Parameters[ProblemDataParameterName]; }
+    }
+    #endregion
+
+    #region Properties
+    private IRegressionProblemData ProblemData {
+      get { return ProblemDataParameter.ActualValue; }
+    }
+    #endregion
+    [StorableConstructor]
+    private GaussianProcessRegressionModelCreator(bool deserializing) : base(deserializing) { }
+    private GaussianProcessRegressionModelCreator(GaussianProcessRegressionModelCreator original, Cloner cloner) : base(original, cloner) { }
+    public GaussianProcessRegressionModelCreator()
+      : base() {
+      Parameters.Add(new LookupParameter<IRegressionProblemData>(ProblemDataParameterName, "The regression problem data for the Gaussian process model."));
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new GaussianProcessRegressionModelCreator(this, cloner);
+    }
+
+    public override IOperation Apply() {
+      try {
+        var model = Create(ProblemData, Hyperparameter.ToArray(), MeanFunction, CovarianceFunction, ScaleInputValues);
+        ModelParameter.ActualValue = model;
+        NegativeLogLikelihoodParameter.ActualValue = new DoubleValue(model.NegativeLogLikelihood);
+        HyperparameterGradientsParameter.ActualValue = new RealVector(model.HyperparameterGradients);
+        return base.Apply();
+      }
+      catch (ArgumentException) { }
+      catch (alglib.alglibexception) { }
+      NegativeLogLikelihoodParameter.ActualValue = new DoubleValue(1E300);
+      HyperparameterGradientsParameter.ActualValue = new RealVector(Hyperparameter.Count());
+      return base.Apply();
+    }
+
+    public static IGaussianProcessModel Create(IRegressionProblemData problemData, double[] hyperparameter, IMeanFunction meanFunction, ICovarianceFunction covarianceFunction, bool scaleInputs = true) {
+      return new GaussianProcessModel(problemData.Dataset, problemData.TargetVariable, problemData.AllowedInputVariables, problemData.TrainingIndices, hyperparameter, meanFunction, covarianceFunction, scaleInputs);
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/GaussianProcessRegressionSolution.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/GaussianProcessRegressionSolution.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/GaussianProcessRegressionSolution.cs	(revision 13819)
@@ -0,0 +1,94 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Problems.DataAnalysis;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  /// <summary>
+  /// Represents a Gaussian process solution for a regression problem which can be visualized in the GUI.
+  /// </summary>
+  [Item("GaussianProcessRegressionSolution", "Represents a Gaussian process solution for a regression problem which can be visualized in the GUI.")]
+  [StorableClass]
+  public sealed class GaussianProcessRegressionSolution : RegressionSolution, IGaussianProcessSolution {
+    private new readonly Dictionary<int, double> evaluationCache;
+
+    public new IGaussianProcessModel Model {
+      get { return (IGaussianProcessModel)base.Model; }
+      set { base.Model = value; }
+    }
+
+    [StorableConstructor]
+    private GaussianProcessRegressionSolution(bool deserializing)
+      : base(deserializing) {
+      evaluationCache = new Dictionary<int, double>();
+
+    }
+    private GaussianProcessRegressionSolution(GaussianProcessRegressionSolution original, Cloner cloner)
+      : base(original, cloner) {
+      evaluationCache = new Dictionary<int, double>(original.evaluationCache);
+    }
+    public GaussianProcessRegressionSolution(IGaussianProcessModel model, IRegressionProblemData problemData)
+      : base(model, problemData) {
+
+      evaluationCache = new Dictionary<int, double>(problemData.Dataset.Rows);
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new GaussianProcessRegressionSolution(this, cloner);
+    }
+
+    public IEnumerable<double> EstimatedVariance {
+      get { return GetEstimatedVariance(Enumerable.Range(0, ProblemData.Dataset.Rows)); }
+    }
+    public IEnumerable<double> EstimatedTrainingVariance {
+      get { return GetEstimatedVariance(ProblemData.TrainingIndices); }
+    }
+    public IEnumerable<double> EstimatedTestVariance {
+      get { return GetEstimatedVariance(ProblemData.TestIndices); }
+    }
+
+    public IEnumerable<double> GetEstimatedVariance(IEnumerable<int> rows) {
+      var rowsToEvaluate = rows.Except(evaluationCache.Keys);
+      var rowsEnumerator = rowsToEvaluate.GetEnumerator();
+      var valuesEnumerator = Model.GetEstimatedVariance(ProblemData.Dataset, rowsToEvaluate).GetEnumerator();
+
+      while (rowsEnumerator.MoveNext() & valuesEnumerator.MoveNext()) {
+        evaluationCache.Add(rowsEnumerator.Current, valuesEnumerator.Current);
+      }
+
+      return rows.Select(row => evaluationCache[row]);
+    }
+
+    protected override void OnModelChanged() {
+      evaluationCache.Clear();
+      base.OnModelChanged();
+    }
+    protected override void OnProblemDataChanged() {
+      evaluationCache.Clear();
+      base.OnProblemDataChanged();
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/GaussianProcessRegressionSolutionCreator.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/GaussianProcessRegressionSolutionCreator.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/GaussianProcessRegressionSolutionCreator.cs	(revision 13819)
@@ -0,0 +1,119 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Operators;
+using HeuristicLab.Optimization;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Problems.DataAnalysis;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  [StorableClass]
+  [Item(Name = "GaussianProcessRegressionSolutionCreator",
+    Description = "Creates a Gaussian process solution from a trained model.")]
+  public sealed class GaussianProcessRegressionSolutionCreator : SingleSuccessorOperator {
+    private const string ProblemDataParameterName = "ProblemData";
+    private const string ModelParameterName = "GaussianProcessRegressionModel";
+    private const string SolutionParameterName = "Solution";
+    private const string ResultsParameterName = "Results";
+    private const string TrainingRSquaredResultName = "Training R²";
+    private const string TestRSquaredResultName = "Test R²";
+    private const string CreateSolutionParameterName = "CreateSolution";
+
+    #region Parameter Properties
+    public ILookupParameter<IRegressionProblemData> ProblemDataParameter {
+      get { return (ILookupParameter<IRegressionProblemData>)Parameters[ProblemDataParameterName]; }
+    }
+    public ILookupParameter<IGaussianProcessSolution> SolutionParameter {
+      get { return (ILookupParameter<IGaussianProcessSolution>)Parameters[SolutionParameterName]; }
+    }
+    public ILookupParameter<IGaussianProcessModel> ModelParameter {
+      get { return (ILookupParameter<IGaussianProcessModel>)Parameters[ModelParameterName]; }
+    }
+    public ILookupParameter<ResultCollection> ResultsParameter {
+      get { return (ILookupParameter<ResultCollection>)Parameters[ResultsParameterName]; }
+    }
+    public ILookupParameter<BoolValue> CreateSolutionParameter {
+      get { return (ILookupParameter<BoolValue>)Parameters[CreateSolutionParameterName]; }
+    }
+    #endregion
+
+    [StorableConstructor]
+    private GaussianProcessRegressionSolutionCreator(bool deserializing) : base(deserializing) { }
+    private GaussianProcessRegressionSolutionCreator(GaussianProcessRegressionSolutionCreator original, Cloner cloner) : base(original, cloner) { }
+    public GaussianProcessRegressionSolutionCreator()
+      : base() {
+      // in
+      Parameters.Add(new LookupParameter<IRegressionProblemData>(ProblemDataParameterName, "The regression problem data for the Gaussian process solution."));
+      Parameters.Add(new LookupParameter<IGaussianProcessModel>(ModelParameterName, "The Gaussian process regression model to use for the solution."));
+      Parameters.Add(new LookupParameter<BoolValue>(CreateSolutionParameterName, "Flag that indicates if a solution should be produced at the end of the run"));
+
+      // in & out
+      Parameters.Add(new LookupParameter<ResultCollection>(ResultsParameterName, "The result collection of the algorithm."));
+      // out
+      Parameters.Add(new LookupParameter<IGaussianProcessSolution>(SolutionParameterName, "The produced Gaussian process solution."));
+    }
+
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() {
+      // BackwardsCompatibility3.3
+      #region Backwards compatible code, remove with 3.4
+      if (!Parameters.ContainsKey(CreateSolutionParameterName)) {
+        Parameters.Add(new LookupParameter<BoolValue>(CreateSolutionParameterName, "Flag that indicates if a solution should be produced at the end of the run"));
+      }
+      #endregion
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new GaussianProcessRegressionSolutionCreator(this, cloner);
+    }
+
+    public override IOperation Apply() {
+      if (ModelParameter.ActualValue != null && CreateSolutionParameter.ActualValue.Value == true) {
+        var m = (IGaussianProcessModel)ModelParameter.ActualValue.Clone();
+        m.FixParameters();
+        var data = (IRegressionProblemData)ProblemDataParameter.ActualValue.Clone();
+        var s = new GaussianProcessRegressionSolution(m, data);
+
+
+        SolutionParameter.ActualValue = s;
+        var results = ResultsParameter.ActualValue;
+        if (!results.ContainsKey(SolutionParameterName)) {
+          results.Add(new Result(SolutionParameterName, "The Gaussian process regression solution", s));
+          results.Add(new Result(TrainingRSquaredResultName,
+                                 "The Pearson's R² of the Gaussian process solution on the training partition.",
+                                 new DoubleValue(s.TrainingRSquared)));
+          results.Add(new Result(TestRSquaredResultName,
+                                 "The Pearson's R² of the Gaussian process solution on the test partition.",
+                                 new DoubleValue(s.TestRSquared)));
+        } else {
+          results[SolutionParameterName].Value = s;
+          results[TrainingRSquaredResultName].Value = new DoubleValue(s.TrainingRSquared);
+          results[TestRSquaredResultName].Value = new DoubleValue(s.TestRSquared);
+        }
+      }
+      return base.Apply();
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/ICovarianceFunction.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/ICovarianceFunction.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/ICovarianceFunction.cs	(revision 13819)
@@ -0,0 +1,42 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Collections.Generic;
+using HeuristicLab.Core;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+
+  public delegate double CovarianceFunctionDelegate(double[,] x, int i, int j);
+  public delegate double CrossCovarianceFunctionDelegate(double[,] x, double[,] xt, int i, int j);
+  public delegate IList<double> CovarianceGradientFunctionDelegate(double[,] x, int i, int j);
+
+  public class ParameterizedCovarianceFunction {
+    public CovarianceFunctionDelegate Covariance { get; set; }
+    public CrossCovarianceFunctionDelegate CrossCovariance { get; set; }
+    public CovarianceGradientFunctionDelegate CovarianceGradient { get; set; }
+  }
+
+  public interface ICovarianceFunction : IItem {
+    int GetNumberOfParameters(int numberOfVariables);
+    void SetParameter(double[] p);
+    ParameterizedCovarianceFunction GetParameterizedCovarianceFunction(double[] p, int[] columnIndices);
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/IMeanFunction.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/IMeanFunction.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/IMeanFunction.cs	(revision 13819)
@@ -0,0 +1,38 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using HeuristicLab.Core;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  public delegate double MeanFunctionDelegate(double[,] x, int row);
+  public delegate double MeanGradientDelegate(double[,] x, int row, int k);
+
+  public class ParameterizedMeanFunction {
+    public MeanFunctionDelegate Mean { get; set; }
+    public MeanGradientDelegate Gradient { get; set; }
+  }
+
+  public interface IMeanFunction : IItem {
+    int GetNumberOfParameters(int numberOfVariables);
+    void SetParameter(double[] p);
+    ParameterizedMeanFunction GetParameterizedMeanFunction(double[] p, int[] columnIndices);
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/MeanFunctions/MeanConst.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/MeanFunctions/MeanConst.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/MeanFunctions/MeanConst.cs	(revision 13819)
@@ -0,0 +1,90 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  [StorableClass]
+  [Item(Name = "MeanConst", Description = "Constant mean function for Gaussian processes.")]
+  public sealed class MeanConst : ParameterizedNamedItem, IMeanFunction {
+    public IValueParameter<DoubleValue> ValueParameter {
+      get { return (IValueParameter<DoubleValue>)Parameters["Value"]; }
+    }
+
+    [StorableConstructor]
+    private MeanConst(bool deserializing) : base(deserializing) { }
+    private MeanConst(MeanConst original, Cloner cloner)
+      : base(original, cloner) {
+    }
+    public MeanConst()
+      : base() {
+      this.name = ItemName;
+      this.description = ItemDescription;
+
+      Parameters.Add(new OptionalValueParameter<DoubleValue>("Value", "The constant value for the constant mean function."));
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new MeanConst(this, cloner);
+    }
+
+    public int GetNumberOfParameters(int numberOfVariables) {
+      return ValueParameter.Value != null ? 0 : 1;
+    }
+
+    public void SetParameter(double[] p) {
+      double c;
+      GetParameters(p, out c);
+      ValueParameter.Value = new DoubleValue(c);
+    }
+
+    private void GetParameters(double[] p, out double c) {
+      if (ValueParameter.Value == null) {
+        c = p[0];
+      } else {
+        if (p.Length > 0)
+          throw new ArgumentException(
+            "The length of the parameter vector does not match the number of free parameters for the constant mean function.",
+            "p");
+        c = ValueParameter.Value.Value;
+      }
+    }
+
+    public ParameterizedMeanFunction GetParameterizedMeanFunction(double[] p, int[] columnIndices) {
+      double c;
+      GetParameters(p, out c);
+      var mf = new ParameterizedMeanFunction();
+      mf.Mean = (x, i) => c;
+      mf.Gradient = (x, i, k) => {
+        if (k > 0) throw new ArgumentException();
+        return 1.0;
+      };
+      return mf;
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/MeanFunctions/MeanLinear.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/MeanFunctions/MeanLinear.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/MeanFunctions/MeanLinear.cs	(revision 13819)
@@ -0,0 +1,88 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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 HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  [StorableClass]
+  [Item(Name = "MeanLinear", Description = "Linear mean function for Gaussian processes.")]
+  public sealed class MeanLinear : ParameterizedNamedItem, IMeanFunction {
+    public IValueParameter<DoubleArray> WeightsParameter {
+      get { return (IValueParameter<DoubleArray>)Parameters["Weights"]; }
+    }
+
+    [StorableConstructor]
+    private MeanLinear(bool deserializing) : base(deserializing) { }
+    private MeanLinear(MeanLinear original, Cloner cloner)
+      : base(original, cloner) {
+    }
+    public MeanLinear()
+      : base() {
+      Parameters.Add(new OptionalValueParameter<DoubleArray>("Weights", "The weights parameter for the linear mean function."));
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new MeanLinear(this, cloner);
+    }
+
+    public int GetNumberOfParameters(int numberOfVariables) {
+      return WeightsParameter.Value != null ? 0 : numberOfVariables;
+    }
+
+    public void SetParameter(double[] p) {
+      double[] weights;
+      GetParameter(p, out weights);
+      WeightsParameter.Value = new DoubleArray(weights);
+    }
+
+    public void GetParameter(double[] p, out double[] weights) {
+      if (WeightsParameter.Value == null) {
+        weights = p;
+      } else {
+        if (p.Length != 0) throw new ArgumentException("The length of the parameter vector does not match the number of free parameters for the linear mean function.", "p");
+        weights = WeightsParameter.Value.ToArray();
+      }
+    }
+
+    public ParameterizedMeanFunction GetParameterizedMeanFunction(double[] p, int[] columnIndices) {
+      double[] weights;
+      int[] columns = columnIndices;
+      GetParameter(p, out weights);
+      var mf = new ParameterizedMeanFunction();
+      mf.Mean = (x, i) => {
+        // sanity check
+        if (weights.Length != columns.Length) throw new ArgumentException("The number of rparameters must match the number of variables for the linear mean function.");
+        return Util.ScalarProd(weights, Util.GetRow(x, i, columns).ToArray());
+      };
+      mf.Gradient = (x, i, k) => {
+        if (k > columns.Length) throw new ArgumentException();
+        return x[i, columns[k]];
+      };
+      return mf;
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/MeanFunctions/MeanModel.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/MeanFunctions/MeanModel.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/MeanFunctions/MeanModel.cs	(revision 13819)
@@ -0,0 +1,98 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Problems.DataAnalysis;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  [StorableClass]
+  [Item(Name = "MeanModel", Description = "A mean function for Gaussian processes that uses a regression solution created with a different algorithm to calculate the mean.")]
+  // essentially an adaptor which maps from IMeanFunction to IRegressionSolution
+  public sealed class MeanModel : ParameterizedNamedItem, IMeanFunction {
+    public IValueParameter<IRegressionSolution> RegressionSolutionParameter {
+      get { return (IValueParameter<IRegressionSolution>)Parameters["RegressionSolution"]; }
+    }
+    public IRegressionSolution RegressionSolution {
+      get { return RegressionSolutionParameter.Value; }
+      set { RegressionSolutionParameter.Value = value; }
+    }
+
+    [StorableConstructor]
+    private MeanModel(bool deserializing) : base(deserializing) { }
+    private MeanModel(MeanModel original, Cloner cloner)
+      : base(original, cloner) {
+    }
+
+    public MeanModel()
+      : base("MeanModel", "A mean function for Gaussian processes that uses a regression solution created with a different algorithm to calculate the mean.") {
+      Parameters.Add(new ValueParameter<IRegressionSolution>("RegressionSolution", "The solution containing the model that should be used for the mean prediction."));
+    }
+
+    public MeanModel(IRegressionSolution solution)
+      : this() {
+      // here we cannot check if the model is actually compatible (uses only input variables that are available)
+      // we only assume that the list of allowed inputs in the regression solution is the same as the list of allowed
+      // inputs in the Gaussian process.
+      // later we might get an error or bad behaviour when the mean function is evaluated
+      RegressionSolution = solution;
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new MeanModel(this, cloner);
+    }
+
+    public int GetNumberOfParameters(int numberOfVariables) {
+      return 0; // no support for hyperparameters for regression models yet
+    }
+
+    public void SetParameter(double[] p) {
+      if (p.Length > 0) throw new ArgumentException("No parameters allowed for model-based mean function.", "p");
+    }
+
+    public ParameterizedMeanFunction GetParameterizedMeanFunction(double[] p, int[] columnIndices) {
+      if (p.Length > 0) throw new ArgumentException("No parameters allowed for model-based mean function.", "p");
+      var solution = RegressionSolution;
+      var variableNames = solution.ProblemData.AllowedInputVariables.ToArray();
+      if (variableNames.Length != columnIndices.Length)
+        throw new ArgumentException("The number of input variables does not match in MeanModel");
+      var variableValues = variableNames.Select(_ => new List<double>() { 0.0 }).ToArray(); // or of zeros
+      // uses modifyable dataset to pass values to the model
+      var ds = new ModifiableDataset(variableNames, variableValues);
+      var mf = new ParameterizedMeanFunction();
+      var model = solution.Model; // effort for parameter access only once
+      mf.Mean = (x, i) => {
+        ds.ReplaceRow(0, Util.GetRow(x, i, columnIndices).OfType<object>());
+        return model.GetEstimatedValues(ds, 0.ToEnumerable()).Single(); // evaluate the model on the specified row only
+      };
+      mf.Gradient = (x, i, k) => {
+        if (k > 0)
+          throw new ArgumentException();
+        return 0.0;
+      };
+      return mf;
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/MeanFunctions/MeanProduct.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/MeanFunctions/MeanProduct.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/MeanFunctions/MeanProduct.cs	(revision 13819)
@@ -0,0 +1,113 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  [StorableClass]
+  [Item(Name = "MeanProduct", Description = "Product of mean functions for Gaussian processes.")]
+  public sealed class MeanProduct : Item, IMeanFunction {
+    [Storable]
+    private ItemList<IMeanFunction> factors;
+
+    [Storable]
+    private int numberOfVariables;
+
+    public ItemList<IMeanFunction> Factors {
+      get { return factors; }
+    }
+
+    [StorableConstructor]
+    private MeanProduct(bool deserializing)
+      : base(deserializing) {
+    }
+
+    private MeanProduct(MeanProduct original, Cloner cloner)
+      : base(original, cloner) {
+      this.factors = cloner.Clone(original.factors);
+      this.numberOfVariables = original.numberOfVariables;
+    }
+
+    public MeanProduct() {
+      this.factors = new ItemList<IMeanFunction>();
+    }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new MeanProduct(this, cloner);
+    }
+
+    public int GetNumberOfParameters(int numberOfVariables) {
+      this.numberOfVariables = numberOfVariables;
+      return factors.Select(t => t.GetNumberOfParameters(numberOfVariables)).Sum();
+    }
+
+    public void SetParameter(double[] p) {
+      int offset = 0;
+      foreach (var t in factors) {
+        var numberOfParameters = t.GetNumberOfParameters(numberOfVariables);
+        t.SetParameter(p.Skip(offset).Take(numberOfParameters).ToArray());
+        offset += numberOfParameters;
+      }
+    }
+
+
+    public ParameterizedMeanFunction GetParameterizedMeanFunction(double[] p, int[] columnIndices) {
+      var factorMf = new List<ParameterizedMeanFunction>();
+      int totalNumberOfParameters = GetNumberOfParameters(numberOfVariables);
+      int[] factorIndexMap = new int[totalNumberOfParameters]; // maps k-th hyperparameter to the correct mean-term
+      int[] hyperParameterIndexMap = new int[totalNumberOfParameters]; // maps k-th hyperparameter to the l-th hyperparameter of the correct mean-term
+      int c = 0;
+      // get the parameterized mean function for each term
+      for (int factorIndex = 0; factorIndex < factors.Count; factorIndex++) {
+        var numberOfParameters = factors[factorIndex].GetNumberOfParameters(numberOfVariables);
+        factorMf.Add(factors[factorIndex].GetParameterizedMeanFunction(p.Take(numberOfParameters).ToArray(), columnIndices));
+        p = p.Skip(numberOfParameters).ToArray();
+
+        for (int hyperParameterIndex = 0; hyperParameterIndex < numberOfParameters; hyperParameterIndex++) {
+          factorIndexMap[c] = factorIndex;
+          hyperParameterIndexMap[c] = hyperParameterIndex;
+          c++;
+        }
+      }
+
+      var mf = new ParameterizedMeanFunction();
+      mf.Mean = (x, i) => factorMf.Select(t => t.Mean(x, i)).Aggregate((a, b) => a * b);
+      mf.Gradient = (x, i, k) => {
+        double result = 1.0;
+        int hyperParameterFactorIndex = factorIndexMap[k];
+        for (int factorIndex = 0; factorIndex < factors.Count; factorIndex++) {
+          if (factorIndex == hyperParameterFactorIndex) {
+            // multiply gradient
+            result *= factorMf[factorIndex].Gradient(x, i, hyperParameterIndexMap[k]);
+          } else {
+            // multiply mean
+            result *= factorMf[factorIndex].Mean(x, i);
+          }
+        }
+        return result;
+      };
+      return mf;
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/MeanFunctions/MeanSum.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/MeanFunctions/MeanSum.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/MeanFunctions/MeanSum.cs	(revision 13819)
@@ -0,0 +1,97 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  [StorableClass]
+  [Item(Name = "MeanSum", Description = "Sum of mean functions for Gaussian processes.")]
+  public sealed class MeanSum : Item, IMeanFunction {
+    [Storable]
+    private ItemList<IMeanFunction> terms;
+
+    [Storable]
+    private int numberOfVariables;
+    public ItemList<IMeanFunction> Terms {
+      get { return terms; }
+    }
+
+    [StorableConstructor]
+    private MeanSum(bool deserializing) : base(deserializing) { }
+    private MeanSum(MeanSum original, Cloner cloner)
+      : base(original, cloner) {
+      this.terms = cloner.Clone(original.terms);
+      this.numberOfVariables = original.numberOfVariables;
+    }
+    public MeanSum() {
+      this.terms = new ItemList<IMeanFunction>();
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new MeanSum(this, cloner);
+    }
+
+    public int GetNumberOfParameters(int numberOfVariables) {
+      this.numberOfVariables = numberOfVariables;
+      return terms.Select(t => t.GetNumberOfParameters(numberOfVariables)).Sum();
+    }
+
+    public void SetParameter(double[] p) {
+      int offset = 0;
+      foreach (var t in terms) {
+        var numberOfParameters = t.GetNumberOfParameters(numberOfVariables);
+        t.SetParameter(p.Skip(offset).Take(numberOfParameters).ToArray());
+        offset += numberOfParameters;
+      }
+    }
+
+    public ParameterizedMeanFunction GetParameterizedMeanFunction(double[] p, int[] columnIndices) {
+      var termMf = new List<ParameterizedMeanFunction>();
+      int totalNumberOfParameters = GetNumberOfParameters(numberOfVariables);
+      int[] termIndexMap = new int[totalNumberOfParameters]; // maps k-th parameter to the correct mean-term
+      int[] hyperParameterIndexMap = new int[totalNumberOfParameters]; // maps k-th parameter to the l-th parameter of the correct mean-term
+      int c = 0;
+      // get the parameterized mean function for each term
+      for (int termIndex = 0; termIndex < terms.Count; termIndex++) {
+        var numberOfParameters = terms[termIndex].GetNumberOfParameters(numberOfVariables);
+        termMf.Add(terms[termIndex].GetParameterizedMeanFunction(p.Take(numberOfParameters).ToArray(), columnIndices));
+        p = p.Skip(numberOfParameters).ToArray();
+
+        for (int hyperParameterIndex = 0; hyperParameterIndex < numberOfParameters; hyperParameterIndex++) {
+          termIndexMap[c] = termIndex;
+          hyperParameterIndexMap[c] = hyperParameterIndex;
+          c++;
+        }
+      }
+
+      var mf = new ParameterizedMeanFunction();
+      mf.Mean = (x, i) => termMf.Select(t => t.Mean(x, i)).Sum();
+      mf.Gradient = (x, i, k) => {
+        return termMf[termIndexMap[k]].Gradient(x, i, hyperParameterIndexMap[k]);
+      };
+      return mf;
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/MeanFunctions/MeanZero.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/MeanFunctions/MeanZero.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/MeanFunctions/MeanZero.cs	(revision 13819)
@@ -0,0 +1,62 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+using System;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  [StorableClass]
+  [Item(Name = "MeanZero", Description = "Constant zero mean function for Gaussian processes.")]
+  public sealed class MeanZero : Item, IMeanFunction {
+    [StorableConstructor]
+    private MeanZero(bool deserializing) : base(deserializing) { }
+    private MeanZero(MeanZero original, Cloner cloner)
+      : base(original, cloner) {
+    }
+    public MeanZero() {
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new MeanZero(this, cloner);
+    }
+
+    public int GetNumberOfParameters(int numberOfVariables) {
+      return 0;
+    }
+
+    public void SetParameter(double[] p) {
+      if (p.Length > 0) throw new ArgumentException("No parameters allowed for zero mean function.", "p");
+    }
+
+    public ParameterizedMeanFunction GetParameterizedMeanFunction(double[] p, int[] columnIndices) {
+      if (p.Length > 0) throw new ArgumentException("No parameters allowed for zero mean function.", "p");
+      var mf = new ParameterizedMeanFunction();
+      mf.Mean = (x, i) => 0.0;
+      mf.Gradient = (x, i, k) => {
+        if (k > 0)
+          throw new ArgumentException();
+        return 0.0;
+      };
+      return mf;
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/StudentTProcessModel.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/StudentTProcessModel.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/StudentTProcessModel.cs	(revision 13819)
@@ -0,0 +1,411 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Problems.DataAnalysis;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  /// <summary>
+  /// Represents a Gaussian process model.
+  /// </summary>
+  [StorableClass]
+  [Item("StudentTProcessModel", "Represents a Student-t process posterior.")]
+  public sealed class StudentTProcessModel : NamedItem, IGaussianProcessModel {
+    [Storable]
+    private double negativeLogLikelihood;
+    public double NegativeLogLikelihood {
+      get { return negativeLogLikelihood; }
+    }
+
+    [Storable]
+    private double[] hyperparameterGradients;
+    public double[] HyperparameterGradients {
+      get {
+        var copy = new double[hyperparameterGradients.Length];
+        Array.Copy(hyperparameterGradients, copy, copy.Length);
+        return copy;
+      }
+    }
+
+    [Storable]
+    private ICovarianceFunction covarianceFunction;
+    public ICovarianceFunction CovarianceFunction {
+      get { return covarianceFunction; }
+    }
+    [Storable]
+    private IMeanFunction meanFunction;
+    public IMeanFunction MeanFunction {
+      get { return meanFunction; }
+    }
+    [Storable]
+    private string targetVariable;
+    public string TargetVariable {
+      get { return targetVariable; }
+    }
+    [Storable]
+    private string[] allowedInputVariables;
+    public string[] AllowedInputVariables {
+      get { return allowedInputVariables; }
+    }
+
+    [Storable]
+    private double[] alpha;
+    [Storable]
+    private double beta;
+
+    public double SigmaNoise {
+      get { return 0; }
+    }
+
+    [Storable]
+    private double[] meanParameter;
+    [Storable]
+    private double[] covarianceParameter;
+    [Storable]
+    private double nu;
+
+    private double[,] l; // used to be storable in previous versions (is calculated lazily now)
+    private double[,] x; // scaled training dataset, used to be storable in previous versions (is calculated lazily now)
+
+    // BackwardsCompatibility3.4
+    #region Backwards compatible code, remove with 3.5
+    [Storable(Name = "l")] // restore if available but don't store anymore
+    private double[,] l_storable {
+      set { this.l = value; }
+      get {
+        if (trainingDataset == null) return l; // this model has been created with an old version 
+        else return null; // if the training dataset is available l should not be serialized
+      }
+    }
+    [Storable(Name = "x")] // restore if available but don't store anymore
+    private double[,] x_storable {
+      set { this.x = value; }
+      get {
+        if (trainingDataset == null) return x; // this model has been created with an old version 
+        else return null; // if the training dataset is available x should not be serialized
+      }
+    }
+    #endregion
+
+
+    [Storable]
+    private IDataset trainingDataset; // it is better to store the original training dataset completely because this is more efficient in persistence
+    [Storable]
+    private int[] trainingRows;
+
+    [Storable]
+    private Scaling inputScaling;
+
+
+    [StorableConstructor]
+    private StudentTProcessModel(bool deserializing) : base(deserializing) { }
+    private StudentTProcessModel(StudentTProcessModel original, Cloner cloner)
+      : base(original, cloner) {
+      this.meanFunction = cloner.Clone(original.meanFunction);
+      this.covarianceFunction = cloner.Clone(original.covarianceFunction);
+      if (original.inputScaling != null)
+        this.inputScaling = cloner.Clone(original.inputScaling);
+      this.trainingDataset = cloner.Clone(original.trainingDataset);
+      this.negativeLogLikelihood = original.negativeLogLikelihood;
+      this.targetVariable = original.targetVariable;
+      if (original.meanParameter != null) {
+        this.meanParameter = (double[])original.meanParameter.Clone();
+      }
+      if (original.covarianceParameter != null) {
+        this.covarianceParameter = (double[])original.covarianceParameter.Clone();
+      }
+      nu = original.nu;
+
+      // shallow copies of arrays because they cannot be modified
+      this.trainingRows = original.trainingRows;
+      this.allowedInputVariables = original.allowedInputVariables;
+      this.alpha = original.alpha;
+      this.beta = original.beta;
+      this.l = original.l;
+      this.x = original.x;
+    }
+    public StudentTProcessModel(IDataset ds, string targetVariable, IEnumerable<string> allowedInputVariables, IEnumerable<int> rows,
+      IEnumerable<double> hyp, IMeanFunction meanFunction, ICovarianceFunction covarianceFunction,
+      bool scaleInputs = true)
+      : base() {
+      this.name = ItemName;
+      this.description = ItemDescription;
+      this.meanFunction = (IMeanFunction)meanFunction.Clone();
+      this.covarianceFunction = (ICovarianceFunction)covarianceFunction.Clone();
+      this.targetVariable = targetVariable;
+      this.allowedInputVariables = allowedInputVariables.ToArray();
+
+
+      int nVariables = this.allowedInputVariables.Length;
+      meanParameter = hyp
+        .Take(this.meanFunction.GetNumberOfParameters(nVariables))
+        .ToArray();
+
+      covarianceParameter = hyp.Skip(meanParameter.Length)
+                                             .Take(this.covarianceFunction.GetNumberOfParameters(nVariables))
+                                             .ToArray();
+      nu = Math.Exp(hyp.Skip(meanParameter.Length + covarianceParameter.Length).First()) + 2; //TODO check gradient
+      try {
+        CalculateModel(ds, rows, scaleInputs);
+      }
+      catch (alglib.alglibexception ae) {
+        // wrap exception so that calling code doesn't have to know about alglib implementation
+        throw new ArgumentException("There was a problem in the calculation of the Gaussian process model", ae);
+      }
+    }
+
+    private void CalculateModel(IDataset ds, IEnumerable<int> rows, bool scaleInputs = true) {
+      this.trainingDataset = (IDataset)ds.Clone();
+      this.trainingRows = rows.ToArray();
+      this.inputScaling = scaleInputs ? new Scaling(ds, allowedInputVariables, rows) : null;
+
+      x = GetData(ds, this.allowedInputVariables, this.trainingRows, this.inputScaling);
+
+      IEnumerable<double> y;
+      y = ds.GetDoubleValues(targetVariable, rows);
+
+      int n = x.GetLength(0);
+      var columns = Enumerable.Range(0, x.GetLength(1)).ToArray();
+
+      // calculate cholesky decomposed (lower triangular) covariance matrix
+      var cov = covarianceFunction.GetParameterizedCovarianceFunction(covarianceParameter, columns);
+      this.l = CalculateL(x, cov);
+
+      // calculate mean
+      var mean = meanFunction.GetParameterizedMeanFunction(meanParameter, columns);
+      double[] m = Enumerable.Range(0, x.GetLength(0))
+        .Select(r => mean.Mean(x, r))
+        .ToArray();
+
+      // calculate sum of diagonal elements for likelihood
+      double diagSum = Enumerable.Range(0, n).Select(i => Math.Log(l[i, i])).Sum();
+
+      // solve for alpha
+      double[] ym = y.Zip(m, (a, b) => a - b).ToArray();
+
+      int info;
+      alglib.densesolverreport denseSolveRep;
+
+      alglib.spdmatrixcholeskysolve(l, n, false, ym, out info, out denseSolveRep, out alpha);
+
+      beta = Util.ScalarProd(ym, alpha);
+      double sign0, sign1;
+      double lngamma0 = alglib.lngamma(0.5 * (nu + n), out sign0);
+      lngamma0 *= sign0;
+      double lngamma1 = alglib.lngamma(0.5 * nu, out sign1);
+      lngamma1 *= sign1;
+      negativeLogLikelihood =
+        0.5 * n * Math.Log((nu - 2) * Math.PI) +
+        diagSum +
+        -lngamma0 + lngamma1 +
+        //-Math.Log(alglib.gammafunction((n + nu) / 2) / alglib.gammafunction(nu / 2)) +
+        0.5 * (nu + n) * Math.Log(1 + beta / (nu - 2));
+
+      // derivatives
+      int nAllowedVariables = x.GetLength(1);
+
+      alglib.matinvreport matInvRep;
+      double[,] lCopy = new double[l.GetLength(0), l.GetLength(1)];
+      Array.Copy(l, lCopy, lCopy.Length);
+
+      alglib.spdmatrixcholeskyinverse(ref lCopy, n, false, out info, out matInvRep);
+      double c = (nu + n) / (nu + beta - 2);
+      if (info != 1) throw new ArgumentException("Can't invert matrix to calculate gradients.");
+      for (int i = 0; i < n; i++) {
+        for (int j = 0; j <= i; j++)
+          lCopy[i, j] = lCopy[i, j] - c * alpha[i] * alpha[j];
+      }
+
+      double[] meanGradients = new double[meanFunction.GetNumberOfParameters(nAllowedVariables)];
+      for (int k = 0; k < meanGradients.Length; k++) {
+        var meanGrad = new double[alpha.Length];
+        for (int g = 0; g < meanGrad.Length; g++)
+          meanGrad[g] = mean.Gradient(x, g, k);
+        meanGradients[k] = -Util.ScalarProd(meanGrad, alpha);//TODO not working yet, try to fix with gradient check
+      }
+
+      double[] covGradients = new double[covarianceFunction.GetNumberOfParameters(nAllowedVariables)];
+      if (covGradients.Length > 0) {
+        for (int i = 0; i < n; i++) {
+          for (int j = 0; j < i; j++) {
+            var g = cov.CovarianceGradient(x, i, j);
+            for (int k = 0; k < covGradients.Length; k++) {
+              covGradients[k] += lCopy[i, j] * g[k];
+            }
+          }
+
+          var gDiag = cov.CovarianceGradient(x, i, i);
+          for (int k = 0; k < covGradients.Length; k++) {
+            // diag
+            covGradients[k] += 0.5 * lCopy[i, i] * gDiag[k];
+          }
+        }
+      }
+
+      double nuGradient = 0.5 * n
+        - 0.5 * (nu - 2) * alglib.psi((n + nu) / 2) + 0.5 * (nu - 2) * alglib.psi(nu / 2)
+        + 0.5 * (nu - 2) * Math.Log(1 + beta / (nu - 2)) - beta * (n + nu) / (2 * (beta + (nu - 2)));
+
+      //nuGradient = (nu-2) * nuGradient;
+      hyperparameterGradients =
+        meanGradients
+        .Concat(covGradients)
+        .Concat(new double[] { nuGradient }).ToArray();
+
+    }
+
+    private static double[,] GetData(IDataset ds, IEnumerable<string> allowedInputs, IEnumerable<int> rows, Scaling scaling) {
+      if (scaling != null) {
+        return AlglibUtil.PrepareAndScaleInputMatrix(ds, allowedInputs, rows, scaling);
+      } else {
+        return AlglibUtil.PrepareInputMatrix(ds, allowedInputs, rows);
+      }
+    }
+
+    private static double[,] CalculateL(double[,] x, ParameterizedCovarianceFunction cov) {
+      int n = x.GetLength(0);
+      var l = new double[n, n];
+
+      // calculate covariances
+      for (int i = 0; i < n; i++) {
+        for (int j = i; j < n; j++) {
+          l[j, i] = cov.Covariance(x, i, j);
+        }
+      }
+
+      // cholesky decomposition
+      var res = alglib.trfac.spdmatrixcholesky(ref l, n, false);
+      if (!res) throw new ArgumentException("Matrix is not positive semidefinite");
+      return l;
+    }
+
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new StudentTProcessModel(this, cloner);
+    }
+
+    // is called by the solution creator to set all parameter values of the covariance and mean function
+    // to the optimized values (necessary to make the values visible in the GUI)
+    public void FixParameters() {
+      covarianceFunction.SetParameter(covarianceParameter);
+      meanFunction.SetParameter(meanParameter);
+      covarianceParameter = new double[0];
+      meanParameter = new double[0];
+    }
+
+    #region IRegressionModel Members
+    public IEnumerable<double> GetEstimatedValues(IDataset dataset, IEnumerable<int> rows) {
+      return GetEstimatedValuesHelper(dataset, rows);
+    }
+    public GaussianProcessRegressionSolution CreateRegressionSolution(IRegressionProblemData problemData) {
+      return new GaussianProcessRegressionSolution(this, new RegressionProblemData(problemData));
+    }
+    IRegressionSolution IRegressionModel.CreateRegressionSolution(IRegressionProblemData problemData) {
+      return CreateRegressionSolution(problemData);
+    }
+    #endregion
+
+
+    private IEnumerable<double> GetEstimatedValuesHelper(IDataset dataset, IEnumerable<int> rows) {
+      try {
+        if (x == null) {
+          x = GetData(trainingDataset, allowedInputVariables, trainingRows, inputScaling);
+        }
+        int n = x.GetLength(0);
+
+        double[,] newX = GetData(dataset, allowedInputVariables, rows, inputScaling);
+        int newN = newX.GetLength(0);
+        var columns = Enumerable.Range(0, newX.GetLength(1)).ToArray();
+
+        var Ks = new double[newN][];
+        var mean = meanFunction.GetParameterizedMeanFunction(meanParameter, columns);
+        var ms = Enumerable.Range(0, newX.GetLength(0))
+        .Select(r => mean.Mean(newX, r))
+        .ToArray();
+        var cov = covarianceFunction.GetParameterizedCovarianceFunction(covarianceParameter, columns);
+        for (int i = 0; i < newN; i++) {
+          Ks[i] = new double[n];
+          for (int j = 0; j < n; j++) {
+            Ks[i][j] = cov.CrossCovariance(x, newX, j, i);
+          }
+        }
+
+        return Enumerable.Range(0, newN)
+          .Select(i => ms[i] + Util.ScalarProd(Ks[i], alpha));
+      }
+      catch (alglib.alglibexception ae) {
+        // wrap exception so that calling code doesn't have to know about alglib implementation
+        throw new ArgumentException("There was a problem in the calculation of the Gaussian process model", ae);
+      }
+    }
+
+    public IEnumerable<double> GetEstimatedVariance(IDataset dataset, IEnumerable<int> rows) {
+      try {
+        if (x == null) {
+          x = GetData(trainingDataset, allowedInputVariables, trainingRows, inputScaling);
+        }
+        int n = x.GetLength(0);
+
+        var newX = GetData(dataset, allowedInputVariables, rows, inputScaling);
+        int newN = newX.GetLength(0);
+
+        var kss = new double[newN];
+        double[,] sWKs = new double[n, newN];
+        var cov = covarianceFunction.GetParameterizedCovarianceFunction(covarianceParameter, Enumerable.Range(0, x.GetLength(1)).ToArray());
+
+        if (l == null) {
+          l = CalculateL(x, cov);
+        }
+
+        // for stddev 
+        for (int i = 0; i < newN; i++)
+          kss[i] = cov.Covariance(newX, i, i);
+
+        for (int i = 0; i < newN; i++) {
+          for (int j = 0; j < n; j++) {
+            sWKs[j, i] = cov.CrossCovariance(x, newX, j, i);
+          }
+        }
+
+        // for stddev 
+        alglib.ablas.rmatrixlefttrsm(n, newN, l, 0, 0, false, false, 0, ref sWKs, 0, 0);
+
+        for (int i = 0; i < newN; i++) {
+          var col = Util.GetCol(sWKs, i).ToArray();
+          var sumV = Util.ScalarProd(col, col);
+          kss[i] -= sumV;
+          kss[i] *= (nu + beta - 2) / (nu + n - 2);
+          if (kss[i] < 0) kss[i] = 0;
+        }
+        return kss;
+      }
+      catch (alglib.alglibexception ae) {
+        // wrap exception so that calling code doesn't have to know about alglib implementation
+        throw new ArgumentException("There was a problem in the calculation of the Gaussian process model", ae);
+      }
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/StudentTProcessRegressionModelCreator.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/StudentTProcessRegressionModelCreator.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/StudentTProcessRegressionModelCreator.cs	(revision 13819)
@@ -0,0 +1,81 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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 HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Encodings.RealVectorEncoding;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Problems.DataAnalysis;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  [StorableClass]
+  [Item(Name = "StudentTProcessRegressionModelCreator",
+    Description = "Creates a Student-t process model for regression given the data, the hyperparameters, a mean function, and a covariance function.")]
+  public sealed class StudentTProcessRegressionModelCreator : GaussianProcessModelCreator, IGaussianProcessRegressionModelCreator {
+    private const string ProblemDataParameterName = "ProblemData";
+
+    #region Parameter Properties
+    public ILookupParameter<IRegressionProblemData> ProblemDataParameter {
+      get { return (ILookupParameter<IRegressionProblemData>)Parameters[ProblemDataParameterName]; }
+    }
+    #endregion
+
+    #region Properties
+    private IRegressionProblemData ProblemData {
+      get { return ProblemDataParameter.ActualValue; }
+    }
+    #endregion
+    [StorableConstructor]
+    private StudentTProcessRegressionModelCreator(bool deserializing) : base(deserializing) { }
+    private StudentTProcessRegressionModelCreator(StudentTProcessRegressionModelCreator original, Cloner cloner) : base(original, cloner) { }
+    public StudentTProcessRegressionModelCreator()
+      : base() {
+      Parameters.Add(new LookupParameter<IRegressionProblemData>(ProblemDataParameterName, "The regression problem data for the Gaussian process model."));
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new StudentTProcessRegressionModelCreator(this, cloner);
+    }
+
+    public override IOperation Apply() {
+      try {
+        var model = Create(ProblemData, Hyperparameter.ToArray(), MeanFunction, CovarianceFunction, ScaleInputValues);
+        ModelParameter.ActualValue = model;
+        NegativeLogLikelihoodParameter.ActualValue = new DoubleValue(model.NegativeLogLikelihood);
+        HyperparameterGradientsParameter.ActualValue = new RealVector(model.HyperparameterGradients);
+        return base.Apply();
+      }
+      catch (ArgumentException) { }
+      catch (alglib.alglibexception) { }
+      NegativeLogLikelihoodParameter.ActualValue = new DoubleValue(1E300);
+      HyperparameterGradientsParameter.ActualValue = new RealVector(Hyperparameter.Count());
+      return base.Apply();
+    }
+
+    public static IGaussianProcessModel Create(IRegressionProblemData problemData, double[] hyperparameter, IMeanFunction meanFunction, ICovarianceFunction covarianceFunction, bool scaleInputs = true) {
+      return new StudentTProcessModel(problemData.Dataset, problemData.TargetVariable, problemData.AllowedInputVariables, problemData.TrainingIndices, hyperparameter, meanFunction, covarianceFunction, scaleInputs);
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/Util.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/Util.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GaussianProcess/Util.cs	(revision 13819)
@@ -0,0 +1,120 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  internal static class Util {
+    public static double ScalarProd(double[] v, double[] u) {
+      if (v.Length != u.Length) throw new InvalidOperationException();
+      double prod = 0.0;
+      for (int i = 0; i < v.Length; i++)
+        prod += v[i] * u[i];
+      return prod;
+    }
+
+    public static double SqrDist(IEnumerable<double> x, IEnumerable<double> y) {
+      return x.Zip(y, (a, b) => (a - b) * (a - b)).Sum();
+    }
+
+    public static double SqrDist(double x, double y) {
+      double d = x - y;
+      return d * d;
+    }
+
+    public static double SqrDist(double[,] x, int i, int j, int[] columnIndices, double scale = 1.0) {
+      return SqrDist(x, i, x, j, columnIndices, scale);
+    }
+
+    public static double SqrDist(double[,] x, int i, double[,] xt, int j, int[] columnIndices, double scale = 1.0) {
+      double ss = 0.0;
+      if (columnIndices == null) columnIndices = Enumerable.Range(0, x.GetLength(1)).ToArray();
+      for (int c = 0; c < columnIndices.Length; c++) {
+        var columnIndex = columnIndices[c];
+        double d = x[i, columnIndex] - xt[j, columnIndex];
+        ss += d * d;
+      }
+      return scale * scale * ss;
+    }
+
+    public static double SqrDist(double[,] x, int i, int j, double[] scale, int[] columnIndices) {
+      return SqrDist(x, i, x, j, scale, columnIndices);
+    }
+
+    public static double SqrDist(double[,] x, int i, double[,] xt, int j, double[] scale, int[] columnIndices) {
+      double ss = 0.0;
+      int scaleIndex = 0;
+      for (int c = 0; c < columnIndices.Length; c++) {
+        var columnIndex = columnIndices[c];
+        double d = x[i, columnIndex] - xt[j, columnIndex];
+        ss += d * d * scale[scaleIndex] * scale[scaleIndex];
+        scaleIndex++;
+      }
+      // must be at the end of scale after iterating over columnIndices
+      if (scaleIndex != scale.Length)
+        throw new ArgumentException("Lengths of scales and covariance functions does not match.");
+      return ss;
+    }
+    public static double ScalarProd(double[,] x, int i, int j, int[] columnIndices, double scale = 1.0) {
+      return ScalarProd(x, i, x, j, columnIndices, scale);
+    }
+
+    public static double ScalarProd(double[,] x, int i, double[,] xt, int j, int[] columnIndices, double scale = 1.0) {
+      double sum = 0.0;
+      for (int c = 0; c < columnIndices.Length; c++) {
+        var columnIndex = columnIndices[c];
+        sum += x[i, columnIndex] * xt[j, columnIndex];
+      }
+      return scale * scale * sum;
+    }
+    public static double ScalarProd(double[,] x, int i, int j, double[] scale, int[] columnIndices) {
+      return ScalarProd(x, i, x, j, scale, columnIndices);
+    }
+
+    public static double ScalarProd(double[,] x, int i, double[,] xt, int j, double[] scale, int[] columnIndices) {
+      double sum = 0.0;
+      int scaleIndex = 0;
+      for (int c = 0; c < columnIndices.Length; c++, scaleIndex++) {
+        var columnIndex = columnIndices[c];
+        sum += x[i, columnIndex] * scale[scaleIndex] * xt[j, columnIndex] * scale[scaleIndex];
+      }
+      // must be at the end of scale after iterating over columnIndices
+      if (scaleIndex != scale.Length)
+        throw new ArgumentException("Lengths of scales and covariance functions does not match.");
+
+      return sum;
+    }
+
+    public static IEnumerable<double> GetRow(double[,] x, int r) {
+      int cols = x.GetLength(1);
+      return GetRow(x, r, Enumerable.Range(0, cols));
+    }
+    public static IEnumerable<double> GetRow(double[,] x, int r, IEnumerable<int> columnIndices) {
+      return columnIndices.Select(c => x[r, c]);
+    }
+    public static IEnumerable<double> GetCol(double[,] x, int c) {
+      int rows = x.GetLength(0);
+      return Enumerable.Range(0, rows).Select(r => x[r, c]);
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GradientBoostedTrees/GradientBoostedTreesAlgorithm.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GradientBoostedTrees/GradientBoostedTreesAlgorithm.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GradientBoostedTrees/GradientBoostedTreesAlgorithm.cs	(revision 13819)
@@ -0,0 +1,276 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ * and the BEACON Center for the Study of Evolution in Action.
+ * 
+ * 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.Threading;
+using HeuristicLab.Analysis;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Optimization;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.PluginInfrastructure;
+using HeuristicLab.Problems.DataAnalysis;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  [Item("Gradient Boosted Trees (GBT)", "Gradient boosted trees algorithm. Specific implementation of gradient boosting for regression trees. Friedman, J. \"Greedy Function Approximation: A Gradient Boosting Machine\", IMS 1999 Reitz Lecture.")]
+  [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; }
+    }
+
+    #region ParameterNames
+    private const string IterationsParameterName = "Iterations";
+    private const string MaxSizeParameterName = "Maximum Tree Size";
+    private const string NuParameterName = "Nu";
+    private const string RParameterName = "R";
+    private const string MParameterName = "M";
+    private const string SeedParameterName = "Seed";
+    private const string SetSeedRandomlyParameterName = "SetSeedRandomly";
+    private const string LossFunctionParameterName = "LossFunction";
+    private const string UpdateIntervalParameterName = "UpdateInterval";
+    private const string CreateSolutionParameterName = "CreateSolution";
+    #endregion
+
+    #region ParameterProperties
+    public IFixedValueParameter<IntValue> IterationsParameter {
+      get { return (IFixedValueParameter<IntValue>)Parameters[IterationsParameterName]; }
+    }
+    public IFixedValueParameter<IntValue> MaxSizeParameter {
+      get { return (IFixedValueParameter<IntValue>)Parameters[MaxSizeParameterName]; }
+    }
+    public IFixedValueParameter<DoubleValue> NuParameter {
+      get { return (IFixedValueParameter<DoubleValue>)Parameters[NuParameterName]; }
+    }
+    public IFixedValueParameter<DoubleValue> RParameter {
+      get { return (IFixedValueParameter<DoubleValue>)Parameters[RParameterName]; }
+    }
+    public IFixedValueParameter<DoubleValue> MParameter {
+      get { return (IFixedValueParameter<DoubleValue>)Parameters[MParameterName]; }
+    }
+    public IFixedValueParameter<IntValue> SeedParameter {
+      get { return (IFixedValueParameter<IntValue>)Parameters[SeedParameterName]; }
+    }
+    public FixedValueParameter<BoolValue> SetSeedRandomlyParameter {
+      get { return (FixedValueParameter<BoolValue>)Parameters[SetSeedRandomlyParameterName]; }
+    }
+    public IConstrainedValueParameter<ILossFunction> LossFunctionParameter {
+      get { return (IConstrainedValueParameter<ILossFunction>)Parameters[LossFunctionParameterName]; }
+    }
+    public IFixedValueParameter<IntValue> UpdateIntervalParameter {
+      get { return (IFixedValueParameter<IntValue>)Parameters[UpdateIntervalParameterName]; }
+    }
+    public IFixedValueParameter<BoolValue> CreateSolutionParameter {
+      get { return (IFixedValueParameter<BoolValue>)Parameters[CreateSolutionParameterName]; }
+    }
+    #endregion
+
+    #region Properties
+    public int Iterations {
+      get { return IterationsParameter.Value.Value; }
+      set { IterationsParameter.Value.Value = value; }
+    }
+    public int Seed {
+      get { return SeedParameter.Value.Value; }
+      set { SeedParameter.Value.Value = value; }
+    }
+    public bool SetSeedRandomly {
+      get { return SetSeedRandomlyParameter.Value.Value; }
+      set { SetSeedRandomlyParameter.Value.Value = value; }
+    }
+    public int MaxSize {
+      get { return MaxSizeParameter.Value.Value; }
+      set { MaxSizeParameter.Value.Value = value; }
+    }
+    public double Nu {
+      get { return NuParameter.Value.Value; }
+      set { NuParameter.Value.Value = value; }
+    }
+    public double R {
+      get { return RParameter.Value.Value; }
+      set { RParameter.Value.Value = value; }
+    }
+    public double M {
+      get { return MParameter.Value.Value; }
+      set { MParameter.Value.Value = value; }
+    }
+    public bool CreateSolution {
+      get { return CreateSolutionParameter.Value.Value; }
+      set { CreateSolutionParameter.Value.Value = value; }
+    }
+    #endregion
+
+    #region ResultsProperties
+    private double ResultsBestQuality {
+      get { return ((DoubleValue)Results["Best Quality"].Value).Value; }
+      set { ((DoubleValue)Results["Best Quality"].Value).Value = value; }
+    }
+    private DataTable ResultsQualities {
+      get { return ((DataTable)Results["Qualities"].Value); }
+    }
+    #endregion
+
+    [StorableConstructor]
+    protected GradientBoostedTreesAlgorithm(bool deserializing) : base(deserializing) { }
+
+    protected GradientBoostedTreesAlgorithm(GradientBoostedTreesAlgorithm original, Cloner cloner)
+      : base(original, cloner) {
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new GradientBoostedTreesAlgorithm(this, cloner);
+    }
+
+    public GradientBoostedTreesAlgorithm() {
+      Problem = new RegressionProblem(); // default problem
+
+      Parameters.Add(new FixedValueParameter<IntValue>(IterationsParameterName, "Number of iterations (set as high as possible, adjust in combination with nu, when increasing iterations also decrease nu)", new IntValue(1000)));
+      Parameters.Add(new FixedValueParameter<IntValue>(SeedParameterName, "The random seed used to initialize the new pseudo random number generator.", new IntValue(0)));
+      Parameters.Add(new FixedValueParameter<BoolValue>(SetSeedRandomlyParameterName, "True if the random seed should be set to a random value, otherwise false.", new BoolValue(true)));
+      Parameters.Add(new FixedValueParameter<IntValue>(MaxSizeParameterName, "Maximal size of the tree learned in each step (prefer smaller sizes if possible)", new IntValue(10)));
+      Parameters.Add(new FixedValueParameter<DoubleValue>(RParameterName, "Ratio of training rows selected randomly in each step (0 < R <= 1)", new DoubleValue(0.5)));
+      Parameters.Add(new FixedValueParameter<DoubleValue>(MParameterName, "Ratio of variables selected randomly in each step (0 < M <= 1)", new DoubleValue(0.5)));
+      Parameters.Add(new FixedValueParameter<DoubleValue>(NuParameterName, "Learning rate nu (step size for the gradient update, should be small 0 < nu < 0.1)", new DoubleValue(0.002)));
+      Parameters.Add(new FixedValueParameter<IntValue>(UpdateIntervalParameterName, "", new IntValue(100)));
+      Parameters[UpdateIntervalParameterName].Hidden = true;
+      Parameters.Add(new FixedValueParameter<BoolValue>(CreateSolutionParameterName, "Flag that indicates if a solution should be produced at the end of the run", new BoolValue(true)));
+      Parameters[CreateSolutionParameterName].Hidden = true;
+
+      var lossFunctions = ApplicationManager.Manager.GetInstances<ILossFunction>();
+      Parameters.Add(new ConstrainedValueParameter<ILossFunction>(LossFunctionParameterName, "The loss function", new ItemSet<ILossFunction>(lossFunctions)));
+      LossFunctionParameter.Value = LossFunctionParameter.ValidValues.First(f => f.ToString().Contains("Squared")); // squared error loss is the default
+    }
+
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() {
+      // BackwardsCompatibility3.4
+      #region Backwards compatible code, remove with 3.5
+      // parameter type has been changed
+      var lossFunctionParam = Parameters[LossFunctionParameterName] as ConstrainedValueParameter<StringValue>;
+      if (lossFunctionParam != null) {
+        Parameters.Remove(LossFunctionParameterName);
+        var selectedValue = lossFunctionParam.Value; // to be restored below
+
+        var lossFunctions = ApplicationManager.Manager.GetInstances<ILossFunction>();
+        Parameters.Add(new ConstrainedValueParameter<ILossFunction>(LossFunctionParameterName, "The loss function", new ItemSet<ILossFunction>(lossFunctions)));
+        // try to restore selected value
+        var selectedLossFunction =
+          LossFunctionParameter.ValidValues.FirstOrDefault(f => f.ToString() == selectedValue.Value);
+        if (selectedLossFunction != null) {
+          LossFunctionParameter.Value = selectedLossFunction;
+        } else {
+          LossFunctionParameter.Value = LossFunctionParameter.ValidValues.First(f => f.ToString().Contains("Squared")); // default: SE
+        }
+      }
+      #endregion
+    }
+
+    protected override void Run(CancellationToken cancellationToken) {
+      // Set up the algorithm
+      if (SetSeedRandomly) Seed = new System.Random().Next();
+
+      // Set up the results display
+      var iterations = new IntValue(0);
+      Results.Add(new Result("Iterations", iterations));
+
+      var table = new DataTable("Qualities");
+      table.Rows.Add(new DataRow("Loss (train)"));
+      table.Rows.Add(new DataRow("Loss (test)"));
+      Results.Add(new Result("Qualities", table));
+      var curLoss = new DoubleValue();
+      Results.Add(new Result("Loss (train)", curLoss));
+
+      // init
+      var problemData = (IRegressionProblemData)Problem.ProblemData.Clone();
+      var lossFunction = LossFunctionParameter.Value;
+      var state = GradientBoostedTreesAlgorithmStatic.CreateGbmState(problemData, lossFunction, (uint)Seed, MaxSize, R, M, Nu);
+
+      var updateInterval = UpdateIntervalParameter.Value.Value;
+      // Loop until iteration limit reached or canceled.
+      for (int i = 0; i < Iterations; i++) {
+        cancellationToken.ThrowIfCancellationRequested();
+
+        GradientBoostedTreesAlgorithmStatic.MakeStep(state);
+
+        // iteration results
+        if (i % updateInterval == 0) {
+          curLoss.Value = state.GetTrainLoss();
+          table.Rows["Loss (train)"].Values.Add(curLoss.Value);
+          table.Rows["Loss (test)"].Values.Add(state.GetTestLoss());
+          iterations.Value = i;
+        }
+      }
+
+      // final results
+      iterations.Value = Iterations;
+      curLoss.Value = state.GetTrainLoss();
+      table.Rows["Loss (train)"].Values.Add(curLoss.Value);
+      table.Rows["Loss (test)"].Values.Add(state.GetTestLoss());
+
+      // produce variable relevance
+      var orderedImpacts = state.GetVariableRelevance().Select(t => new { name = t.Key, impact = t.Value }).ToList();
+
+      var impacts = new DoubleMatrix();
+      var matrix = impacts as IStringConvertibleMatrix;
+      matrix.Rows = orderedImpacts.Count;
+      matrix.RowNames = orderedImpacts.Select(x => x.name);
+      matrix.Columns = 1;
+      matrix.ColumnNames = new string[] { "Relative variable relevance" };
+
+      int rowIdx = 0;
+      foreach (var p in orderedImpacts) {
+        matrix.SetValue(string.Format("{0:N2}", p.impact), rowIdx++, 0);
+      }
+
+      Results.Add(new Result("Variable relevance", impacts));
+      Results.Add(new Result("Loss (test)", new DoubleValue(state.GetTestLoss())));
+
+      // produce solution 
+      if (CreateSolution) {
+        var model = state.GetModel();
+
+        // for logistic regression we produce a classification solution
+        if (lossFunction is LogisticRegressionLoss) {
+          var classificationModel = new DiscriminantFunctionClassificationModel(model,
+            new AccuracyMaximizationThresholdCalculator());
+          var classificationProblemData = new ClassificationProblemData(problemData.Dataset,
+            problemData.AllowedInputVariables, problemData.TargetVariable, problemData.Transformations);
+          classificationModel.RecalculateModelParameters(classificationProblemData, classificationProblemData.TrainingIndices);
+
+          var classificationSolution = new DiscriminantFunctionClassificationSolution(classificationModel, classificationProblemData);
+          Results.Add(new Result("Solution", classificationSolution));
+        } else {
+          // otherwise we produce a regression solution
+          Results.Add(new Result("Solution", new RegressionSolution(model, problemData)));
+        }
+      }
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GradientBoostedTrees/GradientBoostedTreesAlgorithmStatic.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GradientBoostedTrees/GradientBoostedTreesAlgorithmStatic.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GradientBoostedTrees/GradientBoostedTreesAlgorithmStatic.cs	(revision 13819)
@@ -0,0 +1,201 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ * and the BEACON Center for the Study of Evolution in Action.
+ * 
+ * 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.Diagnostics.Contracts;
+using System.Linq;
+using HeuristicLab.Problems.DataAnalysis;
+using HeuristicLab.Random;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  public static class GradientBoostedTreesAlgorithmStatic {
+    #region static API
+
+    public interface IGbmState {
+      IRegressionModel GetModel();
+      double GetTrainLoss();
+      double GetTestLoss();
+      IEnumerable<KeyValuePair<string, double>> GetVariableRelevance();
+    }
+
+    // created through factory method
+    // GbmState details are private API users can only use methods from IGbmState
+    private class GbmState : IGbmState {
+      internal IRegressionProblemData problemData { get; private set; }
+      internal ILossFunction lossFunction { get; private set; }
+      internal int maxSize { get; private set; }
+      internal double nu { get; private set; }
+      internal double r { get; private set; }
+      internal double m { get; private set; }
+      internal int[] trainingRows { get; private set; }
+      internal int[] testRows { get; private set; }
+      internal RegressionTreeBuilder treeBuilder { get; private set; }
+
+      private readonly uint randSeed;
+      private MersenneTwister random { get; set; }
+
+      // array members (allocate only once)
+      internal double[] pred;
+      internal double[] predTest;
+      internal double[] y;
+      internal int[] activeIdx;
+      internal double[] pseudoRes;
+
+      private readonly IList<IRegressionModel> models;
+      private readonly IList<double> weights;
+
+      public GbmState(IRegressionProblemData problemData, ILossFunction lossFunction, uint randSeed, int maxSize, double r, double m, double nu) {
+        // default settings for MaxSize, Nu and R
+        this.maxSize = maxSize;
+        this.nu = nu;
+        this.r = r;
+        this.m = m;
+
+        this.randSeed = randSeed;
+        random = new MersenneTwister(randSeed);
+        this.problemData = problemData;
+        this.trainingRows = problemData.TrainingIndices.ToArray();
+        this.testRows = problemData.TestIndices.ToArray();
+        this.lossFunction = lossFunction;
+
+        int nRows = trainingRows.Length;
+
+        y = problemData.Dataset.GetDoubleValues(problemData.TargetVariable, trainingRows).ToArray();
+
+        treeBuilder = new RegressionTreeBuilder(problemData, random);
+
+        activeIdx = Enumerable.Range(0, nRows).ToArray();
+
+        var zeros = Enumerable.Repeat(0.0, nRows).ToArray();
+        double f0 = lossFunction.LineSearch(y, zeros, activeIdx, 0, nRows - 1); // initial constant value (mean for squared errors)
+        pred = Enumerable.Repeat(f0, nRows).ToArray();
+        predTest = Enumerable.Repeat(f0, testRows.Length).ToArray();
+        pseudoRes = new double[nRows];
+
+        models = new List<IRegressionModel>();
+        weights = new List<double>();
+        // add constant model
+        models.Add(new ConstantModel(f0));
+        weights.Add(1.0);
+      }
+
+      public IRegressionModel GetModel() {
+#pragma warning disable 618
+        var model = new GradientBoostedTreesModel(models, weights);
+#pragma warning restore 618
+        // we don't know the number of iterations here but the number of weights is equal 
+        // to the number of iterations + 1 (for the constant model)
+        // wrap the actual model in a surrogate that enables persistence and lazy recalculation of the model if necessary
+        return new GradientBoostedTreesModelSurrogate(problemData, randSeed, lossFunction, weights.Count - 1, maxSize, r, m, nu, model);
+      }
+      public IEnumerable<KeyValuePair<string, double>> GetVariableRelevance() {
+        return treeBuilder.GetVariableRelevance();
+      }
+
+      public double GetTrainLoss() {
+        int nRows = y.Length;
+        return lossFunction.GetLoss(y, pred) / nRows;
+      }
+      public double GetTestLoss() {
+        var yTest = problemData.Dataset.GetDoubleValues(problemData.TargetVariable, testRows);
+        var nRows = testRows.Length;
+        return lossFunction.GetLoss(yTest, predTest) / nRows;
+      }
+
+      internal void AddModel(IRegressionModel m, double weight) {
+        models.Add(m);
+        weights.Add(weight);
+      }
+    }
+
+    // simple interface
+    public static GradientBoostedTreesSolution TrainGbm(IRegressionProblemData problemData, ILossFunction lossFunction, int maxSize, double nu, double r, double m, int maxIterations, uint randSeed = 31415) {
+      Contract.Assert(r > 0);
+      Contract.Assert(r <= 1.0);
+      Contract.Assert(nu > 0);
+      Contract.Assert(nu <= 1.0);
+
+      var state = (GbmState)CreateGbmState(problemData, lossFunction, randSeed, maxSize, r, m, nu);
+
+      for (int iter = 0; iter < maxIterations; iter++) {
+        MakeStep(state);
+      }
+
+      var model = state.GetModel();
+      return new GradientBoostedTreesSolution(model, (IRegressionProblemData)problemData.Clone());
+    }
+
+    // for custom stepping & termination
+    public static IGbmState CreateGbmState(IRegressionProblemData problemData, ILossFunction lossFunction, uint randSeed, int maxSize = 3, double r = 0.66, double m = 0.5, double nu = 0.01) {
+      return new GbmState(problemData, lossFunction, randSeed, maxSize, r, m, nu);
+    }
+
+    // use default settings for maxSize, nu, r from state
+    public static void MakeStep(IGbmState state) {
+      var gbmState = state as GbmState;
+      if (gbmState == null) throw new ArgumentException("state");
+
+      MakeStep(gbmState, gbmState.maxSize, gbmState.nu, gbmState.r, gbmState.m);
+    }
+
+    // allow dynamic adaptation of maxSize, nu and r (even though this is not used)
+    public static void MakeStep(IGbmState state, int maxSize, double nu, double r, double m) {
+      var gbmState = state as GbmState;
+      if (gbmState == null) throw new ArgumentException("state");
+
+      var problemData = gbmState.problemData;
+      var lossFunction = gbmState.lossFunction;
+      var yPred = gbmState.pred;
+      var yPredTest = gbmState.predTest;
+      var treeBuilder = gbmState.treeBuilder;
+      var y = gbmState.y;
+      var activeIdx = gbmState.activeIdx;
+      var pseudoRes = gbmState.pseudoRes;
+      var trainingRows = gbmState.trainingRows;
+      var testRows = gbmState.testRows;
+
+      // copy output of gradient function to pre-allocated rim array (pseudo-residual per row and model)
+      int rimIdx = 0;
+      foreach (var g in lossFunction.GetLossGradient(y, yPred)) {
+        pseudoRes[rimIdx++] = g;
+      }
+
+      var tree = treeBuilder.CreateRegressionTreeForGradientBoosting(pseudoRes, yPred, maxSize, activeIdx, lossFunction, r, m);
+
+      int i = 0;
+      foreach (var pred in tree.GetEstimatedValues(problemData.Dataset, trainingRows)) {
+        yPred[i] = yPred[i] + nu * pred;
+        i++;
+      }
+      // update predictions for validation set
+      i = 0;
+      foreach (var pred in tree.GetEstimatedValues(problemData.Dataset, testRows)) {
+        yPredTest[i] = yPredTest[i] + nu * pred;
+        i++;
+      }
+
+      gbmState.AddModel(tree, nu);
+    }
+    #endregion
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GradientBoostedTrees/GradientBoostedTreesModel.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GradientBoostedTrees/GradientBoostedTreesModel.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GradientBoostedTrees/GradientBoostedTreesModel.cs	(revision 13819)
@@ -0,0 +1,111 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ * and the BEACON Center for the Study of Evolution in Action.
+ * 
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Problems.DataAnalysis;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  [StorableClass]
+  [Item("Gradient boosted tree model", "")]
+  // this is essentially a collection of weighted regression models
+  public sealed class GradientBoostedTreesModel : NamedItem, IGradientBoostedTreesModel {
+    // BackwardsCompatibility3.4 for allowing deserialization & serialization of old models
+    #region Backwards compatible code, remove with 3.5
+    private bool isCompatibilityLoaded = false; // only set to true if the model is deserialized from the old format, needed to make sure that information is serialized again if it was loaded from the old format
+
+    [Storable(Name = "models")]
+    private IList<IRegressionModel> __persistedModels {
+      set {
+        this.isCompatibilityLoaded = true;
+        this.models.Clear();
+        foreach (var m in value) this.models.Add(m);
+      }
+      get { if (this.isCompatibilityLoaded) return models; else return null; }
+    }
+    [Storable(Name = "weights")]
+    private IList<double> __persistedWeights {
+      set {
+        this.isCompatibilityLoaded = true;
+        this.weights.Clear();
+        foreach (var w in value) this.weights.Add(w);
+      }
+      get { if (this.isCompatibilityLoaded) return weights; else return null; }
+    }
+    #endregion
+
+    private readonly IList<IRegressionModel> models;
+    public IEnumerable<IRegressionModel> Models { get { return models; } }
+
+    private readonly IList<double> weights;
+    public IEnumerable<double> Weights { get { return weights; } }
+
+    [StorableConstructor]
+    private GradientBoostedTreesModel(bool deserializing)
+      : base(deserializing) {
+      models = new List<IRegressionModel>();
+      weights = new List<double>();
+    }
+    private GradientBoostedTreesModel(GradientBoostedTreesModel original, Cloner cloner)
+      : base(original, cloner) {
+      this.weights = new List<double>(original.weights);
+      this.models = new List<IRegressionModel>(original.models.Select(m => cloner.Clone(m)));
+      this.isCompatibilityLoaded = original.isCompatibilityLoaded;
+    }
+    [Obsolete("The constructor of GBTModel should not be used directly anymore (use GBTModelSurrogate instead)")]
+    public GradientBoostedTreesModel(IEnumerable<IRegressionModel> models, IEnumerable<double> weights)
+      : base("Gradient boosted tree model", string.Empty) {
+      this.models = new List<IRegressionModel>(models);
+      this.weights = new List<double>(weights);
+
+      if (this.models.Count != this.weights.Count) throw new ArgumentException();
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new GradientBoostedTreesModel(this, cloner);
+    }
+
+    public IEnumerable<double> GetEstimatedValues(IDataset dataset, IEnumerable<int> rows) {
+      // allocate target array go over all models and add up weighted estimation for each row
+      if (!rows.Any()) return Enumerable.Empty<double>(); // return immediately if rows is empty. This prevents multiple iteration over lazy rows enumerable.
+      // (which essentially looks up indexes in a dictionary)
+      var res = new double[rows.Count()];
+      for (int i = 0; i < models.Count; i++) {
+        var w = weights[i];
+        var m = models[i];
+        int r = 0;
+        foreach (var est in m.GetEstimatedValues(dataset, rows)) {
+          res[r++] += w * est;
+        }
+      }
+      return res;
+    }
+
+    public IRegressionSolution CreateRegressionSolution(IRegressionProblemData problemData) {
+      return new RegressionSolution(this, (IRegressionProblemData)problemData.Clone());
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GradientBoostedTrees/GradientBoostedTreesModelSurrogate.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GradientBoostedTrees/GradientBoostedTreesModelSurrogate.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GradientBoostedTrees/GradientBoostedTreesModelSurrogate.cs	(revision 13819)
@@ -0,0 +1,126 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ * and the BEACON Center for the Study of Evolution in Action.
+ * 
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Collections.Generic;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Problems.DataAnalysis;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  [StorableClass]
+  // this class is used as a surrogate for persistence of an actual GBT model 
+  // since the actual GBT model would be very large when persisted we only store all necessary information to
+  // recalculate the actual GBT model on demand
+  [Item("Gradient boosted tree model", "")]
+  public sealed class GradientBoostedTreesModelSurrogate : NamedItem, IGradientBoostedTreesModel {
+    // don't store the actual model!
+    private IGradientBoostedTreesModel actualModel; // the actual model is only recalculated when necessary
+
+    [Storable]
+    private readonly IRegressionProblemData trainingProblemData;
+    [Storable]
+    private readonly uint seed;
+    [Storable]
+    private ILossFunction lossFunction;
+    [Storable]
+    private double r;
+    [Storable]
+    private double m;
+    [Storable]
+    private double nu;
+    [Storable]
+    private int iterations;
+    [Storable]
+    private int maxSize;
+
+
+    [StorableConstructor]
+    private GradientBoostedTreesModelSurrogate(bool deserializing) : base(deserializing) { }
+
+    private GradientBoostedTreesModelSurrogate(GradientBoostedTreesModelSurrogate original, Cloner cloner)
+      : base(original, cloner) {
+      if (original.actualModel != null) this.actualModel = cloner.Clone(original.actualModel);
+
+      this.trainingProblemData = cloner.Clone(original.trainingProblemData);
+      this.lossFunction = cloner.Clone(original.lossFunction);
+      this.seed = original.seed;
+      this.iterations = original.iterations;
+      this.maxSize = original.maxSize;
+      this.r = original.r;
+      this.m = original.m;
+      this.nu = original.nu;
+    }
+
+    // create only the surrogate model without an actual model
+    public GradientBoostedTreesModelSurrogate(IRegressionProblemData trainingProblemData, uint seed, ILossFunction lossFunction, int iterations, int maxSize, double r, double m, double nu)
+      : base("Gradient boosted tree model", string.Empty) {
+      this.trainingProblemData = trainingProblemData;
+      this.seed = seed;
+      this.lossFunction = lossFunction;
+      this.iterations = iterations;
+      this.maxSize = maxSize;
+      this.r = r;
+      this.m = m;
+      this.nu = nu;
+    }
+
+    // wrap an actual model in a surrograte
+    public GradientBoostedTreesModelSurrogate(IRegressionProblemData trainingProblemData, uint seed, ILossFunction lossFunction, int iterations, int maxSize, double r, double m, double nu, IGradientBoostedTreesModel model)
+      : this(trainingProblemData, seed, lossFunction, iterations, maxSize, r, m, nu) {
+      this.actualModel = model;
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new GradientBoostedTreesModelSurrogate(this, cloner);
+    }
+
+    // forward message to actual model (recalculate model first if necessary)
+    public IEnumerable<double> GetEstimatedValues(IDataset dataset, IEnumerable<int> rows) {
+      if (actualModel == null) actualModel = RecalculateModel();
+      return actualModel.GetEstimatedValues(dataset, rows);
+    }
+
+    public IRegressionSolution CreateRegressionSolution(IRegressionProblemData problemData) {
+      return new RegressionSolution(this, (IRegressionProblemData)problemData.Clone());
+    }
+
+
+    private IGradientBoostedTreesModel RecalculateModel() {
+      return GradientBoostedTreesAlgorithmStatic.TrainGbm(trainingProblemData, lossFunction, maxSize, nu, r, m, iterations, seed).Model;
+    }
+
+    public IEnumerable<IRegressionModel> Models {
+      get {
+        if (actualModel == null) actualModel = RecalculateModel();
+        return actualModel.Models;
+      }
+    }
+
+    public IEnumerable<double> Weights {
+      get {
+        if (actualModel == null) actualModel = RecalculateModel();
+        return actualModel.Weights;
+      }
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GradientBoostedTrees/GradientBoostedTreesSolution.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GradientBoostedTrees/GradientBoostedTreesSolution.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GradientBoostedTrees/GradientBoostedTreesSolution.cs	(revision 13819)
@@ -0,0 +1,51 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Problems.DataAnalysis;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  [StorableClass]
+  public sealed class GradientBoostedTreesSolution : RegressionSolution {
+    public new IGradientBoostedTreesModel Model {
+      get { return (IGradientBoostedTreesModel)base.Model; }
+    }
+
+
+    [StorableConstructor]
+    private GradientBoostedTreesSolution(bool deserializing)
+      : base(deserializing) {
+    }
+    private GradientBoostedTreesSolution(GradientBoostedTreesSolution original, Cloner cloner)
+      : base(original, cloner) {
+    }
+    public GradientBoostedTreesSolution(IRegressionModel model, IRegressionProblemData problemData)
+      : base(model, problemData) {
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new GradientBoostedTreesSolution(this, cloner);
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GradientBoostedTrees/IGradientBoostedTreesModel.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GradientBoostedTrees/IGradientBoostedTreesModel.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GradientBoostedTrees/IGradientBoostedTreesModel.cs	(revision 13819)
@@ -0,0 +1,36 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ * and the BEACON Center for the Study of Evolution in Action.
+ * 
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Problems.DataAnalysis;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  public interface IGradientBoostedTreesModel : IRegressionModel {
+    IEnumerable<IRegressionModel> Models { get; }
+    IEnumerable<double> Weights { get; }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GradientBoostedTrees/LossFunctions/AbsoluteErrorLoss.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GradientBoostedTrees/LossFunctions/AbsoluteErrorLoss.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GradientBoostedTrees/LossFunctions/AbsoluteErrorLoss.cs	(revision 13819)
@@ -0,0 +1,94 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ * and the BEACON Center for the Study of Evolution in Action.
+ * 
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  // loss function for the weighted absolute error
+  [StorableClass]
+  [Item("Absolute error loss", "")]
+  public sealed class AbsoluteErrorLoss : Item, ILossFunction {
+    public AbsoluteErrorLoss() { }
+
+    public double GetLoss(IEnumerable<double> target, IEnumerable<double> pred) {
+      var targetEnum = target.GetEnumerator();
+      var predEnum = pred.GetEnumerator();
+
+      double s = 0;
+      while (targetEnum.MoveNext() & predEnum.MoveNext()) {
+        double res = targetEnum.Current - predEnum.Current;
+        s += Math.Abs(res);  // |res|
+      }
+      if (targetEnum.MoveNext() | predEnum.MoveNext())
+        throw new ArgumentException("target and pred have differing lengths");
+
+      return s;
+    }
+
+    public IEnumerable<double> GetLossGradient(IEnumerable<double> target, IEnumerable<double> pred) {
+      var targetEnum = target.GetEnumerator();
+      var predEnum = pred.GetEnumerator();
+
+      while (targetEnum.MoveNext() & predEnum.MoveNext()) {
+        // dL(y, f(x)) / df(x) = sign(res)
+        var res = targetEnum.Current - predEnum.Current;
+        if (res > 0) yield return 1.0;
+        else if (res < 0) yield return -1.0;
+        else yield return 0.0;
+      }
+      if (targetEnum.MoveNext() | predEnum.MoveNext())
+        throw new ArgumentException("target and pred have differing lengths");
+    }
+
+    // return median of residuals
+    // targetArr and predArr are not changed by LineSearch
+    public double LineSearch(double[] targetArr, double[] predArr, int[] idx, int startIdx, int endIdx) {
+      if (targetArr.Length != predArr.Length)
+        throw new ArgumentException("target and pred have differing lengths");
+
+      // Median() is allocating an array anyway
+      // It would be possible to pre-allocated an array for the residuals if Median() would allow specification of a sub-range
+      int nRows = endIdx - startIdx + 1;
+      var res = new double[nRows];
+      for (int i = startIdx; i <= endIdx; i++) {
+        var row = idx[i];
+        res[i - startIdx] = targetArr[row] - predArr[row];
+      }
+      return res.Median(); // TODO: improve efficiency
+    }
+
+    #region item implementation
+    [StorableConstructor]
+    private AbsoluteErrorLoss(bool deserializing) : base(deserializing) { }
+
+    private AbsoluteErrorLoss(AbsoluteErrorLoss original, Cloner cloner) : base(original, cloner) { }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new AbsoluteErrorLoss(this, cloner);
+    }
+    #endregion
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GradientBoostedTrees/LossFunctions/ILossFunction.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GradientBoostedTrees/LossFunctions/ILossFunction.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GradientBoostedTrees/LossFunctions/ILossFunction.cs	(revision 13819)
@@ -0,0 +1,42 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ * and the BEACON Center for the Study of Evolution in Action.
+ * 
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Collections.Generic;
+using HeuristicLab.Core;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  // represents an interface for loss functions used by gradient boosting
+  // target represents the target vector  (original targets from the problem data, never changed)
+  // pred   represents the current vector of predictions (a weighted combination of models learned so far, this vector is updated after each step)
+  public interface ILossFunction : IItem {
+    // returns the loss of the current prediction vector 
+    double GetLoss(IEnumerable<double> target, IEnumerable<double> pred);
+
+    // returns an enumerable of the loss gradient for each row
+    IEnumerable<double> GetLossGradient(IEnumerable<double> target, IEnumerable<double> pred);
+
+    // returns the optimal value for the partition of rows stored in idx[startIdx] .. idx[endIdx] inclusive
+    double LineSearch(double[] targetArr, double[] predArr, int[] idx, int startIdx, int endIdx);
+  }
+}
+
+
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GradientBoostedTrees/LossFunctions/LogisticRegressionLoss.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GradientBoostedTrees/LossFunctions/LogisticRegressionLoss.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GradientBoostedTrees/LossFunctions/LogisticRegressionLoss.cs	(revision 13819)
@@ -0,0 +1,103 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ * and the BEACON Center for the Study of Evolution in Action.
+ * 
+ * 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.Diagnostics;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  // Greedy Function Approximation: A Gradient Boosting Machine (page 9) 
+  [StorableClass]
+  [Item("Logistic regression loss", "")]
+  public sealed class LogisticRegressionLoss : Item, ILossFunction {
+    public LogisticRegressionLoss() { }
+
+    public double GetLoss(IEnumerable<double> target, IEnumerable<double> pred) {
+      var targetEnum = target.GetEnumerator();
+      var predEnum = pred.GetEnumerator();
+
+      double s = 0;
+      while (targetEnum.MoveNext() & predEnum.MoveNext()) {
+        Debug.Assert(targetEnum.Current.IsAlmost(0.0) || targetEnum.Current.IsAlmost(1.0), "labels must be 0 or 1 for logistic regression loss");
+
+        var y = targetEnum.Current * 2 - 1; // y in {-1,1}
+        s += Math.Log(1 + Math.Exp(-2 * y * predEnum.Current));
+      }
+      if (targetEnum.MoveNext() | predEnum.MoveNext())
+        throw new ArgumentException("target and pred have different lengths");
+
+      return s;
+    }
+
+    public IEnumerable<double> GetLossGradient(IEnumerable<double> target, IEnumerable<double> pred) {
+      var targetEnum = target.GetEnumerator();
+      var predEnum = pred.GetEnumerator();
+
+      while (targetEnum.MoveNext() & predEnum.MoveNext()) {
+        Debug.Assert(targetEnum.Current.IsAlmost(0.0) || targetEnum.Current.IsAlmost(1.0), "labels must be 0 or 1 for logistic regression loss");
+        var y = targetEnum.Current * 2 - 1; // y in {-1,1}
+
+        yield return 2 * y / (1 + Math.Exp(2 * y * predEnum.Current));
+
+      }
+      if (targetEnum.MoveNext() | predEnum.MoveNext())
+        throw new ArgumentException("target and pred have different lengths");
+    }
+
+    // targetArr and predArr are not changed by LineSearch
+    public double LineSearch(double[] targetArr, double[] predArr, int[] idx, int startIdx, int endIdx) {
+      if (targetArr.Length != predArr.Length)
+        throw new ArgumentException("target and pred have different lengths");
+
+      // "Simple Newton-Raphson step" of eqn. 23 
+      double sumY = 0.0;
+      double sumDiff = 0.0;
+      for (int i = startIdx; i <= endIdx; i++) {
+        var row = idx[i];
+        var y = targetArr[row] * 2 - 1; // y in {-1,1}
+        var pseudoResponse = 2 * y / (1 + Math.Exp(2 * y * predArr[row]));
+
+        sumY += pseudoResponse;
+        sumDiff += Math.Abs(pseudoResponse) * (2 - Math.Abs(pseudoResponse));
+      }
+      // prevent divByZero
+      sumDiff = Math.Max(1E-12, sumDiff);
+      return sumY / sumDiff;
+    }
+
+    #region item implementation
+    [StorableConstructor]
+    private LogisticRegressionLoss(bool deserializing) : base(deserializing) { }
+
+    private LogisticRegressionLoss(LogisticRegressionLoss original, Cloner cloner) : base(original, cloner) { }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new LogisticRegressionLoss(this, cloner);
+    }
+    #endregion
+
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GradientBoostedTrees/LossFunctions/QuantileRegressionLoss.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GradientBoostedTrees/LossFunctions/QuantileRegressionLoss.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GradientBoostedTrees/LossFunctions/QuantileRegressionLoss.cs	(revision 13819)
@@ -0,0 +1,118 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ * and the BEACON Center for the Study of Evolution in Action.
+ * 
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  // loss function for quantile regression
+  // Generalized Boosted Models - A Guide To The gbm Package, Greg Ridgeway, August 2007, page 11 
+  [StorableClass]
+  [Item("QuantileRegressionloss", "Loss function for quantile regression")]
+  public sealed class QuantileRegressionLoss : ParameterizedNamedItem, ILossFunction {
+    public IFixedValueParameter<PercentValue> AlphaParameter {
+      get { return (IFixedValueParameter<PercentValue>)Parameters["Alpha"]; }
+    }
+
+    public double Alpha {
+      get { return AlphaParameter.Value.Value; }
+      set {
+        if (value <= 0.0 || value >= 1.0) throw new ArgumentException("Valid values for alpha: 0 < alpha < 1");
+        AlphaParameter.Value.Value = value;
+      }
+    }
+
+    public QuantileRegressionLoss()
+      : base("QuantileRegressionLoss", "Loss function for quantile regression") {
+      Parameters.Add(new FixedValueParameter<PercentValue>("Alpha", new PercentValue(0.9)));
+    }
+
+    public double GetLoss(IEnumerable<double> target, IEnumerable<double> pred) {
+      var targetEnum = target.GetEnumerator();
+      var predEnum = pred.GetEnumerator();
+      var alpha = Alpha;
+      double leftSum = 0;
+      double rightsum = 0;
+      while (targetEnum.MoveNext() & predEnum.MoveNext()) {
+        double res = targetEnum.Current - predEnum.Current;
+        if (res > 0) leftSum += res;
+        else rightsum += -res;
+      }
+      if (targetEnum.MoveNext() | predEnum.MoveNext())
+        throw new ArgumentException("target and pred have differing lengths");
+
+      return alpha * leftSum + (1 - alpha) * rightsum;
+    }
+
+    public IEnumerable<double> GetLossGradient(IEnumerable<double> target, IEnumerable<double> pred) {
+      var targetEnum = target.GetEnumerator();
+      var predEnum = pred.GetEnumerator();
+      var alpha = AlphaParameter.Value.Value;
+
+      while (targetEnum.MoveNext() & predEnum.MoveNext()) {
+        var res = targetEnum.Current - predEnum.Current;
+        if (res > 0) yield return alpha;
+        else if (res < 0) yield return -(1.0 - alpha);
+        else yield return 0.0;
+      }
+      if (targetEnum.MoveNext() | predEnum.MoveNext())
+        throw new ArgumentException("target and pred have differing lengths");
+    }
+
+    // targetArr and predArr are not changed by LineSearch
+    public double LineSearch(double[] targetArr, double[] predArr, int[] idx, int startIdx, int endIdx) {
+      if (targetArr.Length != predArr.Length)
+        throw new ArgumentException("target and pred have differing lengths");
+
+      // Quantile() is allocating an array anyway
+      // It would be possible to pre-allocated an array for the residuals if Quantile() would allow specification of a sub-range
+      int nRows = endIdx - startIdx + 1;
+      var res = new double[nRows];
+      for (int i = startIdx; i <= endIdx; i++) {
+        var row = idx[i];
+        res[i - startIdx] = targetArr[row] - predArr[row];
+      }
+      return res.Quantile(Alpha);
+    }
+
+    #region item implementation
+    [StorableConstructor]
+    private QuantileRegressionLoss(bool deserializing) : base(deserializing) { }
+
+    private QuantileRegressionLoss(QuantileRegressionLoss original, Cloner cloner)
+      : base(original, cloner) {
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new QuantileRegressionLoss(this, cloner);
+    }
+    #endregion
+
+    public override bool CanChangeName { get { return false; } }
+    public override bool CanChangeDescription { get { return false; } }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GradientBoostedTrees/LossFunctions/RelativeErrorLoss.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GradientBoostedTrees/LossFunctions/RelativeErrorLoss.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GradientBoostedTrees/LossFunctions/RelativeErrorLoss.cs	(revision 13819)
@@ -0,0 +1,124 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ * and the BEACON Center for the Study of Evolution in Action.
+ * 
+ * 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.Diagnostics;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  // relative error loss is a special case of weighted absolute error loss with weights = (1/target)
+  [StorableClass]
+  [Item("Relative error loss", "")]
+  public sealed class RelativeErrorLoss : Item, ILossFunction {
+    public RelativeErrorLoss() { }
+
+    public double GetLoss(IEnumerable<double> target, IEnumerable<double> pred) {
+      var targetEnum = target.GetEnumerator();
+      var predEnum = pred.GetEnumerator();
+
+      double s = 0;
+      while (targetEnum.MoveNext() & predEnum.MoveNext()) {
+        double res = targetEnum.Current - predEnum.Current;
+        s += Math.Abs(res) * Math.Abs(1.0 / targetEnum.Current);
+      }
+      if (targetEnum.MoveNext() | predEnum.MoveNext())
+        throw new ArgumentException("target and pred have different lengths");
+
+      return s;
+    }
+
+    public IEnumerable<double> GetLossGradient(IEnumerable<double> target, IEnumerable<double> pred) {
+      var targetEnum = target.GetEnumerator();
+      var predEnum = pred.GetEnumerator();
+
+      while (targetEnum.MoveNext() & predEnum.MoveNext()) {
+        // sign(res) * abs(1 / target)
+        var res = targetEnum.Current - predEnum.Current;
+        if (res > 0) yield return 1.0 / Math.Abs(targetEnum.Current);
+        else if (res < 0) yield return -1.0 / Math.Abs(targetEnum.Current);
+        else yield return 0.0;
+      }
+      if (targetEnum.MoveNext() | predEnum.MoveNext())
+        throw new ArgumentException("target and pred have different lengths");
+    }
+
+    // targetArr and predArr are not changed by LineSearch
+    public double LineSearch(double[] targetArr, double[] predArr, int[] idx, int startIdx, int endIdx) {
+      if (targetArr.Length != predArr.Length)
+        throw new ArgumentException("target and pred have different lengths");
+
+      // line search for relative error
+      // weighted median (weight = 1/target)
+      int nRows = endIdx - startIdx + 1; // startIdx and endIdx are inclusive
+      if (nRows == 1) return targetArr[idx[startIdx]] - predArr[idx[startIdx]]; // res 
+      else if (nRows == 2) {
+        // weighted average of two residuals
+        var w0 = Math.Abs(1.0 / targetArr[idx[startIdx]]);
+        var w1 = Math.Abs(1.0 / targetArr[idx[endIdx]]);
+        if (w0 > w1) {
+          return targetArr[idx[startIdx]] - predArr[idx[startIdx]];
+        } else if (w0 < w1) {
+          return targetArr[idx[endIdx]] - predArr[idx[endIdx]];
+        } else {
+          // same weight -> return average of both residuals
+          return ((targetArr[idx[startIdx]] - predArr[idx[startIdx]]) + (targetArr[idx[endIdx]] - predArr[idx[endIdx]])) / 2;
+        }
+      } else {
+        // create an array of key-value pairs to be sorted (instead of using Array.Sort(res, weights))
+        var res_w = new KeyValuePair<double, double>[nRows];
+        var totalWeight = 0.0;
+        for (int i = startIdx; i <= endIdx; i++) {
+          int row = idx[i];
+          var res = targetArr[row] - predArr[row];
+          var w = Math.Abs(1.0 / targetArr[row]);
+          res_w[i - startIdx] = new KeyValuePair<double, double>(res, w);
+          totalWeight += w;
+        }
+        // TODO: improve efficiency (find median without sort)
+        res_w.StableSort((a, b) => Math.Sign(a.Key - b.Key));
+
+        int k = 0;
+        double sum = totalWeight - res_w[k].Value; // total - first weight
+        while (sum > totalWeight / 2) {
+          k++;
+          sum -= res_w[k].Value;
+        }
+        return res_w[k].Key;
+      }
+    }
+
+    #region item implementation
+    [StorableConstructor]
+    private RelativeErrorLoss(bool deserializing) : base(deserializing) { }
+
+    private RelativeErrorLoss(RelativeErrorLoss original, Cloner cloner) : base(original, cloner) { }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new RelativeErrorLoss(this, cloner);
+    }
+    #endregion
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GradientBoostedTrees/LossFunctions/SquaredErrorLoss.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GradientBoostedTrees/LossFunctions/SquaredErrorLoss.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GradientBoostedTrees/LossFunctions/SquaredErrorLoss.cs	(revision 13819)
@@ -0,0 +1,90 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ * and the BEACON Center for the Study of Evolution in Action.
+ * 
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  [StorableClass]
+  [Item("Squared error loss", "")]
+  public sealed class SquaredErrorLoss : Item, ILossFunction {
+    public SquaredErrorLoss() { }
+
+    public double GetLoss(IEnumerable<double> target, IEnumerable<double> pred) {
+      var targetEnum = target.GetEnumerator();
+      var predEnum = pred.GetEnumerator();
+
+      double s = 0;
+      while (targetEnum.MoveNext() & predEnum.MoveNext()) {
+        double res = targetEnum.Current - predEnum.Current;
+        s += res * res; // (res)^2
+      }
+      if (targetEnum.MoveNext() | predEnum.MoveNext())
+        throw new ArgumentException("target and pred have different lengths");
+
+      return s;
+    }
+
+    public IEnumerable<double> GetLossGradient(IEnumerable<double> target, IEnumerable<double> pred) {
+      var targetEnum = target.GetEnumerator();
+      var predEnum = pred.GetEnumerator();
+
+      while (targetEnum.MoveNext() & predEnum.MoveNext()) {
+        yield return 2.0 * (targetEnum.Current - predEnum.Current); // dL(y, f(x)) / df(x)  = 2 * res 
+      }
+      if (targetEnum.MoveNext() | predEnum.MoveNext())
+        throw new ArgumentException("target and pred have different lengths");
+    }
+
+    // targetArr and predArr are not changed by LineSearch
+    public double LineSearch(double[] targetArr, double[] predArr, int[] idx, int startIdx, int endIdx) {
+      if (targetArr.Length != predArr.Length)
+        throw new ArgumentException("target and pred have different lengths");
+
+      // line search for squared error loss 
+      // for a given partition of rows the optimal constant that should be added to the current prediction values is the average of the residuals
+      double s = 0.0;
+      int n = 0;
+      for (int i = startIdx; i <= endIdx; i++) {
+        int row = idx[i];
+        s += (targetArr[row] - predArr[row]);
+        n++;
+      }
+      return s / n;
+    }
+
+    #region item implementation
+    [StorableConstructor]
+    private SquaredErrorLoss(bool deserializing) : base(deserializing) { }
+
+    private SquaredErrorLoss(SquaredErrorLoss original, Cloner cloner) : base(original, cloner) { }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new SquaredErrorLoss(this, cloner);
+    }
+    #endregion
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GradientBoostedTrees/RegressionTreeBuilder.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GradientBoostedTrees/RegressionTreeBuilder.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GradientBoostedTrees/RegressionTreeBuilder.cs	(revision 13819)
@@ -0,0 +1,474 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ * and the BEACON Center for the Study of Evolution in Action.
+ * 
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using HeuristicLab.Core;
+using HeuristicLab.Problems.DataAnalysis;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  // This class implements a greedy decision tree learner which selects splits with the maximum reduction in sum of squared errors.
+  // The tree builder also tracks variable relevance metrics based on the splits and improvement after the split.
+  // The implementation is tuned for gradient boosting where multiple trees have to be calculated for the same training data 
+  // each time with a different target vector. Vectors of idx to allow iteration of intput variables in sorted order are
+  // pre-calculated so that optimal thresholds for splits can be calculated in O(n) for each input variable.
+  // After each split the row idx are partitioned in a left an right part.
+  internal class RegressionTreeBuilder {
+    private readonly IRandom random;
+    private readonly IRegressionProblemData problemData;
+
+    private readonly int nCols;
+    private readonly double[][] x; // all training data (original order from problemData), x is constant
+    private double[] originalY; // the original target labels (from problemData), originalY is constant
+    private double[] curPred; // current predictions for originalY (in case we are using gradient boosting, otherwise = zeros), only necessary for line search
+
+    private double[] y; // training labels (original order from problemData), y can be changed
+
+    private Dictionary<string, double> sumImprovements; // for variable relevance calculation
+
+    private readonly string[] allowedVariables; // all variables in shuffled order
+    private Dictionary<string, int> varName2Index; // maps the variable names to column indexes 
+    private int effectiveVars; // number of variables that are used from allowedVariables
+
+    private int effectiveRows; // number of rows that are used from 
+    private readonly int[][] sortedIdxAll;
+    private readonly int[][] sortedIdx; // random selection from sortedIdxAll (for r < 1.0)
+
+    // helper arrays which are allocated to maximal necessary size only once in the ctor
+    private readonly int[] internalIdx, which, leftTmp, rightTmp;
+    private readonly double[] outx;
+    private readonly int[] outSortedIdx;
+
+    private RegressionTreeModel.TreeNode[] tree; // tree is represented as a flat array of nodes
+    private int curTreeNodeIdx; // the index where the next tree node is stored
+
+    // This class represents information about potential splits.
+    // For each node generated the best splitting variable and threshold as well as
+    // the improvement from the split are stored in a priority queue
+    private class PartitionSplits {
+      public int ParentNodeIdx { get; set; } // the idx of the leaf node representing this partition 
+      public int StartIdx { get; set; } // the start idx of the partition
+      public int EndIndex { get; set; } // the end idx of the partition
+      public string SplittingVariable { get; set; } // the best splitting variable
+      public double SplittingThreshold { get; set; } // the best threshold
+      public double SplittingImprovement { get; set; } // the improvement of the split (for priority queue)
+    }
+
+    // this list hold partitions with the information about the best split (organized as a sorted queue)
+    private readonly IList<PartitionSplits> queue;
+
+    // prepare and allocate buffer variables in ctor
+    public RegressionTreeBuilder(IRegressionProblemData problemData, IRandom random) {
+      this.problemData = problemData;
+      this.random = random;
+
+      var rows = problemData.TrainingIndices.Count();
+
+      this.nCols = problemData.AllowedInputVariables.Count();
+
+      allowedVariables = problemData.AllowedInputVariables.ToArray();
+      varName2Index = new Dictionary<string, int>(allowedVariables.Length);
+      for (int i = 0; i < allowedVariables.Length; i++) varName2Index.Add(allowedVariables[i], i);
+
+      sortedIdxAll = new int[nCols][];
+      sortedIdx = new int[nCols][];
+      sumImprovements = new Dictionary<string, double>();
+      internalIdx = new int[rows];
+      which = new int[rows];
+      leftTmp = new int[rows];
+      rightTmp = new int[rows];
+      outx = new double[rows];
+      outSortedIdx = new int[rows];
+      queue = new List<PartitionSplits>(100);
+
+      x = new double[nCols][];
+      originalY = problemData.Dataset.GetDoubleValues(problemData.TargetVariable, problemData.TrainingIndices).ToArray();
+      y = new double[originalY.Length];
+      Array.Copy(originalY, y, y.Length); // copy values (originalY is fixed, y is changed in gradient boosting)
+      curPred = Enumerable.Repeat(0.0, y.Length).ToArray(); // zeros
+
+      int col = 0;
+      foreach (var inputVariable in problemData.AllowedInputVariables) {
+        x[col] = problemData.Dataset.GetDoubleValues(inputVariable, problemData.TrainingIndices).ToArray();
+        sortedIdxAll[col] = Enumerable.Range(0, rows).OrderBy(r => x[col][r]).ToArray();
+        sortedIdx[col] = new int[rows];
+        col++;
+      }
+    }
+
+    // specific interface that allows to specify the target labels and the training rows which is necessary when for gradient boosted trees
+    public IRegressionModel CreateRegressionTreeForGradientBoosting(double[] y, double[] curPred, int maxSize, int[] idx, ILossFunction lossFunction, double r = 0.5, double m = 0.5) {
+      Debug.Assert(maxSize > 0);
+      Debug.Assert(r > 0);
+      Debug.Assert(r <= 1.0);
+      Debug.Assert(y.Count() == this.y.Length);
+      Debug.Assert(m > 0);
+      Debug.Assert(m <= 1.0);
+
+      // y and curPred are changed in gradient boosting
+      this.y = y; 
+      this.curPred = curPred; 
+
+      // shuffle row idx
+      HeuristicLab.Random.ListExtensions.ShuffleInPlace(idx, random);
+
+      int nRows = idx.Count();
+
+      // shuffle variable idx
+      HeuristicLab.Random.ListExtensions.ShuffleInPlace(allowedVariables, random);
+
+      // only select a part of the rows and columns randomly
+      effectiveRows = (int)Math.Ceiling(nRows * r);
+      effectiveVars = (int)Math.Ceiling(nCols * m);
+
+      // the which array is used for partitioing row idxs  
+      Array.Clear(which, 0, which.Length);
+
+      // mark selected rows
+      for (int row = 0; row < effectiveRows; row++) {
+        which[idx[row]] = 1; // we use the which vector as a temporary variable here
+        internalIdx[row] = idx[row];
+      }
+
+      for (int col = 0; col < nCols; col++) {
+        int i = 0;
+        for (int row = 0; row < nRows; row++) {
+          if (which[sortedIdxAll[col][row]] > 0) {
+            Debug.Assert(i < effectiveRows);
+            sortedIdx[col][i] = sortedIdxAll[col][row];
+            i++;
+          }
+        }
+      }
+
+      this.tree = new RegressionTreeModel.TreeNode[maxSize];
+      this.queue.Clear();
+      this.curTreeNodeIdx = 0;
+
+      // start out with only one leaf node (constant prediction)
+      // and calculate the best split for this root node and enqueue it into a queue sorted by improvement throught the split
+      // start and end idx are inclusive
+      CreateLeafNode(0, effectiveRows - 1, lossFunction);
+
+      // process the priority queue to complete the tree
+      CreateRegressionTreeFromQueue(maxSize, lossFunction);
+
+      return new RegressionTreeModel(tree.ToArray());
+    }
+
+
+    // processes potential splits from the queue as long as splits are left and the maximum size of the tree is not reached
+    private void CreateRegressionTreeFromQueue(int maxNodes, ILossFunction lossFunction) {
+      while (queue.Any() && curTreeNodeIdx + 1 < maxNodes) { // two nodes are created in each loop
+        var f = queue[queue.Count - 1]; // last element has the largest improvement
+        queue.RemoveAt(queue.Count - 1);
+
+        var startIdx = f.StartIdx;
+        var endIdx = f.EndIndex;
+
+        Debug.Assert(endIdx - startIdx >= 0);
+        Debug.Assert(startIdx >= 0);
+        Debug.Assert(endIdx < internalIdx.Length);
+
+        // split partition into left and right
+        int splitIdx;
+        SplitPartition(f.StartIdx, f.EndIndex, f.SplittingVariable, f.SplittingThreshold, out splitIdx);
+        Debug.Assert(splitIdx + 1 <= endIdx);
+        Debug.Assert(startIdx <= splitIdx);
+
+        // create two leaf nodes (and enqueue best splits for both)
+        var leftTreeIdx = CreateLeafNode(startIdx, splitIdx, lossFunction);
+        var rightTreeIdx = CreateLeafNode(splitIdx + 1, endIdx, lossFunction);
+
+        // overwrite existing leaf node with an internal node
+        tree[f.ParentNodeIdx] = new RegressionTreeModel.TreeNode(f.SplittingVariable, f.SplittingThreshold, leftTreeIdx, rightTreeIdx);
+      }
+    }
+
+
+    // returns the index of the newly created tree node
+    private int CreateLeafNode(int startIdx, int endIdx, ILossFunction lossFunction) {
+      // write a leaf node
+      var val = lossFunction.LineSearch(originalY, curPred, internalIdx, startIdx, endIdx);
+      tree[curTreeNodeIdx] = new RegressionTreeModel.TreeNode(RegressionTreeModel.TreeNode.NO_VARIABLE, val);
+
+      EnqueuePartitionSplit(curTreeNodeIdx, startIdx, endIdx);
+      curTreeNodeIdx++;
+      return curTreeNodeIdx - 1;
+    }
+
+
+    // calculates the optimal split for the partition [startIdx .. endIdx] (inclusive) 
+    // which is represented by the leaf node with the specified nodeIdx
+    private void EnqueuePartitionSplit(int nodeIdx, int startIdx, int endIdx) {
+      double threshold, improvement;
+      string bestVariableName;
+      // only enqueue a new split if there are at least 2 rows left and a split is possible
+      if (startIdx < endIdx &&
+        FindBestVariableAndThreshold(startIdx, endIdx, out threshold, out bestVariableName, out improvement)) {
+        var split = new PartitionSplits() {
+          ParentNodeIdx = nodeIdx,
+          StartIdx = startIdx,
+          EndIndex = endIdx,
+          SplittingThreshold = threshold,
+          SplittingVariable = bestVariableName
+        };
+        InsertSortedQueue(split);
+      }
+    }
+
+
+    // routine for splitting a partition of rows stored in internalIdx between startIdx and endIdx into
+    // a left partition and a right partition using the given splittingVariable and threshold
+    // the splitIdx is the last index of the left partition 
+    // splitIdx + 1 is the first index of the right partition
+    // startIdx and endIdx are inclusive
+    private void SplitPartition(int startIdx, int endIdx, string splittingVar, double threshold, out int splitIdx) {
+      int bestVarIdx = varName2Index[splittingVar];
+      // split - two pass
+
+      // store which index goes into which partition 
+      for (int k = startIdx; k <= endIdx; k++) {
+        if (x[bestVarIdx][internalIdx[k]] <= threshold)
+          which[internalIdx[k]] = -1; // left partition
+        else
+          which[internalIdx[k]] = 1; // right partition
+      }
+
+      // partition sortedIdx for each variable
+      int i;
+      int j;
+      for (int col = 0; col < nCols; col++) {
+        i = 0;
+        j = 0;
+        int k;
+        for (k = startIdx; k <= endIdx; k++) {
+          Debug.Assert(Math.Abs(which[sortedIdx[col][k]]) == 1);
+
+          if (which[sortedIdx[col][k]] < 0) {
+            leftTmp[i++] = sortedIdx[col][k];
+          } else {
+            rightTmp[j++] = sortedIdx[col][k];
+          }
+        }
+        Debug.Assert(i > 0); // at least on element in the left partition
+        Debug.Assert(j > 0); // at least one element in the right partition
+        Debug.Assert(i + j == endIdx - startIdx + 1);
+        k = startIdx;
+        for (int l = 0; l < i; l++) sortedIdx[col][k++] = leftTmp[l];
+        for (int l = 0; l < j; l++) sortedIdx[col][k++] = rightTmp[l];
+      }
+
+      // partition row indices
+      i = startIdx;
+      j = endIdx;
+      while (i <= j) {
+        Debug.Assert(Math.Abs(which[internalIdx[i]]) == 1);
+        Debug.Assert(Math.Abs(which[internalIdx[j]]) == 1);
+        if (which[internalIdx[i]] < 0) i++;
+        else if (which[internalIdx[j]] > 0) j--;
+        else {
+          Debug.Assert(which[internalIdx[i]] > 0);
+          Debug.Assert(which[internalIdx[j]] < 0);
+          // swap
+          int tmp = internalIdx[i];
+          internalIdx[i] = internalIdx[j];
+          internalIdx[j] = tmp;
+          i++;
+          j--;
+        }
+      }
+      Debug.Assert(j + 1 == i);
+      Debug.Assert(i <= endIdx);
+      Debug.Assert(startIdx <= j);
+
+      splitIdx = j;
+    }
+
+    private bool FindBestVariableAndThreshold(int startIdx, int endIdx, out double threshold, out string bestVar, out double improvement) {
+      Debug.Assert(startIdx < endIdx + 1); // at least 2 elements
+
+      int rows = endIdx - startIdx + 1;
+      Debug.Assert(rows >= 2);
+
+      double sumY = 0.0;
+      for (int i = startIdx; i <= endIdx; i++) {
+        sumY += y[internalIdx[i]];
+      }
+
+      // see description of calculation in FindBestThreshold
+      double bestImprovement = 1.0 / rows * sumY * sumY; // any improvement must be larger than this baseline
+      double bestThreshold = double.PositiveInfinity;
+      bestVar = RegressionTreeModel.TreeNode.NO_VARIABLE;
+
+      for (int col = 0; col < effectiveVars; col++) {
+        // sort values for variable to prepare for threshold selection 
+        var curVariable = allowedVariables[col];
+        var curVariableIdx = varName2Index[curVariable];
+        for (int i = startIdx; i <= endIdx; i++) {
+          var sortedI = sortedIdx[curVariableIdx][i];
+          outSortedIdx[i - startIdx] = sortedI;
+          outx[i - startIdx] = x[curVariableIdx][sortedI];
+        }
+
+        double curImprovement;
+        double curThreshold;
+        FindBestThreshold(outx, outSortedIdx, rows, y, sumY, out curThreshold, out curImprovement);
+
+        if (curImprovement > bestImprovement) {
+          bestImprovement = curImprovement;
+          bestThreshold = curThreshold;
+          bestVar = allowedVariables[col];
+        }
+      }
+      if (bestVar == RegressionTreeModel.TreeNode.NO_VARIABLE) {
+        // not successfull
+        threshold = double.PositiveInfinity;
+        improvement = double.NegativeInfinity;
+        return false;
+      } else {
+        UpdateVariableRelevance(bestVar, sumY, bestImprovement, rows);
+        improvement = bestImprovement;
+        threshold = bestThreshold;
+        return true;
+      }
+    }
+
+    // x [0..N-1] contains rows sorted values in the range from [0..rows-1]
+    // sortedIdx [0..N-1] contains the idx of the values in x in the original dataset in the range from [0..rows-1]
+    // rows specifies the number of valid entries in x and sortedIdx
+    // y [0..N-1] contains the target values in original sorting order
+    // sumY is y.Sum()
+    // 
+    // the routine returns the best threshold (x[i] + x[i+1]) / 2 for i = [0 .. rows-2] by calculating the reduction in squared error
+    // additionally the reduction in squared error is returned in bestImprovement
+    // if all elements of x are equal the routing fails to produce a threshold
+    private static void FindBestThreshold(double[] x, int[] sortedIdx, int rows, double[] y, double sumY, out double bestThreshold, out double bestImprovement) {
+      Debug.Assert(rows >= 2);
+
+      double sl = 0.0;
+      double sr = sumY;
+      double nl = 0.0;
+      double nr = rows;
+
+      bestImprovement = 1.0 / rows * sumY * sumY; // this is the baseline for the improvement
+      bestThreshold = double.NegativeInfinity;
+      // for all thresholds
+      // if we have n rows there are n-1 possible splits
+      for (int i = 0; i < rows - 1; i++) {
+        sl += y[sortedIdx[i]];
+        sr -= y[sortedIdx[i]];
+
+        nl++;
+        nr--;
+        Debug.Assert(nl > 0);
+        Debug.Assert(nr > 0);
+
+        if (x[i] < x[i + 1]) { // don't try to split when two elements are equal
+
+          // goal is to find the split with leading to minimal total variance of left and right parts
+          // without partitioning the variance is var(y) = E(y²) - E(y)²  
+          //    = 1/n * sum(y²) - (1/n * sum(y))²
+          //      -------------   ---------------
+          //         constant       baseline for improvement
+          // 
+          // if we split into right and left part the overall variance is the weigthed combination nl/n * var(y_l) + nr/n * var(y_r)  
+          //    = nl/n * (1/nl * sum(y_l²) - (1/nl * sum(y_l))²) + nr/n * (1/nr * sum(y_r²) - (1/nr * sum(y_r))²)
+          //    = 1/n * sum(y_l²) - 1/nl * 1/n * sum(y_l)² + 1/n * sum(y_r²) - 1/nr * 1/n * sum(y_r)²
+          //    = 1/n * (sum(y_l²) + sum(y_r²)) - 1/n * (sum(y_l)² / nl + sum(y_r)² / nr)
+          //    = 1/n * sum(y²) - 1/n * (sum(y_l)² / nl + sum(y_r)² / nr)
+          //      -------------
+          //       not changed by split (and the same for total variance without partitioning)
+          //
+          //   therefore we need to find the maximum value (sum(y_l)² / nl + sum(y_r)² / nr) (ignoring the factor 1/n)
+          //   and this value must be larger than 1/n * sum(y)² to be an improvement over no split 
+
+          double curQuality = sl * sl / nl + sr * sr / nr;
+
+          if (curQuality > bestImprovement) {
+            bestThreshold = (x[i] + x[i + 1]) / 2.0;
+            bestImprovement = curQuality;
+          }
+        }
+      }
+
+      // if all elements where the same then no split can be found
+    }
+
+
+    private void UpdateVariableRelevance(string bestVar, double sumY, double bestImprovement, int rows) {
+      if (string.IsNullOrEmpty(bestVar)) return;
+      // update variable relevance
+      double baseLine = 1.0 / rows * sumY * sumY; // if best improvement is equal to baseline then the split had no effect
+
+      double delta = (bestImprovement - baseLine);
+      double v;
+      if (!sumImprovements.TryGetValue(bestVar, out v)) {
+        sumImprovements[bestVar] = delta;
+      }
+      sumImprovements[bestVar] = v + delta;
+    }
+
+    public IEnumerable<KeyValuePair<string, double>> GetVariableRelevance() {
+      // values are scaled: the most important variable has relevance = 100
+      double scaling = 100 / sumImprovements.Max(t => t.Value);
+      return
+        sumImprovements
+        .Select(t => new KeyValuePair<string, double>(t.Key, t.Value * scaling))
+        .OrderByDescending(t => t.Value);
+    }
+
+
+    // insert a new parition split (find insertion point and start at first element of the queue)
+    // elements are removed from the queue at the last position
+    // O(n), splits could be organized as a heap to improve runtime (see alglib tsort)
+    private void InsertSortedQueue(PartitionSplits split) {
+      // find insertion position
+      int i = 0;
+      while (i < queue.Count && queue[i].SplittingImprovement < split.SplittingImprovement) { i++; }
+
+      queue.Insert(i, split);
+    }
+  }
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GradientBoostedTrees/RegressionTreeModel.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GradientBoostedTrees/RegressionTreeModel.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/GradientBoostedTrees/RegressionTreeModel.cs	(revision 13819)
@@ -0,0 +1,155 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ * and the BEACON Center for the Study of Evolution in Action.
+ * 
+ * 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.Collections.ObjectModel;
+using System.Globalization;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Problems.DataAnalysis;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  [StorableClass]
+  [Item("RegressionTreeModel", "Represents a decision tree for regression.")]
+  public sealed class RegressionTreeModel : NamedItem, IRegressionModel {
+
+    // trees are represented as a flat array    
+    internal struct TreeNode {
+      public readonly static string NO_VARIABLE = null;
+
+      public TreeNode(string varName, double val, int leftIdx = -1, int rightIdx = -1)
+        : this() {
+        VarName = varName;
+        Val = val;
+        LeftIdx = leftIdx;
+        RightIdx = rightIdx;
+      }
+
+      public string VarName { get; private set; } // name of the variable for splitting or NO_VARIABLE if terminal node
+      public double Val { get; private set; } // threshold
+      public int LeftIdx { get; private set; }
+      public int RightIdx { get; private set; }
+
+      // necessary because the default implementation of GetHashCode for structs in .NET would only return the hashcode of val here
+      public override int GetHashCode() {
+        return LeftIdx ^ RightIdx ^ Val.GetHashCode();
+      }
+      // necessary because of GetHashCode override
+      public override bool Equals(object obj) {
+        if (obj is TreeNode) {
+          var other = (TreeNode)obj;
+          return Val.Equals(other.Val) &&
+            LeftIdx.Equals(other.LeftIdx) &&
+            RightIdx.Equals(other.RightIdx) &&
+            EqualStrings(VarName, other.VarName);
+        } else {
+          return false;
+        }
+      }
+
+      private bool EqualStrings(string a, string b) {
+        return (a == null && b == null) ||
+               (a != null && b != null && a.Equals(b));
+      }
+    }
+
+    // not storable!
+    private TreeNode[] tree;
+
+    [Storable]
+    // to prevent storing the references to data caches in nodes
+    // TODO seemingly it is bad (performance-wise) to persist tuples (tuples are used as keys in a dictionary)
+    private Tuple<string, double, int, int>[] SerializedTree {
+      get { return tree.Select(t => Tuple.Create(t.VarName, t.Val, t.LeftIdx, t.RightIdx)).ToArray(); }
+      set { this.tree = value.Select(t => new TreeNode(t.Item1, t.Item2, t.Item3, t.Item4)).ToArray(); }
+    }
+
+    [StorableConstructor]
+    private RegressionTreeModel(bool serializing) : base(serializing) { }
+    // cloning ctor
+    private RegressionTreeModel(RegressionTreeModel original, Cloner cloner)
+      : base(original, cloner) {
+      if (original.tree != null) {
+        this.tree = new TreeNode[original.tree.Length];
+        Array.Copy(original.tree, this.tree, this.tree.Length);
+      }
+    }
+
+    internal RegressionTreeModel(TreeNode[] tree)
+      : base("RegressionTreeModel", "Represents a decision tree for regression.") {
+      this.tree = tree;
+    }
+
+    private static double GetPredictionForRow(TreeNode[] t, ReadOnlyCollection<double>[] columnCache, int nodeIdx, int row) {
+      while (nodeIdx != -1) {
+        var node = t[nodeIdx];
+        if (node.VarName == TreeNode.NO_VARIABLE)
+          return node.Val;
+
+        if (columnCache[nodeIdx][row] <= node.Val)
+          nodeIdx = node.LeftIdx;
+        else
+          nodeIdx = node.RightIdx;
+      }
+      throw new InvalidOperationException("Invalid tree in RegressionTreeModel");
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new RegressionTreeModel(this, cloner);
+    }
+
+    public IEnumerable<double> GetEstimatedValues(IDataset ds, IEnumerable<int> rows) {
+      // lookup columns for variableNames in one pass over the tree to speed up evaluation later on
+      ReadOnlyCollection<double>[] columnCache = new ReadOnlyCollection<double>[tree.Length];
+
+      for (int i = 0; i < tree.Length; i++) {
+        if (tree[i].VarName != TreeNode.NO_VARIABLE) {
+          columnCache[i] = ds.GetReadOnlyDoubleValues(tree[i].VarName);
+        }
+      }
+      return rows.Select(r => GetPredictionForRow(tree, columnCache, 0, r));
+    }
+
+    public IRegressionSolution CreateRegressionSolution(IRegressionProblemData problemData) {
+      return new RegressionSolution(this, new RegressionProblemData(problemData));
+    }
+
+    // mainly for debugging
+    public override string ToString() {
+      return TreeToString(0, "");
+    }
+
+    private string TreeToString(int idx, string part) {
+      var n = tree[idx];
+      if (n.VarName == TreeNode.NO_VARIABLE) {
+        return string.Format(CultureInfo.InvariantCulture, "{0} -> {1:F}{2}", part, n.Val, Environment.NewLine);
+      } else {
+        return
+          TreeToString(n.LeftIdx, string.Format(CultureInfo.InvariantCulture, "{0}{1}{2} <= {3:F}", part, string.IsNullOrEmpty(part) ? "" : " and ", n.VarName, n.Val))
+        + TreeToString(n.RightIdx, string.Format(CultureInfo.InvariantCulture, "{0}{1}{2} >  {3:F}", part, string.IsNullOrEmpty(part) ? "" : " and ", n.VarName, n.Val));
+      }
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/HeuristicLab.Algorithms.DataAnalysis-3.4.csproj
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/HeuristicLab.Algorithms.DataAnalysis-3.4.csproj	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/HeuristicLab.Algorithms.DataAnalysis-3.4.csproj	(revision 13819)
@@ -0,0 +1,463 @@
+﻿<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProductVersion>9.0.30729</ProductVersion>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{2E782078-FA81-4B70-B56F-74CE38DAC6C8}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>HeuristicLab.Algorithms.DataAnalysis</RootNamespace>
+    <AssemblyName>HeuristicLab.Algorithms.DataAnalysis-3.4</AssemblyName>
+    <SignAssembly>true</SignAssembly>
+    <AssemblyOriginatorKeyFile>HeuristicLab.snk</AssemblyOriginatorKeyFile>
+    <FileUpgradeFlags>
+    </FileUpgradeFlags>
+    <OldToolsVersion>3.5</OldToolsVersion>
+    <UpgradeBackupLocation>
+    </UpgradeBackupLocation>
+    <StartupObject>
+    </StartupObject>
+    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
+    <TargetFrameworkProfile>
+    </TargetFrameworkProfile>
+    <PublishUrl>publish\</PublishUrl>
+    <Install>true</Install>
+    <InstallFrom>Disk</InstallFrom>
+    <UpdateEnabled>false</UpdateEnabled>
+    <UpdateMode>Foreground</UpdateMode>
+    <UpdateInterval>7</UpdateInterval>
+    <UpdateIntervalUnits>Days</UpdateIntervalUnits>
+    <UpdatePeriodically>false</UpdatePeriodically>
+    <UpdateRequired>false</UpdateRequired>
+    <MapFileExtensions>true</MapFileExtensions>
+    <ApplicationRevision>0</ApplicationRevision>
+    <ApplicationVersion>1.0.0.%2a</ApplicationVersion>
+    <IsWebBootstrapper>false</IsWebBootstrapper>
+    <UseApplicationTrust>false</UseApplicationTrust>
+    <BootstrapperEnabled>true</BootstrapperEnabled>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>..\..\..\..\trunk\sources\bin\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
+    <Prefer32Bit>false</Prefer32Bit>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>..\..\..\..\trunk\sources\bin\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <DocumentationFile>
+    </DocumentationFile>
+    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
+    <Prefer32Bit>false</Prefer32Bit>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
+    <DebugSymbols>true</DebugSymbols>
+    <OutputPath>..\..\..\..\trunk\sources\bin\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <DebugType>full</DebugType>
+    <PlatformTarget>x86</PlatformTarget>
+    <ErrorReport>prompt</ErrorReport>
+    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
+    <Prefer32Bit>false</Prefer32Bit>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
+    <OutputPath>..\..\..\..\trunk\sources\bin\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <DocumentationFile>
+    </DocumentationFile>
+    <Optimize>true</Optimize>
+    <DebugType>pdbonly</DebugType>
+    <PlatformTarget>x86</PlatformTarget>
+    <ErrorReport>prompt</ErrorReport>
+    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
+    <Prefer32Bit>false</Prefer32Bit>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x64' ">
+    <DebugSymbols>true</DebugSymbols>
+    <OutputPath>..\..\..\..\trunk\sources\bin\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <DebugType>full</DebugType>
+    <PlatformTarget>x64</PlatformTarget>
+    <ErrorReport>prompt</ErrorReport>
+    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
+    <Prefer32Bit>false</Prefer32Bit>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x64' ">
+    <OutputPath>..\..\..\..\trunk\sources\bin\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <DocumentationFile>
+    </DocumentationFile>
+    <Optimize>true</Optimize>
+    <DebugType>pdbonly</DebugType>
+    <PlatformTarget>x64</PlatformTarget>
+    <ErrorReport>prompt</ErrorReport>
+    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
+    <Prefer32Bit>false</Prefer32Bit>
+  </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="HeuristicLab.Algorithms.GradientDescent-3.3, Version=3.3.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\..\trunk\sources\bin\HeuristicLab.Algorithms.GradientDescent-3.3.dll</HintPath>
+    </Reference>
+    <Reference Include="HeuristicLab.Algorithms.OffspringSelectionGeneticAlgorithm-3.3, Version=3.3.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\..\trunk\sources\bin\HeuristicLab.Algorithms.OffspringSelectionGeneticAlgorithm-3.3.dll</HintPath>
+    </Reference>
+    <Reference Include="HeuristicLab.Analysis-3.3, Version=3.3.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\..\trunk\sources\bin\HeuristicLab.Analysis-3.3.dll</HintPath>
+    </Reference>
+    <Reference Include="HeuristicLab.Collections-3.3, Version=3.3.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\..\trunk\sources\bin\HeuristicLab.Collections-3.3.dll</HintPath>
+    </Reference>
+    <Reference Include="HeuristicLab.Common-3.3, Version=3.3.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\..\trunk\sources\bin\HeuristicLab.Common-3.3.dll</HintPath>
+    </Reference>
+    <Reference Include="HeuristicLab.Common.Resources-3.3, Version=3.3.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\..\trunk\sources\bin\HeuristicLab.Common.Resources-3.3.dll</HintPath>
+    </Reference>
+    <Reference Include="HeuristicLab.Core-3.3, Version=3.3.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\..\trunk\sources\bin\HeuristicLab.Core-3.3.dll</HintPath>
+    </Reference>
+    <Reference Include="HeuristicLab.Data-3.3, Version=3.3.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\..\trunk\sources\bin\HeuristicLab.Data-3.3.dll</HintPath>
+    </Reference>
+    <Reference Include="HeuristicLab.Encodings.RealVectorEncoding-3.3, Version=3.3.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\..\trunk\sources\bin\HeuristicLab.Encodings.RealVectorEncoding-3.3.dll</HintPath>
+    </Reference>
+    <Reference Include="HeuristicLab.Encodings.SymbolicExpressionTreeEncoding-3.4, Version=3.4.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\..\trunk\sources\bin\HeuristicLab.Encodings.SymbolicExpressionTreeEncoding-3.4.dll</HintPath>
+    </Reference>
+    <Reference Include="HeuristicLab.Operators-3.3, Version=3.3.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\..\trunk\sources\bin\HeuristicLab.Operators-3.3.dll</HintPath>
+    </Reference>
+    <Reference Include="HeuristicLab.Optimization-3.3, Version=3.3.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\..\trunk\sources\bin\HeuristicLab.Optimization-3.3.dll</HintPath>
+    </Reference>
+    <Reference Include="HeuristicLab.Parameters-3.3, Version=3.3.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\..\trunk\sources\bin\HeuristicLab.Parameters-3.3.dll</HintPath>
+    </Reference>
+    <Reference Include="HeuristicLab.Persistence-3.3, Version=3.3.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\..\trunk\sources\bin\HeuristicLab.Persistence-3.3.dll</HintPath>
+    </Reference>
+    <Reference Include="HeuristicLab.PluginInfrastructure-3.3, Version=3.3.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\..\trunk\sources\bin\HeuristicLab.PluginInfrastructure-3.3.dll</HintPath>
+    </Reference>
+    <Reference Include="HeuristicLab.Problems.DataAnalysis.Symbolic-3.4, Version=3.4.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\..\trunk\sources\bin\HeuristicLab.Problems.DataAnalysis.Symbolic-3.4.dll</HintPath>
+    </Reference>
+    <Reference Include="HeuristicLab.Problems.DataAnalysis.Symbolic.Classification-3.4, Version=3.4.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\..\trunk\sources\bin\HeuristicLab.Problems.DataAnalysis.Symbolic.Classification-3.4.dll</HintPath>
+    </Reference>
+    <Reference Include="HeuristicLab.Problems.DataAnalysis.Symbolic.Regression-3.4, Version=3.4.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\..\trunk\sources\bin\HeuristicLab.Problems.DataAnalysis.Symbolic.Regression-3.4.dll</HintPath>
+    </Reference>
+    <Reference Include="HeuristicLab.Problems.DataAnalysis.Symbolic.TimeSeriesPrognosis-3.4, Version=3.4.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\..\trunk\sources\bin\HeuristicLab.Problems.DataAnalysis.Symbolic.TimeSeriesPrognosis-3.4.dll</HintPath>
+    </Reference>
+    <Reference Include="HeuristicLab.Problems.Instances-3.3, Version=3.3.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\..\trunk\sources\bin\HeuristicLab.Problems.Instances-3.3.dll</HintPath>
+    </Reference>
+    <Reference Include="HeuristicLab.Random-3.3, Version=3.3.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\..\trunk\sources\bin\HeuristicLab.Random-3.3.dll</HintPath>
+    </Reference>
+    <Reference Include="HeuristicLab.Selection-3.3, Version=3.3.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\..\trunk\sources\bin\HeuristicLab.Selection-3.3.dll</HintPath>
+    </Reference>
+    <Reference Include="LibSVM-3.12, Version=3.12.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <HintPath>..\..\bin\LibSVM-3.12.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="System" />
+    <Reference Include="System.Core">
+      <RequiredTargetFramework>3.5</RequiredTargetFramework>
+    </Reference>
+    <Reference Include="System.Drawing" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="BaselineClassifiers\OneR.cs" />
+    <Compile Include="BaselineClassifiers\OneRClassificationModel.cs" />
+    <Compile Include="BaselineClassifiers\OneRClassificationSolution.cs" />
+    <Compile Include="BaselineClassifiers\ZeroR.cs" />
+    <Compile Include="CrossValidation.cs">
+      <SubType>Code</SubType>
+    </Compile>
+    <Compile Include="FixedDataAnalysisAlgorithm.cs" />
+    <Compile Include="GaussianProcess\StudentTProcessRegressionModelCreator.cs" />
+    <Compile Include="GaussianProcess\StudentTProcessModel.cs" />
+    <Compile Include="GaussianProcess\CovarianceFunctions\CovarianceSpectralMixture.cs" />
+    <Compile Include="GaussianProcess\CovarianceFunctions\CovariancePiecewisePolynomial.cs" />
+    <Compile Include="GaussianProcess\CovarianceFunctions\CovarianceNeuralNetwork.cs" />
+    <Compile Include="GaussianProcess\CovarianceFunctions\CovariancePolynomial.cs" />
+    <Compile Include="GaussianProcess\GaussianProcessBase.cs" />
+    <Compile Include="GaussianProcess\CovarianceFunctions\CovarianceConst.cs">
+      <SubType>Code</SubType>
+    </Compile>
+    <Compile Include="GaussianProcess\CovarianceFunctions\CovarianceLinear.cs">
+      <SubType>Code</SubType>
+    </Compile>
+    <Compile Include="GaussianProcess\CovarianceFunctions\CovarianceLinearArd.cs">
+      <SubType>Code</SubType>
+    </Compile>
+    <Compile Include="GaussianProcess\CovarianceFunctions\CovarianceMask.cs">
+      <SubType>Code</SubType>
+    </Compile>
+    <Compile Include="GaussianProcess\CovarianceFunctions\CovarianceMaternIso.cs">
+      <SubType>Code</SubType>
+    </Compile>
+    <Compile Include="GaussianProcess\CovarianceFunctions\CovarianceNoise.cs">
+      <SubType>Code</SubType>
+    </Compile>
+    <Compile Include="GaussianProcess\CovarianceFunctions\CovariancePeriodic.cs">
+      <SubType>Code</SubType>
+    </Compile>
+    <Compile Include="GaussianProcess\CovarianceFunctions\CovarianceProduct.cs">
+      <SubType>Code</SubType>
+    </Compile>
+    <Compile Include="GaussianProcess\CovarianceFunctions\CovarianceRationalQuadraticArd.cs">
+      <SubType>Code</SubType>
+    </Compile>
+    <Compile Include="GaussianProcess\CovarianceFunctions\CovarianceRationalQuadraticIso.cs">
+      <SubType>Code</SubType>
+    </Compile>
+    <Compile Include="GaussianProcess\CovarianceFunctions\CovarianceScale.cs">
+      <SubType>Code</SubType>
+    </Compile>
+    <Compile Include="GaussianProcess\CovarianceFunctions\CovarianceSquaredExponentialArd.cs">
+      <SubType>Code</SubType>
+    </Compile>
+    <Compile Include="GaussianProcess\CovarianceFunctions\CovarianceSquaredExponentialIso.cs" />
+    <Compile Include="GaussianProcess\CovarianceFunctions\CovarianceSum.cs">
+      <SubType>Code</SubType>
+    </Compile>
+    <Compile Include="GaussianProcess\GaussianProcessClassificationSolutionCreator.cs" />
+    <Compile Include="GaussianProcess\GaussianProcessClassificationModelCreator.cs" />
+    <Compile Include="GaussianProcess\GaussianProcessClassification.cs" />
+    <Compile Include="GaussianProcess\MeanFunctions\MeanModel.cs" />
+    <Compile Include="GaussianProcess\MeanFunctions\MeanConst.cs" />
+    <Compile Include="GaussianProcess\MeanFunctions\MeanLinear.cs" />
+    <Compile Include="GaussianProcess\MeanFunctions\MeanProduct.cs">
+      <SubType>Code</SubType>
+    </Compile>
+    <Compile Include="GaussianProcess\MeanFunctions\MeanSum.cs">
+      <SubType>Code</SubType>
+    </Compile>
+    <Compile Include="GaussianProcess\MeanFunctions\MeanZero.cs" />
+    <Compile Include="GaussianProcess\GaussianProcessHyperparameterInitializer.cs" />
+    <Compile Include="GaussianProcess\GaussianProcessRegressionSolutionCreator.cs" />
+    <Compile Include="GaussianProcess\GaussianProcessRegressionModelCreator.cs" />
+    <Compile Include="GaussianProcess\GaussianProcessModelCreator.cs">
+      <SubType>Code</SubType>
+    </Compile>
+    <Compile Include="GaussianProcess\GaussianProcessCovarianceOptimizationProblem.cs" />
+    <Compile Include="GaussianProcess\Util.cs" />
+    <Compile Include="GaussianProcess\IMeanFunction.cs" />
+    <Compile Include="GaussianProcess\GaussianProcessModel.cs" />
+    <Compile Include="GaussianProcess\GaussianProcessRegression.cs" />
+    <Compile Include="GaussianProcess\GaussianProcessRegressionSolution.cs" />
+    <Compile Include="GaussianProcess\ICovarianceFunction.cs" />
+    <Compile Include="GBM\GradientBoostingRegressionAlgorithm.cs" />
+    <Compile Include="GradientBoostedTrees\IGradientBoostedTreesModel.cs" />
+    <Compile Include="GradientBoostedTrees\GradientBoostedTreesModelSurrogate.cs" />
+    <Compile Include="GradientBoostedTrees\GradientBoostedTreesAlgorithm.cs" />
+    <Compile Include="GradientBoostedTrees\GradientBoostedTreesAlgorithmStatic.cs" />
+    <Compile Include="GradientBoostedTrees\GradientBoostedTreesModel.cs" />
+    <Compile Include="GradientBoostedTrees\LossFunctions\AbsoluteErrorLoss.cs" />
+    <Compile Include="GradientBoostedTrees\LossFunctions\QuantileRegressionLoss.cs" />
+    <Compile Include="GradientBoostedTrees\LossFunctions\ILossFunction.cs" />
+    <Compile Include="GradientBoostedTrees\LossFunctions\LogisticRegressionLoss.cs" />
+    <Compile Include="GradientBoostedTrees\LossFunctions\RelativeErrorLoss.cs" />
+    <Compile Include="GradientBoostedTrees\LossFunctions\SquaredErrorLoss.cs" />
+    <Compile Include="GradientBoostedTrees\GradientBoostedTreesSolution.cs" />
+    <Compile Include="GradientBoostedTrees\RegressionTreeBuilder.cs" />
+    <Compile Include="GradientBoostedTrees\RegressionTreeModel.cs" />
+    <Compile Include="Interfaces\IGaussianProcessClassificationModelCreator.cs" />
+    <Compile Include="Interfaces\IGaussianProcessRegressionModelCreator.cs" />
+    <Compile Include="Interfaces\IGaussianProcessModelCreator.cs" />
+    <Compile Include="Interfaces\IGaussianProcessModel.cs" />
+    <Compile Include="Interfaces\IGaussianProcessSolution.cs" />
+    <Compile Include="Interfaces\INcaClassificationSolution.cs" />
+    <Compile Include="Interfaces\INcaModel.cs" />
+    <Compile Include="Interfaces\INearestNeighbourClassificationSolution.cs" />
+    <Compile Include="Interfaces\INearestNeighbourRegressionSolution.cs" />
+    <Compile Include="Interfaces\INearestNeighbourModel.cs" />
+    <Compile Include="Interfaces\INeuralNetworkEnsembleClassificationSolution.cs" />
+    <Compile Include="Interfaces\INeuralNetworkEnsembleRegressionSolution.cs" />
+    <Compile Include="Interfaces\INeuralNetworkEnsembleModel.cs" />
+    <Compile Include="Interfaces\INeuralNetworkClassificationSolution.cs" />
+    <Compile Include="Interfaces\INeuralNetworkRegressionSolution.cs" />
+    <Compile Include="Interfaces\INeuralNetworkModel.cs" />
+    <Compile Include="Interfaces\IRandomForestClassificationSolution.cs" />
+    <Compile Include="Interfaces\IRandomForestModel.cs" />
+    <Compile Include="Interfaces\IRandomForestRegressionSolution.cs" />
+    <Compile Include="Interfaces\ISupportVectorMachineModel.cs" />
+    <Compile Include="Interfaces\ISupportVectorMachineSolution.cs" />
+    <Compile Include="Interfaces\IDataAnalysisAlgorithm.cs" />
+    <Compile Include="kMeans\KMeansClustering.cs" />
+    <Compile Include="kMeans\KMeansClusteringModel.cs" />
+    <Compile Include="kMeans\KMeansClusteringSolution.cs" />
+    <Compile Include="kMeans\KMeansClusteringUtil.cs">
+      <SubType>Code</SubType>
+    </Compile>
+    <Compile Include="Linear\AlglibUtil.cs" />
+    <Compile Include="Linear\Scaling.cs" />
+    <Compile Include="Linear\LinearDiscriminantAnalysis.cs" />
+    <Compile Include="Linear\LinearRegression.cs">
+      <SubType>Code</SubType>
+    </Compile>
+    <Compile Include="Linear\MultinomialLogitClassification.cs" />
+    <Compile Include="Linear\MultinomialLogitClassificationSolution.cs" />
+    <Compile Include="Linear\MultinomialLogitModel.cs" />
+    <Compile Include="MctsSymbolicRegression\Automaton.cs" />
+    <Compile Include="MctsSymbolicRegression\CodeGenerator.cs" />
+    <Compile Include="MctsSymbolicRegression\ConstraintHandler.cs" />
+    <Compile Include="MctsSymbolicRegression\Disassembler.cs" />
+    <Compile Include="MctsSymbolicRegression\ExpressionEvaluator.cs" />
+    <Compile Include="MctsSymbolicRegression\MctsSymbolicRegressionAlgorithm.cs" />
+    <Compile Include="MctsSymbolicRegression\MctsSymbolicRegressionStatic.cs" />
+    <Compile Include="MctsSymbolicRegression\OpCodes.cs" />
+    <Compile Include="MctsSymbolicRegression\Policies\EpsGreedy.cs" />
+    <Compile Include="MctsSymbolicRegression\Policies\UcbTuned.cs" />
+    <Compile Include="MctsSymbolicRegression\Policies\IActionStatistics.cs" />
+    <Compile Include="MctsSymbolicRegression\Policies\IPolicy.cs" />
+    <Compile Include="MctsSymbolicRegression\Policies\PolicyBase.cs" />
+    <Compile Include="MctsSymbolicRegression\Policies\Ucb.cs" />
+    <Compile Include="MctsSymbolicRegression\SymbolicExpressionGenerator.cs" />
+    <Compile Include="MctsSymbolicRegression\Tree.cs" />
+    <Compile Include="Nca\Initialization\INcaInitializer.cs" />
+    <Compile Include="Nca\Initialization\LdaInitializer.cs" />
+    <Compile Include="Nca\Initialization\NcaInitializer.cs" />
+    <Compile Include="Nca\Initialization\PcaInitializer.cs" />
+    <Compile Include="Nca\Initialization\RandomInitializer.cs" />
+    <Compile Include="Nca\Matrix.cs" />
+    <Compile Include="Nca\ModelCreation\INcaModelCreator.cs" />
+    <Compile Include="Nca\ModelCreation\NcaModelCreator.cs" />
+    <Compile Include="Nca\NcaAlgorithm.cs" />
+    <Compile Include="Nca\NcaClassificationSolution.cs" />
+    <Compile Include="Nca\NcaGradientCalculator.cs" />
+    <Compile Include="Nca\NcaModel.cs" />
+    <Compile Include="Nca\SolutionCreation\INcaSolutionCreator.cs" />
+    <Compile Include="Nca\SolutionCreation\NcaSolutionCreator.cs" />
+    <Compile Include="NearestNeighbour\NearestNeighbourClassification.cs" />
+    <Compile Include="NearestNeighbour\NearestNeighbourClassificationSolution.cs" />
+    <Compile Include="NearestNeighbour\NearestNeighbourModel.cs" />
+    <Compile Include="NearestNeighbour\NearestNeighbourRegression.cs" />
+    <Compile Include="NearestNeighbour\NearestNeighbourRegressionSolution.cs" />
+    <Compile Include="NeuralNetwork\NeuralNetworkEnsembleClassification.cs" />
+    <Compile Include="NeuralNetwork\NeuralNetworkEnsembleClassificationSolution.cs" />
+    <Compile Include="NeuralNetwork\NeuralNetworkEnsembleModel.cs" />
+    <Compile Include="NeuralNetwork\NeuralNetworkEnsembleRegressionSolution.cs" />
+    <Compile Include="NeuralNetwork\NeuralNetworkEnsembleRegression.cs" />
+    <Compile Include="NeuralNetwork\NeuralNetworkClassification.cs" />
+    <Compile Include="NeuralNetwork\NeuralNetworkClassificationSolution.cs" />
+    <Compile Include="NeuralNetwork\NeuralNetworkModel.cs" />
+    <Compile Include="NeuralNetwork\NeuralNetworkRegression.cs" />
+    <Compile Include="NeuralNetwork\NeuralNetworkRegressionSolution.cs" />
+    <Compile Include="Plugin.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="RandomForest\RandomForestClassificationSolution.cs" />
+    <Compile Include="RandomForest\RandomForestClassification.cs" />
+    <Compile Include="RandomForest\RandomForestModel.cs" />
+    <Compile Include="RandomForest\RandomForestRegression.cs" />
+    <Compile Include="RandomForest\RandomForestRegressionSolution.cs" />
+    <Compile Include="RandomForest\RandomForestUtil.cs" />
+    <Compile Include="SupportVectorMachine\SupportVectorClassification.cs" />
+    <Compile Include="SupportVectorMachine\SupportVectorClassificationSolution.cs" />
+    <Compile Include="SupportVectorMachine\SupportVectorMachineModel.cs" />
+    <Compile Include="SupportVectorMachine\SupportVectorMachineUtil.cs">
+      <SubType>Code</SubType>
+    </Compile>
+    <Compile Include="SupportVectorMachine\SupportVectorRegression.cs">
+      <SubType>Code</SubType>
+    </Compile>
+    <Compile Include="SupportVectorMachine\SupportVectorRegressionSolution.cs">
+      <SubType>Code</SubType>
+    </Compile>
+    <Compile Include="TimeSeries\AutoregressiveModeling.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="HeuristicLab.snk" />
+    <None Include="Plugin.cs.frame" />
+    <None Include="Properties\AssemblyInfo.cs.frame" />
+  </ItemGroup>
+  <ItemGroup>
+    <BootstrapperPackage Include="Microsoft.Net.Client.3.5">
+      <Visible>False</Visible>
+      <ProductName>.NET Framework 3.5 SP1 Client Profile</ProductName>
+      <Install>false</Install>
+    </BootstrapperPackage>
+    <BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
+      <Visible>False</Visible>
+      <ProductName>.NET Framework 3.5 SP1</ProductName>
+      <Install>true</Install>
+    </BootstrapperPackage>
+    <BootstrapperPackage Include="Microsoft.Windows.Installer.3.1">
+      <Visible>False</Visible>
+      <ProductName>Windows Installer 3.1</ProductName>
+      <Install>true</Install>
+    </BootstrapperPackage>
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\..\HeuristicLab.Problems.DataAnalysis\3.4\HeuristicLab.Problems.DataAnalysis-3.4.csproj">
+      <Project>{df87c13e-a889-46ff-8153-66dcaa8c5674}</Project>
+      <Name>HeuristicLab.Problems.DataAnalysis-3.4</Name>
+    </ProjectReference>
+  </ItemGroup>
+  <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+  <PropertyGroup>
+    <PreBuildEvent Condition=" '$(OS)' == 'Windows_NT' ">set Path=%25Path%25;$(ProjectDir);$(SolutionDir)
+set ProjectDir=$(ProjectDir)
+set SolutionDir=$(SolutionDir)
+set Outdir=$(Outdir)
+
+call PreBuildEvent.cmd
+</PreBuildEvent>
+    <PreBuildEvent Condition=" '$(OS)' != 'Windows_NT' ">
+export ProjectDir=$(ProjectDir)
+export SolutionDir=$(SolutionDir)
+
+$SolutionDir/PreBuildEvent.sh
+</PreBuildEvent>
+  </PropertyGroup>
+</Project>
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/IDataAnalysisAlgorithm.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/IDataAnalysisAlgorithm.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/IDataAnalysisAlgorithm.cs	(revision 13819)
@@ -0,0 +1,32 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using HeuristicLab.Optimization;
+using HeuristicLab.Problems.DataAnalysis;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  /// <summary>
+  /// Interface to represent a data analysis algorithm.
+  /// </summary>
+  public interface IDataAnalysisAlgorithm<T> : IAlgorithm where T : class, IDataAnalysisProblem {
+    new T Problem { get; set; }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/IGaussianProcessClassificationModelCreator.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/IGaussianProcessClassificationModelCreator.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/IGaussianProcessClassificationModelCreator.cs	(revision 13819)
@@ -0,0 +1,32 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using HeuristicLab.Core;
+using HeuristicLab.Problems.DataAnalysis;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  /// <summary>
+  /// Interface to represent a Gaussian process model creator for classification
+  /// </summary>
+  public interface IGaussianProcessClassificationModelCreator : IGaussianProcessModelCreator {
+    ILookupParameter<IClassificationProblemData> ProblemDataParameter { get; }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/IGaussianProcessModel.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/IGaussianProcessModel.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/IGaussianProcessModel.cs	(revision 13819)
@@ -0,0 +1,39 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Collections.Generic;
+using HeuristicLab.Problems.DataAnalysis;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  /// <summary>
+  /// Interface to represent a Gaussian process posterior
+  /// </summary>
+  public interface IGaussianProcessModel : IRegressionModel {
+    double NegativeLogLikelihood { get; }
+    double SigmaNoise { get; }
+    IMeanFunction MeanFunction { get; }
+    ICovarianceFunction CovarianceFunction { get; }
+    double[] HyperparameterGradients { get; }
+
+    IEnumerable<double> GetEstimatedVariance(IDataset ds, IEnumerable<int> rows);
+    void FixParameters();
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/IGaussianProcessModelCreator.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/IGaussianProcessModelCreator.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/IGaussianProcessModelCreator.cs	(revision 13819)
@@ -0,0 +1,39 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Encodings.RealVectorEncoding;
+using HeuristicLab.Problems.DataAnalysis;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  /// <summary>
+  /// Interface to represent a Gaussian process model creator (either regression or classification)
+  /// </summary>
+  public interface IGaussianProcessModelCreator : IOperator {
+    ILookupParameter<RealVector> HyperparameterParameter { get; }
+    ILookupParameter<IMeanFunction> MeanFunctionParameter { get; }
+    ILookupParameter<ICovarianceFunction> CovarianceFunctionParameter { get; }
+    ILookupParameter<IGaussianProcessModel> ModelParameter { get; }
+    ILookupParameter<RealVector> HyperparameterGradientsParameter { get; }
+    ILookupParameter<DoubleValue> NegativeLogLikelihoodParameter { get; }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/IGaussianProcessRegressionModelCreator.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/IGaussianProcessRegressionModelCreator.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/IGaussianProcessRegressionModelCreator.cs	(revision 13819)
@@ -0,0 +1,32 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using HeuristicLab.Core;
+using HeuristicLab.Problems.DataAnalysis;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  /// <summary>
+  /// Interface to represent a Gaussian process model creator for regression
+  /// </summary>
+  public interface IGaussianProcessRegressionModelCreator : IGaussianProcessModelCreator {
+    ILookupParameter<IRegressionProblemData> ProblemDataParameter { get; }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/IGaussianProcessSolution.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/IGaussianProcessSolution.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/IGaussianProcessSolution.cs	(revision 13819)
@@ -0,0 +1,31 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using HeuristicLab.Problems.DataAnalysis;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  /// <summary>
+  /// Interface to represent a Gaussian process solution (either regression or classification)
+  /// </summary>
+  public interface IGaussianProcessSolution : IDataAnalysisSolution {
+    new IGaussianProcessModel Model { get; }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/INcaClassificationSolution.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/INcaClassificationSolution.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/INcaClassificationSolution.cs	(revision 13819)
@@ -0,0 +1,28 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using HeuristicLab.Problems.DataAnalysis;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  public interface INcaClassificationSolution : IClassificationSolution {
+    new INcaModel Model { get; }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/INcaModel.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/INcaModel.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/INcaModel.cs	(revision 13819)
@@ -0,0 +1,31 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Collections.Generic;
+using HeuristicLab.Problems.DataAnalysis;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  public interface INcaModel : IClassificationModel {
+    new INcaClassificationSolution CreateClassificationSolution(IClassificationProblemData problemData);
+
+    double[,] Reduce(IDataset dataset, IEnumerable<int> rows);
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/INearestNeighbourClassificationSolution.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/INearestNeighbourClassificationSolution.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/INearestNeighbourClassificationSolution.cs	(revision 13819)
@@ -0,0 +1,33 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using HeuristicLab.Optimization;
+using HeuristicLab.Problems.DataAnalysis;
+using HeuristicLab.Core;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  /// <summary>
+  /// Interface to represent a nearest neighbour classification solution
+  /// </summary>
+  public interface INearestNeighbourClassificationSolution : IClassificationSolution {
+    new INearestNeighbourModel Model { get; }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/INearestNeighbourModel.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/INearestNeighbourModel.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/INearestNeighbourModel.cs	(revision 13819)
@@ -0,0 +1,33 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using HeuristicLab.Optimization;
+using HeuristicLab.Problems.DataAnalysis;
+using HeuristicLab.Core;
+using System.Collections.Generic;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  /// <summary>
+  /// Interface to represent a nearest neighbour model for either regression or classification
+  /// </summary>
+  public interface INearestNeighbourModel : IRegressionModel, IClassificationModel {
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/INearestNeighbourRegressionSolution.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/INearestNeighbourRegressionSolution.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/INearestNeighbourRegressionSolution.cs	(revision 13819)
@@ -0,0 +1,33 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using HeuristicLab.Optimization;
+using HeuristicLab.Problems.DataAnalysis;
+using HeuristicLab.Core;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  /// <summary>
+  /// Interface to represent a nearest neighbour regression solution
+  /// </summary>
+  public interface INearestNeighbourRegressionSolution : IRegressionSolution {
+    new INearestNeighbourModel Model { get; }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/INeuralNetworkClassificationSolution.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/INeuralNetworkClassificationSolution.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/INeuralNetworkClassificationSolution.cs	(revision 13819)
@@ -0,0 +1,33 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using HeuristicLab.Optimization;
+using HeuristicLab.Problems.DataAnalysis;
+using HeuristicLab.Core;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  /// <summary>
+  /// Interface to represent a neural network classification solution
+  /// </summary>
+  public interface INeuralNetworkClassificationSolution : IClassificationSolution {
+    new INeuralNetworkModel Model { get; }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/INeuralNetworkEnsembleClassificationSolution.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/INeuralNetworkEnsembleClassificationSolution.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/INeuralNetworkEnsembleClassificationSolution.cs	(revision 13819)
@@ -0,0 +1,33 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using HeuristicLab.Optimization;
+using HeuristicLab.Problems.DataAnalysis;
+using HeuristicLab.Core;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  /// <summary>
+  /// Interface to represent a neural network ensemble classification solution
+  /// </summary>
+  public interface INeuralNetworkEnsembleClassificationSolution : IClassificationSolution {
+    new INeuralNetworkEnsembleModel Model { get; }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/INeuralNetworkEnsembleModel.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/INeuralNetworkEnsembleModel.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/INeuralNetworkEnsembleModel.cs	(revision 13819)
@@ -0,0 +1,33 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using HeuristicLab.Optimization;
+using HeuristicLab.Problems.DataAnalysis;
+using HeuristicLab.Core;
+using System.Collections.Generic;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  /// <summary>
+  /// Interface to represent a neural network ensemble model for either regression or classification
+  /// </summary>
+  public interface INeuralNetworkEnsembleModel : IRegressionModel, IClassificationModel {
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/INeuralNetworkEnsembleRegressionSolution.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/INeuralNetworkEnsembleRegressionSolution.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/INeuralNetworkEnsembleRegressionSolution.cs	(revision 13819)
@@ -0,0 +1,33 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using HeuristicLab.Optimization;
+using HeuristicLab.Problems.DataAnalysis;
+using HeuristicLab.Core;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  /// <summary>
+  /// Interface to represent a neural network ensemble regression solution
+  /// </summary>
+  public interface INeuralNetworkEnsembleRegressionSolution : IRegressionSolution {
+    new INeuralNetworkEnsembleModel Model { get; }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/INeuralNetworkModel.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/INeuralNetworkModel.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/INeuralNetworkModel.cs	(revision 13819)
@@ -0,0 +1,33 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using HeuristicLab.Optimization;
+using HeuristicLab.Problems.DataAnalysis;
+using HeuristicLab.Core;
+using System.Collections.Generic;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  /// <summary>
+  /// Interface to represent a neural network model for either regression or classification
+  /// </summary>
+  public interface INeuralNetworkModel : IRegressionModel, IClassificationModel {
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/INeuralNetworkRegressionSolution.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/INeuralNetworkRegressionSolution.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/INeuralNetworkRegressionSolution.cs	(revision 13819)
@@ -0,0 +1,33 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using HeuristicLab.Optimization;
+using HeuristicLab.Problems.DataAnalysis;
+using HeuristicLab.Core;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  /// <summary>
+  /// Interface to represent a neural network regression solution
+  /// </summary>
+  public interface INeuralNetworkRegressionSolution : IRegressionSolution {
+    new INeuralNetworkModel Model { get; }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/IRandomForestClassificationSolution.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/IRandomForestClassificationSolution.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/IRandomForestClassificationSolution.cs	(revision 13819)
@@ -0,0 +1,33 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using HeuristicLab.Optimization;
+using HeuristicLab.Problems.DataAnalysis;
+using HeuristicLab.Core;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  /// <summary>
+  /// Interface to represent a random forest classification solution
+  /// </summary>
+  public interface IRandomForestClassificationSolution : IClassificationSolution {
+    new IRandomForestModel Model { get; }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/IRandomForestModel.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/IRandomForestModel.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/IRandomForestModel.cs	(revision 13819)
@@ -0,0 +1,33 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using HeuristicLab.Optimization;
+using HeuristicLab.Problems.DataAnalysis;
+using HeuristicLab.Core;
+using System.Collections.Generic;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  /// <summary>
+  /// Interface to represent a random forest model for either regression or classification
+  /// </summary>
+  public interface IRandomForestModel : IRegressionModel, IClassificationModel {
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/IRandomForestRegressionSolution.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/IRandomForestRegressionSolution.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/IRandomForestRegressionSolution.cs	(revision 13819)
@@ -0,0 +1,33 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using HeuristicLab.Optimization;
+using HeuristicLab.Problems.DataAnalysis;
+using HeuristicLab.Core;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  /// <summary>
+  /// Interface to represent a random forest regression solution
+  /// </summary>
+  public interface IRandomForestRegressionSolution : IRegressionSolution {
+    new IRandomForestModel Model { get; }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/ISupportVectorMachineModel.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/ISupportVectorMachineModel.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/ISupportVectorMachineModel.cs	(revision 13819)
@@ -0,0 +1,34 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using HeuristicLab.Problems.DataAnalysis;
+using LibSVM;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  /// <summary>
+  /// Interface to represent a support vector machine model
+  /// </summary>
+  public interface ISupportVectorMachineModel : IDataAnalysisModel, IRegressionModel, IClassificationModel {
+    svm_model Model { get; }
+    RangeTransform RangeTransform { get; }
+    Dataset SupportVectors { get; }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/ISupportVectorMachineSolution.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/ISupportVectorMachineSolution.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/ISupportVectorMachineSolution.cs	(revision 13819)
@@ -0,0 +1,33 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using HeuristicLab.Optimization;
+using HeuristicLab.Problems.DataAnalysis;
+using HeuristicLab.Core;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  /// <summary>
+  /// Interface to represent a support vector solution (either regression or classification)
+  /// </summary>
+  public interface ISupportVectorMachineSolution : IDataAnalysisSolution {
+    new ISupportVectorMachineModel Model { get; }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Linear/AlglibUtil.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Linear/AlglibUtil.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Linear/AlglibUtil.cs	(revision 13819)
@@ -0,0 +1,67 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Problems.DataAnalysis;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  public static class AlglibUtil {
+    public static double[,] PrepareInputMatrix(IDataset dataset, IEnumerable<string> variables, IEnumerable<int> rows) {
+      List<string> variablesList = variables.ToList();
+      List<int> rowsList = rows.ToList();
+
+      double[,] matrix = new double[rowsList.Count, variablesList.Count];
+
+      int col = 0;
+      foreach (string column in variables) {
+        var values = dataset.GetDoubleValues(column, rows);
+        int row = 0;
+        foreach (var value in values) {
+          matrix[row, col] = value;
+          row++;
+        }
+        col++;
+      }
+
+      return matrix;
+    }
+    public static double[,] PrepareAndScaleInputMatrix(IDataset dataset, IEnumerable<string> variables, IEnumerable<int> rows, Scaling scaling) {
+      List<string> variablesList = variables.ToList();
+      List<int> rowsList = rows.ToList();
+
+      double[,] matrix = new double[rowsList.Count, variablesList.Count];
+
+      int col = 0;
+      foreach (string column in variables) {
+        var values = scaling.GetScaledValues(dataset, column, rows);
+        int row = 0;
+        foreach (var value in values) {
+          matrix[row, col] = value;
+          row++;
+        }
+        col++;
+      }
+
+      return matrix;
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Linear/LinearDiscriminantAnalysis.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Linear/LinearDiscriminantAnalysis.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Linear/LinearDiscriminantAnalysis.cs	(revision 13819)
@@ -0,0 +1,118 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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.Encodings.SymbolicExpressionTreeEncoding;
+using HeuristicLab.Optimization;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Problems.DataAnalysis;
+using HeuristicLab.Problems.DataAnalysis.Symbolic;
+using HeuristicLab.Problems.DataAnalysis.Symbolic.Classification;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  /// <summary>
+  /// Linear discriminant analysis classification algorithm.
+  /// </summary>
+  [Item("Linear Discriminant Analysis", "Linear discriminant analysis classification algorithm (wrapper for ALGLIB).")]
+  [Creatable(CreatableAttribute.Categories.DataAnalysisClassification, Priority = 100)]
+  [StorableClass]
+  public sealed class LinearDiscriminantAnalysis : FixedDataAnalysisAlgorithm<IClassificationProblem> {
+    private const string LinearDiscriminantAnalysisSolutionResultName = "Linear discriminant analysis solution";
+
+    [StorableConstructor]
+    private LinearDiscriminantAnalysis(bool deserializing) : base(deserializing) { }
+    private LinearDiscriminantAnalysis(LinearDiscriminantAnalysis original, Cloner cloner)
+      : base(original, cloner) {
+    }
+    public LinearDiscriminantAnalysis()
+      : base() {
+      Problem = new ClassificationProblem();
+    }
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() { }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new LinearDiscriminantAnalysis(this, cloner);
+    }
+
+    #region Fisher LDA
+    protected override void Run() {
+      var solution = CreateLinearDiscriminantAnalysisSolution(Problem.ProblemData);
+      Results.Add(new Result(LinearDiscriminantAnalysisSolutionResultName, "The linear discriminant analysis.", solution));
+    }
+
+    public static IClassificationSolution CreateLinearDiscriminantAnalysisSolution(IClassificationProblemData problemData) {
+      var dataset = problemData.Dataset;
+      string targetVariable = problemData.TargetVariable;
+      IEnumerable<string> allowedInputVariables = problemData.AllowedInputVariables;
+      IEnumerable<int> rows = problemData.TrainingIndices;
+      int nClasses = problemData.ClassNames.Count();
+      double[,] inputMatrix = AlglibUtil.PrepareInputMatrix(dataset, allowedInputVariables.Concat(new string[] { targetVariable }), rows);
+      if (inputMatrix.Cast<double>().Any(x => double.IsNaN(x) || double.IsInfinity(x)))
+        throw new NotSupportedException("Linear discriminant analysis does not support NaN or infinity values in the input dataset.");
+
+      // change class values into class index
+      int targetVariableColumn = inputMatrix.GetLength(1) - 1;
+      List<double> classValues = problemData.ClassValues.OrderBy(x => x).ToList();
+      for (int row = 0; row < inputMatrix.GetLength(0); row++) {
+        inputMatrix[row, targetVariableColumn] = classValues.IndexOf(inputMatrix[row, targetVariableColumn]);
+      }
+      int info;
+      double[] w;
+      alglib.fisherlda(inputMatrix, inputMatrix.GetLength(0), allowedInputVariables.Count(), nClasses, out info, out w);
+      if (info < 1) throw new ArgumentException("Error in calculation of linear discriminant analysis solution");
+
+      ISymbolicExpressionTree tree = new SymbolicExpressionTree(new ProgramRootSymbol().CreateTreeNode());
+      ISymbolicExpressionTreeNode startNode = new StartSymbol().CreateTreeNode();
+      tree.Root.AddSubtree(startNode);
+      ISymbolicExpressionTreeNode addition = new Addition().CreateTreeNode();
+      startNode.AddSubtree(addition);
+
+      int col = 0;
+      foreach (string column in allowedInputVariables) {
+        VariableTreeNode vNode = (VariableTreeNode)new HeuristicLab.Problems.DataAnalysis.Symbolic.Variable().CreateTreeNode();
+        vNode.VariableName = column;
+        vNode.Weight = w[col];
+        addition.AddSubtree(vNode);
+        col++;
+      }
+
+      var model = LinearDiscriminantAnalysis.CreateDiscriminantFunctionModel(tree, new SymbolicDataAnalysisExpressionTreeInterpreter(), problemData, rows);
+      SymbolicDiscriminantFunctionClassificationSolution solution = new SymbolicDiscriminantFunctionClassificationSolution(model, (IClassificationProblemData)problemData.Clone());
+
+      return solution;
+    }
+    #endregion
+
+    private static SymbolicDiscriminantFunctionClassificationModel CreateDiscriminantFunctionModel(ISymbolicExpressionTree tree,
+      ISymbolicDataAnalysisExpressionTreeInterpreter interpreter,
+      IClassificationProblemData problemData,
+      IEnumerable<int> rows) {
+      var model = new SymbolicDiscriminantFunctionClassificationModel(tree, interpreter, new AccuracyMaximizationThresholdCalculator());
+      model.RecalculateModelParameters(problemData, rows);
+      return model;
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Linear/LinearRegression.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Linear/LinearRegression.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Linear/LinearRegression.cs	(revision 13819)
@@ -0,0 +1,119 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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.Optimization;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Problems.DataAnalysis;
+using HeuristicLab.Problems.DataAnalysis.Symbolic;
+using HeuristicLab.Problems.DataAnalysis.Symbolic.Regression;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  /// <summary>
+  /// Linear regression data analysis algorithm.
+  /// </summary>
+  [Item("Linear Regression (LR)", "Linear regression data analysis algorithm (wrapper for ALGLIB).")]
+  [Creatable(CreatableAttribute.Categories.DataAnalysisRegression, Priority = 100)]
+  [StorableClass]
+  public sealed class LinearRegression : FixedDataAnalysisAlgorithm<IRegressionProblem> {
+    private const string LinearRegressionModelResultName = "Linear regression solution";
+
+    [StorableConstructor]
+    private LinearRegression(bool deserializing) : base(deserializing) { }
+    private LinearRegression(LinearRegression original, Cloner cloner)
+      : base(original, cloner) {
+    }
+    public LinearRegression()
+      : base() {
+      Problem = new RegressionProblem();
+    }
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() { }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new LinearRegression(this, cloner);
+    }
+
+    #region linear regression
+    protected override void Run() {
+      double rmsError, cvRmsError;
+      var solution = CreateLinearRegressionSolution(Problem.ProblemData, out rmsError, out cvRmsError);
+      Results.Add(new Result(LinearRegressionModelResultName, "The linear regression solution.", solution));
+      Results.Add(new Result("Root mean square error", "The root of the mean of squared errors of the linear regression solution on the training set.", new DoubleValue(rmsError)));
+      Results.Add(new Result("Estimated root mean square error (cross-validation)", "The estimated root of the mean of squared errors of the linear regression solution via cross validation.", new DoubleValue(cvRmsError)));
+    }
+
+    public static ISymbolicRegressionSolution CreateLinearRegressionSolution(IRegressionProblemData problemData, out double rmsError, out double cvRmsError) {
+      var dataset = problemData.Dataset;
+      string targetVariable = problemData.TargetVariable;
+      IEnumerable<string> allowedInputVariables = problemData.AllowedInputVariables;
+      IEnumerable<int> rows = problemData.TrainingIndices;
+      double[,] inputMatrix = AlglibUtil.PrepareInputMatrix(dataset, allowedInputVariables.Concat(new string[] { targetVariable }), rows);
+      if (inputMatrix.Cast<double>().Any(x => double.IsNaN(x) || double.IsInfinity(x)))
+        throw new NotSupportedException("Linear regression does not support NaN or infinity values in the input dataset.");
+
+      alglib.linearmodel lm = new alglib.linearmodel();
+      alglib.lrreport ar = new alglib.lrreport();
+      int nRows = inputMatrix.GetLength(0);
+      int nFeatures = inputMatrix.GetLength(1) - 1;
+      double[] coefficients = new double[nFeatures + 1]; // last coefficient is for the constant
+
+      int retVal = 1;
+      alglib.lrbuild(inputMatrix, nRows, nFeatures, out retVal, out lm, out ar);
+      if (retVal != 1) throw new ArgumentException("Error in calculation of linear regression solution");
+      rmsError = ar.rmserror;
+      cvRmsError = ar.cvrmserror;
+
+      alglib.lrunpack(lm, out coefficients, out nFeatures);
+
+      ISymbolicExpressionTree tree = new SymbolicExpressionTree(new ProgramRootSymbol().CreateTreeNode());
+      ISymbolicExpressionTreeNode startNode = new StartSymbol().CreateTreeNode();
+      tree.Root.AddSubtree(startNode);
+      ISymbolicExpressionTreeNode addition = new Addition().CreateTreeNode();
+      startNode.AddSubtree(addition);
+
+      int col = 0;
+      foreach (string column in allowedInputVariables) {
+        VariableTreeNode vNode = (VariableTreeNode)new HeuristicLab.Problems.DataAnalysis.Symbolic.Variable().CreateTreeNode();
+        vNode.VariableName = column;
+        vNode.Weight = coefficients[col];
+        addition.AddSubtree(vNode);
+        col++;
+      }
+
+      ConstantTreeNode cNode = (ConstantTreeNode)new Constant().CreateTreeNode();
+      cNode.Value = coefficients[coefficients.Length - 1];
+      addition.AddSubtree(cNode);
+
+      SymbolicRegressionSolution solution = new SymbolicRegressionSolution(new SymbolicRegressionModel(tree, new SymbolicDataAnalysisExpressionTreeInterpreter()), (IRegressionProblemData)problemData.Clone());
+      solution.Model.Name = "Linear Regression Model";
+      solution.Name = "Linear Regression Solution";
+      return solution;
+    }
+    #endregion
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Linear/MultinomialLogitClassification.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Linear/MultinomialLogitClassification.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Linear/MultinomialLogitClassification.cs	(revision 13819)
@@ -0,0 +1,102 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Optimization;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Problems.DataAnalysis;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  /// <summary>
+  /// Multinomial logit regression data analysis algorithm.
+  /// </summary>
+  [Item("Multinomial Logit Classification (MNL)", "Multinomial logit classification data analysis algorithm (wrapper for ALGLIB).")]
+  [Creatable(CreatableAttribute.Categories.DataAnalysisClassification, Priority = 180)]
+  [StorableClass]
+  public sealed class MultiNomialLogitClassification : FixedDataAnalysisAlgorithm<IClassificationProblem> {
+    private const string LogitClassificationModelResultName = "Logit classification solution";
+
+    [StorableConstructor]
+    private MultiNomialLogitClassification(bool deserializing) : base(deserializing) { }
+    private MultiNomialLogitClassification(MultiNomialLogitClassification original, Cloner cloner)
+      : base(original, cloner) {
+    }
+    public MultiNomialLogitClassification()
+      : base() {
+      Problem = new ClassificationProblem();
+    }
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() { }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new MultiNomialLogitClassification(this, cloner);
+    }
+
+    #region logit classification
+    protected override void Run() {
+      double rmsError, relClassError;
+      var solution = CreateLogitClassificationSolution(Problem.ProblemData, out rmsError, out relClassError);
+      Results.Add(new Result(LogitClassificationModelResultName, "The logit classification solution.", solution));
+      Results.Add(new Result("Root mean squared error", "The root of the mean of squared errors of the logit regression solution on the training set.", new DoubleValue(rmsError)));
+      Results.Add(new Result("Relative classification error", "Relative classification error on the training set (percentage of misclassified cases).", new PercentValue(relClassError)));
+    }
+
+    public static IClassificationSolution CreateLogitClassificationSolution(IClassificationProblemData problemData, out double rmsError, out double relClassError) {
+      var dataset = problemData.Dataset;
+      string targetVariable = problemData.TargetVariable;
+      IEnumerable<string> allowedInputVariables = problemData.AllowedInputVariables;
+      IEnumerable<int> rows = problemData.TrainingIndices;
+      double[,] inputMatrix = AlglibUtil.PrepareInputMatrix(dataset, allowedInputVariables.Concat(new string[] { targetVariable }), rows);
+      if (inputMatrix.Cast<double>().Any(x => double.IsNaN(x) || double.IsInfinity(x)))
+        throw new NotSupportedException("Multinomial logit classification does not support NaN or infinity values in the input dataset.");
+
+      alglib.logitmodel lm = new alglib.logitmodel();
+      alglib.mnlreport rep = new alglib.mnlreport();
+      int nRows = inputMatrix.GetLength(0);
+      int nFeatures = inputMatrix.GetLength(1) - 1;
+      double[] classValues = dataset.GetDoubleValues(targetVariable).Distinct().OrderBy(x => x).ToArray();
+      int nClasses = classValues.Count();
+      // map original class values to values [0..nClasses-1]
+      Dictionary<double, double> classIndices = new Dictionary<double, double>();
+      for (int i = 0; i < nClasses; i++) {
+        classIndices[classValues[i]] = i;
+      }
+      for (int row = 0; row < nRows; row++) {
+        inputMatrix[row, nFeatures] = classIndices[inputMatrix[row, nFeatures]];
+      }
+      int info;
+      alglib.mnltrainh(inputMatrix, nRows, nFeatures, nClasses, out info, out lm, out rep);
+      if (info != 1) throw new ArgumentException("Error in calculation of logit classification solution");
+
+      rmsError = alglib.mnlrmserror(lm, inputMatrix, nRows);
+      relClassError = alglib.mnlrelclserror(lm, inputMatrix, nRows);
+
+      MultinomialLogitClassificationSolution solution = new MultinomialLogitClassificationSolution((IClassificationProblemData)problemData.Clone(), new MultinomialLogitModel(lm, targetVariable, allowedInputVariables, classValues));
+      return solution;
+    }
+    #endregion
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Linear/MultinomialLogitClassificationSolution.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Linear/MultinomialLogitClassificationSolution.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Linear/MultinomialLogitClassificationSolution.cs	(revision 13819)
@@ -0,0 +1,53 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Problems.DataAnalysis;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  /// <summary>
+  /// Represents a multinomial logit solution for a classification problem which can be visualized in the GUI.
+  /// </summary>
+  [Item("Multinomial Logit Classification Solution", "Represents a multinomial logit solution for a classification problem which can be visualized in the GUI.")]
+  [StorableClass]
+  public sealed class MultinomialLogitClassificationSolution : ClassificationSolution {
+
+    public new MultinomialLogitModel Model {
+      get { return (MultinomialLogitModel)base.Model; }
+      set { base.Model = value; }
+    }
+
+    [StorableConstructor]
+    private MultinomialLogitClassificationSolution(bool deserializing) : base(deserializing) { }
+    private MultinomialLogitClassificationSolution(MultinomialLogitClassificationSolution original, Cloner cloner)
+      : base(original, cloner) {
+    }
+    public MultinomialLogitClassificationSolution(IClassificationProblemData problemData, MultinomialLogitModel logitModel)
+      : base(logitModel, problemData) {
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new MultinomialLogitClassificationSolution(this, cloner);
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Linear/MultinomialLogitModel.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Linear/MultinomialLogitModel.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Linear/MultinomialLogitModel.cs	(revision 13819)
@@ -0,0 +1,138 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Problems.DataAnalysis;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  /// <summary>
+  /// Represents a multinomial logit model for classification
+  /// </summary>
+  [StorableClass]
+  [Item("Multinomial Logit Model", "Represents a multinomial logit model for classification.")]
+  public sealed class MultinomialLogitModel : NamedItem, IClassificationModel {
+
+    private alglib.logitmodel logitModel;
+    public alglib.logitmodel Model {
+      get { return logitModel; }
+      set {
+        if (value != logitModel) {
+          if (value == null) throw new ArgumentNullException();
+          logitModel = value;
+          OnChanged(EventArgs.Empty);
+        }
+      }
+    }
+
+    [Storable]
+    private string targetVariable;
+    [Storable]
+    private string[] allowedInputVariables;
+    [Storable]
+    private double[] classValues;
+    [StorableConstructor]
+    private MultinomialLogitModel(bool deserializing)
+      : base(deserializing) {
+      if (deserializing)
+        logitModel = new alglib.logitmodel();
+    }
+    private MultinomialLogitModel(MultinomialLogitModel original, Cloner cloner)
+      : base(original, cloner) {
+      logitModel = new alglib.logitmodel();
+      logitModel.innerobj.w = (double[])original.logitModel.innerobj.w.Clone();
+      targetVariable = original.targetVariable;
+      allowedInputVariables = (string[])original.allowedInputVariables.Clone();
+      classValues = (double[])original.classValues.Clone();
+    }
+    public MultinomialLogitModel(alglib.logitmodel logitModel, string targetVariable, IEnumerable<string> allowedInputVariables, double[] classValues)
+      : base() {
+      this.name = ItemName;
+      this.description = ItemDescription;
+      this.logitModel = logitModel;
+      this.targetVariable = targetVariable;
+      this.allowedInputVariables = allowedInputVariables.ToArray();
+      this.classValues = (double[])classValues.Clone();
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new MultinomialLogitModel(this, cloner);
+    }
+
+    public IEnumerable<double> GetEstimatedClassValues(IDataset dataset, IEnumerable<int> rows) {
+      double[,] inputData = AlglibUtil.PrepareInputMatrix(dataset, allowedInputVariables, rows);
+
+      int n = inputData.GetLength(0);
+      int columns = inputData.GetLength(1);
+      double[] x = new double[columns];
+      double[] y = new double[classValues.Length];
+
+      for (int row = 0; row < n; row++) {
+        for (int column = 0; column < columns; column++) {
+          x[column] = inputData[row, column];
+        }
+        alglib.mnlprocess(logitModel, x, ref y);
+        // find class for with the largest probability value
+        int maxProbClassIndex = 0;
+        double maxProb = y[0];
+        for (int i = 1; i < y.Length; i++) {
+          if (maxProb < y[i]) {
+            maxProb = y[i];
+            maxProbClassIndex = i;
+          }
+        }
+        yield return classValues[maxProbClassIndex];
+      }
+    }
+
+    public MultinomialLogitClassificationSolution CreateClassificationSolution(IClassificationProblemData problemData) {
+      return new MultinomialLogitClassificationSolution(new ClassificationProblemData(problemData), this);
+    }
+    IClassificationSolution IClassificationModel.CreateClassificationSolution(IClassificationProblemData problemData) {
+      return CreateClassificationSolution(problemData);
+    }
+
+    #region events
+    public event EventHandler Changed;
+    private void OnChanged(EventArgs e) {
+      var handlers = Changed;
+      if (handlers != null)
+        handlers(this, e);
+    }
+    #endregion
+
+    #region persistence
+    [Storable]
+    private double[] LogitModelW {
+      get {
+        return logitModel.innerobj.w;
+      }
+      set {
+        logitModel.innerobj.w = value;
+      }
+    }
+    #endregion
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Linear/Scaling.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Linear/Scaling.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Linear/Scaling.cs	(revision 13819)
@@ -0,0 +1,68 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Problems.DataAnalysis;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  [StorableClass]
+  [Item(Name = "Scaling", Description = "Contains information about scaling of variables for data-analysis algorithms.")]
+  public class Scaling : Item {
+    [Storable]
+    private Dictionary<string, Tuple<double, double>> scalingParameters = new Dictionary<string, Tuple<double, double>>();
+    [StorableConstructor]
+    protected Scaling(bool deserializing) : base(deserializing) { }
+    protected Scaling(Scaling original, Cloner cloner)
+      : base(original, cloner) {
+      foreach (var pair in original.scalingParameters)
+        scalingParameters.Add(pair.Key, Tuple.Create(pair.Value.Item1, pair.Value.Item2));
+    }
+    public Scaling(IDataset ds, IEnumerable<string> variables, IEnumerable<int> rows) {
+      foreach (var variable in variables) {
+        var values = ds.GetDoubleValues(variable, rows);
+        var min = values.Where(x => !double.IsNaN(x)).Min();
+        var max = values.Where(x => !double.IsNaN(x)).Max();
+        scalingParameters[variable] = Tuple.Create(min, max);
+      }
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new Scaling(this, cloner);
+    }
+
+    public IEnumerable<double> GetScaledValues(IDataset ds, string variable, IEnumerable<int> rows) {
+      double min = scalingParameters[variable].Item1;
+      double max = scalingParameters[variable].Item2;
+      if (min.IsAlmost(max)) return rows.Select(i => 0.0); // return enumerable of zeros
+      return ds.GetDoubleValues(variable, rows).Select(x => (x - min) / (max - min));  // scale to range [0..1]
+    }
+
+    public void GetScalingParameters(string variable, out double min, out double max) {
+      min = scalingParameters[variable].Item1;
+      max = scalingParameters[variable].Item2;
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/MctsSymbolicRegression/Automaton.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/MctsSymbolicRegression/Automaton.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/MctsSymbolicRegression/Automaton.cs	(revision 13819)
@@ -0,0 +1,409 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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.IO;
+
+namespace HeuristicLab.Algorithms.DataAnalysis.MctsSymbolicRegression {
+  // this is the core class for generating expressions. 
+  // it represents a finite state automaton, each state transition can be associated with an action (e.g. to produce code).
+  // the automaton determines the possible structures for expressions.
+  // 
+  // to understand this code it is worthwile to generate a graphical visualization of the automaton (see PrintAutomaton).
+  // If the code is compiled in debug mode the automaton produces a Graphviz file into the folder of the application
+  // whenever an instance of the automaton is constructed.
+  //
+  // This class relies on two other classes: 
+  // - CodeGenerator to produce code for a stack-based evaluator and
+  // - ConstraintHandler to restrict the allowed set of expressions. 
+  //
+  // The ConstraintHandler extends the automaton and adds semantic restrictions for expressions produced by the automaton.
+  // 
+  // 
+  internal class Automaton {
+    public const int StateExpr = 1;
+    public const int StateExprEnd = 2;
+    public const int StateTermStart = 3;
+    public const int StateTermEnd = 4;
+    public const int StateFactorStart = 5;
+    public const int StateFactorEnd = 6;
+    public const int StateVariableFactorStart = 7;
+    public const int StateVariableFactorEnd = 8;
+    public const int StateExpFactorStart = 9;
+    public const int StateExpFactorEnd = 10;
+    public const int StateLogFactorStart = 11;
+    public const int StateLogFactorEnd = 12;
+    public const int StateInvFactorStart = 13;
+    public const int StateInvFactorEnd = 14;
+    public const int StateExpFStart = 15;
+    public const int StateExpFEnd = 16;
+    public const int StateLogTStart = 17;
+    public const int StateLogTEnd = 18;
+    public const int StateLogTFStart = 19;
+    public const int StateLogTFEnd = 20;
+    public const int StateInvTStart = 21;
+    public const int StateInvTEnd = 22;
+    public const int StateInvTFStart = 23;
+    public const int StateInvTFEnd = 24;
+    public const int FirstDynamicState = 25;
+    // more states for individual variables are created dynamically
+
+    private const int StartState = StateExpr;
+    public int CurrentState { get; private set; }
+
+    public readonly List<string> stateNames;
+    private List<int>[] followStates;
+    private List<Action>[,] actions; // not every follow state is possible but this representation should be efficient
+    private List<string>[,] actionStrings; // just for printing 
+    private readonly CodeGenerator codeGenerator;
+    private readonly ConstraintHandler constraintHandler;
+
+    public Automaton(double[][] vars, int maxVarsInExpression = 100,
+       bool allowProdOfVars = true,
+       bool allowExp = true,
+       bool allowLog = true,
+       bool allowInv = true,
+       bool allowMultipleTerms = false) {
+      int nVars = vars.Length;
+      stateNames = new List<string>() { string.Empty, "Expr", "ExprEnd", "TermStart", "TermEnd", "FactorStart", "FactorEnd", "VarFactorStart", "VarFactorEnd", "ExpFactorStart", "ExpFactorEnd", "LogFactorStart", "LogFactorEnd", "InvFactorStart", "InvFactorEnd", "ExpFStart", "ExpFEnd", "LogTStart", "LogTEnd", "LogTFStart", "LogTFEnd", "InvTStart", "InvTEnd", "InvTFStart", "InvTFEnd" };
+      codeGenerator = new CodeGenerator();
+      constraintHandler = new ConstraintHandler(maxVarsInExpression);
+      BuildAutomaton(nVars, allowProdOfVars, allowExp, allowLog, allowInv, allowMultipleTerms);
+
+      Reset();
+#if DEBUG
+      PrintAutomaton();
+#endif
+    }
+
+    // reverse notation ops
+    // Expr -> c 0 Term { '+' Term } '+' '*' c '+' 'exit'
+    // Term -> c Fact { '*' Fact } '*'
+    // Fact -> VarFact | ExpFact | LogFact | InvFact
+    // VarFact -> var_1 ... var_n
+    // ExpFact -> 1 ExpF { '*' ExpF } '*' c '*' 'exp' // c must be at end to allow scaling in evaluator
+    // ExpF    -> var_1 ... var_n 
+    // LogFact -> 0 LogT { '+' LogT } '+' c '+' 'log' // c must be at end to allow scaling in evaluator
+    // LogT    -> c LogTF { '*' LogTF } '*' 
+    // LogTF   -> var_1 ... var_n 
+    // InvFact -> 1 InvT { '+' InvT } '+' 'inv'
+    // InvT    -> (var_1 ... var_n) c '*' 
+    private void BuildAutomaton(int nVars,
+      bool allowProdOfVars = true,
+       bool allowExp = true,
+       bool allowLog = true,
+       bool allowInv = true,
+       bool allowMultipleTerms = false) {
+
+      int nStates = FirstDynamicState + 4 * nVars;
+      followStates = new List<int>[nStates];
+      actions = new List<Action>[nStates, nStates];
+      actionStrings = new List<string>[nStates, nStates];
+
+      // Expr -> c 0 Term { '+' Term } '+' '*' c '+' 'exit'
+      AddTransition(StateExpr, StateTermStart, () => {
+        codeGenerator.Reset();
+        codeGenerator.Emit1(OpCodes.LoadParamN);
+        codeGenerator.Emit1(OpCodes.LoadConst0);
+        constraintHandler.Reset();
+      }, "c 0, Reset");
+      AddTransition(StateTermEnd, StateExprEnd, () => {
+        codeGenerator.Emit1(OpCodes.Add);
+        codeGenerator.Emit1(OpCodes.Mul);
+        codeGenerator.Emit1(OpCodes.LoadParamN);
+        codeGenerator.Emit1(OpCodes.Add);
+        codeGenerator.Emit1(OpCodes.Exit);
+      }, "+*c+ exit");
+      if (allowMultipleTerms)
+        AddTransition(StateTermEnd, StateTermStart, () => {
+          codeGenerator.Emit1(OpCodes.Add);
+        }, "+");
+
+      // Term -> c Fact { '*' Fact } '*'
+      AddTransition(StateTermStart, StateFactorStart,
+        () => {
+          codeGenerator.Emit1(OpCodes.LoadParamN);
+          constraintHandler.StartTerm();
+        },
+        "c, StartTerm");
+      AddTransition(StateFactorEnd, StateTermEnd,
+        () => {
+          codeGenerator.Emit1(OpCodes.Mul);
+          constraintHandler.EndTerm();
+        },
+        "*, EndTerm");
+
+      AddTransition(StateFactorEnd, StateFactorStart,
+        () => { codeGenerator.Emit1(OpCodes.Mul); },
+        "*");
+
+
+      // Fact -> VarFact | ExpFact | LogFact | InvFact
+      if (allowProdOfVars)
+        AddTransition(StateFactorStart, StateVariableFactorStart, () => {
+          constraintHandler.StartFactor(StateVariableFactorStart);
+        }, "StartFactor");
+      if (allowExp)
+        AddTransition(StateFactorStart, StateExpFactorStart, () => {
+          constraintHandler.StartFactor(StateExpFactorStart);
+        }, "StartFactor");
+      if (allowLog)
+        AddTransition(StateFactorStart, StateLogFactorStart, () => {
+          constraintHandler.StartFactor(StateLogFactorStart);
+        }, "StartFactor");
+      if (allowInv)
+        AddTransition(StateFactorStart, StateInvFactorStart, () => {
+          constraintHandler.StartFactor(StateInvFactorStart);
+        }, "StartFactor");
+      AddTransition(StateVariableFactorEnd, StateFactorEnd, () => { constraintHandler.EndFactor(); }, "EndFactor");
+      AddTransition(StateExpFactorEnd, StateFactorEnd, () => { constraintHandler.EndFactor(); }, "EndFactor");
+      AddTransition(StateLogFactorEnd, StateFactorEnd, () => { constraintHandler.EndFactor(); }, "EndFactor");
+      AddTransition(StateInvFactorEnd, StateFactorEnd, () => { constraintHandler.EndFactor(); }, "EndFactor");
+
+      // VarFact -> var_1 ... var_n
+      // add dynamic states for each variable 
+      int curDynVarState = FirstDynamicState;
+      for (int i = 0; i < nVars; i++) {
+        short varIdx = (short)i;
+        var varState = curDynVarState;
+        stateNames.Add("var_1");
+        AddTransition(StateVariableFactorStart, curDynVarState,
+          () => {
+            codeGenerator.Emit2(OpCodes.LoadVar, varIdx);
+            constraintHandler.AddVarToCurrentFactor(varState);
+          },
+          "var_" + varIdx + ", AddVar");
+        AddTransition(curDynVarState, StateVariableFactorEnd);
+        curDynVarState++;
+      }
+
+      // ExpFact -> 1 ExpF { '*' ExpF } '*' c '*' 'exp' 
+      AddTransition(StateExpFactorStart, StateExpFStart,
+        () => {
+          codeGenerator.Emit1(OpCodes.LoadConst1);
+        },
+        "1");
+      AddTransition(StateExpFEnd, StateExpFactorEnd,
+        () => {
+          codeGenerator.Emit1(OpCodes.Mul);
+          codeGenerator.Emit1(OpCodes.LoadParamN);
+          codeGenerator.Emit1(OpCodes.Mul);
+          codeGenerator.Emit1(OpCodes.Exp);
+        },
+        "*c*exp");
+      AddTransition(StateExpFEnd, StateExpFStart,
+        () => { codeGenerator.Emit1(OpCodes.Mul); },
+        "*");
+
+      // ExpF    -> var_1 ... var_n 
+      for (int i = 0; i < nVars; i++) {
+        short varIdx = (short)i;
+        int varState = curDynVarState;
+        stateNames.Add("var_2");
+        AddTransition(StateExpFStart, curDynVarState,
+          () => {
+            codeGenerator.Emit2(OpCodes.LoadVar, varIdx);
+            constraintHandler.AddVarToCurrentFactor(varState);
+          },
+          "var_" + varIdx + ", AddVar");
+        AddTransition(curDynVarState, StateExpFEnd);
+        curDynVarState++;
+      }
+
+      // must have c at end because of adjustment of c in evaluator
+      // LogFact -> 0 LogT { '+' LogT } '+' c '+' 'log'
+      AddTransition(StateLogFactorStart, StateLogTStart,
+        () => {
+          codeGenerator.Emit1(OpCodes.LoadConst0);
+          constraintHandler.StartNewTermInPoly();
+        },
+        "0, StartTermInPoly");
+      AddTransition(StateLogTEnd, StateLogFactorEnd,
+        () => {
+          codeGenerator.Emit1(OpCodes.Add);
+          codeGenerator.Emit1(OpCodes.LoadParamN);
+          codeGenerator.Emit1(OpCodes.Add);
+          codeGenerator.Emit1(OpCodes.Log);
+        },
+        "+c+log");
+      AddTransition(StateLogTEnd, StateLogTStart,
+        () => { codeGenerator.Emit1(OpCodes.Add); },
+        "+");
+
+      // LogT    -> c LogTF { '*' LogTF } '*' 
+      AddTransition(StateLogTStart, StateLogTFStart,
+        () => {
+          codeGenerator.Emit1(OpCodes.LoadParamN);
+        },
+        "c");
+      AddTransition(StateLogTFEnd, StateLogTEnd,
+        () => {
+          codeGenerator.Emit1(OpCodes.Mul);
+        },
+        "*");
+      AddTransition(StateLogTFEnd, StateLogTFStart,
+        () => {
+          codeGenerator.Emit1(OpCodes.Mul);
+        },
+        "*");
+
+      // LogTF   -> var_1 ... var_n
+      for (int i = 0; i < nVars; i++) {
+        short varIdx = (short)i;
+        int varState = curDynVarState;
+        stateNames.Add("var_3");
+        AddTransition(StateLogTFStart, curDynVarState,
+          () => {
+            codeGenerator.Emit2(OpCodes.LoadVar, varIdx);
+            constraintHandler.AddVarToCurrentFactor(varState);
+          },
+          "var_" + varIdx + ", AddVar");
+        AddTransition(curDynVarState, StateLogTFEnd);
+        curDynVarState++;
+      }
+
+      // InvFact -> 1 InvT { '+' InvT } '+' 'inv'
+      AddTransition(StateInvFactorStart, StateInvTStart,
+        () => {
+          codeGenerator.Emit1(OpCodes.LoadConst1);
+          constraintHandler.StartNewTermInPoly();
+        },
+        "c, StartTermInPoly");
+      AddTransition(StateInvTEnd, StateInvFactorEnd,
+        () => {
+          codeGenerator.Emit1(OpCodes.Add);
+          codeGenerator.Emit1(OpCodes.Inv);
+        },
+        "+inv");
+      AddTransition(StateInvTEnd, StateInvTStart,
+        () => { codeGenerator.Emit1(OpCodes.Add); },
+        "+");
+
+      // InvT    -> c InvTF { '*' InvTF } '*' 
+      AddTransition(StateInvTStart, StateInvTFStart,
+        () => {
+          codeGenerator.Emit1(OpCodes.LoadParamN);
+        },
+        "c");
+      AddTransition(StateInvTFEnd, StateInvTEnd,
+        () => {
+          codeGenerator.Emit1(OpCodes.Mul);
+        },
+        "*");
+      AddTransition(StateInvTFEnd, StateInvTFStart,
+        () => {
+          codeGenerator.Emit1(OpCodes.Mul);
+        },
+        "*");
+
+      // InvTF    -> (var_1 ... var_n) c '*' 
+      for (int i = 0; i < nVars; i++) {
+        short varIdx = (short)i;
+        int varState = curDynVarState;
+        stateNames.Add("var_4");
+        AddTransition(StateInvTFStart, curDynVarState,
+          () => {
+            codeGenerator.Emit2(OpCodes.LoadVar, varIdx);
+            constraintHandler.AddVarToCurrentFactor(varState);
+          },
+          "var_" + varIdx + ", AddVar");
+        AddTransition(curDynVarState, StateInvTFEnd);
+        curDynVarState++;
+      }
+
+      followStates[StateExprEnd] = new List<int>(); // no follow states
+    }
+
+    private void AddTransition(int fromState, int toState) {
+      if (followStates[fromState] == null) followStates[fromState] = new List<int>();
+      followStates[fromState].Add(toState);
+    }
+    private void AddTransition(int fromState, int toState, Action action, string str) {
+      if (followStates[fromState] == null) followStates[fromState] = new List<int>();
+      followStates[fromState].Add(toState);
+
+      if (actions[fromState, toState] == null) {
+        actions[fromState, toState] = new List<Action>();
+        actionStrings[fromState, toState] = new List<string>();
+      }
+
+      actions[fromState, toState].Add(action);
+      actionStrings[fromState, toState].Add(str);
+    }
+
+    private readonly int[] followStatesBuf = new int[1000];
+    public void FollowStates(int state, out int[] buf, out int nElements) {
+      // for loop instead of where iterator
+      var fs = followStates[state];
+      int j = 0;
+      for (int i = 0; i < fs.Count; i++) {
+        var s = fs[i];
+        if (constraintHandler.IsAllowedFollowState(state, s)) {
+          followStatesBuf[j++] = s;
+        }
+      }
+      buf = followStatesBuf;
+      nElements = j;
+    }
+
+
+    public void Goto(int targetState) {
+      if (actions[CurrentState, targetState] != null)
+        actions[CurrentState, targetState].ForEach(a => a()); // execute all actions
+      CurrentState = targetState;
+    }
+
+    public bool IsFinalState(int s) {
+      return s == StateExprEnd && !constraintHandler.IsInvalidExpression;
+    }
+
+    public void GetCode(out byte[] code, out int nParams) {
+      codeGenerator.GetCode(out code, out nParams);
+    }
+
+    public void Reset() {
+      CurrentState = StartState;
+      codeGenerator.Reset();
+      constraintHandler.Reset();
+    }
+
+#if DEBUG
+    public void PrintAutomaton() {
+      using (var writer = new StreamWriter("automaton.gv")) {
+        writer.WriteLine("digraph {");
+        // writer.WriteLine("rankdir=LR");
+        int[] fs;
+        int nFs;
+        for (int s = StartState; s < stateNames.Count; s++) {
+          for (int i = 0; i < followStates[s].Count; i++) {
+            if (followStates[s][i] <= 0) continue;
+            var followS = followStates[s][i];
+            var label = actionStrings[s, followS] != null ? string.Join(" , ", actionStrings[s, followS]) : "";
+            writer.WriteLine("{0} -> {1} [ label = \"{2}\" ];", stateNames[s], stateNames[followS], label);
+          }
+        }
+        writer.WriteLine("}");
+      }
+    }
+#endif
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/MctsSymbolicRegression/CodeGenerator.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/MctsSymbolicRegression/CodeGenerator.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/MctsSymbolicRegression/CodeGenerator.cs	(revision 13819)
@@ -0,0 +1,56 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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.Diagnostics.Contracts;
+
+namespace HeuristicLab.Algorithms.DataAnalysis.MctsSymbolicRegression {
+  internal class CodeGenerator {
+
+    public const int MaxCodeLength = 10000;
+    public const int MaxConstants = 100;
+
+    private readonly byte[] codeArray = new byte[MaxCodeLength];
+    private int pc;
+    private int nParams;
+
+    public void Reset() {
+      pc = 0;
+      nParams = 0;
+    }
+
+    public void Emit1(OpCodes code) {
+      codeArray[pc++] = (byte)code;
+      if (code == OpCodes.LoadParamN) nParams++;
+    }
+
+    public void Emit2(OpCodes code, short arg) {
+      Contract.Assert(code == OpCodes.LoadVar); // only loadVar opcode has params
+      Emit1(code);
+      codeArray[pc++] = (byte)(arg >> 8);
+      codeArray[pc++] = (byte)(arg & 0xFF);
+    }
+
+    public void GetCode(out byte[] code, out int nParams) {
+      code = codeArray;
+      nParams = this.nParams;
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/MctsSymbolicRegression/ConstraintHandler.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/MctsSymbolicRegression/ConstraintHandler.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/MctsSymbolicRegression/ConstraintHandler.cs	(revision 13819)
@@ -0,0 +1,417 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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.Diagnostics.Contracts;
+using System.Linq;
+
+namespace HeuristicLab.Algorithms.DataAnalysis.MctsSymbolicRegression {
+
+  // This class restricts the set of allowed transitions of the automaton to prevent exploration of duplicate expressions.
+  // It would be possible to implement this class in such a way that the search never visits a duplicate expression. However,
+  // it seems very intricate to detect this robustly and in all cases while generating an expression because 
+  // some for of lookahead is necessary. 
+  // Instead the constraint handler only catches the obvious duplicates directly, but does not guarantee that the search always produces a valid expression.
+  // The ratio of the number of unsuccessful searches, that need backtracking should be tracked in the MCTS alg (MctsSymbolicRegressionStatic)
+
+  // All changes to this class should be tested through unit tests. It is important that the ConstraintHandler is not too restrictive.
+
+  // the constraints are derived from a canonical form for expressions.
+  // overall we can enforce a limited number of variable references
+  // 
+  // an expression is a sum of terms t_1 ... t_n where terms are ordered according to a relation t_i (<=)_term t_j for each pair t_i, t_j and i <= j
+  // a term is a product of factors where factors are ordered according to relation f_i (<=)_factor f_j for each pair f_i,f_j and i <= j
+
+  // we want to enforce lower-order terms before higher-order terms in expressions (based on number of variable references)
+  // factors can have different types (variable, exp, log, inverse)
+
+  // (<=)_term  [IsSmallerOrEqualTerm(t_i, t_j)]
+  //   1.  NumberOfVarRefs(t_i) < NumberOfVarRefs(t_j)  --> true           enforce terms with non-decreasing number of var refs
+  //   2.  NumberOfVarRefs(t_i) > NumberOfVarRefs(t_j)  --> false
+  //   3.  NumFactors(t_i) > NumFactors(t_j)            --> true           enforce terms with non-increasing number of factors
+  //   4.  NumFactors(t_i) < NumFactors(t_j)            --> false
+  //   5.  for all k factors: Factor(k, t_i) (<=)_factor  Factor(k, t_j) --> true // factors must be non-decreasing
+  //   6.  all factors are (=)_factor                   --> true
+  //   7.  else false
+
+  // (<=)_factor  [IsSmallerOrEqualFactor(f_i, f_j)]
+  //   1.  FactorType(t_i) < FactorType(t_j)  --> true           enforce terms with non-decreasing factor type (var < exp < log < inv)
+  //   2.  FactorType(t_i) > FactorType(t_j)  --> false
+  //   3.  Compare the two factors specifically
+  //     - variables: varIdx_i <= varIdx_j (only one var reference)
+  //     - exp: number of variable references and then varIdx_i <= varIdx_j for each position
+  //     - log: number of variable references and ...
+  //     - inv: number of variable references and ...
+  //
+
+  // for log and inverse factors we allow all polynomials as argument
+  // a polynomial is a sum of terms t_1 ... t_n where terms are ordered according to a relation t_i (<=)_poly t_j for each pair t_i, t_j and i <= j
+
+  // (<=)_poly  [IsSmallerOrEqualPoly(t_i, t_j)]
+  //  1. NumberOfVarRefs(t_i) < NumberOfVarRefs(t_j)         --> true // enforce non-decreasing number of var refs
+  //  2. NumberOfVarRefs(t_i) > NumberOfVarRefs(t_j)         --> false // enforce non-decreasing number of var refs
+  //  3. for all k variables: VarIdx(k,t_i) > VarIdx(k, t_j) --> false // enforce non-decreasing variable idx
+
+
+  // we store the following to make comparsions:
+  // - prevTerm (complete & containing all factors)
+  // - curTerm  (incomplete & containing all completed factors)
+  // - curFactor (incomplete)
+  internal class ConstraintHandler {
+    private int nVars;
+    private readonly int maxVariables;
+    private bool invalidExpression;
+
+    public bool IsInvalidExpression {
+      get { return invalidExpression; }
+    }
+
+
+    private TermInformation prevTerm;
+    private TermInformation curTerm;
+    private FactorInformation curFactor;
+
+
+    private class TermInformation {
+      public int numVarReferences { get { return factors.Sum(f => f.numVarReferences); } }
+      public List<FactorInformation> factors = new List<FactorInformation>();
+    }
+
+    private class FactorInformation {
+      public int numVarReferences = 0;
+      public int factorType; // use the state number to represent types
+
+      // for variable factors
+      public int variableState = -1;
+
+      // for exp  factors
+      public List<int> expVariableStates = new List<int>();
+
+      // for log and inv factors
+      public List<List<int>> polyVariableStates = new List<List<int>>();
+    }
+
+
+    public ConstraintHandler(int maxVars) {
+      this.maxVariables = maxVars;
+    }
+
+    // the order relations for terms and factors
+
+    private static int CompareTerms(TermInformation a, TermInformation b) {
+      if (a.numVarReferences < b.numVarReferences) return -1;
+      if (a.numVarReferences > b.numVarReferences) return 1;
+
+      if (a.factors.Count > b.factors.Count) return -1;  // terms with more factors should be ordered first
+      if (a.factors.Count < b.factors.Count) return +1;
+
+      var aFactors = a.factors.GetEnumerator();
+      var bFactors = b.factors.GetEnumerator();
+      while (aFactors.MoveNext() & bFactors.MoveNext()) {
+        var c = CompareFactors(aFactors.Current, bFactors.Current);
+        if (c < 0) return -1;
+        if (c > 0) return 1;
+      }
+      // all factors are the same => terms are the same
+      return 0;
+    }
+
+    private static int CompareFactors(FactorInformation a, FactorInformation b) {
+      if (a.factorType < b.factorType) return -1;
+      if (a.factorType > b.factorType) return +1;
+      // same factor types
+      if (a.factorType == Automaton.StateVariableFactorStart) {
+        return a.variableState.CompareTo(b.variableState);
+      } else if (a.factorType == Automaton.StateExpFactorStart) {
+        return CompareStateLists(a.expVariableStates, b.expVariableStates);
+      } else {
+        if (a.numVarReferences < b.numVarReferences) return -1;
+        if (a.numVarReferences > b.numVarReferences) return +1;
+        if (a.polyVariableStates.Count > b.polyVariableStates.Count) return -1; // more terms in the poly should be ordered first
+        if (a.polyVariableStates.Count < b.polyVariableStates.Count) return +1;
+        // log and inv
+        var aTerms = a.polyVariableStates.GetEnumerator();
+        var bTerms = b.polyVariableStates.GetEnumerator();
+        while (aTerms.MoveNext() & bTerms.MoveNext()) {
+          var c = CompareStateLists(aTerms.Current, bTerms.Current);
+          if (c != 0) return c;
+        }
+        return 0; // all terms in the polynomial are the same
+      }
+    }
+
+    private static int CompareStateLists(List<int> a, List<int> b) {
+      if (a.Count < b.Count) return -1;
+      if (a.Count > b.Count) return +1;
+      for (int i = 0; i < a.Count; i++) {
+        if (a[i] < b[i]) return -1;
+        if (a[i] > b[i]) return +1;
+      }
+      return 0; // all states are the same
+    }
+
+
+    private bool IsNewTermAllowed() {
+      // next term must have at least as many variable references as the previous term
+      return prevTerm == null || nVars + prevTerm.numVarReferences <= maxVariables;
+    }
+
+    private bool IsNewFactorAllowed() {
+      // next factor must have a larger or equal type compared to the previous factor.
+      // if the types are the same it must have at least as many variable references.
+      // so if the prevFactor is any other than invFactor (last possible type) then we only need to be able to add one variable
+      // otherwise we need to be able to add at least as many variables as the previous factor
+      return !curTerm.factors.Any() ||
+             (nVars + curTerm.factors.Last().numVarReferences <= maxVariables);
+    }
+
+    private bool IsAllowedAsNextFactorType(int followState) {
+      // IsNewTermAllowed already ensures that we can add a term with enough variable references
+
+      // enforce constraints within terms (compare to prev factor)
+      if (curTerm.factors.Any()) {
+        // enforce non-decreasing factor types
+        if (curTerm.factors.Last().factorType > followState) return false;
+        // when the factor type is the same, starting a new factor is only allowed if we can add at least the number of variables of the prev factor
+        if (curTerm.factors.Last().factorType == followState && nVars + curTerm.factors.Last().numVarReferences > maxVariables) return false;
+      }
+
+      // enforce constraints on terms (compare to prev term)
+      // meaning that we must ensure non-decreasing terms
+      if (prevTerm != null) {
+        // a factor type is only allowed if we can then produce a term that is larger or equal to the prev term
+        // (1) if we the number of variable references still remaining is larger than the number of variable references in the prev term 
+        //     then it is always possible to build a larger term
+        // (2) otherwise we try to build the largest possible term starting from current factors in the term.
+        //     
+
+        var numVarRefsRemaining = maxVariables - nVars;
+        Contract.Assert(!curTerm.factors.Any() || curTerm.factors.Last().numVarReferences <= numVarRefsRemaining);
+
+        if (prevTerm.numVarReferences < numVarRefsRemaining) return true;
+
+        // variable factors must be handled differently because they can only contain one variable reference
+        if (followState == Automaton.StateVariableFactorStart) {
+          // append the variable factor and the maximum possible state from the previous factor to create a larger factor
+          var varF = CreateLargestPossibleFactor(Automaton.StateVariableFactorStart, 1);
+          var maxF = CreateLargestPossibleFactor(prevTerm.factors.Max(f => f.factorType), numVarRefsRemaining - 1);
+          var origFactorCount = curTerm.factors.Count;
+          // add this factor to the current term
+          curTerm.factors.Add(varF);
+          curTerm.factors.Add(maxF);
+          var c = CompareTerms(prevTerm, curTerm);
+          // restore term
+          curTerm.factors.RemoveRange(origFactorCount, 2);
+          // if the prev term is still larger then this followstate is not allowed
+          if (c > 0) {
+            return false;
+          }
+        } else {
+          var newF = CreateLargestPossibleFactor(followState, numVarRefsRemaining);
+
+          var origFactorCount = curTerm.factors.Count;
+          // add this factor to the current term
+          curTerm.factors.Add(newF);
+          var c = CompareTerms(prevTerm, curTerm);
+          // restore term
+          curTerm.factors.RemoveAt(origFactorCount);
+          // if the prev term is still larger then this followstate is not allowed
+          if (c > 0) {
+            return false;
+          }
+        }
+      }
+      return true;
+    }
+
+    // largest possible factor of the given kind
+    private FactorInformation CreateLargestPossibleFactor(int factorType, int numVarRefs) {
+      var newF = new FactorInformation();
+      newF.factorType = factorType;
+      if (factorType == Automaton.StateVariableFactorStart) {
+        newF.variableState = int.MaxValue;
+        newF.numVarReferences = 1;
+      } else if (factorType == Automaton.StateExpFactorStart) {
+        for (int i = 0; i < numVarRefs; i++)
+          newF.expVariableStates.Add(int.MaxValue);
+        newF.numVarReferences = numVarRefs;
+      } else if (factorType == Automaton.StateInvFactorStart || factorType == Automaton.StateLogFactorStart) {
+        for (int i = 0; i < numVarRefs; i++) {
+          newF.polyVariableStates.Add(new List<int>());
+          newF.polyVariableStates[i].Add(int.MaxValue);
+        }
+        newF.numVarReferences = numVarRefs;
+      }
+      return newF;
+    }
+
+    private bool IsAllowedAsNextVariableFactor(int variableState) {
+      Contract.Assert(variableState >= Automaton.FirstDynamicState);
+      return !curTerm.factors.Any() || curTerm.factors.Last().variableState <= variableState;
+    }
+
+    private bool IsAllowedAsNextInExp(int variableState) {
+      Contract.Assert(variableState >= Automaton.FirstDynamicState);
+      if (curFactor.expVariableStates.Any() && curFactor.expVariableStates.Last() > variableState) return false;
+      if (curTerm.factors.Any()) {
+        // try and compare with prev factor      
+        curFactor.numVarReferences++;
+        curFactor.expVariableStates.Add(variableState);
+        var c = CompareFactors(curTerm.factors.Last(), curFactor);
+        curFactor.numVarReferences--;
+        curFactor.expVariableStates.RemoveAt(curFactor.expVariableStates.Count - 1);
+        return c <= 0;
+      }
+      return true;
+    }
+
+    private bool IsNewTermAllowedInPoly() {
+      return nVars + curFactor.polyVariableStates.Last().Count() <= maxVariables;
+    }
+
+    private bool IsAllowedAsNextInPoly(int variableState) {
+      Contract.Assert(variableState >= Automaton.FirstDynamicState);
+      return !curFactor.polyVariableStates.Any() ||
+             !curFactor.polyVariableStates.Last().Any() ||
+              curFactor.polyVariableStates.Last().Last() <= variableState;
+    }
+    private bool IsTermCompleteInPoly() {
+      var nTerms = curFactor.polyVariableStates.Count;
+      return nTerms == 1 ||
+             curFactor.polyVariableStates[nTerms - 2].Count <= curFactor.polyVariableStates[nTerms - 1].Count;
+
+    }
+    private bool IsCompleteExp() {
+      return !curTerm.factors.Any() || CompareFactors(curTerm.factors.Last(), curFactor) <= 0;
+    }
+
+    public bool IsAllowedFollowState(int currentState, int followState) {
+      // an invalid action was taken earlier on => nothing can be done anymore
+      if (invalidExpression) return false;
+      // states that have no alternative are always allowed
+      // some ending states are only allowed if enough variables have been used in the term
+      if (
+        currentState == Automaton.StateTermStart ||           // no alternative
+        currentState == Automaton.StateExpFactorStart ||
+        currentState == Automaton.StateLogFactorStart ||
+        currentState == Automaton.StateInvFactorStart ||
+        followState == Automaton.StateVariableFactorEnd ||    // no alternative
+        followState == Automaton.StateExpFEnd ||              // no alternative
+        followState == Automaton.StateLogTFEnd ||             // no alternative
+        followState == Automaton.StateInvTFEnd ||             // no alternative
+        followState == Automaton.StateFactorEnd ||            // always allowed because no alternative
+        followState == Automaton.StateExprEnd                 // we could also constrain the minimum number of terms here
+      ) return true;
+
+
+      // starting a new term is only allowed if we can add a term with at least the number of variables of the prev term
+      if (followState == Automaton.StateTermStart && !IsNewTermAllowed()) return false;
+      if (followState == Automaton.StateFactorStart && !IsNewFactorAllowed()) return false;
+      if (currentState == Automaton.StateFactorStart && !IsAllowedAsNextFactorType(followState)) return false;
+      if (followState == Automaton.StateTermEnd && prevTerm != null && CompareTerms(prevTerm, curTerm) > 0) return false;
+
+      // all of these states add at least one variable
+      if (
+          followState == Automaton.StateVariableFactorStart ||
+          followState == Automaton.StateExpFactorStart || followState == Automaton.StateExpFStart ||
+          followState == Automaton.StateLogFactorStart || followState == Automaton.StateLogTStart ||
+          followState == Automaton.StateLogTFStart ||
+          followState == Automaton.StateInvFactorStart || followState == Automaton.StateInvTStart ||
+          followState == Automaton.StateInvTFStart) {
+        if (nVars + 1 > maxVariables) return false;
+      }
+
+      if (currentState == Automaton.StateVariableFactorStart && !IsAllowedAsNextVariableFactor(followState)) return false;
+      else if (currentState == Automaton.StateExpFStart && !IsAllowedAsNextInExp(followState)) return false;
+      else if (followState == Automaton.StateLogTStart && !IsNewTermAllowedInPoly()) return false;
+      else if (currentState == Automaton.StateLogTFStart && !IsAllowedAsNextInPoly(followState)) return false;
+      else if (followState == Automaton.StateInvTStart && !IsNewTermAllowedInPoly()) return false;
+      else if (currentState == Automaton.StateInvTFStart && !IsAllowedAsNextInPoly(followState)) return false;
+      // finishing an exponential factor is only allowed when the number of variable references is large enough
+      else if (followState == Automaton.StateExpFactorEnd && !IsCompleteExp()) return false;
+      // finishing a polynomial (in log or inv) is only allowed when the number of variable references is large enough
+      else if (followState == Automaton.StateInvTEnd && !IsTermCompleteInPoly()) return false;
+      else if (followState == Automaton.StateLogTEnd && !IsTermCompleteInPoly()) return false;
+
+      else if (nVars > maxVariables) return false;
+      else return true;
+    }
+
+
+    public void Reset() {
+      nVars = 0;
+      prevTerm = null;
+      curTerm = null;
+      curFactor = null;
+      invalidExpression = false;
+    }
+
+    public void StartTerm() {
+      curTerm = new TermInformation();
+    }
+
+    public void StartFactor(int state) {
+      curFactor = new FactorInformation();
+      curFactor.factorType = state;
+    }
+
+
+    public void AddVarToCurrentFactor(int state) {
+      Contract.Assert(Automaton.FirstDynamicState <= state);
+      Contract.Assert(curTerm != null);
+      Contract.Assert(curFactor != null);
+
+      nVars++;
+      curFactor.numVarReferences++;
+
+      if (curFactor.factorType == Automaton.StateVariableFactorStart) {
+        Contract.Assert(curFactor.variableState < 0); // not set before
+        curFactor.variableState = state;
+      } else if (curFactor.factorType == Automaton.StateExpFactorStart) {
+        curFactor.expVariableStates.Add(state);
+      } else if (curFactor.factorType == Automaton.StateLogFactorStart ||
+                 curFactor.factorType == Automaton.StateInvFactorStart) {
+        curFactor.polyVariableStates.Last().Add(state);
+      } else throw new InvalidProgramException();
+    }
+
+    public void StartNewTermInPoly() {
+      curFactor.polyVariableStates.Add(new List<int>());
+    }
+
+    public void EndFactor() {
+      // enforce non-decreasing factors 
+      if (curTerm.factors.Any() && CompareFactors(curTerm.factors.Last(), curFactor) > 0)
+        invalidExpression = true;
+      curTerm.factors.Add(curFactor);
+      curFactor = null;
+    }
+
+    public void EndTerm() {
+      // enforce non-decreasing terms (TODO: equal terms should not be allowed)
+      if (prevTerm != null && CompareTerms(prevTerm, curTerm) > 0)
+        invalidExpression = true;
+      prevTerm = curTerm;
+      curTerm = null;
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/MctsSymbolicRegression/Disassembler.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/MctsSymbolicRegression/Disassembler.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/MctsSymbolicRegression/Disassembler.cs	(revision 13819)
@@ -0,0 +1,52 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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.Text;
+
+namespace HeuristicLab.Algorithms.DataAnalysis.MctsSymbolicRegression {
+  internal class Disassembler {
+    public static string CodeToString(byte[] code, double[] consts) {
+      var sb = new StringBuilder();
+      int pc = 0;
+      int nextParamIdx = -1;
+      while (code[pc] != (byte)OpCodes.Exit) {
+        var op = code[pc++];
+        switch (op) {
+          case (byte)OpCodes.Add: sb.Append(" + "); break;
+          case (byte)OpCodes.Mul: sb.Append(" * "); break;
+          case (byte)OpCodes.LoadConst1: sb.Append(" 1 "); break;
+          case (byte)OpCodes.LoadConst0: sb.Append(" 0 "); break;
+          case (byte)OpCodes.LoadParamN: sb.AppendFormat(" {0:N3} ", consts[++nextParamIdx]); break;
+          case (byte)OpCodes.LoadVar:
+          {
+              short arg = (short)(((short)code[pc] << 8) | (short)code[pc + 1]);
+              pc += 2;
+            sb.AppendFormat(" var{0} ", arg); break;
+          }
+          case (byte)OpCodes.Exp: sb.Append(" exp "); break;
+          case (byte)OpCodes.Log: sb.Append(" log "); break;
+          case (byte)OpCodes.Inv: sb.Append(" inv "); break;          
+        }
+      }
+      return sb.ToString();
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/MctsSymbolicRegression/ExpressionEvaluator.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/MctsSymbolicRegression/ExpressionEvaluator.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/MctsSymbolicRegression/ExpressionEvaluator.cs	(revision 13819)
@@ -0,0 +1,519 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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.Diagnostics.Contracts;
+using System.Linq;
+
+namespace HeuristicLab.Algorithms.DataAnalysis.MctsSymbolicRegression {
+  // evalutes expressions (on vectors)
+  internal class ExpressionEvaluator {
+    // manages it's own vector buffers
+    private readonly double[][] vectorBuffers;
+    private readonly double[][] scalarBuffers; // scalars are vectors of length 1 (to allow mixing scalars and vectors on the same stack)
+    private int lastVecBufIdx;
+    private int lastScalarBufIdx;
+
+
+    private double[] GetVectorBuffer() {
+      return vectorBuffers[--lastVecBufIdx];
+    }
+    private double[] GetScalarBuffer() {
+      return scalarBuffers[--lastScalarBufIdx];
+    }
+
+    private void ReleaseBuffer(double[] buf) {
+      if (buf.Length == 1) {
+        scalarBuffers[lastScalarBufIdx++] = buf;
+      } else {
+        vectorBuffers[lastVecBufIdx++] = buf;
+      }
+    }
+
+    public const int MaxStackSize = 100;
+    public const int MaxParams = 50;
+    private readonly int vLen;
+    private readonly double lowerEstimationLimit;
+    private readonly double upperEstimationLimit;
+    private readonly double nanReplacementValue;
+
+    private readonly double[][] stack;
+    private readonly double[][][] gradientStack;
+
+    // preallocate stack and gradient stack 
+    public ExpressionEvaluator(int vLen, double lowerEstimationLimit = double.MinValue, double upperEstimationLimit = double.MaxValue) {
+      if (vLen <= 1) throw new ArgumentException("number of elements in a variable must be > 1", "vlen");
+      this.vLen = vLen;
+      this.lowerEstimationLimit = lowerEstimationLimit;
+      this.upperEstimationLimit = upperEstimationLimit;
+      this.nanReplacementValue = (upperEstimationLimit - lowerEstimationLimit) / 2.0 + lowerEstimationLimit;
+
+      stack = new double[MaxStackSize][];
+      gradientStack = new double[MaxParams][][];
+
+      for (int k = 0; k < MaxParams; k++) {
+        gradientStack[k] = new double[MaxStackSize][];
+      }
+
+      // preallocate buffers 
+      vectorBuffers = new double[MaxStackSize * (1 + MaxParams)][];
+      scalarBuffers = new double[MaxStackSize * (1 + MaxParams)][];
+      for (int i = 0; i < MaxStackSize; i++) {
+        ReleaseBuffer(new double[vLen]);
+        ReleaseBuffer(new double[1]);
+
+        for (int k = 0; k < MaxParams; k++) {
+          ReleaseBuffer(new double[vLen]);
+          ReleaseBuffer(new double[1]);
+        }
+      }
+    }
+
+    // pred must be allocated by the caller
+    // if adjustOffsetForLogAndExp is set to true we determine c in log(c + f(x)) to make sure that c + f(x) is positive
+    public void Exec(byte[] code, double[][] vars, double[] consts, double[] pred, bool adjustOffsetForLogAndExp = false) {
+      Contract.Assert(pred != null && pred.Length >= vLen);
+      int topOfStack = -1;
+      int pc = 0;
+      int curParamIdx = -1;
+      byte op;
+      short arg;
+      // checked at the end to make sure we do not leak buffers
+      int initialScalarCount = lastScalarBufIdx;
+      int initialVectorCount = lastVecBufIdx;
+
+      while (true) {
+        ReadNext(code, ref pc, out op, out arg);
+        switch (op) {
+          case (byte)OpCodes.Nop: throw new InvalidProgramException(); // not allowed
+          case (byte)OpCodes.LoadConst0: {
+              ++topOfStack;
+              var z = GetScalarBuffer();
+              z[0] = 0;
+              stack[topOfStack] = z;
+              break;
+            }
+          case (byte)OpCodes.LoadConst1: {
+              ++topOfStack;
+              var z = GetScalarBuffer();
+              z[0] = 1.0;
+              stack[topOfStack] = z;
+              break;
+            }
+          case (byte)OpCodes.LoadParamN: {
+              ++topOfStack;
+              var c = consts[++curParamIdx];
+              var z = GetScalarBuffer();
+              z[0] = c;
+              stack[topOfStack] = z;
+              break;
+            }
+          case (byte)OpCodes.LoadVar: {
+              ++topOfStack;
+              var z = GetVectorBuffer();
+              Array.Copy(vars[arg], z, vars[arg].Length);
+              stack[topOfStack] = z;
+              break;
+            }
+          case (byte)OpCodes.Add: {
+              topOfStack--;
+              var a = stack[topOfStack + 1];
+              var b = stack[topOfStack];
+              stack[topOfStack] = Add(a, b);
+              ReleaseBuffer(a);
+              ReleaseBuffer(b);
+              break;
+            }
+          case (byte)OpCodes.Mul: {
+              topOfStack--;
+              var a = stack[topOfStack + 1];
+              var b = stack[topOfStack];
+              stack[topOfStack] = Mul(a, b);
+              ReleaseBuffer(a);
+              ReleaseBuffer(b);
+              break;
+            }
+          case (byte)OpCodes.Log: {
+              if (adjustOffsetForLogAndExp) {
+                // here we assume that the last used parameter is c in log(f(x) + c)
+                // this must match actions for producing code in the automaton!
+
+                // we can easily adjust c to make sure that f(x) + c is positive because at this point we all values for f(x)
+                var fxc = stack[topOfStack];
+                var minFx = fxc.Min() - consts[curParamIdx]; // stack[topOfStack] is f(x) + c
+
+                var delta = 1.0 - minFx - consts[curParamIdx];
+                // adjust c so that minFx + c = 1 ... log(minFx + c) = 0
+                consts[curParamIdx] += delta;
+
+                // also adjust values on stack
+                for (int i = 0; i < fxc.Length; i++) fxc[i] += delta;
+              }
+              var x = stack[topOfStack];
+              for (int i = 0; i < x.Length; i++)
+                x[i] = Math.Log(x[i]);
+              break;
+            }
+          case (byte)OpCodes.Exp: {
+              if (adjustOffsetForLogAndExp) {
+                // here we assume that the last used parameter is c in exp(f(x) * c)
+                // this must match actions for producing code in the automaton!
+
+                // adjust c to make sure that exp(f(x) * c) is not too large
+                var fxc = stack[topOfStack];
+                var maxFx = fxc.Max() / consts[curParamIdx]; // stack[topOfStack] is f(x) * c
+
+                var f = 1.0 / (maxFx * consts[curParamIdx]);
+                // adjust c so that maxFx*c = 1 TODO: this is not ideal as it enforces positive arguments to exp()
+                consts[curParamIdx] *= f;
+
+                // also adjust values on stack
+                for (int i = 0; i < fxc.Length; i++) fxc[i] *= f;
+              }
+
+              var x = stack[topOfStack];
+              for (int i = 0; i < x.Length; i++)
+                x[i] = Math.Exp(x[i]);
+              break;
+            }
+          case (byte)OpCodes.Inv: {
+              var x = stack[topOfStack];
+              for (int i = 0; i < x.Length; i++)
+                x[i] = 1.0 / (x[i]);
+              break;
+            }
+          case (byte)OpCodes.Exit:
+            Contract.Assert(topOfStack == 0);
+            var r = stack[topOfStack];
+            if (r.Length == 1) {
+              var v = double.IsNaN(r[0]) ? nanReplacementValue : Math.Min(upperEstimationLimit, Math.Max(lowerEstimationLimit, r[0]));
+              for (int i = 0; i < vLen; i++)
+                pred[i] = v;
+            } else {
+              for (int i = 0; i < vLen; i++) {
+                var v = double.IsNaN(r[i]) ? nanReplacementValue : Math.Min(upperEstimationLimit, Math.Max(lowerEstimationLimit, r[i]));
+                pred[i] = v;
+              }
+            }
+            ReleaseBuffer(r);
+            Contract.Assert(lastVecBufIdx == initialVectorCount);
+            Contract.Assert(lastScalarBufIdx == initialScalarCount);
+            return;
+        }
+      }
+    }
+
+
+    // evaluation with forward autodiff
+    // pred and gradients must be allocated by the caller
+    public void ExecGradient(byte[] code, double[][] vars, double[] consts, double[] pred, double[][] gradients) {
+      Contract.Assert(pred != null && pred.Length >= vLen);
+      int topOfStack = -1;
+      int pc = 0;
+      int curParamIdx = -1;
+      byte op;
+      short arg;
+      int nParams = consts.Length;
+      Contract.Assert(gradients != null && gradients.Length >= nParams && gradients.All(g => g.Length >= vLen));
+
+      // checked at the end to make sure we do not leak buffers
+      int initialScalarCount = lastScalarBufIdx;
+      int initialVectorCount = lastVecBufIdx;
+
+      while (true) {
+        ReadNext(code, ref pc, out op, out arg);
+        switch (op) {
+          case (byte)OpCodes.Nop: throw new InvalidProgramException(); // not allowed
+          case (byte)OpCodes.LoadConst0: {
+              ++topOfStack;
+              var z = GetScalarBuffer();
+              z[0] = 0;
+              stack[topOfStack] = z;
+              for (int k = 0; k < nParams; ++k) {
+                var b = GetScalarBuffer();
+                b[0] = 0.0;
+                gradientStack[k][topOfStack] = b;
+              }
+              break;
+            }
+          case (byte)OpCodes.LoadConst1: {
+              ++topOfStack;
+              var z = GetScalarBuffer();
+              z[0] = 1.0;
+              stack[topOfStack] = z;
+              for (int k = 0; k < nParams; ++k) {
+                var b = GetScalarBuffer();
+                b[0] = 0.0;
+                gradientStack[k][topOfStack] = b;
+              }
+              break;
+            }
+          case (byte)OpCodes.LoadParamN: {
+              var c = consts[++curParamIdx];
+              ++topOfStack;
+              var z = GetScalarBuffer();
+              z[0] = c;
+              stack[topOfStack] = z;
+              for (int k = 0; k < nParams; ++k) {
+                var b = GetScalarBuffer();
+                b[0] = k == curParamIdx ? 1.0 : 0.0;
+                gradientStack[k][topOfStack] = b;
+              }
+              break;
+            }
+          case (byte)OpCodes.LoadVar: {
+              ++topOfStack;
+              var z = GetVectorBuffer();
+              Array.Copy(vars[arg], z, vars[arg].Length);
+              stack[topOfStack] = z;
+              for (int k = 0; k < nParams; ++k) {
+                var b = GetScalarBuffer();
+                b[0] = 0.0;
+                gradientStack[k][topOfStack] = b;
+              }
+            }
+            break;
+          case (byte)OpCodes.Add: {
+              topOfStack--;
+              var a = stack[topOfStack + 1];
+              var b = stack[topOfStack];
+              stack[topOfStack] = Add(a, b);
+              ReleaseBuffer(a);
+              ReleaseBuffer(b);
+
+              // same for gradient
+              for (int k = 0; k < nParams; ++k) {
+                var ag = gradientStack[k][topOfStack + 1];
+                var bg = gradientStack[k][topOfStack];
+                gradientStack[k][topOfStack] = Add(ag, bg);
+                ReleaseBuffer(ag);
+                ReleaseBuffer(bg);
+              }
+              break;
+            }
+          case (byte)OpCodes.Mul: {
+              topOfStack--;
+              var a = stack[topOfStack + 1];
+              var b = stack[topOfStack];
+              stack[topOfStack] = Mul(a, b);
+
+              // same for gradient
+              // f(x) g(x)	f '(x) g(x) + f(x) g'(x)
+              for (int k = 0; k < nParams; ++k) {
+                var ag = gradientStack[k][topOfStack + 1];
+                var bg = gradientStack[k][topOfStack];
+                var t1 = Mul(ag, b);
+                var t2 = Mul(a, bg);
+                gradientStack[k][topOfStack] = Add(t1, t2);
+                ReleaseBuffer(ag);
+                ReleaseBuffer(bg);
+                ReleaseBuffer(t1);
+                ReleaseBuffer(t2);
+              }
+
+              ReleaseBuffer(a);
+              ReleaseBuffer(b);
+
+              break;
+            }
+          case (byte)OpCodes.Log: {
+              var x = stack[topOfStack];
+              // calc gradients first before destroying x
+              // log(f(x))' = f(x)'/f(x)
+              for (int k = 0; k < nParams; k++) {
+                var xg = gradientStack[k][topOfStack];
+                gradientStack[k][topOfStack] = Frac(xg, x);
+                ReleaseBuffer(xg);
+              }
+
+              for (int i = 0; i < x.Length; i++)
+                x[i] = Math.Log(x[i]);
+
+              break;
+            }
+          case (byte)OpCodes.Exp: {
+              var x = stack[topOfStack];
+              for (int i = 0; i < x.Length; i++)
+                x[i] = Math.Exp(x[i]);
+
+              for (int k = 0; k < nParams; k++) {
+                var xg = gradientStack[k][topOfStack];
+                gradientStack[k][topOfStack] = Mul(x, xg);  // e(f(x))' = e(f(x)) * f(x)'
+                ReleaseBuffer(xg);
+              }
+              break;
+            }
+          case (byte)OpCodes.Inv: {
+              var x = stack[topOfStack];
+              for (int i = 0; i < x.Length; i++)
+                x[i] = 1.0 / x[i];
+
+              for (int k = 0; k < nParams; k++) {
+                var xg = gradientStack[k][topOfStack];
+                // x has already been inverted above
+                // (1/f)' = -f' / f²
+                var invF = Mul(xg, x);
+                gradientStack[k][topOfStack] = Mul(invF, x, factor: -1.0);
+                ReleaseBuffer(xg);
+                ReleaseBuffer(invF);
+              }
+              break;
+            }
+          case (byte)OpCodes.Exit:
+            Contract.Assert(topOfStack == 0);
+            var r = stack[topOfStack];
+            if (r.Length == 1) {
+              var v = double.IsNaN(r[0]) ? nanReplacementValue : Math.Min(upperEstimationLimit, Math.Max(lowerEstimationLimit, r[0]));
+              for (int i = 0; i < vLen; i++)
+                pred[i] = v;
+            } else {
+              for (int i = 0; i < vLen; i++) {
+                var v = double.IsNaN(r[i]) ? nanReplacementValue : Math.Min(upperEstimationLimit, Math.Max(lowerEstimationLimit, r[i]));
+                pred[i] = v;
+              }
+            }
+            ReleaseBuffer(r);
+
+            // same for gradients
+            for (int k = 0; k < nParams; k++) {
+              var g = gradientStack[k][topOfStack];
+              if (g.Length == 1) {
+                for (int i = 0; i < vLen; i++)
+                  gradients[k][i] = g[0];
+              } else
+                Array.Copy(g, gradients[k], vLen);
+              ReleaseBuffer(g);
+            }
+
+            Contract.Assert(lastVecBufIdx == initialVectorCount);
+            Contract.Assert(lastScalarBufIdx == initialScalarCount);
+            return; // break loop
+        }
+      }
+    }
+
+    private double[] Add(double[] a, double[] b) {
+      double[] target = null;
+      if (a.Length > 1) {
+        target = GetVectorBuffer();
+        if (b.Length > 1) {
+          for (int i = 0; i < vLen; i++)
+            target[i] = a[i] + b[i];
+        } else {
+          // b == scalar
+          for (int i = 0; i < vLen; i++)
+            target[i] = a[i] + b[0];
+        }
+      } else {
+        // a == scalar
+        if (b.Length > 1) {
+          target = GetVectorBuffer();
+          for (int i = 0; i < vLen; i++)
+            target[i] = a[0] + b[i];
+        } else {
+          // b == scalar
+          target = GetScalarBuffer();
+          target[0] = a[0] + b[0];
+        }
+      }
+      return target;
+    }
+
+    private double[] Mul(double[] a, double[] b, double factor = 1.0) {
+      double[] target = null;
+      if (a.Length > 1) {
+        if (b.Length > 1) {
+          target = GetVectorBuffer();
+          for (int i = 0; i < vLen; i++)
+            target[i] = factor * a[i] * b[i];
+        } else {
+          // b == scalar
+          if (Math.Abs(b[0]) < 1E-12 /* == 0 */) {
+            target = GetScalarBuffer();
+            target[0] = 0.0;
+          } else {
+            target = GetVectorBuffer();
+            for (int i = 0; i < vLen; i++)
+              target[i] = factor * a[i] * b[0];
+          }
+        }
+      } else {
+        // a == scalar
+        if (b.Length > 1) {
+          if (Math.Abs(a[0]) < 1E-12 /* == 0 */) {
+            target = GetScalarBuffer();
+            target[0] = 0.0;
+          } else {
+            target = GetVectorBuffer();
+            for (int i = 0; i < vLen; i++)
+              target[i] = factor * a[0] * b[i];
+          }
+        } else {
+          // b == scalar
+          target = GetScalarBuffer();
+          target[0] = factor * a[0] * b[0];
+        }
+      }
+      return target;
+    }
+
+    private double[] Frac(double[] a, double[] b) {
+      double[] target = null;
+      if (a.Length > 1) {
+        target = GetVectorBuffer();
+        if (b.Length > 1) {
+          for (int i = 0; i < vLen; i++)
+            target[i] = a[i] / b[i];
+        } else {
+          // b == scalar
+          for (int i = 0; i < vLen; i++)
+            target[i] = a[i] / b[0];
+        }
+      } else {
+        // a == scalar
+        if (b.Length > 1) {
+          if (Math.Abs(a[0]) < 1E-12 /* == 0 */) {
+            target = GetScalarBuffer();
+            target[0] = 0.0;
+          } else {
+            target = GetVectorBuffer();
+            for (int i = 0; i < vLen; i++)
+              target[i] = a[0] / b[i];
+          }
+        } else {
+          // b == scalar
+          target = GetScalarBuffer();
+          target[0] = a[0] / b[0];
+        }
+      }
+      return target;
+    }
+
+    private void ReadNext(byte[] code, ref int pc, out byte op, out short s) {
+      op = code[pc++];
+      s = 0;
+      if (op == (byte)OpCodes.LoadVar) {
+        s = (short)(((short)code[pc] << 8) | (short)code[pc + 1]);
+        pc += 2;
+      }
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/MctsSymbolicRegression/MctsSymbolicRegressionAlgorithm.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/MctsSymbolicRegression/MctsSymbolicRegressionAlgorithm.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/MctsSymbolicRegression/MctsSymbolicRegressionAlgorithm.cs	(revision 13819)
@@ -0,0 +1,335 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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.Runtime.CompilerServices;
+using System.Threading;
+using HeuristicLab.Algorithms.DataAnalysis.MctsSymbolicRegression.Policies;
+using HeuristicLab.Analysis;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Optimization;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Problems.DataAnalysis;
+
+namespace HeuristicLab.Algorithms.DataAnalysis.MctsSymbolicRegression {
+  [Item("MCTS Symbolic Regression", "Monte carlo tree search for symbolic regression. Useful mainly as a base learner in gradient boosting.")]
+  [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; }
+    }
+
+    #region ParameterNames
+    private const string IterationsParameterName = "Iterations";
+    private const string MaxVariablesParameterName = "Maximum variables";
+    private const string ScaleVariablesParameterName = "Scale variables";
+    private const string AllowedFactorsParameterName = "Allowed factors";
+    private const string ConstantOptimizationIterationsParameterName = "Iterations (constant optimization)";
+    private const string PolicyParameterName = "Policy";
+    private const string SeedParameterName = "Seed";
+    private const string SetSeedRandomlyParameterName = "SetSeedRandomly";
+    private const string UpdateIntervalParameterName = "UpdateInterval";
+    private const string CreateSolutionParameterName = "CreateSolution";
+    private const string PunishmentFactorParameterName = "PunishmentFactor";
+
+    private const string VariableProductFactorName = "product(xi)";
+    private const string ExpFactorName = "exp(c * product(xi))";
+    private const string LogFactorName = "log(c + sum(c*product(xi))";
+    private const string InvFactorName = "1 / (1 + sum(c*product(xi))";
+    private const string FactorSumsName = "sum of multiple terms";
+    #endregion
+
+    #region ParameterProperties
+    public IFixedValueParameter<IntValue> IterationsParameter {
+      get { return (IFixedValueParameter<IntValue>)Parameters[IterationsParameterName]; }
+    }
+    public IFixedValueParameter<IntValue> MaxVariableReferencesParameter {
+      get { return (IFixedValueParameter<IntValue>)Parameters[MaxVariablesParameterName]; }
+    }
+    public IFixedValueParameter<BoolValue> ScaleVariablesParameter {
+      get { return (IFixedValueParameter<BoolValue>)Parameters[ScaleVariablesParameterName]; }
+    }
+    public IFixedValueParameter<IntValue> ConstantOptimizationIterationsParameter {
+      get { return (IFixedValueParameter<IntValue>)Parameters[ConstantOptimizationIterationsParameterName]; }
+    }
+    public IValueParameter<IPolicy> PolicyParameter {
+      get { return (IValueParameter<IPolicy>)Parameters[PolicyParameterName]; }
+    }
+    public IFixedValueParameter<DoubleValue> PunishmentFactorParameter {
+      get { return (IFixedValueParameter<DoubleValue>)Parameters[PunishmentFactorParameterName]; }
+    }
+    public IValueParameter<ICheckedItemList<StringValue>> AllowedFactorsParameter {
+      get { return (IValueParameter<ICheckedItemList<StringValue>>)Parameters[AllowedFactorsParameterName]; }
+    }
+    public IFixedValueParameter<IntValue> SeedParameter {
+      get { return (IFixedValueParameter<IntValue>)Parameters[SeedParameterName]; }
+    }
+    public FixedValueParameter<BoolValue> SetSeedRandomlyParameter {
+      get { return (FixedValueParameter<BoolValue>)Parameters[SetSeedRandomlyParameterName]; }
+    }
+    public IFixedValueParameter<IntValue> UpdateIntervalParameter {
+      get { return (IFixedValueParameter<IntValue>)Parameters[UpdateIntervalParameterName]; }
+    }
+    public IFixedValueParameter<BoolValue> CreateSolutionParameter {
+      get { return (IFixedValueParameter<BoolValue>)Parameters[CreateSolutionParameterName]; }
+    }
+    #endregion
+
+    #region Properties
+    public int Iterations {
+      get { return IterationsParameter.Value.Value; }
+      set { IterationsParameter.Value.Value = value; }
+    }
+    public int Seed {
+      get { return SeedParameter.Value.Value; }
+      set { SeedParameter.Value.Value = value; }
+    }
+    public bool SetSeedRandomly {
+      get { return SetSeedRandomlyParameter.Value.Value; }
+      set { SetSeedRandomlyParameter.Value.Value = value; }
+    }
+    public int MaxVariableReferences {
+      get { return MaxVariableReferencesParameter.Value.Value; }
+      set { MaxVariableReferencesParameter.Value.Value = value; }
+    }
+    public IPolicy Policy {
+      get { return PolicyParameter.Value; }
+      set { PolicyParameter.Value = value; }
+    }
+    public double PunishmentFactor {
+      get { return PunishmentFactorParameter.Value.Value; }
+      set { PunishmentFactorParameter.Value.Value = value; }
+    }
+    public ICheckedItemList<StringValue> AllowedFactors {
+      get { return AllowedFactorsParameter.Value; }
+    }
+    public int ConstantOptimizationIterations {
+      get { return ConstantOptimizationIterationsParameter.Value.Value; }
+      set { ConstantOptimizationIterationsParameter.Value.Value = value; }
+    }
+    public bool ScaleVariables {
+      get { return ScaleVariablesParameter.Value.Value; }
+      set { ScaleVariablesParameter.Value.Value = value; }
+    }
+    public bool CreateSolution {
+      get { return CreateSolutionParameter.Value.Value; }
+      set { CreateSolutionParameter.Value.Value = value; }
+    }
+    #endregion
+
+    [StorableConstructor]
+    protected MctsSymbolicRegressionAlgorithm(bool deserializing) : base(deserializing) { }
+
+    protected MctsSymbolicRegressionAlgorithm(MctsSymbolicRegressionAlgorithm original, Cloner cloner)
+      : base(original, cloner) {
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new MctsSymbolicRegressionAlgorithm(this, cloner);
+    }
+
+    public MctsSymbolicRegressionAlgorithm() {
+      Problem = new RegressionProblem(); // default problem
+
+      var defaultFactorsList = new CheckedItemList<StringValue>(
+        new string[] { VariableProductFactorName, ExpFactorName, LogFactorName, InvFactorName, FactorSumsName }
+        .Select(s => new StringValue(s).AsReadOnly())
+        ).AsReadOnly();
+      defaultFactorsList.SetItemCheckedState(defaultFactorsList.First(s => s.Value == FactorSumsName), false);
+
+      Parameters.Add(new FixedValueParameter<IntValue>(IterationsParameterName,
+        "Number of iterations", new IntValue(100000)));
+      Parameters.Add(new FixedValueParameter<IntValue>(SeedParameterName,
+        "The random seed used to initialize the new pseudo random number generator.", new IntValue(0)));
+      Parameters.Add(new FixedValueParameter<BoolValue>(SetSeedRandomlyParameterName,
+        "True if the random seed should be set to a random value, otherwise false.", new BoolValue(true)));
+      Parameters.Add(new FixedValueParameter<IntValue>(MaxVariablesParameterName,
+        "Maximal number of variables references in the symbolic regression models (multiple usages of the same variable are counted)", new IntValue(5)));
+      // Parameters.Add(new FixedValueParameter<DoubleValue>(CParameterName,
+      //   "Balancing parameter in UCT formula (0 < c < 1000). Small values: greedy search. Large values: enumeration. Default: 1.0", new DoubleValue(1.0)));
+      Parameters.Add(new ValueParameter<IPolicy>(PolicyParameterName,
+        "The policy to use for selecting nodes in MCTS (e.g. Ucb)", new Ucb()));
+      PolicyParameter.Hidden = true;
+      Parameters.Add(new ValueParameter<ICheckedItemList<StringValue>>(AllowedFactorsParameterName,
+        "Choose which expressions are allowed as factors in the model.", defaultFactorsList));
+
+      Parameters.Add(new FixedValueParameter<IntValue>(ConstantOptimizationIterationsParameterName,
+        "Number of iterations for constant optimization. A small number of iterations should be sufficient for most models. " +
+        "Set to 0 to disable constants optimization.", new IntValue(10)));
+      Parameters.Add(new FixedValueParameter<BoolValue>(ScaleVariablesParameterName,
+        "Set to true to scale all input variables to the range [0..1]", new BoolValue(false)));
+      Parameters[ScaleVariablesParameterName].Hidden = true;
+      Parameters.Add(new FixedValueParameter<DoubleValue>(PunishmentFactorParameterName, "Estimations of models can be bounded. The estimation limits are calculated in the following way (lb = mean(y) - punishmentFactor*range(y), ub = mean(y) + punishmentFactor*range(y))", new DoubleValue(10)));
+      Parameters[PunishmentFactorParameterName].Hidden = true;
+      Parameters.Add(new FixedValueParameter<IntValue>(UpdateIntervalParameterName,
+        "Number of iterations until the results are updated", new IntValue(100)));
+      Parameters[UpdateIntervalParameterName].Hidden = true;
+      Parameters.Add(new FixedValueParameter<BoolValue>(CreateSolutionParameterName,
+        "Flag that indicates if a solution should be produced at the end of the run", new BoolValue(true)));
+      Parameters[CreateSolutionParameterName].Hidden = true;
+    }
+
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() {
+    }
+
+    protected override void Run(CancellationToken cancellationToken) {
+      // Set up the algorithm
+      if (SetSeedRandomly) Seed = new System.Random().Next();
+
+      // Set up the results display
+      var iterations = new IntValue(0);
+      Results.Add(new Result("Iterations", iterations));
+
+      var bestSolutionIteration = new IntValue(0);
+      Results.Add(new Result("Best solution iteration", bestSolutionIteration));
+
+      var table = new DataTable("Qualities");
+      table.Rows.Add(new DataRow("Best quality"));
+      table.Rows.Add(new DataRow("Current best quality"));
+      table.Rows.Add(new DataRow("Average quality"));
+      Results.Add(new Result("Qualities", table));
+
+      var bestQuality = new DoubleValue();
+      Results.Add(new Result("Best quality", bestQuality));
+
+      var curQuality = new DoubleValue();
+      Results.Add(new Result("Current best quality", curQuality));
+
+      var avgQuality = new DoubleValue();
+      Results.Add(new Result("Average quality", avgQuality));
+
+      var totalRollouts = new IntValue();
+      Results.Add(new Result("Total rollouts", totalRollouts));
+      var effRollouts = new IntValue();
+      Results.Add(new Result("Effective rollouts", effRollouts));
+      var funcEvals = new IntValue();
+      Results.Add(new Result("Function evaluations", funcEvals));
+      var gradEvals = new IntValue();
+      Results.Add(new Result("Gradient evaluations", gradEvals));
+
+
+      // same as in SymbolicRegressionSingleObjectiveProblem
+      var y = Problem.ProblemData.Dataset.GetDoubleValues(Problem.ProblemData.TargetVariable,
+        Problem.ProblemData.TrainingIndices);
+      var avgY = y.Average();
+      var minY = y.Min();
+      var maxY = y.Max();
+      var range = maxY - minY;
+      var lowerLimit = avgY - PunishmentFactor * range;
+      var upperLimit = avgY + PunishmentFactor * range;
+
+      // init
+      var problemData = (IRegressionProblemData)Problem.ProblemData.Clone();
+      if (!AllowedFactors.CheckedItems.Any()) throw new ArgumentException("At least on type of factor must be allowed");
+      var state = MctsSymbolicRegressionStatic.CreateState(problemData, (uint)Seed, MaxVariableReferences, ScaleVariables, ConstantOptimizationIterations,
+        Policy,
+        lowerLimit, upperLimit,
+        allowProdOfVars: AllowedFactors.CheckedItems.Any(s => s.Value.Value == VariableProductFactorName),
+        allowExp: AllowedFactors.CheckedItems.Any(s => s.Value.Value == ExpFactorName),
+        allowLog: AllowedFactors.CheckedItems.Any(s => s.Value.Value == LogFactorName),
+        allowInv: AllowedFactors.CheckedItems.Any(s => s.Value.Value == InvFactorName),
+        allowMultipleTerms: AllowedFactors.CheckedItems.Any(s => s.Value.Value == FactorSumsName)
+        );
+
+      var updateInterval = UpdateIntervalParameter.Value.Value;
+      double sumQ = 0.0;
+      double bestQ = 0.0;
+      double curBestQ = 0.0;
+      int n = 0;
+      // Loop until iteration limit reached or canceled.
+      for (int i = 0; i < Iterations && !state.Done; i++) {
+        cancellationToken.ThrowIfCancellationRequested();
+
+        var q = MctsSymbolicRegressionStatic.MakeStep(state);
+        sumQ += q; // sum of qs in the last updateinterval iterations
+        curBestQ = Math.Max(q, curBestQ); // the best q in the last updateinterval iterations
+        bestQ = Math.Max(q, bestQ); // the best q overall
+        n++;
+        // iteration results
+        if (n == updateInterval) {
+          if (bestQ > bestQuality.Value) {
+            bestSolutionIteration.Value = i;
+          }
+          bestQuality.Value = bestQ;
+          curQuality.Value = curBestQ;
+          avgQuality.Value = sumQ / n;
+          sumQ = 0.0;
+          curBestQ = 0.0;
+
+          funcEvals.Value = state.FuncEvaluations;
+          gradEvals.Value = state.GradEvaluations;
+          effRollouts.Value = state.EffectiveRollouts;
+          totalRollouts.Value = state.TotalRollouts;
+
+          table.Rows["Best quality"].Values.Add(bestQuality.Value);
+          table.Rows["Current best quality"].Values.Add(curQuality.Value);
+          table.Rows["Average quality"].Values.Add(avgQuality.Value);
+          iterations.Value += n;
+          n = 0;
+        }
+      }
+
+      // final results
+      if (n > 0) {
+        if (bestQ > bestQuality.Value) {
+          bestSolutionIteration.Value = iterations.Value + n;
+        }
+        bestQuality.Value = bestQ;
+        curQuality.Value = curBestQ;
+        avgQuality.Value = sumQ / n;
+
+        funcEvals.Value = state.FuncEvaluations;
+        gradEvals.Value = state.GradEvaluations;
+        effRollouts.Value = state.EffectiveRollouts;
+        totalRollouts.Value = state.TotalRollouts;
+
+        table.Rows["Best quality"].Values.Add(bestQuality.Value);
+        table.Rows["Current best quality"].Values.Add(curQuality.Value);
+        table.Rows["Average quality"].Values.Add(avgQuality.Value);
+        iterations.Value = iterations.Value + n;
+
+      }
+
+
+      Results.Add(new Result("Best solution quality (train)", new DoubleValue(state.BestSolutionTrainingQuality)));
+      Results.Add(new Result("Best solution quality (test)", new DoubleValue(state.BestSolutionTestQuality)));
+
+
+      // produce solution 
+      if (CreateSolution) {
+        var model = state.BestModel;
+
+        // otherwise we produce a regression solution
+        Results.Add(new Result("Solution", model.CreateRegressionSolution(problemData)));
+      }
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/MctsSymbolicRegression/MctsSymbolicRegressionStatic.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/MctsSymbolicRegression/MctsSymbolicRegressionStatic.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/MctsSymbolicRegression/MctsSymbolicRegressionStatic.cs	(revision 13819)
@@ -0,0 +1,474 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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.Diagnostics.Contracts;
+using System.Linq;
+using HeuristicLab.Algorithms.DataAnalysis.MctsSymbolicRegression.Policies;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
+using HeuristicLab.Problems.DataAnalysis;
+using HeuristicLab.Problems.DataAnalysis.Symbolic;
+using HeuristicLab.Problems.DataAnalysis.Symbolic.Regression;
+using HeuristicLab.Random;
+
+namespace HeuristicLab.Algorithms.DataAnalysis.MctsSymbolicRegression {
+  public static class MctsSymbolicRegressionStatic {
+    // TODO: SGD with adagrad instead of lbfgs?
+    // TODO: check Taylor expansion capabilities (ln(x), sqrt(x), exp(x)) in combination with GBT
+    // TODO: optimize for 3 targets concurrently (y, 1/y, exp(y), and log(y))? Would simplify the number of possible expressions again
+    #region static API
+
+    public interface IState {
+      bool Done { get; }
+      ISymbolicRegressionModel BestModel { get; }
+      double BestSolutionTrainingQuality { get; }
+      double BestSolutionTestQuality { get; }
+      int TotalRollouts { get; }
+      int EffectiveRollouts { get; }
+      int FuncEvaluations { get; }
+      int GradEvaluations { get; } // number of gradient evaluations (* num parameters) to get a value representative of the effort comparable to the number of function evaluations
+      // TODO other stats on LM optimizer might be interesting here
+    }
+
+    // created through factory method
+    private class State : IState {
+      private const int MaxParams = 100;
+
+      // state variables used by MCTS
+      internal readonly Automaton automaton;
+      internal IRandom random { get; private set; }
+      internal readonly Tree tree;
+      internal readonly Func<byte[], int, double> evalFun;
+      internal readonly IPolicy treePolicy;
+      // MCTS might get stuck. Track statistics on the number of effective rollouts
+      internal int totalRollouts;
+      internal int effectiveRollouts;
+
+
+      // state variables used only internally (for eval function)
+      private readonly IRegressionProblemData problemData;
+      private readonly double[][] x;
+      private readonly double[] y;
+      private readonly double[][] testX;
+      private readonly double[] testY;
+      private readonly double[] scalingFactor;
+      private readonly double[] scalingOffset;
+      private readonly int constOptIterations;
+      private readonly double lowerEstimationLimit, upperEstimationLimit;
+
+      private readonly ExpressionEvaluator evaluator, testEvaluator;
+
+      // values for best solution
+      private double bestRSq;
+      private byte[] bestCode;
+      private int bestNParams;
+      private double[] bestConsts;
+
+      // stats
+      private int funcEvaluations;
+      private int gradEvaluations;
+
+      // buffers
+      private readonly double[] ones; // vector of ones (as default params)
+      private readonly double[] constsBuf;
+      private readonly double[] predBuf, testPredBuf;
+      private readonly double[][] gradBuf;
+
+      public State(IRegressionProblemData problemData, uint randSeed, int maxVariables, bool scaleVariables, int constOptIterations,
+        IPolicy treePolicy = null,
+        double lowerEstimationLimit = double.MinValue, double upperEstimationLimit = double.MaxValue,
+        bool allowProdOfVars = true,
+        bool allowExp = true,
+        bool allowLog = true,
+        bool allowInv = true,
+        bool allowMultipleTerms = false) {
+
+        this.problemData = problemData;
+        this.constOptIterations = constOptIterations;
+        this.evalFun = this.Eval;
+        this.lowerEstimationLimit = lowerEstimationLimit;
+        this.upperEstimationLimit = upperEstimationLimit;
+
+        random = new MersenneTwister(randSeed);
+
+        // prepare data for evaluation
+        double[][] x;
+        double[] y;
+        double[][] testX;
+        double[] testY;
+        double[] scalingFactor;
+        double[] scalingOffset;
+        // get training and test datasets (scale linearly based on training set if required)
+        GenerateData(problemData, scaleVariables, problemData.TrainingIndices, out x, out y, out scalingFactor, out scalingOffset);
+        GenerateData(problemData, problemData.TestIndices, scalingFactor, scalingOffset, out testX, out testY);
+        this.x = x;
+        this.y = y;
+        this.testX = testX;
+        this.testY = testY;
+        this.scalingFactor = scalingFactor;
+        this.scalingOffset = scalingOffset;
+        this.evaluator = new ExpressionEvaluator(y.Length, lowerEstimationLimit, upperEstimationLimit);
+        // we need a separate evaluator because the vector length for the test dataset might differ 
+        this.testEvaluator = new ExpressionEvaluator(testY.Length, lowerEstimationLimit, upperEstimationLimit);
+
+        this.automaton = new Automaton(x, maxVariables, allowProdOfVars, allowExp, allowLog, allowInv, allowMultipleTerms);
+        this.treePolicy = treePolicy ?? new Ucb();
+        this.tree = new Tree() { state = automaton.CurrentState, actionStatistics = treePolicy.CreateActionStatistics() };
+
+        // reset best solution
+        this.bestRSq = 0;
+        // code for default solution (constant model)
+        this.bestCode = new byte[] { (byte)OpCodes.LoadConst0, (byte)OpCodes.Exit };
+        this.bestNParams = 0;
+        this.bestConsts = null;
+
+        // init buffers
+        this.ones = Enumerable.Repeat(1.0, MaxParams).ToArray();
+        constsBuf = new double[MaxParams];
+        this.predBuf = new double[y.Length];
+        this.testPredBuf = new double[testY.Length];
+
+        this.gradBuf = Enumerable.Range(0, MaxParams).Select(_ => new double[y.Length]).ToArray();
+      }
+
+      #region IState inferface
+      public bool Done { get { return tree != null && tree.Done; } }
+
+      public double BestSolutionTrainingQuality {
+        get {
+          evaluator.Exec(bestCode, x, bestConsts, predBuf);
+          return RSq(y, predBuf);
+        }
+      }
+
+      public double BestSolutionTestQuality {
+        get {
+          testEvaluator.Exec(bestCode, testX, bestConsts, testPredBuf);
+          return RSq(testY, testPredBuf);
+        }
+      }
+
+      // takes the code of the best solution and creates and equivalent symbolic regression model
+      public ISymbolicRegressionModel BestModel {
+        get {
+          var treeGen = new SymbolicExpressionTreeGenerator(problemData.AllowedInputVariables.ToArray());
+          var interpreter = new SymbolicDataAnalysisExpressionTreeLinearInterpreter();
+
+          var t = new SymbolicExpressionTree(treeGen.Exec(bestCode, bestConsts, bestNParams, scalingFactor, scalingOffset));
+          var model = new SymbolicRegressionModel(t, interpreter, lowerEstimationLimit, upperEstimationLimit);
+
+          // model has already been scaled linearly in Eval
+          return model;
+        }
+      }
+
+      public int TotalRollouts { get { return totalRollouts; } }
+      public int EffectiveRollouts { get { return effectiveRollouts; } }
+      public int FuncEvaluations { get { return funcEvaluations; } }
+      public int GradEvaluations { get { return gradEvaluations; } } // number of gradient evaluations (* num parameters) to get a value representative of the effort comparable to the number of function evaluations
+
+      #endregion
+
+      private double Eval(byte[] code, int nParams) {
+        double[] optConsts;
+        double q;
+        Eval(code, nParams, out q, out optConsts);
+
+        if (q > bestRSq) {
+          bestRSq = q;
+          bestNParams = nParams;
+          this.bestCode = new byte[code.Length];
+          this.bestConsts = new double[bestNParams];
+
+          Array.Copy(code, bestCode, code.Length);
+          Array.Copy(optConsts, bestConsts, bestNParams);
+        }
+
+        return q;
+      }
+
+      private void Eval(byte[] code, int nParams, out double rsq, out double[] optConsts) {
+        // we make a first pass to determine a valid starting configuration for all constants
+        // constant c in log(c + f(x)) is adjusted to guarantee that x is positive (see expression evaluator)
+        // scale and offset are set to optimal starting configuration
+        // assumes scale is the first param and offset is the last param
+        double alpha;
+        double beta;
+
+        // reset constants
+        Array.Copy(ones, constsBuf, nParams);
+        evaluator.Exec(code, x, constsBuf, predBuf, adjustOffsetForLogAndExp: true);
+        funcEvaluations++;
+
+        // calc opt scaling (alpha*f(x) + beta)
+        OnlineCalculatorError error;
+        OnlineLinearScalingParameterCalculator.Calculate(predBuf, y, out alpha, out beta, out error);
+        if (error == OnlineCalculatorError.None) {
+          constsBuf[0] *= beta;
+          constsBuf[nParams - 1] = constsBuf[nParams - 1] * beta + alpha;
+        }
+        if (nParams <= 2 || constOptIterations <= 0) {
+          // if we don't need to optimize parameters then we are done
+          // changing scale and offset does not influence r²
+          rsq = RSq(y, predBuf);
+          optConsts = constsBuf;
+        } else {
+          // optimize constants using the starting point calculated above
+          OptimizeConstsLm(code, constsBuf, nParams, 0.0, nIters: constOptIterations);
+
+          evaluator.Exec(code, x, constsBuf, predBuf);
+          funcEvaluations++;
+
+          rsq = RSq(y, predBuf);
+          optConsts = constsBuf;
+        }
+      }
+
+
+
+      #region helpers
+      private static double RSq(IEnumerable<double> x, IEnumerable<double> y) {
+        OnlineCalculatorError error;
+        double r = OnlinePearsonsRCalculator.Calculate(x, y, out error);
+        return error == OnlineCalculatorError.None ? r * r : 0.0;
+      }
+
+
+      private void OptimizeConstsLm(byte[] code, double[] consts, int nParams, double epsF = 0.0, int nIters = 100) {
+        double[] optConsts = new double[nParams]; // allocate a smaller buffer for constants opt (TODO perf?)
+        Array.Copy(consts, optConsts, nParams);
+
+        alglib.minlmstate state;
+        alglib.minlmreport rep = null;
+        alglib.minlmcreatevj(y.Length, optConsts, out state);
+        alglib.minlmsetcond(state, 0.0, epsF, 0.0, nIters);
+        //alglib.minlmsetgradientcheck(state, 0.000001);
+        alglib.minlmoptimize(state, Func, FuncAndJacobian, null, code);
+        alglib.minlmresults(state, out optConsts, out rep);
+        funcEvaluations += rep.nfunc;
+        gradEvaluations += rep.njac * nParams;
+
+        if (rep.terminationtype < 0) throw new ArgumentException("lm failed: termination type = " + rep.terminationtype);
+
+        // only use optimized constants if successful
+        if (rep.terminationtype >= 0) {
+          Array.Copy(optConsts, consts, optConsts.Length);
+        }
+      }
+
+      private void Func(double[] arg, double[] fi, object obj) {
+        var code = (byte[])obj;
+        evaluator.Exec(code, x, arg, predBuf); // gradients are nParams x vLen
+        for (int r = 0; r < predBuf.Length; r++) {
+          var res = predBuf[r] - y[r];
+          fi[r] = res;
+        }
+      }
+      private void FuncAndJacobian(double[] arg, double[] fi, double[,] jac, object obj) {
+        int nParams = arg.Length;
+        var code = (byte[])obj;
+        evaluator.ExecGradient(code, x, arg, predBuf, gradBuf); // gradients are nParams x vLen
+        for (int r = 0; r < predBuf.Length; r++) {
+          var res = predBuf[r] - y[r];
+          fi[r] = res;
+
+          for (int k = 0; k < nParams; k++) {
+            jac[r, k] = gradBuf[k][r];
+          }
+        }
+      }
+      #endregion
+    }
+
+    public static IState CreateState(IRegressionProblemData problemData, uint randSeed, int maxVariables = 3,
+      bool scaleVariables = true, int constOptIterations = 0,
+      IPolicy policy = null,
+      double lowerEstimationLimit = double.MinValue, double upperEstimationLimit = double.MaxValue,
+      bool allowProdOfVars = true,
+      bool allowExp = true,
+      bool allowLog = true,
+      bool allowInv = true,
+      bool allowMultipleTerms = false
+      ) {
+      return new State(problemData, randSeed, maxVariables, scaleVariables, constOptIterations,
+        policy,
+        lowerEstimationLimit, upperEstimationLimit,
+        allowProdOfVars, allowExp, allowLog, allowInv, allowMultipleTerms);
+    }
+
+    // returns the quality of the evaluated solution
+    public static double MakeStep(IState state) {
+      var mctsState = state as State;
+      if (mctsState == null) throw new ArgumentException("state");
+      if (mctsState.Done) throw new NotSupportedException("The tree search has enumerated all possible solutions.");
+
+      return TreeSearch(mctsState);
+    }
+    #endregion
+
+    private static double TreeSearch(State mctsState) {
+      var automaton = mctsState.automaton;
+      var tree = mctsState.tree;
+      var eval = mctsState.evalFun;
+      var rand = mctsState.random;
+      var treePolicy = mctsState.treePolicy;
+      double q = 0;
+      bool success = false;
+      do {
+        automaton.Reset();
+        success = TryTreeSearchRec(rand, tree, automaton, eval, treePolicy, out q);
+        mctsState.totalRollouts++;
+      } while (!success && !tree.Done);
+      mctsState.effectiveRollouts++;
+      return q;
+    }
+
+    // tree search might fail because of constraints for expressions
+    // in this case we get stuck we just restart
+    // see ConstraintHandler.cs for more info
+    private static bool TryTreeSearchRec(IRandom rand, Tree tree, Automaton automaton, Func<byte[], int, double> eval, IPolicy treePolicy,
+      out double q) {
+      Tree selectedChild = null;
+      Contract.Assert(tree.state == automaton.CurrentState);
+      Contract.Assert(!tree.Done);
+      if (tree.children == null) {
+        if (automaton.IsFinalState(tree.state)) {
+          // final state
+          tree.Done = true;
+
+          // EVALUATE
+          byte[] code; int nParams;
+          automaton.GetCode(out code, out nParams);
+          q = eval(code, nParams);
+
+          treePolicy.Update(tree.actionStatistics, q);
+          return true; // we reached a final state
+        } else {
+          // EXPAND 
+          int[] possibleFollowStates;
+          int nFs;
+          automaton.FollowStates(automaton.CurrentState, out possibleFollowStates, out nFs);
+          if (nFs == 0) {
+            // stuck in a dead end (no final state and no allowed follow states)
+            q = 0;
+            tree.Done = true;
+            tree.children = null;
+            return false;
+          }
+          tree.children = new Tree[nFs];
+          for (int i = 0; i < tree.children.Length; i++)
+            tree.children[i] = new Tree() { children = null, state = possibleFollowStates[i], actionStatistics = treePolicy.CreateActionStatistics() };
+
+          selectedChild = nFs > 1 ? SelectFinalOrRandom(automaton, tree, rand) : tree.children[0];
+        }
+      } else {
+        // tree.children != null
+        // UCT selection within tree
+        int selectedIdx = 0;
+        if (tree.children.Length > 1) {
+          selectedIdx = treePolicy.Select(tree.children.Select(ch => ch.actionStatistics), rand);
+        }
+        selectedChild = tree.children[selectedIdx];
+      }
+      // make selected step and recurse
+      automaton.Goto(selectedChild.state);
+      var success = TryTreeSearchRec(rand, selectedChild, automaton, eval, treePolicy, out q);
+      if (success) {
+        // only update if successful
+        treePolicy.Update(tree.actionStatistics, q);
+      }
+
+      tree.Done = tree.children.All(ch => ch.Done);
+      if (tree.Done) {
+        tree.children = null; // cut off the sub-branch if it has been fully explored
+      }
+      return success;
+    }
+
+    private static Tree SelectFinalOrRandom(Automaton automaton, Tree tree, IRandom rand) {
+      // if one of the new children leads to a final state then go there
+      // otherwise choose a random child
+      int selectedChildIdx = -1;
+      // find first final state if there is one
+      for (int i = 0; i < tree.children.Length; i++) {
+        if (automaton.IsFinalState(tree.children[i].state)) {
+          selectedChildIdx = i;
+          break;
+        }
+      }
+      // no final state -> select a the first child
+      if (selectedChildIdx == -1) {
+        selectedChildIdx = 0;
+      }
+      return tree.children[selectedChildIdx];
+    }
+
+    // scales data and extracts values from dataset into arrays
+    private static void GenerateData(IRegressionProblemData problemData, bool scaleVariables, IEnumerable<int> rows,
+      out double[][] xs, out double[] y, out double[] scalingFactor, out double[] scalingOffset) {
+      xs = new double[problemData.AllowedInputVariables.Count()][];
+
+      var i = 0;
+      if (scaleVariables) {
+        scalingFactor = new double[xs.Length];
+        scalingOffset = new double[xs.Length];
+      } else {
+        scalingFactor = null;
+        scalingOffset = null;
+      }
+      foreach (var var in problemData.AllowedInputVariables) {
+        if (scaleVariables) {
+          var minX = problemData.Dataset.GetDoubleValues(var, rows).Min();
+          var maxX = problemData.Dataset.GetDoubleValues(var, rows).Max();
+          var range = maxX - minX;
+
+          // scaledX = (x - min) / range
+          var sf = 1.0 / range;
+          var offset = -minX / range;
+          scalingFactor[i] = sf;
+          scalingOffset[i] = offset;
+          i++;
+        }
+      }
+
+      GenerateData(problemData, rows, scalingFactor, scalingOffset, out xs, out y);
+    }
+
+    // extract values from dataset into arrays
+    private static void GenerateData(IRegressionProblemData problemData, IEnumerable<int> rows, double[] scalingFactor, double[] scalingOffset,
+     out double[][] xs, out double[] y) {
+      xs = new double[problemData.AllowedInputVariables.Count()][];
+
+      int i = 0;
+      foreach (var var in problemData.AllowedInputVariables) {
+        var sf = scalingFactor == null ? 1.0 : scalingFactor[i];
+        var offset = scalingFactor == null ? 0.0 : scalingOffset[i];
+        xs[i++] =
+          problemData.Dataset.GetDoubleValues(var, rows).Select(xi => xi * sf + offset).ToArray();
+      }
+
+      y = problemData.Dataset.GetDoubleValues(problemData.TargetVariable, rows).ToArray();
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/MctsSymbolicRegression/OpCodes.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/MctsSymbolicRegression/OpCodes.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/MctsSymbolicRegression/OpCodes.cs	(revision 13819)
@@ -0,0 +1,36 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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.Algorithms.DataAnalysis.MctsSymbolicRegression {
+  internal enum OpCodes : byte {
+    Nop,
+    LoadConst0,
+    LoadConst1, // load the constant 1
+    LoadParamN, // load next parameter 
+    LoadVar,    // + 2 byte parameters
+    Mul,
+    Add,
+    Log,
+    Exp,
+    Inv,
+    Exit
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/MctsSymbolicRegression/Policies/EpsGreedy.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/MctsSymbolicRegression/Policies/EpsGreedy.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/MctsSymbolicRegression/Policies/EpsGreedy.cs	(revision 13819)
@@ -0,0 +1,93 @@
+﻿using System;
+using System.Collections.Generic;
+using System.Diagnostics.Contracts;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Algorithms.DataAnalysis.MctsSymbolicRegression.Policies {
+  [StorableClass]
+  [Item("EpsilonGreedy", "Epsilon greedy policy with parameter eps to balance between exploitation and exploration")]
+  public class EpsilonGreedy : PolicyBase {
+    private class ActionStatistics : IActionStatistics {
+      public double SumQuality { get; set; }
+      public double AverageQuality { get { return SumQuality / Tries; } }
+      public int Tries { get; set; }
+      public bool Done { get; set; }
+    }
+    private List<int> buf = new List<int>();
+
+    public IFixedValueParameter<DoubleValue> EpsParameter {
+      get { return (IFixedValueParameter<DoubleValue>)Parameters["Eps"]; }
+    }
+
+    public double Eps {
+      get { return EpsParameter.Value.Value; }
+      set { EpsParameter.Value.Value = value; }
+    }
+
+    [StorableConstructor]
+    protected EpsilonGreedy(bool deserializing) : base(deserializing) { }
+    protected EpsilonGreedy(EpsilonGreedy original, Cloner cloner)
+      : base(original, cloner) {
+    }
+    public EpsilonGreedy()
+      : base() {
+      Parameters.Add(new FixedValueParameter<DoubleValue>("Eps", "Rate of random selection 0 (greedy) <= eps <= 1 (random)", new DoubleValue(0.1)));
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new EpsilonGreedy(this, cloner);
+    }
+
+    public override int Select(IEnumerable<IActionStatistics> actions, IRandom random) {
+      return Select(actions, random, Eps, buf);
+    }
+
+    public override void Update(IActionStatistics action, double q) {
+      var a = action as ActionStatistics;
+      a.SumQuality += q;
+      a.Tries++;
+    }
+
+    public override IActionStatistics CreateActionStatistics() {
+      return new ActionStatistics();
+    }
+
+    private static int Select(IEnumerable<IActionStatistics> actions, IRandom rand, double c, IList<int> buf) {
+      buf.Clear();
+      if (rand.NextDouble() >= c) {
+        // select best
+        var bestQ = double.NegativeInfinity;
+        int aIdx = -1;
+        foreach (var a in actions) {
+          ++aIdx;
+          if (a.Done) continue;
+          var actionQ = a.Tries > 0 ? a.AverageQuality : double.PositiveInfinity; // always try unvisited actions first
+          if (actionQ > bestQ) {
+            buf.Clear();
+            buf.Add(aIdx);
+            bestQ = actionQ;
+          } else if (actionQ >= bestQ) {
+            buf.Add(aIdx);
+          }
+        }
+        return buf[rand.Next(buf.Count)];
+      } else {
+        // random selection
+        int aIdx = -1;
+        foreach (var a in actions) {
+          ++aIdx;
+          if (a.Done) continue;
+          buf.Add(aIdx);
+        }
+        return buf[rand.Next(buf.Count)];
+      }
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/MctsSymbolicRegression/Policies/IActionStatistics.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/MctsSymbolicRegression/Policies/IActionStatistics.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/MctsSymbolicRegression/Policies/IActionStatistics.cs	(revision 13819)
@@ -0,0 +1,13 @@
+﻿using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace HeuristicLab.Algorithms.DataAnalysis.MctsSymbolicRegression.Policies {
+  public interface IActionStatistics {
+    double AverageQuality { get; }
+    int Tries { get; }
+    bool Done { get; set; }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/MctsSymbolicRegression/Policies/IPolicy.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/MctsSymbolicRegression/Policies/IPolicy.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/MctsSymbolicRegression/Policies/IPolicy.cs	(revision 13819)
@@ -0,0 +1,14 @@
+﻿using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using HeuristicLab.Core;
+
+namespace HeuristicLab.Algorithms.DataAnalysis.MctsSymbolicRegression.Policies {
+  public interface IPolicy : IItem {
+    int Select(IEnumerable<IActionStatistics> actions, IRandom random);
+    void Update(IActionStatistics action, double q);
+    IActionStatistics CreateActionStatistics();
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/MctsSymbolicRegression/Policies/PolicyBase.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/MctsSymbolicRegression/Policies/PolicyBase.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/MctsSymbolicRegression/Policies/PolicyBase.cs	(revision 13819)
@@ -0,0 +1,36 @@
+﻿using System;
+using System.Collections.Generic;
+using System.Diagnostics.Contracts;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Algorithms.DataAnalysis.MctsSymbolicRegression.Policies {
+  [StorableClass]
+  public abstract class PolicyBase : Item, IParameterizedItem, IPolicy {
+    [Storable]
+    public IKeyedItemCollection<string, IParameter> Parameters { get; private set; }
+
+    [StorableConstructor]
+    protected PolicyBase(bool deserializing) : base(deserializing) { }
+    protected PolicyBase(PolicyBase original, Cloner cloner)
+      : base(original, cloner) {
+      Parameters = cloner.Clone(original.Parameters);
+    }
+    protected PolicyBase()
+      : base() {
+      Parameters = new ParameterCollection();
+    }
+
+    public void CollectParameterValues(IDictionary<string, IItem> values) {
+      foreach (var p in Parameters) values.Add(this.ItemName + "." + p.Name, p.ActualValue);
+    }
+
+    public abstract int Select(IEnumerable<IActionStatistics> actions, IRandom random);
+    public abstract void Update(IActionStatistics action, double q);
+    public abstract IActionStatistics CreateActionStatistics();
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/MctsSymbolicRegression/Policies/Ucb.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/MctsSymbolicRegression/Policies/Ucb.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/MctsSymbolicRegression/Policies/Ucb.cs	(revision 13819)
@@ -0,0 +1,97 @@
+﻿using System;
+using System.Collections.Generic;
+using System.Diagnostics.Contracts;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Algorithms.DataAnalysis.MctsSymbolicRegression.Policies {
+  [StorableClass]
+  [Item("Ucb Policy", "Ucb with parameter c to balance between exploitation and exploration")]
+  public class Ucb : PolicyBase {
+    private class ActionStatistics : IActionStatistics {
+      public double SumQuality { get; set; }
+      public double AverageQuality { get { return SumQuality / Tries; } }
+      public int Tries { get; set; }
+      public bool Done { get; set; }
+    }
+    private List<int> buf = new List<int>();
+
+    public IFixedValueParameter<DoubleValue> CParameter {
+      get { return (IFixedValueParameter<DoubleValue>)Parameters["C"]; }
+    }
+
+    public double C {
+      get { return CParameter.Value.Value; }
+      set { CParameter.Value.Value = value; }
+    }
+
+    [StorableConstructor]
+    protected Ucb(bool deserializing) : base(deserializing) { }
+    protected Ucb(Ucb original, Cloner cloner)
+      : base(original, cloner) {
+    }
+    public Ucb()
+      : base() {
+      Parameters.Add(new FixedValueParameter<DoubleValue>("C", "Parameter to balance between exploration and exploitation 0 <= c < 100", new DoubleValue(Math.Sqrt(2))));
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new Ucb(this, cloner);
+    }
+
+    public override int Select(IEnumerable<IActionStatistics> actions, IRandom random) {
+      return Select(actions, random, C, buf);
+    }
+
+    public override void Update(IActionStatistics action, double q) {
+      var a = action as ActionStatistics;
+      a.SumQuality += q;
+      a.Tries++;
+    }
+
+    public override IActionStatistics CreateActionStatistics() {
+      return new ActionStatistics();
+    }
+
+    private static int Select(IEnumerable<IActionStatistics> actions, IRandom rand, double c, IList<int> buf) {
+      // determine total tries of still active actions
+      int totalTries = 0;
+      buf.Clear();
+      int aIdx = -1;
+      foreach (var a in actions) {
+        ++aIdx;
+        if (a.Done) continue;
+        if (a.Tries == 0) buf.Add(aIdx);
+        else totalTries += a.Tries;
+      }
+      // if there are unvisited actions select a random action
+      if (buf.Any()) {
+        return buf[rand.Next(buf.Count)];
+      }
+      Contract.Assert(totalTries > 0);
+      double logTotalTries = Math.Log(totalTries);
+      var bestQ = double.NegativeInfinity;
+      aIdx = -1;
+      foreach (var a in actions) {
+        ++aIdx;
+        if (a.Done) continue;
+        var actionQ = a.AverageQuality + c * Math.Sqrt(logTotalTries / a.Tries);
+        if (actionQ > bestQ) {
+          buf.Clear();
+          buf.Add(aIdx);
+          bestQ = actionQ;
+        } else if (actionQ >= bestQ) {
+          buf.Add(aIdx);
+        }
+      }
+      return buf[rand.Next(buf.Count)];
+    }
+
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/MctsSymbolicRegression/Policies/UcbTuned.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/MctsSymbolicRegression/Policies/UcbTuned.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/MctsSymbolicRegression/Policies/UcbTuned.cs	(revision 13819)
@@ -0,0 +1,101 @@
+﻿using System;
+using System.Collections.Generic;
+using System.Diagnostics.Contracts;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Algorithms.DataAnalysis.MctsSymbolicRegression.Policies {
+  [StorableClass]
+  [Item("UcbTuned Policy", "UcbTuned is similar to Ucb but tracks empirical variance. Use parameter c to balance between exploitation and exploration")]
+  public class UcbTuned : PolicyBase {
+    private class ActionStatistics : IActionStatistics {
+      public double SumQuality { get; set; }
+      public double SumSqrQuality { get; set; }
+      public double AverageQuality { get { return SumQuality / Tries; } }
+      public double QualityVariance { get { return SumSqrQuality / Tries - AverageQuality * AverageQuality; } }
+      public int Tries { get; set; }
+      public bool Done { get; set; }
+    }
+    private List<int> buf = new List<int>();
+
+    public IFixedValueParameter<DoubleValue> CParameter {
+      get { return (IFixedValueParameter<DoubleValue>)Parameters["C"]; }
+    }
+
+    public double C {
+      get { return CParameter.Value.Value; }
+      set { CParameter.Value.Value = value; }
+    }
+
+    [StorableConstructor]
+    protected UcbTuned(bool deserializing) : base(deserializing) { }
+    protected UcbTuned(UcbTuned original, Cloner cloner)
+      : base(original, cloner) {
+    }
+    public UcbTuned()
+      : base() {
+      Parameters.Add(new FixedValueParameter<DoubleValue>("C", "Parameter to balance between exploration and exploitation 0 <= c < 100", new DoubleValue(Math.Sqrt(2))));
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new UcbTuned(this, cloner);
+    }
+
+    public override int Select(IEnumerable<IActionStatistics> actions, IRandom random) {
+      return Select(actions, random, C, buf);
+    }
+
+    public override void Update(IActionStatistics action, double q) {
+      var a = action as ActionStatistics;
+      a.SumQuality += q;
+      a.SumSqrQuality += q * q;
+      a.Tries++;
+    }
+
+    public override IActionStatistics CreateActionStatistics() {
+      return new ActionStatistics();
+    }
+
+    private static int Select(IEnumerable<IActionStatistics> actions, IRandom rand, double c, IList<int> buf) {
+      // determine total tries of still active actions
+      int totalTries = 0;
+      buf.Clear();
+      int aIdx = -1;
+      foreach (var a in actions) {
+        ++aIdx;
+        if (a.Done) continue;
+        if (a.Tries == 0) buf.Add(aIdx);
+        else totalTries += a.Tries;
+      }
+      // if there are unvisited actions select a random action
+      if (buf.Any()) {
+        return buf[rand.Next(buf.Count)];
+      }
+      Contract.Assert(totalTries > 0);
+      double logTotalTries = Math.Log(totalTries);
+      var bestQ = double.NegativeInfinity;
+      aIdx = -1;
+      foreach (var a in actions.Cast<ActionStatistics>()) {
+        ++aIdx;
+        if (a.Done) continue;
+        var varianceBound = a.QualityVariance + Math.Sqrt(2.0 * logTotalTries / a.Tries);
+        if (varianceBound > 0.25) varianceBound = 0.25;
+        var actionQ = a.AverageQuality + c * Math.Sqrt(logTotalTries / a.Tries * varianceBound);
+        if (actionQ > bestQ) {
+          buf.Clear();
+          buf.Add(aIdx);
+          bestQ = actionQ;
+        } else if (actionQ >= bestQ) {
+          buf.Add(aIdx);
+        }
+      }
+      return buf[rand.Next(buf.Count)];
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/MctsSymbolicRegression/SymbolicExpressionGenerator.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/MctsSymbolicRegression/SymbolicExpressionGenerator.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/MctsSymbolicRegression/SymbolicExpressionGenerator.cs	(revision 13819)
@@ -0,0 +1,183 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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.Diagnostics.Contracts;
+using System.Linq;
+
+using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
+using HeuristicLab.Problems.DataAnalysis.Symbolic;
+
+namespace HeuristicLab.Algorithms.DataAnalysis.MctsSymbolicRegression {
+
+  // translates byte code to a symbolic expression tree
+  internal class SymbolicExpressionTreeGenerator {
+    const int MaxStackSize = 100;
+    private readonly ISymbolicExpressionTreeNode[] stack;
+    private readonly ConstantTreeNode const0;
+    private readonly ConstantTreeNode const1;
+    private readonly Addition addSy;
+    private readonly Multiplication mulSy;
+    private readonly Exponential expSy;
+    private readonly Logarithm logSy;
+    private readonly Division divSy;
+    private readonly VariableTreeNode varNode;
+    private readonly string[] variableNames;
+    private readonly StartSymbol startSy;
+    private readonly ProgramRootSymbol progRootSy;
+
+    public SymbolicExpressionTreeGenerator(string[] variableNames) {
+      stack = new ISymbolicExpressionTreeNode[MaxStackSize];
+      var grammar = new TypeCoherentExpressionGrammar();
+      this.variableNames = variableNames;
+
+      grammar.ConfigureAsDefaultRegressionGrammar();
+      const0 = (ConstantTreeNode)grammar.Symbols.OfType<Constant>().First().CreateTreeNode();
+      const0.Value = 0;
+      const1 = (ConstantTreeNode)grammar.Symbols.OfType<Constant>().First().CreateTreeNode();
+      const1.Value = 1;
+      varNode = (VariableTreeNode)grammar.Symbols.OfType<Variable>().First().CreateTreeNode();
+
+      addSy = grammar.AllowedSymbols.OfType<Addition>().First();
+      mulSy = grammar.AllowedSymbols.OfType<Multiplication>().First();
+      logSy = grammar.AllowedSymbols.OfType<Logarithm>().First();
+      expSy = grammar.AllowedSymbols.OfType<Exponential>().First();
+      divSy = grammar.AllowedSymbols.OfType<Division>().First();
+
+      progRootSy = grammar.AllowedSymbols.OfType<ProgramRootSymbol>().First();
+      startSy = grammar.AllowedSymbols.OfType<StartSymbol>().First();
+    }
+
+    public ISymbolicExpressionTreeNode Exec(byte[] code, double[] consts, int nParams, double[] scalingFactor, double[] scalingOffset) {
+      int topOfStack = -1;
+      int pc = 0;
+      int nextParamIdx = -1;
+      OpCodes op;
+      short arg;
+      while (true) {
+        ReadNext(code, ref pc, out op, out arg);
+        switch (op) {
+          case OpCodes.Nop: break;
+          case OpCodes.LoadConst0: {
+              ++topOfStack;
+              stack[topOfStack] = (ISymbolicExpressionTreeNode)const0.Clone();
+              break;
+            }
+          case OpCodes.LoadConst1: {
+              ++topOfStack;
+              stack[topOfStack] = (ISymbolicExpressionTreeNode)const1.Clone();
+              break;
+            }
+          case OpCodes.LoadParamN: {
+              ++topOfStack;
+              var p = (ConstantTreeNode)const1.Clone(); // value will be tuned later (evaluator and tree generator both use 1 as initial values)
+              p.Value = consts[++nextParamIdx];
+              stack[topOfStack] = p;
+              break;
+            }
+          case OpCodes.LoadVar:
+            ++topOfStack;
+            if (scalingOffset != null) {
+              var sumNode = addSy.CreateTreeNode();
+              var varNode = (VariableTreeNode)this.varNode.Clone();
+              var constNode = (ConstantTreeNode)const0.Clone();
+              varNode.Weight = scalingFactor[arg];
+              varNode.VariableName = variableNames[arg];
+              constNode.Value = scalingOffset[arg];
+              sumNode.AddSubtree(varNode);
+              sumNode.AddSubtree(constNode);
+              stack[topOfStack] = sumNode;
+            } else {
+              var varNode = (VariableTreeNode)this.varNode.Clone();
+              varNode.Weight = 1.0;
+              varNode.VariableName = variableNames[arg];
+              stack[topOfStack] = varNode;
+            }
+            break;
+          case OpCodes.Add: {
+              var t1 = stack[topOfStack - 1];
+              var t2 = stack[topOfStack];
+              topOfStack--;
+              if (t1.Symbol is Addition) {
+                t1.AddSubtree(t2);
+              } else {
+                var addNode = addSy.CreateTreeNode();
+                addNode.AddSubtree(t1);
+                addNode.AddSubtree(t2);
+                stack[topOfStack] = addNode;
+              }
+              break;
+            }
+          case OpCodes.Mul: {
+              var t1 = stack[topOfStack - 1];
+              var t2 = stack[topOfStack];
+              topOfStack--;
+              if (t1.Symbol is Multiplication) {
+                t1.AddSubtree(t2);
+              } else {
+                var mulNode = mulSy.CreateTreeNode();
+                mulNode.AddSubtree(t1);
+                mulNode.AddSubtree(t2);
+                stack[topOfStack] = mulNode;
+              }
+              break;
+            }
+          case OpCodes.Log: {
+              var v1 = stack[topOfStack];
+              var logNode = logSy.CreateTreeNode();
+              logNode.AddSubtree(v1);
+              stack[topOfStack] = logNode;
+              break;
+            }
+          case OpCodes.Exp: {
+              var v1 = stack[topOfStack];
+              var expNode = expSy.CreateTreeNode();
+              expNode.AddSubtree(v1);
+              stack[topOfStack] = expNode;
+              break;
+            }
+          case OpCodes.Inv: {
+              var v1 = stack[topOfStack];
+              var divNode = divSy.CreateTreeNode();
+              divNode.AddSubtree(v1);
+              stack[topOfStack] = divNode;
+              break;
+            }
+          case OpCodes.Exit:
+            Contract.Assert(topOfStack == 0);
+            var rootNode = progRootSy.CreateTreeNode();
+            var startNode = startSy.CreateTreeNode();
+            startNode.AddSubtree(stack[topOfStack]);
+            rootNode.AddSubtree(startNode);
+            return rootNode;
+        }
+      }
+    }
+
+    private void ReadNext(byte[] code, ref int pc, out OpCodes op, out short s) {
+      op = (OpCodes)Enum.ToObject(typeof(OpCodes), code[pc++]);
+      s = 0;
+      if (op == OpCodes.LoadVar) {
+        s = (short)(((short)code[pc] << 8) | (short)code[pc + 1]);
+        pc += 2;
+      }
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/MctsSymbolicRegression/Tree.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/MctsSymbolicRegression/Tree.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/MctsSymbolicRegression/Tree.cs	(revision 13819)
@@ -0,0 +1,35 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ * 
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using HeuristicLab.Algorithms.DataAnalysis.MctsSymbolicRegression.Policies;
+
+namespace HeuristicLab.Algorithms.DataAnalysis.MctsSymbolicRegression {
+  // represents tree nodes for the search tree in MCTS
+  internal class Tree {
+    public int state;
+    public bool Done {
+      get { return actionStatistics.Done; }
+      set { actionStatistics.Done = value; }
+    }
+    public IActionStatistics actionStatistics;
+    public Tree[] children;
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Nca/Initialization/INcaInitializer.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Nca/Initialization/INcaInitializer.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Nca/Initialization/INcaInitializer.cs	(revision 13819)
@@ -0,0 +1,35 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using HeuristicLab.Core;
+using HeuristicLab.Problems.DataAnalysis;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  public interface INcaInitializer : IOperator {
+    /// <summary>
+    /// Calculates an initial projection for the NCA to start from.
+    /// </summary>
+    /// <param name="data">The problem data that contains the AllowedInputVariables and TrainingIndices.</param>
+    /// <param name="dimensions">The amount of columns in the matrix</param>
+    /// <returns>The matrix that projects the input variables into a lower dimensional space.</returns>
+    double[,] Initialize(IClassificationProblemData data, int dimensions);
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Nca/Initialization/LdaInitializer.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Nca/Initialization/LdaInitializer.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Nca/Initialization/LdaInitializer.cs	(revision 13819)
@@ -0,0 +1,67 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Problems.DataAnalysis;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  [Item("LDA", "Initializes the matrix by performing a linear discriminant analysis.")]
+  [StorableClass]
+  public class LdaInitializer : NcaInitializer {
+
+    [StorableConstructor]
+    protected LdaInitializer(bool deserializing) : base(deserializing) { }
+    protected LdaInitializer(LdaInitializer original, Cloner cloner) : base(original, cloner) { }
+    public LdaInitializer() : base() { }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new LdaInitializer(this, cloner);
+    }
+
+    public override double[,] Initialize(IClassificationProblemData data, int dimensions) {
+      var instances = data.TrainingIndices.Count();
+      var attributes = data.AllowedInputVariables.Count();
+
+      var ldaDs = AlglibUtil.PrepareInputMatrix(data.Dataset,
+                                                data.AllowedInputVariables.Concat(data.TargetVariable.ToEnumerable()),
+                                                data.TrainingIndices);
+
+      // map class values to sequential natural numbers (required by alglib)
+      var uniqueClasses = data.Dataset.GetDoubleValues(data.TargetVariable, data.TrainingIndices)
+                                        .Distinct()
+                                        .Select((v, i) => new { v, i })
+                                        .ToDictionary(x => x.v, x => x.i);
+
+      for (int row = 0; row < instances; row++)
+        ldaDs[row, attributes] = uniqueClasses[ldaDs[row, attributes]];
+
+      int info;
+      double[,] matrix;
+      alglib.fisherldan(ldaDs, instances, attributes, uniqueClasses.Count, out info, out matrix);
+
+      return matrix;
+    }
+
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Nca/Initialization/NcaInitializer.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Nca/Initialization/NcaInitializer.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Nca/Initialization/NcaInitializer.cs	(revision 13819)
@@ -0,0 +1,73 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Encodings.RealVectorEncoding;
+using HeuristicLab.Operators;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Problems.DataAnalysis;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  [Item("NcaInitializer", "Base class for initializers for NCA.")]
+  [StorableClass]
+  public abstract class NcaInitializer : SingleSuccessorOperator, INcaInitializer {
+
+    public ILookupParameter<IClassificationProblemData> ProblemDataParameter {
+      get { return (ILookupParameter<IClassificationProblemData>)Parameters["ProblemData"]; }
+    }
+    public ILookupParameter<IntValue> DimensionsParameter {
+      get { return (ILookupParameter<IntValue>)Parameters["Dimensions"]; }
+    }
+    public ILookupParameter<RealVector> NcaMatrixParameter {
+      get { return (ILookupParameter<RealVector>)Parameters["NcaMatrix"]; }
+    }
+
+    [StorableConstructor]
+    protected NcaInitializer(bool deserializing) : base(deserializing) { }
+    protected NcaInitializer(NcaInitializer original, Cloner cloner) : base(original, cloner) { }
+    public NcaInitializer() {
+      Parameters.Add(new LookupParameter<IClassificationProblemData>("ProblemData", "The classification problem data."));
+      Parameters.Add(new LookupParameter<IntValue>("Dimensions", "The number of dimensions to which the features should be pruned."));
+      Parameters.Add(new LookupParameter<RealVector>("NcaMatrix", "The coefficients of the matrix that need to be optimized. Note that the matrix is flattened."));
+    }
+
+    public override IOperation Apply() {
+      var problemData = ProblemDataParameter.ActualValue;
+
+      var dimensions = DimensionsParameter.ActualValue.Value;
+      var matrix = Initialize(problemData, dimensions);
+      var attributes = matrix.GetLength(0);
+
+      var result = new double[attributes * dimensions];
+      for (int i = 0; i < attributes; i++)
+        for (int j = 0; j < dimensions; j++)
+          result[i * dimensions + j] = matrix[i, j];
+
+      NcaMatrixParameter.ActualValue = new RealVector(result);
+      return base.Apply();
+    }
+
+    public abstract double[,] Initialize(IClassificationProblemData data, int dimensions);
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Nca/Initialization/PcaInitializer.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Nca/Initialization/PcaInitializer.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Nca/Initialization/PcaInitializer.cs	(revision 13819)
@@ -0,0 +1,57 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Problems.DataAnalysis;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  [Item("PCA", "Initializes the matrix by performing a principal components analysis.")]
+  [StorableClass]
+  public sealed class PcaInitializer : NcaInitializer {
+
+    [StorableConstructor]
+    private PcaInitializer(bool deserializing) : base(deserializing) { }
+    private PcaInitializer(PcaInitializer original, Cloner cloner) : base(original, cloner) { }
+    public PcaInitializer() : base() { }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new PcaInitializer(this, cloner);
+    }
+
+    public override double[,] Initialize(IClassificationProblemData data, int dimensions) {
+      var instances = data.TrainingIndices.Count();
+      var attributes = data.AllowedInputVariables.Count();
+
+      var pcaDs = AlglibUtil.PrepareInputMatrix(data.Dataset, data.AllowedInputVariables, data.TrainingIndices);
+
+      int info;
+      double[] varianceValues;
+      double[,] matrix;
+      alglib.pcabuildbasis(pcaDs, instances, attributes, out info, out varianceValues, out matrix);
+
+      return matrix;
+    }
+
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Nca/Initialization/RandomInitializer.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Nca/Initialization/RandomInitializer.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Nca/Initialization/RandomInitializer.cs	(revision 13819)
@@ -0,0 +1,62 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Optimization;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Problems.DataAnalysis;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  [Item("Random", "Initializes the matrix randomly.")]
+  [StorableClass]
+  public sealed class RandomInitializer : NcaInitializer, IStochasticOperator {
+    public ILookupParameter<IRandom> RandomParameter {
+      get { return (ILookupParameter<IRandom>)Parameters["Random"]; }
+    }
+
+    [StorableConstructor]
+    private RandomInitializer(bool deserializing) : base(deserializing) { }
+    private RandomInitializer(RandomInitializer original, Cloner cloner) : base(original, cloner) { }
+    public RandomInitializer()
+      : base() {
+      Parameters.Add(new LookupParameter<IRandom>("Random", "The random number generator to use."));
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new RandomInitializer(this, cloner);
+    }
+
+    public override double[,] Initialize(IClassificationProblemData data, int dimensions) {
+      var attributes = data.AllowedInputVariables.Count();
+
+      var random = RandomParameter.ActualValue;
+      var matrix = new double[attributes, dimensions];
+      for (int i = 0; i < attributes; i++)
+        for (int j = 0; j < dimensions; j++)
+          matrix[i, j] = random.NextDouble();
+
+      return matrix;
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Nca/Matrix.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Nca/Matrix.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Nca/Matrix.cs	(revision 13819)
@@ -0,0 +1,228 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.PluginInfrastructure;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  [NonDiscoverableType]
+  internal class Matrix : IEnumerable<double>, IDeepCloneable {
+    // this type is immutable
+    private readonly IEnumerable<double> values;
+    public readonly int Rows;
+    public readonly int Columns;
+
+    protected Matrix(Matrix original, Cloner cloner) {
+      this.values = original.values.ToArray();
+      this.Rows = original.Rows;
+      this.Columns = original.Columns;
+      cloner.RegisterClonedObject(original, this);
+    }
+    public Matrix(IEnumerable<double> vector) {
+      this.values = vector;
+      Rows = 1;
+      Columns = vector.Count();
+    }
+    public Matrix(IEnumerable<double> vector, int length) {
+      this.values = vector;
+      Rows = 1;
+      Columns = length;
+    }
+    public Matrix(double[,] matrix) {
+      this.values = GetOnlineValues(matrix);
+      Rows = matrix.GetLength(0);
+      Columns = matrix.GetLength(1);
+    }
+    public Matrix(IEnumerable<double> matrix, int rows, int columns) {
+      this.values = matrix;
+      Rows = rows;
+      Columns = columns;
+    }
+
+    public object Clone() {
+      return Clone(new Cloner());
+    }
+    public IDeepCloneable Clone(Cloner cloner) {
+      return new Matrix(this, cloner);
+    }
+
+    public Matrix Transpose() {
+      return new Matrix(Transpose(values, Columns, Rows), Columns, Rows);
+    }
+
+    private IEnumerable<double> Transpose(IEnumerable<double> values, int rows, int columns) {
+      // vectors don't need to be transposed
+      if (rows == 1 || columns == 1) {
+        foreach (var v in values) yield return v;
+        yield break;
+      }
+
+      int skip = 0;
+      var iter = values.GetEnumerator();
+      if (!iter.MoveNext()) yield break;
+      while (skip < rows) {
+        for (int i = 0; i < skip; i++) iter.MoveNext();
+        yield return iter.Current;
+        for (int j = 0; j < columns - 1; j++) {
+          for (int i = 0; i < rows; i++) iter.MoveNext();
+          yield return iter.Current;
+        }
+        skip++;
+        if (skip < rows) {
+          iter = values.GetEnumerator();
+          iter.MoveNext();
+        }
+      }
+    }
+
+    public Matrix Add(Matrix other) {
+      return new Matrix(AddOnline(other), Rows, Columns);
+    }
+
+    public void AddTo(double[,] matrix) {
+      if (Rows != matrix.GetLength(0) || Columns != matrix.GetLength(1)) throw new ArgumentException("unequal size", "matrix");
+      var iter = values.GetEnumerator();
+      for (int i = 0; i < Rows; i++)
+        for (int j = 0; j < Columns; j++) {
+          iter.MoveNext();
+          matrix[i, j] += iter.Current;
+        }
+    }
+
+    public Matrix Subtract(Matrix other) {
+      return new Matrix(SubtractOnline(other), Rows, Columns);
+    }
+
+    public Matrix Multiply(Matrix other) {
+      return new Matrix(MultiplyOnline(other), Rows, other.Columns);
+    }
+
+    public Matrix Multiply(double value) {
+      return new Matrix(values.Select(x => x * value), Rows, Columns);
+    }
+
+    public double EuclideanNorm() {
+      return Math.Sqrt(SumOfSquares());
+    }
+
+    public double SumOfSquares() {
+      return values.Sum(x => x * x);
+    }
+
+    public Matrix OuterProduct(Matrix other) {
+      if (Rows != 1 || other.Rows != 1) throw new ArgumentException("OuterProduct can only be applied to vectors.");
+      return Transpose().Multiply(other);
+    }
+
+    public IEnumerable<double> ColumnSums() {
+      return Transpose().RowSums();
+    }
+
+    public IEnumerable<double> RowSums() {
+      var sum = 0.0;
+      int counter = 0;
+      foreach (var v in values) {
+        sum += v;
+        counter++;
+        if (counter == Rows) {
+          yield return sum;
+          sum = 0.0;
+          counter = 0;
+        }
+      }
+    }
+
+    public Matrix Negate() {
+      return new Matrix(values.Select(x => -x), Rows, Columns);
+    }
+
+    public Matrix Apply() {
+      return new Matrix(values.ToArray(), Rows, Columns);
+    }
+
+    public IEnumerator<double> GetEnumerator() { return values.GetEnumerator(); }
+    IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }
+
+
+    private IEnumerable<double> AddOnline(Matrix other) {
+      if (Rows != other.Rows || Columns != other.Columns) throw new ArgumentException("Number of rows and columns are not equal.");
+      var meIter = values.GetEnumerator();
+      var otherIter = other.GetEnumerator();
+      if (!meIter.MoveNext()) yield break;
+      if (!otherIter.MoveNext()) yield break;
+      for (int i = 0; i < Rows * Columns; i++) {
+        yield return meIter.Current + otherIter.Current;
+        meIter.MoveNext();
+        otherIter.MoveNext();
+      }
+    }
+
+    private IEnumerable<double> SubtractOnline(Matrix other) {
+      if (Rows != other.Rows || Columns != other.Columns) throw new ArgumentException("Number of rows and columns are not equal.");
+      var meIter = values.GetEnumerator();
+      var otherIter = other.GetEnumerator();
+      if (!meIter.MoveNext()) yield break;
+      if (!otherIter.MoveNext()) yield break;
+      for (int i = 0; i < Rows * Columns; i++) {
+        yield return meIter.Current - otherIter.Current;
+        meIter.MoveNext();
+        otherIter.MoveNext();
+      }
+    }
+
+    private IEnumerable<double> MultiplyOnline(Matrix other) {
+      if (Columns != other.Rows) throw new ArgumentException("Number of rows and columns are not equal.");
+      var meIter = values.GetEnumerator();
+      var otherByColumn = other.Transpose();
+      var otherIter = otherByColumn.GetEnumerator();
+      if (!meIter.MoveNext()) yield break;
+      if (!otherIter.MoveNext()) yield break;
+      for (int r = 0; r < Rows; r++) {
+        var row = new double[Columns];
+        for (int x = 0; x < Columns; x++) {
+          row[x] = meIter.Current;
+          meIter.MoveNext();
+        }
+        for (int c = 0; c < other.Columns; c++) {
+          var sum = 0.0;
+          for (int y = 0; y < other.Rows; y++) {
+            sum += row[y] * otherIter.Current;
+            otherIter.MoveNext();
+          }
+          yield return sum;
+        }
+        otherIter = otherByColumn.GetEnumerator();
+        otherIter.MoveNext();
+      }
+    }
+
+    private IEnumerable<double> GetOnlineValues(double[,] matrix) {
+      for (int i = 0; i < matrix.GetLength(0); i++)
+        for (int j = 0; j < matrix.GetLength(1); j++) {
+          yield return matrix[i, j];
+        }
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Nca/ModelCreation/INcaModelCreator.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Nca/ModelCreation/INcaModelCreator.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Nca/ModelCreation/INcaModelCreator.cs	(revision 13819)
@@ -0,0 +1,32 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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 System.Text;
+using HeuristicLab.Core;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  public interface INcaModelCreator : IOperator {
+
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Nca/ModelCreation/NcaModelCreator.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Nca/ModelCreation/NcaModelCreator.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Nca/ModelCreation/NcaModelCreator.cs	(revision 13819)
@@ -0,0 +1,93 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Encodings.RealVectorEncoding;
+using HeuristicLab.Operators;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Problems.DataAnalysis;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  [Item("NcaModelCreator", "Creates an NCA model with a given matrix.")]
+  [StorableClass]
+  public class NcaModelCreator : SingleSuccessorOperator, INcaModelCreator {
+
+    public ILookupParameter<IntValue> KParameter {
+      get { return (ILookupParameter<IntValue>)Parameters["K"]; }
+    }
+
+    public ILookupParameter<IntValue> DimensionsParameter {
+      get { return (ILookupParameter<IntValue>)Parameters["Dimensions"]; }
+    }
+
+    public ILookupParameter<RealVector> NcaMatrixParameter {
+      get { return (ILookupParameter<RealVector>)Parameters["NcaMatrix"]; }
+    }
+
+    public ILookupParameter<RealVector> NcaMatrixGradientsParameter {
+      get { return (ILookupParameter<RealVector>)Parameters["NcaMatrixGradients"]; }
+    }
+
+    public ILookupParameter<IClassificationProblemData> ProblemDataParameter {
+      get { return (ILookupParameter<IClassificationProblemData>)Parameters["ProblemData"]; }
+    }
+
+    public ILookupParameter<INcaModel> NcaModelParameter {
+      get { return (ILookupParameter<INcaModel>)Parameters["NcaModel"]; }
+    }
+
+    [StorableConstructor]
+    protected NcaModelCreator(bool deserializing) : base(deserializing) { }
+    protected NcaModelCreator(NcaModelCreator original, Cloner cloner) : base(original, cloner) { }
+    public NcaModelCreator() {
+      Parameters.Add(new LookupParameter<IntValue>("K", "How many neighbors should be considered for classification."));
+      Parameters.Add(new LookupParameter<IntValue>("Dimensions", "The dimensions to which the feature space should be reduced to."));
+      Parameters.Add(new LookupParameter<RealVector>("NcaMatrix", "The optimized matrix."));
+      Parameters.Add(new LookupParameter<RealVector>("NcaMatrixGradients", "The gradients from the matrix that is being optimized."));
+      Parameters.Add(new LookupParameter<IClassificationProblemData>("ProblemData", "The classification problem data."));
+      Parameters.Add(new LookupParameter<INcaModel>("NcaModel", "The NCA model that should be created."));
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new NcaModelCreator(this, cloner);
+    }
+
+    public override IOperation Apply() {
+      var k = KParameter.ActualValue.Value;
+      var dim = DimensionsParameter.ActualValue.Value;
+      var vector = NcaMatrixParameter.ActualValue;
+      var matrix = new double[vector.Length / dim, dim];
+
+      for (int i = 0; i < matrix.GetLength(0); i++)
+        for (int j = 0; j < dim; j++) {
+          matrix[i, j] = vector[i * dim + j];
+        }
+
+      var problemData = ProblemDataParameter.ActualValue;
+      NcaModelParameter.ActualValue = new NcaModel(k, matrix, problemData.Dataset, problemData.TrainingIndices, problemData.TargetVariable, problemData.AllowedInputVariables, problemData.ClassValues.ToArray());
+      return base.Apply();
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Nca/NcaAlgorithm.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Nca/NcaAlgorithm.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Nca/NcaAlgorithm.cs	(revision 13819)
@@ -0,0 +1,254 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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 HeuristicLab.Algorithms.GradientDescent;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Operators;
+using HeuristicLab.Optimization;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.PluginInfrastructure;
+using HeuristicLab.Problems.DataAnalysis;
+using HeuristicLab.Random;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  /// <summary>
+  /// Neighborhood Components Analysis
+  /// </summary>
+  [Item("Neighborhood Components Analysis (NCA)", @"Implementation of Neighborhood Components Analysis
+based on the description of J. Goldberger, S. Roweis, G. Hinton, R. Salakhutdinov. 2005.
+Neighbourhood Component Analysis. Advances in Neural Information Processing Systems, 17. pp. 513-520
+with additional regularizations described in Z. Yang, J. Laaksonen. 2007.
+Regularized Neighborhood Component Analysis. Lecture Notes in Computer Science, 4522. pp. 253-262.")]
+  [Creatable(CreatableAttribute.Categories.DataAnalysisClassification, Priority = 170)]
+  [StorableClass]
+  public sealed class NcaAlgorithm : EngineAlgorithm {
+    #region Parameter Names
+    private const string SeedParameterName = "Seed";
+    private const string SetSeedRandomlyParameterName = "SetSeedRandomly";
+    private const string KParameterName = "K";
+    private const string DimensionsParameterName = "Dimensions";
+    private const string InitializationParameterName = "Initialization";
+    private const string NeighborSamplesParameterName = "NeighborSamples";
+    private const string IterationsParameterName = "Iterations";
+    private const string RegularizationParameterName = "Regularization";
+    private const string NcaModelCreatorParameterName = "NcaModelCreator";
+    private const string NcaSolutionCreatorParameterName = "NcaSolutionCreator";
+    private const string ApproximateGradientsParameterName = "ApproximateGradients";
+    private const string NcaMatrixParameterName = "NcaMatrix";
+    private const string NcaMatrixGradientsParameterName = "NcaMatrixGradients";
+    private const string QualityParameterName = "Quality";
+    #endregion
+
+    public override Type ProblemType { get { return typeof(IClassificationProblem); } }
+    public new IClassificationProblem Problem {
+      get { return (IClassificationProblem)base.Problem; }
+      set { base.Problem = value; }
+    }
+
+    #region Parameter Properties
+    public IValueParameter<IntValue> SeedParameter {
+      get { return (IValueParameter<IntValue>)Parameters[SeedParameterName]; }
+    }
+    public IValueParameter<BoolValue> SetSeedRandomlyParameter {
+      get { return (IValueParameter<BoolValue>)Parameters[SetSeedRandomlyParameterName]; }
+    }
+    public IFixedValueParameter<IntValue> KParameter {
+      get { return (IFixedValueParameter<IntValue>)Parameters[KParameterName]; }
+    }
+    public IFixedValueParameter<IntValue> DimensionsParameter {
+      get { return (IFixedValueParameter<IntValue>)Parameters[DimensionsParameterName]; }
+    }
+    public IConstrainedValueParameter<INcaInitializer> InitializationParameter {
+      get { return (IConstrainedValueParameter<INcaInitializer>)Parameters[InitializationParameterName]; }
+    }
+    public IFixedValueParameter<IntValue> NeighborSamplesParameter {
+      get { return (IFixedValueParameter<IntValue>)Parameters[NeighborSamplesParameterName]; }
+    }
+    public IFixedValueParameter<IntValue> IterationsParameter {
+      get { return (IFixedValueParameter<IntValue>)Parameters[IterationsParameterName]; }
+    }
+    public IFixedValueParameter<DoubleValue> RegularizationParameter {
+      get { return (IFixedValueParameter<DoubleValue>)Parameters[RegularizationParameterName]; }
+    }
+    public IValueParameter<BoolValue> ApproximateGradientsParameter {
+      get { return (IValueParameter<BoolValue>)Parameters[ApproximateGradientsParameterName]; }
+    }
+    public IValueParameter<INcaModelCreator> NcaModelCreatorParameter {
+      get { return (IValueParameter<INcaModelCreator>)Parameters[NcaModelCreatorParameterName]; }
+    }
+    public IValueParameter<INcaSolutionCreator> NcaSolutionCreatorParameter {
+      get { return (IValueParameter<INcaSolutionCreator>)Parameters[NcaSolutionCreatorParameterName]; }
+    }
+    #endregion
+
+    #region Properties
+    public int Seed {
+      get { return SeedParameter.Value.Value; }
+      set { SeedParameter.Value.Value = value; }
+    }
+    public bool SetSeedRandomly {
+      get { return SetSeedRandomlyParameter.Value.Value; }
+      set { SetSeedRandomlyParameter.Value.Value = value; }
+    }
+    public int K {
+      get { return KParameter.Value.Value; }
+      set { KParameter.Value.Value = value; }
+    }
+    public int Dimensions {
+      get { return DimensionsParameter.Value.Value; }
+      set { DimensionsParameter.Value.Value = value; }
+    }
+    public int NeighborSamples {
+      get { return NeighborSamplesParameter.Value.Value; }
+      set { NeighborSamplesParameter.Value.Value = value; }
+    }
+    public int Iterations {
+      get { return IterationsParameter.Value.Value; }
+      set { IterationsParameter.Value.Value = value; }
+    }
+    public double Regularization {
+      get { return RegularizationParameter.Value.Value; }
+      set { RegularizationParameter.Value.Value = value; }
+    }
+    public INcaModelCreator NcaModelCreator {
+      get { return NcaModelCreatorParameter.Value; }
+      set { NcaModelCreatorParameter.Value = value; }
+    }
+    public INcaSolutionCreator NcaSolutionCreator {
+      get { return NcaSolutionCreatorParameter.Value; }
+      set { NcaSolutionCreatorParameter.Value = value; }
+    }
+    #endregion
+
+    [StorableConstructor]
+    private NcaAlgorithm(bool deserializing) : base(deserializing) { }
+    private NcaAlgorithm(NcaAlgorithm original, Cloner cloner) : base(original, cloner) { }
+    public NcaAlgorithm()
+      : base() {
+      Parameters.Add(new ValueParameter<IntValue>(SeedParameterName, "The seed of the random number generator.", new IntValue(0)));
+      Parameters.Add(new ValueParameter<BoolValue>(SetSeedRandomlyParameterName, "A boolean flag that indicates whether the seed should be randomly reset each time the algorithm is run.", new BoolValue(true)));
+      Parameters.Add(new FixedValueParameter<IntValue>(KParameterName, "The K for the nearest neighbor.", new IntValue(3)));
+      Parameters.Add(new FixedValueParameter<IntValue>(DimensionsParameterName, "The number of dimensions that NCA should reduce the data to.", new IntValue(2)));
+      Parameters.Add(new ConstrainedValueParameter<INcaInitializer>(InitializationParameterName, "Which method should be used to initialize the matrix. Typically LDA (linear discriminant analysis) should provide a good estimate."));
+      Parameters.Add(new FixedValueParameter<IntValue>(NeighborSamplesParameterName, "How many of the neighbors should be sampled in order to speed up the calculation. This should be at least the value of k and at most the number of training instances minus one will be used.", new IntValue(60)));
+      Parameters.Add(new FixedValueParameter<IntValue>(IterationsParameterName, "How many iterations the conjugate gradient (CG) method should be allowed to perform. The method might still terminate earlier if a local optima has already been reached.", new IntValue(50)));
+      Parameters.Add(new FixedValueParameter<DoubleValue>(RegularizationParameterName, "A non-negative paramter which can be set to increase generalization and avoid overfitting. If set to 0 the algorithm is similar to NCA as proposed by Goldberger et al.", new DoubleValue(0)));
+      Parameters.Add(new ValueParameter<INcaModelCreator>(NcaModelCreatorParameterName, "Creates an NCA model out of the matrix.", new NcaModelCreator()));
+      Parameters.Add(new ValueParameter<INcaSolutionCreator>(NcaSolutionCreatorParameterName, "Creates an NCA solution given a model and some data.", new NcaSolutionCreator()));
+      Parameters.Add(new ValueParameter<BoolValue>(ApproximateGradientsParameterName, "True if the gradient should be approximated otherwise they are computed exactly.", new BoolValue()));
+
+      NcaSolutionCreatorParameter.Hidden = true;
+      ApproximateGradientsParameter.Hidden = true;
+
+      INcaInitializer defaultInitializer = null;
+      foreach (var initializer in ApplicationManager.Manager.GetInstances<INcaInitializer>().OrderBy(x => x.ItemName)) {
+        if (initializer is LdaInitializer) defaultInitializer = initializer;
+        InitializationParameter.ValidValues.Add(initializer);
+      }
+      if (defaultInitializer != null) InitializationParameter.Value = defaultInitializer;
+
+      var randomCreator = new RandomCreator();
+      var ncaInitializer = new Placeholder();
+      var bfgsInitializer = new LbfgsInitializer();
+      var makeStep = new LbfgsMakeStep();
+      var branch = new ConditionalBranch();
+      var gradientCalculator = new NcaGradientCalculator();
+      var modelCreator = new Placeholder();
+      var updateResults = new LbfgsUpdateResults();
+      var analyzer = new LbfgsAnalyzer();
+      var finalModelCreator = new Placeholder();
+      var finalAnalyzer = new LbfgsAnalyzer();
+      var solutionCreator = new Placeholder();
+
+      OperatorGraph.InitialOperator = randomCreator;
+      randomCreator.SeedParameter.ActualName = SeedParameterName;
+      randomCreator.SeedParameter.Value = null;
+      randomCreator.SetSeedRandomlyParameter.ActualName = SetSeedRandomlyParameterName;
+      randomCreator.SetSeedRandomlyParameter.Value = null;
+      randomCreator.Successor = ncaInitializer;
+
+      ncaInitializer.Name = "(NcaInitializer)";
+      ncaInitializer.OperatorParameter.ActualName = InitializationParameterName;
+      ncaInitializer.Successor = bfgsInitializer;
+
+      bfgsInitializer.IterationsParameter.ActualName = IterationsParameterName;
+      bfgsInitializer.PointParameter.ActualName = NcaMatrixParameterName;
+      bfgsInitializer.ApproximateGradientsParameter.ActualName = ApproximateGradientsParameterName;
+      bfgsInitializer.Successor = makeStep;
+
+      makeStep.StateParameter.ActualName = bfgsInitializer.StateParameter.Name;
+      makeStep.PointParameter.ActualName = NcaMatrixParameterName;
+      makeStep.Successor = branch;
+
+      branch.ConditionParameter.ActualName = makeStep.TerminationCriterionParameter.Name;
+      branch.FalseBranch = gradientCalculator;
+      branch.TrueBranch = finalModelCreator;
+
+      gradientCalculator.Successor = modelCreator;
+
+      modelCreator.OperatorParameter.ActualName = NcaModelCreatorParameterName;
+      modelCreator.Successor = updateResults;
+
+      updateResults.StateParameter.ActualName = bfgsInitializer.StateParameter.Name;
+      updateResults.QualityParameter.ActualName = QualityParameterName;
+      updateResults.QualityGradientsParameter.ActualName = NcaMatrixGradientsParameterName;
+      updateResults.ApproximateGradientsParameter.ActualName = ApproximateGradientsParameterName;
+      updateResults.Successor = analyzer;
+
+      analyzer.QualityParameter.ActualName = QualityParameterName;
+      analyzer.PointParameter.ActualName = NcaMatrixParameterName;
+      analyzer.QualityGradientsParameter.ActualName = NcaMatrixGradientsParameterName;
+      analyzer.StateParameter.ActualName = bfgsInitializer.StateParameter.Name;
+      analyzer.PointsTableParameter.ActualName = "Matrix table";
+      analyzer.QualityGradientsTableParameter.ActualName = "Gradients table";
+      analyzer.QualitiesTableParameter.ActualName = "Qualities";
+      analyzer.Successor = makeStep;
+
+      finalModelCreator.OperatorParameter.ActualName = NcaModelCreatorParameterName;
+      finalModelCreator.Successor = finalAnalyzer;
+
+      finalAnalyzer.QualityParameter.ActualName = QualityParameterName;
+      finalAnalyzer.PointParameter.ActualName = NcaMatrixParameterName;
+      finalAnalyzer.QualityGradientsParameter.ActualName = NcaMatrixGradientsParameterName;
+      finalAnalyzer.PointsTableParameter.ActualName = analyzer.PointsTableParameter.ActualName;
+      finalAnalyzer.QualityGradientsTableParameter.ActualName = analyzer.QualityGradientsTableParameter.ActualName;
+      finalAnalyzer.QualitiesTableParameter.ActualName = analyzer.QualitiesTableParameter.ActualName;
+      finalAnalyzer.Successor = solutionCreator;
+
+      solutionCreator.OperatorParameter.ActualName = NcaSolutionCreatorParameterName;
+
+      Problem = new ClassificationProblem();
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new NcaAlgorithm(this, cloner);
+    }
+
+    public override void Prepare() {
+      if (Problem != null) base.Prepare();
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Nca/NcaClassificationSolution.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Nca/NcaClassificationSolution.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Nca/NcaClassificationSolution.cs	(revision 13819)
@@ -0,0 +1,50 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Problems.DataAnalysis;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  [Item("NCA Classification Solution", "")]
+  [StorableClass]
+  public class NcaClassificationSolution : ClassificationSolution, INcaClassificationSolution {
+
+    public new INcaModel Model {
+      get { return (INcaModel)base.Model; }
+      set { base.Model = value; }
+    }
+
+    [StorableConstructor]
+    protected NcaClassificationSolution(bool deserializing) : base(deserializing) { }
+    protected NcaClassificationSolution(NcaClassificationSolution original, Cloner cloner)
+      : base(original, cloner) {
+    }
+    public NcaClassificationSolution(IClassificationProblemData problemData, INcaModel ncaModel)
+      : base(ncaModel, problemData) {
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new NcaClassificationSolution(this, cloner);
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Nca/NcaGradientCalculator.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Nca/NcaGradientCalculator.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Nca/NcaGradientCalculator.cs	(revision 13819)
@@ -0,0 +1,174 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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.RealVectorEncoding;
+using HeuristicLab.Operators;
+using HeuristicLab.Optimization;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Problems.DataAnalysis;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  [Item("NcaGradientCalculator", "Calculates the quality and gradient of a certain NCA matrix.")]
+  [StorableClass]
+  public class NcaGradientCalculator : SingleSuccessorOperator, ISingleObjectiveOperator {
+
+    #region Parameter Properties
+    public ILookupParameter<IntValue> DimensionsParameter {
+      get { return (ILookupParameter<IntValue>)Parameters["Dimensions"]; }
+    }
+
+    public ILookupParameter<IntValue> NeighborSamplesParameter {
+      get { return (ILookupParameter<IntValue>)Parameters["NeighborSamples"]; }
+    }
+
+    public ILookupParameter<DoubleValue> RegularizationParameter {
+      get { return (ILookupParameter<DoubleValue>)Parameters["Regularization"]; }
+    }
+
+    public ILookupParameter<RealVector> NcaMatrixParameter {
+      get { return (ILookupParameter<RealVector>)Parameters["NcaMatrix"]; }
+    }
+
+    public ILookupParameter<RealVector> NcaMatrixGradientsParameter {
+      get { return (ILookupParameter<RealVector>)Parameters["NcaMatrixGradients"]; }
+    }
+
+    public ILookupParameter<DoubleValue> QualityParameter {
+      get { return (ILookupParameter<DoubleValue>)Parameters["Quality"]; }
+    }
+
+    public ILookupParameter<IClassificationProblemData> ProblemDataParameter {
+      get { return (ILookupParameter<IClassificationProblemData>)Parameters["ProblemData"]; }
+    }
+    #endregion
+
+    [StorableConstructor]
+    protected NcaGradientCalculator(bool deserializing) : base(deserializing) { }
+    protected NcaGradientCalculator(NcaGradientCalculator original, Cloner cloner) : base(original, cloner) { }
+    public NcaGradientCalculator()
+      : base() {
+      Parameters.Add(new LookupParameter<IntValue>("Dimensions", "The dimensions to which the feature space should be reduced to."));
+      Parameters.Add(new LookupParameter<IntValue>("NeighborSamples", "The number of neighbors that should be taken into account at maximum."));
+      Parameters.Add(new LookupParameter<DoubleValue>("Regularization", "The regularization term that constrains the expansion of the projected space."));
+      Parameters.Add(new LookupParameter<RealVector>("NcaMatrix", "The optimized matrix."));
+      Parameters.Add(new LookupParameter<RealVector>("NcaMatrixGradients", "The gradients from the matrix that is being optimized."));
+      Parameters.Add(new LookupParameter<DoubleValue>("Quality", "The quality of the current matrix."));
+      Parameters.Add(new LookupParameter<IClassificationProblemData>("ProblemData", "The classification problem data."));
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new NcaGradientCalculator(this, cloner);
+    }
+
+    public override IOperation Apply() {
+      var problemData = ProblemDataParameter.ActualValue;
+      var dimensions = DimensionsParameter.ActualValue.Value;
+      var neighborSamples = NeighborSamplesParameter.ActualValue.Value;
+      var regularization = RegularizationParameter.ActualValue.Value;
+
+      var vector = NcaMatrixParameter.ActualValue;
+      var gradients = NcaMatrixGradientsParameter.ActualValue;
+      if (gradients == null) {
+        gradients = new RealVector(vector.Length);
+        NcaMatrixGradientsParameter.ActualValue = gradients;
+      }
+
+      var data = AlglibUtil.PrepareInputMatrix(problemData.Dataset, problemData.AllowedInputVariables,
+                                               problemData.TrainingIndices);
+      var classes = problemData.Dataset.GetDoubleValues(problemData.TargetVariable, problemData.TrainingIndices).ToArray();
+
+      var quality = Gradient(vector, gradients, data, classes, dimensions, neighborSamples, regularization);
+      QualityParameter.ActualValue = new DoubleValue(quality);
+
+      return base.Apply();
+    }
+
+    private static double Gradient(RealVector A, RealVector grad, double[,] data, double[] classes, int dimensions, int neighborSamples, double regularization) {
+      var instances = data.GetLength(0);
+      var attributes = data.GetLength(1);
+
+      var AMatrix = new Matrix(A, A.Length / dimensions, dimensions);
+
+      alglib.sparsematrix probabilities;
+      alglib.sparsecreate(instances, instances, out probabilities);
+      var transformedDistances = new Dictionary<int, double>(instances);
+      for (int i = 0; i < instances; i++) {
+        var iVector = new Matrix(GetRow(data, i), data.GetLength(1));
+        for (int k = 0; k < instances; k++) {
+          if (k == i) {
+            transformedDistances.Remove(k);
+            continue;
+          }
+          var kVector = new Matrix(GetRow(data, k));
+          transformedDistances[k] = Math.Exp(-iVector.Multiply(AMatrix).Subtract(kVector.Multiply(AMatrix)).SumOfSquares());
+        }
+        var normalization = transformedDistances.Sum(x => x.Value);
+        if (normalization <= 0) continue;
+        foreach (var s in transformedDistances.Where(x => x.Value > 0).OrderByDescending(x => x.Value).Take(neighborSamples)) {
+          alglib.sparseset(probabilities, i, s.Key, s.Value / normalization);
+        }
+      }
+      alglib.sparseconverttocrs(probabilities); // needed to enumerate in order (top-down and left-right)
+
+      int t0 = 0, t1 = 0, r, c;
+      double val;
+      var pi = new double[instances];
+      while (alglib.sparseenumerate(probabilities, ref t0, ref t1, out r, out c, out val)) {
+        if (classes[r].IsAlmost(classes[c])) {
+          pi[r] += val;
+        }
+      }
+
+      var innerSum = new double[attributes, attributes];
+      while (alglib.sparseenumerate(probabilities, ref t0, ref t1, out r, out c, out val)) {
+        var vector = new Matrix(GetRow(data, r)).Subtract(new Matrix(GetRow(data, c)));
+        vector.OuterProduct(vector).Multiply(val * pi[r]).AddTo(innerSum);
+
+        if (classes[r].IsAlmost(classes[c])) {
+          vector.OuterProduct(vector).Multiply(-val).AddTo(innerSum);
+        }
+      }
+
+      var func = -pi.Sum() + regularization * AMatrix.SumOfSquares();
+
+      r = 0;
+      var newGrad = AMatrix.Multiply(-2.0).Transpose().Multiply(new Matrix(innerSum)).Transpose();
+      foreach (var g in newGrad) {
+        grad[r] = g + regularization * 2 * A[r];
+        r++;
+      }
+
+      return func;
+    }
+
+    private static IEnumerable<double> GetRow(double[,] data, int row) {
+      for (int i = 0; i < data.GetLength(1); i++)
+        yield return data[row, i];
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Nca/NcaModel.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Nca/NcaModel.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Nca/NcaModel.cs	(revision 13819)
@@ -0,0 +1,110 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Problems.DataAnalysis;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  [Item("NCA Model", "")]
+  [StorableClass]
+  public class NcaModel : NamedItem, INcaModel {
+
+    [Storable]
+    private double[,] transformationMatrix;
+    public double[,] TransformationMatrix {
+      get { return (double[,])transformationMatrix.Clone(); }
+    }
+    [Storable]
+    private string[] allowedInputVariables;
+    [Storable]
+    private string targetVariable;
+    [Storable]
+    private INearestNeighbourModel nnModel;
+    [Storable]
+    private double[] classValues;
+
+    [StorableConstructor]
+    protected NcaModel(bool deserializing) : base(deserializing) { }
+    protected NcaModel(NcaModel original, Cloner cloner)
+      : base(original, cloner) {
+      this.transformationMatrix = (double[,])original.transformationMatrix.Clone();
+      this.allowedInputVariables = (string[])original.allowedInputVariables.Clone();
+      this.targetVariable = original.targetVariable;
+      this.nnModel = cloner.Clone(original.nnModel);
+      this.classValues = (double[])original.classValues.Clone();
+    }
+    public NcaModel(int k, double[,] transformationMatrix, IDataset dataset, IEnumerable<int> rows, string targetVariable, IEnumerable<string> allowedInputVariables, double[] classValues) {
+      Name = ItemName;
+      Description = ItemDescription;
+      this.transformationMatrix = (double[,])transformationMatrix.Clone();
+      this.allowedInputVariables = allowedInputVariables.ToArray();
+      this.targetVariable = targetVariable;
+      this.classValues = (double[])classValues.Clone();
+
+      var ds = ReduceDataset(dataset, rows);
+      nnModel = new NearestNeighbourModel(ds, Enumerable.Range(0, ds.Rows), k, ds.VariableNames.Last(), ds.VariableNames.Take(transformationMatrix.GetLength(1)), classValues);
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new NcaModel(this, cloner);
+    }
+
+    public IEnumerable<double> GetEstimatedClassValues(IDataset dataset, IEnumerable<int> rows) {
+      var ds = ReduceDataset(dataset, rows);
+      return nnModel.GetEstimatedClassValues(ds, Enumerable.Range(0, ds.Rows));
+    }
+
+    public INcaClassificationSolution CreateClassificationSolution(IClassificationProblemData problemData) {
+      return new NcaClassificationSolution(new ClassificationProblemData(problemData), this);
+    }
+
+    IClassificationSolution IClassificationModel.CreateClassificationSolution(IClassificationProblemData problemData) {
+      return CreateClassificationSolution(problemData);
+    }
+
+    public double[,] Reduce(IDataset dataset, IEnumerable<int> rows) {
+      var data = AlglibUtil.PrepareInputMatrix(dataset, allowedInputVariables, rows);
+
+      var targets = dataset.GetDoubleValues(targetVariable, rows).ToArray();
+      var result = new double[data.GetLength(0), transformationMatrix.GetLength(1) + 1];
+      for (int i = 0; i < data.GetLength(0); i++)
+        for (int j = 0; j < data.GetLength(1); j++) {
+          for (int x = 0; x < transformationMatrix.GetLength(1); x++) {
+            result[i, x] += data[i, j] * transformationMatrix[j, x];
+          }
+          result[i, transformationMatrix.GetLength(1)] = targets[i];
+        }
+      return result;
+    }
+
+    public Dataset ReduceDataset(IDataset dataset, IEnumerable<int> rows) {
+      return new Dataset(Enumerable
+          .Range(0, transformationMatrix.GetLength(1))
+          .Select(x => "X" + x.ToString())
+          .Concat(targetVariable.ToEnumerable()),
+        Reduce(dataset, rows));
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Nca/SolutionCreation/INcaSolutionCreator.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Nca/SolutionCreation/INcaSolutionCreator.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Nca/SolutionCreation/INcaSolutionCreator.cs	(revision 13819)
@@ -0,0 +1,28 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using HeuristicLab.Core;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  public interface INcaSolutionCreator : IOperator {
+
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Nca/SolutionCreation/NcaSolutionCreator.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Nca/SolutionCreation/NcaSolutionCreator.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Nca/SolutionCreation/NcaSolutionCreator.cs	(revision 13819)
@@ -0,0 +1,91 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Operators;
+using HeuristicLab.Optimization;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Problems.DataAnalysis;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  [Item("NcaSolutionCreator", "Creates an NCA solution with a given model and some given data.")]
+  [StorableClass]
+  public class NcaSolutionCreator : SingleSuccessorOperator, INcaSolutionCreator {
+
+    public ILookupParameter<IClassificationProblemData> ProblemDataParameter {
+      get { return (ILookupParameter<IClassificationProblemData>)Parameters["ProblemData"]; }
+    }
+
+    public ILookupParameter<INcaModel> NcaModelParameter {
+      get { return (ILookupParameter<INcaModel>)Parameters["NcaModel"]; }
+    }
+
+    public ILookupParameter<INcaClassificationSolution> NcaSolutionParameter {
+      get { return (ILookupParameter<INcaClassificationSolution>)Parameters["NcaSolution"]; }
+    }
+
+    public ILookupParameter<ResultCollection> ResultsParameter {
+      get { return (ILookupParameter<ResultCollection>)Parameters["Results"]; }
+    }
+
+    [StorableConstructor]
+    protected NcaSolutionCreator(bool deserializing) : base(deserializing) { }
+    protected NcaSolutionCreator(NcaSolutionCreator original, Cloner cloner) : base(original, cloner) { }
+    public NcaSolutionCreator()
+      : base() {
+      Parameters.Add(new LookupParameter<IClassificationProblemData>("ProblemData", "The classification problem data."));
+      Parameters.Add(new LookupParameter<INcaModel>("NcaModel", "The NCA model that should be created."));
+      Parameters.Add(new LookupParameter<INcaClassificationSolution>("NcaSolution", "The created NCA solution."));
+      Parameters.Add(new LookupParameter<ResultCollection>("Results", "The results collection to store the results."));
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new NcaSolutionCreator(this, cloner);
+    }
+
+    public override IOperation Apply() {
+      var problemData = ProblemDataParameter.ActualValue;
+      var model = NcaModelParameter.ActualValue;
+      var results = ResultsParameter.ActualValue;
+
+      var s = model.CreateClassificationSolution(problemData);
+      NcaSolutionParameter.ActualValue = s;
+
+      if (!results.ContainsKey("Solution")) {
+        results.Add(new Result("Solution", "The NCA classification solution", s));
+        results.Add(new Result("Accuracy (training)",
+                               "The accuracy of the NCA solution on the training partition.",
+                               new DoubleValue(s.TrainingAccuracy)));
+        results.Add(new Result("Accuracy (test)",
+                               "The accuracy of the NCA solution on the test partition.",
+                               new DoubleValue(s.TestAccuracy)));
+      } else {
+        results["Solution"].Value = s;
+        results["Accuracy (training)"].Value = new DoubleValue(s.TrainingAccuracy);
+        results["Accuracy (test)"].Value = new DoubleValue(s.TestAccuracy);
+      }
+      return base.Apply();
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/NearestNeighbour/NearestNeighbourClassification.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/NearestNeighbour/NearestNeighbourClassification.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/NearestNeighbour/NearestNeighbourClassification.cs	(revision 13819)
@@ -0,0 +1,96 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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 HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Optimization;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Problems.DataAnalysis;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  /// <summary>
+  /// Nearest neighbour classification data analysis algorithm.
+  /// </summary>
+  [Item("Nearest Neighbour Classification (kNN)", "Nearest neighbour classification data analysis algorithm (wrapper for ALGLIB).")]
+  [Creatable(CreatableAttribute.Categories.DataAnalysisClassification, Priority = 150)]
+  [StorableClass]
+  public sealed class NearestNeighbourClassification : FixedDataAnalysisAlgorithm<IClassificationProblem> {
+    private const string KParameterName = "K";
+    private const string NearestNeighbourClassificationModelResultName = "Nearest neighbour classification solution";
+
+    #region parameter properties
+    public IFixedValueParameter<IntValue> KParameter {
+      get { return (IFixedValueParameter<IntValue>)Parameters[KParameterName]; }
+    }
+    #endregion
+    #region properties
+    public int K {
+      get { return KParameter.Value.Value; }
+      set {
+        if (value <= 0) throw new ArgumentException("K must be larger than zero.", "K");
+        else KParameter.Value.Value = value;
+      }
+    }
+    #endregion
+
+    [StorableConstructor]
+    private NearestNeighbourClassification(bool deserializing) : base(deserializing) { }
+    private NearestNeighbourClassification(NearestNeighbourClassification original, Cloner cloner)
+      : base(original, cloner) {
+    }
+    public NearestNeighbourClassification()
+      : base() {
+      Parameters.Add(new FixedValueParameter<IntValue>(KParameterName, "The number of nearest neighbours to consider for regression.", new IntValue(3)));
+      Problem = new ClassificationProblem();
+    }
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() { }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new NearestNeighbourClassification(this, cloner);
+    }
+
+    #region nearest neighbour
+    protected override void Run() {
+      var solution = CreateNearestNeighbourClassificationSolution(Problem.ProblemData, K);
+      Results.Add(new Result(NearestNeighbourClassificationModelResultName, "The nearest neighbour classification solution.", solution));
+    }
+
+    public static IClassificationSolution CreateNearestNeighbourClassificationSolution(IClassificationProblemData problemData, int k) {
+      var problemDataClone = (IClassificationProblemData)problemData.Clone();
+      return new NearestNeighbourClassificationSolution(problemDataClone, Train(problemDataClone, k));
+    }
+
+    public static INearestNeighbourModel Train(IClassificationProblemData problemData, int k) {
+      return new NearestNeighbourModel(problemData.Dataset,
+        problemData.TrainingIndices,
+        k,
+        problemData.TargetVariable,
+        problemData.AllowedInputVariables,
+        problemData.ClassValues.ToArray());
+    }
+    #endregion
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/NearestNeighbour/NearestNeighbourClassificationSolution.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/NearestNeighbour/NearestNeighbourClassificationSolution.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/NearestNeighbour/NearestNeighbourClassificationSolution.cs	(revision 13819)
@@ -0,0 +1,53 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Problems.DataAnalysis;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  /// <summary>
+  /// Represents a nearest neighbour solution for a classification problem which can be visualized in the GUI.
+  /// </summary>
+  [Item("NearestNeighbourClassificationSolution", "Represents a nearest neighbour solution for a classification problem which can be visualized in the GUI.")]
+  [StorableClass]
+  public sealed class NearestNeighbourClassificationSolution : ClassificationSolution, INearestNeighbourClassificationSolution {
+
+    public new INearestNeighbourModel Model {
+      get { return (INearestNeighbourModel)base.Model; }
+      set { base.Model = value; }
+    }
+
+    [StorableConstructor]
+    private NearestNeighbourClassificationSolution(bool deserializing) : base(deserializing) { }
+    private NearestNeighbourClassificationSolution(NearestNeighbourClassificationSolution original, Cloner cloner)
+      : base(original, cloner) {
+    }
+    public NearestNeighbourClassificationSolution(IClassificationProblemData problemData, INearestNeighbourModel nnModel)
+      : base(nnModel, problemData) {
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new NearestNeighbourClassificationSolution(this, cloner);
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/NearestNeighbour/NearestNeighbourModel.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/NearestNeighbour/NearestNeighbourModel.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/NearestNeighbour/NearestNeighbourModel.cs	(revision 13819)
@@ -0,0 +1,343 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Problems.DataAnalysis;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  /// <summary>
+  /// Represents a nearest neighbour model for regression and classification
+  /// </summary>
+  [StorableClass]
+  [Item("NearestNeighbourModel", "Represents a nearest neighbour model for regression and classification.")]
+  public sealed class NearestNeighbourModel : NamedItem, INearestNeighbourModel {
+
+    private alglib.nearestneighbor.kdtree kdTree;
+    public alglib.nearestneighbor.kdtree KDTree {
+      get { return kdTree; }
+      set {
+        if (value != kdTree) {
+          if (value == null) throw new ArgumentNullException();
+          kdTree = value;
+          OnChanged(EventArgs.Empty);
+        }
+      }
+    }
+
+    [Storable]
+    private string targetVariable;
+    [Storable]
+    private string[] allowedInputVariables;
+    [Storable]
+    private double[] classValues;
+    [Storable]
+    private int k;
+
+    [StorableConstructor]
+    private NearestNeighbourModel(bool deserializing)
+      : base(deserializing) {
+      if (deserializing)
+        kdTree = new alglib.nearestneighbor.kdtree();
+    }
+    private NearestNeighbourModel(NearestNeighbourModel original, Cloner cloner)
+      : base(original, cloner) {
+      kdTree = new alglib.nearestneighbor.kdtree();
+      kdTree.approxf = original.kdTree.approxf;
+      kdTree.boxmax = (double[])original.kdTree.boxmax.Clone();
+      kdTree.boxmin = (double[])original.kdTree.boxmin.Clone();
+      kdTree.buf = (double[])original.kdTree.buf.Clone();
+      kdTree.curboxmax = (double[])original.kdTree.curboxmax.Clone();
+      kdTree.curboxmin = (double[])original.kdTree.curboxmin.Clone();
+      kdTree.curdist = original.kdTree.curdist;
+      kdTree.debugcounter = original.kdTree.debugcounter;
+      kdTree.idx = (int[])original.kdTree.idx.Clone();
+      kdTree.kcur = original.kdTree.kcur;
+      kdTree.kneeded = original.kdTree.kneeded;
+      kdTree.n = original.kdTree.n;
+      kdTree.nodes = (int[])original.kdTree.nodes.Clone();
+      kdTree.normtype = original.kdTree.normtype;
+      kdTree.nx = original.kdTree.nx;
+      kdTree.ny = original.kdTree.ny;
+      kdTree.r = (double[])original.kdTree.r.Clone();
+      kdTree.rneeded = original.kdTree.rneeded;
+      kdTree.selfmatch = original.kdTree.selfmatch;
+      kdTree.splits = (double[])original.kdTree.splits.Clone();
+      kdTree.tags = (int[])original.kdTree.tags.Clone();
+      kdTree.x = (double[])original.kdTree.x.Clone();
+      kdTree.xy = (double[,])original.kdTree.xy.Clone();
+
+      k = original.k;
+      targetVariable = original.targetVariable;
+      allowedInputVariables = (string[])original.allowedInputVariables.Clone();
+      if (original.classValues != null)
+        this.classValues = (double[])original.classValues.Clone();
+    }
+    public NearestNeighbourModel(IDataset dataset, IEnumerable<int> rows, int k, string targetVariable, IEnumerable<string> allowedInputVariables, double[] classValues = null) {
+      Name = ItemName;
+      Description = ItemDescription;
+      this.k = k;
+      this.targetVariable = targetVariable;
+      this.allowedInputVariables = allowedInputVariables.ToArray();
+
+      var inputMatrix = AlglibUtil.PrepareInputMatrix(dataset,
+                                   allowedInputVariables.Concat(new string[] { targetVariable }),
+                                   rows);
+
+      if (inputMatrix.Cast<double>().Any(x => double.IsNaN(x) || double.IsInfinity(x)))
+        throw new NotSupportedException(
+          "Nearest neighbour classification does not support NaN or infinity values in the input dataset.");
+
+      this.kdTree = new alglib.nearestneighbor.kdtree();
+
+      var nRows = inputMatrix.GetLength(0);
+      var nFeatures = inputMatrix.GetLength(1) - 1;
+
+      if (classValues != null) {
+        this.classValues = (double[])classValues.Clone();
+        int nClasses = classValues.Length;
+        // map original class values to values [0..nClasses-1]
+        var classIndices = new Dictionary<double, double>();
+        for (int i = 0; i < nClasses; i++)
+          classIndices[classValues[i]] = i;
+
+        for (int row = 0; row < nRows; row++) {
+          inputMatrix[row, nFeatures] = classIndices[inputMatrix[row, nFeatures]];
+        }
+      }
+      alglib.nearestneighbor.kdtreebuild(inputMatrix, nRows, inputMatrix.GetLength(1) - 1, 1, 2, kdTree);
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new NearestNeighbourModel(this, cloner);
+    }
+
+    public IEnumerable<double> GetEstimatedValues(IDataset dataset, IEnumerable<int> rows) {
+      double[,] inputData = AlglibUtil.PrepareInputMatrix(dataset, allowedInputVariables, rows);
+
+      int n = inputData.GetLength(0);
+      int columns = inputData.GetLength(1);
+      double[] x = new double[columns];
+      double[] y = new double[1];
+      double[] dists = new double[k];
+      double[,] neighbours = new double[k, columns + 1];
+
+      for (int row = 0; row < n; row++) {
+        for (int column = 0; column < columns; column++) {
+          x[column] = inputData[row, column];
+        }
+        int actNeighbours = alglib.nearestneighbor.kdtreequeryknn(kdTree, x, k, false);
+        alglib.nearestneighbor.kdtreequeryresultsdistances(kdTree, ref dists);
+        alglib.nearestneighbor.kdtreequeryresultsxy(kdTree, ref neighbours);
+
+        double distanceWeightedValue = 0.0;
+        double distsSum = 0.0;
+        for (int i = 0; i < actNeighbours; i++) {
+          distanceWeightedValue += neighbours[i, columns] / dists[i];
+          distsSum += 1.0 / dists[i];
+        }
+        yield return distanceWeightedValue / distsSum;
+      }
+    }
+
+    public IEnumerable<double> GetEstimatedClassValues(IDataset dataset, IEnumerable<int> rows) {
+      if (classValues == null) throw new InvalidOperationException("No class values are defined.");
+      double[,] inputData = AlglibUtil.PrepareInputMatrix(dataset, allowedInputVariables, rows);
+
+      int n = inputData.GetLength(0);
+      int columns = inputData.GetLength(1);
+      double[] x = new double[columns];
+      int[] y = new int[classValues.Length];
+      double[] dists = new double[k];
+      double[,] neighbours = new double[k, columns + 1];
+
+      for (int row = 0; row < n; row++) {
+        for (int column = 0; column < columns; column++) {
+          x[column] = inputData[row, column];
+        }
+        int actNeighbours = alglib.nearestneighbor.kdtreequeryknn(kdTree, x, k, false);
+        alglib.nearestneighbor.kdtreequeryresultsdistances(kdTree, ref dists);
+        alglib.nearestneighbor.kdtreequeryresultsxy(kdTree, ref neighbours);
+
+        Array.Clear(y, 0, y.Length);
+        for (int i = 0; i < actNeighbours; i++) {
+          int classValue = (int)Math.Round(neighbours[i, columns]);
+          y[classValue]++;
+        }
+
+        // find class for with the largest probability value
+        int maxProbClassIndex = 0;
+        double maxProb = y[0];
+        for (int i = 1; i < y.Length; i++) {
+          if (maxProb < y[i]) {
+            maxProb = y[i];
+            maxProbClassIndex = i;
+          }
+        }
+        yield return classValues[maxProbClassIndex];
+      }
+    }
+
+    public INearestNeighbourRegressionSolution CreateRegressionSolution(IRegressionProblemData problemData) {
+      return new NearestNeighbourRegressionSolution(new RegressionProblemData(problemData), this);
+    }
+    IRegressionSolution IRegressionModel.CreateRegressionSolution(IRegressionProblemData problemData) {
+      return CreateRegressionSolution(problemData);
+    }
+    public INearestNeighbourClassificationSolution CreateClassificationSolution(IClassificationProblemData problemData) {
+      return new NearestNeighbourClassificationSolution(new ClassificationProblemData(problemData), this);
+    }
+    IClassificationSolution IClassificationModel.CreateClassificationSolution(IClassificationProblemData problemData) {
+      return CreateClassificationSolution(problemData);
+    }
+
+    #region events
+    public event EventHandler Changed;
+    private void OnChanged(EventArgs e) {
+      var handlers = Changed;
+      if (handlers != null)
+        handlers(this, e);
+    }
+    #endregion
+
+    #region persistence
+    [Storable]
+    public double KDTreeApproxF {
+      get { return kdTree.approxf; }
+      set { kdTree.approxf = value; }
+    }
+    [Storable]
+    public double[] KDTreeBoxMax {
+      get { return kdTree.boxmax; }
+      set { kdTree.boxmax = value; }
+    }
+    [Storable]
+    public double[] KDTreeBoxMin {
+      get { return kdTree.boxmin; }
+      set { kdTree.boxmin = value; }
+    }
+    [Storable]
+    public double[] KDTreeBuf {
+      get { return kdTree.buf; }
+      set { kdTree.buf = value; }
+    }
+    [Storable]
+    public double[] KDTreeCurBoxMax {
+      get { return kdTree.curboxmax; }
+      set { kdTree.curboxmax = value; }
+    }
+    [Storable]
+    public double[] KDTreeCurBoxMin {
+      get { return kdTree.curboxmin; }
+      set { kdTree.curboxmin = value; }
+    }
+    [Storable]
+    public double KDTreeCurDist {
+      get { return kdTree.curdist; }
+      set { kdTree.curdist = value; }
+    }
+    [Storable]
+    public int KDTreeDebugCounter {
+      get { return kdTree.debugcounter; }
+      set { kdTree.debugcounter = value; }
+    }
+    [Storable]
+    public int[] KDTreeIdx {
+      get { return kdTree.idx; }
+      set { kdTree.idx = value; }
+    }
+    [Storable]
+    public int KDTreeKCur {
+      get { return kdTree.kcur; }
+      set { kdTree.kcur = value; }
+    }
+    [Storable]
+    public int KDTreeKNeeded {
+      get { return kdTree.kneeded; }
+      set { kdTree.kneeded = value; }
+    }
+    [Storable]
+    public int KDTreeN {
+      get { return kdTree.n; }
+      set { kdTree.n = value; }
+    }
+    [Storable]
+    public int[] KDTreeNodes {
+      get { return kdTree.nodes; }
+      set { kdTree.nodes = value; }
+    }
+    [Storable]
+    public int KDTreeNormType {
+      get { return kdTree.normtype; }
+      set { kdTree.normtype = value; }
+    }
+    [Storable]
+    public int KDTreeNX {
+      get { return kdTree.nx; }
+      set { kdTree.nx = value; }
+    }
+    [Storable]
+    public int KDTreeNY {
+      get { return kdTree.ny; }
+      set { kdTree.ny = value; }
+    }
+    [Storable]
+    public double[] KDTreeR {
+      get { return kdTree.r; }
+      set { kdTree.r = value; }
+    }
+    [Storable]
+    public double KDTreeRNeeded {
+      get { return kdTree.rneeded; }
+      set { kdTree.rneeded = value; }
+    }
+    [Storable]
+    public bool KDTreeSelfMatch {
+      get { return kdTree.selfmatch; }
+      set { kdTree.selfmatch = value; }
+    }
+    [Storable]
+    public double[] KDTreeSplits {
+      get { return kdTree.splits; }
+      set { kdTree.splits = value; }
+    }
+    [Storable]
+    public int[] KDTreeTags {
+      get { return kdTree.tags; }
+      set { kdTree.tags = value; }
+    }
+    [Storable]
+    public double[] KDTreeX {
+      get { return kdTree.x; }
+      set { kdTree.x = value; }
+    }
+    [Storable]
+    public double[,] KDTreeXY {
+      get { return kdTree.xy; }
+      set { kdTree.xy = value; }
+    }
+    #endregion
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/NearestNeighbour/NearestNeighbourRegression.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/NearestNeighbour/NearestNeighbourRegression.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/NearestNeighbour/NearestNeighbourRegression.cs	(revision 13819)
@@ -0,0 +1,94 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Optimization;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Problems.DataAnalysis;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  /// <summary>
+  /// Nearest neighbour regression data analysis algorithm.
+  /// </summary>
+  [Item("Nearest Neighbour Regression (kNN)", "Nearest neighbour regression data analysis algorithm (wrapper for ALGLIB).")]
+  [Creatable(CreatableAttribute.Categories.DataAnalysisRegression, Priority = 150)]
+  [StorableClass]
+  public sealed class NearestNeighbourRegression : FixedDataAnalysisAlgorithm<IRegressionProblem> {
+    private const string KParameterName = "K";
+    private const string NearestNeighbourRegressionModelResultName = "Nearest neighbour regression solution";
+
+    #region parameter properties
+    public IFixedValueParameter<IntValue> KParameter {
+      get { return (IFixedValueParameter<IntValue>)Parameters[KParameterName]; }
+    }
+    #endregion
+    #region properties
+    public int K {
+      get { return KParameter.Value.Value; }
+      set {
+        if (value <= 0) throw new ArgumentException("K must be larger than zero.", "K");
+        else KParameter.Value.Value = value;
+      }
+    }
+    #endregion
+
+    [StorableConstructor]
+    private NearestNeighbourRegression(bool deserializing) : base(deserializing) { }
+    private NearestNeighbourRegression(NearestNeighbourRegression original, Cloner cloner)
+      : base(original, cloner) {
+    }
+    public NearestNeighbourRegression()
+      : base() {
+      Parameters.Add(new FixedValueParameter<IntValue>(KParameterName, "The number of nearest neighbours to consider for regression.", new IntValue(3)));
+      Problem = new RegressionProblem();
+    }
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() { }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new NearestNeighbourRegression(this, cloner);
+    }
+
+    #region nearest neighbour
+    protected override void Run() {
+      var solution = CreateNearestNeighbourRegressionSolution(Problem.ProblemData, K);
+      Results.Add(new Result(NearestNeighbourRegressionModelResultName, "The nearest neighbour regression solution.", solution));
+    }
+
+    public static IRegressionSolution CreateNearestNeighbourRegressionSolution(IRegressionProblemData problemData, int k) {
+      var clonedProblemData = (IRegressionProblemData)problemData.Clone();
+      return new NearestNeighbourRegressionSolution(clonedProblemData, Train(problemData, k));
+    }
+
+    public static INearestNeighbourModel Train(IRegressionProblemData problemData, int k) {
+      return new NearestNeighbourModel(problemData.Dataset,
+        problemData.TrainingIndices,
+        k,
+        problemData.TargetVariable,
+        problemData.AllowedInputVariables);
+    }
+    #endregion
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/NearestNeighbour/NearestNeighbourRegressionSolution.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/NearestNeighbour/NearestNeighbourRegressionSolution.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/NearestNeighbour/NearestNeighbourRegressionSolution.cs	(revision 13819)
@@ -0,0 +1,53 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Problems.DataAnalysis;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  /// <summary>
+  /// Represents a nearest neighbour solution for a regression problem which can be visualized in the GUI.
+  /// </summary>
+  [Item("NearestNeighbourRegressionSolution", "Represents a nearest neighbour solution for a regression problem which can be visualized in the GUI.")]
+  [StorableClass]
+  public sealed class NearestNeighbourRegressionSolution : RegressionSolution, INearestNeighbourRegressionSolution {
+
+    public new INearestNeighbourModel Model {
+      get { return (INearestNeighbourModel)base.Model; }
+      set { base.Model = value; }
+    }
+
+    [StorableConstructor]
+    private NearestNeighbourRegressionSolution(bool deserializing) : base(deserializing) { }
+    private NearestNeighbourRegressionSolution(NearestNeighbourRegressionSolution original, Cloner cloner)
+      : base(original, cloner) {
+    }
+    public NearestNeighbourRegressionSolution(IRegressionProblemData problemData, INearestNeighbourModel nnModel)
+      : base(nnModel, problemData) {
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new NearestNeighbourRegressionSolution(this, cloner);
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/NeuralNetwork/NeuralNetworkClassification.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/NeuralNetwork/NeuralNetworkClassification.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/NeuralNetwork/NeuralNetworkClassification.cs	(revision 13819)
@@ -0,0 +1,226 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Optimization;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Problems.DataAnalysis;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  /// <summary>
+  /// Neural network classification data analysis algorithm.
+  /// </summary>
+  [Item("Neural Network Classification (NN)", "Neural network classification data analysis algorithm (wrapper for ALGLIB). Further documentation: http://www.alglib.net/dataanalysis/neuralnetworks.php")]
+  [Creatable(CreatableAttribute.Categories.DataAnalysisClassification, Priority = 130)]
+  [StorableClass]
+  public sealed class NeuralNetworkClassification : FixedDataAnalysisAlgorithm<IClassificationProblem> {
+    private const string DecayParameterName = "Decay";
+    private const string HiddenLayersParameterName = "HiddenLayers";
+    private const string NodesInFirstHiddenLayerParameterName = "NodesInFirstHiddenLayer";
+    private const string NodesInSecondHiddenLayerParameterName = "NodesInSecondHiddenLayer";
+    private const string RestartsParameterName = "Restarts";
+    private const string NeuralNetworkClassificationModelResultName = "Neural network classification solution";
+
+    #region parameter properties
+    public IFixedValueParameter<DoubleValue> DecayParameter {
+      get { return (IFixedValueParameter<DoubleValue>)Parameters[DecayParameterName]; }
+    }
+    public IConstrainedValueParameter<IntValue> HiddenLayersParameter {
+      get { return (IConstrainedValueParameter<IntValue>)Parameters[HiddenLayersParameterName]; }
+    }
+    public IFixedValueParameter<IntValue> NodesInFirstHiddenLayerParameter {
+      get { return (IFixedValueParameter<IntValue>)Parameters[NodesInFirstHiddenLayerParameterName]; }
+    }
+    public IFixedValueParameter<IntValue> NodesInSecondHiddenLayerParameter {
+      get { return (IFixedValueParameter<IntValue>)Parameters[NodesInSecondHiddenLayerParameterName]; }
+    }
+    public IFixedValueParameter<IntValue> RestartsParameter {
+      get { return (IFixedValueParameter<IntValue>)Parameters[RestartsParameterName]; }
+    }
+    #endregion
+
+    #region properties
+    public double Decay {
+      get { return DecayParameter.Value.Value; }
+      set {
+        if (value < 0.001 || value > 100) throw new ArgumentException("The decay parameter should be set to a value between 0.001 and 100.", "Decay");
+        DecayParameter.Value.Value = value;
+      }
+    }
+    public int HiddenLayers {
+      get { return HiddenLayersParameter.Value.Value; }
+      set {
+        if (value < 0 || value > 2) throw new ArgumentException("The number of hidden layers should be set to 0, 1, or 2.", "HiddenLayers");
+        HiddenLayersParameter.Value = (from v in HiddenLayersParameter.ValidValues
+                                       where v.Value == value
+                                       select v)
+                                      .Single();
+      }
+    }
+    public int NodesInFirstHiddenLayer {
+      get { return NodesInFirstHiddenLayerParameter.Value.Value; }
+      set {
+        if (value < 1) throw new ArgumentException("The number of nodes in the first hidden layer must be at least one.", "NodesInFirstHiddenLayer");
+        NodesInFirstHiddenLayerParameter.Value.Value = value;
+      }
+    }
+    public int NodesInSecondHiddenLayer {
+      get { return NodesInSecondHiddenLayerParameter.Value.Value; }
+      set {
+        if (value < 1) throw new ArgumentException("The number of nodes in the first second layer must be at least one.", "NodesInSecondHiddenLayer");
+        NodesInSecondHiddenLayerParameter.Value.Value = value;
+      }
+    }
+    public int Restarts {
+      get { return RestartsParameter.Value.Value; }
+      set {
+        if (value < 0) throw new ArgumentException("The number of restarts must be positive.", "Restarts");
+        RestartsParameter.Value.Value = value;
+      }
+    }
+    #endregion
+
+
+    [StorableConstructor]
+    private NeuralNetworkClassification(bool deserializing) : base(deserializing) { }
+    private NeuralNetworkClassification(NeuralNetworkClassification original, Cloner cloner)
+      : base(original, cloner) {
+      RegisterEventHandlers();
+    }
+    public NeuralNetworkClassification()
+      : base() {
+      var validHiddenLayerValues = new ItemSet<IntValue>(new IntValue[] { 
+        (IntValue)new IntValue(0).AsReadOnly(), 
+        (IntValue)new IntValue(1).AsReadOnly(), 
+        (IntValue)new IntValue(2).AsReadOnly() });
+      var selectedHiddenLayerValue = (from v in validHiddenLayerValues
+                                      where v.Value == 1
+                                      select v)
+                                     .Single();
+      Parameters.Add(new FixedValueParameter<DoubleValue>(DecayParameterName, "The decay parameter for the training phase of the neural network. This parameter determines the strengh of regularization and should be set to a value between 0.001 (weak regularization) to 100 (very strong regularization). The correct value should be determined via cross-validation.", new DoubleValue(1)));
+      Parameters.Add(new ConstrainedValueParameter<IntValue>(HiddenLayersParameterName, "The number of hidden layers for the neural network (0, 1, or 2)", validHiddenLayerValues, selectedHiddenLayerValue));
+      Parameters.Add(new FixedValueParameter<IntValue>(NodesInFirstHiddenLayerParameterName, "The number of nodes in the first hidden layer. This value is not used if the number of hidden layers is zero.", new IntValue(10)));
+      Parameters.Add(new FixedValueParameter<IntValue>(NodesInSecondHiddenLayerParameterName, "The number of nodes in the second hidden layer. This value is not used if the number of hidden layers is zero or one.", new IntValue(10)));
+      Parameters.Add(new FixedValueParameter<IntValue>(RestartsParameterName, "The number of restarts for learning.", new IntValue(2)));
+
+      RestartsParameter.Hidden = true;
+      NodesInSecondHiddenLayerParameter.Hidden = true;
+
+      RegisterEventHandlers();
+
+      Problem = new ClassificationProblem();
+    }
+
+    private void RegisterEventHandlers() {
+      HiddenLayersParameter.Value.ValueChanged += HiddenLayersParameterValueValueChanged;
+      HiddenLayersParameter.ValueChanged += HiddenLayersParameterValueChanged;
+    }
+
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() {
+      RegisterEventHandlers();
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new NeuralNetworkClassification(this, cloner);
+    }
+    private void HiddenLayersParameterValueChanged(object source, EventArgs e) {
+      HiddenLayersParameter.Value.ValueChanged += HiddenLayersParameterValueValueChanged;
+      HiddenLayersParameterValueValueChanged(this, EventArgs.Empty);
+    }
+
+    private void HiddenLayersParameterValueValueChanged(object source, EventArgs e) {
+      if (HiddenLayers == 0) {
+        NodesInFirstHiddenLayerParameter.Hidden = true;
+        NodesInSecondHiddenLayerParameter.Hidden = true;
+      } else if (HiddenLayers == 1) {
+        NodesInFirstHiddenLayerParameter.Hidden = false;
+        NodesInSecondHiddenLayerParameter.Hidden = true;
+      } else {
+        NodesInFirstHiddenLayerParameter.Hidden = false;
+        NodesInSecondHiddenLayerParameter.Hidden = false;
+      }
+    }
+
+    #region neural network
+    protected override void Run() {
+      double rmsError, avgRelError, relClassError;
+      var solution = CreateNeuralNetworkClassificationSolution(Problem.ProblemData, HiddenLayers, NodesInFirstHiddenLayer, NodesInSecondHiddenLayer, Decay, Restarts, out rmsError, out avgRelError, out relClassError);
+      Results.Add(new Result(NeuralNetworkClassificationModelResultName, "The neural network classification solution.", solution));
+      Results.Add(new Result("Root mean square error", "The root of the mean of squared errors of the neural network classification solution on the training set.", new DoubleValue(rmsError)));
+      Results.Add(new Result("Average relative error", "The average of relative errors of the neural network classification solution on the training set.", new PercentValue(avgRelError)));
+      Results.Add(new Result("Relative classification error", "The percentage of misclassified samples.", new PercentValue(relClassError)));
+    }
+
+    public static IClassificationSolution CreateNeuralNetworkClassificationSolution(IClassificationProblemData problemData, int nLayers, int nHiddenNodes1, int nHiddenNodes2, double decay, int restarts,
+      out double rmsError, out double avgRelError, out double relClassError) {
+      var dataset = problemData.Dataset;
+      string targetVariable = problemData.TargetVariable;
+      IEnumerable<string> allowedInputVariables = problemData.AllowedInputVariables;
+      IEnumerable<int> rows = problemData.TrainingIndices;
+      double[,] inputMatrix = AlglibUtil.PrepareInputMatrix(dataset, allowedInputVariables.Concat(new string[] { targetVariable }), rows);
+      if (inputMatrix.Cast<double>().Any(x => double.IsNaN(x) || double.IsInfinity(x)))
+        throw new NotSupportedException("Neural network classification does not support NaN or infinity values in the input dataset.");
+
+      int nRows = inputMatrix.GetLength(0);
+      int nFeatures = inputMatrix.GetLength(1) - 1;
+      double[] classValues = dataset.GetDoubleValues(targetVariable).Distinct().OrderBy(x => x).ToArray();
+      int nClasses = classValues.Count();
+      // map original class values to values [0..nClasses-1]
+      Dictionary<double, double> classIndices = new Dictionary<double, double>();
+      for (int i = 0; i < nClasses; i++) {
+        classIndices[classValues[i]] = i;
+      }
+      for (int row = 0; row < nRows; row++) {
+        inputMatrix[row, nFeatures] = classIndices[inputMatrix[row, nFeatures]];
+      }
+
+      alglib.multilayerperceptron multiLayerPerceptron = null;
+      if (nLayers == 0) {
+        alglib.mlpcreatec0(allowedInputVariables.Count(), nClasses, out multiLayerPerceptron);
+      } else if (nLayers == 1) {
+        alglib.mlpcreatec1(allowedInputVariables.Count(), nHiddenNodes1, nClasses, out multiLayerPerceptron);
+      } else if (nLayers == 2) {
+        alglib.mlpcreatec2(allowedInputVariables.Count(), nHiddenNodes1, nHiddenNodes2, nClasses, out multiLayerPerceptron);
+      } else throw new ArgumentException("Number of layers must be zero, one, or two.", "nLayers");
+      alglib.mlpreport rep;
+
+      int info;
+      // using mlptrainlm instead of mlptraines or mlptrainbfgs because only one parameter is necessary
+      alglib.mlptrainlm(multiLayerPerceptron, inputMatrix, nRows, decay, restarts, out info, out rep);
+      if (info != 2) throw new ArgumentException("Error in calculation of neural network classification solution");
+
+      rmsError = alglib.mlprmserror(multiLayerPerceptron, inputMatrix, nRows);
+      avgRelError = alglib.mlpavgrelerror(multiLayerPerceptron, inputMatrix, nRows);
+      relClassError = alglib.mlpclserror(multiLayerPerceptron, inputMatrix, nRows) / (double)nRows;
+
+      var problemDataClone = (IClassificationProblemData)problemData.Clone();
+      return new NeuralNetworkClassificationSolution(problemDataClone, new NeuralNetworkModel(multiLayerPerceptron, targetVariable, allowedInputVariables, problemDataClone.ClassValues.ToArray()));
+    }
+    #endregion
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/NeuralNetwork/NeuralNetworkClassificationSolution.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/NeuralNetwork/NeuralNetworkClassificationSolution.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/NeuralNetwork/NeuralNetworkClassificationSolution.cs	(revision 13819)
@@ -0,0 +1,54 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Problems.DataAnalysis;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  /// <summary>
+  /// Represents a neural network solution for a classification problem which can be visualized in the GUI.
+  /// </summary>
+  [Item("NeuralNetworkClassificationSolution", "Represents a neural network solution for a classification problem which can be visualized in the GUI.")]
+  [StorableClass]
+  public sealed class NeuralNetworkClassificationSolution : ClassificationSolution, INeuralNetworkClassificationSolution {
+
+    public new INeuralNetworkModel Model {
+      get { return (INeuralNetworkModel)base.Model; }
+      set { base.Model = value; }
+    }
+
+    [StorableConstructor]
+    private NeuralNetworkClassificationSolution(bool deserializing) : base(deserializing) { }
+    private NeuralNetworkClassificationSolution(NeuralNetworkClassificationSolution original, Cloner cloner)
+      : base(original, cloner) {
+    }
+    public NeuralNetworkClassificationSolution(IClassificationProblemData problemData, INeuralNetworkModel nnModel)
+      : base(nnModel, problemData) {
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new NeuralNetworkClassificationSolution(this, cloner);
+    }
+
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/NeuralNetwork/NeuralNetworkEnsembleClassification.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/NeuralNetwork/NeuralNetworkEnsembleClassification.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/NeuralNetwork/NeuralNetworkEnsembleClassification.cs	(revision 13819)
@@ -0,0 +1,210 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Optimization;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Problems.DataAnalysis;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  /// <summary>
+  /// Neural network ensemble classification data analysis algorithm.
+  /// </summary>
+  [Item("Neural Network Ensemble Classification (NN)", "Neural network ensemble classification data analysis algorithm (wrapper for ALGLIB). Further documentation: http://www.alglib.net/dataanalysis/mlpensembles.php")]
+  [Creatable(CreatableAttribute.Categories.DataAnalysisClassification, Priority = 140)]
+  [StorableClass]
+  public sealed class NeuralNetworkEnsembleClassification : FixedDataAnalysisAlgorithm<IClassificationProblem> {
+    private const string EnsembleSizeParameterName = "EnsembleSize";
+    private const string DecayParameterName = "Decay";
+    private const string HiddenLayersParameterName = "HiddenLayers";
+    private const string NodesInFirstHiddenLayerParameterName = "NodesInFirstHiddenLayer";
+    private const string NodesInSecondHiddenLayerParameterName = "NodesInSecondHiddenLayer";
+    private const string RestartsParameterName = "Restarts";
+    private const string NeuralNetworkEnsembleClassificationModelResultName = "Neural network ensemble classification solution";
+
+    #region parameter properties
+    public IFixedValueParameter<IntValue> EnsembleSizeParameter {
+      get { return (IFixedValueParameter<IntValue>)Parameters[EnsembleSizeParameterName]; }
+    }
+    public IFixedValueParameter<DoubleValue> DecayParameter {
+      get { return (IFixedValueParameter<DoubleValue>)Parameters[DecayParameterName]; }
+    }
+    public IConstrainedValueParameter<IntValue> HiddenLayersParameter {
+      get { return (IConstrainedValueParameter<IntValue>)Parameters[HiddenLayersParameterName]; }
+    }
+    public IFixedValueParameter<IntValue> NodesInFirstHiddenLayerParameter {
+      get { return (IFixedValueParameter<IntValue>)Parameters[NodesInFirstHiddenLayerParameterName]; }
+    }
+    public IFixedValueParameter<IntValue> NodesInSecondHiddenLayerParameter {
+      get { return (IFixedValueParameter<IntValue>)Parameters[NodesInSecondHiddenLayerParameterName]; }
+    }
+    public IFixedValueParameter<IntValue> RestartsParameter {
+      get { return (IFixedValueParameter<IntValue>)Parameters[RestartsParameterName]; }
+    }
+    #endregion
+
+    #region properties
+    public int EnsembleSize {
+      get { return EnsembleSizeParameter.Value.Value; }
+      set {
+        if (value < 1) throw new ArgumentException("The number of models in the ensemble must be positive and at least one.", "EnsembleSize");
+        EnsembleSizeParameter.Value.Value = value;
+      }
+    }
+    public double Decay {
+      get { return DecayParameter.Value.Value; }
+      set {
+        if (value < 0.001 || value > 100) throw new ArgumentException("The decay parameter should be set to a value between 0.001 and 100.", "Decay");
+        DecayParameter.Value.Value = value;
+      }
+    }
+    public int HiddenLayers {
+      get { return HiddenLayersParameter.Value.Value; }
+      set {
+        if (value < 0 || value > 2) throw new ArgumentException("The number of hidden layers should be set to 0, 1, or 2.", "HiddenLayers");
+        HiddenLayersParameter.Value = (from v in HiddenLayersParameter.ValidValues
+                                       where v.Value == value
+                                       select v)
+                                      .Single();
+      }
+    }
+    public int NodesInFirstHiddenLayer {
+      get { return NodesInFirstHiddenLayerParameter.Value.Value; }
+      set {
+        if (value < 1) throw new ArgumentException("The number of nodes in the first hidden layer must be at least one.", "NodesInFirstHiddenLayer");
+        NodesInFirstHiddenLayerParameter.Value.Value = value;
+      }
+    }
+    public int NodesInSecondHiddenLayer {
+      get { return NodesInSecondHiddenLayerParameter.Value.Value; }
+      set {
+        if (value < 1) throw new ArgumentException("The number of nodes in the first second layer must be at least one.", "NodesInSecondHiddenLayer");
+        NodesInSecondHiddenLayerParameter.Value.Value = value;
+      }
+    }
+    public int Restarts {
+      get { return RestartsParameter.Value.Value; }
+      set {
+        if (value < 0) throw new ArgumentException("The number of restarts must be positive.", "Restarts");
+        RestartsParameter.Value.Value = value;
+      }
+    }
+    #endregion
+
+
+    [StorableConstructor]
+    private NeuralNetworkEnsembleClassification(bool deserializing) : base(deserializing) { }
+    private NeuralNetworkEnsembleClassification(NeuralNetworkEnsembleClassification original, Cloner cloner)
+      : base(original, cloner) {
+    }
+    public NeuralNetworkEnsembleClassification()
+      : base() {
+      var validHiddenLayerValues = new ItemSet<IntValue>(new IntValue[] { 
+        (IntValue)new IntValue(0).AsReadOnly(), 
+        (IntValue)new IntValue(1).AsReadOnly(), 
+        (IntValue)new IntValue(2).AsReadOnly() });
+      var selectedHiddenLayerValue = (from v in validHiddenLayerValues
+                                      where v.Value == 1
+                                      select v)
+                                     .Single();
+      Parameters.Add(new FixedValueParameter<IntValue>(EnsembleSizeParameterName, "The number of simple neural network models in the ensemble. A good value is 10.", new IntValue(10)));
+      Parameters.Add(new FixedValueParameter<DoubleValue>(DecayParameterName, "The decay parameter for the training phase of the neural network. This parameter determines the strengh of regularization and should be set to a value between 0.001 (weak regularization) to 100 (very strong regularization). The correct value should be determined via cross-validation.", new DoubleValue(0.001)));
+      Parameters.Add(new ConstrainedValueParameter<IntValue>(HiddenLayersParameterName, "The number of hidden layers for the neural network (0, 1, or 2)", validHiddenLayerValues, selectedHiddenLayerValue));
+      Parameters.Add(new FixedValueParameter<IntValue>(NodesInFirstHiddenLayerParameterName, "The number of nodes in the first hidden layer. The value should be rather large (30-100 nodes) in order to make the network highly flexible and run into the early stopping criterion). This value is not used if the number of hidden layers is zero.", new IntValue(100)));
+      Parameters.Add(new FixedValueParameter<IntValue>(NodesInSecondHiddenLayerParameterName, "The number of nodes in the second hidden layer. This value is not used if the number of hidden layers is zero or one.", new IntValue(100)));
+      Parameters.Add(new FixedValueParameter<IntValue>(RestartsParameterName, "The number of restarts for learning.", new IntValue(2)));
+
+      HiddenLayersParameter.Hidden = true;
+      NodesInFirstHiddenLayerParameter.Hidden = true;
+      NodesInSecondHiddenLayerParameter.Hidden = true;
+      RestartsParameter.Hidden = true;
+
+      Problem = new ClassificationProblem();
+    }
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() { }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new NeuralNetworkEnsembleClassification(this, cloner);
+    }
+
+    #region neural network ensemble
+    protected override void Run() {
+      double rmsError, avgRelError, relClassError;
+      var solution = CreateNeuralNetworkEnsembleClassificationSolution(Problem.ProblemData, EnsembleSize, HiddenLayers, NodesInFirstHiddenLayer, NodesInSecondHiddenLayer, Decay, Restarts, out rmsError, out avgRelError, out relClassError);
+      Results.Add(new Result(NeuralNetworkEnsembleClassificationModelResultName, "The neural network ensemble classification solution.", solution));
+      Results.Add(new Result("Root mean square error", "The root of the mean of squared errors of the neural network ensemble classification solution on the training set.", new DoubleValue(rmsError)));
+      Results.Add(new Result("Average relative error", "The average of relative errors of the neural network ensemble classification solution on the training set.", new PercentValue(avgRelError)));
+      Results.Add(new Result("Relative classification error", "The percentage of misclassified samples.", new PercentValue(relClassError)));
+    }
+
+    public static IClassificationSolution CreateNeuralNetworkEnsembleClassificationSolution(IClassificationProblemData problemData, int ensembleSize, int nLayers, int nHiddenNodes1, int nHiddenNodes2, double decay, int restarts,
+      out double rmsError, out double avgRelError, out double relClassError) {
+      var dataset = problemData.Dataset;
+      string targetVariable = problemData.TargetVariable;
+      IEnumerable<string> allowedInputVariables = problemData.AllowedInputVariables;
+      IEnumerable<int> rows = problemData.TrainingIndices;
+      double[,] inputMatrix = AlglibUtil.PrepareInputMatrix(dataset, allowedInputVariables.Concat(new string[] { targetVariable }), rows);
+      if (inputMatrix.Cast<double>().Any(x => double.IsNaN(x) || double.IsInfinity(x)))
+        throw new NotSupportedException("Neural network ensemble classification does not support NaN or infinity values in the input dataset.");
+
+      int nRows = inputMatrix.GetLength(0);
+      int nFeatures = inputMatrix.GetLength(1) - 1;
+      double[] classValues = dataset.GetDoubleValues(targetVariable).Distinct().OrderBy(x => x).ToArray();
+      int nClasses = classValues.Count();
+      // map original class values to values [0..nClasses-1]
+      Dictionary<double, double> classIndices = new Dictionary<double, double>();
+      for (int i = 0; i < nClasses; i++) {
+        classIndices[classValues[i]] = i;
+      }
+      for (int row = 0; row < nRows; row++) {
+        inputMatrix[row, nFeatures] = classIndices[inputMatrix[row, nFeatures]];
+      }
+
+      alglib.mlpensemble mlpEnsemble = null;
+      if (nLayers == 0) {
+        alglib.mlpecreatec0(allowedInputVariables.Count(), nClasses, ensembleSize, out mlpEnsemble);
+      } else if (nLayers == 1) {
+        alglib.mlpecreatec1(allowedInputVariables.Count(), nHiddenNodes1, nClasses, ensembleSize, out mlpEnsemble);
+      } else if (nLayers == 2) {
+        alglib.mlpecreatec2(allowedInputVariables.Count(), nHiddenNodes1, nHiddenNodes2, nClasses, ensembleSize, out mlpEnsemble);
+      } else throw new ArgumentException("Number of layers must be zero, one, or two.", "nLayers");
+      alglib.mlpreport rep;
+
+      int info;
+      alglib.mlpetraines(mlpEnsemble, inputMatrix, nRows, decay, restarts, out info, out rep);
+      if (info != 6) throw new ArgumentException("Error in calculation of neural network ensemble classification solution");
+
+      rmsError = alglib.mlpermserror(mlpEnsemble, inputMatrix, nRows);
+      avgRelError = alglib.mlpeavgrelerror(mlpEnsemble, inputMatrix, nRows);
+      relClassError = alglib.mlperelclserror(mlpEnsemble, inputMatrix, nRows);
+      var problemDataClone = (IClassificationProblemData)problemData.Clone();
+      return new NeuralNetworkEnsembleClassificationSolution(problemDataClone, new NeuralNetworkEnsembleModel(mlpEnsemble, targetVariable, allowedInputVariables, problemDataClone.ClassValues.ToArray()));
+    }
+    #endregion
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/NeuralNetwork/NeuralNetworkEnsembleClassificationSolution.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/NeuralNetwork/NeuralNetworkEnsembleClassificationSolution.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/NeuralNetwork/NeuralNetworkEnsembleClassificationSolution.cs	(revision 13819)
@@ -0,0 +1,53 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Problems.DataAnalysis;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  /// <summary>
+  /// Represents a neural network ensemble solution for a classification problem which can be visualized in the GUI.
+  /// </summary>
+  [Item("NeuralNetworkEnsembleClassificationSolution", "Represents a neural network ensemble solution for a classification problem which can be visualized in the GUI.")]
+  [StorableClass]
+  public sealed class NeuralNetworkEnsembleClassificationSolution : ClassificationSolution, INeuralNetworkEnsembleClassificationSolution {
+
+    public new INeuralNetworkEnsembleModel Model {
+      get { return (INeuralNetworkEnsembleModel)base.Model; }
+      set { base.Model = value; }
+    }
+
+    [StorableConstructor]
+    private NeuralNetworkEnsembleClassificationSolution(bool deserializing) : base(deserializing) { }
+    private NeuralNetworkEnsembleClassificationSolution(NeuralNetworkEnsembleClassificationSolution original, Cloner cloner)
+      : base(original, cloner) {
+    }
+    public NeuralNetworkEnsembleClassificationSolution(IClassificationProblemData problemData, INeuralNetworkEnsembleModel nnModel)
+      : base(nnModel, problemData) {
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new NeuralNetworkEnsembleClassificationSolution(this, cloner);
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/NeuralNetwork/NeuralNetworkEnsembleModel.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/NeuralNetwork/NeuralNetworkEnsembleModel.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/NeuralNetwork/NeuralNetworkEnsembleModel.cs	(revision 13819)
@@ -0,0 +1,235 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Problems.DataAnalysis;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  /// <summary>
+  /// Represents a neural network ensembel model for regression and classification
+  /// </summary>
+  [StorableClass]
+  [Item("NeuralNetworkEnsembleModel", "Represents a neural network ensemble for regression and classification.")]
+  public sealed class NeuralNetworkEnsembleModel : NamedItem, INeuralNetworkEnsembleModel {
+
+    private alglib.mlpensemble mlpEnsemble;
+    public alglib.mlpensemble MultiLayerPerceptronEnsemble {
+      get { return mlpEnsemble; }
+      set {
+        if (value != mlpEnsemble) {
+          if (value == null) throw new ArgumentNullException();
+          mlpEnsemble = value;
+          OnChanged(EventArgs.Empty);
+        }
+      }
+    }
+
+    [Storable]
+    private string targetVariable;
+    [Storable]
+    private string[] allowedInputVariables;
+    [Storable]
+    private double[] classValues;
+    [StorableConstructor]
+    private NeuralNetworkEnsembleModel(bool deserializing)
+      : base(deserializing) {
+      if (deserializing)
+        mlpEnsemble = new alglib.mlpensemble();
+    }
+    private NeuralNetworkEnsembleModel(NeuralNetworkEnsembleModel original, Cloner cloner)
+      : base(original, cloner) {
+      mlpEnsemble = new alglib.mlpensemble();
+      string serializedEnsemble;
+      alglib.mlpeserialize(original.mlpEnsemble, out serializedEnsemble);
+      alglib.mlpeunserialize(serializedEnsemble, out this.mlpEnsemble);
+      targetVariable = original.targetVariable;
+      allowedInputVariables = (string[])original.allowedInputVariables.Clone();
+      if (original.classValues != null)
+        this.classValues = (double[])original.classValues.Clone();
+    }
+    public NeuralNetworkEnsembleModel(alglib.mlpensemble mlpEnsemble, string targetVariable, IEnumerable<string> allowedInputVariables, double[] classValues = null)
+      : base() {
+      this.name = ItemName;
+      this.description = ItemDescription;
+      this.mlpEnsemble = mlpEnsemble;
+      this.targetVariable = targetVariable;
+      this.allowedInputVariables = allowedInputVariables.ToArray();
+      if (classValues != null)
+        this.classValues = (double[])classValues.Clone();
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new NeuralNetworkEnsembleModel(this, cloner);
+    }
+
+    public IEnumerable<double> GetEstimatedValues(IDataset dataset, IEnumerable<int> rows) {
+      double[,] inputData = AlglibUtil.PrepareInputMatrix(dataset, allowedInputVariables, rows);
+
+      int n = inputData.GetLength(0);
+      int columns = inputData.GetLength(1);
+      double[] x = new double[columns];
+      double[] y = new double[1];
+
+      for (int row = 0; row < n; row++) {
+        for (int column = 0; column < columns; column++) {
+          x[column] = inputData[row, column];
+        }
+        alglib.mlpeprocess(mlpEnsemble, x, ref y);
+        yield return y[0];
+      }
+    }
+
+    public IEnumerable<double> GetEstimatedClassValues(IDataset dataset, IEnumerable<int> rows) {
+      double[,] inputData = AlglibUtil.PrepareInputMatrix(dataset, allowedInputVariables, rows);
+
+      int n = inputData.GetLength(0);
+      int columns = inputData.GetLength(1);
+      double[] x = new double[columns];
+      double[] y = new double[classValues.Length];
+
+      for (int row = 0; row < n; row++) {
+        for (int column = 0; column < columns; column++) {
+          x[column] = inputData[row, column];
+        }
+        alglib.mlpeprocess(mlpEnsemble, x, ref y);
+        // find class for with the largest probability value
+        int maxProbClassIndex = 0;
+        double maxProb = y[0];
+        for (int i = 1; i < y.Length; i++) {
+          if (maxProb < y[i]) {
+            maxProb = y[i];
+            maxProbClassIndex = i;
+          }
+        }
+        yield return classValues[maxProbClassIndex];
+      }
+    }
+
+    public INeuralNetworkEnsembleRegressionSolution CreateRegressionSolution(IRegressionProblemData problemData) {
+      return new NeuralNetworkEnsembleRegressionSolution(new RegressionEnsembleProblemData(problemData), this);
+    }
+    IRegressionSolution IRegressionModel.CreateRegressionSolution(IRegressionProblemData problemData) {
+      return CreateRegressionSolution(problemData);
+    }
+    public INeuralNetworkEnsembleClassificationSolution CreateClassificationSolution(IClassificationProblemData problemData) {
+      return new NeuralNetworkEnsembleClassificationSolution(new ClassificationEnsembleProblemData(problemData), this);
+    }
+    IClassificationSolution IClassificationModel.CreateClassificationSolution(IClassificationProblemData problemData) {
+      return CreateClassificationSolution(problemData);
+    }
+
+    #region events
+    public event EventHandler Changed;
+    private void OnChanged(EventArgs e) {
+      var handlers = Changed;
+      if (handlers != null)
+        handlers(this, e);
+    }
+    #endregion
+
+    #region persistence
+    [Storable]
+    private string MultiLayerPerceptronEnsembleNetwork {
+      get {
+        string serializedNetwork;
+        alglib.mlpeserialize(this.mlpEnsemble, out serializedNetwork);
+        return serializedNetwork;
+      }
+      set {
+        alglib.mlpeunserialize(value, out this.mlpEnsemble);
+      }
+    }
+
+    [Storable]
+    private double[] MultiLayerPerceptronEnsembleColumnMeans {
+      get { return mlpEnsemble.innerobj.columnmeans; }
+      set {
+        mlpEnsemble.innerobj.columnmeans = value;
+        mlpEnsemble.innerobj.network.columnmeans = value;
+      }
+    }
+    [Storable]
+    private double[] MultiLayerPerceptronEnsembleColumnSigmas {
+      get { return mlpEnsemble.innerobj.columnsigmas; }
+      set {
+        mlpEnsemble.innerobj.columnsigmas = value;
+        mlpEnsemble.innerobj.network.columnsigmas = value;
+      }
+    }
+    [Storable(AllowOneWay = true)]
+    private double[] MultiLayerPerceptronEnsembleDfdnet {
+      set {
+        mlpEnsemble.innerobj.network.dfdnet = value;
+      }
+    }
+    [Storable]
+    private int MultiLayerPerceptronEnsembleSize {
+      get { return mlpEnsemble.innerobj.ensemblesize; }
+      set {
+        mlpEnsemble.innerobj.ensemblesize = value;
+        mlpEnsemble.innerobj.ensemblesize = value;
+      }
+    }
+    [Storable(AllowOneWay = true)]
+    private double[] MultiLayerPerceptronEnsembleNeurons {
+      set { mlpEnsemble.innerobj.network.neurons = value; }
+    }
+    [Storable(AllowOneWay = true)]
+    private double[] MultiLayerPerceptronEnsembleSerializedMlp {
+      set {
+        mlpEnsemble.innerobj.network.dfdnet = value;
+      }
+    }
+    [Storable(AllowOneWay = true)]
+    private int[] MultiLayerPerceptronStuctinfo {
+      set {
+        mlpEnsemble.innerobj.network.structinfo = value;
+      }
+    }
+
+    [Storable]
+    private double[] MultiLayerPerceptronWeights {
+      get {
+        return mlpEnsemble.innerobj.weights;
+      }
+      set {
+        mlpEnsemble.innerobj.weights = value;
+        mlpEnsemble.innerobj.network.weights = value;
+      }
+    }
+    [Storable]
+    private double[] MultiLayerPerceptronY {
+      get {
+        return mlpEnsemble.innerobj.y;
+      }
+      set {
+        mlpEnsemble.innerobj.y = value;
+        mlpEnsemble.innerobj.network.y = value;
+      }
+    }
+    #endregion
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/NeuralNetwork/NeuralNetworkEnsembleRegression.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/NeuralNetwork/NeuralNetworkEnsembleRegression.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/NeuralNetwork/NeuralNetworkEnsembleRegression.cs	(revision 13819)
@@ -0,0 +1,196 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Optimization;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Problems.DataAnalysis;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  /// <summary>
+  /// Neural network ensemble regression data analysis algorithm.
+  /// </summary>
+  [Item("Neural Network Ensemble Regression (NN)", "Neural network ensemble regression data analysis algorithm (wrapper for ALGLIB). Further documentation: http://www.alglib.net/dataanalysis/mlpensembles.php")]
+  [Creatable(CreatableAttribute.Categories.DataAnalysisRegression, Priority = 140)]
+  [StorableClass]
+  public sealed class NeuralNetworkEnsembleRegression : FixedDataAnalysisAlgorithm<IRegressionProblem> {
+    private const string EnsembleSizeParameterName = "EnsembleSize";
+    private const string DecayParameterName = "Decay";
+    private const string HiddenLayersParameterName = "HiddenLayers";
+    private const string NodesInFirstHiddenLayerParameterName = "NodesInFirstHiddenLayer";
+    private const string NodesInSecondHiddenLayerParameterName = "NodesInSecondHiddenLayer";
+    private const string RestartsParameterName = "Restarts";
+    private const string NeuralNetworkEnsembleRegressionModelResultName = "Neural network ensemble regression solution";
+
+    #region parameter properties
+    public IFixedValueParameter<IntValue> EnsembleSizeParameter {
+      get { return (IFixedValueParameter<IntValue>)Parameters[EnsembleSizeParameterName]; }
+    }
+    public IFixedValueParameter<DoubleValue> DecayParameter {
+      get { return (IFixedValueParameter<DoubleValue>)Parameters[DecayParameterName]; }
+    }
+    public IConstrainedValueParameter<IntValue> HiddenLayersParameter {
+      get { return (IConstrainedValueParameter<IntValue>)Parameters[HiddenLayersParameterName]; }
+    }
+    public IFixedValueParameter<IntValue> NodesInFirstHiddenLayerParameter {
+      get { return (IFixedValueParameter<IntValue>)Parameters[NodesInFirstHiddenLayerParameterName]; }
+    }
+    public IFixedValueParameter<IntValue> NodesInSecondHiddenLayerParameter {
+      get { return (IFixedValueParameter<IntValue>)Parameters[NodesInSecondHiddenLayerParameterName]; }
+    }
+    public IFixedValueParameter<IntValue> RestartsParameter {
+      get { return (IFixedValueParameter<IntValue>)Parameters[RestartsParameterName]; }
+    }
+    #endregion
+
+    #region properties
+    public int EnsembleSize {
+      get { return EnsembleSizeParameter.Value.Value; }
+      set {
+        if (value < 1) throw new ArgumentException("The number of models in the ensemble must be positive and at least one.", "EnsembleSize");
+        EnsembleSizeParameter.Value.Value = value;
+      }
+    }
+    public double Decay {
+      get { return DecayParameter.Value.Value; }
+      set {
+        if (value < 0.001 || value > 100) throw new ArgumentException("The decay parameter should be set to a value between 0.001 and 100.", "Decay");
+        DecayParameter.Value.Value = value;
+      }
+    }
+    public int HiddenLayers {
+      get { return HiddenLayersParameter.Value.Value; }
+      set {
+        if (value < 0 || value > 2) throw new ArgumentException("The number of hidden layers should be set to 0, 1, or 2.", "HiddenLayers");
+        HiddenLayersParameter.Value = (from v in HiddenLayersParameter.ValidValues
+                                       where v.Value == value
+                                       select v)
+                                      .Single();
+      }
+    }
+    public int NodesInFirstHiddenLayer {
+      get { return NodesInFirstHiddenLayerParameter.Value.Value; }
+      set {
+        if (value < 1) throw new ArgumentException("The number of nodes in the first hidden layer must be at least one.", "NodesInFirstHiddenLayer");
+        NodesInFirstHiddenLayerParameter.Value.Value = value;
+      }
+    }
+    public int NodesInSecondHiddenLayer {
+      get { return NodesInSecondHiddenLayerParameter.Value.Value; }
+      set {
+        if (value < 1) throw new ArgumentException("The number of nodes in the first second layer must be at least one.", "NodesInSecondHiddenLayer");
+        NodesInSecondHiddenLayerParameter.Value.Value = value;
+      }
+    }
+    public int Restarts {
+      get { return RestartsParameter.Value.Value; }
+      set {
+        if (value < 0) throw new ArgumentException("The number of restarts must be positive.", "Restarts");
+        RestartsParameter.Value.Value = value;
+      }
+    }
+    #endregion
+
+
+    [StorableConstructor]
+    private NeuralNetworkEnsembleRegression(bool deserializing) : base(deserializing) { }
+    private NeuralNetworkEnsembleRegression(NeuralNetworkEnsembleRegression original, Cloner cloner)
+      : base(original, cloner) {
+    }
+    public NeuralNetworkEnsembleRegression()
+      : base() {
+      var validHiddenLayerValues = new ItemSet<IntValue>(new IntValue[] { 
+        (IntValue)new IntValue(0).AsReadOnly(), 
+        (IntValue)new IntValue(1).AsReadOnly(), 
+        (IntValue)new IntValue(2).AsReadOnly() });
+      var selectedHiddenLayerValue = (from v in validHiddenLayerValues
+                                      where v.Value == 1
+                                      select v)
+                                     .Single();
+      Parameters.Add(new FixedValueParameter<IntValue>(EnsembleSizeParameterName, "The number of simple neural network models in the ensemble. A good value is 10.", new IntValue(10)));
+      Parameters.Add(new FixedValueParameter<DoubleValue>(DecayParameterName, "The decay parameter for the training phase of the neural network. This parameter determines the strengh of regularization and should be set to a value between 0.001 (weak regularization) to 100 (very strong regularization). The correct value should be determined via cross-validation.", new DoubleValue(0.001)));
+      Parameters.Add(new ConstrainedValueParameter<IntValue>(HiddenLayersParameterName, "The number of hidden layers for the neural network (0, 1, or 2)", validHiddenLayerValues, selectedHiddenLayerValue));
+      Parameters.Add(new FixedValueParameter<IntValue>(NodesInFirstHiddenLayerParameterName, "The number of nodes in the first hidden layer. The value should be rather large (30-100 nodes) in order to make the network highly flexible and run into the early stopping criterion). This value is not used if the number of hidden layers is zero.", new IntValue(100)));
+      Parameters.Add(new FixedValueParameter<IntValue>(NodesInSecondHiddenLayerParameterName, "The number of nodes in the second hidden layer. This value is not used if the number of hidden layers is zero or one.", new IntValue(100)));
+      Parameters.Add(new FixedValueParameter<IntValue>(RestartsParameterName, "The number of restarts for learning.", new IntValue(2)));
+
+      HiddenLayersParameter.Hidden = true;
+      NodesInFirstHiddenLayerParameter.Hidden = true;
+      NodesInSecondHiddenLayerParameter.Hidden = true;
+      RestartsParameter.Hidden = true;
+
+      Problem = new RegressionProblem();
+    }
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() { }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new NeuralNetworkEnsembleRegression(this, cloner);
+    }
+
+    #region neural network ensemble
+    protected override void Run() {
+      double rmsError, avgRelError;
+      var solution = CreateNeuralNetworkEnsembleRegressionSolution(Problem.ProblemData, EnsembleSize, HiddenLayers, NodesInFirstHiddenLayer, NodesInSecondHiddenLayer, Decay, Restarts, out rmsError, out avgRelError);
+      Results.Add(new Result(NeuralNetworkEnsembleRegressionModelResultName, "The neural network ensemble regression solution.", solution));
+      Results.Add(new Result("Root mean square error", "The root of the mean of squared errors of the neural network ensemble regression solution on the training set.", new DoubleValue(rmsError)));
+      Results.Add(new Result("Average relative error", "The average of relative errors of the neural network ensemble regression solution on the training set.", new PercentValue(avgRelError)));
+    }
+
+    public static IRegressionSolution CreateNeuralNetworkEnsembleRegressionSolution(IRegressionProblemData problemData, int ensembleSize, int nLayers, int nHiddenNodes1, int nHiddenNodes2, double decay, int restarts,
+      out double rmsError, out double avgRelError) {
+      var dataset = problemData.Dataset;
+      string targetVariable = problemData.TargetVariable;
+      IEnumerable<string> allowedInputVariables = problemData.AllowedInputVariables;
+      IEnumerable<int> rows = problemData.TrainingIndices;
+      double[,] inputMatrix = AlglibUtil.PrepareInputMatrix(dataset, allowedInputVariables.Concat(new string[] { targetVariable }), rows);
+      if (inputMatrix.Cast<double>().Any(x => double.IsNaN(x) || double.IsInfinity(x)))
+        throw new NotSupportedException("Neural network ensemble regression does not support NaN or infinity values in the input dataset.");
+
+      alglib.mlpensemble mlpEnsemble = null;
+      if (nLayers == 0) {
+        alglib.mlpecreate0(allowedInputVariables.Count(), 1, ensembleSize, out mlpEnsemble);
+      } else if (nLayers == 1) {
+        alglib.mlpecreate1(allowedInputVariables.Count(), nHiddenNodes1, 1, ensembleSize, out mlpEnsemble);
+      } else if (nLayers == 2) {
+        alglib.mlpecreate2(allowedInputVariables.Count(), nHiddenNodes1, nHiddenNodes2, 1, ensembleSize, out mlpEnsemble);
+      } else throw new ArgumentException("Number of layers must be zero, one, or two.", "nLayers");
+      alglib.mlpreport rep;
+      int nRows = inputMatrix.GetLength(0);
+
+      int info;
+      alglib.mlpetraines(mlpEnsemble, inputMatrix, nRows, decay, restarts, out info, out rep);
+      if (info != 6) throw new ArgumentException("Error in calculation of neural network ensemble regression solution");
+
+      rmsError = alglib.mlpermserror(mlpEnsemble, inputMatrix, nRows);
+      avgRelError = alglib.mlpeavgrelerror(mlpEnsemble, inputMatrix, nRows);
+
+      return new NeuralNetworkEnsembleRegressionSolution((IRegressionProblemData)problemData.Clone(), new NeuralNetworkEnsembleModel(mlpEnsemble, targetVariable, allowedInputVariables));
+    }
+    #endregion
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/NeuralNetwork/NeuralNetworkEnsembleRegressionSolution.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/NeuralNetwork/NeuralNetworkEnsembleRegressionSolution.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/NeuralNetwork/NeuralNetworkEnsembleRegressionSolution.cs	(revision 13819)
@@ -0,0 +1,54 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Problems.DataAnalysis;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  /// <summary>
+  /// Represents a neural network ensemble solution for a regression problem which can be visualized in the GUI.
+  /// </summary>
+  [Item("NeuralNetworkEnsembleRegressionSolution", "Represents a neural network ensemble solution for a regression problem which can be visualized in the GUI.")]
+  [StorableClass]
+  public sealed class NeuralNetworkEnsembleRegressionSolution : RegressionSolution, INeuralNetworkEnsembleRegressionSolution {
+
+    public new INeuralNetworkEnsembleModel Model {
+      get { return (INeuralNetworkEnsembleModel)base.Model; }
+      set { base.Model = value; }
+    }
+
+    [StorableConstructor]
+    private NeuralNetworkEnsembleRegressionSolution(bool deserializing) : base(deserializing) { }
+    private NeuralNetworkEnsembleRegressionSolution(NeuralNetworkEnsembleRegressionSolution original, Cloner cloner)
+      : base(original, cloner) {
+    }
+    public NeuralNetworkEnsembleRegressionSolution(IRegressionProblemData problemData, INeuralNetworkEnsembleModel nnModel)
+      : base(nnModel, problemData) {
+      RecalculateResults();
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new NeuralNetworkEnsembleRegressionSolution(this, cloner);
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/NeuralNetwork/NeuralNetworkModel.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/NeuralNetwork/NeuralNetworkModel.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/NeuralNetwork/NeuralNetworkModel.cs	(revision 13819)
@@ -0,0 +1,263 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Problems.DataAnalysis;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  /// <summary>
+  /// Represents a neural network model for regression and classification
+  /// </summary>
+  [StorableClass]
+  [Item("NeuralNetworkModel", "Represents a neural network for regression and classification.")]
+  public sealed class NeuralNetworkModel : NamedItem, INeuralNetworkModel {
+
+    private alglib.multilayerperceptron multiLayerPerceptron;
+    public alglib.multilayerperceptron MultiLayerPerceptron {
+      get { return multiLayerPerceptron; }
+      set {
+        if (value != multiLayerPerceptron) {
+          if (value == null) throw new ArgumentNullException();
+          multiLayerPerceptron = value;
+          OnChanged(EventArgs.Empty);
+        }
+      }
+    }
+
+    [Storable]
+    private string targetVariable;
+    [Storable]
+    private string[] allowedInputVariables;
+    [Storable]
+    private double[] classValues;
+    [StorableConstructor]
+    private NeuralNetworkModel(bool deserializing)
+      : base(deserializing) {
+      if (deserializing)
+        multiLayerPerceptron = new alglib.multilayerperceptron();
+    }
+    private NeuralNetworkModel(NeuralNetworkModel original, Cloner cloner)
+      : base(original, cloner) {
+      multiLayerPerceptron = new alglib.multilayerperceptron();
+      multiLayerPerceptron.innerobj.chunks = (double[,])original.multiLayerPerceptron.innerobj.chunks.Clone();
+      multiLayerPerceptron.innerobj.columnmeans = (double[])original.multiLayerPerceptron.innerobj.columnmeans.Clone();
+      multiLayerPerceptron.innerobj.columnsigmas = (double[])original.multiLayerPerceptron.innerobj.columnsigmas.Clone();
+      multiLayerPerceptron.innerobj.derror = (double[])original.multiLayerPerceptron.innerobj.derror.Clone();
+      multiLayerPerceptron.innerobj.dfdnet = (double[])original.multiLayerPerceptron.innerobj.dfdnet.Clone();
+      multiLayerPerceptron.innerobj.neurons = (double[])original.multiLayerPerceptron.innerobj.neurons.Clone();
+      multiLayerPerceptron.innerobj.nwbuf = (double[])original.multiLayerPerceptron.innerobj.nwbuf.Clone();
+      multiLayerPerceptron.innerobj.structinfo = (int[])original.multiLayerPerceptron.innerobj.structinfo.Clone();
+      multiLayerPerceptron.innerobj.weights = (double[])original.multiLayerPerceptron.innerobj.weights.Clone();
+      multiLayerPerceptron.innerobj.x = (double[])original.multiLayerPerceptron.innerobj.x.Clone();
+      multiLayerPerceptron.innerobj.y = (double[])original.multiLayerPerceptron.innerobj.y.Clone();
+      targetVariable = original.targetVariable;
+      allowedInputVariables = (string[])original.allowedInputVariables.Clone();
+      if (original.classValues != null)
+        this.classValues = (double[])original.classValues.Clone();
+    }
+    public NeuralNetworkModel(alglib.multilayerperceptron multiLayerPerceptron, string targetVariable, IEnumerable<string> allowedInputVariables, double[] classValues = null)
+      : base() {
+      this.name = ItemName;
+      this.description = ItemDescription;
+      this.multiLayerPerceptron = multiLayerPerceptron;
+      this.targetVariable = targetVariable;
+      this.allowedInputVariables = allowedInputVariables.ToArray();
+      if (classValues != null)
+        this.classValues = (double[])classValues.Clone();
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new NeuralNetworkModel(this, cloner);
+    }
+
+    public IEnumerable<double> GetEstimatedValues(IDataset dataset, IEnumerable<int> rows) {
+      double[,] inputData = AlglibUtil.PrepareInputMatrix(dataset, allowedInputVariables, rows);
+
+      int n = inputData.GetLength(0);
+      int columns = inputData.GetLength(1);
+      double[] x = new double[columns];
+      double[] y = new double[1];
+
+      for (int row = 0; row < n; row++) {
+        for (int column = 0; column < columns; column++) {
+          x[column] = inputData[row, column];
+        }
+        alglib.mlpprocess(multiLayerPerceptron, x, ref y);
+        yield return y[0];
+      }
+    }
+
+    public IEnumerable<double> GetEstimatedClassValues(IDataset dataset, IEnumerable<int> rows) {
+      double[,] inputData = AlglibUtil.PrepareInputMatrix(dataset, allowedInputVariables, rows);
+
+      int n = inputData.GetLength(0);
+      int columns = inputData.GetLength(1);
+      double[] x = new double[columns];
+      double[] y = new double[classValues.Length];
+
+      for (int row = 0; row < n; row++) {
+        for (int column = 0; column < columns; column++) {
+          x[column] = inputData[row, column];
+        }
+        alglib.mlpprocess(multiLayerPerceptron, x, ref y);
+        // find class for with the largest probability value
+        int maxProbClassIndex = 0;
+        double maxProb = y[0];
+        for (int i = 1; i < y.Length; i++) {
+          if (maxProb < y[i]) {
+            maxProb = y[i];
+            maxProbClassIndex = i;
+          }
+        }
+        yield return classValues[maxProbClassIndex];
+      }
+    }
+
+    public INeuralNetworkRegressionSolution CreateRegressionSolution(IRegressionProblemData problemData) {
+      return new NeuralNetworkRegressionSolution(new RegressionProblemData(problemData), this);
+    }
+    IRegressionSolution IRegressionModel.CreateRegressionSolution(IRegressionProblemData problemData) {
+      return CreateRegressionSolution(problemData);
+    }
+    public INeuralNetworkClassificationSolution CreateClassificationSolution(IClassificationProblemData problemData) {
+      return new NeuralNetworkClassificationSolution(new ClassificationProblemData(problemData), this);
+    }
+    IClassificationSolution IClassificationModel.CreateClassificationSolution(IClassificationProblemData problemData) {
+      return CreateClassificationSolution(problemData);
+    }
+
+    #region events
+    public event EventHandler Changed;
+    private void OnChanged(EventArgs e) {
+      var handlers = Changed;
+      if (handlers != null)
+        handlers(this, e);
+    }
+    #endregion
+
+    #region persistence
+    [Storable]
+    private double[,] MultiLayerPerceptronChunks {
+      get {
+        return multiLayerPerceptron.innerobj.chunks;
+      }
+      set {
+        multiLayerPerceptron.innerobj.chunks = value;
+      }
+    }
+    [Storable]
+    private double[] MultiLayerPerceptronColumnMeans {
+      get {
+        return multiLayerPerceptron.innerobj.columnmeans;
+      }
+      set {
+        multiLayerPerceptron.innerobj.columnmeans = value;
+      }
+    }
+    [Storable]
+    private double[] MultiLayerPerceptronColumnSigmas {
+      get {
+        return multiLayerPerceptron.innerobj.columnsigmas;
+      }
+      set {
+        multiLayerPerceptron.innerobj.columnsigmas = value;
+      }
+    }
+    [Storable]
+    private double[] MultiLayerPerceptronDError {
+      get {
+        return multiLayerPerceptron.innerobj.derror;
+      }
+      set {
+        multiLayerPerceptron.innerobj.derror = value;
+      }
+    }
+    [Storable]
+    private double[] MultiLayerPerceptronDfdnet {
+      get {
+        return multiLayerPerceptron.innerobj.dfdnet;
+      }
+      set {
+        multiLayerPerceptron.innerobj.dfdnet = value;
+      }
+    }
+    [Storable]
+    private double[] MultiLayerPerceptronNeurons {
+      get {
+        return multiLayerPerceptron.innerobj.neurons;
+      }
+      set {
+        multiLayerPerceptron.innerobj.neurons = value;
+      }
+    }
+    [Storable]
+    private double[] MultiLayerPerceptronNwbuf {
+      get {
+        return multiLayerPerceptron.innerobj.nwbuf;
+      }
+      set {
+        multiLayerPerceptron.innerobj.nwbuf = value;
+      }
+    }
+    [Storable]
+    private int[] MultiLayerPerceptronStuctinfo {
+      get {
+        return multiLayerPerceptron.innerobj.structinfo;
+      }
+      set {
+        multiLayerPerceptron.innerobj.structinfo = value;
+      }
+    }
+    [Storable]
+    private double[] MultiLayerPerceptronWeights {
+      get {
+        return multiLayerPerceptron.innerobj.weights;
+      }
+      set {
+        multiLayerPerceptron.innerobj.weights = value;
+      }
+    }
+    [Storable]
+    private double[] MultiLayerPerceptronX {
+      get {
+        return multiLayerPerceptron.innerobj.x;
+      }
+      set {
+        multiLayerPerceptron.innerobj.x = value;
+      }
+    }
+    [Storable]
+    private double[] MultiLayerPerceptronY {
+      get {
+        return multiLayerPerceptron.innerobj.y;
+      }
+      set {
+        multiLayerPerceptron.innerobj.y = value;
+      }
+    }
+    #endregion
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/NeuralNetwork/NeuralNetworkRegression.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/NeuralNetwork/NeuralNetworkRegression.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/NeuralNetwork/NeuralNetworkRegression.cs	(revision 13819)
@@ -0,0 +1,213 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Optimization;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Problems.DataAnalysis;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  /// <summary>
+  /// Neural network regression data analysis algorithm.
+  /// </summary>
+  [Item("Neural Network Regression (NN)", "Neural network regression data analysis algorithm (wrapper for ALGLIB). Further documentation: http://www.alglib.net/dataanalysis/neuralnetworks.php")]
+  [Creatable(CreatableAttribute.Categories.DataAnalysisRegression, Priority = 130)]
+  [StorableClass]
+  public sealed class NeuralNetworkRegression : FixedDataAnalysisAlgorithm<IRegressionProblem> {
+    private const string DecayParameterName = "Decay";
+    private const string HiddenLayersParameterName = "HiddenLayers";
+    private const string NodesInFirstHiddenLayerParameterName = "NodesInFirstHiddenLayer";
+    private const string NodesInSecondHiddenLayerParameterName = "NodesInSecondHiddenLayer";
+    private const string RestartsParameterName = "Restarts";
+    private const string NeuralNetworkRegressionModelResultName = "Neural network regression solution";
+
+    #region parameter properties
+    public IFixedValueParameter<DoubleValue> DecayParameter {
+      get { return (IFixedValueParameter<DoubleValue>)Parameters[DecayParameterName]; }
+    }
+    public IConstrainedValueParameter<IntValue> HiddenLayersParameter {
+      get { return (IConstrainedValueParameter<IntValue>)Parameters[HiddenLayersParameterName]; }
+    }
+    public IFixedValueParameter<IntValue> NodesInFirstHiddenLayerParameter {
+      get { return (IFixedValueParameter<IntValue>)Parameters[NodesInFirstHiddenLayerParameterName]; }
+    }
+    public IFixedValueParameter<IntValue> NodesInSecondHiddenLayerParameter {
+      get { return (IFixedValueParameter<IntValue>)Parameters[NodesInSecondHiddenLayerParameterName]; }
+    }
+    public IFixedValueParameter<IntValue> RestartsParameter {
+      get { return (IFixedValueParameter<IntValue>)Parameters[RestartsParameterName]; }
+    }
+    #endregion
+
+    #region properties
+    public double Decay {
+      get { return DecayParameter.Value.Value; }
+      set {
+        if (value < 0.001 || value > 100) throw new ArgumentException("The decay parameter should be set to a value between 0.001 and 100.", "Decay");
+        DecayParameter.Value.Value = value;
+      }
+    }
+    public int HiddenLayers {
+      get { return HiddenLayersParameter.Value.Value; }
+      set {
+        if (value < 0 || value > 2) throw new ArgumentException("The number of hidden layers should be set to 0, 1, or 2.", "HiddenLayers");
+        HiddenLayersParameter.Value = (from v in HiddenLayersParameter.ValidValues
+                                       where v.Value == value
+                                       select v)
+                                      .Single();
+      }
+    }
+    public int NodesInFirstHiddenLayer {
+      get { return NodesInFirstHiddenLayerParameter.Value.Value; }
+      set {
+        if (value < 1) throw new ArgumentException("The number of nodes in the first hidden layer must be at least one.", "NodesInFirstHiddenLayer");
+        NodesInFirstHiddenLayerParameter.Value.Value = value;
+      }
+    }
+    public int NodesInSecondHiddenLayer {
+      get { return NodesInSecondHiddenLayerParameter.Value.Value; }
+      set {
+        if (value < 1) throw new ArgumentException("The number of nodes in the first second layer must be at least one.", "NodesInSecondHiddenLayer");
+        NodesInSecondHiddenLayerParameter.Value.Value = value;
+      }
+    }
+    public int Restarts {
+      get { return RestartsParameter.Value.Value; }
+      set {
+        if (value < 0) throw new ArgumentException("The number of restarts must be positive.", "Restarts");
+        RestartsParameter.Value.Value = value;
+      }
+    }
+    #endregion
+
+
+    [StorableConstructor]
+    private NeuralNetworkRegression(bool deserializing) : base(deserializing) { }
+    private NeuralNetworkRegression(NeuralNetworkRegression original, Cloner cloner)
+      : base(original, cloner) {
+      RegisterEventHandlers();
+    }
+    public NeuralNetworkRegression()
+      : base() {
+      var validHiddenLayerValues = new ItemSet<IntValue>(new IntValue[] { 
+        (IntValue)new IntValue(0).AsReadOnly(), 
+        (IntValue)new IntValue(1).AsReadOnly(), 
+        (IntValue)new IntValue(2).AsReadOnly() });
+      var selectedHiddenLayerValue = (from v in validHiddenLayerValues
+                                      where v.Value == 1
+                                      select v)
+                                     .Single();
+      Parameters.Add(new FixedValueParameter<DoubleValue>(DecayParameterName, "The decay parameter for the training phase of the neural network. This parameter determines the strengh of regularization and should be set to a value between 0.001 (weak regularization) to 100 (very strong regularization). The correct value should be determined via cross-validation.", new DoubleValue(1)));
+      Parameters.Add(new ConstrainedValueParameter<IntValue>(HiddenLayersParameterName, "The number of hidden layers for the neural network (0, 1, or 2)", validHiddenLayerValues, selectedHiddenLayerValue));
+      Parameters.Add(new FixedValueParameter<IntValue>(NodesInFirstHiddenLayerParameterName, "The number of nodes in the first hidden layer. This value is not used if the number of hidden layers is zero.", new IntValue(10)));
+      Parameters.Add(new FixedValueParameter<IntValue>(NodesInSecondHiddenLayerParameterName, "The number of nodes in the second hidden layer. This value is not used if the number of hidden layers is zero or one.", new IntValue(10)));
+      Parameters.Add(new FixedValueParameter<IntValue>(RestartsParameterName, "The number of restarts for learning.", new IntValue(2)));
+
+      RestartsParameter.Hidden = true;
+      NodesInSecondHiddenLayerParameter.Hidden = true;
+
+      RegisterEventHandlers();
+
+      Problem = new RegressionProblem();
+    }
+
+    private void RegisterEventHandlers() {
+      HiddenLayersParameter.Value.ValueChanged += HiddenLayersParameterValueValueChanged;
+      HiddenLayersParameter.ValueChanged += HiddenLayersParameterValueChanged;
+    }
+
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() {
+      RegisterEventHandlers();
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new NeuralNetworkRegression(this, cloner);
+    }
+
+    private void HiddenLayersParameterValueChanged(object source, EventArgs e) {
+      HiddenLayersParameter.Value.ValueChanged += HiddenLayersParameterValueValueChanged;
+      HiddenLayersParameterValueValueChanged(this, EventArgs.Empty);
+    }
+
+    private void HiddenLayersParameterValueValueChanged(object source, EventArgs e) {
+      if (HiddenLayers == 0) {
+        NodesInFirstHiddenLayerParameter.Hidden = true;
+        NodesInSecondHiddenLayerParameter.Hidden = true;
+      } else if (HiddenLayers == 1) {
+        NodesInFirstHiddenLayerParameter.Hidden = false;
+        NodesInSecondHiddenLayerParameter.Hidden = true;
+      } else {
+        NodesInFirstHiddenLayerParameter.Hidden = false;
+        NodesInSecondHiddenLayerParameter.Hidden = false;
+      }
+    }
+
+
+    #region neural network
+    protected override void Run() {
+      double rmsError, avgRelError;
+      var solution = CreateNeuralNetworkRegressionSolution(Problem.ProblemData, HiddenLayers, NodesInFirstHiddenLayer, NodesInSecondHiddenLayer, Decay, Restarts, out rmsError, out avgRelError);
+      Results.Add(new Result(NeuralNetworkRegressionModelResultName, "The neural network regression solution.", solution));
+      Results.Add(new Result("Root mean square error", "The root of the mean of squared errors of the neural network regression solution on the training set.", new DoubleValue(rmsError)));
+      Results.Add(new Result("Average relative error", "The average of relative errors of the neural network regression solution on the training set.", new PercentValue(avgRelError)));
+    }
+
+    public static IRegressionSolution CreateNeuralNetworkRegressionSolution(IRegressionProblemData problemData, int nLayers, int nHiddenNodes1, int nHiddenNodes2, double decay, int restarts,
+      out double rmsError, out double avgRelError) {
+      var dataset = problemData.Dataset;
+      string targetVariable = problemData.TargetVariable;
+      IEnumerable<string> allowedInputVariables = problemData.AllowedInputVariables;
+      IEnumerable<int> rows = problemData.TrainingIndices;
+      double[,] inputMatrix = AlglibUtil.PrepareInputMatrix(dataset, allowedInputVariables.Concat(new string[] { targetVariable }), rows);
+      if (inputMatrix.Cast<double>().Any(x => double.IsNaN(x) || double.IsInfinity(x)))
+        throw new NotSupportedException("Neural network regression does not support NaN or infinity values in the input dataset.");
+
+      alglib.multilayerperceptron multiLayerPerceptron = null;
+      if (nLayers == 0) {
+        alglib.mlpcreate0(allowedInputVariables.Count(), 1, out multiLayerPerceptron);
+      } else if (nLayers == 1) {
+        alglib.mlpcreate1(allowedInputVariables.Count(), nHiddenNodes1, 1, out multiLayerPerceptron);
+      } else if (nLayers == 2) {
+        alglib.mlpcreate2(allowedInputVariables.Count(), nHiddenNodes1, nHiddenNodes2, 1, out multiLayerPerceptron);
+      } else throw new ArgumentException("Number of layers must be zero, one, or two.", "nLayers");
+      alglib.mlpreport rep;
+      int nRows = inputMatrix.GetLength(0);
+
+      int info;
+      // using mlptrainlm instead of mlptraines or mlptrainbfgs because only one parameter is necessary
+      alglib.mlptrainlm(multiLayerPerceptron, inputMatrix, nRows, decay, restarts, out info, out rep);
+      if (info != 2) throw new ArgumentException("Error in calculation of neural network regression solution");
+
+      rmsError = alglib.mlprmserror(multiLayerPerceptron, inputMatrix, nRows);
+      avgRelError = alglib.mlpavgrelerror(multiLayerPerceptron, inputMatrix, nRows);
+
+      return new NeuralNetworkRegressionSolution((IRegressionProblemData)problemData.Clone(), new NeuralNetworkModel(multiLayerPerceptron, targetVariable, allowedInputVariables));
+    }
+    #endregion
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/NeuralNetwork/NeuralNetworkRegressionSolution.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/NeuralNetwork/NeuralNetworkRegressionSolution.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/NeuralNetwork/NeuralNetworkRegressionSolution.cs	(revision 13819)
@@ -0,0 +1,53 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Problems.DataAnalysis;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  /// <summary>
+  /// Represents a neural network solution for a regression problem which can be visualized in the GUI.
+  /// </summary>
+  [Item("NeuralNetworkRegressionSolution", "Represents a neural network solution for a regression problem which can be visualized in the GUI.")]
+  [StorableClass]
+  public sealed class NeuralNetworkRegressionSolution : RegressionSolution, INeuralNetworkRegressionSolution {
+
+    public new INeuralNetworkModel Model {
+      get { return (INeuralNetworkModel)base.Model; }
+      set { base.Model = value; }
+    }
+
+    [StorableConstructor]
+    private NeuralNetworkRegressionSolution(bool deserializing) : base(deserializing) { }
+    private NeuralNetworkRegressionSolution(NeuralNetworkRegressionSolution original, Cloner cloner)
+      : base(original, cloner) {
+    }
+    public NeuralNetworkRegressionSolution(IRegressionProblemData problemData, INeuralNetworkModel nnModel)
+      : base(nnModel, problemData) {
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new NeuralNetworkRegressionSolution(this, cloner);
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Plugin.cs.frame
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Plugin.cs.frame	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Plugin.cs.frame	(revision 13819)
@@ -0,0 +1,56 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using HeuristicLab.PluginInfrastructure;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  /// <summary>
+  /// Plugin class for HeuristicLab.Algorithms.DataAnalysis plugin.
+  /// </summary>
+  [Plugin("HeuristicLab.Algorithms.DataAnalysis", "Provides wrappers for data analysis algorithms implemented in external libraries (linear regression, linear discriminant analysis, k-means clustering, support vector classification and regression)", "3.4.9.$WCREV$")]
+  [PluginFile("HeuristicLab.Algorithms.DataAnalysis-3.4.dll", PluginFileType.Assembly)]
+  [PluginDependency("HeuristicLab.ALGLIB", "3.7.0")]
+  [PluginDependency("HeuristicLab.Algorithms.OffspringSelectionGeneticAlgorithm", "3.3")] // for GBM
+  [PluginDependency("HeuristicLab.Algorithms.GradientDescent", "3.3")]
+  [PluginDependency("HeuristicLab.Analysis", "3.3")]
+  [PluginDependency("HeuristicLab.Collections", "3.3")]
+  [PluginDependency("HeuristicLab.Common", "3.3")]
+  [PluginDependency("HeuristicLab.Common.Resources", "3.3")]
+  [PluginDependency("HeuristicLab.Core", "3.3")]
+  [PluginDependency("HeuristicLab.Data", "3.3")]
+  [PluginDependency("HeuristicLab.Encodings.RealVectorEncoding", "3.3")]
+  [PluginDependency("HeuristicLab.Encodings.SymbolicExpressionTreeEncoding", "3.4")]
+  [PluginDependency("HeuristicLab.Operators", "3.3")]
+  [PluginDependency("HeuristicLab.Optimization", "3.3")]
+  [PluginDependency("HeuristicLab.Parameters", "3.3")]
+  [PluginDependency("HeuristicLab.Persistence", "3.3")]
+  [PluginDependency("HeuristicLab.Problems.DataAnalysis", "3.4")]
+  [PluginDependency("HeuristicLab.Problems.DataAnalysis.Symbolic", "3.4")]
+  [PluginDependency("HeuristicLab.Problems.DataAnalysis.Symbolic.Classification", "3.4")]
+  [PluginDependency("HeuristicLab.Problems.DataAnalysis.Symbolic.Regression", "3.4")]
+  [PluginDependency("HeuristicLab.Problems.DataAnalysis.Symbolic.TimeSeriesPrognosis", "3.4")]
+  [PluginDependency("HeuristicLab.Problems.Instances", "3.3")]
+  [PluginDependency("HeuristicLab.LibSVM", "3.12")]
+  [PluginDependency("HeuristicLab.Random", "3.3")]
+  [PluginDependency("HeuristicLab.Selection", "3.3")]
+  public class HeuristicLabAlgorithmsDataAnalysisPlugin : PluginBase {
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Properties/AssemblyInfo.cs.frame
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Properties/AssemblyInfo.cs.frame	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/Properties/AssemblyInfo.cs.frame	(revision 13819)
@@ -0,0 +1,55 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Reflection;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following 
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("HeuristicLab.Algorithms.DataAnalysis")]
+[assembly: AssemblyDescription("Provides wrappers for data analysis algorithms implemented in external libraries (linear regression, linear discriminant analysis, k-means clustering, support vector classification and regression)")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("HeuristicLab")]
+[assembly: AssemblyCopyright("(c) 2002-2015 HEAL")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible 
+// to COM components.  If you need to access a type in this assembly from 
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("3E422463-0CE0-400D-9544-5C11D5818769")]
+
+// Version information for an assembly consists of the following four values:
+//
+//      Major Version
+//      Minor Version 
+//      Build Number
+//      Revision
+//
+// You can specify all the values or you can default the Revision and Build Numbers 
+// by using the '*' as shown below:
+[assembly: AssemblyVersion("3.4.0.0")]
+[assembly: AssemblyFileVersion("3.4.9.$WCREV$")]
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/RandomForest/RandomForestClassification.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/RandomForest/RandomForestClassification.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/RandomForest/RandomForestClassification.cs	(revision 13819)
@@ -0,0 +1,163 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Optimization;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Problems.DataAnalysis;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  /// <summary>
+  /// Random forest classification data analysis algorithm.
+  /// </summary>
+  [Item("Random Forest Classification (RF)", "Random forest classification data analysis algorithm (wrapper for ALGLIB).")]
+  [Creatable(CreatableAttribute.Categories.DataAnalysisClassification, Priority = 120)]
+  [StorableClass]
+  public sealed class RandomForestClassification : FixedDataAnalysisAlgorithm<IClassificationProblem> {
+    private const string RandomForestClassificationModelResultName = "Random forest classification solution";
+    private const string NumberOfTreesParameterName = "Number of trees";
+    private const string RParameterName = "R";
+    private const string MParameterName = "M";
+    private const string SeedParameterName = "Seed";
+    private const string SetSeedRandomlyParameterName = "SetSeedRandomly";
+    private const string CreateSolutionParameterName = "CreateSolution";
+
+    #region parameter properties
+    public IFixedValueParameter<IntValue> NumberOfTreesParameter {
+      get { return (IFixedValueParameter<IntValue>)Parameters[NumberOfTreesParameterName]; }
+    }
+    public IFixedValueParameter<DoubleValue> RParameter {
+      get { return (IFixedValueParameter<DoubleValue>)Parameters[RParameterName]; }
+    }
+    public IFixedValueParameter<DoubleValue> MParameter {
+      get { return (IFixedValueParameter<DoubleValue>)Parameters[MParameterName]; }
+    }
+    public IFixedValueParameter<IntValue> SeedParameter {
+      get { return (IFixedValueParameter<IntValue>)Parameters[SeedParameterName]; }
+    }
+    public IFixedValueParameter<BoolValue> SetSeedRandomlyParameter {
+      get { return (IFixedValueParameter<BoolValue>)Parameters[SetSeedRandomlyParameterName]; }
+    }
+    public IFixedValueParameter<BoolValue> CreateSolutionParameter {
+      get { return (IFixedValueParameter<BoolValue>)Parameters[CreateSolutionParameterName]; }
+    }
+    #endregion
+    #region properties
+    public int NumberOfTrees {
+      get { return NumberOfTreesParameter.Value.Value; }
+      set { NumberOfTreesParameter.Value.Value = value; }
+    }
+    public double R {
+      get { return RParameter.Value.Value; }
+      set { RParameter.Value.Value = value; }
+    }
+    public double M {
+      get { return MParameter.Value.Value; }
+      set { MParameter.Value.Value = value; }
+    }
+    public int Seed {
+      get { return SeedParameter.Value.Value; }
+      set { SeedParameter.Value.Value = value; }
+    }
+    public bool SetSeedRandomly {
+      get { return SetSeedRandomlyParameter.Value.Value; }
+      set { SetSeedRandomlyParameter.Value.Value = value; }
+    }
+    public bool CreateSolution {
+      get { return CreateSolutionParameter.Value.Value; }
+      set { CreateSolutionParameter.Value.Value = value; }
+    }
+    #endregion
+
+    [StorableConstructor]
+    private RandomForestClassification(bool deserializing) : base(deserializing) { }
+    private RandomForestClassification(RandomForestClassification original, Cloner cloner)
+      : base(original, cloner) {
+    }
+
+    public RandomForestClassification()
+      : base() {
+      Parameters.Add(new FixedValueParameter<IntValue>(NumberOfTreesParameterName, "The number of trees in the forest. Should be between 50 and 100", new IntValue(50)));
+      Parameters.Add(new FixedValueParameter<DoubleValue>(RParameterName, "The ratio of the training set that will be used in the construction of individual trees (0<r<=1). Should be adjusted depending on the noise level in the dataset in the range from 0.66 (low noise) to 0.05 (high noise). This parameter should be adjusted to achieve good generalization error.", new DoubleValue(0.3)));
+      Parameters.Add(new FixedValueParameter<DoubleValue>(MParameterName, "The ratio of features that will be used in the construction of individual trees (0<m<=1)", new DoubleValue(0.5)));
+      Parameters.Add(new FixedValueParameter<IntValue>(SeedParameterName, "The random seed used to initialize the new pseudo random number generator.", new IntValue(0)));
+      Parameters.Add(new FixedValueParameter<BoolValue>(SetSeedRandomlyParameterName, "True if the random seed should be set to a random value, otherwise false.", new BoolValue(true)));
+      Parameters.Add(new FixedValueParameter<BoolValue>(CreateSolutionParameterName, "Flag that indicates if a solution should be produced at the end of the run", new BoolValue(true)));
+      Parameters[CreateSolutionParameterName].Hidden = true;
+
+      Problem = new ClassificationProblem();
+    }
+
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() {
+      // BackwardsCompatibility3.3
+      #region Backwards compatible code, remove with 3.4
+      if (!Parameters.ContainsKey(MParameterName))
+        Parameters.Add(new FixedValueParameter<DoubleValue>(MParameterName, "The ratio of features that will be used in the construction of individual trees (0<m<=1)", new DoubleValue(0.5)));
+      if (!Parameters.ContainsKey(SeedParameterName))
+        Parameters.Add(new FixedValueParameter<IntValue>(SeedParameterName, "The random seed used to initialize the new pseudo random number generator.", new IntValue(0)));
+      if (!Parameters.ContainsKey((SetSeedRandomlyParameterName)))
+        Parameters.Add(new FixedValueParameter<BoolValue>(SetSeedRandomlyParameterName, "True if the random seed should be set to a random value, otherwise false.", new BoolValue(true)));
+      if (!Parameters.ContainsKey(CreateSolutionParameterName)) {
+        Parameters.Add(new FixedValueParameter<BoolValue>(CreateSolutionParameterName, "Flag that indicates if a solution should be produced at the end of the run", new BoolValue(true)));
+        Parameters[CreateSolutionParameterName].Hidden = true;
+      }
+      #endregion
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new RandomForestClassification(this, cloner);
+    }
+
+    #region random forest
+    protected override void Run() {
+      double rmsError, relClassificationError, outOfBagRmsError, outOfBagRelClassificationError;
+      if (SetSeedRandomly) Seed = new System.Random().Next();
+
+      var model = CreateRandomForestClassificationModel(Problem.ProblemData, NumberOfTrees, R, M, Seed, out rmsError, out relClassificationError, out outOfBagRmsError, out outOfBagRelClassificationError);
+      Results.Add(new Result("Root mean square error", "The root of the mean of squared errors of the random forest regression solution on the training set.", new DoubleValue(rmsError)));
+      Results.Add(new Result("Relative classification error", "Relative classification error of the random forest regression solution on the training set.", new PercentValue(relClassificationError)));
+      Results.Add(new Result("Root mean square error (out-of-bag)", "The out-of-bag root of the mean of squared errors of the random forest regression solution.", new DoubleValue(outOfBagRmsError)));
+      Results.Add(new Result("Relative classification error (out-of-bag)", "The out-of-bag relative classification error  of the random forest regression solution.", new PercentValue(outOfBagRelClassificationError)));
+
+      if (CreateSolution) {
+        var solution = new RandomForestClassificationSolution((IClassificationProblemData)Problem.ProblemData.Clone(), model);
+        Results.Add(new Result(RandomForestClassificationModelResultName, "The random forest classification solution.", solution));
+      }
+    }
+    
+    // keep for compatibility with old API
+    public static RandomForestClassificationSolution CreateRandomForestClassificationSolution(IClassificationProblemData problemData, int nTrees, double r, double m, int seed,
+      out double rmsError, out double relClassificationError, out double outOfBagRmsError, out double outOfBagRelClassificationError) {
+      var model = CreateRandomForestClassificationModel(problemData, nTrees, r, m, seed, out rmsError, out relClassificationError, out outOfBagRmsError, out outOfBagRelClassificationError);
+      return new RandomForestClassificationSolution((IClassificationProblemData)problemData.Clone(), model);
+    }
+
+    public static RandomForestModel CreateRandomForestClassificationModel(IClassificationProblemData problemData, int nTrees, double r, double m, int seed,
+      out double rmsError, out double relClassificationError, out double outOfBagRmsError, out double outOfBagRelClassificationError) {
+      return RandomForestModel.CreateClassificationModel(problemData, nTrees, r, m, seed, out rmsError, out relClassificationError, out outOfBagRmsError, out outOfBagRelClassificationError);
+    }
+    #endregion
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/RandomForest/RandomForestClassificationSolution.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/RandomForest/RandomForestClassificationSolution.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/RandomForest/RandomForestClassificationSolution.cs	(revision 13819)
@@ -0,0 +1,53 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Problems.DataAnalysis;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  /// <summary>
+  /// Represents a random forest solution for a classification problem which can be visualized in the GUI.
+  /// </summary>
+  [Item("RandomForestClassificationSolution", "Represents a random forest solution for a classification problem which can be visualized in the GUI.")]
+  [StorableClass]
+  public sealed class RandomForestClassificationSolution : ClassificationSolution, IRandomForestClassificationSolution {
+
+    public new IRandomForestModel Model {
+      get { return (IRandomForestModel)base.Model; }
+      set { base.Model = value; }
+    }
+
+    [StorableConstructor]
+    private RandomForestClassificationSolution(bool deserializing) : base(deserializing) { }
+    private RandomForestClassificationSolution(RandomForestClassificationSolution original, Cloner cloner)
+      : base(original, cloner) {
+    }
+    public RandomForestClassificationSolution(IClassificationProblemData problemData, IRandomForestModel randomForestModel)
+      : base(randomForestModel, problemData) {
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new RandomForestClassificationSolution(this, cloner);
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/RandomForest/RandomForestModel.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/RandomForest/RandomForestModel.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/RandomForest/RandomForestModel.cs	(revision 13819)
@@ -0,0 +1,342 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Problems.DataAnalysis;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  /// <summary>
+  /// Represents a random forest model for regression and classification
+  /// </summary>
+  [StorableClass]
+  [Item("RandomForestModel", "Represents a random forest for regression and classification.")]
+  public sealed class RandomForestModel : NamedItem, IRandomForestModel {
+    // not persisted
+    private alglib.decisionforest randomForest;
+    private alglib.decisionforest RandomForest {
+      get {
+        // recalculate lazily
+        if (randomForest.innerobj.trees == null || randomForest.innerobj.trees.Length == 0) RecalculateModel();
+        return randomForest;
+      }
+    }
+
+    // instead of storing the data of the model itself
+    // we instead only store data necessary to recalculate the same model lazily on demand
+    [Storable]
+    private int seed;
+    [Storable]
+    private IDataAnalysisProblemData originalTrainingData;
+    [Storable]
+    private double[] classValues;
+    [Storable]
+    private int nTrees;
+    [Storable]
+    private double r;
+    [Storable]
+    private double m;
+
+
+    [StorableConstructor]
+    private RandomForestModel(bool deserializing)
+      : base(deserializing) {
+      // for backwards compatibility (loading old solutions)
+      randomForest = new alglib.decisionforest();
+    }
+    private RandomForestModel(RandomForestModel original, Cloner cloner)
+      : base(original, cloner) {
+      randomForest = new alglib.decisionforest();
+      randomForest.innerobj.bufsize = original.randomForest.innerobj.bufsize;
+      randomForest.innerobj.nclasses = original.randomForest.innerobj.nclasses;
+      randomForest.innerobj.ntrees = original.randomForest.innerobj.ntrees;
+      randomForest.innerobj.nvars = original.randomForest.innerobj.nvars;
+      // we assume that the trees array (double[]) is immutable in alglib
+      randomForest.innerobj.trees = original.randomForest.innerobj.trees;
+
+      // allowedInputVariables is immutable so we don't need to clone
+      allowedInputVariables = original.allowedInputVariables;
+
+      // clone data which is necessary to rebuild the model
+      this.seed = original.seed;
+      this.originalTrainingData = cloner.Clone(original.originalTrainingData);
+      // classvalues is immutable so we don't need to clone
+      this.classValues = original.classValues;
+      this.nTrees = original.nTrees;
+      this.r = original.r;
+      this.m = original.m;
+    }
+
+    // random forest models can only be created through the static factory methods CreateRegressionModel and CreateClassificationModel
+    private RandomForestModel(alglib.decisionforest randomForest,
+      int seed, IDataAnalysisProblemData originalTrainingData,
+      int nTrees, double r, double m, double[] classValues = null)
+      : base() {
+      this.name = ItemName;
+      this.description = ItemDescription;
+      // the model itself
+      this.randomForest = randomForest;
+      // data which is necessary for recalculation of the model
+      this.seed = seed;
+      this.originalTrainingData = (IDataAnalysisProblemData)originalTrainingData.Clone();
+      this.classValues = classValues;
+      this.nTrees = nTrees;
+      this.r = r;
+      this.m = m;
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new RandomForestModel(this, cloner);
+    }
+
+    private void RecalculateModel() {
+      double rmsError, oobRmsError, relClassError, oobRelClassError;
+      var regressionProblemData = originalTrainingData as IRegressionProblemData;
+      var classificationProblemData = originalTrainingData as IClassificationProblemData;
+      if (regressionProblemData != null) {
+        var model = CreateRegressionModel(regressionProblemData,
+                                              nTrees, r, m, seed, out rmsError, out oobRmsError,
+                                              out relClassError, out oobRelClassError);
+        randomForest = model.randomForest;
+      } else if (classificationProblemData != null) {
+        var model = CreateClassificationModel(classificationProblemData,
+                                              nTrees, r, m, seed, out rmsError, out oobRmsError,
+                                              out relClassError, out oobRelClassError);
+        randomForest = model.randomForest;
+      }
+    }
+
+    public IEnumerable<double> GetEstimatedValues(IDataset dataset, IEnumerable<int> rows) {
+      double[,] inputData = AlglibUtil.PrepareInputMatrix(dataset, AllowedInputVariables, rows);
+      AssertInputMatrix(inputData);
+
+      int n = inputData.GetLength(0);
+      int columns = inputData.GetLength(1);
+      double[] x = new double[columns];
+      double[] y = new double[1];
+
+      for (int row = 0; row < n; row++) {
+        for (int column = 0; column < columns; column++) {
+          x[column] = inputData[row, column];
+        }
+        alglib.dfprocess(RandomForest, x, ref y);
+        yield return y[0];
+      }
+    }
+
+    public IEnumerable<double> GetEstimatedClassValues(IDataset dataset, IEnumerable<int> rows) {
+      double[,] inputData = AlglibUtil.PrepareInputMatrix(dataset, AllowedInputVariables, rows);
+      AssertInputMatrix(inputData);
+
+      int n = inputData.GetLength(0);
+      int columns = inputData.GetLength(1);
+      double[] x = new double[columns];
+      double[] y = new double[RandomForest.innerobj.nclasses];
+
+      for (int row = 0; row < n; row++) {
+        for (int column = 0; column < columns; column++) {
+          x[column] = inputData[row, column];
+        }
+        alglib.dfprocess(randomForest, x, ref y);
+        // find class for with the largest probability value
+        int maxProbClassIndex = 0;
+        double maxProb = y[0];
+        for (int i = 1; i < y.Length; i++) {
+          if (maxProb < y[i]) {
+            maxProb = y[i];
+            maxProbClassIndex = i;
+          }
+        }
+        yield return classValues[maxProbClassIndex];
+      }
+    }
+
+    public IRandomForestRegressionSolution CreateRegressionSolution(IRegressionProblemData problemData) {
+      return new RandomForestRegressionSolution(new RegressionProblemData(problemData), this);
+    }
+    IRegressionSolution IRegressionModel.CreateRegressionSolution(IRegressionProblemData problemData) {
+      return CreateRegressionSolution(problemData);
+    }
+    public IRandomForestClassificationSolution CreateClassificationSolution(IClassificationProblemData problemData) {
+      return new RandomForestClassificationSolution(new ClassificationProblemData(problemData), this);
+    }
+    IClassificationSolution IClassificationModel.CreateClassificationSolution(IClassificationProblemData problemData) {
+      return CreateClassificationSolution(problemData);
+    }
+
+    public static RandomForestModel CreateRegressionModel(IRegressionProblemData problemData, int nTrees, double r, double m, int seed,
+      out double rmsError, out double outOfBagRmsError, out double avgRelError, out double outOfBagAvgRelError) {
+      return CreateRegressionModel(problemData, problemData.TrainingIndices, nTrees, r, m, seed, out rmsError, out avgRelError, out outOfBagAvgRelError, out outOfBagRmsError);
+    }
+
+    public static RandomForestModel CreateRegressionModel(IRegressionProblemData problemData, IEnumerable<int> trainingIndices, int nTrees, double r, double m, int seed,
+      out double rmsError, out double outOfBagRmsError, out double avgRelError, out double outOfBagAvgRelError) {
+      var variables = problemData.AllowedInputVariables.Concat(new string[] { problemData.TargetVariable });
+      double[,] inputMatrix = AlglibUtil.PrepareInputMatrix(problemData.Dataset, variables, trainingIndices);
+
+      alglib.dfreport rep;
+      var dForest = CreateRandomForestModel(seed, inputMatrix, nTrees, r, m, 1, out rep);
+
+      rmsError = rep.rmserror;
+      avgRelError = rep.avgrelerror;
+      outOfBagAvgRelError = rep.oobavgrelerror;
+      outOfBagRmsError = rep.oobrmserror;
+
+      return new RandomForestModel(dForest, seed, problemData, nTrees, r, m);
+    }
+
+    public static RandomForestModel CreateClassificationModel(IClassificationProblemData problemData, int nTrees, double r, double m, int seed,
+      out double rmsError, out double outOfBagRmsError, out double relClassificationError, out double outOfBagRelClassificationError) {
+      return CreateClassificationModel(problemData, problemData.TrainingIndices, nTrees, r, m, seed, out rmsError, out outOfBagRmsError, out relClassificationError, out outOfBagRelClassificationError);
+    }
+
+    public static RandomForestModel CreateClassificationModel(IClassificationProblemData problemData, IEnumerable<int> trainingIndices, int nTrees, double r, double m, int seed,
+      out double rmsError, out double outOfBagRmsError, out double relClassificationError, out double outOfBagRelClassificationError) {
+
+      var variables = problemData.AllowedInputVariables.Concat(new string[] { problemData.TargetVariable });
+      double[,] inputMatrix = AlglibUtil.PrepareInputMatrix(problemData.Dataset, variables, trainingIndices);
+
+      var classValues = problemData.ClassValues.ToArray();
+      int nClasses = classValues.Length;
+
+      // map original class values to values [0..nClasses-1]
+      var classIndices = new Dictionary<double, double>();
+      for (int i = 0; i < nClasses; i++) {
+        classIndices[classValues[i]] = i;
+      }
+
+      int nRows = inputMatrix.GetLength(0);
+      int nColumns = inputMatrix.GetLength(1);
+      for (int row = 0; row < nRows; row++) {
+        inputMatrix[row, nColumns - 1] = classIndices[inputMatrix[row, nColumns - 1]];
+      }
+
+      alglib.dfreport rep;
+      var dForest = CreateRandomForestModel(seed, inputMatrix, nTrees, r, m, nClasses, out rep);
+
+      rmsError = rep.rmserror;
+      outOfBagRmsError = rep.oobrmserror;
+      relClassificationError = rep.relclserror;
+      outOfBagRelClassificationError = rep.oobrelclserror;
+
+      return new RandomForestModel(dForest, seed, problemData, nTrees, r, m, classValues);
+    }
+
+    private static alglib.decisionforest CreateRandomForestModel(int seed, double[,] inputMatrix, int nTrees, double r, double m, int nClasses, out alglib.dfreport rep) {
+      AssertParameters(r, m);
+      AssertInputMatrix(inputMatrix);
+
+      int info = 0;
+      alglib.math.rndobject = new System.Random(seed);
+      var dForest = new alglib.decisionforest();
+      rep = new alglib.dfreport();
+      int nRows = inputMatrix.GetLength(0);
+      int nColumns = inputMatrix.GetLength(1);
+      int sampleSize = Math.Max((int)Math.Round(r * nRows), 1);
+      int nFeatures = Math.Max((int)Math.Round(m * (nColumns - 1)), 1);
+
+      alglib.dforest.dfbuildinternal(inputMatrix, nRows, nColumns - 1, nClasses, nTrees, sampleSize, nFeatures, alglib.dforest.dfusestrongsplits + alglib.dforest.dfuseevs, ref info, dForest.innerobj, rep.innerobj);
+      if (info != 1) throw new ArgumentException("Error in calculation of random forest model");
+      return dForest;
+    }
+
+    private static void AssertParameters(double r, double m) {
+      if (r <= 0 || r > 1) throw new ArgumentException("The R parameter for random forest modeling must be between 0 and 1.");
+      if (m <= 0 || m > 1) throw new ArgumentException("The M parameter for random forest modeling must be between 0 and 1.");
+    }
+
+    private static void AssertInputMatrix(double[,] inputMatrix) {
+      if (inputMatrix.Cast<double>().Any(x => Double.IsNaN(x) || Double.IsInfinity(x)))
+        throw new NotSupportedException("Random forest modeling does not support NaN or infinity values in the input dataset.");
+    }
+
+    #region persistence for backwards compatibility
+    // when the originalTrainingData is null this means the model was loaded from an old file 
+    // therefore, we cannot use the new persistence mechanism because the original data is not available anymore
+    // in such cases we still store the compete model
+    private bool IsCompatibilityLoaded { get { return originalTrainingData == null; } }
+
+    private string[] allowedInputVariables;
+    [Storable(Name = "allowedInputVariables")]
+    private string[] AllowedInputVariables {
+      get {
+        if (IsCompatibilityLoaded) return allowedInputVariables;
+        else return originalTrainingData.AllowedInputVariables.ToArray();
+      }
+      set { allowedInputVariables = value; }
+    }
+    [Storable]
+    private int RandomForestBufSize {
+      get {
+        if (IsCompatibilityLoaded) return randomForest.innerobj.bufsize;
+        else return 0;
+      }
+      set {
+        randomForest.innerobj.bufsize = value;
+      }
+    }
+    [Storable]
+    private int RandomForestNClasses {
+      get {
+        if (IsCompatibilityLoaded) return randomForest.innerobj.nclasses;
+        else return 0;
+      }
+      set {
+        randomForest.innerobj.nclasses = value;
+      }
+    }
+    [Storable]
+    private int RandomForestNTrees {
+      get {
+        if (IsCompatibilityLoaded) return randomForest.innerobj.ntrees;
+        else return 0;
+      }
+      set {
+        randomForest.innerobj.ntrees = value;
+      }
+    }
+    [Storable]
+    private int RandomForestNVars {
+      get {
+        if (IsCompatibilityLoaded) return randomForest.innerobj.nvars;
+        else return 0;
+      }
+      set {
+        randomForest.innerobj.nvars = value;
+      }
+    }
+    [Storable]
+    private double[] RandomForestTrees {
+      get {
+        if (IsCompatibilityLoaded) return randomForest.innerobj.trees;
+        else return new double[] { };
+      }
+      set {
+        randomForest.innerobj.trees = value;
+      }
+    }
+    #endregion
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/RandomForest/RandomForestRegression.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/RandomForest/RandomForestRegression.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/RandomForest/RandomForestRegression.cs	(revision 13819)
@@ -0,0 +1,166 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Optimization;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Problems.DataAnalysis;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  /// <summary>
+  /// Random forest regression data analysis algorithm.
+  /// </summary>
+  [Item("Random Forest Regression (RF)", "Random forest regression data analysis algorithm (wrapper for ALGLIB).")]
+  [Creatable(CreatableAttribute.Categories.DataAnalysisRegression, Priority = 120)]
+  [StorableClass]
+  public sealed class RandomForestRegression : FixedDataAnalysisAlgorithm<IRegressionProblem> {
+    private const string RandomForestRegressionModelResultName = "Random forest regression solution";
+    private const string NumberOfTreesParameterName = "Number of trees";
+    private const string RParameterName = "R";
+    private const string MParameterName = "M";
+    private const string SeedParameterName = "Seed";
+    private const string SetSeedRandomlyParameterName = "SetSeedRandomly";
+    private const string CreateSolutionParameterName = "CreateSolution";
+
+    #region parameter properties
+    public IFixedValueParameter<IntValue> NumberOfTreesParameter {
+      get { return (IFixedValueParameter<IntValue>)Parameters[NumberOfTreesParameterName]; }
+    }
+    public IFixedValueParameter<DoubleValue> RParameter {
+      get { return (IFixedValueParameter<DoubleValue>)Parameters[RParameterName]; }
+    }
+    public IFixedValueParameter<DoubleValue> MParameter {
+      get { return (IFixedValueParameter<DoubleValue>)Parameters[MParameterName]; }
+    }
+    public IFixedValueParameter<IntValue> SeedParameter {
+      get { return (IFixedValueParameter<IntValue>)Parameters[SeedParameterName]; }
+    }
+    public IFixedValueParameter<BoolValue> SetSeedRandomlyParameter {
+      get { return (IFixedValueParameter<BoolValue>)Parameters[SetSeedRandomlyParameterName]; }
+    }
+    public IFixedValueParameter<BoolValue> CreateSolutionParameter {
+      get { return (IFixedValueParameter<BoolValue>)Parameters[CreateSolutionParameterName]; }
+    }
+    #endregion
+    #region properties
+    public int NumberOfTrees {
+      get { return NumberOfTreesParameter.Value.Value; }
+      set { NumberOfTreesParameter.Value.Value = value; }
+    }
+    public double R {
+      get { return RParameter.Value.Value; }
+      set { RParameter.Value.Value = value; }
+    }
+    public double M {
+      get { return MParameter.Value.Value; }
+      set { MParameter.Value.Value = value; }
+    }
+    public int Seed {
+      get { return SeedParameter.Value.Value; }
+      set { SeedParameter.Value.Value = value; }
+    }
+    public bool SetSeedRandomly {
+      get { return SetSeedRandomlyParameter.Value.Value; }
+      set { SetSeedRandomlyParameter.Value.Value = value; }
+    }
+    public bool CreateSolution {
+      get { return CreateSolutionParameter.Value.Value; }
+      set { CreateSolutionParameter.Value.Value = value; }
+    }
+    #endregion
+    [StorableConstructor]
+    private RandomForestRegression(bool deserializing) : base(deserializing) { }
+    private RandomForestRegression(RandomForestRegression original, Cloner cloner)
+      : base(original, cloner) {
+    }
+
+    public RandomForestRegression()
+      : base() {
+      Parameters.Add(new FixedValueParameter<IntValue>(NumberOfTreesParameterName, "The number of trees in the forest. Should be between 50 and 100", new IntValue(50)));
+      Parameters.Add(new FixedValueParameter<DoubleValue>(RParameterName, "The ratio of the training set that will be used in the construction of individual trees (0<r<=1). Should be adjusted depending on the noise level in the dataset in the range from 0.66 (low noise) to 0.05 (high noise). This parameter should be adjusted to achieve good generalization error.", new DoubleValue(0.3)));
+      Parameters.Add(new FixedValueParameter<DoubleValue>(MParameterName, "The ratio of features that will be used in the construction of individual trees (0<m<=1)", new DoubleValue(0.5)));
+      Parameters.Add(new FixedValueParameter<IntValue>(SeedParameterName, "The random seed used to initialize the new pseudo random number generator.", new IntValue(0)));
+      Parameters.Add(new FixedValueParameter<BoolValue>(SetSeedRandomlyParameterName, "True if the random seed should be set to a random value, otherwise false.", new BoolValue(true)));
+      Parameters.Add(new FixedValueParameter<BoolValue>(CreateSolutionParameterName, "Flag that indicates if a solution should be produced at the end of the run", new BoolValue(true)));
+      Parameters[CreateSolutionParameterName].Hidden = true;
+
+      Problem = new RegressionProblem();
+    }
+
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() {
+      // BackwardsCompatibility3.3
+      #region Backwards compatible code, remove with 3.4
+      if (!Parameters.ContainsKey(MParameterName))
+        Parameters.Add(new FixedValueParameter<DoubleValue>(MParameterName, "The ratio of features that will be used in the construction of individual trees (0<m<=1)", new DoubleValue(0.5)));
+      if (!Parameters.ContainsKey(SeedParameterName))
+        Parameters.Add(new FixedValueParameter<IntValue>(SeedParameterName, "The random seed used to initialize the new pseudo random number generator.", new IntValue(0)));
+      if (!Parameters.ContainsKey((SetSeedRandomlyParameterName)))
+        Parameters.Add(new FixedValueParameter<BoolValue>(SetSeedRandomlyParameterName, "True if the random seed should be set to a random value, otherwise false.", new BoolValue(true)));
+      if (!Parameters.ContainsKey(CreateSolutionParameterName)) {
+        Parameters.Add(new FixedValueParameter<BoolValue>(CreateSolutionParameterName, "Flag that indicates if a solution should be produced at the end of the run", new BoolValue(true)));
+        Parameters[CreateSolutionParameterName].Hidden = true;
+      }
+      #endregion
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new RandomForestRegression(this, cloner);
+    }
+
+    #region random forest
+    protected override void Run() {
+      double rmsError, avgRelError, outOfBagRmsError, outOfBagAvgRelError;
+      if (SetSeedRandomly) Seed = new System.Random().Next();
+      var model = CreateRandomForestRegressionModel(Problem.ProblemData, NumberOfTrees, R, M, Seed,
+        out rmsError, out avgRelError, out outOfBagRmsError, out outOfBagAvgRelError);
+
+      Results.Add(new Result("Root mean square error", "The root of the mean of squared errors of the random forest regression solution on the training set.", new DoubleValue(rmsError)));
+      Results.Add(new Result("Average relative error", "The average of relative errors of the random forest regression solution on the training set.", new PercentValue(avgRelError)));
+      Results.Add(new Result("Root mean square error (out-of-bag)", "The out-of-bag root of the mean of squared errors of the random forest regression solution.", new DoubleValue(outOfBagRmsError)));
+      Results.Add(new Result("Average relative error (out-of-bag)", "The out-of-bag average of relative errors of the random forest regression solution.", new PercentValue(outOfBagAvgRelError)));
+
+      if (CreateSolution) {
+        var solution = new RandomForestRegressionSolution((IRegressionProblemData)Problem.ProblemData.Clone(), model);
+        Results.Add(new Result(RandomForestRegressionModelResultName, "The random forest regression solution.", solution));
+      }
+    }
+
+    // keep for compatibility with old API
+    public static RandomForestRegressionSolution CreateRandomForestRegressionSolution(IRegressionProblemData problemData, int nTrees, double r, double m, int seed,
+      out double rmsError, out double avgRelError, out double outOfBagRmsError, out double outOfBagAvgRelError) {
+      var model = CreateRandomForestRegressionModel(problemData, nTrees, r, m, seed,
+        out rmsError, out avgRelError, out outOfBagRmsError, out outOfBagAvgRelError);
+      return new RandomForestRegressionSolution((IRegressionProblemData)problemData.Clone(), model);
+    }
+
+    public static RandomForestModel CreateRandomForestRegressionModel(IRegressionProblemData problemData, int nTrees,
+      double r, double m, int seed,
+      out double rmsError, out double avgRelError, out double outOfBagRmsError, out double outOfBagAvgRelError) {
+      return RandomForestModel.CreateRegressionModel(problemData, nTrees, r, m, seed, out rmsError, out avgRelError, out outOfBagRmsError, out outOfBagAvgRelError);
+    }
+
+    #endregion
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/RandomForest/RandomForestRegressionSolution.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/RandomForest/RandomForestRegressionSolution.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/RandomForest/RandomForestRegressionSolution.cs	(revision 13819)
@@ -0,0 +1,53 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Problems.DataAnalysis;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  /// <summary>
+  /// Represents a random forest solution for a regression problem which can be visualized in the GUI.
+  /// </summary>
+  [Item("RandomForestRegressionSolution", "Represents a random forest solution for a regression problem which can be visualized in the GUI.")]
+  [StorableClass]
+  public sealed class RandomForestRegressionSolution : RegressionSolution, IRandomForestRegressionSolution {
+
+    public new IRandomForestModel Model {
+      get { return (IRandomForestModel)base.Model; }
+      set { base.Model = value; }
+    }
+
+    [StorableConstructor]
+    private RandomForestRegressionSolution(bool deserializing) : base(deserializing) { }
+    private RandomForestRegressionSolution(RandomForestRegressionSolution original, Cloner cloner)
+      : base(original, cloner) {
+    }
+    public RandomForestRegressionSolution(IRegressionProblemData problemData, IRandomForestModel randomForestModel)
+      : base(randomForestModel, problemData) {
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new RandomForestRegressionSolution(this, cloner);
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/RandomForest/RandomForestUtil.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/RandomForest/RandomForestUtil.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/RandomForest/RandomForestUtil.cs	(revision 13819)
@@ -0,0 +1,358 @@
+﻿#region License Information
+
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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 System.Linq.Expressions;
+using System.Threading.Tasks;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Problems.DataAnalysis;
+using HeuristicLab.Random;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  [Item("RFParameter", "A random forest parameter collection")]
+  [StorableClass]
+  public class RFParameter : ParameterCollection {
+    public RFParameter() {
+      base.Add(new FixedValueParameter<IntValue>("N", "The number of random forest trees", new IntValue(50)));
+      base.Add(new FixedValueParameter<DoubleValue>("M", "The ratio of features that will be used in the construction of individual trees (0<m<=1)", new DoubleValue(0.1)));
+      base.Add(new FixedValueParameter<DoubleValue>("R", "The ratio of the training set that will be used in the construction of individual trees (0<r<=1)", new DoubleValue(0.1)));
+    }
+
+    [StorableConstructor]
+    protected RFParameter(bool deserializing)
+      : base(deserializing) {
+    }
+
+    protected RFParameter(RFParameter original, Cloner cloner)
+      : base(original, cloner) {
+      this.N = original.N;
+      this.R = original.R;
+      this.M = original.M;
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new RFParameter(this, cloner);
+    }
+
+    private IFixedValueParameter<IntValue> NParameter {
+      get { return (IFixedValueParameter<IntValue>)base["N"]; }
+    }
+
+    private IFixedValueParameter<DoubleValue> RParameter {
+      get { return (IFixedValueParameter<DoubleValue>)base["R"]; }
+    }
+
+    private IFixedValueParameter<DoubleValue> MParameter {
+      get { return (IFixedValueParameter<DoubleValue>)base["M"]; }
+    }
+
+    public int N {
+      get { return NParameter.Value.Value; }
+      set { NParameter.Value.Value = value; }
+    }
+
+    public double R {
+      get { return RParameter.Value.Value; }
+      set { RParameter.Value.Value = value; }
+    }
+
+    public double M {
+      get { return MParameter.Value.Value; }
+      set { MParameter.Value.Value = value; }
+    }
+  }
+
+  public static class RandomForestUtil {
+    private static void CrossValidate(IRegressionProblemData problemData, Tuple<IEnumerable<int>, IEnumerable<int>>[] partitions, int nTrees, double r, double m, int seed, out double avgTestMse) {
+      avgTestMse = 0;
+      var ds = problemData.Dataset;
+      var targetVariable = GetTargetVariableName(problemData);
+      foreach (var tuple in partitions) {
+        double rmsError, avgRelError, outOfBagAvgRelError, outOfBagRmsError;
+        var trainingRandomForestPartition = tuple.Item1;
+        var testRandomForestPartition = tuple.Item2;
+        var model = RandomForestModel.CreateRegressionModel(problemData, trainingRandomForestPartition, nTrees, r, m, seed, out rmsError, out avgRelError, out outOfBagRmsError, out outOfBagAvgRelError);
+        var estimatedValues = model.GetEstimatedValues(ds, testRandomForestPartition);
+        var targetValues = ds.GetDoubleValues(targetVariable, testRandomForestPartition);
+        OnlineCalculatorError calculatorError;
+        double mse = OnlineMeanSquaredErrorCalculator.Calculate(estimatedValues, targetValues, out calculatorError);
+        if (calculatorError != OnlineCalculatorError.None)
+          mse = double.NaN;
+        avgTestMse += mse;
+      }
+      avgTestMse /= partitions.Length;
+    }
+
+    private static void CrossValidate(IClassificationProblemData problemData, Tuple<IEnumerable<int>, IEnumerable<int>>[] partitions, int nTrees, double r, double m, int seed, out double avgTestAccuracy) {
+      avgTestAccuracy = 0;
+      var ds = problemData.Dataset;
+      var targetVariable = GetTargetVariableName(problemData);
+      foreach (var tuple in partitions) {
+        double rmsError, avgRelError, outOfBagAvgRelError, outOfBagRmsError;
+        var trainingRandomForestPartition = tuple.Item1;
+        var testRandomForestPartition = tuple.Item2;
+        var model = RandomForestModel.CreateClassificationModel(problemData, trainingRandomForestPartition, nTrees, r, m, seed, out rmsError, out avgRelError, out outOfBagRmsError, out outOfBagAvgRelError);
+        var estimatedValues = model.GetEstimatedClassValues(ds, testRandomForestPartition);
+        var targetValues = ds.GetDoubleValues(targetVariable, testRandomForestPartition);
+        OnlineCalculatorError calculatorError;
+        double accuracy = OnlineAccuracyCalculator.Calculate(estimatedValues, targetValues, out calculatorError);
+        if (calculatorError != OnlineCalculatorError.None)
+          accuracy = double.NaN;
+        avgTestAccuracy += accuracy;
+      }
+      avgTestAccuracy /= partitions.Length;
+    }
+
+    /// <summary>
+    /// Grid search without crossvalidation (since for random forests the out-of-bag estimate is unbiased)
+    /// </summary>
+    /// <param name="problemData">The regression problem data</param>
+    /// <param name="parameterRanges">The ranges for each parameter in the grid search</param>
+    /// <param name="seed">The random seed (required by the random forest model)</param>
+    /// <param name="maxDegreeOfParallelism">The maximum allowed number of threads (to parallelize the grid search)</param>
+    public static RFParameter GridSearch(IRegressionProblemData problemData, Dictionary<string, IEnumerable<double>> parameterRanges, int seed = 12345, int maxDegreeOfParallelism = 1) {
+      var setters = parameterRanges.Keys.Select(GenerateSetter).ToList();
+      var crossProduct = parameterRanges.Values.CartesianProduct();
+      double bestOutOfBagRmsError = double.MaxValue;
+      RFParameter bestParameters = new RFParameter();
+
+      var locker = new object();
+      Parallel.ForEach(crossProduct, new ParallelOptions { MaxDegreeOfParallelism = maxDegreeOfParallelism }, parameterCombination => {
+        var parameterValues = parameterCombination.ToList();
+        var parameters = new RFParameter();
+        for (int i = 0; i < setters.Count; ++i) { setters[i](parameters, parameterValues[i]); }
+        double rmsError, outOfBagRmsError, avgRelError, outOfBagAvgRelError;
+        RandomForestModel.CreateRegressionModel(problemData, problemData.TrainingIndices, parameters.N, parameters.R, parameters.M, seed, out rmsError, out outOfBagRmsError, out avgRelError, out outOfBagAvgRelError);
+
+        lock (locker) {
+          if (bestOutOfBagRmsError > outOfBagRmsError) {
+            bestOutOfBagRmsError = outOfBagRmsError;
+            bestParameters = (RFParameter)parameters.Clone();
+          }
+        }
+      });
+      return bestParameters;
+    }
+
+    /// <summary>
+    /// Grid search without crossvalidation (since for random forests the out-of-bag estimate is unbiased)
+    /// </summary>
+    /// <param name="problemData">The classification problem data</param>
+    /// <param name="parameterRanges">The ranges for each parameter in the grid search</param>
+    /// <param name="seed">The random seed (required by the random forest model)</param>
+    /// <param name="maxDegreeOfParallelism">The maximum allowed number of threads (to parallelize the grid search)</param>
+    public static RFParameter GridSearch(IClassificationProblemData problemData, Dictionary<string, IEnumerable<double>> parameterRanges, int seed = 12345, int maxDegreeOfParallelism = 1) {
+      var setters = parameterRanges.Keys.Select(GenerateSetter).ToList();
+      var crossProduct = parameterRanges.Values.CartesianProduct();
+
+      double bestOutOfBagRmsError = double.MaxValue;
+      RFParameter bestParameters = new RFParameter();
+
+      var locker = new object();
+      Parallel.ForEach(crossProduct, new ParallelOptions { MaxDegreeOfParallelism = maxDegreeOfParallelism }, parameterCombination => {
+        var parameterValues = parameterCombination.ToList();
+        var parameters = new RFParameter();
+        for (int i = 0; i < setters.Count; ++i) { setters[i](parameters, parameterValues[i]); }
+        double rmsError, outOfBagRmsError, avgRelError, outOfBagAvgRelError;
+        RandomForestModel.CreateClassificationModel(problemData, problemData.TrainingIndices, parameters.N, parameters.R, parameters.M, seed,
+                                                                out rmsError, out outOfBagRmsError, out avgRelError, out outOfBagAvgRelError);
+
+        lock (locker) {
+          if (bestOutOfBagRmsError > outOfBagRmsError) {
+            bestOutOfBagRmsError = outOfBagRmsError;
+            bestParameters = (RFParameter)parameters.Clone();
+          }
+        }
+      });
+      return bestParameters;
+    }
+
+    /// <summary>
+    /// Grid search with crossvalidation
+    /// </summary>
+    /// <param name="problemData">The regression problem data</param>
+    /// <param name="numberOfFolds">The number of folds for crossvalidation</param>
+    /// <param name="shuffleFolds">Specifies whether the folds should be shuffled</param>
+    /// <param name="parameterRanges">The ranges for each parameter in the grid search</param>
+    /// <param name="seed">The random seed (required by the random forest model)</param>
+    /// <param name="maxDegreeOfParallelism">The maximum allowed number of threads (to parallelize the grid search)</param>
+    /// <returns>The best parameter values found by the grid search</returns>
+    public static RFParameter GridSearch(IRegressionProblemData problemData, int numberOfFolds, bool shuffleFolds, Dictionary<string, IEnumerable<double>> parameterRanges, int seed = 12345, int maxDegreeOfParallelism = 1) {
+      DoubleValue mse = new DoubleValue(Double.MaxValue);
+      RFParameter bestParameter = new RFParameter();
+
+      var setters = parameterRanges.Keys.Select(GenerateSetter).ToList();
+      var partitions = GenerateRandomForestPartitions(problemData, numberOfFolds);
+      var crossProduct = parameterRanges.Values.CartesianProduct();
+
+      var locker = new object();
+      Parallel.ForEach(crossProduct, new ParallelOptions { MaxDegreeOfParallelism = maxDegreeOfParallelism }, parameterCombination => {
+        var parameterValues = parameterCombination.ToList();
+        double testMSE;
+        var parameters = new RFParameter();
+        for (int i = 0; i < setters.Count; ++i) {
+          setters[i](parameters, parameterValues[i]);
+        }
+        CrossValidate(problemData, partitions, parameters.N, parameters.R, parameters.M, seed, out testMSE);
+
+        lock (locker) {
+          if (testMSE < mse.Value) {
+            mse.Value = testMSE;
+            bestParameter = (RFParameter)parameters.Clone();
+          }
+        }
+      });
+      return bestParameter;
+    }
+
+    /// <summary>
+    /// Grid search with crossvalidation
+    /// </summary>
+    /// <param name="problemData">The classification problem data</param>
+    /// <param name="numberOfFolds">The number of folds for crossvalidation</param>
+    /// <param name="shuffleFolds">Specifies whether the folds should be shuffled</param>
+    /// <param name="parameterRanges">The ranges for each parameter in the grid search</param>
+    /// <param name="seed">The random seed (for shuffling)</param>
+    /// <param name="maxDegreeOfParallelism">The maximum allowed number of threads (to parallelize the grid search)</param>
+    public static RFParameter GridSearch(IClassificationProblemData problemData, int numberOfFolds, bool shuffleFolds, Dictionary<string, IEnumerable<double>> parameterRanges, int seed = 12345, int maxDegreeOfParallelism = 1) {
+      DoubleValue accuracy = new DoubleValue(0);
+      RFParameter bestParameter = new RFParameter();
+
+      var setters = parameterRanges.Keys.Select(GenerateSetter).ToList();
+      var crossProduct = parameterRanges.Values.CartesianProduct();
+      var partitions = GenerateRandomForestPartitions(problemData, numberOfFolds, shuffleFolds);
+
+      var locker = new object();
+      Parallel.ForEach(crossProduct, new ParallelOptions { MaxDegreeOfParallelism = maxDegreeOfParallelism }, parameterCombination => {
+        var parameterValues = parameterCombination.ToList();
+        double testAccuracy;
+        var parameters = new RFParameter();
+        for (int i = 0; i < setters.Count; ++i) {
+          setters[i](parameters, parameterValues[i]);
+        }
+        CrossValidate(problemData, partitions, parameters.N, parameters.R, parameters.M, seed, out testAccuracy);
+
+        lock (locker) {
+          if (testAccuracy > accuracy.Value) {
+            accuracy.Value = testAccuracy;
+            bestParameter = (RFParameter)parameters.Clone();
+          }
+        }
+      });
+      return bestParameter;
+    }
+
+    private static Tuple<IEnumerable<int>, IEnumerable<int>>[] GenerateRandomForestPartitions(IDataAnalysisProblemData problemData, int numberOfFolds, bool shuffleFolds = false) {
+      var folds = GenerateFolds(problemData, numberOfFolds, shuffleFolds).ToList();
+      var partitions = new Tuple<IEnumerable<int>, IEnumerable<int>>[numberOfFolds];
+
+      for (int i = 0; i < numberOfFolds; ++i) {
+        int p = i; // avoid "access to modified closure" warning
+        var trainingRows = folds.SelectMany((par, j) => j != p ? par : Enumerable.Empty<int>());
+        var testRows = folds[i];
+        partitions[i] = new Tuple<IEnumerable<int>, IEnumerable<int>>(trainingRows, testRows);
+      }
+      return partitions;
+    }
+
+    public static IEnumerable<IEnumerable<int>> GenerateFolds(IDataAnalysisProblemData problemData, int numberOfFolds, bool shuffleFolds = false) {
+      var random = new MersenneTwister((uint)Environment.TickCount);
+      if (problemData is IRegressionProblemData) {
+        var trainingIndices = shuffleFolds ? problemData.TrainingIndices.OrderBy(x => random.Next()) : problemData.TrainingIndices;
+        return GenerateFolds(trainingIndices, problemData.TrainingPartition.Size, numberOfFolds);
+      }
+      if (problemData is IClassificationProblemData) {
+        // when shuffle is enabled do stratified folds generation, some folds may have zero elements 
+        // otherwise, generate folds normally
+        return shuffleFolds ? GenerateFoldsStratified(problemData as IClassificationProblemData, numberOfFolds, random) : GenerateFolds(problemData.TrainingIndices, problemData.TrainingPartition.Size, numberOfFolds);
+      }
+      throw new ArgumentException("Problem data is neither regression or classification problem data.");
+    }
+
+    /// <summary>
+    /// Stratified fold generation from classification data. Stratification means that we ensure the same distribution of class labels for each fold.
+    /// The samples are grouped by class label and each group is split into @numberOfFolds parts. The final folds are formed from the joining of 
+    /// the corresponding parts from each class label.
+    /// </summary>
+    /// <param name="problemData">The classification problem data.</param>
+    /// <param name="numberOfFolds">The number of folds in which to split the data.</param>
+    /// <param name="random">The random generator used to shuffle the folds.</param>
+    /// <returns>An enumerable sequece of folds, where a fold is represented by a sequence of row indices.</returns>
+    private static IEnumerable<IEnumerable<int>> GenerateFoldsStratified(IClassificationProblemData problemData, int numberOfFolds, IRandom random) {
+      var values = problemData.Dataset.GetDoubleValues(problemData.TargetVariable, problemData.TrainingIndices);
+      var valuesIndices = problemData.TrainingIndices.Zip(values, (i, v) => new { Index = i, Value = v }).ToList();
+      IEnumerable<IEnumerable<IEnumerable<int>>> foldsByClass = valuesIndices.GroupBy(x => x.Value, x => x.Index).Select(g => GenerateFolds(g, g.Count(), numberOfFolds));
+      var enumerators = foldsByClass.Select(f => f.GetEnumerator()).ToList();
+      while (enumerators.All(e => e.MoveNext())) {
+        yield return enumerators.SelectMany(e => e.Current).OrderBy(x => random.Next()).ToList();
+      }
+    }
+
+    private static IEnumerable<IEnumerable<T>> GenerateFolds<T>(IEnumerable<T> values, int valuesCount, int numberOfFolds) {
+      // if number of folds is greater than the number of values, some empty folds will be returned
+      if (valuesCount < numberOfFolds) {
+        for (int i = 0; i < numberOfFolds; ++i)
+          yield return i < valuesCount ? values.Skip(i).Take(1) : Enumerable.Empty<T>();
+      } else {
+        int f = valuesCount / numberOfFolds, r = valuesCount % numberOfFolds; // number of folds rounded to integer and remainder
+        int start = 0, end = f;
+        for (int i = 0; i < numberOfFolds; ++i) {
+          if (r > 0) {
+            ++end;
+            --r;
+          }
+          yield return values.Skip(start).Take(end - start);
+          start = end;
+          end += f;
+        }
+      }
+    }
+
+    private static Action<RFParameter, double> GenerateSetter(string field) {
+      var targetExp = Expression.Parameter(typeof(RFParameter));
+      var valueExp = Expression.Parameter(typeof(double));
+      var fieldExp = Expression.Property(targetExp, field);
+      var assignExp = Expression.Assign(fieldExp, Expression.Convert(valueExp, fieldExp.Type));
+      var setter = Expression.Lambda<Action<RFParameter, double>>(assignExp, targetExp, valueExp).Compile();
+      return setter;
+    }
+
+    private static string GetTargetVariableName(IDataAnalysisProblemData problemData) {
+      var regressionProblemData = problemData as IRegressionProblemData;
+      var classificationProblemData = problemData as IClassificationProblemData;
+
+      if (regressionProblemData != null)
+        return regressionProblemData.TargetVariable;
+      if (classificationProblemData != null)
+        return classificationProblemData.TargetVariable;
+
+      throw new ArgumentException("Problem data is neither regression or classification problem data.");
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/SupportVectorMachine/SupportVectorClassification.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/SupportVectorMachine/SupportVectorClassification.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/SupportVectorMachine/SupportVectorClassification.cs	(revision 13819)
@@ -0,0 +1,267 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Optimization;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Problems.DataAnalysis;
+using LibSVM;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  /// <summary>
+  /// Support vector machine classification data analysis algorithm.
+  /// </summary>
+  [Item("Support Vector Classification (SVM)", "Support vector machine classification data analysis algorithm (wrapper for libSVM).")]
+  [Creatable(CreatableAttribute.Categories.DataAnalysisClassification, Priority = 110)]
+  [StorableClass]
+  public sealed class SupportVectorClassification : FixedDataAnalysisAlgorithm<IClassificationProblem> {
+    private const string SvmTypeParameterName = "SvmType";
+    private const string KernelTypeParameterName = "KernelType";
+    private const string CostParameterName = "Cost";
+    private const string NuParameterName = "Nu";
+    private const string GammaParameterName = "Gamma";
+    private const string DegreeParameterName = "Degree";
+    private const string CreateSolutionParameterName = "CreateSolution";
+
+    #region parameter properties
+    public IConstrainedValueParameter<StringValue> SvmTypeParameter {
+      get { return (IConstrainedValueParameter<StringValue>)Parameters[SvmTypeParameterName]; }
+    }
+    public IConstrainedValueParameter<StringValue> KernelTypeParameter {
+      get { return (IConstrainedValueParameter<StringValue>)Parameters[KernelTypeParameterName]; }
+    }
+    public IValueParameter<DoubleValue> NuParameter {
+      get { return (IValueParameter<DoubleValue>)Parameters[NuParameterName]; }
+    }
+    public IValueParameter<DoubleValue> CostParameter {
+      get { return (IValueParameter<DoubleValue>)Parameters[CostParameterName]; }
+    }
+    public IValueParameter<DoubleValue> GammaParameter {
+      get { return (IValueParameter<DoubleValue>)Parameters[GammaParameterName]; }
+    }
+    public IValueParameter<IntValue> DegreeParameter {
+      get { return (IValueParameter<IntValue>)Parameters[DegreeParameterName]; }
+    }
+    public IFixedValueParameter<BoolValue> CreateSolutionParameter {
+      get { return (IFixedValueParameter<BoolValue>)Parameters[CreateSolutionParameterName]; }
+    }
+    #endregion
+    #region properties
+    public StringValue SvmType {
+      get { return SvmTypeParameter.Value; }
+      set { SvmTypeParameter.Value = value; }
+    }
+    public StringValue KernelType {
+      get { return KernelTypeParameter.Value; }
+      set { KernelTypeParameter.Value = value; }
+    }
+    public DoubleValue Nu {
+      get { return NuParameter.Value; }
+    }
+    public DoubleValue Cost {
+      get { return CostParameter.Value; }
+    }
+    public DoubleValue Gamma {
+      get { return GammaParameter.Value; }
+    }
+    public IntValue Degree {
+      get { return DegreeParameter.Value; }
+    }
+    public bool CreateSolution {
+      get { return CreateSolutionParameter.Value.Value; }
+      set { CreateSolutionParameter.Value.Value = value; }
+    }
+    #endregion
+    [StorableConstructor]
+    private SupportVectorClassification(bool deserializing) : base(deserializing) { }
+    private SupportVectorClassification(SupportVectorClassification original, Cloner cloner)
+      : base(original, cloner) {
+    }
+    public SupportVectorClassification()
+      : base() {
+      Problem = new ClassificationProblem();
+
+      List<StringValue> svrTypes = (from type in new List<string> { "NU_SVC", "C_SVC" }
+                                    select new StringValue(type).AsReadOnly())
+                                   .ToList();
+      ItemSet<StringValue> svrTypeSet = new ItemSet<StringValue>(svrTypes);
+      List<StringValue> kernelTypes = (from type in new List<string> { "LINEAR", "POLY", "SIGMOID", "RBF" }
+                                       select new StringValue(type).AsReadOnly())
+                                   .ToList();
+      ItemSet<StringValue> kernelTypeSet = new ItemSet<StringValue>(kernelTypes);
+      Parameters.Add(new ConstrainedValueParameter<StringValue>(SvmTypeParameterName, "The type of SVM to use.", svrTypeSet, svrTypes[0]));
+      Parameters.Add(new ConstrainedValueParameter<StringValue>(KernelTypeParameterName, "The kernel type to use for the SVM.", kernelTypeSet, kernelTypes[3]));
+      Parameters.Add(new ValueParameter<DoubleValue>(NuParameterName, "The value of the nu parameter nu-SVC.", new DoubleValue(0.5)));
+      Parameters.Add(new ValueParameter<DoubleValue>(CostParameterName, "The value of the C (cost) parameter of C-SVC.", new DoubleValue(1.0)));
+      Parameters.Add(new ValueParameter<DoubleValue>(GammaParameterName, "The value of the gamma parameter in the kernel function.", new DoubleValue(1.0)));
+      Parameters.Add(new ValueParameter<IntValue>(DegreeParameterName, "The degree parameter for the polynomial kernel function.", new IntValue(3)));
+      Parameters.Add(new FixedValueParameter<BoolValue>(CreateSolutionParameterName, "Flag that indicates if a solution should be produced at the end of the run", new BoolValue(true)));
+      Parameters[CreateSolutionParameterName].Hidden = true;
+    }
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() {
+      #region backwards compatibility (change with 3.4)
+      if (!Parameters.ContainsKey(DegreeParameterName)) {
+        Parameters.Add(new ValueParameter<IntValue>(DegreeParameterName,
+          "The degree parameter for the polynomial kernel function.", new IntValue(3)));
+      }
+      if (!Parameters.ContainsKey(CreateSolutionParameterName)) {
+        Parameters.Add(new FixedValueParameter<BoolValue>(CreateSolutionParameterName,
+          "Flag that indicates if a solution should be produced at the end of the run", new BoolValue(true)));
+        Parameters[CreateSolutionParameterName].Hidden = true;
+      }
+      #endregion
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new SupportVectorClassification(this, cloner);
+    }
+
+    #region support vector classification
+    protected override void Run() {
+      IClassificationProblemData problemData = Problem.ProblemData;
+      IEnumerable<string> selectedInputVariables = problemData.AllowedInputVariables;
+      int nSv;
+      ISupportVectorMachineModel model;
+
+      Run(problemData, selectedInputVariables, GetSvmType(SvmType.Value), GetKernelType(KernelType.Value), Cost.Value, Nu.Value, Gamma.Value, Degree.Value, out model, out nSv);
+
+      if (CreateSolution) {
+        var solution = new SupportVectorClassificationSolution((SupportVectorMachineModel)model, (IClassificationProblemData)problemData.Clone());
+        Results.Add(new Result("Support vector classification solution", "The support vector classification solution.",
+          solution));
+      }
+
+      {
+        // calculate classification metrics
+        // calculate regression model metrics 
+        var ds = problemData.Dataset;
+        var trainRows = problemData.TrainingIndices;
+        var testRows = problemData.TestIndices;
+        var yTrain = ds.GetDoubleValues(problemData.TargetVariable, trainRows);
+        var yTest = ds.GetDoubleValues(problemData.TargetVariable, testRows);
+        var yPredTrain = model.GetEstimatedClassValues(ds, trainRows);
+        var yPredTest = model.GetEstimatedClassValues(ds, testRows);
+
+        OnlineCalculatorError error;
+        var trainAccuracy = OnlineAccuracyCalculator.Calculate(yPredTrain, yTrain, out error);
+        if (error != OnlineCalculatorError.None) trainAccuracy = double.MaxValue;
+        var testAccuracy = OnlineAccuracyCalculator.Calculate(yPredTest, yTest, out error);
+        if (error != OnlineCalculatorError.None) testAccuracy = double.MaxValue;
+
+        Results.Add(new Result("Accuracy (training)", "The mean of squared errors of the SVR solution on the training partition.", new DoubleValue(trainAccuracy)));
+        Results.Add(new Result("Accuracy (test)", "The mean of squared errors of the SVR solution on the test partition.", new DoubleValue(testAccuracy)));
+
+        Results.Add(new Result("Number of support vectors", "The number of support vectors of the SVR solution.",
+          new IntValue(nSv)));
+      }
+    }
+
+    public static SupportVectorClassificationSolution CreateSupportVectorClassificationSolution(IClassificationProblemData problemData, IEnumerable<string> allowedInputVariables,
+      string svmType, string kernelType, double cost, double nu, double gamma, int degree, out double trainingAccuracy, out double testAccuracy, out int nSv) {
+      return CreateSupportVectorClassificationSolution(problemData, allowedInputVariables, GetSvmType(svmType), GetKernelType(kernelType), cost, nu, gamma, degree,
+        out trainingAccuracy, out testAccuracy, out nSv);
+    }
+
+    // BackwardsCompatibility3.4
+    #region Backwards compatible code, remove with 3.5
+    public static SupportVectorClassificationSolution CreateSupportVectorClassificationSolution(IClassificationProblemData problemData, IEnumerable<string> allowedInputVariables,
+      int svmType, int kernelType, double cost, double nu, double gamma, int degree, out double trainingAccuracy, out double testAccuracy, out int nSv) {
+
+      ISupportVectorMachineModel model;
+      Run(problemData, allowedInputVariables, svmType, kernelType, cost, nu, gamma, degree, out model, out nSv);
+      var solution = new SupportVectorClassificationSolution((SupportVectorMachineModel)model, (IClassificationProblemData)problemData.Clone());
+
+      trainingAccuracy = solution.TrainingAccuracy;
+      testAccuracy = solution.TestAccuracy;
+
+      return solution;
+    }
+
+    #endregion
+
+    public static void Run(IClassificationProblemData problemData, IEnumerable<string> allowedInputVariables,
+      int svmType, int kernelType, double cost, double nu, double gamma, int degree,
+      out ISupportVectorMachineModel model, out int nSv) {
+      var dataset = problemData.Dataset;
+      string targetVariable = problemData.TargetVariable;
+      IEnumerable<int> rows = problemData.TrainingIndices;
+
+      svm_parameter parameter = new svm_parameter {
+        svm_type = svmType,
+        kernel_type = kernelType,
+        C = cost,
+        nu = nu,
+        gamma = gamma,
+        cache_size = 500,
+        probability = 0,
+        eps = 0.001,
+        degree = degree,
+        shrinking = 1,
+        coef0 = 0
+      };
+
+      var weightLabels = new List<int>();
+      var weights = new List<double>();
+      foreach (double c in problemData.ClassValues) {
+        double wSum = 0.0;
+        foreach (double otherClass in problemData.ClassValues) {
+          if (!c.IsAlmost(otherClass)) {
+            wSum += problemData.GetClassificationPenalty(c, otherClass);
+          }
+        }
+        weightLabels.Add((int)c);
+        weights.Add(wSum);
+      }
+      parameter.weight_label = weightLabels.ToArray();
+      parameter.weight = weights.ToArray();
+
+      svm_problem problem = SupportVectorMachineUtil.CreateSvmProblem(dataset, targetVariable, allowedInputVariables, rows);
+      RangeTransform rangeTransform = RangeTransform.Compute(problem);
+      svm_problem scaledProblem = rangeTransform.Scale(problem);
+      var svmModel = svm.svm_train(scaledProblem, parameter);
+      nSv = svmModel.SV.Length;
+
+      model = new SupportVectorMachineModel(svmModel, rangeTransform, targetVariable, allowedInputVariables, problemData.ClassValues);
+    }
+
+    private static int GetSvmType(string svmType) {
+      if (svmType == "NU_SVC") return svm_parameter.NU_SVC;
+      if (svmType == "C_SVC") return svm_parameter.C_SVC;
+      throw new ArgumentException("Unknown SVM type");
+    }
+
+    private static int GetKernelType(string kernelType) {
+      if (kernelType == "LINEAR") return svm_parameter.LINEAR;
+      if (kernelType == "POLY") return svm_parameter.POLY;
+      if (kernelType == "SIGMOID") return svm_parameter.SIGMOID;
+      if (kernelType == "RBF") return svm_parameter.RBF;
+      throw new ArgumentException("Unknown kernel type");
+    }
+    #endregion
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/SupportVectorMachine/SupportVectorClassificationSolution.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/SupportVectorMachine/SupportVectorClassificationSolution.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/SupportVectorMachine/SupportVectorClassificationSolution.cs	(revision 13819)
@@ -0,0 +1,53 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Problems.DataAnalysis;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  /// <summary>
+  /// Represents a support vector solution for a classification problem which can be visualized in the GUI.
+  /// </summary>
+  [Item("SupportVectorClassificationSolution", "Represents a support vector solution for a classification problem which can be visualized in the GUI.")]
+  [StorableClass]
+  public sealed class SupportVectorClassificationSolution : ClassificationSolution, ISupportVectorMachineSolution {
+
+    public new ISupportVectorMachineModel Model {
+      get { return (ISupportVectorMachineModel)base.Model; }
+      set { base.Model = value; }
+    }
+
+    [StorableConstructor]
+    private SupportVectorClassificationSolution(bool deserializing) : base(deserializing) { }
+    private SupportVectorClassificationSolution(SupportVectorClassificationSolution original, Cloner cloner)
+      : base(original, cloner) {
+    }
+    public SupportVectorClassificationSolution(SupportVectorMachineModel model, IClassificationProblemData problemData)
+      : base(model, problemData) {
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new SupportVectorClassificationSolution(this, cloner);
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/SupportVectorMachine/SupportVectorMachineModel.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/SupportVectorMachine/SupportVectorMachineModel.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/SupportVectorMachine/SupportVectorMachineModel.cs	(revision 13819)
@@ -0,0 +1,215 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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.IO;
+using System.Linq;
+using System.Text;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Problems.DataAnalysis;
+using LibSVM;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  /// <summary>
+  /// Represents a support vector machine model.
+  /// </summary>
+  [StorableClass]
+  [Item("SupportVectorMachineModel", "Represents a support vector machine model.")]
+  public sealed class SupportVectorMachineModel : NamedItem, ISupportVectorMachineModel {
+
+    private svm_model model;
+    /// <summary>
+    /// Gets or sets the SVM model.
+    /// </summary>
+    public svm_model Model {
+      get { return model; }
+      set {
+        if (value != model) {
+          if (value == null) throw new ArgumentNullException();
+          model = value;
+          OnChanged(EventArgs.Empty);
+        }
+      }
+    }
+
+    /// <summary>
+    /// Gets or sets the range transformation for the model.
+    /// </summary>
+    private RangeTransform rangeTransform;
+    public RangeTransform RangeTransform {
+      get { return rangeTransform; }
+      set {
+        if (value != rangeTransform) {
+          if (value == null) throw new ArgumentNullException();
+          rangeTransform = value;
+          OnChanged(EventArgs.Empty);
+        }
+      }
+    }
+
+    public Dataset SupportVectors {
+      get {
+        var data = new double[Model.sv_coef.Length, allowedInputVariables.Count()];
+        for (int i = 0; i < Model.sv_coef.Length; i++) {
+          var sv = Model.SV[i];
+          for (int j = 0; j < sv.Length; j++) {
+            data[i, j] = sv[j].value;
+          }
+        }
+        return new Dataset(allowedInputVariables, data);
+      }
+    }
+
+    [Storable]
+    private string targetVariable;
+    [Storable]
+    private string[] allowedInputVariables;
+    [Storable]
+    private double[] classValues; // only for SVM classification models
+
+    [StorableConstructor]
+    private SupportVectorMachineModel(bool deserializing) : base(deserializing) { }
+    private SupportVectorMachineModel(SupportVectorMachineModel original, Cloner cloner)
+      : base(original, cloner) {
+      // only using a shallow copy here! (gkronber)
+      this.model = original.model;
+      this.rangeTransform = original.rangeTransform;
+      this.targetVariable = original.targetVariable;
+      this.allowedInputVariables = (string[])original.allowedInputVariables.Clone();
+      if (original.classValues != null)
+        this.classValues = (double[])original.classValues.Clone();
+    }
+    public SupportVectorMachineModel(svm_model model, RangeTransform rangeTransform, string targetVariable, IEnumerable<string> allowedInputVariables, IEnumerable<double> classValues)
+      : this(model, rangeTransform, targetVariable, allowedInputVariables) {
+      this.classValues = classValues.ToArray();
+    }
+    public SupportVectorMachineModel(svm_model model, RangeTransform rangeTransform, string targetVariable, IEnumerable<string> allowedInputVariables)
+      : base() {
+      this.name = ItemName;
+      this.description = ItemDescription;
+      this.model = model;
+      this.rangeTransform = rangeTransform;
+      this.targetVariable = targetVariable;
+      this.allowedInputVariables = allowedInputVariables.ToArray();
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new SupportVectorMachineModel(this, cloner);
+    }
+
+    #region IRegressionModel Members
+    public IEnumerable<double> GetEstimatedValues(IDataset dataset, IEnumerable<int> rows) {
+      return GetEstimatedValuesHelper(dataset, rows);
+    }
+    public SupportVectorRegressionSolution CreateRegressionSolution(IRegressionProblemData problemData) {
+      return new SupportVectorRegressionSolution(this, new RegressionProblemData(problemData));
+    }
+    IRegressionSolution IRegressionModel.CreateRegressionSolution(IRegressionProblemData problemData) {
+      return CreateRegressionSolution(problemData);
+    }
+    #endregion
+
+    #region IClassificationModel Members
+    public IEnumerable<double> GetEstimatedClassValues(IDataset dataset, IEnumerable<int> rows) {
+      if (classValues == null) throw new NotSupportedException();
+      // return the original class value instead of the predicted value of the model
+      // svm classification only works for integer classes
+      foreach (var estimated in GetEstimatedValuesHelper(dataset, rows)) {
+        // find closest class
+        double bestDist = double.MaxValue;
+        double bestClass = -1;
+        for (int i = 0; i < classValues.Length; i++) {
+          double d = Math.Abs(estimated - classValues[i]);
+          if (d < bestDist) {
+            bestDist = d;
+            bestClass = classValues[i];
+            if (d.IsAlmost(0.0)) break; // exact match no need to look further
+          }
+        }
+        yield return bestClass;
+      }
+    }
+
+    public SupportVectorClassificationSolution CreateClassificationSolution(IClassificationProblemData problemData) {
+      return new SupportVectorClassificationSolution(this, new ClassificationProblemData(problemData));
+    }
+    IClassificationSolution IClassificationModel.CreateClassificationSolution(IClassificationProblemData problemData) {
+      return CreateClassificationSolution(problemData);
+    }
+    #endregion
+    private IEnumerable<double> GetEstimatedValuesHelper(IDataset dataset, IEnumerable<int> rows) {
+      // calculate predictions for the currently requested rows
+      svm_problem problem = SupportVectorMachineUtil.CreateSvmProblem(dataset, targetVariable, allowedInputVariables, rows);
+      svm_problem scaledProblem = rangeTransform.Scale(problem);
+
+      for (int i = 0; i < problem.l; i++) {
+        yield return svm.svm_predict(Model, scaledProblem.x[i]);
+      }
+    }
+
+    #region events
+    public event EventHandler Changed;
+    private void OnChanged(EventArgs e) {
+      var handlers = Changed;
+      if (handlers != null)
+        handlers(this, e);
+    }
+    #endregion
+
+    #region persistence
+    [Storable]
+    private string ModelAsString {
+      get {
+        using (MemoryStream stream = new MemoryStream()) {
+          svm.svm_save_model(new StreamWriter(stream), Model);
+          stream.Seek(0, System.IO.SeekOrigin.Begin);
+          StreamReader reader = new StreamReader(stream);
+          return reader.ReadToEnd();
+        }
+      }
+      set {
+        using (MemoryStream stream = new MemoryStream(Encoding.ASCII.GetBytes(value))) {
+          model = svm.svm_load_model(new StreamReader(stream));
+        }
+      }
+    }
+    [Storable]
+    private string RangeTransformAsString {
+      get {
+        using (MemoryStream stream = new MemoryStream()) {
+          RangeTransform.Write(stream, RangeTransform);
+          stream.Seek(0, System.IO.SeekOrigin.Begin);
+          StreamReader reader = new StreamReader(stream);
+          return reader.ReadToEnd();
+        }
+      }
+      set {
+        using (MemoryStream stream = new MemoryStream(Encoding.ASCII.GetBytes(value))) {
+          RangeTransform = RangeTransform.Read(stream);
+        }
+      }
+    }
+    #endregion
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/SupportVectorMachine/SupportVectorMachineUtil.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/SupportVectorMachine/SupportVectorMachineUtil.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/SupportVectorMachine/SupportVectorMachineUtil.cs	(revision 13819)
@@ -0,0 +1,230 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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 System.Linq.Expressions;
+using System.Threading.Tasks;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Problems.DataAnalysis;
+using HeuristicLab.Random;
+using LibSVM;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  public class SupportVectorMachineUtil {
+    /// <summary>
+    /// Transforms <paramref name="problemData"/> into a data structure as needed by libSVM.
+    /// </summary>
+    /// <param name="problemData">The problem data to transform</param>
+    /// <param name="rowIndices">The rows of the dataset that should be contained in the resulting SVM-problem</param>
+    /// <returns>A problem data type that can be used to train a support vector machine.</returns>
+    public static svm_problem CreateSvmProblem(IDataset dataset, string targetVariable, IEnumerable<string> inputVariables, IEnumerable<int> rowIndices) {
+      double[] targetVector = dataset.GetDoubleValues(targetVariable, rowIndices).ToArray();
+      svm_node[][] nodes = new svm_node[targetVector.Length][];
+      int maxNodeIndex = 0;
+      int svmProblemRowIndex = 0;
+      List<string> inputVariablesList = inputVariables.ToList();
+      foreach (int row in rowIndices) {
+        List<svm_node> tempRow = new List<svm_node>();
+        int colIndex = 1; // make sure the smallest node index for SVM = 1
+        foreach (var inputVariable in inputVariablesList) {
+          double value = dataset.GetDoubleValue(inputVariable, row);
+          // SVM also works with missing values
+          // => don't add NaN values in the dataset to the sparse SVM matrix representation
+          if (!double.IsNaN(value)) {
+            tempRow.Add(new svm_node() { index = colIndex, value = value });
+            // nodes must be sorted in ascending ordered by column index
+            if (colIndex > maxNodeIndex) maxNodeIndex = colIndex;
+          }
+          colIndex++;
+        }
+        nodes[svmProblemRowIndex++] = tempRow.ToArray();
+      }
+      return new svm_problem { l = targetVector.Length, y = targetVector, x = nodes };
+    }
+
+    /// <summary>
+    /// Instantiate and return a svm_parameter object with default values.
+    /// </summary>
+    /// <returns>A svm_parameter object with default values</returns>
+    public static svm_parameter DefaultParameters() {
+      svm_parameter parameter = new svm_parameter();
+      parameter.svm_type = svm_parameter.NU_SVR;
+      parameter.kernel_type = svm_parameter.RBF;
+      parameter.C = 1;
+      parameter.nu = 0.5;
+      parameter.gamma = 1;
+      parameter.p = 1;
+      parameter.cache_size = 500;
+      parameter.probability = 0;
+      parameter.eps = 0.001;
+      parameter.degree = 3;
+      parameter.shrinking = 1;
+      parameter.coef0 = 0;
+
+      return parameter;
+    }
+
+    public static double CrossValidate(IDataAnalysisProblemData problemData, svm_parameter parameters, int numberOfFolds, bool shuffleFolds = true) {
+      var partitions = GenerateSvmPartitions(problemData, numberOfFolds, shuffleFolds);
+      return CalculateCrossValidationPartitions(partitions, parameters);
+    }
+
+    public static svm_parameter GridSearch(out double cvMse, IDataAnalysisProblemData problemData, Dictionary<string, IEnumerable<double>> parameterRanges, int numberOfFolds, bool shuffleFolds = true, int maxDegreeOfParallelism = 1) {
+      DoubleValue mse = new DoubleValue(Double.MaxValue);
+      var bestParam = DefaultParameters();
+      var crossProduct = parameterRanges.Values.CartesianProduct();
+      var setters = parameterRanges.Keys.Select(GenerateSetter).ToList();
+      var partitions = GenerateSvmPartitions(problemData, numberOfFolds, shuffleFolds);
+
+      var locker = new object(); // for thread synchronization
+      Parallel.ForEach(crossProduct, new ParallelOptions { MaxDegreeOfParallelism = maxDegreeOfParallelism },
+      parameterCombination => {
+        var parameters = DefaultParameters();
+        var parameterValues = parameterCombination.ToList();
+        for (int i = 0; i < parameterValues.Count; ++i)
+          setters[i](parameters, parameterValues[i]);
+
+        double testMse = CalculateCrossValidationPartitions(partitions, parameters);
+        if (!double.IsNaN(testMse)) {
+          lock (locker) {
+            if (testMse < mse.Value) {
+              mse.Value = testMse;
+              bestParam = (svm_parameter)parameters.Clone();
+            }
+          }
+        }
+      });
+      cvMse = mse.Value;
+      return bestParam;
+    }
+
+    private static double CalculateCrossValidationPartitions(Tuple<svm_problem, svm_problem>[] partitions, svm_parameter parameters) {
+      double avgTestMse = 0;
+      var calc = new OnlineMeanSquaredErrorCalculator();
+      foreach (Tuple<svm_problem, svm_problem> tuple in partitions) {
+        var trainingSvmProblem = tuple.Item1;
+        var testSvmProblem = tuple.Item2;
+        var model = svm.svm_train(trainingSvmProblem, parameters);
+        calc.Reset();
+        for (int i = 0; i < testSvmProblem.l; ++i)
+          calc.Add(testSvmProblem.y[i], svm.svm_predict(model, testSvmProblem.x[i]));
+        double mse = calc.ErrorState == OnlineCalculatorError.None ? calc.MeanSquaredError : double.NaN;
+        avgTestMse += mse;
+      }
+      avgTestMse /= partitions.Length;
+      return avgTestMse;
+    }
+
+    private static Tuple<svm_problem, svm_problem>[] GenerateSvmPartitions(IDataAnalysisProblemData problemData, int numberOfFolds, bool shuffleFolds = true) {
+      var folds = GenerateFolds(problemData, numberOfFolds, shuffleFolds).ToList();
+      var targetVariable = GetTargetVariableName(problemData);
+      var partitions = new Tuple<svm_problem, svm_problem>[numberOfFolds];
+      for (int i = 0; i < numberOfFolds; ++i) {
+        int p = i; // avoid "access to modified closure" warning below
+        var trainingRows = folds.SelectMany((par, j) => j != p ? par : Enumerable.Empty<int>());
+        var testRows = folds[i];
+        var trainingSvmProblem = CreateSvmProblem(problemData.Dataset, targetVariable, problemData.AllowedInputVariables, trainingRows);
+        var rangeTransform = RangeTransform.Compute(trainingSvmProblem);
+        var testSvmProblem = rangeTransform.Scale(CreateSvmProblem(problemData.Dataset, targetVariable, problemData.AllowedInputVariables, testRows));
+        partitions[i] = new Tuple<svm_problem, svm_problem>(rangeTransform.Scale(trainingSvmProblem), testSvmProblem);
+      }
+      return partitions;
+    }
+
+    public static IEnumerable<IEnumerable<int>> GenerateFolds(IDataAnalysisProblemData problemData, int numberOfFolds, bool shuffleFolds = true) {
+      var random = new MersenneTwister((uint)Environment.TickCount);
+      if (problemData is IRegressionProblemData) {
+        var trainingIndices = shuffleFolds ? problemData.TrainingIndices.OrderBy(x => random.Next()) : problemData.TrainingIndices;
+        return GenerateFolds(trainingIndices, problemData.TrainingPartition.Size, numberOfFolds);
+      }
+      if (problemData is IClassificationProblemData) {
+        // when shuffle is enabled do stratified folds generation, some folds may have zero elements 
+        // otherwise, generate folds normally
+        return shuffleFolds ? GenerateFoldsStratified(problemData as IClassificationProblemData, numberOfFolds, random) : GenerateFolds(problemData.TrainingIndices, problemData.TrainingPartition.Size, numberOfFolds);
+      }
+      throw new ArgumentException("Problem data is neither regression or classification problem data.");
+    }
+
+    /// <summary>
+    /// Stratified fold generation from classification data. Stratification means that we ensure the same distribution of class labels for each fold.
+    /// The samples are grouped by class label and each group is split into @numberOfFolds parts. The final folds are formed from the joining of 
+    /// the corresponding parts from each class label.
+    /// </summary>
+    /// <param name="problemData">The classification problem data.</param>
+    /// <param name="numberOfFolds">The number of folds in which to split the data.</param>
+    /// <param name="random">The random generator used to shuffle the folds.</param>
+    /// <returns>An enumerable sequece of folds, where a fold is represented by a sequence of row indices.</returns>
+    private static IEnumerable<IEnumerable<int>> GenerateFoldsStratified(IClassificationProblemData problemData, int numberOfFolds, IRandom random) {
+      var values = problemData.Dataset.GetDoubleValues(problemData.TargetVariable, problemData.TrainingIndices);
+      var valuesIndices = problemData.TrainingIndices.Zip(values, (i, v) => new { Index = i, Value = v }).ToList();
+      IEnumerable<IEnumerable<IEnumerable<int>>> foldsByClass = valuesIndices.GroupBy(x => x.Value, x => x.Index).Select(g => GenerateFolds(g, g.Count(), numberOfFolds));
+      var enumerators = foldsByClass.Select(f => f.GetEnumerator()).ToList();
+      while (enumerators.All(e => e.MoveNext())) {
+        yield return enumerators.SelectMany(e => e.Current).OrderBy(x => random.Next()).ToList();
+      }
+    }
+
+    private static IEnumerable<IEnumerable<T>> GenerateFolds<T>(IEnumerable<T> values, int valuesCount, int numberOfFolds) {
+      // if number of folds is greater than the number of values, some empty folds will be returned
+      if (valuesCount < numberOfFolds) {
+        for (int i = 0; i < numberOfFolds; ++i)
+          yield return i < valuesCount ? values.Skip(i).Take(1) : Enumerable.Empty<T>();
+      } else {
+        int f = valuesCount / numberOfFolds, r = valuesCount % numberOfFolds; // number of folds rounded to integer and remainder
+        int start = 0, end = f;
+        for (int i = 0; i < numberOfFolds; ++i) {
+          if (r > 0) {
+            ++end;
+            --r;
+          }
+          yield return values.Skip(start).Take(end - start);
+          start = end;
+          end += f;
+        }
+      }
+    }
+
+    private static Action<svm_parameter, double> GenerateSetter(string fieldName) {
+      var targetExp = Expression.Parameter(typeof(svm_parameter));
+      var valueExp = Expression.Parameter(typeof(double));
+      var fieldExp = Expression.Field(targetExp, fieldName);
+      var assignExp = Expression.Assign(fieldExp, Expression.Convert(valueExp, fieldExp.Type));
+      var setter = Expression.Lambda<Action<svm_parameter, double>>(assignExp, targetExp, valueExp).Compile();
+      return setter;
+    }
+
+    private static string GetTargetVariableName(IDataAnalysisProblemData problemData) {
+      var regressionProblemData = problemData as IRegressionProblemData;
+      var classificationProblemData = problemData as IClassificationProblemData;
+
+      if (regressionProblemData != null)
+        return regressionProblemData.TargetVariable;
+      if (classificationProblemData != null)
+        return classificationProblemData.TargetVariable;
+
+      throw new ArgumentException("Problem data is neither regression or classification problem data.");
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/SupportVectorMachine/SupportVectorRegression.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/SupportVectorMachine/SupportVectorRegression.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/SupportVectorMachine/SupportVectorRegression.cs	(revision 13819)
@@ -0,0 +1,270 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Optimization;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Problems.DataAnalysis;
+using LibSVM;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  /// <summary>
+  /// Support vector machine regression data analysis algorithm.
+  /// </summary>
+  [Item("Support Vector Regression (SVM)", "Support vector machine regression data analysis algorithm (wrapper for libSVM).")]
+  [Creatable(CreatableAttribute.Categories.DataAnalysisRegression, Priority = 110)]
+  [StorableClass]
+  public sealed class SupportVectorRegression : FixedDataAnalysisAlgorithm<IRegressionProblem> {
+    private const string SvmTypeParameterName = "SvmType";
+    private const string KernelTypeParameterName = "KernelType";
+    private const string CostParameterName = "Cost";
+    private const string NuParameterName = "Nu";
+    private const string GammaParameterName = "Gamma";
+    private const string EpsilonParameterName = "Epsilon";
+    private const string DegreeParameterName = "Degree";
+    private const string CreateSolutionParameterName = "CreateSolution";
+
+    #region parameter properties
+    public IConstrainedValueParameter<StringValue> SvmTypeParameter {
+      get { return (IConstrainedValueParameter<StringValue>)Parameters[SvmTypeParameterName]; }
+    }
+    public IConstrainedValueParameter<StringValue> KernelTypeParameter {
+      get { return (IConstrainedValueParameter<StringValue>)Parameters[KernelTypeParameterName]; }
+    }
+    public IValueParameter<DoubleValue> NuParameter {
+      get { return (IValueParameter<DoubleValue>)Parameters[NuParameterName]; }
+    }
+    public IValueParameter<DoubleValue> CostParameter {
+      get { return (IValueParameter<DoubleValue>)Parameters[CostParameterName]; }
+    }
+    public IValueParameter<DoubleValue> GammaParameter {
+      get { return (IValueParameter<DoubleValue>)Parameters[GammaParameterName]; }
+    }
+    public IValueParameter<DoubleValue> EpsilonParameter {
+      get { return (IValueParameter<DoubleValue>)Parameters[EpsilonParameterName]; }
+    }
+    public IValueParameter<IntValue> DegreeParameter {
+      get { return (IValueParameter<IntValue>)Parameters[DegreeParameterName]; }
+    }
+    public IFixedValueParameter<BoolValue> CreateSolutionParameter {
+      get { return (IFixedValueParameter<BoolValue>)Parameters[CreateSolutionParameterName]; }
+    }
+    #endregion
+    #region properties
+    public StringValue SvmType {
+      get { return SvmTypeParameter.Value; }
+      set { SvmTypeParameter.Value = value; }
+    }
+    public StringValue KernelType {
+      get { return KernelTypeParameter.Value; }
+      set { KernelTypeParameter.Value = value; }
+    }
+    public DoubleValue Nu {
+      get { return NuParameter.Value; }
+    }
+    public DoubleValue Cost {
+      get { return CostParameter.Value; }
+    }
+    public DoubleValue Gamma {
+      get { return GammaParameter.Value; }
+    }
+    public DoubleValue Epsilon {
+      get { return EpsilonParameter.Value; }
+    }
+    public IntValue Degree {
+      get { return DegreeParameter.Value; }
+    }
+    public bool CreateSolution {
+      get { return CreateSolutionParameter.Value.Value; }
+      set { CreateSolutionParameter.Value.Value = value; }
+    }
+    #endregion
+    [StorableConstructor]
+    private SupportVectorRegression(bool deserializing) : base(deserializing) { }
+    private SupportVectorRegression(SupportVectorRegression original, Cloner cloner)
+      : base(original, cloner) {
+    }
+    public SupportVectorRegression()
+      : base() {
+      Problem = new RegressionProblem();
+
+      List<StringValue> svrTypes = (from type in new List<string> { "NU_SVR", "EPSILON_SVR" }
+                                    select new StringValue(type).AsReadOnly())
+                                   .ToList();
+      ItemSet<StringValue> svrTypeSet = new ItemSet<StringValue>(svrTypes);
+      List<StringValue> kernelTypes = (from type in new List<string> { "LINEAR", "POLY", "SIGMOID", "RBF" }
+                                       select new StringValue(type).AsReadOnly())
+                                   .ToList();
+      ItemSet<StringValue> kernelTypeSet = new ItemSet<StringValue>(kernelTypes);
+      Parameters.Add(new ConstrainedValueParameter<StringValue>(SvmTypeParameterName, "The type of SVM to use.", svrTypeSet, svrTypes[0]));
+      Parameters.Add(new ConstrainedValueParameter<StringValue>(KernelTypeParameterName, "The kernel type to use for the SVM.", kernelTypeSet, kernelTypes[3]));
+      Parameters.Add(new ValueParameter<DoubleValue>(NuParameterName, "The value of the nu parameter of the nu-SVR.", new DoubleValue(0.5)));
+      Parameters.Add(new ValueParameter<DoubleValue>(CostParameterName, "The value of the C (cost) parameter of epsilon-SVR and nu-SVR.", new DoubleValue(1.0)));
+      Parameters.Add(new ValueParameter<DoubleValue>(GammaParameterName, "The value of the gamma parameter in the kernel function.", new DoubleValue(1.0)));
+      Parameters.Add(new ValueParameter<DoubleValue>(EpsilonParameterName, "The value of the epsilon parameter for epsilon-SVR.", new DoubleValue(0.1)));
+      Parameters.Add(new ValueParameter<IntValue>(DegreeParameterName, "The degree parameter for the polynomial kernel function.", new IntValue(3)));
+      Parameters.Add(new FixedValueParameter<BoolValue>(CreateSolutionParameterName, "Flag that indicates if a solution should be produced at the end of the run", new BoolValue(true)));
+      Parameters[CreateSolutionParameterName].Hidden = true;
+    }
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() {
+      #region backwards compatibility (change with 3.4)
+
+      if (!Parameters.ContainsKey(DegreeParameterName)) {
+        Parameters.Add(new ValueParameter<IntValue>(DegreeParameterName,
+          "The degree parameter for the polynomial kernel function.", new IntValue(3)));
+      }
+      if (!Parameters.ContainsKey(CreateSolutionParameterName)) {
+        Parameters.Add(new FixedValueParameter<BoolValue>(CreateSolutionParameterName, "Flag that indicates if a solution should be produced at the end of the run", new BoolValue(true)));
+        Parameters[CreateSolutionParameterName].Hidden = true;
+      }
+      #endregion
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new SupportVectorRegression(this, cloner);
+    }
+
+    #region support vector regression
+    protected override void Run() {
+      IRegressionProblemData problemData = Problem.ProblemData;
+      IEnumerable<string> selectedInputVariables = problemData.AllowedInputVariables;
+      int nSv;
+      ISupportVectorMachineModel model;
+      Run(problemData, selectedInputVariables, SvmType.Value, KernelType.Value, Cost.Value, Nu.Value, Gamma.Value, Epsilon.Value, Degree.Value, out model, out nSv);
+
+      if (CreateSolution) {
+        var solution = new SupportVectorRegressionSolution((SupportVectorMachineModel)model, (IRegressionProblemData)problemData.Clone());
+        Results.Add(new Result("Support vector regression solution", "The support vector regression solution.", solution));
+      }
+
+      Results.Add(new Result("Number of support vectors", "The number of support vectors of the SVR solution.", new IntValue(nSv)));
+
+
+      {
+        // calculate regression model metrics 
+        var ds = problemData.Dataset;
+        var trainRows = problemData.TrainingIndices;
+        var testRows = problemData.TestIndices;
+        var yTrain = ds.GetDoubleValues(problemData.TargetVariable, trainRows);
+        var yTest = ds.GetDoubleValues(problemData.TargetVariable, testRows);
+        var yPredTrain = model.GetEstimatedValues(ds, trainRows).ToArray();
+        var yPredTest = model.GetEstimatedValues(ds, testRows).ToArray();
+
+        OnlineCalculatorError error;
+        var trainMse = OnlineMeanSquaredErrorCalculator.Calculate(yPredTrain, yTrain, out error);
+        if (error != OnlineCalculatorError.None) trainMse = double.MaxValue;
+        var testMse = OnlineMeanSquaredErrorCalculator.Calculate(yPredTest, yTest, out error);
+        if (error != OnlineCalculatorError.None) testMse = double.MaxValue;
+
+        Results.Add(new Result("Mean squared error (training)", "The mean of squared errors of the SVR solution on the training partition.", new DoubleValue(trainMse)));
+        Results.Add(new Result("Mean squared error (test)", "The mean of squared errors of the SVR solution on the test partition.", new DoubleValue(testMse)));
+
+
+        var trainMae = OnlineMeanAbsoluteErrorCalculator.Calculate(yPredTrain, yTrain, out error);
+        if (error != OnlineCalculatorError.None) trainMae = double.MaxValue;
+        var testMae = OnlineMeanAbsoluteErrorCalculator.Calculate(yPredTest, yTest, out error);
+        if (error != OnlineCalculatorError.None) testMae = double.MaxValue;
+
+        Results.Add(new Result("Mean absolute error (training)", "The mean of absolute errors of the SVR solution on the training partition.", new DoubleValue(trainMae)));
+        Results.Add(new Result("Mean absolute error (test)", "The mean of absolute errors of the SVR solution on the test partition.", new DoubleValue(testMae)));
+
+
+        var trainRelErr = OnlineMeanAbsolutePercentageErrorCalculator.Calculate(yPredTrain, yTrain, out error);
+        if (error != OnlineCalculatorError.None) trainRelErr = double.MaxValue;
+        var testRelErr = OnlineMeanAbsolutePercentageErrorCalculator.Calculate(yPredTest, yTest, out error);
+        if (error != OnlineCalculatorError.None) testRelErr = double.MaxValue;
+
+        Results.Add(new Result("Average relative error (training)", "The mean of relative errors of the SVR solution on the training partition.", new DoubleValue(trainRelErr)));
+        Results.Add(new Result("Average relative error (test)", "The mean of relative errors of the SVR solution on the test partition.", new DoubleValue(testRelErr)));
+      }
+    }
+
+    // BackwardsCompatibility3.4
+    #region Backwards compatible code, remove with 3.5
+    // for compatibility with old API
+    public static SupportVectorRegressionSolution CreateSupportVectorRegressionSolution(
+      IRegressionProblemData problemData, IEnumerable<string> allowedInputVariables,
+      string svmType, string kernelType, double cost, double nu, double gamma, double epsilon, int degree,
+      out double trainingR2, out double testR2, out int nSv) {
+      ISupportVectorMachineModel model;
+      Run(problemData, allowedInputVariables, svmType, kernelType, cost, nu, gamma, epsilon, degree, out model, out nSv);
+
+      var solution = new SupportVectorRegressionSolution((SupportVectorMachineModel)model, (IRegressionProblemData)problemData.Clone());
+      trainingR2 = solution.TrainingRSquared;
+      testR2 = solution.TestRSquared;
+      return solution;
+    }
+    #endregion
+
+    public static void Run(IRegressionProblemData problemData, IEnumerable<string> allowedInputVariables,
+      string svmType, string kernelType, double cost, double nu, double gamma, double epsilon, int degree,
+      out ISupportVectorMachineModel model, out int nSv) {
+      var dataset = problemData.Dataset;
+      string targetVariable = problemData.TargetVariable;
+      IEnumerable<int> rows = problemData.TrainingIndices;
+
+      svm_parameter parameter = new svm_parameter {
+        svm_type = GetSvmType(svmType),
+        kernel_type = GetKernelType(kernelType),
+        C = cost,
+        nu = nu,
+        gamma = gamma,
+        p = epsilon,
+        cache_size = 500,
+        probability = 0,
+        eps = 0.001,
+        degree = degree,
+        shrinking = 1,
+        coef0 = 0
+      };
+
+      svm_problem problem = SupportVectorMachineUtil.CreateSvmProblem(dataset, targetVariable, allowedInputVariables, rows);
+      RangeTransform rangeTransform = RangeTransform.Compute(problem);
+      svm_problem scaledProblem = rangeTransform.Scale(problem);
+      var svmModel = svm.svm_train(scaledProblem, parameter);
+      nSv = svmModel.SV.Length;
+
+      model = new SupportVectorMachineModel(svmModel, rangeTransform, targetVariable, allowedInputVariables);
+    }
+
+    private static int GetSvmType(string svmType) {
+      if (svmType == "NU_SVR") return svm_parameter.NU_SVR;
+      if (svmType == "EPSILON_SVR") return svm_parameter.EPSILON_SVR;
+      throw new ArgumentException("Unknown SVM type");
+    }
+
+    private static int GetKernelType(string kernelType) {
+      if (kernelType == "LINEAR") return svm_parameter.LINEAR;
+      if (kernelType == "POLY") return svm_parameter.POLY;
+      if (kernelType == "SIGMOID") return svm_parameter.SIGMOID;
+      if (kernelType == "RBF") return svm_parameter.RBF;
+      throw new ArgumentException("Unknown kernel type");
+    }
+    #endregion
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/SupportVectorMachine/SupportVectorRegressionSolution.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/SupportVectorMachine/SupportVectorRegressionSolution.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/SupportVectorMachine/SupportVectorRegressionSolution.cs	(revision 13819)
@@ -0,0 +1,53 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Problems.DataAnalysis;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  /// <summary>
+  /// Represents a support vector solution for a regression problem which can be visualized in the GUI.
+  /// </summary>
+  [Item("SupportVectorRegressionSolution", "Represents a support vector solution for a regression problem which can be visualized in the GUI.")]
+  [StorableClass]
+  public sealed class SupportVectorRegressionSolution : RegressionSolution, ISupportVectorMachineSolution {
+
+    public new ISupportVectorMachineModel Model {
+      get { return (ISupportVectorMachineModel)base.Model; }
+      set { base.Model = value; }
+    }
+
+    [StorableConstructor]
+    private SupportVectorRegressionSolution(bool deserializing) : base(deserializing) { }
+    private SupportVectorRegressionSolution(SupportVectorRegressionSolution original, Cloner cloner)
+      : base(original, cloner) {
+    }
+    public SupportVectorRegressionSolution(SupportVectorMachineModel model, IRegressionProblemData problemData)
+      : base(model, problemData) {
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new SupportVectorRegressionSolution(this, cloner);
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/TimeSeries/AutoregressiveModeling.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/TimeSeries/AutoregressiveModeling.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/TimeSeries/AutoregressiveModeling.cs	(revision 13819)
@@ -0,0 +1,141 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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 HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
+using HeuristicLab.Optimization;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Problems.DataAnalysis;
+using HeuristicLab.Problems.DataAnalysis.Symbolic;
+using HeuristicLab.Problems.DataAnalysis.Symbolic.TimeSeriesPrognosis;
+
+namespace HeuristicLab.Algorithms.DataAnalysis.TimeSeries {
+  [Item("Autoregressive Modeling (AR)", "Timeseries modeling algorithm that creates AR-N models.")]
+  [Creatable(CreatableAttribute.Categories.DataAnalysis, Priority = 130)]
+  [StorableClass]
+  public class AutoregressiveModeling : FixedDataAnalysisAlgorithm<ITimeSeriesPrognosisProblem> {
+    private const string TimeOffesetParameterName = "Maximum Time Offset";
+
+    public IFixedValueParameter<IntValue> TimeOffsetParameter {
+      get { return (IFixedValueParameter<IntValue>)Parameters[TimeOffesetParameterName]; }
+    }
+
+
+    public int TimeOffset {
+      get { return TimeOffsetParameter.Value.Value; }
+      set { TimeOffsetParameter.Value.Value = value; }
+    }
+
+    [StorableConstructor]
+    protected AutoregressiveModeling(bool deserializing) : base(deserializing) { }
+    protected AutoregressiveModeling(AutoregressiveModeling original, Cloner cloner) : base(original, cloner) { }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new AutoregressiveModeling(this, cloner);
+    }
+
+    public AutoregressiveModeling()
+      : base() {
+      Parameters.Add(new FixedValueParameter<IntValue>(TimeOffesetParameterName, "The maximum time offset for the model ranging from 1 to infinity.", new IntValue(1)));
+      Problem = new TimeSeriesPrognosisProblem();
+    }
+
+    protected override void Run() {
+      double rmsError, cvRmsError;
+      var solution = CreateAutoRegressiveSolution(Problem.ProblemData, TimeOffset, out rmsError, out cvRmsError);
+      Results.Add(new Result("Autoregressive solution", "The autoregressive time series prognosis solution.", solution));
+      Results.Add(new Result("Root mean square error", "The root of the mean of squared errors of the autoregressive time series prognosis solution on the training set.", new DoubleValue(rmsError)));
+      Results.Add(new Result("Estimated root mean square error (cross-validation)", "The estimated root of the mean of squared errors of the autoregressive time series prognosis solution via cross validation.", new DoubleValue(cvRmsError)));
+    }
+
+    /// <summary>
+    /// Calculates an AR(p) model. For further information see http://en.wikipedia.org/wiki/Autoregressive_model
+    /// </summary>
+    /// <param name="problemData">The problem data which should be used for training</param>
+    /// <param name="timeOffset">The parameter p of the AR(p) specifying the maximum time offset [1,infinity] </param>
+    /// <returns>The times series autoregressive solution </returns>
+    public static ITimeSeriesPrognosisSolution CreateAutoRegressiveSolution(ITimeSeriesPrognosisProblemData problemData, int timeOffset) {
+      double rmsError, cvRmsError;
+      return CreateAutoRegressiveSolution(problemData, timeOffset, out rmsError, out cvRmsError);
+    }
+
+    private static ITimeSeriesPrognosisSolution CreateAutoRegressiveSolution(ITimeSeriesPrognosisProblemData problemData, int timeOffset, out double rmsError, out double cvRmsError) {
+      string targetVariable = problemData.TargetVariable;
+
+      double[,] inputMatrix = new double[problemData.TrainingPartition.Size, timeOffset + 1];
+      var targetValues = problemData.Dataset.GetDoubleValues(targetVariable).ToList();
+      for (int i = 0, row = problemData.TrainingPartition.Start; i < problemData.TrainingPartition.Size; i++, row++) {
+        for (int col = 0; col < timeOffset; col++) {
+          inputMatrix[i, col] = targetValues[row - col - 1];
+        }
+      }
+      // set target values in last column
+      for (int i = 0; i < inputMatrix.GetLength(0); i++)
+        inputMatrix[i, timeOffset] = targetValues[i + problemData.TrainingPartition.Start];
+
+      if (inputMatrix.Cast<double>().Any(x => double.IsNaN(x) || double.IsInfinity(x)))
+        throw new NotSupportedException("Linear regression does not support NaN or infinity values in the input dataset.");
+
+
+      alglib.linearmodel lm = new alglib.linearmodel();
+      alglib.lrreport ar = new alglib.lrreport();
+      int nRows = inputMatrix.GetLength(0);
+      int nFeatures = inputMatrix.GetLength(1) - 1;
+      double[] coefficients = new double[nFeatures + 1]; // last coefficient is for the constant
+
+      int retVal = 1;
+      alglib.lrbuild(inputMatrix, nRows, nFeatures, out retVal, out lm, out ar);
+      if (retVal != 1) throw new ArgumentException("Error in calculation of linear regression solution");
+      rmsError = ar.rmserror;
+      cvRmsError = ar.cvrmserror;
+
+      alglib.lrunpack(lm, out coefficients, out nFeatures);
+
+
+      ISymbolicExpressionTree tree = new SymbolicExpressionTree(new ProgramRootSymbol().CreateTreeNode());
+      ISymbolicExpressionTreeNode startNode = new StartSymbol().CreateTreeNode();
+      tree.Root.AddSubtree(startNode);
+      ISymbolicExpressionTreeNode addition = new Addition().CreateTreeNode();
+      startNode.AddSubtree(addition);
+
+      for (int i = 0; i < timeOffset; i++) {
+        LaggedVariableTreeNode node = (LaggedVariableTreeNode)new LaggedVariable().CreateTreeNode();
+        node.VariableName = targetVariable;
+        node.Weight = coefficients[i];
+        node.Lag = (i + 1) * -1;
+        addition.AddSubtree(node);
+      }
+
+      ConstantTreeNode cNode = (ConstantTreeNode)new Constant().CreateTreeNode();
+      cNode.Value = coefficients[coefficients.Length - 1];
+      addition.AddSubtree(cNode);
+
+      var interpreter = new SymbolicTimeSeriesPrognosisExpressionTreeInterpreter(problemData.TargetVariable);
+      var model = new SymbolicTimeSeriesPrognosisModel(tree, interpreter);
+      var solution = model.CreateTimeSeriesPrognosisSolution((ITimeSeriesPrognosisProblemData)problemData.Clone());
+      return solution;
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/kMeans/KMeansClustering.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/kMeans/KMeansClustering.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/kMeans/KMeansClustering.cs	(revision 13819)
@@ -0,0 +1,103 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Optimization;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Problems.DataAnalysis;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  /// <summary>
+  /// k-Means clustering algorithm data analysis algorithm.
+  /// </summary>
+  [Item("k-Means", "The k-Means clustering algorithm (wrapper for ALGLIB).")]
+  [Creatable(CreatableAttribute.Categories.DataAnalysis, Priority = 10)]
+  [StorableClass]
+  public sealed class KMeansClustering : FixedDataAnalysisAlgorithm<IClusteringProblem> {
+    private const string KParameterName = "k";
+    private const string RestartsParameterName = "Restarts";
+    private const string KMeansSolutionResultName = "k-Means clustering solution";
+    #region parameter properties
+    public IValueParameter<IntValue> KParameter {
+      get { return (IValueParameter<IntValue>)Parameters[KParameterName]; }
+    }
+    public IValueParameter<IntValue> RestartsParameter {
+      get { return (IValueParameter<IntValue>)Parameters[RestartsParameterName]; }
+    }
+    #endregion
+    #region properties
+    public IntValue K {
+      get { return KParameter.Value; }
+    }
+    public IntValue Restarts {
+      get { return RestartsParameter.Value; }
+    }
+    #endregion
+    [StorableConstructor]
+    private KMeansClustering(bool deserializing) : base(deserializing) { }
+    private KMeansClustering(KMeansClustering original, Cloner cloner)
+      : base(original, cloner) {
+    }
+    public KMeansClustering()
+      : base() {
+      Parameters.Add(new ValueParameter<IntValue>(KParameterName, "The number of clusters.", new IntValue(3)));
+      Parameters.Add(new ValueParameter<IntValue>(RestartsParameterName, "The number of restarts.", new IntValue(0)));
+      Problem = new ClusteringProblem();
+    }
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() { }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new KMeansClustering(this, cloner);
+    }
+
+    #region k-Means clustering
+    protected override void Run() {
+      var solution = CreateKMeansSolution(Problem.ProblemData, K.Value, Restarts.Value);
+      Results.Add(new Result(KMeansSolutionResultName, "The k-Means clustering solution.", solution));
+    }
+
+    public static KMeansClusteringSolution CreateKMeansSolution(IClusteringProblemData problemData, int k, int restarts) {
+      var dataset = problemData.Dataset;
+      IEnumerable<string> allowedInputVariables = problemData.AllowedInputVariables;
+      IEnumerable<int> rows = problemData.TrainingIndices;
+      int info;
+      double[,] centers;
+      int[] xyc;
+      double[,] inputMatrix = AlglibUtil.PrepareInputMatrix(dataset, allowedInputVariables, rows);
+      if (inputMatrix.Cast<double>().Any(x => double.IsNaN(x) || double.IsInfinity(x)))
+        throw new NotSupportedException("k-Means clustering does not support NaN or infinity values in the input dataset.");
+
+      alglib.kmeansgenerate(inputMatrix, inputMatrix.GetLength(0), inputMatrix.GetLength(1), k, restarts + 1, out info, out centers, out xyc);
+      if (info != 1) throw new ArgumentException("Error in calculation of k-Means clustering solution");
+
+      KMeansClusteringSolution solution = new KMeansClusteringSolution(new KMeansClusteringModel(centers, allowedInputVariables), (IClusteringProblemData)problemData.Clone());
+      return solution;
+    }
+    #endregion
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/kMeans/KMeansClusteringModel.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/kMeans/KMeansClusteringModel.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/kMeans/KMeansClusteringModel.cs	(revision 13819)
@@ -0,0 +1,87 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Collections.Generic;
+using System.Drawing;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Problems.DataAnalysis;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  /// <summary>
+  /// Represents a k-Means clustering model.
+  /// </summary>
+  [StorableClass]
+  [Item("KMeansClusteringModel", "Represents a k-Means clustering model.")]
+  public sealed class KMeansClusteringModel : NamedItem, IClusteringModel {
+    public static new Image StaticItemImage {
+      get { return HeuristicLab.Common.Resources.VSImageLibrary.Function; }
+    }
+
+    [Storable]
+    private string[] allowedInputVariables;
+    public IEnumerable<string> AllowedInputVariables {
+      get { return allowedInputVariables; }
+    }
+    [Storable]
+    private List<double[]> centers;
+    public IEnumerable<double[]> Centers {
+      get {
+        return centers.Select(x => (double[])x.Clone());
+      }
+    }
+    [StorableConstructor]
+    private KMeansClusteringModel(bool deserializing) : base(deserializing) { }
+    private KMeansClusteringModel(KMeansClusteringModel original, Cloner cloner)
+      : base(original, cloner) {
+      this.allowedInputVariables = (string[])original.allowedInputVariables.Clone();
+      this.centers = new List<double[]>(original.Centers);
+    }
+    public KMeansClusteringModel(double[,] centers, IEnumerable<string> allowedInputVariables)
+      : base() {
+      this.name = ItemName;
+      this.description = ItemDescription;
+      // disect center matrix into list of double[]
+      // centers are given as double matrix where number of rows = dimensions and number of columns = clusters
+      // each column is a cluster center
+      this.centers = new List<double[]>();
+      for (int i = 0; i < centers.GetLength(1); i++) {
+        double[] c = new double[centers.GetLength(0)];
+        for (int j = 0; j < c.Length; j++) {
+          c[j] = centers[j, i];
+        }
+        this.centers.Add(c);
+      }
+      this.allowedInputVariables = allowedInputVariables.ToArray();
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new KMeansClusteringModel(this, cloner);
+    }
+
+
+    public IEnumerable<int> GetClusterValues(IDataset dataset, IEnumerable<int> rows) {
+      return KMeansClusteringUtil.FindClosestCenters(centers, dataset, allowedInputVariables, rows);
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/kMeans/KMeansClusteringSolution.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/kMeans/KMeansClusteringSolution.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/kMeans/KMeansClusteringSolution.cs	(revision 13819)
@@ -0,0 +1,64 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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 HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Problems.DataAnalysis;
+using HeuristicLab.Optimization;
+using HeuristicLab.Data;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  /// <summary>
+  /// Represents a k-Means clustering solution for a clustering problem which can be visualized in the GUI.
+  /// </summary>
+  [Item("k-Means clustering solution", "Represents a k-Means solution for a clustering problem which can be visualized in the GUI.")]
+  [StorableClass]
+  public sealed class KMeansClusteringSolution : ClusteringSolution {
+    private const string TrainingIntraClusterSumOfSquaresResultName = "Intra-cluster sum of squares (training)";
+    private const string TestIntraClusterSumOfSquaresResultName = "Intra-cluster sum of squares (test)";
+    public new KMeansClusteringModel Model {
+      get { return (KMeansClusteringModel)base.Model; }
+      set { base.Model = value; }
+    }
+
+    [StorableConstructor]
+    private KMeansClusteringSolution(bool deserializing) : base(deserializing) { }
+    private KMeansClusteringSolution(KMeansClusteringSolution original, Cloner cloner)
+      : base(original, cloner) {
+    }
+    public KMeansClusteringSolution(KMeansClusteringModel model, IClusteringProblemData problemData)
+      : base(model, problemData) {
+      double trainingIntraClusterSumOfSquares = KMeansClusteringUtil.CalculateIntraClusterSumOfSquares(model, problemData.Dataset, problemData.TrainingIndices);
+      double testIntraClusterSumOfSquares = KMeansClusteringUtil.CalculateIntraClusterSumOfSquares(model, problemData.Dataset, problemData.TestIndices);
+      this.Add(new Result(TrainingIntraClusterSumOfSquaresResultName, "The sum of squared distances of points of the training partition to the cluster center (is minimized by k-Means).", new DoubleValue(trainingIntraClusterSumOfSquares)));
+      this.Add(new Result(TestIntraClusterSumOfSquaresResultName, "The sum of squared distances of points of the test partition to the cluster center (is minimized by k-Means).", new DoubleValue(testIntraClusterSumOfSquares)));
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new KMeansClusteringSolution(this, cloner);
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/kMeans/KMeansClusteringUtil.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/kMeans/KMeansClusteringUtil.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Algorithms.DataAnalysis/3.4/kMeans/KMeansClusteringUtil.cs	(revision 13819)
@@ -0,0 +1,111 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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.Problems.DataAnalysis;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  public static class KMeansClusteringUtil {
+    public static IEnumerable<int> FindClosestCenters(IEnumerable<double[]> centers, IDataset dataset, IEnumerable<string> allowedInputVariables, IEnumerable<int> rows) {
+      int nRows = rows.Count();
+      int nCols = allowedInputVariables.Count();
+      int[] closestCenter = new int[nRows];
+      double[] bestCenterDistance = Enumerable.Repeat(double.MaxValue, nRows).ToArray();
+      int centerIndex = 1;
+
+      foreach (double[] center in centers) {
+        if (nCols != center.Length) throw new ArgumentException();
+        int rowIndex = 0;
+        foreach (var row in rows) {
+          // calc euclidian distance of point to center
+          double centerDistance = 0;
+          int col = 0;
+          foreach (var inputVariable in allowedInputVariables) {
+            double d = center[col++] - dataset.GetDoubleValue(inputVariable, row);
+            d = d * d; // square;
+            centerDistance += d;
+            if (centerDistance > bestCenterDistance[rowIndex]) break;
+          }
+          if (centerDistance < bestCenterDistance[rowIndex]) {
+            bestCenterDistance[rowIndex] = centerDistance;
+            closestCenter[rowIndex] = centerIndex;
+          }
+          rowIndex++;
+        }
+        centerIndex++;
+      }
+      return closestCenter;
+    }
+
+    public static double CalculateIntraClusterSumOfSquares(KMeansClusteringModel model, IDataset dataset, IEnumerable<int> rows) {
+      List<int> clusterValues = model.GetClusterValues(dataset, rows).ToList();
+      List<string> allowedInputVariables = model.AllowedInputVariables.ToList();
+      int nCols = allowedInputVariables.Count;
+      Dictionary<int, List<double[]>> clusterPoints = new Dictionary<int, List<double[]>>();
+      Dictionary<int, double[]> clusterMeans = new Dictionary<int, double[]>();
+      foreach (var clusterValue in clusterValues.Distinct()) {
+        clusterPoints.Add(clusterValue, new List<double[]>());
+      }
+
+      // collect points of clusters
+      int clusterValueIndex = 0;
+      foreach (var row in rows) {
+        double[] p = new double[allowedInputVariables.Count];
+        for (int i = 0; i < nCols; i++) {
+          p[i] = dataset.GetDoubleValue(allowedInputVariables[i], row);
+        }
+        clusterPoints[clusterValues[clusterValueIndex++]].Add(p);
+      }
+      // calculate cluster means
+      foreach (var pair in clusterPoints) {
+        double[] mean = new double[nCols];
+        foreach (var p in pair.Value) {
+          for (int i = 0; i < nCols; i++) {
+            mean[i] += p[i];
+          }
+        }
+        for (int i = 0; i < nCols; i++) {
+          mean[i] /= pair.Value.Count;
+        }
+        clusterMeans[pair.Key] = mean;
+      }
+      // calculate distances
+      double allCenterDistances = 0;
+      foreach (var pair in clusterMeans) {
+        double[] mean = pair.Value;
+        double centerDistances = 0;
+        foreach (var clusterPoint in clusterPoints[pair.Key]) {
+          double centerDistance = 0;
+          for (int i = 0; i < nCols; i++) {
+            double d = mean[i] - clusterPoint[i];
+            d = d * d;
+            centerDistance += d;
+          }
+          centerDistances += centerDistance;
+        }
+        allCenterDistances += centerDistances;
+      }
+      return allCenterDistances;
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis.Views/3.4/HeuristicLab.Problems.DataAnalysis.Views-3.4.csproj
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis.Views/3.4/HeuristicLab.Problems.DataAnalysis.Views-3.4.csproj	(revision 13818)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis.Views/3.4/HeuristicLab.Problems.DataAnalysis.Views-3.4.csproj	(revision 13819)
@@ -179,8 +179,4 @@
       <Private>False</Private>
     </Reference>
-    <Reference Include="HeuristicLab.Problems.DataAnalysis-3.4">
-      <HintPath>..\..\..\..\trunk\sources\bin\HeuristicLab.Problems.DataAnalysis-3.4.dll</HintPath>
-      <Private>False</Private>
-    </Reference>
     <Reference Include="HeuristicLab.Problems.DataAnalysis.Symbolic-3.4">
       <HintPath>..\..\..\..\trunk\sources\bin\HeuristicLab.Problems.DataAnalysis.Symbolic-3.4.dll</HintPath>
@@ -503,4 +499,10 @@
     </EmbeddedResource>
   </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\..\HeuristicLab.Problems.DataAnalysis\3.4\HeuristicLab.Problems.DataAnalysis-3.4.csproj">
+      <Project>{df87c13e-a889-46ff-8153-66dcaa8c5674}</Project>
+      <Name>HeuristicLab.Problems.DataAnalysis-3.4</Name>
+    </ProjectReference>
+  </ItemGroup>
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
   <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Dataset.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Dataset.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Dataset.cs	(revision 13819)
@@ -0,0 +1,259 @@
+#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;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  [Item("Dataset", "Represents a dataset containing data that should be analyzed.")]
+  [StorableClass]
+  public class Dataset : NamedItem, IDataset {
+    [StorableConstructor]
+    protected Dataset(bool deserializing) : base(deserializing) { }
+    protected Dataset(Dataset original, Cloner cloner)
+      : base(original, cloner) {
+      variableValues = new Dictionary<string, IList>(original.variableValues);
+      variableNames = new List<string>(original.variableNames);
+      rows = original.rows;
+    }
+    public override IDeepCloneable Clone(Cloner cloner) { return new Dataset(this, cloner); }
+
+    public Dataset()
+      : base() {
+      Name = "-";
+      VariableNames = Enumerable.Empty<string>();
+      variableValues = new Dictionary<string, IList>();
+      rows = 0;
+    }
+
+    /// <summary>
+    /// Creates a new dataset. The variableValues are not cloned.
+    /// </summary>
+    /// <param name="variableNames">The names of the variables in the dataset</param>
+    /// <param name="variableValues">The values for the variables (column-oriented storage). Values are not cloned!</param>
+    public Dataset(IEnumerable<string> variableNames, IEnumerable<IList> variableValues)
+      : base() {
+      Name = "-";
+      if (!variableNames.Any()) {
+        this.variableNames = Enumerable.Range(0, variableValues.Count()).Select(x => "Column " + x).ToList();
+      } else if (variableNames.Count() != variableValues.Count()) {
+        throw new ArgumentException("Number of variable names doesn't match the number of columns of variableValues");
+      } else if (!variableValues.All(list => list.Count == variableValues.First().Count)) {
+        throw new ArgumentException("The number of values must be equal for every variable");
+      } else if (variableNames.Distinct().Count() != variableNames.Count()) {
+        var duplicateVariableNames =
+          variableNames.GroupBy(v => v).Where(g => g.Count() > 1).Select(g => g.Key).ToList();
+        string message = "The dataset cannot contain duplicate variables names: " + Environment.NewLine;
+        foreach (var duplicateVariableName in duplicateVariableNames)
+          message += duplicateVariableName + Environment.NewLine;
+        throw new ArgumentException(message);
+      }
+
+      rows = variableValues.First().Count;
+      this.variableNames = new List<string>(variableNames);
+      this.variableValues = new Dictionary<string, IList>(this.variableNames.Count);
+      for (int i = 0; i < this.variableNames.Count; i++) {
+        var values = variableValues.ElementAt(i);
+        this.variableValues.Add(this.variableNames[i], values);
+      }
+    }
+
+    public Dataset(IEnumerable<string> variableNames, double[,] variableValues) {
+      Name = "-";
+      if (variableNames.Count() != variableValues.GetLength(1)) {
+        throw new ArgumentException("Number of variable names doesn't match the number of columns of variableValues");
+      }
+      if (variableNames.Distinct().Count() != variableNames.Count()) {
+        var duplicateVariableNames = variableNames.GroupBy(v => v).Where(g => g.Count() > 1).Select(g => g.Key).ToList();
+        string message = "The dataset cannot contain duplicate variables names: " + Environment.NewLine;
+        foreach (var duplicateVariableName in duplicateVariableNames)
+          message += duplicateVariableName + Environment.NewLine;
+        throw new ArgumentException(message);
+      }
+
+      rows = variableValues.GetLength(0);
+      this.variableNames = new List<string>(variableNames);
+
+      this.variableValues = new Dictionary<string, IList>(variableValues.GetLength(1));
+      for (int col = 0; col < variableValues.GetLength(1); col++) {
+        string columName = this.variableNames[col];
+        var values = new List<double>(variableValues.GetLength(0));
+        for (int row = 0; row < variableValues.GetLength(0); row++) {
+          values.Add(variableValues[row, col]);
+        }
+        this.variableValues.Add(columName, values);
+      }
+    }
+
+    public ModifiableDataset ToModifiable() {
+      var values = new List<IList>();
+      foreach (var v in variableNames) {
+        if (VariableHasType<double>(v)) {
+          values.Add(new List<double>((List<double>)variableValues[v]));
+        } else if (VariableHasType<string>(v)) {
+          values.Add(new List<string>((List<string>)variableValues[v]));
+        } else if (VariableHasType<DateTime>(v)) {
+          values.Add(new List<DateTime>((List<DateTime>)variableValues[v]));
+        } else {
+          throw new ArgumentException("Unknown variable type.");
+        }
+      }
+      return new ModifiableDataset(variableNames, values);
+    }
+
+    protected Dataset(Dataset dataset) : this(dataset.variableNames, dataset.variableValues.Values) { }
+
+    #region Backwards compatible code, remove with 3.5
+    private double[,] storableData;
+    //name alias used to suppport backwards compatibility
+    [Storable(Name = "data", AllowOneWay = true)]
+    private double[,] StorableData { set { storableData = value; } }
+
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() {
+      if (variableValues == null) {
+        rows = storableData.GetLength(0);
+        variableValues = new Dictionary<string, IList>();
+        for (int col = 0; col < storableData.GetLength(1); col++) {
+          string columName = variableNames[col];
+          var values = new List<double>(rows);
+          for (int row = 0; row < rows; row++) {
+            values.Add(storableData[row, col]);
+          }
+          variableValues.Add(columName, values);
+        }
+        storableData = null;
+      }
+    }
+    #endregion
+
+    [Storable(Name = "VariableValues")]
+    protected Dictionary<string, IList> variableValues;
+
+    protected List<string> variableNames;
+    [Storable]
+    public IEnumerable<string> VariableNames {
+      get { return variableNames; }
+      protected set {
+        if (variableNames != null) throw new InvalidOperationException();
+        variableNames = new List<string>(value);
+      }
+    }
+    public IEnumerable<string> DoubleVariables {
+      get { return variableValues.Where(p => p.Value is List<double>).Select(p => p.Key); }
+    }
+    public IEnumerable<double> GetDoubleValues(string variableName) {
+      return GetValues<double>(variableName);
+    }
+    public IEnumerable<string> GetStringValues(string variableName) {
+      return GetValues<string>(variableName);
+    }
+    public IEnumerable<DateTime> GetDateTimeValues(string variableName) {
+      return GetValues<DateTime>(variableName);
+    }
+
+    public ReadOnlyCollection<double> GetReadOnlyDoubleValues(string variableName) {
+      var values = GetValues<double>(variableName);
+      return values.AsReadOnly();
+    }
+    public double GetDoubleValue(string variableName, int row) {
+      var values = GetValues<double>(variableName);
+      return values[row];
+    }
+    public IEnumerable<double> GetDoubleValues(string variableName, IEnumerable<int> rows) {
+      return GetValues<double>(variableName, rows);
+    }
+    private IEnumerable<T> GetValues<T>(string variableName, IEnumerable<int> rows) {
+      var values = GetValues<T>(variableName);
+      return rows.Select(x => values[x]);
+    }
+    private List<T> GetValues<T>(string variableName) {
+      IList list;
+      if (!variableValues.TryGetValue(variableName, out list))
+        throw new ArgumentException("The variable " + variableName + " does not exist in the dataset.");
+      List<T> values = list as List<T>;
+      if (values == null) throw new ArgumentException("The variable " + variableName + " is not a " + typeof(T) + " variable.");
+      return values;
+    }
+    public bool VariableHasType<T>(string variableName) {
+      return variableValues[variableName] is IList<T>;
+    }
+
+    #region IStringConvertibleMatrix Members
+    [Storable]
+    protected int rows;
+    public int Rows {
+      get { return rows; }
+    }
+    int IStringConvertibleMatrix.Rows {
+      get { return Rows; }
+      set { throw new NotSupportedException(); }
+    }
+
+    public int Columns {
+      get { return variableNames.Count; }
+    }
+    int IStringConvertibleMatrix.Columns {
+      get { return Columns; }
+      set { throw new NotSupportedException(); }
+    }
+    bool IStringConvertibleMatrix.SortableView {
+      get { return false; }
+      set { throw new NotSupportedException(); }
+    }
+    bool IStringConvertibleMatrix.ReadOnly {
+      get { return true; }
+    }
+    IEnumerable<string> IStringConvertibleMatrix.ColumnNames {
+      get { return this.VariableNames; }
+      set { throw new NotSupportedException(); }
+    }
+    IEnumerable<string> IStringConvertibleMatrix.RowNames {
+      get { return Enumerable.Empty<string>(); }
+      set { throw new NotSupportedException(); }
+    }
+    string IStringConvertibleMatrix.GetValue(int rowIndex, int columnIndex) {
+      return variableValues[variableNames[columnIndex]][rowIndex].ToString();
+    }
+    bool IStringConvertibleMatrix.SetValue(string value, int rowIndex, int columnIndex) {
+      throw new NotSupportedException();
+    }
+    bool IStringConvertibleMatrix.Validate(string value, out string errorMessage) {
+      throw new NotSupportedException();
+    }
+
+    public virtual event EventHandler ColumnsChanged { add { } remove { } }
+    public virtual event EventHandler RowsChanged { add { } remove { } }
+    public virtual event EventHandler ColumnNamesChanged { add { } remove { } }
+    public virtual event EventHandler RowNamesChanged { add { } remove { } }
+    public virtual event EventHandler SortableViewChanged { add { } remove { } }
+    public virtual event EventHandler<EventArgs<int, int>> ItemChanged { add { } remove { } }
+    public virtual event EventHandler Reset { add { } remove { } }
+    #endregion
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/DatasetExtensions.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/DatasetExtensions.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/DatasetExtensions.cs	(revision 13819)
@@ -0,0 +1,34 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Collections.Generic;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  public static class DatasetExtensions {
+    public static IEnumerable<T> TakeEvery<T>(this IEnumerable<T> xs, int nth) {
+      int i = 0;
+      foreach (var x in xs) {
+        if (i % nth == 0) yield return x;
+        i++;
+      }
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/DoubleLimit.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/DoubleLimit.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/DoubleLimit.cs	(revision 13819)
@@ -0,0 +1,66 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  [StorableClass]
+  [Item("DoubleLimit", "Represents a lower and a upper bound for double values.")]
+  public class DoubleLimit : StringConvertibleValueTuple<DoubleValue, DoubleValue> {
+
+    public double Lower {
+      get { return Item1.Value; }
+      set { Item1.Value = value; }
+    }
+    public double Upper {
+      get { return Item2.Value; }
+      set { Item2.Value = value; }
+    }
+
+    [StorableConstructor]
+    protected DoubleLimit(bool deserializing) : base(deserializing) { }
+    protected DoubleLimit(DoubleLimit original, Cloner cloner)
+      : base(original, cloner) {
+    }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new DoubleLimit(this, cloner);
+    }
+
+    public DoubleLimit() : base(new DoubleValue(), new DoubleValue()) { }
+    public DoubleLimit(DoubleValue start, DoubleValue end) : base(start, end) { }
+    public DoubleLimit(double start, double end) : base(new DoubleValue(start), new DoubleValue(end)) { }
+
+    public override string ToString() {
+      return string.Format("Lower: {0}, Upper: {1}", Lower, Upper);
+    }
+
+    public override StringConvertibleValueTuple<DoubleValue, DoubleValue> AsReadOnly() {
+      var readOnly = new DoubleLimit();
+      readOnly.values = Tuple.Create<DoubleValue, DoubleValue>((DoubleValue)Item1.AsReadOnly(), (DoubleValue)Item2.AsReadOnly());
+      readOnly.readOnly = true;
+      return readOnly;
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/HeuristicLab.Problems.DataAnalysis-3.4.csproj
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/HeuristicLab.Problems.DataAnalysis-3.4.csproj	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/HeuristicLab.Problems.DataAnalysis-3.4.csproj	(revision 13819)
@@ -0,0 +1,329 @@
+﻿<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProductVersion>9.0.30729</ProductVersion>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{DF87C13E-A889-46FF-8153-66DCAA8C5674}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>HeuristicLab.Problems.DataAnalysis</RootNamespace>
+    <AssemblyName>HeuristicLab.Problems.DataAnalysis-3.4</AssemblyName>
+    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
+    <TargetFrameworkProfile>
+    </TargetFrameworkProfile>
+    <FileAlignment>512</FileAlignment>
+    <SignAssembly>true</SignAssembly>
+    <AssemblyOriginatorKeyFile>HeuristicLab.snk</AssemblyOriginatorKeyFile>
+    <FileUpgradeFlags>
+    </FileUpgradeFlags>
+    <OldToolsVersion>3.5</OldToolsVersion>
+    <UpgradeBackupLocation />
+    <PublishUrl>publish\</PublishUrl>
+    <Install>true</Install>
+    <InstallFrom>Disk</InstallFrom>
+    <UpdateEnabled>false</UpdateEnabled>
+    <UpdateMode>Foreground</UpdateMode>
+    <UpdateInterval>7</UpdateInterval>
+    <UpdateIntervalUnits>Days</UpdateIntervalUnits>
+    <UpdatePeriodically>false</UpdatePeriodically>
+    <UpdateRequired>false</UpdateRequired>
+    <MapFileExtensions>true</MapFileExtensions>
+    <ApplicationRevision>0</ApplicationRevision>
+    <ApplicationVersion>1.0.0.%2a</ApplicationVersion>
+    <IsWebBootstrapper>false</IsWebBootstrapper>
+    <UseApplicationTrust>false</UseApplicationTrust>
+    <BootstrapperEnabled>true</BootstrapperEnabled>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>..\..\..\..\trunk\sources\bin\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
+    <Prefer32Bit>false</Prefer32Bit>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>..\..\..\..\trunk\sources\bin\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
+    <Prefer32Bit>false</Prefer32Bit>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x64' ">
+    <DebugSymbols>true</DebugSymbols>
+    <OutputPath>..\..\..\..\trunk\sources\bin\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <DebugType>full</DebugType>
+    <PlatformTarget>x64</PlatformTarget>
+    <ErrorReport>prompt</ErrorReport>
+    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
+    <Prefer32Bit>false</Prefer32Bit>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x64' ">
+    <OutputPath>..\..\..\..\trunk\sources\bin\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <Optimize>true</Optimize>
+    <DebugType>pdbonly</DebugType>
+    <PlatformTarget>x64</PlatformTarget>
+    <ErrorReport>prompt</ErrorReport>
+    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
+    <Prefer32Bit>false</Prefer32Bit>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
+    <DebugSymbols>true</DebugSymbols>
+    <OutputPath>..\..\..\..\trunk\sources\bin\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <DebugType>full</DebugType>
+    <PlatformTarget>x86</PlatformTarget>
+    <ErrorReport>prompt</ErrorReport>
+    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
+    <Prefer32Bit>false</Prefer32Bit>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
+    <OutputPath>..\..\..\..\trunk\sources\bin\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <Optimize>true</Optimize>
+    <DebugType>pdbonly</DebugType>
+    <PlatformTarget>x86</PlatformTarget>
+    <ErrorReport>prompt</ErrorReport>
+    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
+    <Prefer32Bit>false</Prefer32Bit>
+  </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="HeuristicLab.Collections-3.3, Version=3.3.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\..\trunk\sources\bin\HeuristicLab.Collections-3.3.dll</HintPath>
+    </Reference>
+    <Reference Include="HeuristicLab.Common-3.3, Version=3.3.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\..\trunk\sources\bin\HeuristicLab.Common-3.3.dll</HintPath>
+    </Reference>
+    <Reference Include="HeuristicLab.Common.Resources-3.3, Version=3.3.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\..\trunk\sources\bin\HeuristicLab.Common.Resources-3.3.dll</HintPath>
+    </Reference>
+    <Reference Include="HeuristicLab.Core-3.3, Version=3.3.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\..\trunk\sources\bin\HeuristicLab.Core-3.3.dll</HintPath>
+    </Reference>
+    <Reference Include="HeuristicLab.Data-3.3, Version=3.3.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\..\trunk\sources\bin\HeuristicLab.Data-3.3.dll</HintPath>
+    </Reference>
+    <Reference Include="HeuristicLab.Optimization-3.3, Version=3.3.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\..\trunk\sources\bin\HeuristicLab.Optimization-3.3.dll</HintPath>
+    </Reference>
+    <Reference Include="HeuristicLab.Parameters-3.3, Version=3.3.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\..\trunk\sources\bin\HeuristicLab.Parameters-3.3.dll</HintPath>
+    </Reference>
+    <Reference Include="HeuristicLab.Persistence-3.3, Version=3.3.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\..\trunk\sources\bin\HeuristicLab.Persistence-3.3.dll</HintPath>
+    </Reference>
+    <Reference Include="HeuristicLab.PluginInfrastructure-3.3, Version=3.3.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\..\trunk\sources\bin\HeuristicLab.PluginInfrastructure-3.3.dll</HintPath>
+    </Reference>
+    <Reference Include="HeuristicLab.Problems.Instances-3.3, Version=3.3.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\..\trunk\sources\bin\HeuristicLab.Problems.Instances-3.3.dll</HintPath>
+    </Reference>
+    <Reference Include="System" />
+    <Reference Include="System.Core">
+      <RequiredTargetFramework>3.5</RequiredTargetFramework>
+    </Reference>
+    <Reference Include="System.Drawing" />
+    <Reference Include="System.Xml.Linq">
+      <RequiredTargetFramework>3.5</RequiredTargetFramework>
+    </Reference>
+    <Reference Include="System.Data.DataSetExtensions">
+      <RequiredTargetFramework>3.5</RequiredTargetFramework>
+    </Reference>
+    <Reference Include="System.Data" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="DatasetExtensions.cs" />
+    <Compile Include="DoubleLimit.cs" />
+    <Compile Include="Implementation\Classification\ClassificationEnsembleModel.cs">
+      <SubType>Code</SubType>
+    </Compile>
+    <Compile Include="Implementation\Classification\ClassificationEnsembleSolution.cs" />
+    <Compile Include="Implementation\Classification\ClassificationPerformanceMeasures.cs" />
+    <Compile Include="Implementation\Classification\ClassificationProblemData.cs" />
+    <Compile Include="Implementation\Classification\ClassificationProblem.cs" />
+    <Compile Include="Implementation\Classification\ClassificationSolution.cs" />
+    <Compile Include="Implementation\Classification\ClassificationEnsembleProblemData.cs" />
+    <Compile Include="Implementation\Classification\ClassificationSolutionBase.cs" />
+    <Compile Include="Implementation\Classification\ConstantClassificationSolution.cs" />
+    <Compile Include="Implementation\Classification\DiscriminantFunctionClassificationSolutionBase.cs" />
+    <Compile Include="Implementation\Clustering\ClusteringProblem.cs" />
+    <Compile Include="Implementation\Clustering\ClusteringProblemData.cs" />
+    <Compile Include="Implementation\Clustering\ClusteringSolution.cs" />
+    <Compile Include="Implementation\ConstantModel.cs" />
+    <Compile Include="Implementation\Regression\ConstantRegressionModel.cs" />
+    <Compile Include="Implementation\Regression\ConstantRegressionSolution.cs" />
+    <Compile Include="Implementation\Regression\RegressionEnsembleProblemData.cs" />
+    <Compile Include="Implementation\Regression\RegressionEnsembleModel.cs">
+      <SubType>Code</SubType>
+    </Compile>
+    <Compile Include="Implementation\Regression\RegressionEnsembleSolution.cs" />
+    <Compile Include="Implementation\Regression\RegressionSolutionVariableImpactsCalculator.cs" />
+    <Compile Include="Implementation\TimeSeriesPrognosis\Models\ConstantTimeSeriesPrognosisModel.cs" />
+    <Compile Include="Implementation\TimeSeriesPrognosis\Models\TimeSeriesPrognosisAutoRegressiveModel.cs" />
+    <Compile Include="Implementation\TimeSeriesPrognosis\TimeSeriesPrognosisProblem.cs" />
+    <Compile Include="Implementation\TimeSeriesPrognosis\TimeSeriesPrognosisProblemData.cs" />
+    <Compile Include="Implementation\TimeSeriesPrognosis\TimeSeriesPrognosisResults.cs" />
+    <Compile Include="Implementation\TimeSeriesPrognosis\TimeSeriesPrognosisSolution.cs" />
+    <Compile Include="Implementation\TimeSeriesPrognosis\TimeSeriesPrognosisSolutionBase.cs" />
+    <Compile Include="Implementation\Transformations\CopyColumnTransformation.cs" />
+    <Compile Include="Implementation\Transformations\ExponentialTransformation.cs" />
+    <Compile Include="Implementation\Transformations\LinearTransformation.cs" />
+    <Compile Include="Implementation\Transformations\LogarithmicTransformation.cs" />
+    <Compile Include="Implementation\Transformations\PowerTransformation.cs" />
+    <Compile Include="Implementation\Transformations\ReciprocalTransformation.cs" />
+    <Compile Include="Implementation\Transformations\ShiftStandardDistributionTransformation.cs" />
+    <Compile Include="Implementation\Transformations\ShiftToRangeTransformation.cs" />
+    <Compile Include="Implementation\Transformations\Transformation.cs" />
+    <Compile Include="Interfaces\Classification\IClassificationEnsembleModel.cs">
+      <SubType>Code</SubType>
+    </Compile>
+    <Compile Include="Interfaces\Classification\IClassificationEnsembleSolution.cs">
+      <SubType>Code</SubType>
+    </Compile>
+    <Compile Include="Interfaces\Classification\IDiscriminantFunctionThresholdCalculator.cs" />
+    <Compile Include="Interfaces\IDataAnalysisSolutionExporter.cs" />
+    <Compile Include="Interfaces\IDataset.cs" />
+    <Compile Include="Interfaces\IDependencyCalculator.cs" />
+    <Compile Include="Interfaces\ITransformation.cs" />
+    <Compile Include="Interfaces\ITransformationMapper.cs" />
+    <Compile Include="Interfaces\Regression\IRegressionEnsembleModel.cs">
+      <SubType>Code</SubType>
+    </Compile>
+    <Compile Include="Interfaces\Regression\IRegressionEnsembleSolution.cs" />
+    <Compile Include="Implementation\Regression\RegressionSolutionBase.cs" />
+    <Compile Include="Interfaces\TimeSeriesPrognosis\IOnlineTimeSeriesCalculator.cs" />
+    <Compile Include="Interfaces\TimeSeriesPrognosis\ITimeSeriesPrognosisModel.cs" />
+    <Compile Include="Interfaces\TimeSeriesPrognosis\ITimeSeriesPrognosisProblem.cs" />
+    <Compile Include="Interfaces\TimeSeriesPrognosis\ITimeSeriesPrognosisProblemData.cs" />
+    <Compile Include="Interfaces\TimeSeriesPrognosis\ITimeSeriesPrognosisSolution.cs" />
+    <Compile Include="ModifiableDataset.cs" />
+    <Compile Include="OnlineCalculators\AutoCorrelationCalculator.cs" />
+    <Compile Include="OnlineCalculators\ClassificationPerformanceMeasuresCalculator.cs" />
+    <Compile Include="OnlineCalculators\ConfusionMatrixCalculator.cs" />
+    <Compile Include="OnlineCalculators\DependencyCalculator\HoeffdingsDependenceCalculator.cs" />
+    <Compile Include="OnlineCalculators\DependencyCalculator\PearsonsRDependenceCalculator.cs" />
+    <Compile Include="OnlineCalculators\DependencyCalculator\PearsonsRSquaredDependenceCalculator.cs" />
+    <Compile Include="OnlineCalculators\DependencyCalculator\SpearmansRankCorrelationCoefficientCalculator.cs" />
+    <Compile Include="OnlineCalculators\FOneScoreCalculator.cs" />
+    <Compile Include="OnlineCalculators\MatthewsCorrelationCoefficientCalculator.cs" />
+    <Compile Include="OnlineCalculators\OnlineBoundedMeanSquaredErrorCalculator.cs" />
+    <Compile Include="OnlineCalculators\OnlineCovarianceCalculator.cs" />
+    <Compile Include="OnlineCalculators\OnlineDirectionalSymmetryCalculator.cs" />
+    <Compile Include="OnlineCalculators\OnlineMaxAbsoluteErrorCalculator.cs" />
+    <Compile Include="OnlineCalculators\OnlineMeanErrorCalculator.cs" />
+    <Compile Include="OnlineCalculators\NormalizedGiniCalculator.cs" />
+    <Compile Include="OnlineCalculators\OnlineMeanAbsoluteErrorCalculator.cs" />
+    <Compile Include="OnlineCalculators\OnlineLinearScalingParameterCalculator.cs" />
+    <Compile Include="Implementation\Classification\DiscriminantFunctionClassificationModel.cs" />
+    <Compile Include="Implementation\Classification\DiscriminantFunctionClassificationSolution.cs" />
+    <Compile Include="Implementation\DataAnalysisSolution.cs" />
+    <Compile Include="Interfaces\Classification\IDiscriminantFunctionClassificationModel.cs" />
+    <Compile Include="Interfaces\Classification\IDiscriminantFunctionClassificationSolution.cs" />
+    <Compile Include="Interfaces\Clustering\IClusteringModel.cs" />
+    <Compile Include="Interfaces\Clustering\IClusteringProblem.cs" />
+    <Compile Include="Interfaces\Clustering\IClusteringProblemData.cs" />
+    <Compile Include="Interfaces\Clustering\IClusteringSolution.cs" />
+    <Compile Include="OnlineCalculators\OnlineAccuracyCalculator.cs" />
+    <Compile Include="Implementation\Regression\RegressionProblemData.cs" />
+    <Compile Include="Implementation\DataAnalysisProblemData.cs" />
+    <Compile Include="Implementation\Regression\RegressionProblem.cs" />
+    <Compile Include="Implementation\DataAnalysisProblem.cs" />
+    <Compile Include="Dataset.cs" />
+    <Compile Include="Interfaces\Classification\IClassificationModel.cs" />
+    <Compile Include="Interfaces\Classification\IClassificationProblem.cs" />
+    <Compile Include="Interfaces\Classification\IClassificationProblemData.cs" />
+    <Compile Include="Interfaces\Classification\IClassificationSolution.cs" />
+    <Compile Include="Interfaces\IDataAnalysisProblemData.cs" />
+    <Compile Include="Interfaces\IDataAnalysisSolution.cs" />
+    <Compile Include="Interfaces\IOnlineCalculator.cs" />
+    <Compile Include="Interfaces\Regression\IRegressionModel.cs" />
+    <Compile Include="Interfaces\Regression\IRegressionProblem.cs" />
+    <Compile Include="Interfaces\Regression\IRegressionProblemData.cs" />
+    <Compile Include="Interfaces\Regression\IRegressionSolution.cs" />
+    <Compile Include="OnlineCalculators\OnlineMeanAbsolutePercentageErrorCalculator.cs" />
+    <Compile Include="OnlineCalculators\OnlineMeanAndVarianceCalculator.cs" />
+    <Compile Include="OnlineCalculators\OnlineMeanSquaredErrorCalculator.cs" />
+    <Compile Include="OnlineCalculators\OnlineNormalizedMeanSquaredErrorCalculator.cs" />
+    <Compile Include="OnlineCalculators\OnlinePearsonsRCalculator.cs" />
+    <Compile Include="OnlineCalculators\OnlinePearsonsRSquaredCalculator.cs" />
+    <Compile Include="Implementation\Regression\RegressionSolution.cs" />
+    <Compile Include="OnlineCalculators\OnlineTheilsUStatisticCalculator.cs" />
+    <Compile Include="OnlineCalculators\OnlineWeightedDirectionalSymmetryCalculator.cs" />
+    <Compile Include="Plugin.cs" />
+    <Compile Include="Implementation\Classification\ThresholdCalculators\AccuracyMaximizationThresholdCalculator.cs" />
+    <Compile Include="Implementation\Classification\ThresholdCalculators\NormalDistributionCutPointsThresholdCalculator.cs" />
+    <Compile Include="Implementation\Classification\ThresholdCalculators\ThresholdCalculator.cs" />
+    <None Include="HeuristicLab.snk" />
+    <None Include="Plugin.cs.frame" />
+    <None Include="Properties\AssemblyInfo.cs.frame" />
+    <Compile Include="Interfaces\IDataAnalysisModel.cs" />
+    <Compile Include="Interfaces\IDataAnalysisProblem.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <BootstrapperPackage Include="Microsoft.Net.Client.3.5">
+      <Visible>False</Visible>
+      <ProductName>.NET Framework 3.5 SP1 Client Profile</ProductName>
+      <Install>false</Install>
+    </BootstrapperPackage>
+    <BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
+      <Visible>False</Visible>
+      <ProductName>.NET Framework 3.5 SP1</ProductName>
+      <Install>true</Install>
+    </BootstrapperPackage>
+    <BootstrapperPackage Include="Microsoft.Windows.Installer.3.1">
+      <Visible>False</Visible>
+      <ProductName>Windows Installer 3.1</ProductName>
+      <Install>true</Install>
+    </BootstrapperPackage>
+  </ItemGroup>
+  <ItemGroup />
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+  <PropertyGroup>
+    <PreBuildEvent Condition=" '$(OS)' == 'Windows_NT' ">set Path=%25Path%25;$(ProjectDir);$(SolutionDir)
+set ProjectDir=$(ProjectDir)
+set SolutionDir=$(SolutionDir)
+set Outdir=$(Outdir)
+
+call PreBuildEvent.cmd
+</PreBuildEvent>
+    <PreBuildEvent Condition=" '$(OS)' != 'Windows_NT' ">
+export ProjectDir=$(ProjectDir)
+export SolutionDir=$(SolutionDir)
+
+$SolutionDir/PreBuildEvent.sh
+</PreBuildEvent>
+  </PropertyGroup>
+</Project>
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ClassificationEnsembleModel.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ClassificationEnsembleModel.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ClassificationEnsembleModel.cs	(revision 13819)
@@ -0,0 +1,101 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  /// <summary>
+  /// Represents classification solutions that contain an ensemble of multiple classification models
+  /// </summary>
+  [StorableClass]
+  [Item("ClassificationEnsembleModel", "A classification model that contains an ensemble of multiple classification models")]
+  public class ClassificationEnsembleModel : NamedItem, IClassificationEnsembleModel {
+
+    [Storable]
+    private List<IClassificationModel> models;
+    public IEnumerable<IClassificationModel> Models {
+      get { return new List<IClassificationModel>(models); }
+    }
+
+    [StorableConstructor]
+    protected ClassificationEnsembleModel(bool deserializing) : base(deserializing) { }
+    protected ClassificationEnsembleModel(ClassificationEnsembleModel original, Cloner cloner)
+      : base(original, cloner) {
+      this.models = original.Models.Select(m => cloner.Clone(m)).ToList();
+    }
+
+    public ClassificationEnsembleModel() : this(Enumerable.Empty<IClassificationModel>()) { }
+    public ClassificationEnsembleModel(IEnumerable<IClassificationModel> models)
+      : base() {
+      this.name = ItemName;
+      this.description = ItemDescription;
+      this.models = new List<IClassificationModel>(models);
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new ClassificationEnsembleModel(this, cloner);
+    }
+
+    #region IClassificationEnsembleModel Members
+    public void Add(IClassificationModel model) {
+      models.Add(model);
+    }
+    public void Remove(IClassificationModel model) {
+      models.Remove(model);
+    }
+
+    public IEnumerable<IEnumerable<double>> GetEstimatedClassValueVectors(IDataset dataset, IEnumerable<int> rows) {
+      var estimatedValuesEnumerators = (from model in models
+                                        select model.GetEstimatedClassValues(dataset, rows).GetEnumerator())
+                                       .ToList();
+
+      while (estimatedValuesEnumerators.All(en => en.MoveNext())) {
+        yield return from enumerator in estimatedValuesEnumerators
+                     select enumerator.Current;
+      }
+    }
+
+    #endregion
+
+    #region IClassificationModel Members
+
+    public IEnumerable<double> GetEstimatedClassValues(IDataset dataset, IEnumerable<int> rows) {
+      foreach (var estimatedValuesVector in GetEstimatedClassValueVectors(dataset, rows)) {
+        // return the class which is most often occuring
+        yield return
+          estimatedValuesVector
+          .GroupBy(x => x)
+          .OrderBy(g => -g.Count())
+          .Select(g => g.Key)
+          .First();
+      }
+    }
+
+    IClassificationSolution IClassificationModel.CreateClassificationSolution(IClassificationProblemData problemData) {
+      return new ClassificationEnsembleSolution(models, new ClassificationEnsembleProblemData(problemData));
+    }
+    #endregion
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ClassificationEnsembleProblemData.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ClassificationEnsembleProblemData.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ClassificationEnsembleProblemData.cs	(revision 13819)
@@ -0,0 +1,88 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Collections.Generic;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  [StorableClass]
+  [Item("ClassificationEnsembleProblemData", "Represents an item containing all data defining a classification problem.")]
+  public class ClassificationEnsembleProblemData : ClassificationProblemData {
+
+    public override bool IsTrainingSample(int index) {
+      return index >= 0 && index < Dataset.Rows &&
+             TrainingPartition.Start <= index && index < TrainingPartition.End;
+    }
+
+    public override bool IsTestSample(int index) {
+      return index >= 0 && index < Dataset.Rows &&
+             TestPartition.Start <= index && index < TestPartition.End;
+    }
+
+    private static readonly ClassificationEnsembleProblemData emptyProblemData;
+    public static new ClassificationEnsembleProblemData EmptyProblemData {
+      get { return emptyProblemData; }
+    }
+
+    static ClassificationEnsembleProblemData() {
+      var problemData = new ClassificationEnsembleProblemData();
+      problemData.Parameters.Clear();
+      problemData.Name = "Empty Classification ProblemData";
+      problemData.Description = "This ProblemData acts as place holder before the correct problem data is loaded.";
+      problemData.isEmpty = true;
+
+      problemData.Parameters.Add(new FixedValueParameter<Dataset>(DatasetParameterName, "", new Dataset()));
+      problemData.Parameters.Add(new FixedValueParameter<ReadOnlyCheckedItemList<StringValue>>(InputVariablesParameterName, ""));
+      problemData.Parameters.Add(new FixedValueParameter<IntRange>(TrainingPartitionParameterName, "", (IntRange)new IntRange(0, 0).AsReadOnly()));
+      problemData.Parameters.Add(new FixedValueParameter<IntRange>(TestPartitionParameterName, "", (IntRange)new IntRange(0, 0).AsReadOnly()));
+      problemData.Parameters.Add(new ConstrainedValueParameter<StringValue>(TargetVariableParameterName, new ItemSet<StringValue>()));
+      problemData.Parameters.Add(new FixedValueParameter<StringMatrix>(ClassNamesParameterName, "", new StringMatrix(0, 0).AsReadOnly()));
+      problemData.Parameters.Add(new FixedValueParameter<DoubleMatrix>(ClassificationPenaltiesParameterName, "", (DoubleMatrix)new DoubleMatrix(0, 0).AsReadOnly()));
+      emptyProblemData = problemData;
+    }
+
+    [StorableConstructor]
+    protected ClassificationEnsembleProblemData(bool deserializing) : base(deserializing) { }
+    protected ClassificationEnsembleProblemData(ClassificationEnsembleProblemData original, Cloner cloner) : base(original, cloner) { }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      if (this == emptyProblemData) return emptyProblemData;
+      return new ClassificationEnsembleProblemData(this, cloner);
+    }
+
+    public ClassificationEnsembleProblemData() : base() { }
+    public ClassificationEnsembleProblemData(IClassificationProblemData classificationProblemData)
+      : base(classificationProblemData.Dataset, classificationProblemData.AllowedInputVariables, classificationProblemData.TargetVariable) {
+      this.TrainingPartition.Start = classificationProblemData.TrainingPartition.Start;
+      this.TrainingPartition.End = classificationProblemData.TrainingPartition.End;
+      this.TestPartition.Start = classificationProblemData.TestPartition.Start;
+      this.TestPartition.End = classificationProblemData.TestPartition.End;
+      this.PositiveClass = classificationProblemData.PositiveClass;
+    }
+
+    public ClassificationEnsembleProblemData(Dataset dataset, IEnumerable<string> allowedInputVariables, string targetVariable)
+      : base(dataset, allowedInputVariables, targetVariable) {
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ClassificationEnsembleSolution.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ClassificationEnsembleSolution.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ClassificationEnsembleSolution.cs	(revision 13819)
@@ -0,0 +1,340 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Collections;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  /// <summary>
+  /// Represents classification solutions that contain an ensemble of multiple classification models
+  /// </summary>
+  [StorableClass]
+  [Item("Classification Ensemble Solution", "A classification solution that contains an ensemble of multiple classification models")]
+  [Creatable(CreatableAttribute.Categories.DataAnalysisEnsembles, Priority = 110)]
+  public sealed class ClassificationEnsembleSolution : ClassificationSolutionBase, IClassificationEnsembleSolution {
+    private readonly Dictionary<int, double> trainingEvaluationCache = new Dictionary<int, double>();
+    private readonly Dictionary<int, double> testEvaluationCache = new Dictionary<int, double>();
+    private readonly Dictionary<int, double> evaluationCache = new Dictionary<int, double>();
+
+    public new IClassificationEnsembleModel Model {
+      get { return (IClassificationEnsembleModel)base.Model; }
+    }
+    public new ClassificationEnsembleProblemData ProblemData {
+      get { return (ClassificationEnsembleProblemData)base.ProblemData; }
+      set { base.ProblemData = value; }
+    }
+
+    [Storable]
+    private readonly ItemCollection<IClassificationSolution> classificationSolutions;
+    public IItemCollection<IClassificationSolution> ClassificationSolutions {
+      get { return classificationSolutions; }
+    }
+
+    [Storable]
+    private Dictionary<IClassificationModel, IntRange> trainingPartitions;
+    [Storable]
+    private Dictionary<IClassificationModel, IntRange> testPartitions;
+
+    [StorableConstructor]
+    private ClassificationEnsembleSolution(bool deserializing)
+      : base(deserializing) {
+      classificationSolutions = new ItemCollection<IClassificationSolution>();
+    }
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() {
+      if (!classificationSolutions.Any()) {
+        foreach (var model in Model.Models) {
+          IClassificationProblemData problemData = (IClassificationProblemData)ProblemData.Clone();
+          problemData.TrainingPartition.Start = trainingPartitions[model].Start;
+          problemData.TrainingPartition.End = trainingPartitions[model].End;
+          problemData.TestPartition.Start = testPartitions[model].Start;
+          problemData.TestPartition.End = testPartitions[model].End;
+
+          classificationSolutions.Add(model.CreateClassificationSolution(problemData));
+        }
+      }
+      RegisterClassificationSolutionsEventHandler();
+    }
+
+    private ClassificationEnsembleSolution(ClassificationEnsembleSolution original, Cloner cloner)
+      : base(original, cloner) {
+      trainingPartitions = new Dictionary<IClassificationModel, IntRange>();
+      testPartitions = new Dictionary<IClassificationModel, IntRange>();
+      foreach (var pair in original.trainingPartitions) {
+        trainingPartitions[cloner.Clone(pair.Key)] = cloner.Clone(pair.Value);
+      }
+      foreach (var pair in original.testPartitions) {
+        testPartitions[cloner.Clone(pair.Key)] = cloner.Clone(pair.Value);
+      }
+
+      trainingEvaluationCache = new Dictionary<int, double>(original.ProblemData.TrainingIndices.Count());
+      testEvaluationCache = new Dictionary<int, double>(original.ProblemData.TestIndices.Count());
+
+      classificationSolutions = cloner.Clone(original.classificationSolutions);
+      RegisterClassificationSolutionsEventHandler();
+    }
+
+    public ClassificationEnsembleSolution()
+      : base(new ClassificationEnsembleModel(), ClassificationEnsembleProblemData.EmptyProblemData) {
+      trainingPartitions = new Dictionary<IClassificationModel, IntRange>();
+      testPartitions = new Dictionary<IClassificationModel, IntRange>();
+      classificationSolutions = new ItemCollection<IClassificationSolution>();
+
+      RegisterClassificationSolutionsEventHandler();
+    }
+
+    public ClassificationEnsembleSolution(IClassificationProblemData problemData) :
+      this(Enumerable.Empty<IClassificationModel>(), problemData) { }
+
+    public ClassificationEnsembleSolution(IEnumerable<IClassificationModel> models, IClassificationProblemData problemData)
+      : this(models, problemData,
+             models.Select(m => (IntRange)problemData.TrainingPartition.Clone()),
+             models.Select(m => (IntRange)problemData.TestPartition.Clone())
+      ) { }
+
+    public ClassificationEnsembleSolution(IEnumerable<IClassificationModel> models, IClassificationProblemData problemData, IEnumerable<IntRange> trainingPartitions, IEnumerable<IntRange> testPartitions)
+      : base(new ClassificationEnsembleModel(Enumerable.Empty<IClassificationModel>()), new ClassificationEnsembleProblemData(problemData)) {
+      this.trainingPartitions = new Dictionary<IClassificationModel, IntRange>();
+      this.testPartitions = new Dictionary<IClassificationModel, IntRange>();
+      this.classificationSolutions = new ItemCollection<IClassificationSolution>();
+
+      List<IClassificationSolution> solutions = new List<IClassificationSolution>();
+      var modelEnumerator = models.GetEnumerator();
+      var trainingPartitionEnumerator = trainingPartitions.GetEnumerator();
+      var testPartitionEnumerator = testPartitions.GetEnumerator();
+
+      while (modelEnumerator.MoveNext() & trainingPartitionEnumerator.MoveNext() & testPartitionEnumerator.MoveNext()) {
+        var p = (IClassificationProblemData)problemData.Clone();
+        p.TrainingPartition.Start = trainingPartitionEnumerator.Current.Start;
+        p.TrainingPartition.End = trainingPartitionEnumerator.Current.End;
+        p.TestPartition.Start = testPartitionEnumerator.Current.Start;
+        p.TestPartition.End = testPartitionEnumerator.Current.End;
+
+        solutions.Add(modelEnumerator.Current.CreateClassificationSolution(p));
+      }
+      if (modelEnumerator.MoveNext() | trainingPartitionEnumerator.MoveNext() | testPartitionEnumerator.MoveNext()) {
+        throw new ArgumentException();
+      }
+
+      trainingEvaluationCache = new Dictionary<int, double>(problemData.TrainingIndices.Count());
+      testEvaluationCache = new Dictionary<int, double>(problemData.TestIndices.Count());
+
+      RegisterClassificationSolutionsEventHandler();
+      classificationSolutions.AddRange(solutions);
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new ClassificationEnsembleSolution(this, cloner);
+    }
+    private void RegisterClassificationSolutionsEventHandler() {
+      classificationSolutions.ItemsAdded += new CollectionItemsChangedEventHandler<IClassificationSolution>(classificationSolutions_ItemsAdded);
+      classificationSolutions.ItemsRemoved += new CollectionItemsChangedEventHandler<IClassificationSolution>(classificationSolutions_ItemsRemoved);
+      classificationSolutions.CollectionReset += new CollectionItemsChangedEventHandler<IClassificationSolution>(classificationSolutions_CollectionReset);
+    }
+
+
+    #region Evaluation
+    public override IEnumerable<double> EstimatedClassValues {
+      get { return GetEstimatedClassValues(Enumerable.Range(0, ProblemData.Dataset.Rows)); }
+    }
+
+    public override IEnumerable<double> EstimatedTrainingClassValues {
+      get {
+        var rows = ProblemData.TrainingIndices;
+        var rowsToEvaluate = rows.Except(trainingEvaluationCache.Keys);
+        var rowsEnumerator = rowsToEvaluate.GetEnumerator();
+        var valuesEnumerator = GetEstimatedValues(rowsToEvaluate, (r, m) => RowIsTrainingForModel(r, m) && !RowIsTestForModel(r, m)).GetEnumerator();
+
+        while (rowsEnumerator.MoveNext() & valuesEnumerator.MoveNext()) {
+          trainingEvaluationCache.Add(rowsEnumerator.Current, valuesEnumerator.Current);
+        }
+
+        return rows.Select(row => trainingEvaluationCache[row]);
+      }
+    }
+
+    public override IEnumerable<double> EstimatedTestClassValues {
+      get {
+        var rows = ProblemData.TestIndices;
+        var rowsToEvaluate = rows.Except(testEvaluationCache.Keys);
+        var rowsEnumerator = rowsToEvaluate.GetEnumerator();
+        var valuesEnumerator = GetEstimatedValues(rowsToEvaluate, RowIsTestForModel).GetEnumerator();
+
+        while (rowsEnumerator.MoveNext() & valuesEnumerator.MoveNext()) {
+          testEvaluationCache.Add(rowsEnumerator.Current, valuesEnumerator.Current);
+        }
+
+        return rows.Select(row => testEvaluationCache[row]);
+      }
+    }
+
+    private IEnumerable<double> GetEstimatedValues(IEnumerable<int> rows, Func<int, IClassificationModel, bool> modelSelectionPredicate) {
+      var estimatedValuesEnumerators = (from model in Model.Models
+                                        select new { Model = model, EstimatedValuesEnumerator = model.GetEstimatedClassValues(ProblemData.Dataset, rows).GetEnumerator() })
+                                       .ToList();
+      var rowsEnumerator = rows.GetEnumerator();
+      // aggregate to make sure that MoveNext is called for all enumerators 
+      while (rowsEnumerator.MoveNext() & estimatedValuesEnumerators.Select(en => en.EstimatedValuesEnumerator.MoveNext()).Aggregate(true, (acc, b) => acc & b)) {
+        int currentRow = rowsEnumerator.Current;
+
+        var selectedEnumerators = from pair in estimatedValuesEnumerators
+                                  where modelSelectionPredicate(currentRow, pair.Model)
+                                  select pair.EstimatedValuesEnumerator;
+
+        yield return AggregateEstimatedClassValues(selectedEnumerators.Select(x => x.Current));
+      }
+    }
+
+    private bool RowIsTrainingForModel(int currentRow, IClassificationModel model) {
+      return trainingPartitions == null || !trainingPartitions.ContainsKey(model) ||
+              (trainingPartitions[model].Start <= currentRow && currentRow < trainingPartitions[model].End);
+    }
+
+    private bool RowIsTestForModel(int currentRow, IClassificationModel model) {
+      return testPartitions == null || !testPartitions.ContainsKey(model) ||
+              (testPartitions[model].Start <= currentRow && currentRow < testPartitions[model].End);
+    }
+
+    public override IEnumerable<double> GetEstimatedClassValues(IEnumerable<int> rows) {
+      var rowsToEvaluate = rows.Except(evaluationCache.Keys);
+      var rowsEnumerator = rowsToEvaluate.GetEnumerator();
+      var valuesEnumerator = (from xs in GetEstimatedClassValueVectors(ProblemData.Dataset, rowsToEvaluate)
+                              select AggregateEstimatedClassValues(xs))
+                             .GetEnumerator();
+
+      while (rowsEnumerator.MoveNext() & valuesEnumerator.MoveNext()) {
+        evaluationCache.Add(rowsEnumerator.Current, valuesEnumerator.Current);
+      }
+
+      return rows.Select(row => evaluationCache[row]);
+    }
+
+    public IEnumerable<IEnumerable<double>> GetEstimatedClassValueVectors(IDataset dataset, IEnumerable<int> rows) {
+      if (!Model.Models.Any()) yield break;
+      var estimatedValuesEnumerators = (from model in Model.Models
+                                        select model.GetEstimatedClassValues(dataset, rows).GetEnumerator())
+                                       .ToList();
+
+      while (estimatedValuesEnumerators.All(en => en.MoveNext())) {
+        yield return from enumerator in estimatedValuesEnumerators
+                     select enumerator.Current;
+      }
+    }
+
+    private double AggregateEstimatedClassValues(IEnumerable<double> estimatedClassValues) {
+      return estimatedClassValues
+      .GroupBy(x => x)
+      .OrderBy(g => -g.Count())
+      .Select(g => g.Key)
+      .DefaultIfEmpty(double.NaN)
+      .First();
+    }
+    #endregion
+
+    protected override void OnProblemDataChanged() {
+      trainingEvaluationCache.Clear();
+      testEvaluationCache.Clear();
+      evaluationCache.Clear();
+
+      IClassificationProblemData problemData = new ClassificationProblemData(ProblemData.Dataset,
+                                                                     ProblemData.AllowedInputVariables,
+                                                                     ProblemData.TargetVariable);
+      problemData.TrainingPartition.Start = ProblemData.TrainingPartition.Start;
+      problemData.TrainingPartition.End = ProblemData.TrainingPartition.End;
+      problemData.TestPartition.Start = ProblemData.TestPartition.Start;
+      problemData.TestPartition.End = ProblemData.TestPartition.End;
+
+      foreach (var solution in ClassificationSolutions) {
+        if (solution is ClassificationEnsembleSolution)
+          solution.ProblemData = ProblemData;
+        else
+          solution.ProblemData = problemData;
+      }
+      foreach (var trainingPartition in trainingPartitions.Values) {
+        trainingPartition.Start = ProblemData.TrainingPartition.Start;
+        trainingPartition.End = ProblemData.TrainingPartition.End;
+      }
+      foreach (var testPartition in testPartitions.Values) {
+        testPartition.Start = ProblemData.TestPartition.Start;
+        testPartition.End = ProblemData.TestPartition.End;
+      }
+
+      base.OnProblemDataChanged();
+    }
+
+    public void AddClassificationSolutions(IEnumerable<IClassificationSolution> solutions) {
+      classificationSolutions.AddRange(solutions);
+
+      trainingEvaluationCache.Clear();
+      testEvaluationCache.Clear();
+      evaluationCache.Clear();
+    }
+    public void RemoveClassificationSolutions(IEnumerable<IClassificationSolution> solutions) {
+      classificationSolutions.RemoveRange(solutions);
+
+      trainingEvaluationCache.Clear();
+      testEvaluationCache.Clear();
+      evaluationCache.Clear();
+    }
+
+    private void classificationSolutions_ItemsAdded(object sender, CollectionItemsChangedEventArgs<IClassificationSolution> e) {
+      foreach (var solution in e.Items) AddClassificationSolution(solution);
+      RecalculateResults();
+    }
+    private void classificationSolutions_ItemsRemoved(object sender, CollectionItemsChangedEventArgs<IClassificationSolution> e) {
+      foreach (var solution in e.Items) RemoveClassificationSolution(solution);
+      RecalculateResults();
+    }
+    private void classificationSolutions_CollectionReset(object sender, CollectionItemsChangedEventArgs<IClassificationSolution> e) {
+      foreach (var solution in e.OldItems) RemoveClassificationSolution(solution);
+      foreach (var solution in e.Items) AddClassificationSolution(solution);
+      RecalculateResults();
+    }
+
+    private void AddClassificationSolution(IClassificationSolution solution) {
+      if (Model.Models.Contains(solution.Model)) throw new ArgumentException();
+      Model.Add(solution.Model);
+      trainingPartitions[solution.Model] = solution.ProblemData.TrainingPartition;
+      testPartitions[solution.Model] = solution.ProblemData.TestPartition;
+
+      trainingEvaluationCache.Clear();
+      testEvaluationCache.Clear();
+      evaluationCache.Clear();
+    }
+
+    private void RemoveClassificationSolution(IClassificationSolution solution) {
+      if (!Model.Models.Contains(solution.Model)) throw new ArgumentException();
+      Model.Remove(solution.Model);
+      trainingPartitions.Remove(solution.Model);
+      testPartitions.Remove(solution.Model);
+
+      trainingEvaluationCache.Clear();
+      testEvaluationCache.Clear();
+      evaluationCache.Clear();
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ClassificationPerformanceMeasures.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ClassificationPerformanceMeasures.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ClassificationPerformanceMeasures.cs	(revision 13819)
@@ -0,0 +1,205 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using HeuristicLab.Common;
+using HeuristicLab.Data;
+using HeuristicLab.Optimization;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  [StorableClass]
+  public class ClassificationPerformanceMeasuresResultCollection : ResultCollection {
+    #region result names
+    protected const string ClassificationPositiveClassNameResultName = "Classification positive class";
+    protected const string TrainingTruePositiveRateResultName = "True positive rate (training)";
+    protected const string TrainingTrueNegativeRateResultName = "True negative rate (training)";
+    protected const string TrainingPositivePredictiveValueResultName = "Positive predictive value (training)";
+    protected const string TrainingNegativePredictiveValueResultName = "Negative predictive value (training)";
+    protected const string TrainingFalsePositiveRateResultName = "False positive rate (training)";
+    protected const string TrainingFalseDiscoveryRateResultName = "False discovery rate (training)";
+    protected const string TrainingF1ScoreResultName = "F1 score (training)";
+    protected const string TrainingMatthewsCorrelationResultName = "Matthews Correlation (training)";
+    protected const string TestTruePositiveRateResultName = "True positive rate (test)";
+    protected const string TestTrueNegativeRateResultName = "True negative rate (test)";
+    protected const string TestPositivePredictiveValueResultName = "Positive predictive value (test)";
+    protected const string TestNegativePredictiveValueResultName = "Negative predictive value (test)";
+    protected const string TestFalsePositiveRateResultName = "False positive rate (test)";
+    protected const string TestFalseDiscoveryRateResultName = "False discovery rate (test)";
+    protected const string TestF1ScoreResultName = "F1 score (test)";
+    protected const string TestMatthewsCorrelationResultName = "Matthews Correlation (test)";
+    #endregion
+
+    public ClassificationPerformanceMeasuresResultCollection()
+      : base() {
+      AddMeasures();
+    }
+    [StorableConstructor]
+    protected ClassificationPerformanceMeasuresResultCollection(bool deserializing)
+      : base(deserializing) {
+    }
+
+    protected ClassificationPerformanceMeasuresResultCollection(ClassificationPerformanceMeasuresResultCollection original, Cloner cloner)
+      : base(original, cloner) { }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new ClassificationPerformanceMeasuresResultCollection(this, cloner);
+    }
+
+    #region result properties
+    public string ClassificationPositiveClassName {
+      get { return ((StringValue)this[ClassificationPositiveClassNameResultName].Value).Value; }
+      set { ((StringValue)this[ClassificationPositiveClassNameResultName].Value).Value = value; }
+    }
+    public double TrainingTruePositiveRate {
+      get { return ((DoubleValue)this[TrainingTruePositiveRateResultName].Value).Value; }
+      set { ((DoubleValue)this[TrainingTruePositiveRateResultName].Value).Value = value; }
+    }
+    public double TrainingTrueNegativeRate {
+      get { return ((DoubleValue)this[TrainingTrueNegativeRateResultName].Value).Value; }
+      set { ((DoubleValue)this[TrainingTrueNegativeRateResultName].Value).Value = value; }
+    }
+    public double TrainingPositivePredictiveValue {
+      get { return ((DoubleValue)this[TrainingPositivePredictiveValueResultName].Value).Value; }
+      set { ((DoubleValue)this[TrainingPositivePredictiveValueResultName].Value).Value = value; }
+    }
+    public double TrainingNegativePredictiveValue {
+      get { return ((DoubleValue)this[TrainingNegativePredictiveValueResultName].Value).Value; }
+      set { ((DoubleValue)this[TrainingNegativePredictiveValueResultName].Value).Value = value; }
+    }
+    public double TrainingFalsePositiveRate {
+      get { return ((DoubleValue)this[TrainingFalsePositiveRateResultName].Value).Value; }
+      set { ((DoubleValue)this[TrainingFalsePositiveRateResultName].Value).Value = value; }
+    }
+    public double TrainingFalseDiscoveryRate {
+      get { return ((DoubleValue)this[TrainingFalseDiscoveryRateResultName].Value).Value; }
+      set { ((DoubleValue)this[TrainingFalseDiscoveryRateResultName].Value).Value = value; }
+    }
+    public double TrainingF1Score {
+      get { return ((DoubleValue)this[TrainingF1ScoreResultName].Value).Value; }
+      set { ((DoubleValue)this[TrainingF1ScoreResultName].Value).Value = value; }
+    }
+    public double TrainingMatthewsCorrelation {
+      get { return ((DoubleValue)this[TrainingMatthewsCorrelationResultName].Value).Value; }
+      set { ((DoubleValue)this[TrainingMatthewsCorrelationResultName].Value).Value = value; }
+    }
+    public double TestTruePositiveRate {
+      get { return ((DoubleValue)this[TestTruePositiveRateResultName].Value).Value; }
+      set { ((DoubleValue)this[TestTruePositiveRateResultName].Value).Value = value; }
+    }
+    public double TestTrueNegativeRate {
+      get { return ((DoubleValue)this[TestTrueNegativeRateResultName].Value).Value; }
+      set { ((DoubleValue)this[TestTrueNegativeRateResultName].Value).Value = value; }
+    }
+    public double TestPositivePredictiveValue {
+      get { return ((DoubleValue)this[TestPositivePredictiveValueResultName].Value).Value; }
+      set { ((DoubleValue)this[TestPositivePredictiveValueResultName].Value).Value = value; }
+    }
+    public double TestNegativePredictiveValue {
+      get { return ((DoubleValue)this[TestNegativePredictiveValueResultName].Value).Value; }
+      set { ((DoubleValue)this[TestNegativePredictiveValueResultName].Value).Value = value; }
+    }
+    public double TestFalsePositiveRate {
+      get { return ((DoubleValue)this[TestFalsePositiveRateResultName].Value).Value; }
+      set { ((DoubleValue)this[TestFalsePositiveRateResultName].Value).Value = value; }
+    }
+    public double TestFalseDiscoveryRate {
+      get { return ((DoubleValue)this[TestFalseDiscoveryRateResultName].Value).Value; }
+      set { ((DoubleValue)this[TestFalseDiscoveryRateResultName].Value).Value = value; }
+    }
+    public double TestF1Score {
+      get { return ((DoubleValue)this[TestF1ScoreResultName].Value).Value; }
+      set { ((DoubleValue)this[TestF1ScoreResultName].Value).Value = value; }
+    }
+    public double TestMatthewsCorrelation {
+      get { return ((DoubleValue)this[TestMatthewsCorrelationResultName].Value).Value; }
+      set { ((DoubleValue)this[TestMatthewsCorrelationResultName].Value).Value = value; }
+    }
+    #endregion
+
+    protected void AddMeasures() {
+      Add(new Result(ClassificationPositiveClassNameResultName, "The positive class which is used for the performance measure calculations.", new StringValue()));
+      Add(new Result(TrainingTruePositiveRateResultName, "Sensitivity/True positive rate of the model on the training partition\n(TP/(TP+FN)).", new PercentValue()));
+      Add(new Result(TrainingTrueNegativeRateResultName, "Specificity/True negative rate of the model on the training partition\n(TN/(FP+TN)).", new PercentValue()));
+      Add(new Result(TrainingPositivePredictiveValueResultName, "Precision/Positive predictive value of the model on the training partition\n(TP/(TP+FP)).", new PercentValue()));
+      Add(new Result(TrainingNegativePredictiveValueResultName, "Negative predictive value of the model on the training partition\n(TN/(TN+FN)).", new PercentValue()));
+      Add(new Result(TrainingFalsePositiveRateResultName, "The false positive rate is the complement of the true negative rate of the model on the training partition.", new PercentValue()));
+      Add(new Result(TrainingFalseDiscoveryRateResultName, "The false discovery rate is the complement of the positive predictive value of the model on the training partition.", new PercentValue()));
+      Add(new Result(TrainingF1ScoreResultName, "The F1 score of the model on the training partition.", new DoubleValue()));
+      Add(new Result(TrainingMatthewsCorrelationResultName, "The Matthews correlation value of the model on the training partition.", new DoubleValue()));
+      Add(new Result(TestTruePositiveRateResultName, "Sensitivity/True positive rate of the model on the test partition\n(TP/(TP+FN)).", new PercentValue()));
+      Add(new Result(TestTrueNegativeRateResultName, "Specificity/True negative rate of the model on the test partition\n(TN/(FP+TN)).", new PercentValue()));
+      Add(new Result(TestPositivePredictiveValueResultName, "Precision/Positive predictive value of the model on the test partition\n(TP/(TP+FP)).", new PercentValue()));
+      Add(new Result(TestNegativePredictiveValueResultName, "Negative predictive value of the model on the test partition\n(TN/(TN+FN)).", new PercentValue()));
+      Add(new Result(TestFalsePositiveRateResultName, "The false positive rate is the complement of the true negative rate of the model on the test partition.", new PercentValue()));
+      Add(new Result(TestFalseDiscoveryRateResultName, "The false discovery rate is the complement of the positive predictive value of the model on the test partition.", new PercentValue()));
+      Add(new Result(TestF1ScoreResultName, "The F1 score of the model on the test partition.", new DoubleValue()));
+      Add(new Result(TestMatthewsCorrelationResultName, "The Matthews correlation value of the model on the test partition.", new DoubleValue()));
+
+      Reset();
+    }
+
+
+    public void Reset() {
+      TrainingTruePositiveRate = double.NaN;
+      TrainingTrueNegativeRate = double.NaN;
+      TrainingPositivePredictiveValue = double.NaN;
+      TrainingNegativePredictiveValue = double.NaN;
+      TrainingFalsePositiveRate = double.NaN;
+      TrainingFalseDiscoveryRate = double.NaN;
+      TrainingF1Score = double.NaN;
+      TrainingMatthewsCorrelation = double.NaN;
+      TestTruePositiveRate = double.NaN;
+      TestTrueNegativeRate = double.NaN;
+      TestPositivePredictiveValue = double.NaN;
+      TestNegativePredictiveValue = double.NaN;
+      TestFalsePositiveRate = double.NaN;
+      TestFalseDiscoveryRate = double.NaN;
+      TestF1Score = double.NaN;
+      TestMatthewsCorrelation = double.NaN;
+    }
+
+    public void SetTrainingResults(ClassificationPerformanceMeasuresCalculator trainingPerformanceCalculator) {
+      if (!string.IsNullOrWhiteSpace(ClassificationPositiveClassName)
+              && !ClassificationPositiveClassName.Equals(trainingPerformanceCalculator.PositiveClassName))
+        throw new ArgumentException("Classification positive class of the training data doesn't match with the data of test partition.");
+      ClassificationPositiveClassName = trainingPerformanceCalculator.PositiveClassName;
+      TrainingTruePositiveRate = trainingPerformanceCalculator.TruePositiveRate;
+      TrainingTrueNegativeRate = trainingPerformanceCalculator.TrueNegativeRate;
+      TrainingPositivePredictiveValue = trainingPerformanceCalculator.PositivePredictiveValue;
+      TrainingNegativePredictiveValue = trainingPerformanceCalculator.NegativePredictiveValue;
+      TrainingFalsePositiveRate = trainingPerformanceCalculator.FalsePositiveRate;
+      TrainingFalseDiscoveryRate = trainingPerformanceCalculator.FalseDiscoveryRate;
+    }
+
+    public void SetTestResults(ClassificationPerformanceMeasuresCalculator testPerformanceCalculator) {
+      if (!string.IsNullOrWhiteSpace(ClassificationPositiveClassName)
+                && !ClassificationPositiveClassName.Equals(testPerformanceCalculator.PositiveClassName))
+        throw new ArgumentException("Classification positive class of the test data doesn't match with the data of training partition.");
+      ClassificationPositiveClassName = testPerformanceCalculator.PositiveClassName;
+      TestTruePositiveRate = testPerformanceCalculator.TruePositiveRate;
+      TestTrueNegativeRate = testPerformanceCalculator.TrueNegativeRate;
+      TestPositivePredictiveValue = testPerformanceCalculator.PositivePredictiveValue;
+      TestNegativePredictiveValue = testPerformanceCalculator.NegativePredictiveValue;
+      TestFalsePositiveRate = testPerformanceCalculator.FalsePositiveRate;
+      TestFalseDiscoveryRate = testPerformanceCalculator.FalseDiscoveryRate;
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ClassificationProblem.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ClassificationProblem.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ClassificationProblem.cs	(revision 13819)
@@ -0,0 +1,39 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  [StorableClass]
+  [Item("Classification Problem", "A general classification problem.")]
+  public class ClassificationProblem : DataAnalysisProblem<IClassificationProblemData>, IClassificationProblem, IStorableContent {
+    public string Filename { get; set; }
+
+    [StorableConstructor]
+    protected ClassificationProblem(bool deserializing) : base(deserializing) { }
+    protected ClassificationProblem(ClassificationProblem original, Cloner cloner) : base(original, cloner) { }
+    public override IDeepCloneable Clone(Cloner cloner) { return new ClassificationProblem(this, cloner); }
+
+    public ClassificationProblem() : base(new ClassificationProblemData()) { }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ClassificationProblemData.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ClassificationProblemData.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ClassificationProblemData.cs	(revision 13819)
@@ -0,0 +1,518 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  [StorableClass]
+  [Item("ClassificationProblemData", "Represents an item containing all data defining a classification problem.")]
+  public class ClassificationProblemData : DataAnalysisProblemData, IClassificationProblemData, IStorableContent {
+    protected const string TargetVariableParameterName = "TargetVariable";
+    protected const string ClassNamesParameterName = "ClassNames";
+    protected const string ClassificationPenaltiesParameterName = "ClassificationPenalties";
+    protected const string PositiveClassParameterName = "PositiveClass";
+    protected const int MaximumNumberOfClasses = 100;
+    protected const int InspectedRowsToDetermineTargets = 2000;
+
+    public string Filename { get; set; }
+
+    #region default data
+    private static string[] defaultVariableNames = new string[] { "sample", "clump thickness", "cell size", "cell shape", "marginal adhesion", "epithelial cell size", "bare nuclei", "chromatin", "nucleoli", "mitoses", "class" };
+    private static double[,] defaultData = new double[,]{
+     {1000025,5,1,1,1,2,1,3,1,1,2      },
+     {1002945,5,4,4,5,7,10,3,2,1,2     },
+     {1015425,3,1,1,1,2,2,3,1,1,2      },
+     {1016277,6,8,8,1,3,4,3,7,1,2      },
+     {1017023,4,1,1,3,2,1,3,1,1,2      },
+     {1017122,8,10,10,8,7,10,9,7,1,4   },
+     {1018099,1,1,1,1,2,10,3,1,1,2     },
+     {1018561,2,1,2,1,2,1,3,1,1,2      },
+     {1033078,2,1,1,1,2,1,1,1,5,2      },
+     {1033078,4,2,1,1,2,1,2,1,1,2      },
+     {1035283,1,1,1,1,1,1,3,1,1,2      },
+     {1036172,2,1,1,1,2,1,2,1,1,2      },
+     {1041801,5,3,3,3,2,3,4,4,1,4      },
+     {1043999,1,1,1,1,2,3,3,1,1,2      },
+     {1044572,8,7,5,10,7,9,5,5,4,4     },
+     {1047630,7,4,6,4,6,1,4,3,1,4      },
+     {1048672,4,1,1,1,2,1,2,1,1,2      },
+     {1049815,4,1,1,1,2,1,3,1,1,2      },
+     {1050670,10,7,7,6,4,10,4,1,2,4    },
+     {1050718,6,1,1,1,2,1,3,1,1,2      },
+     {1054590,7,3,2,10,5,10,5,4,4,4    },
+     {1054593,10,5,5,3,6,7,7,10,1,4    },
+     {1056784,3,1,1,1,2,1,2,1,1,2      },
+     {1057013,8,4,5,1,2,2,7,3,1,4      },
+     {1059552,1,1,1,1,2,1,3,1,1,2      },
+     {1065726,5,2,3,4,2,7,3,6,1,4      },
+     {1066373,3,2,1,1,1,1,2,1,1,2      },
+     {1066979,5,1,1,1,2,1,2,1,1,2      },
+     {1067444,2,1,1,1,2,1,2,1,1,2      },
+     {1070935,1,1,3,1,2,1,1,1,1,2      },
+     {1070935,3,1,1,1,1,1,2,1,1,2      },
+     {1071760,2,1,1,1,2,1,3,1,1,2      },
+     {1072179,10,7,7,3,8,5,7,4,3,4     },
+     {1074610,2,1,1,2,2,1,3,1,1,2      },
+     {1075123,3,1,2,1,2,1,2,1,1,2      },
+     {1079304,2,1,1,1,2,1,2,1,1,2      },
+     {1080185,10,10,10,8,6,1,8,9,1,4   },
+     {1081791,6,2,1,1,1,1,7,1,1,2      },
+     {1084584,5,4,4,9,2,10,5,6,1,4     },
+     {1091262,2,5,3,3,6,7,7,5,1,4      },
+     {1096800,6,6,6,9,6,4,7,8,1,2      },
+     {1099510,10,4,3,1,3,3,6,5,2,4     },
+     {1100524,6,10,10,2,8,10,7,3,3,4   },
+     {1102573,5,6,5,6,10,1,3,1,1,4     },
+     {1103608,10,10,10,4,8,1,8,10,1,4  },
+     {1103722,1,1,1,1,2,1,2,1,2,2      },
+     {1105257,3,7,7,4,4,9,4,8,1,4      },
+     {1105524,1,1,1,1,2,1,2,1,1,2      },
+     {1106095,4,1,1,3,2,1,3,1,1,2      },
+     {1106829,7,8,7,2,4,8,3,8,2,4      },
+     {1108370,9,5,8,1,2,3,2,1,5,4      },
+     {1108449,5,3,3,4,2,4,3,4,1,4      },
+     {1110102,10,3,6,2,3,5,4,10,2,4    },
+     {1110503,5,5,5,8,10,8,7,3,7,4     },
+     {1110524,10,5,5,6,8,8,7,1,1,4     },
+     {1111249,10,6,6,3,4,5,3,6,1,4     },
+     {1112209,8,10,10,1,3,6,3,9,1,4    },
+     {1113038,8,2,4,1,5,1,5,4,4,4      },
+     {1113483,5,2,3,1,6,10,5,1,1,4     },
+     {1113906,9,5,5,2,2,2,5,1,1,4      },
+     {1115282,5,3,5,5,3,3,4,10,1,4     },
+     {1115293,1,1,1,1,2,2,2,1,1,2      },
+     {1116116,9,10,10,1,10,8,3,3,1,4   },
+     {1116132,6,3,4,1,5,2,3,9,1,4      },
+     {1116192,1,1,1,1,2,1,2,1,1,2      },
+     {1116998,10,4,2,1,3,2,4,3,10,4    },
+     {1117152,4,1,1,1,2,1,3,1,1,2      },
+     {1118039,5,3,4,1,8,10,4,9,1,4     },
+     {1120559,8,3,8,3,4,9,8,9,8,4      },
+     {1121732,1,1,1,1,2,1,3,2,1,2      },
+     {1121919,5,1,3,1,2,1,2,1,1,2      },
+     {1123061,6,10,2,8,10,2,7,8,10,4   },
+     {1124651,1,3,3,2,2,1,7,2,1,2      },
+     {1125035,9,4,5,10,6,10,4,8,1,4    },
+     {1126417,10,6,4,1,3,4,3,2,3,4     },
+     {1131294,1,1,2,1,2,2,4,2,1,2      },
+     {1132347,1,1,4,1,2,1,2,1,1,2      },
+     {1133041,5,3,1,2,2,1,2,1,1,2      },
+     {1133136,3,1,1,1,2,3,3,1,1,2      },
+     {1136142,2,1,1,1,3,1,2,1,1,2      },
+     {1137156,2,2,2,1,1,1,7,1,1,2      },
+     {1143978,4,1,1,2,2,1,2,1,1,2      },
+     {1143978,5,2,1,1,2,1,3,1,1,2      },
+     {1147044,3,1,1,1,2,2,7,1,1,2      },
+     {1147699,3,5,7,8,8,9,7,10,7,4     },
+     {1147748,5,10,6,1,10,4,4,10,10,4  },
+     {1148278,3,3,6,4,5,8,4,4,1,4      },
+     {1148873,3,6,6,6,5,10,6,8,3,4     },
+     {1152331,4,1,1,1,2,1,3,1,1,2      },
+     {1155546,2,1,1,2,3,1,2,1,1,2      },
+     {1156272,1,1,1,1,2,1,3,1,1,2      },
+     {1156948,3,1,1,2,2,1,1,1,1,2      },
+     {1157734,4,1,1,1,2,1,3,1,1,2      },
+     {1158247,1,1,1,1,2,1,2,1,1,2      },
+     {1160476,2,1,1,1,2,1,3,1,1,2      },
+     {1164066,1,1,1,1,2,1,3,1,1,2      },
+     {1165297,2,1,1,2,2,1,1,1,1,2      },
+     {1165790,5,1,1,1,2,1,3,1,1,2      },
+     {1165926,9,6,9,2,10,6,2,9,10,4    },
+     {1166630,7,5,6,10,5,10,7,9,4,4    },
+     {1166654,10,3,5,1,10,5,3,10,2,4   },
+     {1167439,2,3,4,4,2,5,2,5,1,4      },
+     {1167471,4,1,2,1,2,1,3,1,1,2      },
+     {1168359,8,2,3,1,6,3,7,1,1,4      },
+     {1168736,10,10,10,10,10,1,8,8,8,4 },
+     {1169049,7,3,4,4,3,3,3,2,7,4      },
+     {1170419,10,10,10,8,2,10,4,1,1,4  },
+     {1170420,1,6,8,10,8,10,5,7,1,4    },
+     {1171710,1,1,1,1,2,1,2,3,1,2      },
+     {1171710,6,5,4,4,3,9,7,8,3,4      },
+     {1171795,1,3,1,2,2,2,5,3,2,2      },
+     {1171845,8,6,4,3,5,9,3,1,1,4      },
+     {1172152,10,3,3,10,2,10,7,3,3,4   },
+     {1173216,10,10,10,3,10,8,8,1,1,4  },
+     {1173235,3,3,2,1,2,3,3,1,1,2      },
+     {1173347,1,1,1,1,2,5,1,1,1,2      },
+     {1173347,8,3,3,1,2,2,3,2,1,2      },
+     {1173509,4,5,5,10,4,10,7,5,8,4    },
+     {1173514,1,1,1,1,4,3,1,1,1,2      },
+     {1173681,3,2,1,1,2,2,3,1,1,2      },
+     {1174057,1,1,2,2,2,1,3,1,1,2      },
+     {1174057,4,2,1,1,2,2,3,1,1,2      },
+     {1174131,10,10,10,2,10,10,5,3,3,4 },
+     {1174428,5,3,5,1,8,10,5,3,1,4     },
+     {1175937,5,4,6,7,9,7,8,10,1,4     },
+     {1176406,1,1,1,1,2,1,2,1,1,2      },
+     {1176881,7,5,3,7,4,10,7,5,5,4        }
+};
+    private static readonly Dataset defaultDataset;
+    private static readonly IEnumerable<string> defaultAllowedInputVariables;
+    private static readonly string defaultTargetVariable;
+
+    private static readonly ClassificationProblemData emptyProblemData;
+    public static ClassificationProblemData EmptyProblemData {
+      get { return EmptyProblemData; }
+    }
+
+    static ClassificationProblemData() {
+      defaultDataset = new Dataset(defaultVariableNames, defaultData);
+      defaultDataset.Name = "Wisconsin classification problem";
+      defaultDataset.Description = "subset from to ..";
+
+      defaultAllowedInputVariables = defaultVariableNames.Except(new List<string>() { "sample", "class" });
+      defaultTargetVariable = "class";
+
+      var problemData = new ClassificationProblemData();
+      problemData.Parameters.Clear();
+      problemData.Name = "Empty Classification ProblemData";
+      problemData.Description = "This ProblemData acts as place holder before the correct problem data is loaded.";
+      problemData.isEmpty = true;
+
+      problemData.Parameters.Add(new FixedValueParameter<Dataset>(DatasetParameterName, "", new Dataset()));
+      problemData.Parameters.Add(new FixedValueParameter<ReadOnlyCheckedItemList<StringValue>>(InputVariablesParameterName, ""));
+      problemData.Parameters.Add(new FixedValueParameter<IntRange>(TrainingPartitionParameterName, "", (IntRange)new IntRange(0, 0).AsReadOnly()));
+      problemData.Parameters.Add(new FixedValueParameter<IntRange>(TestPartitionParameterName, "", (IntRange)new IntRange(0, 0).AsReadOnly()));
+      problemData.Parameters.Add(new ConstrainedValueParameter<StringValue>(TargetVariableParameterName, new ItemSet<StringValue>()));
+      problemData.Parameters.Add(new FixedValueParameter<StringMatrix>(ClassNamesParameterName, "", new StringMatrix(0, 0).AsReadOnly()));
+      problemData.Parameters.Add(new FixedValueParameter<DoubleMatrix>(ClassificationPenaltiesParameterName, "", (DoubleMatrix)new DoubleMatrix(0, 0).AsReadOnly()));
+      emptyProblemData = problemData;
+    }
+    #endregion
+
+    #region parameter properties
+    public IConstrainedValueParameter<StringValue> TargetVariableParameter {
+      get { return (IConstrainedValueParameter<StringValue>)Parameters[TargetVariableParameterName]; }
+    }
+    public IFixedValueParameter<StringMatrix> ClassNamesParameter {
+      get { return (IFixedValueParameter<StringMatrix>)Parameters[ClassNamesParameterName]; }
+    }
+    public IConstrainedValueParameter<StringValue> PositiveClassParameter {
+      get { return (IConstrainedValueParameter<StringValue>)Parameters[PositiveClassParameterName]; }
+    }
+    public IFixedValueParameter<DoubleMatrix> ClassificationPenaltiesParameter {
+      get { return (IFixedValueParameter<DoubleMatrix>)Parameters[ClassificationPenaltiesParameterName]; }
+    }
+    #endregion
+
+    #region properties
+    public string TargetVariable {
+      get { return TargetVariableParameter.Value.Value; }
+      set {
+        if (value == null) throw new ArgumentNullException("targetVariable", "The provided value for the targetVariable is null.");
+        if (value == TargetVariable) return;
+
+
+        var matchingParameterValue = TargetVariableParameter.ValidValues.FirstOrDefault(v => v.Value == value);
+        if (matchingParameterValue == null) throw new ArgumentException("The provided value is not valid as the targetVariable.", "targetVariable");
+        TargetVariableParameter.Value = matchingParameterValue;
+      }
+    }
+
+    private List<double> classValuesCache;
+    private List<double> ClassValuesCache {
+      get {
+        if (classValuesCache == null) {
+          classValuesCache = Dataset.GetDoubleValues(TargetVariableParameter.Value.Value).Distinct().OrderBy(x => x).ToList();
+        }
+        return classValuesCache;
+      }
+    }
+    public IEnumerable<double> ClassValues {
+      get { return ClassValuesCache; }
+    }
+    public int Classes {
+      get { return ClassValuesCache.Count; }
+    }
+
+    private List<string> classNamesCache;
+    private List<string> ClassNamesCache {
+      get {
+        if (classNamesCache == null) {
+          classNamesCache = new List<string>();
+          for (int i = 0; i < ClassNamesParameter.Value.Rows; i++)
+            classNamesCache.Add(ClassNamesParameter.Value[i, 0]);
+        }
+        return classNamesCache;
+      }
+    }
+    public IEnumerable<string> ClassNames {
+      get { return ClassNamesCache; }
+    }
+
+    public string PositiveClass {
+      get { return PositiveClassParameter.Value.Value; }
+      set {
+        var matchingValue = PositiveClassParameter.ValidValues.SingleOrDefault(x => x.Value == value);
+        if (matchingValue == null) throw new ArgumentException(string.Format("{0} cannot be set as positive class.", value));
+        PositiveClassParameter.Value = matchingValue;
+      }
+    }
+    #endregion
+
+
+    [StorableConstructor]
+    protected ClassificationProblemData(bool deserializing) : base(deserializing) { }
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() {
+      RegisterParameterEvents();
+
+      classNamesCache = new List<string>();
+      for (int i = 0; i < ClassNamesParameter.Value.Rows; i++)
+        classNamesCache.Add(ClassNamesParameter.Value[i, 0]);
+
+      // BackwardsCompatibility3.4
+      #region Backwards compatible code, remove with 3.5
+      if (!Parameters.ContainsKey(PositiveClassParameterName)) {
+        var validValues = new ItemSet<StringValue>(ClassNames.Select(s => new StringValue(s).AsReadOnly()));
+        Parameters.Add(new ConstrainedValueParameter<StringValue>(PositiveClassParameterName,
+          "The positive class which is used for quality measure calculation (e.g., specifity, sensitivity,...)", validValues, validValues.First()));
+      }
+      #endregion
+
+    }
+
+    protected ClassificationProblemData(ClassificationProblemData original, Cloner cloner)
+      : base(original, cloner) {
+      RegisterParameterEvents();
+      classNamesCache = new List<string>();
+      for (int i = 0; i < ClassNamesParameter.Value.Rows; i++)
+        classNamesCache.Add(ClassNamesParameter.Value[i, 0]);
+    }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      if (this == emptyProblemData) return emptyProblemData;
+      return new ClassificationProblemData(this, cloner);
+    }
+
+    public ClassificationProblemData() : this(defaultDataset, defaultAllowedInputVariables, defaultTargetVariable) { }
+
+    public ClassificationProblemData(IClassificationProblemData classificationProblemData)
+      : this(classificationProblemData.Dataset, classificationProblemData.AllowedInputVariables, classificationProblemData.TargetVariable) {
+      TrainingPartition.Start = classificationProblemData.TrainingPartition.Start;
+      TrainingPartition.End = classificationProblemData.TrainingPartition.End;
+      TestPartition.Start = classificationProblemData.TestPartition.Start;
+      TestPartition.End = classificationProblemData.TestPartition.End;
+
+      PositiveClass = classificationProblemData.PositiveClass;
+
+      for (int i = 0; i < classificationProblemData.ClassNames.Count(); i++)
+        ClassNamesParameter.Value[i, 0] = classificationProblemData.ClassNames.ElementAt(i);
+
+      for (int i = 0; i < Classes; i++) {
+        for (int j = 0; j < Classes; j++) {
+          ClassificationPenaltiesParameter.Value[i, j] = classificationProblemData.GetClassificationPenalty(ClassValuesCache[i], ClassValuesCache[j]);
+        }
+      }
+    }
+
+    public ClassificationProblemData(IDataset dataset, IEnumerable<string> allowedInputVariables, string targetVariable, IEnumerable<ITransformation> transformations = null)
+      : base(dataset, allowedInputVariables, transformations ?? Enumerable.Empty<ITransformation>()) {
+      var validTargetVariableValues = CheckVariablesForPossibleTargetVariables(dataset).Select(x => new StringValue(x).AsReadOnly()).ToList();
+      var target = validTargetVariableValues.Where(x => x.Value == targetVariable).DefaultIfEmpty(validTargetVariableValues.First()).First();
+
+      Parameters.Add(new ConstrainedValueParameter<StringValue>(TargetVariableParameterName, new ItemSet<StringValue>(validTargetVariableValues), target));
+      Parameters.Add(new FixedValueParameter<StringMatrix>(ClassNamesParameterName, ""));
+      Parameters.Add(new ConstrainedValueParameter<StringValue>(PositiveClassParameterName, "The positive class which is used for quality measure calculation (e.g., specifity, sensitivity,...)"));
+      Parameters.Add(new FixedValueParameter<DoubleMatrix>(ClassificationPenaltiesParameterName, ""));
+
+      RegisterParameterEvents();
+      ResetTargetVariableDependentMembers();
+    }
+
+    public static IEnumerable<string> CheckVariablesForPossibleTargetVariables(IDataset dataset) {
+      int maxSamples = Math.Min(InspectedRowsToDetermineTargets, dataset.Rows);
+      var validTargetVariables = (from v in dataset.DoubleVariables
+                                  let distinctValues = dataset.GetDoubleValues(v)
+                                    .Take(maxSamples)
+                                    .Distinct()
+                                    .Count()
+                                  where distinctValues <= MaximumNumberOfClasses
+                                  select v).ToArray();
+
+      if (!validTargetVariables.Any())
+        throw new ArgumentException("Import of classification problem data was not successful, because no target variable was found." +
+          " A target variable must have at most " + MaximumNumberOfClasses + " distinct values to be applicable to classification.");
+      return validTargetVariables;
+    }
+
+
+    private void ResetTargetVariableDependentMembers() {
+      DeregisterParameterEvents();
+
+      ((IStringConvertibleMatrix)ClassNamesParameter.Value).Columns = 1;
+      ((IStringConvertibleMatrix)ClassNamesParameter.Value).Rows = ClassValuesCache.Count;
+      for (int i = 0; i < Classes; i++)
+        ClassNamesParameter.Value[i, 0] = "Class " + ClassValuesCache[i];
+      ClassNamesParameter.Value.ColumnNames = new List<string>() { "ClassNames" };
+      ClassNamesParameter.Value.RowNames = ClassValues.Select(s => "ClassValue: " + s);
+
+      PositiveClassParameter.ValidValues.Clear();
+      foreach (var className in ClassNames) {
+        PositiveClassParameter.ValidValues.Add(new StringValue(className).AsReadOnly());
+      }
+
+      ((IStringConvertibleMatrix)ClassificationPenaltiesParameter.Value).Rows = Classes;
+      ((IStringConvertibleMatrix)ClassificationPenaltiesParameter.Value).Columns = Classes;
+      ClassificationPenaltiesParameter.Value.RowNames = ClassNames.Select(name => "Actual " + name);
+      ClassificationPenaltiesParameter.Value.ColumnNames = ClassNames.Select(name => "Estimated " + name);
+      for (int i = 0; i < Classes; i++) {
+        for (int j = 0; j < Classes; j++) {
+          if (i != j) ClassificationPenaltiesParameter.Value[i, j] = 1;
+          else ClassificationPenaltiesParameter.Value[i, j] = 0;
+        }
+      }
+      RegisterParameterEvents();
+    }
+
+    public string GetClassName(double classValue) {
+      if (!ClassValuesCache.Contains(classValue)) throw new ArgumentException();
+      int index = ClassValuesCache.IndexOf(classValue);
+      return ClassNamesCache[index];
+    }
+    public double GetClassValue(string className) {
+      if (!ClassNamesCache.Contains(className)) throw new ArgumentException();
+      int index = ClassNamesCache.IndexOf(className);
+      return ClassValuesCache[index];
+    }
+    public void SetClassName(double classValue, string className) {
+      if (!ClassValuesCache.Contains(classValue)) throw new ArgumentException();
+      int index = ClassValuesCache.IndexOf(classValue);
+      ClassNamesParameter.Value[index, 0] = className;
+      // updating of class names cache is not necessary here as the parameter value fires a changed event which updates the cache
+    }
+
+    public double GetClassificationPenalty(string correctClassName, string estimatedClassName) {
+      return GetClassificationPenalty(GetClassValue(correctClassName), GetClassValue(estimatedClassName));
+    }
+    public double GetClassificationPenalty(double correctClassValue, double estimatedClassValue) {
+      int correctClassIndex = ClassValuesCache.IndexOf(correctClassValue);
+      int estimatedClassIndex = ClassValuesCache.IndexOf(estimatedClassValue);
+      return ClassificationPenaltiesParameter.Value[correctClassIndex, estimatedClassIndex];
+    }
+    public void SetClassificationPenalty(string correctClassName, string estimatedClassName, double penalty) {
+      SetClassificationPenalty(GetClassValue(correctClassName), GetClassValue(estimatedClassName), penalty);
+    }
+    public void SetClassificationPenalty(double correctClassValue, double estimatedClassValue, double penalty) {
+      int correctClassIndex = ClassValuesCache.IndexOf(correctClassValue);
+      int estimatedClassIndex = ClassValuesCache.IndexOf(estimatedClassValue);
+
+      ClassificationPenaltiesParameter.Value[correctClassIndex, estimatedClassIndex] = penalty;
+    }
+
+    #region events
+    private void RegisterParameterEvents() {
+      TargetVariableParameter.ValueChanged += new EventHandler(TargetVariableParameter_ValueChanged);
+      ClassNamesParameter.Value.Reset += new EventHandler(Parameter_ValueChanged);
+      ClassNamesParameter.Value.ItemChanged += new EventHandler<EventArgs<int, int>>(Parameter_ValueChanged);
+      ClassificationPenaltiesParameter.Value.ItemChanged += new EventHandler<EventArgs<int, int>>(Parameter_ValueChanged);
+      ClassificationPenaltiesParameter.Value.Reset += new EventHandler(Parameter_ValueChanged);
+    }
+    private void DeregisterParameterEvents() {
+      TargetVariableParameter.ValueChanged -= new EventHandler(TargetVariableParameter_ValueChanged);
+      ClassNamesParameter.Value.Reset -= new EventHandler(Parameter_ValueChanged);
+      ClassNamesParameter.Value.ItemChanged -= new EventHandler<EventArgs<int, int>>(Parameter_ValueChanged);
+      ClassificationPenaltiesParameter.Value.ItemChanged -= new EventHandler<EventArgs<int, int>>(Parameter_ValueChanged);
+      ClassificationPenaltiesParameter.Value.Reset -= new EventHandler(Parameter_ValueChanged);
+    }
+
+    private void TargetVariableParameter_ValueChanged(object sender, EventArgs e) {
+      classValuesCache = null;
+      classNamesCache = null;
+      ResetTargetVariableDependentMembers();
+      OnChanged();
+    }
+    private void Parameter_ValueChanged(object sender, EventArgs e) {
+      var oldPositiveClass = PositiveClass;
+      var oldClassNames = classNamesCache;
+      var index = oldClassNames.IndexOf(oldPositiveClass);
+
+      classNamesCache = null;
+      ClassificationPenaltiesParameter.Value.RowNames = ClassNames.Select(name => "Actual " + name);
+      ClassificationPenaltiesParameter.Value.ColumnNames = ClassNames.Select(name => "Estimated " + name);
+
+      PositiveClassParameter.ValidValues.Clear();
+      foreach (var className in ClassNames) {
+        PositiveClassParameter.ValidValues.Add(new StringValue(className).AsReadOnly());
+      }
+      PositiveClassParameter.Value = PositiveClassParameter.ValidValues.ElementAt(index);
+
+      OnChanged();
+    }
+    #endregion
+
+    protected override bool IsProblemDataCompatible(IDataAnalysisProblemData problemData, out string errorMessage) {
+      if (problemData == null) throw new ArgumentNullException("problemData", "The provided problemData is null.");
+      IClassificationProblemData classificationProblemData = problemData as IClassificationProblemData;
+      if (classificationProblemData == null)
+        throw new ArgumentException("The problem data is no classification problem data. Instead a " + problemData.GetType().GetPrettyName() + " was provided.", "problemData");
+
+      var returnValue = base.IsProblemDataCompatible(classificationProblemData, out errorMessage);
+      //check targetVariable
+      if (classificationProblemData.InputVariables.All(var => var.Value != TargetVariable)) {
+        errorMessage = string.Format("The target variable {0} is not present in the new problem data.", TargetVariable)
+                       + Environment.NewLine + errorMessage;
+        return false;
+      }
+
+      var newClassValues = classificationProblemData.Dataset.GetDoubleValues(TargetVariable).Distinct().OrderBy(x => x);
+      if (!newClassValues.SequenceEqual(ClassValues)) {
+        errorMessage = errorMessage + string.Format("The class values differ in the provided classification problem data.");
+        returnValue = false;
+      }
+
+      var newPositivieClassName = classificationProblemData.PositiveClass;
+      if (newPositivieClassName != PositiveClass) {
+        errorMessage = errorMessage + string.Format("The positive class differs in the provided classification problem data.");
+        returnValue = false;
+      }
+
+      return returnValue;
+    }
+
+    public override void AdjustProblemDataProperties(IDataAnalysisProblemData problemData) {
+      if (problemData == null) throw new ArgumentNullException("problemData", "The provided problemData is null.");
+      ClassificationProblemData classificationProblemData = problemData as ClassificationProblemData;
+      if (classificationProblemData == null)
+        throw new ArgumentException("The problem data is not a classification problem data. Instead a " + problemData.GetType().GetPrettyName() + " was provided.", "problemData");
+
+      base.AdjustProblemDataProperties(problemData);
+      TargetVariable = classificationProblemData.TargetVariable;
+      for (int i = 0; i < classificationProblemData.ClassNames.Count(); i++)
+        ClassNamesParameter.Value[i, 0] = classificationProblemData.ClassNames.ElementAt(i);
+
+      PositiveClass = classificationProblemData.PositiveClass;
+
+      for (int i = 0; i < Classes; i++) {
+        for (int j = 0; j < Classes; j++) {
+          ClassificationPenaltiesParameter.Value[i, j] = classificationProblemData.GetClassificationPenalty(ClassValuesCache[i], ClassValuesCache[j]);
+        }
+      }
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ClassificationSolution.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ClassificationSolution.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ClassificationSolution.cs	(revision 13819)
@@ -0,0 +1,86 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  /// <summary>
+  /// Represents a classification data analysis solution
+  /// </summary>
+  [StorableClass]
+  public class ClassificationSolution : ClassificationSolutionBase {
+    protected readonly Dictionary<int, double> evaluationCache;
+
+    [StorableConstructor]
+    protected ClassificationSolution(bool deserializing)
+      : base(deserializing) {
+      evaluationCache = new Dictionary<int, double>();
+    }
+    protected ClassificationSolution(ClassificationSolution original, Cloner cloner)
+      : base(original, cloner) {
+      evaluationCache = new Dictionary<int, double>(original.evaluationCache);
+    }
+    public ClassificationSolution(IClassificationModel model, IClassificationProblemData problemData)
+      : base(model, problemData) {
+      evaluationCache = new Dictionary<int, double>(problemData.Dataset.Rows);
+      CalculateClassificationResults();
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new ClassificationSolution(this, cloner);
+    }
+
+    public override IEnumerable<double> EstimatedClassValues {
+      get { return GetEstimatedClassValues(Enumerable.Range(0, ProblemData.Dataset.Rows)); }
+    }
+    public override IEnumerable<double> EstimatedTrainingClassValues {
+      get { return GetEstimatedClassValues(ProblemData.TrainingIndices); }
+    }
+    public override IEnumerable<double> EstimatedTestClassValues {
+      get { return GetEstimatedClassValues(ProblemData.TestIndices); }
+    }
+
+    public override IEnumerable<double> GetEstimatedClassValues(IEnumerable<int> rows) {
+      var rowsToEvaluate = rows.Except(evaluationCache.Keys);
+      var rowsEnumerator = rowsToEvaluate.GetEnumerator();
+      var valuesEnumerator = Model.GetEstimatedClassValues(ProblemData.Dataset, rowsToEvaluate).GetEnumerator();
+
+      while (rowsEnumerator.MoveNext() & valuesEnumerator.MoveNext()) {
+        evaluationCache.Add(rowsEnumerator.Current, valuesEnumerator.Current);
+      }
+
+      return rows.Select(row => evaluationCache[row]);
+    }
+
+    protected override void OnProblemDataChanged() {
+      evaluationCache.Clear();
+      base.OnProblemDataChanged();
+    }
+
+    protected override void OnModelChanged() {
+      evaluationCache.Clear();
+      base.OnModelChanged();
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ClassificationSolutionBase.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ClassificationSolutionBase.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ClassificationSolutionBase.cs	(revision 13819)
@@ -0,0 +1,164 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Data;
+using HeuristicLab.Optimization;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Problems.DataAnalysis.OnlineCalculators;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  [StorableClass]
+  public abstract class ClassificationSolutionBase : DataAnalysisSolution, IClassificationSolution {
+    private const string TrainingAccuracyResultName = "Accuracy (training)";
+    private const string TestAccuracyResultName = "Accuracy (test)";
+    private const string TrainingNormalizedGiniCoefficientResultName = "Normalized Gini Coefficient (training)";
+    private const string TestNormalizedGiniCoefficientResultName = "Normalized Gini Coefficient (test)";
+    private const string ClassificationPerformanceMeasuresResultName = "Classification Performance Measures";
+
+    public new IClassificationModel Model {
+      get { return (IClassificationModel)base.Model; }
+      protected set { base.Model = value; }
+    }
+
+    public new IClassificationProblemData ProblemData {
+      get { return (IClassificationProblemData)base.ProblemData; }
+      set { base.ProblemData = value; }
+    }
+
+    #region Results
+    public double TrainingAccuracy {
+      get { return ((DoubleValue)this[TrainingAccuracyResultName].Value).Value; }
+      private set { ((DoubleValue)this[TrainingAccuracyResultName].Value).Value = value; }
+    }
+    public double TestAccuracy {
+      get { return ((DoubleValue)this[TestAccuracyResultName].Value).Value; }
+      private set { ((DoubleValue)this[TestAccuracyResultName].Value).Value = value; }
+    }
+    public double TrainingNormalizedGiniCoefficient {
+      get { return ((DoubleValue)this[TrainingNormalizedGiniCoefficientResultName].Value).Value; }
+      protected set { ((DoubleValue)this[TrainingNormalizedGiniCoefficientResultName].Value).Value = value; }
+    }
+    public double TestNormalizedGiniCoefficient {
+      get { return ((DoubleValue)this[TestNormalizedGiniCoefficientResultName].Value).Value; }
+      protected set { ((DoubleValue)this[TestNormalizedGiniCoefficientResultName].Value).Value = value; }
+    }
+    public ClassificationPerformanceMeasuresResultCollection ClassificationPerformanceMeasures {
+      get { return ((ClassificationPerformanceMeasuresResultCollection)this[ClassificationPerformanceMeasuresResultName].Value); }
+      protected set { (this[ClassificationPerformanceMeasuresResultName].Value) = value; }
+    }
+    #endregion
+
+    [StorableConstructor]
+    protected ClassificationSolutionBase(bool deserializing) : base(deserializing) { }
+    protected ClassificationSolutionBase(ClassificationSolutionBase original, Cloner cloner)
+      : base(original, cloner) {
+    }
+    protected ClassificationSolutionBase(IClassificationModel model, IClassificationProblemData problemData)
+      : base(model, problemData) {
+      Add(new Result(TrainingAccuracyResultName, "Accuracy of the model on the training partition (percentage of correctly classified instances).", new PercentValue()));
+      Add(new Result(TestAccuracyResultName, "Accuracy of the model on the test partition (percentage of correctly classified instances).", new PercentValue()));
+      Add(new Result(TrainingNormalizedGiniCoefficientResultName, "Normalized Gini coefficient of the model on the training partition.", new DoubleValue()));
+      Add(new Result(TestNormalizedGiniCoefficientResultName, "Normalized Gini coefficient of the model on the test partition.", new DoubleValue()));
+      Add(new Result(ClassificationPerformanceMeasuresResultName, @"Classification performance measures.\n
+                              In a multiclass classification all misclassifications of the negative class will be treated as true negatives except on positive class estimations.",
+                            new ClassificationPerformanceMeasuresResultCollection()));
+    }
+
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() {
+      if (!this.ContainsKey(TrainingNormalizedGiniCoefficientResultName))
+        Add(new Result(TrainingNormalizedGiniCoefficientResultName, "Normalized Gini coefficient of the model on the training partition.", new DoubleValue()));
+      if (!this.ContainsKey(TestNormalizedGiniCoefficientResultName))
+        Add(new Result(TestNormalizedGiniCoefficientResultName, "Normalized Gini coefficient of the model on the test partition.", new DoubleValue()));
+      if (!this.ContainsKey(ClassificationPerformanceMeasuresResultName)) {
+        Add(new Result(ClassificationPerformanceMeasuresResultName, @"Classification performance measures.\n
+                              In a multiclass classification all misclassifications of the negative class will be treated as true negatives except on positive class estimations.",
+                              new ClassificationPerformanceMeasuresResultCollection()));
+        CalculateClassificationResults();
+      }
+    }
+
+    protected void CalculateClassificationResults() {
+      double[] estimatedTrainingClassValues = EstimatedTrainingClassValues.ToArray(); // cache values
+      double[] originalTrainingClassValues = ProblemData.Dataset.GetDoubleValues(ProblemData.TargetVariable, ProblemData.TrainingIndices).ToArray();
+
+      double[] estimatedTestClassValues = EstimatedTestClassValues.ToArray(); // cache values
+      double[] originalTestClassValues = ProblemData.Dataset.GetDoubleValues(ProblemData.TargetVariable, ProblemData.TestIndices).ToArray();
+
+      var positiveClassName = ProblemData.PositiveClass;
+      double positiveClassValue = ProblemData.GetClassValue(positiveClassName);
+      ClassificationPerformanceMeasuresCalculator trainingPerformanceCalculator = new ClassificationPerformanceMeasuresCalculator(positiveClassName, positiveClassValue);
+      ClassificationPerformanceMeasuresCalculator testPerformanceCalculator = new ClassificationPerformanceMeasuresCalculator(positiveClassName, positiveClassValue);
+
+      OnlineCalculatorError errorState;
+      double trainingAccuracy = OnlineAccuracyCalculator.Calculate(originalTrainingClassValues, estimatedTrainingClassValues, out errorState);
+      if (errorState != OnlineCalculatorError.None) trainingAccuracy = double.NaN;
+      double testAccuracy = OnlineAccuracyCalculator.Calculate(originalTestClassValues, estimatedTestClassValues, out errorState);
+      if (errorState != OnlineCalculatorError.None) testAccuracy = double.NaN;
+
+      TrainingAccuracy = trainingAccuracy;
+      TestAccuracy = testAccuracy;
+
+      double trainingNormalizedGini = NormalizedGiniCalculator.Calculate(originalTrainingClassValues, estimatedTrainingClassValues, out errorState);
+      if (errorState != OnlineCalculatorError.None) trainingNormalizedGini = double.NaN;
+      double testNormalizedGini = NormalizedGiniCalculator.Calculate(originalTestClassValues, estimatedTestClassValues, out errorState);
+      if (errorState != OnlineCalculatorError.None) testNormalizedGini = double.NaN;
+
+      TrainingNormalizedGiniCoefficient = trainingNormalizedGini;
+      TestNormalizedGiniCoefficient = testNormalizedGini;
+
+      ClassificationPerformanceMeasures.Reset();
+
+      trainingPerformanceCalculator.Calculate(originalTrainingClassValues, estimatedTrainingClassValues);
+      if (trainingPerformanceCalculator.ErrorState == OnlineCalculatorError.None)
+        ClassificationPerformanceMeasures.SetTrainingResults(trainingPerformanceCalculator);
+
+      testPerformanceCalculator.Calculate(originalTestClassValues, estimatedTestClassValues);
+      if (testPerformanceCalculator.ErrorState == OnlineCalculatorError.None)
+        ClassificationPerformanceMeasures.SetTestResults(testPerformanceCalculator);
+
+      if (ProblemData.Classes == 2) {
+        var f1Training = FOneScoreCalculator.Calculate(originalTrainingClassValues, estimatedTrainingClassValues, out errorState);
+        if (errorState == OnlineCalculatorError.None) ClassificationPerformanceMeasures.TrainingF1Score = f1Training;
+        var f1Test = FOneScoreCalculator.Calculate(originalTestClassValues, estimatedTestClassValues, out errorState);
+        if (errorState == OnlineCalculatorError.None) ClassificationPerformanceMeasures.TestF1Score = f1Test;
+      }
+
+      var mccTraining = MatthewsCorrelationCoefficientCalculator.Calculate(originalTrainingClassValues, estimatedTrainingClassValues, out errorState);
+      if (errorState == OnlineCalculatorError.None) ClassificationPerformanceMeasures.TrainingMatthewsCorrelation = mccTraining;
+      var mccTest = MatthewsCorrelationCoefficientCalculator.Calculate(originalTestClassValues, estimatedTestClassValues, out errorState);
+      if (errorState == OnlineCalculatorError.None) ClassificationPerformanceMeasures.TestMatthewsCorrelation = mccTest;
+    }
+
+    public abstract IEnumerable<double> EstimatedClassValues { get; }
+    public abstract IEnumerable<double> EstimatedTrainingClassValues { get; }
+    public abstract IEnumerable<double> EstimatedTestClassValues { get; }
+
+    public abstract IEnumerable<double> GetEstimatedClassValues(IEnumerable<int> rows);
+
+    protected override void RecalculateResults() {
+      CalculateClassificationResults();
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ConstantClassificationSolution.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ConstantClassificationSolution.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ConstantClassificationSolution.cs	(revision 13819)
@@ -0,0 +1,47 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  [StorableClass]
+  [Item(Name = "Constant Classification Solution", Description = "Represents a constant classification solution (model + data).")]
+  public class ConstantClassificationSolution : ClassificationSolution {
+    public new ConstantModel Model {
+      get { return (ConstantModel)base.Model; }
+      set { base.Model = value; }
+    }
+
+    [StorableConstructor]
+    protected ConstantClassificationSolution(bool deserializing) : base(deserializing) { }
+    protected ConstantClassificationSolution(ConstantClassificationSolution original, Cloner cloner) : base(original, cloner) { }
+    public ConstantClassificationSolution(ConstantModel model, IClassificationProblemData problemData)
+      : base(model, problemData) {
+      RecalculateResults();
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new ConstantClassificationSolution(this, cloner);
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/DiscriminantFunctionClassificationModel.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/DiscriminantFunctionClassificationModel.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/DiscriminantFunctionClassificationModel.cs	(revision 13819)
@@ -0,0 +1,145 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  /// <summary>
+  /// Represents discriminant function classification data analysis models.
+  /// </summary>
+  [StorableClass]
+  [Item("DiscriminantFunctionClassificationModel", "Represents a classification model that uses a discriminant function and classification thresholds.")]
+  public class DiscriminantFunctionClassificationModel : NamedItem, IDiscriminantFunctionClassificationModel {
+    [Storable]
+    private IRegressionModel model;
+    public IRegressionModel Model {
+      get { return model; }
+      private set { model = value; }
+    }
+
+    [Storable]
+    private double[] classValues;
+    public IEnumerable<double> ClassValues {
+      get { return (double[])classValues.Clone(); }
+      private set { classValues = value.ToArray(); }
+    }
+
+    [Storable]
+    private double[] thresholds;
+    public IEnumerable<double> Thresholds {
+      get { return (IEnumerable<double>)thresholds.Clone(); }
+      private set { thresholds = value.ToArray(); }
+    }
+
+    private IDiscriminantFunctionThresholdCalculator thresholdCalculator;
+    [Storable]
+    public IDiscriminantFunctionThresholdCalculator ThresholdCalculator {
+      get { return thresholdCalculator; }
+      private set { thresholdCalculator = value; }
+    }
+
+
+    [StorableConstructor]
+    protected DiscriminantFunctionClassificationModel(bool deserializing) : base(deserializing) { }
+    protected DiscriminantFunctionClassificationModel(DiscriminantFunctionClassificationModel original, Cloner cloner)
+      : base(original, cloner) {
+      model = cloner.Clone(original.model);
+      classValues = (double[])original.classValues.Clone();
+      thresholds = (double[])original.thresholds.Clone();
+    }
+
+    public DiscriminantFunctionClassificationModel(IRegressionModel model, IDiscriminantFunctionThresholdCalculator thresholdCalculator)
+      : base() {
+      this.name = ItemName;
+      this.description = ItemDescription;
+      this.model = model;
+      this.classValues = new double[0];
+      this.thresholds = new double[0];
+      this.thresholdCalculator = thresholdCalculator;
+    }
+
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() {
+      if (ThresholdCalculator == null) ThresholdCalculator = new AccuracyMaximizationThresholdCalculator();
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new DiscriminantFunctionClassificationModel(this, cloner);
+    }
+
+    public void SetThresholdsAndClassValues(IEnumerable<double> thresholds, IEnumerable<double> classValues) {
+      var classValuesArr = classValues.ToArray();
+      var thresholdsArr = thresholds.ToArray();
+      if (thresholdsArr.Length != classValuesArr.Length) throw new ArgumentException();
+
+      this.classValues = classValuesArr;
+      this.thresholds = thresholdsArr;
+      OnThresholdsChanged(EventArgs.Empty);
+    }
+
+    public virtual void RecalculateModelParameters(IClassificationProblemData problemData, IEnumerable<int> rows) {
+      double[] classValues;
+      double[] thresholds;
+      var targetClassValues = problemData.Dataset.GetDoubleValues(problemData.TargetVariable, rows);
+      var estimatedTrainingValues = GetEstimatedValues(problemData.Dataset, rows);
+      thresholdCalculator.Calculate(problemData, estimatedTrainingValues, targetClassValues, out classValues, out thresholds);
+      SetThresholdsAndClassValues(thresholds, classValues);
+    }
+
+
+    public IEnumerable<double> GetEstimatedValues(IDataset dataset, IEnumerable<int> rows) {
+      return model.GetEstimatedValues(dataset, rows);
+    }
+
+    public IEnumerable<double> GetEstimatedClassValues(IDataset dataset, IEnumerable<int> rows) {
+      if (!Thresholds.Any() && !ClassValues.Any()) throw new ArgumentException("No thresholds and class values were set for the current classification model.");
+      foreach (var x in GetEstimatedValues(dataset, rows)) {
+        int classIndex = 0;
+        // find first threshold value which is larger than x => class index = threshold index + 1
+        for (int i = 0; i < thresholds.Length; i++) {
+          if (x > thresholds[i]) classIndex++;
+          else break;
+        }
+        yield return classValues.ElementAt(classIndex - 1);
+      }
+    }
+    #region events
+    public event EventHandler ThresholdsChanged;
+    protected virtual void OnThresholdsChanged(EventArgs e) {
+      var listener = ThresholdsChanged;
+      if (listener != null) listener(this, e);
+    }
+    #endregion
+
+    public virtual IDiscriminantFunctionClassificationSolution CreateDiscriminantFunctionClassificationSolution(IClassificationProblemData problemData) {
+      return new DiscriminantFunctionClassificationSolution(this, new ClassificationProblemData(problemData));
+    }
+
+    public virtual IClassificationSolution CreateClassificationSolution(IClassificationProblemData problemData) {
+      return CreateDiscriminantFunctionClassificationSolution(problemData);
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/DiscriminantFunctionClassificationSolution.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/DiscriminantFunctionClassificationSolution.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/DiscriminantFunctionClassificationSolution.cs	(revision 13819)
@@ -0,0 +1,121 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  /// <summary>
+  /// Represents a classification solution that uses a discriminant function and classification thresholds.
+  /// </summary>
+  [StorableClass]
+  [Item("DiscriminantFunctionClassificationSolution", "Represents a classification solution that uses a discriminant function and classification thresholds.")]
+  public class DiscriminantFunctionClassificationSolution : DiscriminantFunctionClassificationSolutionBase {
+    protected readonly Dictionary<int, double> valueEvaluationCache;
+    protected readonly Dictionary<int, double> classValueEvaluationCache;
+
+    [StorableConstructor]
+    protected DiscriminantFunctionClassificationSolution(bool deserializing)
+      : base(deserializing) {
+      valueEvaluationCache = new Dictionary<int, double>();
+      classValueEvaluationCache = new Dictionary<int, double>();
+    }
+    protected DiscriminantFunctionClassificationSolution(DiscriminantFunctionClassificationSolution original, Cloner cloner)
+      : base(original, cloner) {
+      valueEvaluationCache = new Dictionary<int, double>(original.valueEvaluationCache);
+      classValueEvaluationCache = new Dictionary<int, double>(original.classValueEvaluationCache);
+    }
+    public DiscriminantFunctionClassificationSolution(IDiscriminantFunctionClassificationModel model, IClassificationProblemData problemData)
+      : base(model, problemData) {
+      valueEvaluationCache = new Dictionary<int, double>();
+      classValueEvaluationCache = new Dictionary<int, double>();
+      CalculateRegressionResults();
+      CalculateClassificationResults();
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new DiscriminantFunctionClassificationSolution(this, cloner);
+    }
+
+    public override IEnumerable<double> EstimatedClassValues {
+      get { return GetEstimatedClassValues(Enumerable.Range(0, ProblemData.Dataset.Rows)); }
+    }
+    public override IEnumerable<double> EstimatedTrainingClassValues {
+      get { return GetEstimatedClassValues(ProblemData.TrainingIndices); }
+    }
+    public override IEnumerable<double> EstimatedTestClassValues {
+      get { return GetEstimatedClassValues(ProblemData.TestIndices); }
+    }
+
+    public override IEnumerable<double> GetEstimatedClassValues(IEnumerable<int> rows) {
+      var rowsToEvaluate = rows.Except(classValueEvaluationCache.Keys);
+      var rowsEnumerator = rowsToEvaluate.GetEnumerator();
+      var valuesEnumerator = Model.GetEstimatedClassValues(ProblemData.Dataset, rowsToEvaluate).GetEnumerator();
+
+      while (rowsEnumerator.MoveNext() & valuesEnumerator.MoveNext()) {
+        classValueEvaluationCache.Add(rowsEnumerator.Current, valuesEnumerator.Current);
+      }
+
+      return rows.Select(row => classValueEvaluationCache[row]);
+    }
+
+
+    public override IEnumerable<double> EstimatedValues {
+      get { return GetEstimatedValues(Enumerable.Range(0, ProblemData.Dataset.Rows)); }
+    }
+    public override IEnumerable<double> EstimatedTrainingValues {
+      get { return GetEstimatedValues(ProblemData.TrainingIndices); }
+    }
+    public override IEnumerable<double> EstimatedTestValues {
+      get { return GetEstimatedValues(ProblemData.TestIndices); }
+    }
+
+    public override IEnumerable<double> GetEstimatedValues(IEnumerable<int> rows) {
+      var rowsToEvaluate = rows.Except(valueEvaluationCache.Keys);
+      var rowsEnumerator = rowsToEvaluate.GetEnumerator();
+      var valuesEnumerator = Model.GetEstimatedValues(ProblemData.Dataset, rowsToEvaluate).GetEnumerator();
+
+      while (rowsEnumerator.MoveNext() & valuesEnumerator.MoveNext()) {
+        valueEvaluationCache.Add(rowsEnumerator.Current, valuesEnumerator.Current);
+      }
+
+      return rows.Select(row => valueEvaluationCache[row]);
+    }
+
+    protected override void OnModelChanged() {
+      valueEvaluationCache.Clear();
+      classValueEvaluationCache.Clear();
+      base.OnModelChanged();
+    }
+    protected override void OnModelThresholdsChanged(System.EventArgs e) {
+      classValueEvaluationCache.Clear();
+      base.OnModelThresholdsChanged(e);
+    }
+    protected override void OnProblemDataChanged() {
+      valueEvaluationCache.Clear();
+      classValueEvaluationCache.Clear();
+      base.OnProblemDataChanged();
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/DiscriminantFunctionClassificationSolutionBase.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/DiscriminantFunctionClassificationSolutionBase.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/DiscriminantFunctionClassificationSolutionBase.cs	(revision 13819)
@@ -0,0 +1,146 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Optimization;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  /// <summary>
+  /// Represents a classification solution that uses a discriminant function and classification thresholds.
+  /// </summary>
+  [StorableClass]
+  [Item("DiscriminantFunctionClassificationSolution", "Represents a classification solution that uses a discriminant function and classification thresholds.")]
+  public abstract class DiscriminantFunctionClassificationSolutionBase : ClassificationSolutionBase, IDiscriminantFunctionClassificationSolution {
+    private const string TrainingMeanSquaredErrorResultName = "Mean squared error (training)";
+    private const string TestMeanSquaredErrorResultName = "Mean squared error (test)";
+    private const string TrainingRSquaredResultName = "Pearson's R² (training)";
+    private const string TestRSquaredResultName = "Pearson's R² (test)";
+
+    public new IDiscriminantFunctionClassificationModel Model {
+      get { return (IDiscriminantFunctionClassificationModel)base.Model; }
+      protected set {
+        if (value != null && value != Model) {
+          if (Model != null) {
+            Model.ThresholdsChanged -= new EventHandler(Model_ThresholdsChanged);
+          }
+          value.ThresholdsChanged += new EventHandler(Model_ThresholdsChanged);
+          base.Model = value;
+        }
+      }
+    }
+
+    #region Results
+    public double TrainingMeanSquaredError {
+      get { return ((DoubleValue)this[TrainingMeanSquaredErrorResultName].Value).Value; }
+      private set { ((DoubleValue)this[TrainingMeanSquaredErrorResultName].Value).Value = value; }
+    }
+    public double TestMeanSquaredError {
+      get { return ((DoubleValue)this[TestMeanSquaredErrorResultName].Value).Value; }
+      private set { ((DoubleValue)this[TestMeanSquaredErrorResultName].Value).Value = value; }
+    }
+    public double TrainingRSquared {
+      get { return ((DoubleValue)this[TrainingRSquaredResultName].Value).Value; }
+      private set { ((DoubleValue)this[TrainingRSquaredResultName].Value).Value = value; }
+    }
+    public double TestRSquared {
+      get { return ((DoubleValue)this[TestRSquaredResultName].Value).Value; }
+      private set { ((DoubleValue)this[TestRSquaredResultName].Value).Value = value; }
+    }
+    #endregion
+
+    [StorableConstructor]
+    protected DiscriminantFunctionClassificationSolutionBase(bool deserializing) : base(deserializing) { }
+    protected DiscriminantFunctionClassificationSolutionBase(DiscriminantFunctionClassificationSolutionBase original, Cloner cloner)
+      : base(original, cloner) {
+      RegisterEventHandler();
+    }
+    protected DiscriminantFunctionClassificationSolutionBase(IDiscriminantFunctionClassificationModel model, IClassificationProblemData problemData)
+      : base(model, problemData) {
+      Add(new Result(TrainingMeanSquaredErrorResultName, "Mean of squared errors of the model on the training partition", new DoubleValue()));
+      Add(new Result(TestMeanSquaredErrorResultName, "Mean of squared errors of the model on the test partition", new DoubleValue()));
+      Add(new Result(TrainingRSquaredResultName, "Squared Pearson's correlation coefficient of the model output and the actual values on the training partition", new DoubleValue()));
+      Add(new Result(TestRSquaredResultName, "Squared Pearson's correlation coefficient of the model output and the actual values on the test partition", new DoubleValue()));
+      RegisterEventHandler();
+    }
+
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() {
+      RegisterEventHandler();
+    }
+
+    protected void CalculateRegressionResults() {
+      double[] estimatedTrainingValues = EstimatedTrainingValues.ToArray(); // cache values
+      double[] originalTrainingValues = ProblemData.Dataset.GetDoubleValues(ProblemData.TargetVariable, ProblemData.TrainingIndices).ToArray();
+      double[] estimatedTestValues = EstimatedTestValues.ToArray(); // cache values
+      double[] originalTestValues = ProblemData.Dataset.GetDoubleValues(ProblemData.TargetVariable, ProblemData.TestIndices).ToArray();
+
+      OnlineCalculatorError errorState;
+      double trainingMSE = OnlineMeanSquaredErrorCalculator.Calculate(originalTrainingValues, estimatedTrainingValues, out errorState);
+      TrainingMeanSquaredError = errorState == OnlineCalculatorError.None ? trainingMSE : double.NaN;
+      double testMSE = OnlineMeanSquaredErrorCalculator.Calculate(originalTestValues, estimatedTestValues, out errorState);
+      TestMeanSquaredError = errorState == OnlineCalculatorError.None ? testMSE : double.NaN;
+
+      double trainingR = OnlinePearsonsRCalculator.Calculate(originalTrainingValues, estimatedTrainingValues, out errorState);
+      TrainingRSquared = errorState == OnlineCalculatorError.None ? trainingR*trainingR : double.NaN;
+      double testR = OnlinePearsonsRCalculator.Calculate(originalTestValues, estimatedTestValues, out errorState);
+      TestRSquared = errorState == OnlineCalculatorError.None ? testR*testR : double.NaN;
+
+      double trainingNormalizedGini = NormalizedGiniCalculator.Calculate(originalTrainingValues, estimatedTrainingValues, out errorState);
+      if (errorState != OnlineCalculatorError.None) trainingNormalizedGini = double.NaN;
+      double testNormalizedGini = NormalizedGiniCalculator.Calculate(originalTestValues, estimatedTestValues, out errorState);
+      if (errorState != OnlineCalculatorError.None) testNormalizedGini = double.NaN;
+
+      TrainingNormalizedGiniCoefficient = trainingNormalizedGini;
+      TestNormalizedGiniCoefficient = testNormalizedGini;
+    }
+
+    private void RegisterEventHandler() {
+      Model.ThresholdsChanged += new EventHandler(Model_ThresholdsChanged);
+    }
+    private void DeregisterEventHandler() {
+      Model.ThresholdsChanged -= new EventHandler(Model_ThresholdsChanged);
+    }
+    private void Model_ThresholdsChanged(object sender, EventArgs e) {
+      OnModelThresholdsChanged(e);
+    }
+
+    protected virtual void OnModelThresholdsChanged(EventArgs e) {
+      OnModelChanged();
+    }
+
+    public abstract IEnumerable<double> EstimatedValues { get; }
+    public abstract IEnumerable<double> EstimatedTrainingValues { get; }
+    public abstract IEnumerable<double> EstimatedTestValues { get; }
+
+    public abstract IEnumerable<double> GetEstimatedValues(IEnumerable<int> rows);
+
+    protected override void RecalculateResults() {
+      base.RecalculateResults();
+      CalculateRegressionResults();
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ThresholdCalculators/AccuracyMaximizationThresholdCalculator.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ThresholdCalculators/AccuracyMaximizationThresholdCalculator.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ThresholdCalculators/AccuracyMaximizationThresholdCalculator.cs	(revision 13819)
@@ -0,0 +1,133 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  /// <summary>
+  /// Represents a threshold calculator that maximizes the weighted accuracy of the classifcation model.
+  /// </summary>
+  [StorableClass]
+  [Item("AccuracyMaximizationThresholdCalculator", "Represents a threshold calculator that maximizes the weighted accuracy of the classifcation model.")]
+  public class AccuracyMaximizationThresholdCalculator : ThresholdCalculator {
+
+    [StorableConstructor]
+    protected AccuracyMaximizationThresholdCalculator(bool deserializing) : base(deserializing) { }
+    protected AccuracyMaximizationThresholdCalculator(AccuracyMaximizationThresholdCalculator original, Cloner cloner)
+      : base(original, cloner) {
+    }
+    public AccuracyMaximizationThresholdCalculator()
+      : base() {
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new AccuracyMaximizationThresholdCalculator(this, cloner);
+    }
+
+    public override void Calculate(IClassificationProblemData problemData, IEnumerable<double> estimatedValues, IEnumerable<double> targetClassValues, out double[] classValues, out double[] thresholds) {
+      AccuracyMaximizationThresholdCalculator.CalculateThresholds(problemData, estimatedValues, targetClassValues, out classValues, out thresholds);
+    }
+
+    public static void CalculateThresholds(IClassificationProblemData problemData, IEnumerable<double> estimatedValues, IEnumerable<double> targetClassValues, out double[] classValues, out double[] thresholds) {
+      const int slices = 100;
+      const double minThresholdInc = 10e-5; // necessary to prevent infinite loop when maxEstimated - minEstimated is effectively zero (constant model)
+      List<double> estimatedValuesList = estimatedValues.ToList();
+      double maxEstimatedValue = estimatedValuesList.Max();
+      double minEstimatedValue = estimatedValuesList.Min();
+      double thresholdIncrement = Math.Max((maxEstimatedValue - minEstimatedValue) / slices, minThresholdInc);
+      var estimatedAndTargetValuePairs =
+        estimatedValuesList.Zip(targetClassValues, (x, y) => new { EstimatedValue = x, TargetClassValue = y })
+        .OrderBy(x => x.EstimatedValue).ToList();
+
+      classValues = estimatedAndTargetValuePairs.GroupBy(x => x.TargetClassValue)
+        .Select(x => new { Median = x.Select(y => y.EstimatedValue).Median(), Class = x.Key })
+        .OrderBy(x => x.Median).Select(x => x.Class).ToArray();
+
+      int nClasses = classValues.Length;
+      thresholds = new double[nClasses];
+      thresholds[0] = double.NegativeInfinity;
+
+      // incrementally calculate accuracy of all possible thresholds
+      for (int i = 1; i < thresholds.Length; i++) {
+        double lowerThreshold = thresholds[i - 1];
+        double actualThreshold = Math.Max(lowerThreshold, minEstimatedValue);
+        double lowestBestThreshold = double.NaN;
+        double highestBestThreshold = double.NaN;
+        double bestClassificationScore = double.PositiveInfinity;
+        bool seriesOfEqualClassificationScores = false;
+
+        while (actualThreshold < maxEstimatedValue) {
+          double classificationScore = 0.0;
+
+          foreach (var pair in estimatedAndTargetValuePairs) {
+            //all positives
+            if (pair.TargetClassValue.IsAlmost(classValues[i - 1])) {
+              if (pair.EstimatedValue > lowerThreshold && pair.EstimatedValue <= actualThreshold)
+                //true positive
+                classificationScore += problemData.GetClassificationPenalty(pair.TargetClassValue, pair.TargetClassValue);
+              else
+                //false negative
+                classificationScore += problemData.GetClassificationPenalty(pair.TargetClassValue, classValues[i]);
+            }
+              //all negatives
+            else {
+              //false positive
+              if (pair.EstimatedValue > lowerThreshold && pair.EstimatedValue <= actualThreshold)
+                classificationScore += problemData.GetClassificationPenalty(pair.TargetClassValue, classValues[i - 1]);
+              else if (pair.EstimatedValue <= lowerThreshold)
+                classificationScore += problemData.GetClassificationPenalty(pair.TargetClassValue, classValues[i - 2]);
+              else if (pair.EstimatedValue > actualThreshold) {
+                if (pair.TargetClassValue < classValues[i - 1]) //negative in wrong class, consider upper class
+                  classificationScore += problemData.GetClassificationPenalty(pair.TargetClassValue, classValues[i]);
+                else //true negative, must be optimized by the other thresholds
+                  classificationScore += problemData.GetClassificationPenalty(pair.TargetClassValue, pair.TargetClassValue);
+              }
+            }
+          }
+
+          //new best classification score found
+          if (classificationScore < bestClassificationScore) {
+            bestClassificationScore = classificationScore;
+            lowestBestThreshold = actualThreshold;
+            highestBestThreshold = actualThreshold;
+            seriesOfEqualClassificationScores = true;
+          }
+            //equal classification scores => if seriesOfEqualClassifcationScores == true update highest threshold
+          else if (Math.Abs(classificationScore - bestClassificationScore) < double.Epsilon && seriesOfEqualClassificationScores)
+            highestBestThreshold = actualThreshold;
+          //worse classificatoin score found reset seriesOfEqualClassifcationScores
+          else seriesOfEqualClassificationScores = false;
+
+          actualThreshold += thresholdIncrement;
+        }
+        //scale lowest thresholds and highest found optimal threshold according to the misclassification matrix
+        double falseNegativePenalty = problemData.GetClassificationPenalty(classValues[i], classValues[i - 1]);
+        double falsePositivePenalty = problemData.GetClassificationPenalty(classValues[i - 1], classValues[i]);
+        thresholds[i] = (lowestBestThreshold * falsePositivePenalty + highestBestThreshold * falseNegativePenalty) / (falseNegativePenalty + falsePositivePenalty);
+      }
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ThresholdCalculators/NormalDistributionCutPointsThresholdCalculator.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ThresholdCalculators/NormalDistributionCutPointsThresholdCalculator.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ThresholdCalculators/NormalDistributionCutPointsThresholdCalculator.cs	(revision 13819)
@@ -0,0 +1,216 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  /// <summary>
+  /// Represents a threshold calculator that calculates thresholds as the cutting points between the estimated class distributions (assuming normally distributed class values).
+  /// </summary>
+  [StorableClass]
+  [Item("NormalDistributionCutPointsThresholdCalculator", "Represents a threshold calculator that calculates thresholds as the cutting points between the estimated class distributions (assuming normally distributed class values).")]
+  public class NormalDistributionCutPointsThresholdCalculator : ThresholdCalculator {
+
+    [StorableConstructor]
+    protected NormalDistributionCutPointsThresholdCalculator(bool deserializing) : base(deserializing) { }
+    protected NormalDistributionCutPointsThresholdCalculator(NormalDistributionCutPointsThresholdCalculator original, Cloner cloner)
+      : base(original, cloner) {
+    }
+    public NormalDistributionCutPointsThresholdCalculator()
+      : base() {
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new NormalDistributionCutPointsThresholdCalculator(this, cloner);
+    }
+
+    public override void Calculate(IClassificationProblemData problemData, IEnumerable<double> estimatedValues, IEnumerable<double> targetClassValues, out double[] classValues, out double[] thresholds) {
+      NormalDistributionCutPointsThresholdCalculator.CalculateThresholds(problemData, estimatedValues, targetClassValues, out classValues, out thresholds);
+    }
+
+    public static void CalculateThresholds(IClassificationProblemData problemData, IEnumerable<double> estimatedValues, IEnumerable<double> targetClassValues, out double[] classValues, out double[] thresholds) {
+      var estimatedTargetValues = Enumerable.Zip(estimatedValues, targetClassValues, (e, t) => new { EstimatedValue = e, TargetValue = t }).ToList();
+      double estimatedValuesRange = estimatedValues.Range();
+
+      Dictionary<double, double> classMean = new Dictionary<double, double>();
+      Dictionary<double, double> classStdDev = new Dictionary<double, double>();
+      // calculate moments per class
+      foreach (var group in estimatedTargetValues.GroupBy(p => p.TargetValue)) {
+        IEnumerable<double> estimatedClassValues = group.Select(x => x.EstimatedValue);
+        double classValue = group.Key;
+        double mean, variance;
+        OnlineCalculatorError meanErrorState, varianceErrorState;
+        OnlineMeanAndVarianceCalculator.Calculate(estimatedClassValues, out mean, out variance, out meanErrorState, out varianceErrorState);
+
+        if (meanErrorState == OnlineCalculatorError.None && varianceErrorState == OnlineCalculatorError.None) {
+          classMean[classValue] = mean;
+          classStdDev[classValue] = Math.Sqrt(variance);
+        }
+      }
+
+      double[] originalClasses = classMean.Keys.OrderBy(x => x).ToArray();
+      int nClasses = originalClasses.Length;
+      List<double> thresholdList = new List<double>();
+      for (int i = 0; i < nClasses - 1; i++) {
+        for (int j = i + 1; j < nClasses; j++) {
+          double x1, x2;
+          double class0 = originalClasses[i];
+          double class1 = originalClasses[j];
+          // calculate all thresholds
+          CalculateCutPoints(classMean[class0], classStdDev[class0], classMean[class1], classStdDev[class1], out x1, out x2);
+
+          // if the two cut points are too close (for instance because the stdDev=0)
+          // then move them by 0.1% of the range of estimated values
+          if (x1.IsAlmost(x2)) {
+            x1 -= 0.001 * estimatedValuesRange;
+            x2 += 0.001 * estimatedValuesRange;
+          }
+          if (!double.IsInfinity(x1) && !thresholdList.Any(x => x.IsAlmost(x1))) thresholdList.Add(x1);
+          if (!double.IsInfinity(x2) && !thresholdList.Any(x => x.IsAlmost(x2))) thresholdList.Add(x2);
+        }
+      }
+      thresholdList.Sort();
+
+      // add small value and large value for the calculation of most influential class in each thresholded section
+      thresholdList.Insert(0, double.NegativeInfinity);
+      thresholdList.Add(double.PositiveInfinity);
+
+
+      // find the most likely class for the points between thresholds m
+      List<double> filteredThresholds = new List<double>();
+      List<double> filteredClassValues = new List<double>();
+      for (int i = 0; i < thresholdList.Count - 1; i++) {
+        // determine class with maximal density mass between the thresholds
+        double maxDensity = DensityMass(thresholdList[i], thresholdList[i + 1], classMean[originalClasses[0]], classStdDev[originalClasses[0]]);
+        double maxDensityClassValue = originalClasses[0];
+        foreach (var classValue in originalClasses.Skip(1)) {
+          double density = DensityMass(thresholdList[i], thresholdList[i + 1], classMean[classValue], classStdDev[classValue]);
+          if (density > maxDensity) {
+            maxDensity = density;
+            maxDensityClassValue = classValue;
+          }
+        }
+        if (maxDensity > double.NegativeInfinity &&
+          (filteredClassValues.Count == 0 || !maxDensityClassValue.IsAlmost(filteredClassValues.Last()))) {
+          filteredThresholds.Add(thresholdList[i]);
+          filteredClassValues.Add(maxDensityClassValue);
+        }
+      }
+
+      if (filteredThresholds.Count == 0 || !double.IsNegativeInfinity(filteredThresholds.First())) {
+        // this happens if there are no thresholds (distributions for all classes are exactly the same)
+        // or when the CDF up to the first threshold is zero
+        // -> all samples should be classified as the class with the most observations
+        // group observations by target class and select the class with largest count 
+        double mostFrequentClass = targetClassValues.GroupBy(c => c)
+                              .OrderBy(g => g.Count())
+                              .Last().Key;
+        filteredThresholds.Insert(0, double.NegativeInfinity);
+        filteredClassValues.Insert(0, mostFrequentClass);
+      }
+
+      thresholds = filteredThresholds.ToArray();
+      classValues = filteredClassValues.ToArray();
+    }
+
+    private static double sqr2 = Math.Sqrt(2.0);
+    // returns the density function of the standard normal distribution at x
+    private static double NormalCDF(double x) {
+      return 0.5 * (1 + alglib.errorfunction(x / sqr2));
+    }
+
+    // approximation of the log of the normal cummulative distribution from the lightspeed toolbox by Tom Minka
+    // http://research.microsoft.com/en-us/um/people/minka/software/lightspeed/
+    private static double[] c = new double[] { -1, 5 / 2.0, -37 / 3.0, 353 / 4.0, -4081 / 5.0, 55205 / 6.0, -854197 / 7.0 };
+    private static double LogNormalCDF(double x) {
+      if (x >= -6.5)
+        // calculate the log directly if x is large enough
+        return Math.Log(NormalCDF(x));
+      else {
+        double z = Math.Pow(x, -2);
+        // asymptotic series for logcdf
+        double y = z * (c[0] + z * (c[1] + z * (c[2] + z * (c[3] + z * (c[4] + z * (c[5] + z * c[6]))))));
+        return y - 0.5 * Math.Log(2 * Math.PI) - 0.5 * x * x - Math.Log(-x);
+      }
+    }
+
+    // determines the value NormalCDF(mu,sigma, upper)  - NormalCDF(mu, sigma, lower)
+    // = the integral of the PDF of N(mu, sigma) in the range [lower, upper]
+    private static double DensityMass(double lower, double upper, double mu, double sigma) {
+      if (sigma.IsAlmost(0.0)) {
+        if (lower < mu && mu < upper) return 0.0; // all mass is between lower and upper
+        else return double.NegativeInfinity; // no mass is between lower and upper
+      }
+
+      if (lower > mu) {
+        return DensityMass(-upper, -lower, -mu, sigma);
+      }
+
+      upper = (upper - mu) / sigma;
+      lower = (lower - mu) / sigma;
+      if (double.IsNegativeInfinity(lower)) return LogNormalCDF(upper);
+
+      return LogNormalCDF(upper) + Math.Log(1 - Math.Exp(LogNormalCDF(lower) - LogNormalCDF(upper)));
+    }
+
+    // Calculates the points x1 and x2 where the distributions N(m1, s1) == N(m2,s2). 
+    // In the general case there should be two cut points. If either s1 or s2 is 0 then x1==x2. 
+    // If both s1 and s2 are zero than there are no cut points but we should return something reasonable (e.g. (m1 + m2) / 2) then.
+    private static void CalculateCutPoints(double m1, double s1, double m2, double s2, out double x1, out double x2) {
+      if (s1.IsAlmost(s2)) {
+        if (m1.IsAlmost(m2)) {
+          x1 = double.NegativeInfinity;
+          x2 = double.NegativeInfinity;
+        } else {
+          // s1==s2 and m1 != m2
+          // return something reasonable. cut point should be half way between m1 and m2
+          x1 = (m1 + m2) / 2;
+          x2 = double.NegativeInfinity;
+        }
+      } else if (s1.IsAlmost(0.0)) {
+        // when s1 is 0.0 the cut points are exactly at m1 ...
+        x1 = m1;
+        x2 = m1;
+      } else if (s2.IsAlmost(0.0)) {
+        // ... same for s2
+        x1 = m2;
+        x2 = m2;
+      } else {
+        if (s2 < s1) {
+          // make sure s2 is the larger std.dev.
+          CalculateCutPoints(m2, s2, m1, s1, out x1, out x2);
+        } else {
+          // general case
+          // calculate the solutions x1, x2 where N(m1,s1) == N(m2,s2)
+          double g = Math.Sqrt(2 * s2 * s2 * Math.Log(s2 / s1) - 2 * s1 * s1 * Math.Log(s2 / s1) - 2 * m1 * m2 + m1 * m1 + m2 * m2);
+          double s = (s1 * s1 - s2 * s2);
+          x1 = (m2 * s1 * s1 - m1 * s2 * s2 + s1 * s2 * g) / s;
+          x2 = -(m1 * s2 * s2 - m2 * s1 * s1 + s1 * s2 * g) / s;
+        }
+      }
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ThresholdCalculators/ThresholdCalculator.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ThresholdCalculators/ThresholdCalculator.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ThresholdCalculators/ThresholdCalculator.cs	(revision 13819)
@@ -0,0 +1,47 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Collections.Generic;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  /// <summary>
+  /// Base class for threshold calculators for discriminant function classification models.
+  /// </summary>
+  [StorableClass]
+  public abstract class ThresholdCalculator : NamedItem, IDiscriminantFunctionThresholdCalculator {
+
+    [StorableConstructor]
+    protected ThresholdCalculator(bool deserializing) : base(deserializing) { }
+    protected ThresholdCalculator(ThresholdCalculator original, Cloner cloner)
+      : base(original, cloner) {
+    }
+    public ThresholdCalculator()
+      : base() {
+      this.name = ItemName;
+      this.description = ItemDescription;
+    }
+
+    public abstract void Calculate(IClassificationProblemData problemData, IEnumerable<double> estimatedValues, IEnumerable<double> targetClassValues, out double[] classValues, out double[] thresholds);
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Clustering/ClusteringProblem.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Clustering/ClusteringProblem.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Clustering/ClusteringProblem.cs	(revision 13819)
@@ -0,0 +1,37 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  [StorableClass]
+  [Item("Clustering Problem", "A general clustering problem.")]
+  public class ClusteringProblem : DataAnalysisProblem<IClusteringProblemData>, IClusteringProblem {
+    [StorableConstructor]
+    protected ClusteringProblem(bool deserializing) : base(deserializing) { }
+    protected ClusteringProblem(ClusteringProblem original, Cloner cloner) : base(original, cloner) { }
+    public override IDeepCloneable Clone(Cloner cloner) { return new ClusteringProblem(this, cloner); }
+
+    public ClusteringProblem() : base(new ClusteringProblemData()) { }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Clustering/ClusteringProblemData.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Clustering/ClusteringProblemData.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Clustering/ClusteringProblemData.cs	(revision 13819)
@@ -0,0 +1,93 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  [StorableClass]
+  [Item("ClusteringProblemData", "Represents an item containing all data defining a clustering problem.")]
+  public sealed class ClusteringProblemData : DataAnalysisProblemData, IClusteringProblemData, IStorableContent {
+    public string Filename { get; set; }
+
+    #region default data
+    private static double[,] kozaF1 = new double[,] {
+          {2.017885919,	-1.449165046},
+          {1.30060506,	-1.344523885},
+          {1.147134798,	-1.317989331},
+          {0.877182504,	-1.266142284},
+          {0.852562452,	-1.261020794},
+          {0.431095788,	-1.158793317},
+          {0.112586002,	-1.050908405},
+          {0.04594507,	-1.021989402},
+          {0.042572879,	-1.020438113},
+          {-0.074027291,	-0.959859562},
+          {-0.109178553,	-0.938094706},
+          {-0.259721109,	-0.803635355},
+          {-0.272991057,	-0.387519561},
+          {-0.161978191,	-0.193611001},
+          {-0.102489983,	-0.114215349},
+          {-0.01469968,	-0.014918985},
+          {-0.008863365,	-0.008942626},
+          {0.026751057,	0.026054094},
+          {0.166922436,	0.14309643},
+          {0.176953808,	0.1504144},
+          {0.190233418,	0.159916534},
+          {0.199800708,	0.166635331},
+          {0.261502822,	0.207600348},
+          {0.30182879,	0.232370249},
+          {0.83763905,	0.468046718}
+    };
+    private static Dataset defaultDataset;
+    private static IEnumerable<string> defaultAllowedInputVariables;
+
+    static ClusteringProblemData() {
+      defaultDataset = new Dataset(new string[] { "y", "x" }, kozaF1);
+      defaultDataset.Name = "Fourth-order Polynomial Function Benchmark Dataset";
+      defaultDataset.Description = "f(x) = x^4 + x^3 + x^2 + x^1";
+      defaultAllowedInputVariables = new List<string>() { "x", "y" };
+    }
+    #endregion
+
+    [StorableConstructor]
+    private ClusteringProblemData(bool deserializing) : base(deserializing) { }
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() {
+    }
+
+
+    private ClusteringProblemData(ClusteringProblemData original, Cloner cloner)
+      : base(original, cloner) {
+    }
+    public override IDeepCloneable Clone(Cloner cloner) { return new ClusteringProblemData(this, cloner); }
+
+    public ClusteringProblemData()
+      : this(defaultDataset, defaultAllowedInputVariables) {
+    }
+
+    public ClusteringProblemData(Dataset dataset, IEnumerable<string> allowedInputVariables, IEnumerable<ITransformation> transformations = null)
+      : base(dataset, allowedInputVariables, transformations ?? Enumerable.Empty<ITransformation>()) {
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Clustering/ClusteringSolution.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Clustering/ClusteringSolution.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Clustering/ClusteringSolution.cs	(revision 13819)
@@ -0,0 +1,85 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  /// <summary>
+  /// Represents a clustering data analysis solution
+  /// </summary>
+  [StorableClass]
+  public class ClusteringSolution : DataAnalysisSolution, IClusteringSolution {
+
+    [StorableConstructor]
+    protected ClusteringSolution(bool deserializing) : base(deserializing) { }
+    protected ClusteringSolution(ClusteringSolution original, Cloner cloner)
+      : base(original, cloner) {
+    }
+    public ClusteringSolution(IClusteringModel model, IClusteringProblemData problemData)
+      : base(model, problemData) {
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new ClusteringSolution(this, cloner);
+    }
+
+    protected override void RecalculateResults() {
+    }
+
+    #region IClusteringSolution Members
+
+    public new IClusteringModel Model {
+      get { return (IClusteringModel)base.Model; }
+      set { base.Model = value; }
+    }
+
+    public new IClusteringProblemData ProblemData {
+      get { return (IClusteringProblemData)base.ProblemData; }
+      set { base.ProblemData = value; }
+    }
+
+    public virtual IEnumerable<int> ClusterValues {
+      get {
+        return GetClusterValues(Enumerable.Range(0, ProblemData.Dataset.Rows));
+      }
+    }
+
+    public virtual IEnumerable<int> TrainingClusterValues {
+      get {
+        return GetClusterValues(ProblemData.TrainingIndices);
+      }
+    }
+
+    public virtual IEnumerable<int> TestClusterValues {
+      get {
+        return GetClusterValues(ProblemData.TestIndices);
+      }
+    }
+
+    public virtual IEnumerable<int> GetClusterValues(IEnumerable<int> rows) {
+      return Model.GetClusterValues(ProblemData.Dataset, rows);
+    }
+    #endregion
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/ConstantModel.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/ConstantModel.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/ConstantModel.cs	(revision 13819)
@@ -0,0 +1,99 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  [StorableClass]
+  [Item("Constant Model", "A model that always returns the same constant value regardless of the presented input data.")]
+  public class ConstantModel : NamedItem, IRegressionModel, IClassificationModel, ITimeSeriesPrognosisModel, IStringConvertibleValue {
+    [Storable]
+    private double constant;
+    public double Constant {
+      get { return constant; }
+      // setter not implemented because manipulation of the constant is not allowed
+    }
+
+    [StorableConstructor]
+    protected ConstantModel(bool deserializing) : base(deserializing) { }
+    protected ConstantModel(ConstantModel original, Cloner cloner)
+      : base(original, cloner) {
+      this.constant = original.constant;
+    }
+    public override IDeepCloneable Clone(Cloner cloner) { return new ConstantModel(this, cloner); }
+
+    public ConstantModel(double constant)
+      : base() {
+      this.name = ItemName;
+      this.description = ItemDescription;
+      this.constant = constant;
+      this.ReadOnly = true; // changing a constant regression model is not supported
+    }
+
+    public IEnumerable<double> GetEstimatedValues(IDataset dataset, IEnumerable<int> rows) {
+      return rows.Select(row => Constant);
+    }
+    public IEnumerable<double> GetEstimatedClassValues(IDataset dataset, IEnumerable<int> rows) {
+      return GetEstimatedValues(dataset, rows);
+    }
+    public IEnumerable<IEnumerable<double>> GetPrognosedValues(IDataset dataset, IEnumerable<int> rows, IEnumerable<int> horizons) {
+      return rows.Select(_ => horizons.Select(__ => Constant));
+    }
+
+    public IRegressionSolution CreateRegressionSolution(IRegressionProblemData problemData) {
+      return new ConstantRegressionSolution(this, new RegressionProblemData(problemData));
+    }
+    public IClassificationSolution CreateClassificationSolution(IClassificationProblemData problemData) {
+      return new ConstantClassificationSolution(this, new ClassificationProblemData(problemData));
+    }
+    public ITimeSeriesPrognosisSolution CreateTimeSeriesPrognosisSolution(ITimeSeriesPrognosisProblemData problemData) {
+      return new TimeSeriesPrognosisSolution(this, new TimeSeriesPrognosisProblemData(problemData));
+    }
+
+    public override string ToString() {
+      return string.Format("Constant: {0}", GetValue());
+    }
+
+    #region IStringConvertibleValue
+    public bool ReadOnly { get; private set; }
+    public bool Validate(string value, out string errorMessage) {
+      throw new NotSupportedException(); // changing a constant regression model is not supported
+    }
+
+    public string GetValue() {
+      return string.Format("{0:E4}", constant);
+    }
+
+    public bool SetValue(string value) {
+      throw new NotSupportedException(); // changing a constant regression model is not supported
+    }
+
+    public event EventHandler ValueChanged;
+    #endregion
+
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/DataAnalysisProblem.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/DataAnalysisProblem.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/DataAnalysisProblem.cs	(revision 13819)
@@ -0,0 +1,105 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Optimization;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Problems.Instances;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  [StorableClass]
+  public abstract class DataAnalysisProblem<T> : Problem, IDataAnalysisProblem<T>,
+    IProblemInstanceConsumer<T>, IProblemInstanceExporter<T>
+    where T : class, IDataAnalysisProblemData {
+    private const string ProblemDataParameterName = "ProblemData";
+    private const string ProblemDataParameterDescription = "The data set, target variable and input variables of the data analysis problem.";
+    #region parameter properties
+    IParameter IDataAnalysisProblem.ProblemDataParameter {
+      get { return ProblemDataParameter; }
+    }
+    public IValueParameter<T> ProblemDataParameter {
+      get { return (IValueParameter<T>)Parameters[ProblemDataParameterName]; }
+    }
+    #endregion
+    #region properties
+    IDataAnalysisProblemData IDataAnalysisProblem.ProblemData {
+      get { return ProblemData; }
+    }
+    public T ProblemData {
+      get { return ProblemDataParameter.Value; }
+      set { ProblemDataParameter.Value = value; }
+    }
+    #endregion
+    protected DataAnalysisProblem(DataAnalysisProblem<T> original, Cloner cloner)
+      : base(original, cloner) {
+      RegisterEventHandlers();
+    }
+    [StorableConstructor]
+    protected DataAnalysisProblem(bool deserializing) : base(deserializing) { }
+
+    protected DataAnalysisProblem(T problemData)
+      : base() {
+      Parameters.Add(new ValueParameter<T>(ProblemDataParameterName, ProblemDataParameterDescription, problemData));
+      RegisterEventHandlers();
+    }
+
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() {
+      RegisterEventHandlers();
+    }
+
+    private void RegisterEventHandlers() {
+      ProblemDataParameter.ValueChanged += new EventHandler(ProblemDataParameter_ValueChanged);
+      if (ProblemDataParameter.Value != null) ProblemDataParameter.Value.Changed += new EventHandler(ProblemData_Changed);
+    }
+
+    private void ProblemDataParameter_ValueChanged(object sender, EventArgs e) {
+      ProblemDataParameter.Value.Changed += new EventHandler(ProblemData_Changed);
+      OnProblemDataChanged();
+      OnReset();
+    }
+
+    private void ProblemData_Changed(object sender, EventArgs e) {
+      OnReset();
+    }
+
+    public event EventHandler ProblemDataChanged;
+    protected virtual void OnProblemDataChanged() {
+      var handler = ProblemDataChanged;
+      if (handler != null) handler(this, EventArgs.Empty);
+    }
+
+    #region Import & Export
+    public void Load(T data) {
+      Name = data.Name;
+      Description = data.Description;
+      ProblemData = data;
+    }
+
+    public T Export() {
+      return ProblemData;
+    }
+    #endregion
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/DataAnalysisProblemData.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/DataAnalysisProblemData.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/DataAnalysisProblemData.cs	(revision 13819)
@@ -0,0 +1,222 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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 System.Text;
+using HeuristicLab.Collections;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  [StorableClass]
+  public abstract class DataAnalysisProblemData : ParameterizedNamedItem, IDataAnalysisProblemData {
+    protected const string DatasetParameterName = "Dataset";
+    protected const string InputVariablesParameterName = "InputVariables";
+    protected const string TrainingPartitionParameterName = "TrainingPartition";
+    protected const string TestPartitionParameterName = "TestPartition";
+    protected const string TransformationsParameterName = "Transformations";
+
+    #region parameter properites
+    public IFixedValueParameter<Dataset> DatasetParameter {
+      get { return (IFixedValueParameter<Dataset>)Parameters[DatasetParameterName]; }
+    }
+    public IFixedValueParameter<ReadOnlyCheckedItemList<StringValue>> InputVariablesParameter {
+      get { return (IFixedValueParameter<ReadOnlyCheckedItemList<StringValue>>)Parameters[InputVariablesParameterName]; }
+    }
+    public IFixedValueParameter<IntRange> TrainingPartitionParameter {
+      get { return (IFixedValueParameter<IntRange>)Parameters[TrainingPartitionParameterName]; }
+    }
+    public IFixedValueParameter<IntRange> TestPartitionParameter {
+      get { return (IFixedValueParameter<IntRange>)Parameters[TestPartitionParameterName]; }
+    }
+    public IFixedValueParameter<ReadOnlyItemList<ITransformation>> TransformationsParameter {
+      get { return (IFixedValueParameter<ReadOnlyItemList<ITransformation>>)Parameters[TransformationsParameterName]; }
+    }
+    #endregion
+
+    #region properties
+    protected bool isEmpty = false;
+    public bool IsEmpty {
+      get { return isEmpty; }
+    }
+    public IDataset Dataset {
+      get { return DatasetParameter.Value; }
+    }
+    public ICheckedItemList<StringValue> InputVariables {
+      get { return InputVariablesParameter.Value; }
+    }
+    public IEnumerable<string> AllowedInputVariables {
+      get { return InputVariables.CheckedItems.Select(x => x.Value.Value); }
+    }
+
+    public IntRange TrainingPartition {
+      get { return TrainingPartitionParameter.Value; }
+    }
+    public IntRange TestPartition {
+      get { return TestPartitionParameter.Value; }
+    }
+
+    public virtual IEnumerable<int> AllIndices {
+      get { return Enumerable.Range(0, Dataset.Rows); }
+    }
+    public virtual IEnumerable<int> TrainingIndices {
+      get {
+        return Enumerable.Range(TrainingPartition.Start, Math.Max(0, TrainingPartition.End - TrainingPartition.Start))
+                         .Where(IsTrainingSample);
+      }
+    }
+    public virtual IEnumerable<int> TestIndices {
+      get {
+        return Enumerable.Range(TestPartition.Start, Math.Max(0, TestPartition.End - TestPartition.Start))
+           .Where(IsTestSample);
+      }
+    }
+
+    public IEnumerable<ITransformation> Transformations {
+      get { return TransformationsParameter.Value; }
+    }
+
+    public virtual bool IsTrainingSample(int index) {
+      return index >= 0 && index < Dataset.Rows &&
+        TrainingPartition.Start <= index && index < TrainingPartition.End &&
+        (index < TestPartition.Start || TestPartition.End <= index);
+    }
+
+    public virtual bool IsTestSample(int index) {
+      return index >= 0 && index < Dataset.Rows &&
+             TestPartition.Start <= index && index < TestPartition.End;
+    }
+    #endregion
+
+    protected DataAnalysisProblemData(DataAnalysisProblemData original, Cloner cloner)
+      : base(original, cloner) {
+      isEmpty = original.isEmpty;
+      RegisterEventHandlers();
+    }
+    [StorableConstructor]
+    protected DataAnalysisProblemData(bool deserializing) : base(deserializing) { }
+
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() {
+      if (!Parameters.ContainsKey(TransformationsParameterName)) {
+        Parameters.Add(new FixedValueParameter<ReadOnlyItemList<ITransformation>>(TransformationsParameterName, "", new ItemList<ITransformation>().AsReadOnly()));
+        TransformationsParameter.Hidden = true;
+      }
+      RegisterEventHandlers();
+    }
+
+    protected DataAnalysisProblemData(IDataset dataset, IEnumerable<string> allowedInputVariables, IEnumerable<ITransformation> transformations = null) {
+      if (dataset == null) throw new ArgumentNullException("The dataset must not be null.");
+      if (allowedInputVariables == null) throw new ArgumentNullException("The allowedInputVariables must not be null.");
+
+      if (allowedInputVariables.Except(dataset.DoubleVariables).Any())
+        throw new ArgumentException("All allowed input variables must be present in the dataset and of type double.");
+
+      var inputVariables = new CheckedItemList<StringValue>(dataset.DoubleVariables.Select(x => new StringValue(x)));
+      foreach (StringValue x in inputVariables)
+        inputVariables.SetItemCheckedState(x, allowedInputVariables.Contains(x.Value));
+
+      int trainingPartitionStart = 0;
+      int trainingPartitionEnd = dataset.Rows / 2;
+      int testPartitionStart = dataset.Rows / 2;
+      int testPartitionEnd = dataset.Rows;
+
+      var transformationsList = new ItemList<ITransformation>(transformations ?? Enumerable.Empty<ITransformation>());
+
+      Parameters.Add(new FixedValueParameter<Dataset>(DatasetParameterName, "", (Dataset)dataset));
+      Parameters.Add(new FixedValueParameter<ReadOnlyCheckedItemList<StringValue>>(InputVariablesParameterName, "", inputVariables.AsReadOnly()));
+      Parameters.Add(new FixedValueParameter<IntRange>(TrainingPartitionParameterName, "", new IntRange(trainingPartitionStart, trainingPartitionEnd)));
+      Parameters.Add(new FixedValueParameter<IntRange>(TestPartitionParameterName, "", new IntRange(testPartitionStart, testPartitionEnd)));
+      Parameters.Add(new FixedValueParameter<ReadOnlyItemList<ITransformation>>(TransformationsParameterName, "", transformationsList.AsReadOnly()));
+
+      TransformationsParameter.Hidden = true;
+
+      ((ValueParameter<Dataset>)DatasetParameter).ReactOnValueToStringChangedAndValueItemImageChanged = false;
+      RegisterEventHandlers();
+    }
+
+    private void RegisterEventHandlers() {
+      DatasetParameter.ValueChanged += new EventHandler(Parameter_ValueChanged);
+      InputVariables.CheckedItemsChanged += new CollectionItemsChangedEventHandler<IndexedItem<StringValue>>(InputVariables_CheckedItemsChanged);
+      TrainingPartition.ValueChanged += new EventHandler(Parameter_ValueChanged);
+      TestPartition.ValueChanged += new EventHandler(Parameter_ValueChanged);
+      TransformationsParameter.ValueChanged += new EventHandler(Parameter_ValueChanged);
+    }
+
+    private void InputVariables_CheckedItemsChanged(object sender, CollectionItemsChangedEventArgs<IndexedItem<StringValue>> e) {
+      OnChanged();
+    }
+
+    private void Parameter_ValueChanged(object sender, EventArgs e) {
+      OnChanged();
+    }
+
+    public event EventHandler Changed;
+    protected virtual void OnChanged() {
+      var listeners = Changed;
+      if (listeners != null) listeners(this, EventArgs.Empty);
+    }
+
+    protected virtual bool IsProblemDataCompatible(IDataAnalysisProblemData problemData, out string errorMessage) {
+      errorMessage = string.Empty;
+      if (problemData == null) throw new ArgumentNullException("problemData", "The provided problemData is null.");
+
+      //check allowed input variables
+      StringBuilder message = new StringBuilder();
+      var variables = new HashSet<string>(problemData.InputVariables.Select(x => x.Value));
+      foreach (var item in AllowedInputVariables) {
+        if (!variables.Contains(item))
+          message.AppendLine("Input variable '" + item + "' is not present in the new problem data.");
+      }
+
+      if (message.Length != 0) {
+        errorMessage = message.ToString();
+        return false;
+      }
+      return true;
+
+    }
+
+    public virtual void AdjustProblemDataProperties(IDataAnalysisProblemData problemData) {
+      DataAnalysisProblemData data = problemData as DataAnalysisProblemData;
+      if (data == null) throw new ArgumentException("The problem data is not a data analysis problem data. Instead a " + problemData.GetType().GetPrettyName() + " was provided.", "problemData");
+
+      string errorMessage;
+      if (!data.IsProblemDataCompatible(this, out errorMessage)) {
+        throw new InvalidOperationException(errorMessage);
+      }
+
+      foreach (var inputVariable in InputVariables) {
+        var variable = data.InputVariables.FirstOrDefault(i => i.Value == inputVariable.Value);
+        InputVariables.SetItemCheckedState(inputVariable, variable != null && data.InputVariables.ItemChecked(variable));
+      }
+
+      TrainingPartition.Start = TrainingPartition.End = 0;
+      TestPartition.Start = 0;
+      TestPartition.End = Dataset.Rows;
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/DataAnalysisSolution.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/DataAnalysisSolution.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/DataAnalysisSolution.cs	(revision 13819)
@@ -0,0 +1,173 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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 HeuristicLab.Common;
+using HeuristicLab.Optimization;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  /// <summary>
+  /// Abstract base class for data analysis solutions
+  /// </summary>
+  [StorableClass]
+  public abstract class DataAnalysisSolution : ResultCollection, IDataAnalysisSolution {
+    private const string ModelResultName = "Model";
+    private const string ProblemDataResultName = "ProblemData";
+
+    public string Filename { get; set; }
+
+    public static new Image StaticItemImage {
+      get { return HeuristicLab.Common.Resources.VSImageLibrary.Function; }
+    }
+
+    #region properties
+    public IDataAnalysisModel Model {
+      get { return (IDataAnalysisModel)this[ModelResultName].Value; }
+      protected set {
+        if (this[ModelResultName].Value != value) {
+          if (value != null) {
+            this[ModelResultName].Value = value;
+            OnModelChanged();
+          }
+        }
+      }
+    }
+
+    public IDataAnalysisProblemData ProblemData {
+      get { return (IDataAnalysisProblemData)this[ProblemDataResultName].Value; }
+      set {
+        if (this[ProblemDataResultName].Value != value) {
+          if (value != null) {
+            ProblemData.Changed -= new EventHandler(ProblemData_Changed);
+            this[ProblemDataResultName].Value = value;
+            ProblemData.Changed += new EventHandler(ProblemData_Changed);
+            OnProblemDataChanged();
+          }
+        }
+      }
+    }
+    #endregion
+
+    [StorableConstructor]
+    protected DataAnalysisSolution(bool deserializing) : base(deserializing) { }
+    protected DataAnalysisSolution(DataAnalysisSolution original, Cloner cloner)
+      : base(original, cloner) {
+      name = original.Name;
+      description = original.Description;
+    }
+    public DataAnalysisSolution(IDataAnalysisModel model, IDataAnalysisProblemData problemData)
+      : base() {
+      name = ItemName;
+      description = ItemDescription;
+      Add(new Result(ModelResultName, "The data analysis model.", model));
+      Add(new Result(ProblemDataResultName, "The data analysis problem data.", problemData));
+
+      problemData.Changed += new EventHandler(ProblemData_Changed);
+    }
+
+    protected abstract void RecalculateResults();
+
+    private void ProblemData_Changed(object sender, EventArgs e) {
+      OnProblemDataChanged();
+    }
+
+    public event EventHandler ModelChanged;
+    protected virtual void OnModelChanged() {
+      RecalculateResults();
+      var listeners = ModelChanged;
+      if (listeners != null) listeners(this, EventArgs.Empty);
+    }
+
+    public event EventHandler ProblemDataChanged;
+    protected virtual void OnProblemDataChanged() {
+      RecalculateResults();
+      var listeners = ProblemDataChanged;
+      if (listeners != null) listeners(this, EventArgs.Empty);
+    }
+
+    //mkommend avoid unnecessary event registration for result name changes
+    protected override void RegisterItemEvents(IEnumerable<IResult> items) { }
+    protected override void DeregisterItemEvents(IEnumerable<IResult> items) { }
+
+    #region INamedItem Members
+    [Storable]
+    protected string name;
+    public string Name {
+      get { return name; }
+      set {
+        if (!CanChangeName) throw new NotSupportedException("Name cannot be changed.");
+        if (!(name.Equals(value) || (value == null) && (name == string.Empty))) {
+          CancelEventArgs<string> e = value == null ? new CancelEventArgs<string>(string.Empty) : new CancelEventArgs<string>(value);
+          OnNameChanging(e);
+          if (!e.Cancel) {
+            name = value == null ? string.Empty : value;
+            OnNameChanged();
+          }
+        }
+      }
+    }
+    public virtual bool CanChangeName {
+      get { return true; }
+    }
+    [Storable]
+    protected string description;
+    public string Description {
+      get { return description; }
+      set {
+        if (!CanChangeDescription) throw new NotSupportedException("Description cannot be changed.");
+        if (!(description.Equals(value) || (value == null) && (description == string.Empty))) {
+          description = value == null ? string.Empty : value;
+          OnDescriptionChanged();
+        }
+      }
+    }
+    public virtual bool CanChangeDescription {
+      get { return true; }
+    }
+
+    public override string ToString() {
+      return Name;
+    }
+
+    public event EventHandler<CancelEventArgs<string>> NameChanging;
+    protected virtual void OnNameChanging(CancelEventArgs<string> e) {
+      var handler = NameChanging;
+      if (handler != null) handler(this, e);
+    }
+
+    public event EventHandler NameChanged;
+    protected virtual void OnNameChanged() {
+      var handler = NameChanged;
+      if (handler != null) handler(this, EventArgs.Empty);
+      OnToStringChanged();
+    }
+
+    public event EventHandler DescriptionChanged;
+    protected virtual void OnDescriptionChanged() {
+      var handler = DescriptionChanged;
+      if (handler != null) handler(this, EventArgs.Empty);
+    }
+    #endregion
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/ConstantRegressionModel.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/ConstantRegressionModel.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/ConstantRegressionModel.cs	(revision 13819)
@@ -0,0 +1,87 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  [StorableClass]
+  [Item("Constant Regression Model", "A model that always returns the same constant value regardless of the presented input data.")]
+  [Obsolete]
+  public class ConstantRegressionModel : NamedItem, IRegressionModel, IStringConvertibleValue {
+    [Storable]
+    private double constant;
+    public double Constant {
+      get { return constant; }
+      // setter not implemented because manipulation of the constant is not allowed
+    }
+
+    [StorableConstructor]
+    protected ConstantRegressionModel(bool deserializing) : base(deserializing) { }
+    protected ConstantRegressionModel(ConstantRegressionModel original, Cloner cloner)
+      : base(original, cloner) {
+      this.constant = original.constant;
+    }
+    public override IDeepCloneable Clone(Cloner cloner) { return new ConstantRegressionModel(this, cloner); }
+
+    public ConstantRegressionModel(double constant)
+      : base() {
+      this.name = ItemName;
+      this.description = ItemDescription;
+      this.constant = constant;
+      this.ReadOnly = true; // changing a constant regression model is not supported
+    }
+
+    public IEnumerable<double> GetEstimatedValues(IDataset dataset, IEnumerable<int> rows) {
+      return rows.Select(row => Constant);
+    }
+
+    public IRegressionSolution CreateRegressionSolution(IRegressionProblemData problemData) {
+      return new ConstantRegressionSolution(new ConstantModel(constant), new RegressionProblemData(problemData));
+    }
+
+    public override string ToString() {
+      return string.Format("Constant: {0}", GetValue());
+    }
+
+    #region IStringConvertibleValue
+    public bool ReadOnly { get; private set; }
+    public bool Validate(string value, out string errorMessage) {
+      throw new NotSupportedException(); // changing a constant regression model is not supported
+    }
+
+    public string GetValue() {
+      return string.Format("{0:E4}", constant);
+    }
+
+    public bool SetValue(string value) {
+      throw new NotSupportedException(); // changing a constant regression model is not supported
+    }
+
+    public event EventHandler ValueChanged;
+    #endregion
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/ConstantRegressionSolution.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/ConstantRegressionSolution.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/ConstantRegressionSolution.cs	(revision 13819)
@@ -0,0 +1,47 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  [StorableClass]
+  [Item(Name = "Constant Regression Solution", Description = "Represents a constant regression solution (model + data).")]
+  public class ConstantRegressionSolution : RegressionSolution {
+    public new ConstantModel Model {
+      get { return (ConstantModel)base.Model; }
+      set { base.Model = value; }
+    }
+
+    [StorableConstructor]
+    protected ConstantRegressionSolution(bool deserializing) : base(deserializing) { }
+    protected ConstantRegressionSolution(ConstantRegressionSolution original, Cloner cloner) : base(original, cloner) { }
+    public ConstantRegressionSolution(ConstantModel model, IRegressionProblemData problemData)
+      : base(model, problemData) {
+      RecalculateResults();
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new ConstantRegressionSolution(this, cloner);
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/RegressionEnsembleModel.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/RegressionEnsembleModel.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/RegressionEnsembleModel.cs	(revision 13819)
@@ -0,0 +1,222 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  /// <summary>
+  /// Represents regression solutions that contain an ensemble of multiple regression models
+  /// </summary>
+  [StorableClass]
+  [Item("RegressionEnsembleModel", "A regression model that contains an ensemble of multiple regression models")]
+  public sealed class RegressionEnsembleModel : NamedItem, IRegressionEnsembleModel {
+
+    private List<IRegressionModel> models;
+    public IEnumerable<IRegressionModel> Models {
+      get { return new List<IRegressionModel>(models); }
+    }
+
+    [Storable(Name = "Models")]
+    private IEnumerable<IRegressionModel> StorableModels {
+      get { return models; }
+      set { models = value.ToList(); }
+    }
+
+    private List<double> modelWeights;
+    public IEnumerable<double> ModelWeights {
+      get { return modelWeights; }
+    }
+
+    [Storable(Name = "ModelWeights")]
+    private IEnumerable<double> StorableModelWeights {
+      get { return modelWeights; }
+      set { modelWeights = value.ToList(); }
+    }
+
+    [Storable]
+    private bool averageModelEstimates = true;
+    public bool AverageModelEstimates {
+      get { return averageModelEstimates; }
+      set {
+        if (averageModelEstimates != value) {
+          averageModelEstimates = value;
+          OnChanged();
+        }
+      }
+    }
+
+    #region backwards compatiblity 3.3.5
+    [Storable(Name = "models", AllowOneWay = true)]
+    private List<IRegressionModel> OldStorableModels {
+      set { models = value; }
+    }
+    #endregion
+
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() {
+      // BackwardsCompatibility 3.3.14
+      #region Backwards compatible code, remove with 3.4
+      if (modelWeights == null || !modelWeights.Any())
+        modelWeights = new List<double>(models.Select(m => 1.0));
+      #endregion
+    }
+
+    [StorableConstructor]
+    private RegressionEnsembleModel(bool deserializing) : base(deserializing) { }
+    private RegressionEnsembleModel(RegressionEnsembleModel original, Cloner cloner)
+      : base(original, cloner) {
+      this.models = original.Models.Select(cloner.Clone).ToList();
+      this.modelWeights = new List<double>(original.ModelWeights);
+      this.averageModelEstimates = original.averageModelEstimates;
+    }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new RegressionEnsembleModel(this, cloner);
+    }
+
+    public RegressionEnsembleModel() : this(Enumerable.Empty<IRegressionModel>()) { }
+    public RegressionEnsembleModel(IEnumerable<IRegressionModel> models) : this(models, models.Select(m => 1.0)) { }
+    public RegressionEnsembleModel(IEnumerable<IRegressionModel> models, IEnumerable<double> modelWeights)
+      : base() {
+      this.name = ItemName;
+      this.description = ItemDescription;
+
+
+      this.models = new List<IRegressionModel>(models);
+      this.modelWeights = new List<double>(modelWeights);
+    }
+
+    public void Add(IRegressionModel model) {
+      Add(model, 1.0);
+    }
+    public void Add(IRegressionModel model, double weight) {
+      models.Add(model);
+      modelWeights.Add(weight);
+      OnChanged();
+    }
+
+    public void AddRange(IEnumerable<IRegressionModel> models) {
+      AddRange(models, models.Select(m => 1.0));
+    }
+    public void AddRange(IEnumerable<IRegressionModel> models, IEnumerable<double> weights) {
+      this.models.AddRange(models);
+      modelWeights.AddRange(weights);
+      OnChanged();
+    }
+
+    public void Remove(IRegressionModel model) {
+      var index = models.IndexOf(model);
+      models.RemoveAt(index);
+      modelWeights.RemoveAt(index);
+      OnChanged();
+    }
+    public void RemoveRange(IEnumerable<IRegressionModel> models) {
+      foreach (var model in models) {
+        var index = this.models.IndexOf(model);
+        this.models.RemoveAt(index);
+        modelWeights.RemoveAt(index);
+      }
+      OnChanged();
+    }
+
+    public double GetModelWeight(IRegressionModel model) {
+      var index = models.IndexOf(model);
+      return modelWeights[index];
+    }
+    public void SetModelWeight(IRegressionModel model, double weight) {
+      var index = models.IndexOf(model);
+      modelWeights[index] = weight;
+      OnChanged();
+    }
+
+    #region evaluation
+    public IEnumerable<IEnumerable<double>> GetEstimatedValueVectors(IDataset dataset, IEnumerable<int> rows) {
+      var estimatedValuesEnumerators = (from model in models
+                                        let weight = GetModelWeight(model)
+                                        select model.GetEstimatedValues(dataset, rows).Select(e => weight * e)
+                                        .GetEnumerator()).ToList();
+
+      while (estimatedValuesEnumerators.All(en => en.MoveNext())) {
+        yield return from enumerator in estimatedValuesEnumerators
+                     select enumerator.Current;
+      }
+    }
+
+    public IEnumerable<double> GetEstimatedValues(IDataset dataset, IEnumerable<int> rows) {
+      double weightsSum = modelWeights.Sum();
+      var summedEstimates = from estimatedValuesVector in GetEstimatedValueVectors(dataset, rows)
+                            select estimatedValuesVector.DefaultIfEmpty(double.NaN).Sum();
+
+      if (AverageModelEstimates)
+        return summedEstimates.Select(v => v / weightsSum);
+      else
+        return summedEstimates;
+
+    }
+
+    public IEnumerable<double> GetEstimatedValues(IDataset dataset, IEnumerable<int> rows, Func<int, IRegressionModel, bool> modelSelectionPredicate) {
+      var estimatedValuesEnumerators = GetEstimatedValueVectors(dataset, rows).GetEnumerator();
+      var rowsEnumerator = rows.GetEnumerator();
+
+      while (rowsEnumerator.MoveNext() & estimatedValuesEnumerators.MoveNext()) {
+        var estimatedValueEnumerator = estimatedValuesEnumerators.Current.GetEnumerator();
+        int currentRow = rowsEnumerator.Current;
+        double weightsSum = 0.0;
+        double filteredEstimatesSum = 0.0;
+
+        for (int m = 0; m < models.Count; m++) {
+          estimatedValueEnumerator.MoveNext();
+          var model = models[m];
+          if (!modelSelectionPredicate(currentRow, model)) continue;
+
+          filteredEstimatesSum += estimatedValueEnumerator.Current;
+          weightsSum += modelWeights[m];
+        }
+
+        if (AverageModelEstimates)
+          yield return filteredEstimatesSum / weightsSum;
+        else
+          yield return filteredEstimatesSum;
+      }
+    }
+
+    #endregion
+
+    public event EventHandler Changed;
+    private void OnChanged() {
+      var handler = Changed;
+      if (handler != null)
+        handler(this, EventArgs.Empty);
+    }
+
+
+    public RegressionEnsembleSolution CreateRegressionSolution(IRegressionProblemData problemData) {
+      return new RegressionEnsembleSolution(this, new RegressionEnsembleProblemData(problemData));
+    }
+    IRegressionSolution IRegressionModel.CreateRegressionSolution(IRegressionProblemData problemData) {
+      return CreateRegressionSolution(problemData);
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/RegressionEnsembleProblemData.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/RegressionEnsembleProblemData.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/RegressionEnsembleProblemData.cs	(revision 13819)
@@ -0,0 +1,83 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Collections.Generic;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  [StorableClass]
+  [Item("RegressionEnsembleProblemData", "Represents an item containing all data defining a regression problem.")]
+  public sealed class RegressionEnsembleProblemData : RegressionProblemData {
+
+    public override bool IsTrainingSample(int index) {
+      return index >= 0 && index < Dataset.Rows &&
+             TrainingPartition.Start <= index && index < TrainingPartition.End;
+    }
+
+    public override bool IsTestSample(int index) {
+      return index >= 0 && index < Dataset.Rows &&
+             TestPartition.Start <= index && index < TestPartition.End;
+    }
+
+    private static readonly RegressionEnsembleProblemData emptyProblemData;
+    public new static RegressionEnsembleProblemData EmptyProblemData {
+      get { return emptyProblemData; }
+    }
+    static RegressionEnsembleProblemData() {
+      var problemData = new RegressionEnsembleProblemData();
+      problemData.Parameters.Clear();
+      problemData.Name = "Empty Regression ProblemData";
+      problemData.Description = "This ProblemData acts as place holder before the correct problem data is loaded.";
+      problemData.isEmpty = true;
+
+      problemData.Parameters.Add(new FixedValueParameter<Dataset>(DatasetParameterName, "", new Dataset()));
+      problemData.Parameters.Add(new FixedValueParameter<ReadOnlyCheckedItemList<StringValue>>(InputVariablesParameterName, ""));
+      problemData.Parameters.Add(new FixedValueParameter<IntRange>(TrainingPartitionParameterName, "", (IntRange)new IntRange(0, 0).AsReadOnly()));
+      problemData.Parameters.Add(new FixedValueParameter<IntRange>(TestPartitionParameterName, "", (IntRange)new IntRange(0, 0).AsReadOnly()));
+      problemData.Parameters.Add(new ConstrainedValueParameter<StringValue>(TargetVariableParameterName, new ItemSet<StringValue>()));
+      emptyProblemData = problemData;
+    }
+
+    [StorableConstructor]
+    private RegressionEnsembleProblemData(bool deserializing) : base(deserializing) { }
+    private RegressionEnsembleProblemData(RegressionEnsembleProblemData original, Cloner cloner) : base(original, cloner) { }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      if (this == emptyProblemData) return emptyProblemData;
+      return new RegressionEnsembleProblemData(this, cloner);
+    }
+
+    public RegressionEnsembleProblemData() : base() { }
+    public RegressionEnsembleProblemData(IRegressionProblemData regressionProblemData)
+      : base(regressionProblemData.Dataset, regressionProblemData.AllowedInputVariables, regressionProblemData.TargetVariable) {
+      TrainingPartition.Start = regressionProblemData.TrainingPartition.Start;
+      TrainingPartition.End = regressionProblemData.TrainingPartition.End;
+      TestPartition.Start = regressionProblemData.TestPartition.Start;
+      TestPartition.End = regressionProblemData.TestPartition.End;
+    }
+    public RegressionEnsembleProblemData(Dataset dataset, IEnumerable<string> allowedInputVariables, string targetVariable)
+      : base(dataset, allowedInputVariables, targetVariable) {
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/RegressionEnsembleSolution.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/RegressionEnsembleSolution.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/RegressionEnsembleSolution.cs	(revision 13819)
@@ -0,0 +1,302 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Collections;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  /// <summary>
+  /// Represents regression solutions that contain an ensemble of multiple regression models
+  /// </summary>
+  [StorableClass]
+  [Item("Regression Ensemble Solution", "A regression solution that contains an ensemble of multiple regression models")]
+  [Creatable(CreatableAttribute.Categories.DataAnalysisEnsembles, Priority = 100)]
+  public sealed class RegressionEnsembleSolution : RegressionSolutionBase, IRegressionEnsembleSolution {
+    private readonly Dictionary<int, double> trainingEvaluationCache = new Dictionary<int, double>();
+    private readonly Dictionary<int, double> testEvaluationCache = new Dictionary<int, double>();
+    private readonly Dictionary<int, double> evaluationCache = new Dictionary<int, double>();
+
+    public new IRegressionEnsembleModel Model {
+      get { return (IRegressionEnsembleModel)base.Model; }
+    }
+
+    public new RegressionEnsembleProblemData ProblemData {
+      get { return (RegressionEnsembleProblemData)base.ProblemData; }
+      set { base.ProblemData = value; }
+    }
+
+    [Storable]
+    private readonly ItemCollection<IRegressionSolution> regressionSolutions;
+    public IItemCollection<IRegressionSolution> RegressionSolutions {
+      get { return regressionSolutions; }
+    }
+
+    [Storable]
+    private readonly Dictionary<IRegressionModel, IntRange> trainingPartitions;
+    [Storable]
+    private readonly Dictionary<IRegressionModel, IntRange> testPartitions;
+
+    [StorableConstructor]
+    private RegressionEnsembleSolution(bool deserializing)
+      : base(deserializing) {
+      regressionSolutions = new ItemCollection<IRegressionSolution>();
+    }
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() {
+      if (!regressionSolutions.Any()) {
+        foreach (var model in Model.Models) {
+          IRegressionProblemData problemData = (IRegressionProblemData)ProblemData.Clone();
+          problemData.TrainingPartition.Start = trainingPartitions[model].Start;
+          problemData.TrainingPartition.End = trainingPartitions[model].End;
+          problemData.TestPartition.Start = testPartitions[model].Start;
+          problemData.TestPartition.End = testPartitions[model].End;
+
+          regressionSolutions.Add(model.CreateRegressionSolution(problemData));
+        }
+      }
+
+      RegisterModelEvents();
+      RegisterRegressionSolutionsEventHandler();
+    }
+
+    private RegressionEnsembleSolution(RegressionEnsembleSolution original, Cloner cloner)
+      : base(original, cloner) {
+      trainingPartitions = new Dictionary<IRegressionModel, IntRange>();
+      testPartitions = new Dictionary<IRegressionModel, IntRange>();
+      foreach (var pair in original.trainingPartitions) {
+        trainingPartitions[cloner.Clone(pair.Key)] = cloner.Clone(pair.Value);
+      }
+      foreach (var pair in original.testPartitions) {
+        testPartitions[cloner.Clone(pair.Key)] = cloner.Clone(pair.Value);
+      }
+
+      evaluationCache = new Dictionary<int, double>(original.ProblemData.Dataset.Rows);
+      trainingEvaluationCache = new Dictionary<int, double>(original.ProblemData.TrainingIndices.Count());
+      testEvaluationCache = new Dictionary<int, double>(original.ProblemData.TestIndices.Count());
+
+      regressionSolutions = cloner.Clone(original.regressionSolutions);
+      RegisterModelEvents();
+      RegisterRegressionSolutionsEventHandler();
+    }
+
+    public RegressionEnsembleSolution()
+      : base(new RegressionEnsembleModel(), RegressionEnsembleProblemData.EmptyProblemData) {
+      trainingPartitions = new Dictionary<IRegressionModel, IntRange>();
+      testPartitions = new Dictionary<IRegressionModel, IntRange>();
+      regressionSolutions = new ItemCollection<IRegressionSolution>();
+
+      RegisterModelEvents();
+      RegisterRegressionSolutionsEventHandler();
+    }
+
+    public RegressionEnsembleSolution(IRegressionProblemData problemData)
+      : this(new RegressionEnsembleModel(), problemData) {
+    }
+
+    public RegressionEnsembleSolution(IRegressionEnsembleModel model, IRegressionProblemData problemData)
+      : base(model, new RegressionEnsembleProblemData(problemData)) {
+      trainingPartitions = new Dictionary<IRegressionModel, IntRange>();
+      testPartitions = new Dictionary<IRegressionModel, IntRange>();
+      regressionSolutions = new ItemCollection<IRegressionSolution>();
+
+      evaluationCache = new Dictionary<int, double>(problemData.Dataset.Rows);
+      trainingEvaluationCache = new Dictionary<int, double>(problemData.TrainingIndices.Count());
+      testEvaluationCache = new Dictionary<int, double>(problemData.TestIndices.Count());
+
+
+      var solutions = model.Models.Select(m => m.CreateRegressionSolution((IRegressionProblemData)problemData.Clone()));
+      foreach (var solution in solutions) {
+        regressionSolutions.Add(solution);
+        trainingPartitions.Add(solution.Model, solution.ProblemData.TrainingPartition);
+        testPartitions.Add(solution.Model, solution.ProblemData.TestPartition);
+      }
+
+      RecalculateResults();
+      RegisterModelEvents();
+      RegisterRegressionSolutionsEventHandler();
+    }
+
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new RegressionEnsembleSolution(this, cloner);
+    }
+
+    private void RegisterModelEvents() {
+      Model.Changed += Model_Changed;
+    }
+    private void RegisterRegressionSolutionsEventHandler() {
+      regressionSolutions.ItemsAdded += new CollectionItemsChangedEventHandler<IRegressionSolution>(regressionSolutions_ItemsAdded);
+      regressionSolutions.ItemsRemoved += new CollectionItemsChangedEventHandler<IRegressionSolution>(regressionSolutions_ItemsRemoved);
+      regressionSolutions.CollectionReset += new CollectionItemsChangedEventHandler<IRegressionSolution>(regressionSolutions_CollectionReset);
+    }
+
+    #region Evaluation
+    public override IEnumerable<double> EstimatedValues {
+      get { return GetEstimatedValues(Enumerable.Range(0, ProblemData.Dataset.Rows)); }
+    }
+
+    public override IEnumerable<double> EstimatedTrainingValues {
+      get {
+        var rows = ProblemData.TrainingIndices;
+        var rowsToEvaluate = rows.Except(trainingEvaluationCache.Keys);
+
+        var rowsEnumerator = rowsToEvaluate.GetEnumerator();
+        var valuesEnumerator = Model.GetEstimatedValues(ProblemData.Dataset, rowsToEvaluate, (r, m) => RowIsTrainingForModel(r, m) && !RowIsTestForModel(r, m)).GetEnumerator();
+
+        while (rowsEnumerator.MoveNext() & valuesEnumerator.MoveNext()) {
+          trainingEvaluationCache.Add(rowsEnumerator.Current, valuesEnumerator.Current);
+        }
+
+        return rows.Select(row => trainingEvaluationCache[row]);
+      }
+    }
+
+    public override IEnumerable<double> EstimatedTestValues {
+      get {
+        var rows = ProblemData.TestIndices;
+        var rowsToEvaluate = rows.Except(testEvaluationCache.Keys);
+        var rowsEnumerator = rowsToEvaluate.GetEnumerator();
+        var valuesEnumerator = Model.GetEstimatedValues(ProblemData.Dataset, rowsToEvaluate, RowIsTestForModel).GetEnumerator();
+
+        while (rowsEnumerator.MoveNext() & valuesEnumerator.MoveNext()) {
+          testEvaluationCache.Add(rowsEnumerator.Current, valuesEnumerator.Current);
+        }
+
+        return rows.Select(row => testEvaluationCache[row]);
+      }
+    }
+    private bool RowIsTrainingForModel(int currentRow, IRegressionModel model) {
+      return trainingPartitions == null || !trainingPartitions.ContainsKey(model) ||
+              (trainingPartitions[model].Start <= currentRow && currentRow < trainingPartitions[model].End);
+    }
+    private bool RowIsTestForModel(int currentRow, IRegressionModel model) {
+      return testPartitions == null || !testPartitions.ContainsKey(model) ||
+              (testPartitions[model].Start <= currentRow && currentRow < testPartitions[model].End);
+    }
+
+    public override IEnumerable<double> GetEstimatedValues(IEnumerable<int> rows) {
+      var rowsToEvaluate = rows.Except(evaluationCache.Keys);
+      var rowsEnumerator = rowsToEvaluate.GetEnumerator();
+      var valuesEnumerator = Model.GetEstimatedValues(ProblemData.Dataset, rowsToEvaluate).GetEnumerator();
+
+      while (rowsEnumerator.MoveNext() & valuesEnumerator.MoveNext()) {
+        evaluationCache.Add(rowsEnumerator.Current, valuesEnumerator.Current);
+      }
+
+      return rows.Select(row => evaluationCache[row]);
+    }
+
+    public IEnumerable<IEnumerable<double>> GetEstimatedValueVectors(IEnumerable<int> rows) {
+      return Model.GetEstimatedValueVectors(ProblemData.Dataset, rows);
+    }
+    #endregion
+
+    protected override void OnProblemDataChanged() {
+      trainingEvaluationCache.Clear();
+      testEvaluationCache.Clear();
+      evaluationCache.Clear();
+      IRegressionProblemData problemData = new RegressionProblemData(ProblemData.Dataset,
+                                                                     ProblemData.AllowedInputVariables,
+                                                                     ProblemData.TargetVariable);
+      problemData.TrainingPartition.Start = ProblemData.TrainingPartition.Start;
+      problemData.TrainingPartition.End = ProblemData.TrainingPartition.End;
+      problemData.TestPartition.Start = ProblemData.TestPartition.Start;
+      problemData.TestPartition.End = ProblemData.TestPartition.End;
+
+      foreach (var solution in RegressionSolutions) {
+        if (solution is RegressionEnsembleSolution)
+          solution.ProblemData = ProblemData;
+        else
+          solution.ProblemData = problemData;
+      }
+      foreach (var trainingPartition in trainingPartitions.Values) {
+        trainingPartition.Start = ProblemData.TrainingPartition.Start;
+        trainingPartition.End = ProblemData.TrainingPartition.End;
+      }
+      foreach (var testPartition in testPartitions.Values) {
+        testPartition.Start = ProblemData.TestPartition.Start;
+        testPartition.End = ProblemData.TestPartition.End;
+      }
+
+      base.OnProblemDataChanged();
+    }
+
+    private void Model_Changed(object sender, EventArgs e) {
+      var modelSet = new HashSet<IRegressionModel>(Model.Models);
+      foreach (var model in Model.Models) {
+        if (!trainingPartitions.ContainsKey(model)) trainingPartitions.Add(model, ProblemData.TrainingPartition);
+        if (!testPartitions.ContainsKey(model)) testPartitions.Add(model, ProblemData.TrainingPartition);
+      }
+      foreach (var model in trainingPartitions.Keys) {
+        if (modelSet.Contains(model)) continue;
+        trainingPartitions.Remove(model);
+        testPartitions.Remove(model);
+      }
+
+      trainingEvaluationCache.Clear();
+      testEvaluationCache.Clear();
+      evaluationCache.Clear();
+
+      OnModelChanged();
+    }
+
+    public void AddRegressionSolutions(IEnumerable<IRegressionSolution> solutions) {
+      regressionSolutions.AddRange(solutions);
+    }
+    public void RemoveRegressionSolutions(IEnumerable<IRegressionSolution> solutions) {
+      regressionSolutions.RemoveRange(solutions);
+    }
+
+    private void regressionSolutions_ItemsAdded(object sender, CollectionItemsChangedEventArgs<IRegressionSolution> e) {
+      foreach (var solution in e.Items) {
+        trainingPartitions.Add(solution.Model, solution.ProblemData.TrainingPartition);
+        testPartitions.Add(solution.Model, solution.ProblemData.TestPartition);
+      }
+      Model.AddRange(e.Items.Select(s => s.Model));
+    }
+    private void regressionSolutions_ItemsRemoved(object sender, CollectionItemsChangedEventArgs<IRegressionSolution> e) {
+      foreach (var solution in e.Items) {
+        trainingPartitions.Remove(solution.Model);
+        testPartitions.Remove(solution.Model);
+      }
+      Model.RemoveRange(e.Items.Select(s => s.Model));
+    }
+    private void regressionSolutions_CollectionReset(object sender, CollectionItemsChangedEventArgs<IRegressionSolution> e) {
+      foreach (var solution in e.OldItems) {
+        trainingPartitions.Remove(solution.Model);
+        testPartitions.Remove(solution.Model);
+      }
+      Model.RemoveRange(e.OldItems.Select(s => s.Model));
+
+      foreach (var solution in e.Items) {
+        trainingPartitions.Add(solution.Model, solution.ProblemData.TrainingPartition);
+        testPartitions.Add(solution.Model, solution.ProblemData.TestPartition);
+      }
+      Model.AddRange(e.Items.Select(s => s.Model));
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/RegressionProblem.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/RegressionProblem.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/RegressionProblem.cs	(revision 13819)
@@ -0,0 +1,40 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  [StorableClass]
+  [Item("Regression Problem", "A general regression problem.")]
+  public class RegressionProblem : DataAnalysisProblem<IRegressionProblemData>, IRegressionProblem, IStorableContent {
+    public string Filename { get; set; }
+
+    [StorableConstructor]
+    protected RegressionProblem(bool deserializing) : base(deserializing) { }
+    protected RegressionProblem(RegressionProblem original, Cloner cloner) : base(original, cloner) { }
+    public override IDeepCloneable Clone(Cloner cloner) { return new RegressionProblem(this, cloner); }
+
+    public RegressionProblem() : base(new RegressionProblemData()) { }
+
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/RegressionProblemData.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/RegressionProblemData.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/RegressionProblemData.cs	(revision 13819)
@@ -0,0 +1,190 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  [StorableClass]
+  [Item("RegressionProblemData", "Represents an item containing all data defining a regression problem.")]
+  public class RegressionProblemData : DataAnalysisProblemData, IRegressionProblemData, IStorableContent {
+    protected const string TargetVariableParameterName = "TargetVariable";
+    public string Filename { get; set; }
+
+    #region default data
+    private static double[,] kozaF1 = new double[,] {
+          {2.017885919,	-1.449165046},
+          {1.30060506,	-1.344523885},
+          {1.147134798,	-1.317989331},
+          {0.877182504,	-1.266142284},
+          {0.852562452,	-1.261020794},
+          {0.431095788,	-1.158793317},
+          {0.112586002,	-1.050908405},
+          {0.04594507,	-1.021989402},
+          {0.042572879,	-1.020438113},
+          {-0.074027291,	-0.959859562},
+          {-0.109178553,	-0.938094706},
+          {-0.259721109,	-0.803635355},
+          {-0.272991057,	-0.387519561},
+          {-0.161978191,	-0.193611001},
+          {-0.102489983,	-0.114215349},
+          {-0.01469968,	-0.014918985},
+          {-0.008863365,	-0.008942626},
+          {0.026751057,	0.026054094},
+          {0.166922436,	0.14309643},
+          {0.176953808,	0.1504144},
+          {0.190233418,	0.159916534},
+          {0.199800708,	0.166635331},
+          {0.261502822,	0.207600348},
+          {0.30182879,	0.232370249},
+          {0.83763905,	0.468046718}
+    };
+    private static readonly Dataset defaultDataset;
+    private static readonly IEnumerable<string> defaultAllowedInputVariables;
+    private static readonly string defaultTargetVariable;
+
+    private static readonly RegressionProblemData emptyProblemData;
+    public static RegressionProblemData EmptyProblemData {
+      get { return emptyProblemData; }
+    }
+
+    static RegressionProblemData() {
+      defaultDataset = new Dataset(new string[] { "y", "x" }, kozaF1);
+      defaultDataset.Name = "Fourth-order Polynomial Function Benchmark Dataset";
+      defaultDataset.Description = "f(x) = x^4 + x^3 + x^2 + x^1";
+      defaultAllowedInputVariables = new List<string>() { "x" };
+      defaultTargetVariable = "y";
+
+      var problemData = new RegressionProblemData();
+      problemData.Parameters.Clear();
+      problemData.Name = "Empty Regression ProblemData";
+      problemData.Description = "This ProblemData acts as place holder before the correct problem data is loaded.";
+      problemData.isEmpty = true;
+
+      problemData.Parameters.Add(new FixedValueParameter<Dataset>(DatasetParameterName, "", new Dataset()));
+      problemData.Parameters.Add(new FixedValueParameter<ReadOnlyCheckedItemList<StringValue>>(InputVariablesParameterName, ""));
+      problemData.Parameters.Add(new FixedValueParameter<IntRange>(TrainingPartitionParameterName, "", (IntRange)new IntRange(0, 0).AsReadOnly()));
+      problemData.Parameters.Add(new FixedValueParameter<IntRange>(TestPartitionParameterName, "", (IntRange)new IntRange(0, 0).AsReadOnly()));
+      problemData.Parameters.Add(new ConstrainedValueParameter<StringValue>(TargetVariableParameterName, new ItemSet<StringValue>()));
+      emptyProblemData = problemData;
+    }
+    #endregion
+
+    public IConstrainedValueParameter<StringValue> TargetVariableParameter {
+      get { return (IConstrainedValueParameter<StringValue>)Parameters[TargetVariableParameterName]; }
+    }
+    public string TargetVariable {
+      get { return TargetVariableParameter.Value.Value; }
+      set {
+        if (value == null) throw new ArgumentNullException("targetVariable", "The provided value for the targetVariable is null.");
+        if (value == TargetVariable) return;
+
+        var matchingParameterValue = TargetVariableParameter.ValidValues.FirstOrDefault(v => v.Value == value);
+        if (matchingParameterValue == null) throw new ArgumentException("The provided value is not valid as the targetVariable.", "targetVariable");
+        TargetVariableParameter.Value = matchingParameterValue;
+      }
+    }
+
+    public IEnumerable<double> TargetVariableValues {
+      get { return Dataset.GetDoubleValues(TargetVariable); }
+    }
+    public IEnumerable<double> TargetVariableTrainingValues {
+      get { return Dataset.GetDoubleValues(TargetVariable, TrainingIndices); }
+    }
+    public IEnumerable<double> TargetVariableTestValues {
+      get { return Dataset.GetDoubleValues(TargetVariable, TestIndices); }
+    }
+
+
+    [StorableConstructor]
+    protected RegressionProblemData(bool deserializing) : base(deserializing) { }
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() {
+      RegisterParameterEvents();
+    }
+
+    protected RegressionProblemData(RegressionProblemData original, Cloner cloner)
+      : base(original, cloner) {
+      RegisterParameterEvents();
+    }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      if (this == emptyProblemData) return emptyProblemData;
+      return new RegressionProblemData(this, cloner);
+    }
+
+    public RegressionProblemData()
+      : this(defaultDataset, defaultAllowedInputVariables, defaultTargetVariable) {
+    }
+    public RegressionProblemData(IRegressionProblemData regressionProblemData)
+      : this(regressionProblemData.Dataset, regressionProblemData.AllowedInputVariables, regressionProblemData.TargetVariable) {
+      TrainingPartition.Start = regressionProblemData.TrainingPartition.Start;
+      TrainingPartition.End = regressionProblemData.TrainingPartition.End;
+      TestPartition.Start = regressionProblemData.TestPartition.Start;
+      TestPartition.End = regressionProblemData.TestPartition.End;
+    }
+
+    public RegressionProblemData(IDataset dataset, IEnumerable<string> allowedInputVariables, string targetVariable, IEnumerable<ITransformation> transformations = null)
+      : base(dataset, allowedInputVariables, transformations ?? Enumerable.Empty<ITransformation>()) {
+      var variables = InputVariables.Select(x => x.AsReadOnly()).ToList();
+      Parameters.Add(new ConstrainedValueParameter<StringValue>(TargetVariableParameterName, new ItemSet<StringValue>(variables), variables.Where(x => x.Value == targetVariable).First()));
+      RegisterParameterEvents();
+    }
+
+    private void RegisterParameterEvents() {
+      TargetVariableParameter.ValueChanged += new EventHandler(TargetVariableParameter_ValueChanged);
+    }
+    private void TargetVariableParameter_ValueChanged(object sender, EventArgs e) {
+      OnChanged();
+    }
+
+    protected override bool IsProblemDataCompatible(IDataAnalysisProblemData problemData, out string errorMessage) {
+      if (problemData == null) throw new ArgumentNullException("problemData", "The provided problemData is null.");
+      IRegressionProblemData regressionProblemData = problemData as IRegressionProblemData;
+      if (regressionProblemData == null)
+        throw new ArgumentException("The problem data is not a regression problem data. Instead a " + problemData.GetType().GetPrettyName() + " was provided.", "problemData");
+
+      var returnValue = base.IsProblemDataCompatible(problemData, out errorMessage);
+      //check targetVariable
+      if (problemData.InputVariables.All(var => var.Value != TargetVariable)) {
+        errorMessage = string.Format("The target variable {0} is not present in the new problem data.", TargetVariable)
+                       + Environment.NewLine + errorMessage;
+        return false;
+      }
+      return returnValue;
+    }
+
+    public override void AdjustProblemDataProperties(IDataAnalysisProblemData problemData) {
+      if (problemData == null) throw new ArgumentNullException("problemData", "The provided problemData is null.");
+      RegressionProblemData regressionProblemData = problemData as RegressionProblemData;
+      if (regressionProblemData == null)
+        throw new ArgumentException("The problem data is not a regression problem data. Instead a " + problemData.GetType().GetPrettyName() + " was provided.", "problemData");
+
+      base.AdjustProblemDataProperties(problemData);
+      TargetVariable = regressionProblemData.TargetVariable;
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/RegressionSolution.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/RegressionSolution.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/RegressionSolution.cs	(revision 13819)
@@ -0,0 +1,86 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  /// <summary>
+  /// Represents a regression data analysis solution
+  /// </summary>
+  [StorableClass]
+  public class RegressionSolution : RegressionSolutionBase {
+    protected readonly Dictionary<int, double> evaluationCache;
+
+    [StorableConstructor]
+    protected RegressionSolution(bool deserializing)
+      : base(deserializing) {
+      evaluationCache = new Dictionary<int, double>();
+    }
+    protected RegressionSolution(RegressionSolution original, Cloner cloner)
+      : base(original, cloner) {
+      evaluationCache = new Dictionary<int, double>(original.evaluationCache);
+    }
+    public RegressionSolution(IRegressionModel model, IRegressionProblemData problemData)
+      : base(model, problemData) {
+      evaluationCache = new Dictionary<int, double>(problemData.Dataset.Rows);
+      CalculateRegressionResults();
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new RegressionSolution(this, cloner);
+    }
+
+    public override IEnumerable<double> EstimatedValues {
+      get { return GetEstimatedValues(Enumerable.Range(0, ProblemData.Dataset.Rows)); }
+    }
+    public override IEnumerable<double> EstimatedTrainingValues {
+      get { return GetEstimatedValues(ProblemData.TrainingIndices); }
+    }
+    public override IEnumerable<double> EstimatedTestValues {
+      get { return GetEstimatedValues(ProblemData.TestIndices); }
+    }
+
+    public override IEnumerable<double> GetEstimatedValues(IEnumerable<int> rows) {
+      var rowsToEvaluate = rows.Where(row => !evaluationCache.ContainsKey(row));
+      var rowsEnumerator = rowsToEvaluate.GetEnumerator();
+      var valuesEnumerator = Model.GetEstimatedValues(ProblemData.Dataset, rowsToEvaluate).GetEnumerator();
+
+      while (rowsEnumerator.MoveNext() & valuesEnumerator.MoveNext()) {
+        evaluationCache.Add(rowsEnumerator.Current, valuesEnumerator.Current);
+      }
+
+      return rows.Select(row => evaluationCache[row]);
+    }
+
+    protected override void OnProblemDataChanged() {
+      evaluationCache.Clear();
+      base.OnProblemDataChanged();
+    }
+
+    protected override void OnModelChanged() {
+      evaluationCache.Clear();
+      base.OnModelChanged();
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/RegressionSolutionBase.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/RegressionSolutionBase.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/RegressionSolutionBase.cs	(revision 13819)
@@ -0,0 +1,262 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using HeuristicLab.Common;
+using HeuristicLab.Data;
+using HeuristicLab.Optimization;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  [StorableClass]
+  public abstract class RegressionSolutionBase : DataAnalysisSolution, IRegressionSolution {
+    protected const string TrainingMeanSquaredErrorResultName = "Mean squared error (training)";
+    protected const string TestMeanSquaredErrorResultName = "Mean squared error (test)";
+    protected const string TrainingMeanAbsoluteErrorResultName = "Mean absolute error (training)";
+    protected const string TestMeanAbsoluteErrorResultName = "Mean absolute error (test)";
+    protected const string TrainingSquaredCorrelationResultName = "Pearson's R² (training)";
+    protected const string TestSquaredCorrelationResultName = "Pearson's R² (test)";
+    protected const string TrainingRelativeErrorResultName = "Average relative error (training)";
+    protected const string TestRelativeErrorResultName = "Average relative error (test)";
+    protected const string TrainingNormalizedMeanSquaredErrorResultName = "Normalized mean squared error (training)";
+    protected const string TestNormalizedMeanSquaredErrorResultName = "Normalized mean squared error (test)";
+    protected const string TrainingRootMeanSquaredErrorResultName = "Root mean squared error (training)";
+    protected const string TestRootMeanSquaredErrorResultName = "Root mean squared error (test)";
+
+    // BackwardsCompatibility3.3
+    #region Backwards compatible code, remove with 3.5
+    private const string TrainingMeanErrorResultName = "Mean error (training)";
+    private const string TestMeanErrorResultName = "Mean error (test)";
+    #endregion
+
+
+    protected const string TrainingMeanSquaredErrorResultDescription = "Mean of squared errors of the model on the training partition";
+    protected const string TestMeanSquaredErrorResultDescription = "Mean of squared errors of the model on the test partition";
+    protected const string TrainingMeanAbsoluteErrorResultDescription = "Mean of absolute errors of the model on the training partition";
+    protected const string TestMeanAbsoluteErrorResultDescription = "Mean of absolute errors of the model on the test partition";
+    protected const string TrainingSquaredCorrelationResultDescription = "Squared Pearson's correlation coefficient of the model output and the actual values on the training partition";
+    protected const string TestSquaredCorrelationResultDescription = "Squared Pearson's correlation coefficient of the model output and the actual values on the test partition";
+    protected const string TrainingRelativeErrorResultDescription = "Average of the relative errors of the model output and the actual values on the training partition";
+    protected const string TestRelativeErrorResultDescription = "Average of the relative errors of the model output and the actual values on the test partition";
+    protected const string TrainingNormalizedMeanSquaredErrorResultDescription = "Normalized mean of squared errors of the model on the training partition";
+    protected const string TestNormalizedMeanSquaredErrorResultDescription = "Normalized mean of squared errors of the model on the test partition";
+    protected const string TrainingRootMeanSquaredErrorResultDescription = "Root mean of squared errors of the model on the training partition";
+    protected const string TestRootMeanSquaredErrorResultDescription = "Root mean of squared errors of the model on the test partition";
+
+    public new IRegressionModel Model {
+      get { return (IRegressionModel)base.Model; }
+      protected set { base.Model = value; }
+    }
+
+    public new IRegressionProblemData ProblemData {
+      get { return (IRegressionProblemData)base.ProblemData; }
+      set { base.ProblemData = value; }
+    }
+
+    public abstract IEnumerable<double> EstimatedValues { get; }
+    public abstract IEnumerable<double> EstimatedTrainingValues { get; }
+    public abstract IEnumerable<double> EstimatedTestValues { get; }
+    public abstract IEnumerable<double> GetEstimatedValues(IEnumerable<int> rows);
+
+    #region Results
+    public double TrainingMeanSquaredError {
+      get { return ((DoubleValue)this[TrainingMeanSquaredErrorResultName].Value).Value; }
+      private set { ((DoubleValue)this[TrainingMeanSquaredErrorResultName].Value).Value = value; }
+    }
+    public double TestMeanSquaredError {
+      get { return ((DoubleValue)this[TestMeanSquaredErrorResultName].Value).Value; }
+      private set { ((DoubleValue)this[TestMeanSquaredErrorResultName].Value).Value = value; }
+    }
+    public double TrainingMeanAbsoluteError {
+      get { return ((DoubleValue)this[TrainingMeanAbsoluteErrorResultName].Value).Value; }
+      private set { ((DoubleValue)this[TrainingMeanAbsoluteErrorResultName].Value).Value = value; }
+    }
+    public double TestMeanAbsoluteError {
+      get { return ((DoubleValue)this[TestMeanAbsoluteErrorResultName].Value).Value; }
+      private set { ((DoubleValue)this[TestMeanAbsoluteErrorResultName].Value).Value = value; }
+    }
+    public double TrainingRSquared {
+      get { return ((DoubleValue)this[TrainingSquaredCorrelationResultName].Value).Value; }
+      private set { ((DoubleValue)this[TrainingSquaredCorrelationResultName].Value).Value = value; }
+    }
+    public double TestRSquared {
+      get { return ((DoubleValue)this[TestSquaredCorrelationResultName].Value).Value; }
+      private set { ((DoubleValue)this[TestSquaredCorrelationResultName].Value).Value = value; }
+    }
+    public double TrainingRelativeError {
+      get { return ((DoubleValue)this[TrainingRelativeErrorResultName].Value).Value; }
+      private set { ((DoubleValue)this[TrainingRelativeErrorResultName].Value).Value = value; }
+    }
+    public double TestRelativeError {
+      get { return ((DoubleValue)this[TestRelativeErrorResultName].Value).Value; }
+      private set { ((DoubleValue)this[TestRelativeErrorResultName].Value).Value = value; }
+    }
+    public double TrainingNormalizedMeanSquaredError {
+      get { return ((DoubleValue)this[TrainingNormalizedMeanSquaredErrorResultName].Value).Value; }
+      private set { ((DoubleValue)this[TrainingNormalizedMeanSquaredErrorResultName].Value).Value = value; }
+    }
+    public double TestNormalizedMeanSquaredError {
+      get { return ((DoubleValue)this[TestNormalizedMeanSquaredErrorResultName].Value).Value; }
+      private set { ((DoubleValue)this[TestNormalizedMeanSquaredErrorResultName].Value).Value = value; }
+    }
+    public double TrainingRootMeanSquaredError {
+      get { return ((DoubleValue)this[TrainingRootMeanSquaredErrorResultName].Value).Value; }
+      private set { ((DoubleValue)this[TrainingRootMeanSquaredErrorResultName].Value).Value = value; }
+    }
+    public double TestRootMeanSquaredError {
+      get { return ((DoubleValue)this[TestRootMeanSquaredErrorResultName].Value).Value; }
+      private set { ((DoubleValue)this[TestRootMeanSquaredErrorResultName].Value).Value = value; }
+    }
+
+    // BackwardsCompatibility3.3
+    #region Backwards compatible code, remove with 3.5
+    private double TrainingMeanError {
+      get {
+        if (!ContainsKey(TrainingMeanErrorResultName)) return double.NaN;
+        return ((DoubleValue)this[TrainingMeanErrorResultName].Value).Value;
+      }
+      set {
+        if (ContainsKey(TrainingMeanErrorResultName))
+          ((DoubleValue)this[TrainingMeanErrorResultName].Value).Value = value;
+      }
+    }
+    private double TestMeanError {
+      get {
+        if (!ContainsKey(TestMeanErrorResultName)) return double.NaN;
+        return ((DoubleValue)this[TestMeanErrorResultName].Value).Value;
+      }
+      set {
+        if (ContainsKey(TestMeanErrorResultName))
+          ((DoubleValue)this[TestMeanErrorResultName].Value).Value = value;
+      }
+    }
+    #endregion
+    #endregion
+
+    [StorableConstructor]
+    protected RegressionSolutionBase(bool deserializing) : base(deserializing) { }
+    protected RegressionSolutionBase(RegressionSolutionBase original, Cloner cloner)
+      : base(original, cloner) {
+    }
+    protected RegressionSolutionBase(IRegressionModel model, IRegressionProblemData problemData)
+      : base(model, problemData) {
+      Add(new Result(TrainingMeanSquaredErrorResultName, TrainingMeanSquaredErrorResultDescription, new DoubleValue()));
+      Add(new Result(TestMeanSquaredErrorResultName, TestMeanSquaredErrorResultDescription, new DoubleValue()));
+      Add(new Result(TrainingMeanAbsoluteErrorResultName, TrainingMeanAbsoluteErrorResultDescription, new DoubleValue()));
+      Add(new Result(TestMeanAbsoluteErrorResultName, TestMeanAbsoluteErrorResultDescription, new DoubleValue()));
+      Add(new Result(TrainingSquaredCorrelationResultName, TrainingSquaredCorrelationResultDescription, new DoubleValue()));
+      Add(new Result(TestSquaredCorrelationResultName, TestSquaredCorrelationResultDescription, new DoubleValue()));
+      Add(new Result(TrainingRelativeErrorResultName, TrainingRelativeErrorResultDescription, new PercentValue()));
+      Add(new Result(TestRelativeErrorResultName, TestRelativeErrorResultDescription, new PercentValue()));
+      Add(new Result(TrainingNormalizedMeanSquaredErrorResultName, TrainingNormalizedMeanSquaredErrorResultDescription, new DoubleValue()));
+      Add(new Result(TestNormalizedMeanSquaredErrorResultName, TestNormalizedMeanSquaredErrorResultDescription, new DoubleValue()));
+      Add(new Result(TrainingRootMeanSquaredErrorResultName, TrainingRootMeanSquaredErrorResultDescription, new DoubleValue()));
+      Add(new Result(TestRootMeanSquaredErrorResultName, TestRootMeanSquaredErrorResultDescription, new DoubleValue()));
+    }
+
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() {
+      // BackwardsCompatibility3.4
+      #region Backwards compatible code, remove with 3.5
+      if (!ContainsKey(TrainingMeanAbsoluteErrorResultName)) {
+        OnlineCalculatorError errorState;
+        Add(new Result(TrainingMeanAbsoluteErrorResultName, "Mean of absolute errors of the model on the training partition", new DoubleValue()));
+        double trainingMAE = OnlineMeanAbsoluteErrorCalculator.Calculate(EstimatedTrainingValues, ProblemData.Dataset.GetDoubleValues(ProblemData.TargetVariable, ProblemData.TrainingIndices), out errorState);
+        TrainingMeanAbsoluteError = errorState == OnlineCalculatorError.None ? trainingMAE : double.NaN;
+      }
+
+      if (!ContainsKey(TestMeanAbsoluteErrorResultName)) {
+        OnlineCalculatorError errorState;
+        Add(new Result(TestMeanAbsoluteErrorResultName, "Mean of absolute errors of the model on the test partition", new DoubleValue()));
+        double testMAE = OnlineMeanAbsoluteErrorCalculator.Calculate(EstimatedTestValues, ProblemData.Dataset.GetDoubleValues(ProblemData.TargetVariable, ProblemData.TestIndices), out errorState);
+        TestMeanAbsoluteError = errorState == OnlineCalculatorError.None ? testMAE : double.NaN;
+      }
+
+      if (!ContainsKey(TrainingRootMeanSquaredErrorResultName)) {
+        OnlineCalculatorError errorState;
+        Add(new Result(TrainingRootMeanSquaredErrorResultName, TrainingRootMeanSquaredErrorResultDescription, new DoubleValue()));
+        double trainingMSE = OnlineMeanSquaredErrorCalculator.Calculate(EstimatedTrainingValues, ProblemData.Dataset.GetDoubleValues(ProblemData.TargetVariable, ProblemData.TrainingIndices), out errorState);
+        TrainingRootMeanSquaredError = errorState == OnlineCalculatorError.None ? Math.Sqrt(trainingMSE) : double.NaN;
+      }
+
+      if (!ContainsKey(TestRootMeanSquaredErrorResultName)) {
+        OnlineCalculatorError errorState;
+        Add(new Result(TestRootMeanSquaredErrorResultName, TestRootMeanSquaredErrorResultDescription, new DoubleValue()));
+        double testMSE = OnlineMeanSquaredErrorCalculator.Calculate(EstimatedTestValues, ProblemData.Dataset.GetDoubleValues(ProblemData.TargetVariable, ProblemData.TestIndices), out errorState);
+        TestRootMeanSquaredError = errorState == OnlineCalculatorError.None ? Math.Sqrt(testMSE) : double.NaN;
+      }
+      #endregion
+    }
+
+    protected override void RecalculateResults() {
+      CalculateRegressionResults();
+    }
+
+    protected void CalculateRegressionResults() {
+      IEnumerable<double> estimatedTrainingValues = EstimatedTrainingValues; // cache values
+      IEnumerable<double> originalTrainingValues = ProblemData.Dataset.GetDoubleValues(ProblemData.TargetVariable, ProblemData.TrainingIndices);
+      IEnumerable<double> estimatedTestValues = EstimatedTestValues; // cache values
+      IEnumerable<double> originalTestValues = ProblemData.Dataset.GetDoubleValues(ProblemData.TargetVariable, ProblemData.TestIndices);
+
+      OnlineCalculatorError errorState;
+      double trainingMSE = OnlineMeanSquaredErrorCalculator.Calculate(originalTrainingValues, estimatedTrainingValues, out errorState);
+      TrainingMeanSquaredError = errorState == OnlineCalculatorError.None ? trainingMSE : double.NaN;
+      double testMSE = OnlineMeanSquaredErrorCalculator.Calculate(originalTestValues, estimatedTestValues, out errorState);
+      TestMeanSquaredError = errorState == OnlineCalculatorError.None ? testMSE : double.NaN;
+
+      double trainingMAE = OnlineMeanAbsoluteErrorCalculator.Calculate(originalTrainingValues, estimatedTrainingValues, out errorState);
+      TrainingMeanAbsoluteError = errorState == OnlineCalculatorError.None ? trainingMAE : double.NaN;
+      double testMAE = OnlineMeanAbsoluteErrorCalculator.Calculate(originalTestValues, estimatedTestValues, out errorState);
+      TestMeanAbsoluteError = errorState == OnlineCalculatorError.None ? testMAE : double.NaN;
+
+      double trainingR = OnlinePearsonsRCalculator.Calculate(originalTrainingValues, estimatedTrainingValues, out errorState);
+      TrainingRSquared = errorState == OnlineCalculatorError.None ? trainingR*trainingR : double.NaN;
+      double testR = OnlinePearsonsRCalculator.Calculate(originalTestValues, estimatedTestValues, out errorState);
+      TestRSquared = errorState == OnlineCalculatorError.None ? testR*testR : double.NaN;
+
+      double trainingRelError = OnlineMeanAbsolutePercentageErrorCalculator.Calculate(originalTrainingValues, estimatedTrainingValues, out errorState);
+      TrainingRelativeError = errorState == OnlineCalculatorError.None ? trainingRelError : double.NaN;
+      double testRelError = OnlineMeanAbsolutePercentageErrorCalculator.Calculate(originalTestValues, estimatedTestValues, out errorState);
+      TestRelativeError = errorState == OnlineCalculatorError.None ? testRelError : double.NaN;
+
+      double trainingNMSE = OnlineNormalizedMeanSquaredErrorCalculator.Calculate(originalTrainingValues, estimatedTrainingValues, out errorState);
+      TrainingNormalizedMeanSquaredError = errorState == OnlineCalculatorError.None ? trainingNMSE : double.NaN;
+      double testNMSE = OnlineNormalizedMeanSquaredErrorCalculator.Calculate(originalTestValues, estimatedTestValues, out errorState);
+      TestNormalizedMeanSquaredError = errorState == OnlineCalculatorError.None ? testNMSE : double.NaN;
+
+      TrainingRootMeanSquaredError = Math.Sqrt(TrainingMeanSquaredError);
+      TestRootMeanSquaredError = Math.Sqrt(TestMeanSquaredError);
+
+      // BackwardsCompatibility3.3
+      #region Backwards compatible code, remove with 3.5
+      if (ContainsKey(TrainingMeanErrorResultName)) {
+        double trainingME = OnlineMeanErrorCalculator.Calculate(originalTrainingValues, estimatedTrainingValues, out errorState);
+        TrainingMeanError = errorState == OnlineCalculatorError.None ? trainingME : double.NaN;
+      }
+      if (ContainsKey(TestMeanErrorResultName)) {
+        double testME = OnlineMeanErrorCalculator.Calculate(originalTestValues, estimatedTestValues, out errorState);
+        TestMeanError = errorState == OnlineCalculatorError.None ? testME : double.NaN;
+      }
+      #endregion
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/RegressionSolutionVariableImpactsCalculator.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/RegressionSolutionVariableImpactsCalculator.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/RegressionSolutionVariableImpactsCalculator.cs	(revision 13819)
@@ -0,0 +1,160 @@
+﻿#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.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  [StorableClass]
+  [Item("RegressionSolution Impacts Calculator", "Calculation of the impacts of input variables for a concrete ")]
+  public sealed class RegressionSolutionVariableImpactsCalculator : ParameterizedNamedItem {
+    public enum ReplacementMethodEnum {
+      Median,
+      Average
+    }
+
+    public enum DataPartitionEnum {
+      Training,
+      Test,
+      All
+    }
+
+    private const string ReplacementParameterName = "Replacement Method";
+    private const string DataPartitionParameterName = "DataPartition";
+
+    public IFixedValueParameter<EnumValue<ReplacementMethodEnum>> ReplacementParameter {
+      get { return (IFixedValueParameter<EnumValue<ReplacementMethodEnum>>)Parameters[ReplacementParameterName]; }
+    }
+    public IFixedValueParameter<EnumValue<DataPartitionEnum>> DataPartitionParameter {
+      get { return (IFixedValueParameter<EnumValue<DataPartitionEnum>>)Parameters[DataPartitionParameterName]; }
+    }
+
+    public ReplacementMethodEnum ReplacementMethod {
+      get { return ReplacementParameter.Value.Value; }
+      set { ReplacementParameter.Value.Value = value; }
+    }
+    public DataPartitionEnum DataPartition {
+      get { return DataPartitionParameter.Value.Value; }
+      set { DataPartitionParameter.Value.Value = value; }
+    }
+
+
+    [StorableConstructor]
+    private RegressionSolutionVariableImpactsCalculator(bool deserializing) : base(deserializing) { }
+    private RegressionSolutionVariableImpactsCalculator(RegressionSolutionVariableImpactsCalculator original, Cloner cloner)
+      : base(original, cloner) { }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new RegressionSolutionVariableImpactsCalculator(this, cloner);
+    }
+
+    public RegressionSolutionVariableImpactsCalculator()
+      : base() {
+      Parameters.Add(new FixedValueParameter<EnumValue<ReplacementMethodEnum>>(ReplacementParameterName, "The replacement method for variables during impact calculation.", new EnumValue<ReplacementMethodEnum>(ReplacementMethodEnum.Median)));
+      Parameters.Add(new FixedValueParameter<EnumValue<DataPartitionEnum>>(ReplacementParameterName, "The data partition on which the impacts are calculated.", new EnumValue<DataPartitionEnum>(DataPartitionEnum.Training)));
+    }
+
+    //mkommend: annoying name clash with static method, open to better naming suggestions
+    public IEnumerable<Tuple<string, double>> Calculate(IRegressionSolution solution) {
+      return CalculateImpacts(solution, DataPartition, ReplacementMethod);
+    }
+
+    public static IEnumerable<Tuple<string, double>> CalculateImpacts(IRegressionSolution solution,
+      DataPartitionEnum data = DataPartitionEnum.Training,
+      ReplacementMethodEnum replacement = ReplacementMethodEnum.Median) {
+
+      var problemData = solution.ProblemData;
+      var dataset = problemData.Dataset;
+
+      IEnumerable<int> rows;
+      IEnumerable<double> targetValues;
+      double originalR2 = -1;
+
+      OnlineCalculatorError error;
+
+      switch (data) {
+        case DataPartitionEnum.All:
+          rows = solution.ProblemData.AllIndices;
+          targetValues = problemData.TargetVariableValues.ToList();
+          originalR2 = OnlinePearsonsRCalculator.Calculate(problemData.TargetVariableValues, solution.EstimatedValues, out error);
+          if (error != OnlineCalculatorError.None) throw new InvalidOperationException("Error during R² calculation.");
+          originalR2 = originalR2 * originalR2;
+          break;
+        case DataPartitionEnum.Training:
+          rows = problemData.TrainingIndices;
+          targetValues = problemData.TargetVariableTrainingValues.ToList();
+          originalR2 = solution.TrainingRSquared;
+          break;
+        case DataPartitionEnum.Test:
+          rows = problemData.TestIndices;
+          targetValues = problemData.TargetVariableTestValues.ToList();
+          originalR2 = solution.TestRSquared;
+          break;
+        default: throw new ArgumentException(string.Format("DataPartition {0} cannot be handled.", data));
+      }
+
+
+      var impacts = new Dictionary<string, double>();
+      var modifiableDataset = ((Dataset)dataset).ToModifiable();
+
+      foreach (var inputVariable in problemData.AllowedInputVariables) {
+        var newEstimates = EvaluateModelWithReplacedVariable(solution.Model, inputVariable, modifiableDataset, rows, replacement);
+        var newR2 = OnlinePearsonsRCalculator.Calculate(targetValues, newEstimates, out error);
+        if (error != OnlineCalculatorError.None) throw new InvalidOperationException("Error during R² calculation with replaced inputs.");
+
+        newR2 = newR2 * newR2;
+        var impact = originalR2 - newR2;
+        impacts[inputVariable] = impact;
+      }
+      return impacts.OrderByDescending(i => i.Value).Select(i => Tuple.Create(i.Key, i.Value));
+    }
+
+    private static IEnumerable<double> EvaluateModelWithReplacedVariable(IRegressionModel model, string variable, ModifiableDataset dataset, IEnumerable<int> rows, ReplacementMethodEnum replacement = ReplacementMethodEnum.Median) {
+      var originalValues = dataset.GetReadOnlyDoubleValues(variable).ToList();
+      double replacementValue;
+
+      switch (replacement) {
+        case ReplacementMethodEnum.Median:
+          replacementValue = rows.Select(r => originalValues[r]).Median();
+          break;
+        case ReplacementMethodEnum.Average:
+          replacementValue = rows.Select(r => originalValues[r]).Average();
+          break;
+        default:
+          throw new ArgumentException(string.Format("ReplacementMethod {0} cannot be handled.", replacement));
+      }
+
+      dataset.ReplaceVariable(variable, Enumerable.Repeat(replacementValue, dataset.Rows).ToList());
+      //mkommend: ToList is used on purpose to avoid lazy evaluation that could result in wrong estimates due to variable replacements
+      var estimates = model.GetEstimatedValues(dataset, rows).ToList();
+      dataset.ReplaceVariable(variable, originalValues);
+
+      return estimates;
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/TimeSeriesPrognosis/Models/ConstantTimeSeriesPrognosisModel.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/TimeSeriesPrognosis/Models/ConstantTimeSeriesPrognosisModel.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/TimeSeriesPrognosis/Models/ConstantTimeSeriesPrognosisModel.cs	(revision 13819)
@@ -0,0 +1,51 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  [StorableClass]
+  [Item("Constant TimeSeries Model", "A time series model that returns for all prediciton the same constant value.")]
+  [Obsolete]
+  public class ConstantTimeSeriesPrognosisModel : ConstantRegressionModel, ITimeSeriesPrognosisModel {
+    [StorableConstructor]
+    protected ConstantTimeSeriesPrognosisModel(bool deserializing) : base(deserializing) { }
+    protected ConstantTimeSeriesPrognosisModel(ConstantTimeSeriesPrognosisModel original, Cloner cloner) : base(original, cloner) { }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new ConstantTimeSeriesPrognosisModel(this, cloner);
+    }
+
+    public ConstantTimeSeriesPrognosisModel(double constant) : base(constant) { }
+
+    public IEnumerable<IEnumerable<double>> GetPrognosedValues(IDataset dataset, IEnumerable<int> rows, IEnumerable<int> horizons) {
+      return horizons.Select(horizon => Enumerable.Repeat(Constant, horizon));
+    }
+
+    public ITimeSeriesPrognosisSolution CreateTimeSeriesPrognosisSolution(ITimeSeriesPrognosisProblemData problemData) {
+      return new TimeSeriesPrognosisSolution(this, new TimeSeriesPrognosisProblemData(problemData));
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/TimeSeriesPrognosis/Models/TimeSeriesPrognosisAutoRegressiveModel.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/TimeSeriesPrognosis/Models/TimeSeriesPrognosisAutoRegressiveModel.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/TimeSeriesPrognosis/Models/TimeSeriesPrognosisAutoRegressiveModel.cs	(revision 13819)
@@ -0,0 +1,118 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  [StorableClass]
+  [Item("Autoregressive TimeSeries Model", "A linear autoregressive time series model used to predict future values.")]
+  public class TimeSeriesPrognosisAutoRegressiveModel : NamedItem, ITimeSeriesPrognosisModel {
+    [Storable]
+    public double[] Phi { get; private set; }
+    [Storable]
+    public double Constant { get; private set; }
+    [Storable]
+    public string TargetVariable { get; private set; }
+
+    public int TimeOffset { get { return Phi.Length; } }
+
+    [StorableConstructor]
+    protected TimeSeriesPrognosisAutoRegressiveModel(bool deserializing) : base(deserializing) { }
+    protected TimeSeriesPrognosisAutoRegressiveModel(TimeSeriesPrognosisAutoRegressiveModel original, Cloner cloner)
+      : base(original, cloner) {
+      this.Phi = (double[])original.Phi.Clone();
+      this.Constant = original.Constant;
+      this.TargetVariable = original.TargetVariable;
+    }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new TimeSeriesPrognosisAutoRegressiveModel(this, cloner);
+    }
+    public TimeSeriesPrognosisAutoRegressiveModel(string targetVariable, double[] phi, double constant)
+      : base("AR(1) Model") {
+      Phi = (double[])phi.Clone();
+      Constant = constant;
+      TargetVariable = targetVariable;
+    }
+
+    public IEnumerable<IEnumerable<double>> GetPrognosedValues(IDataset dataset, IEnumerable<int> rows, IEnumerable<int> horizons) {
+      var rowsEnumerator = rows.GetEnumerator();
+      var horizonsEnumerator = horizons.GetEnumerator();
+      var targetValues = dataset.GetReadOnlyDoubleValues(TargetVariable);
+      // produce a n-step forecast for all rows
+      while (rowsEnumerator.MoveNext() & horizonsEnumerator.MoveNext()) {
+        int row = rowsEnumerator.Current;
+        int horizon = horizonsEnumerator.Current;
+        if (row - TimeOffset < 0) {
+          yield return Enumerable.Repeat(double.NaN, horizon);
+          continue;
+        }
+
+        double[] prognosis = new double[horizon];
+        for (int h = 0; h < horizon; h++) {
+          double estimatedValue = 0.0;
+          for (int i = 1; i <= TimeOffset; i++) {
+            int offset = h - i;
+            if (offset >= 0) estimatedValue += prognosis[offset] * Phi[i - 1];
+            else estimatedValue += targetValues[row + offset] * Phi[i - 1];
+
+          }
+          estimatedValue += Constant;
+          prognosis[h] = estimatedValue;
+        }
+
+        yield return prognosis;
+      }
+
+      if (rowsEnumerator.MoveNext() || horizonsEnumerator.MoveNext())
+        throw new ArgumentException("Number of elements in rows and horizon enumerations doesn't match.");
+    }
+
+    public IEnumerable<double> GetEstimatedValues(IDataset dataset, IEnumerable<int> rows) {
+      var targetVariables = dataset.GetReadOnlyDoubleValues(TargetVariable);
+      foreach (int row in rows) {
+        double estimatedValue = 0.0;
+        if (row - TimeOffset < 0) {
+          yield return double.NaN;
+          continue;
+        }
+
+        for (int i = 1; i <= TimeOffset; i++) {
+          estimatedValue += targetVariables[row - i] * Phi[i - 1];
+        }
+        estimatedValue += Constant;
+        yield return estimatedValue;
+      }
+    }
+
+    public ITimeSeriesPrognosisSolution CreateTimeSeriesPrognosisSolution(ITimeSeriesPrognosisProblemData problemData) {
+      return new TimeSeriesPrognosisSolution(this, new TimeSeriesPrognosisProblemData(problemData));
+    }
+    public IRegressionSolution CreateRegressionSolution(IRegressionProblemData problemData) {
+      throw new NotSupportedException();
+    }
+
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/TimeSeriesPrognosis/TimeSeriesPrognosisProblem.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/TimeSeriesPrognosis/TimeSeriesPrognosisProblem.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/TimeSeriesPrognosis/TimeSeriesPrognosisProblem.cs	(revision 13819)
@@ -0,0 +1,37 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  [StorableClass]
+  [Item("Time-series Prognosis Problem", "A general time-series prognosis problem.")]
+  public class TimeSeriesPrognosisProblem : DataAnalysisProblem<ITimeSeriesPrognosisProblemData>, ITimeSeriesPrognosisProblem {
+    [StorableConstructor]
+    protected TimeSeriesPrognosisProblem(bool deserializing) : base(deserializing) { }
+    protected TimeSeriesPrognosisProblem(TimeSeriesPrognosisProblem original, Cloner cloner) : base(original, cloner) { }
+    public override IDeepCloneable Clone(Cloner cloner) { return new TimeSeriesPrognosisProblem(this, cloner); }
+
+    public TimeSeriesPrognosisProblem() : base(new TimeSeriesPrognosisProblemData()) { }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/TimeSeriesPrognosis/TimeSeriesPrognosisProblemData.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/TimeSeriesPrognosis/TimeSeriesPrognosisProblemData.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/TimeSeriesPrognosis/TimeSeriesPrognosisProblemData.cs	(revision 13819)
@@ -0,0 +1,1655 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  [StorableClass]
+  [Item("TimeSeriesPrognosisProblemData", "Represents an item containing all data defining a time series prognosis problem.")]
+  public class TimeSeriesPrognosisProblemData : RegressionProblemData, ITimeSeriesPrognosisProblemData {
+    #region default data
+    private static double[,] mackey_glass_17 = new double[,] {
+{9.0000000e-01},
+{9.0000000e-01},
+{9.0000000e-01},
+{9.4136145e-01},
+{1.1188041e+00},
+{1.2161867e+00},
+{1.2476827e+00},
+{1.0067861e+00},
+{7.1297054e-01},
+{5.0349420e-01},
+{5.8392542e-01},
+{9.4327347e-01},
+{1.0178784e+00},
+{1.0346794e+00},
+{1.1640420e+00},
+{1.0670009e+00},
+{1.0026658e+00},
+{7.7000347e-01},
+{7.0782984e-01},
+{7.9370192e-01},
+{1.0558440e+00},
+{1.2000510e+00},
+{1.2998549e+00},
+{1.1857500e+00},
+{8.4250325e-01},
+{5.5885374e-01},
+{4.2572016e-01},
+{7.5043060e-01},
+{9.7291951e-01},
+{9.3785503e-01},
+{1.0653587e+00},
+{1.1355961e+00},
+{1.1533842e+00},
+{1.0678134e+00},
+{8.1349649e-01},
+{6.6246660e-01},
+{6.2210481e-01},
+{9.3890430e-01},
+{1.1287058e+00},
+{1.1699535e+00},
+{1.2412759e+00},
+{9.8090748e-01},
+{7.3311051e-01},
+{5.2596003e-01},
+{6.3134850e-01},
+{9.7849655e-01},
+{1.0578901e+00},
+{1.0888001e+00},
+{1.1681297e+00},
+{9.9896471e-01},
+{8.7928027e-01},
+{6.6864116e-01},
+{7.3694626e-01},
+{9.7850487e-01},
+{1.1571565e+00},
+{1.2440406e+00},
+{1.2532851e+00},
+{9.3967388e-01},
+{6.5403177e-01},
+{4.5549437e-01},
+{6.4110939e-01},
+{9.6727507e-01},
+{9.8419122e-01},
+{1.0332443e+00},
+{1.1440570e+00},
+{1.0922307e+00},
+{1.0485820e+00},
+{8.0447560e-01},
+{7.1465526e-01},
+{7.1296010e-01},
+{9.9300973e-01},
+{1.1766813e+00},
+{1.2618288e+00},
+{1.2517022e+00},
+{9.2078170e-01},
+{6.2369710e-01},
+{4.3562308e-01},
+{6.4988558e-01},
+{9.5895791e-01},
+{9.5866122e-01},
+{1.0183775e+00},
+{1.1415533e+00},
+{1.1289579e+00},
+{1.1022163e+00},
+{8.4414928e-01},
+{6.9891813e-01},
+{6.2493643e-01},
+{9.0049230e-01},
+{1.1246569e+00},
+{1.1850486e+00},
+{1.2646400e+00},
+{1.0193893e+00},
+{7.3830722e-01},
+{5.1921750e-01},
+{5.6836076e-01},
+{9.3609361e-01},
+{1.0324202e+00},
+{1.0360676e+00},
+{1.1675966e+00},
+{1.0504944e+00},
+{9.8129158e-01},
+{7.5798016e-01},
+{7.1660079e-01},
+{8.3950658e-01},
+{1.0870027e+00},
+{1.2170776e+00},
+{1.3123779e+00},
+{1.1361782e+00},
+{7.9337369e-01},
+{5.2230472e-01},
+{4.3857925e-01},
+{8.0873950e-01},
+{9.7422631e-01},
+{9.3291515e-01},
+{1.0947530e+00},
+{1.1335086e+00},
+{1.1645714e+00},
+{1.0315895e+00},
+{7.9058261e-01},
+{6.3878936e-01},
+{6.4385427e-01},
+{9.7290237e-01},
+{1.1330941e+00},
+{1.1738960e+00},
+{1.2210669e+00},
+{9.4813374e-01},
+{7.1548595e-01},
+{5.2046031e-01},
+{6.8100333e-01},
+{1.0072944e+00},
+{1.0641199e+00},
+{1.1194312e+00},
+{1.1522817e+00},
+{9.7118023e-01},
+{8.2966445e-01},
+{6.3876024e-01},
+{7.6770138e-01},
+{1.0325752e+00},
+{1.1660632e+00},
+{1.2543878e+00},
+{1.1956003e+00},
+{8.7571542e-01},
+{6.1252082e-01},
+{4.5699619e-01},
+{7.4030148e-01},
+{1.0017485e+00},
+{9.8958385e-01},
+{1.0949833e+00},
+{1.1249612e+00},
+{1.0658962e+00},
+{9.5636335e-01},
+{7.4498806e-01},
+{7.2563393e-01},
+{8.3530455e-01},
+{1.0977307e+00},
+{1.2314926e+00},
+{1.3167422e+00},
+{1.1172604e+00},
+{7.6900341e-01},
+{5.0549771e-01},
+{4.4450990e-01},
+{8.2808038e-01},
+{9.6930396e-01},
+{9.2772189e-01},
+{1.1010458e+00},
+{1.1366939e+00},
+{1.1770457e+00},
+{1.0282839e+00},
+{7.8657093e-01},
+{6.2340354e-01},
+{6.3476140e-01},
+{9.6941037e-01},
+{1.1224823e+00},
+{1.1576217e+00},
+{1.2147442e+00},
+{9.5631199e-01},
+{7.3947874e-01},
+{5.4187646e-01},
+{6.8681641e-01},
+{1.0131445e+00},
+{1.0865854e+00},
+{1.1414849e+00},
+{1.1594630e+00},
+{9.4411600e-01},
+{7.7794034e-01},
+{5.9741518e-01},
+{7.7225037e-01},
+{1.0587360e+00},
+{1.1485933e+00},
+{1.2344562e+00},
+{1.1458853e+00},
+{8.5415118e-01},
+{6.2127481e-01},
+{4.9756097e-01},
+{8.0931406e-01},
+{1.0430891e+00},
+{1.0367506e+00},
+{1.1608048e+00},
+{1.0902522e+00},
+{9.6945804e-01},
+{7.9607346e-01},
+{6.7035674e-01},
+{8.2493000e-01},
+{1.0685565e+00},
+{1.1912458e+00},
+{1.2916937e+00},
+{1.1585237e+00},
+{8.2653804e-01},
+{5.5624667e-01},
+{4.4364773e-01},
+{7.8679896e-01},
+{9.8947432e-01},
+{9.5587476e-01},
+{1.0976735e+00},
+{1.1247419e+00},
+{1.1220470e+00},
+{9.9754667e-01},
+{7.7406653e-01},
+{6.7630712e-01},
+{7.2445263e-01},
+{1.0303591e+00},
+{1.1801427e+00},
+{1.2506686e+00},
+{1.1989987e+00},
+{8.7114663e-01},
+{6.0602798e-01},
+{4.5163741e-01},
+{7.3553573e-01},
+{9.9456302e-01},
+{9.8098646e-01},
+{1.0857031e+00},
+{1.1289641e+00},
+{1.0828069e+00},
+{9.8224963e-01},
+{7.5966277e-01},
+{7.1111527e-01},
+{7.8645769e-01},
+{1.0673541e+00},
+{1.2116816e+00},
+{1.2990734e+00},
+{1.1657704e+00},
+{8.1779454e-01},
+{5.4428063e-01},
+{4.3047549e-01},
+{7.7832590e-01},
+{9.7551443e-01},
+{9.3705618e-01},
+{1.0807206e+00},
+{1.1339189e+00},
+{1.1551319e+00},
+{1.0473610e+00},
+{8.0021464e-01},
+{6.5377513e-01},
+{6.3810292e-01},
+{9.6140773e-01},
+{1.1354401e+00},
+{1.1782311e+00},
+{1.2323246e+00},
+{9.5811452e-01},
+{7.1400985e-01},
+{5.1434848e-01},
+{6.5876782e-01},
+{9.9374878e-01},
+{1.0532057e+00},
+{1.0987291e+00},
+{1.1569941e+00},
+{9.9327584e-01},
+{8.7055783e-01},
+{6.6607204e-01},
+{7.5154249e-01},
+{9.9147904e-01},
+{1.1618652e+00},
+{1.2531013e+00},
+{1.2445235e+00},
+{9.2459418e-01},
+{6.3924685e-01},
+{4.4899067e-01},
+{6.5946924e-01},
+{9.7165260e-01},
+{9.7791817e-01},
+{1.0391898e+00},
+{1.1412631e+00},
+{1.0983393e+00},
+{1.0493420e+00},
+{8.0399406e-01},
+{7.0992449e-01},
+{7.0350356e-01},
+{9.8952236e-01},
+{1.1734521e+00},
+{1.2538876e+00},
+{1.2508500e+00},
+{9.2423636e-01},
+{6.3070030e-01},
+{4.4136962e-01},
+{6.4946966e-01},
+{9.6197955e-01},
+{9.6606332e-01},
+{1.0237953e+00},
+{1.1421522e+00},
+{1.1183774e+00},
+{1.0857179e+00},
+{8.3157725e-01},
+{7.0250588e-01},
+{6.4917325e-01},
+{9.2959329e-01},
+{1.1407976e+00},
+{1.2080261e+00},
+{1.2684960e+00},
+{9.9122930e-01},
+{7.0220017e-01},
+{4.8816416e-01},
+{5.8586111e-01},
+{9.4668329e-01},
+{1.0087590e+00},
+{1.0232927e+00},
+{1.1559444e+00},
+{1.0720927e+00},
+{1.0286336e+00},
+{7.9460252e-01},
+{7.2093651e-01},
+{7.6292167e-01},
+{1.0248985e+00},
+{1.1929944e+00},
+{1.2920208e+00},
+{1.2293181e+00},
+{8.8290244e-01},
+{5.8527613e-01},
+{4.1855360e-01},
+{6.9074767e-01},
+{9.5977708e-01},
+{9.3601019e-01},
+{1.0268467e+00},
+{1.1397909e+00},
+{1.1581327e+00},
+{1.1205956e+00},
+{8.5280669e-01},
+{6.7763483e-01},
+{5.7983286e-01},
+{8.6429914e-01},
+{1.0976939e+00},
+{1.1367408e+00},
+{1.2374931e+00},
+{1.0493382e+00},
+{8.0588138e-01},
+{5.9127581e-01},
+{5.7929225e-01},
+{9.2472931e-01},
+{1.0849831e+00},
+{1.0943246e+00},
+{1.2041235e+00},
+{1.0091917e+00},
+{8.4987188e-01},
+{6.3876182e-01},
+{6.7747918e-01},
+{9.7202288e-01},
+{1.1405471e+00},
+{1.1943368e+00},
+{1.2338428e+00},
+{9.4462558e-01},
+{6.9738430e-01},
+{4.9856007e-01},
+{6.6823589e-01},
+{9.9611375e-01},
+{1.0393748e+00},
+{1.0920087e+00},
+{1.1489492e+00},
+{1.0066576e+00},
+{8.9589007e-01},
+{6.8845995e-01},
+{7.5294149e-01},
+{9.6184563e-01},
+{1.1555071e+00},
+{1.2567316e+00},
+{1.2751778e+00},
+{9.6335246e-01},
+{6.5830948e-01},
+{4.4799275e-01},
+{5.9888825e-01},
+{9.4430988e-01},
+{9.6837958e-01},
+{9.9677549e-01},
+{1.1434629e+00},
+{1.1210684e+00},
+{1.1148356e+00},
+{8.6401556e-01},
+{7.1420118e-01},
+{6.2999725e-01},
+{8.7537864e-01},
+{1.1167941e+00},
+{1.1896694e+00},
+{1.2722030e+00},
+{1.0454715e+00},
+{7.4997564e-01},
+{5.2383173e-01},
+{5.3664145e-01},
+{9.1117041e-01},
+{1.0244044e+00},
+{1.0151287e+00},
+{1.1633675e+00},
+{1.0695966e+00},
+{1.0183575e+00},
+{8.0087884e-01},
+{7.1535296e-01},
+{7.8553095e-01},
+{1.0319822e+00},
+{1.1937155e+00},
+{1.2977947e+00},
+{1.2217806e+00},
+{8.7524512e-01},
+{5.7851885e-01},
+{4.1763620e-01},
+{7.0155638e-01},
+{9.6135267e-01},
+{9.3393602e-01},
+{1.0323424e+00},
+{1.1394608e+00},
+{1.1605598e+00},
+{1.1161968e+00},
+{8.4854339e-01},
+{6.7338626e-01},
+{5.7982826e-01},
+{8.7043086e-01},
+{1.0990834e+00},
+{1.1357404e+00},
+{1.2369383e+00},
+{1.0441753e+00},
+{8.0417958e-01},
+{5.9002711e-01},
+{5.8533894e-01},
+{9.3051649e-01},
+{1.0871279e+00},
+{1.0984983e+00},
+{1.2044155e+00},
+{1.0039892e+00},
+{8.4210523e-01},
+{6.3124655e-01},
+{6.8055115e-01},
+{9.7935183e-01},
+{1.1399170e+00},
+{1.1935307e+00},
+{1.2269029e+00},
+{9.3758049e-01},
+{6.9527243e-01},
+{5.0033084e-01},
+{6.8171448e-01},
+{1.0034848e+00},
+{1.0435853e+00},
+{1.1027381e+00},
+{1.1454200e+00},
+{9.9636446e-01},
+{8.7575610e-01},
+{6.7572455e-01},
+{7.6161436e-01},
+{9.8751885e-01},
+{1.1634852e+00},
+{1.2613366e+00},
+{1.2527158e+00},
+{9.3041078e-01},
+{6.3648886e-01},
+{4.4289908e-01},
+{6.4543043e-01},
+{9.6271252e-01},
+{9.6856037e-01},
+{1.0237816e+00},
+{1.1419384e+00},
+{1.1143808e+00},
+{1.0817980e+00},
+{8.2952128e-01},
+{7.0565231e-01},
+{6.5745758e-01},
+{9.3688510e-01},
+{1.1457239e+00},
+{1.2160319e+00},
+{1.2696485e+00},
+{9.8373294e-01},
+{6.9141844e-01},
+{4.7910268e-01},
+{5.8995166e-01},
+{9.4754885e-01},
+{1.0004197e+00},
+{1.0182334e+00},
+{1.1527974e+00},
+{1.0815601e+00},
+{1.0462772e+00},
+{8.0856012e-01},
+{7.2009150e-01},
+{7.3360533e-01},
+{9.9726771e-01},
+{1.1799228e+00},
+{1.2752553e+00},
+{1.2545993e+00},
+{9.1834232e-01},
+{6.1478702e-01},
+{4.2718988e-01},
+{6.4709630e-01},
+{9.5321724e-01},
+{9.4745071e-01},
+{1.0082615e+00},
+{1.1408283e+00},
+{1.1449070e+00},
+{1.1287695e+00},
+{8.6506953e-01},
+{6.9506068e-01},
+{5.9077914e-01},
+{8.5235412e-01},
+{1.0981812e+00},
+{1.1502068e+00},
+{1.2457878e+00},
+{1.0606248e+00},
+{7.9743949e-01},
+{5.7871635e-01},
+{5.5597309e-01},
+{9.0976389e-01},
+{1.0678545e+00},
+{1.0678466e+00},
+{1.1926843e+00},
+{1.0306506e+00},
+{9.0068600e-01},
+{6.8968565e-01},
+{6.8293693e-01},
+{9.2938386e-01},
+{1.1389931e+00},
+{1.2107723e+00},
+{1.2742112e+00},
+{9.9571305e-01},
+{7.0900966e-01},
+{4.8711002e-01},
+{5.7843327e-01},
+{9.4262722e-01},
+{1.0068885e+00},
+{1.0174671e+00},
+{1.1549847e+00},
+{1.0752383e+00},
+{1.0382561e+00},
+{8.0493588e-01},
+{7.2297438e-01},
+{7.5109199e-01},
+{1.0099650e+00},
+{1.1869526e+00},
+{1.2859723e+00},
+{1.2455314e+00},
+{9.0247113e-01},
+{5.9968946e-01},
+{4.2056794e-01},
+{6.6467784e-01},
+{9.5461231e-01},
+{9.3926954e-01},
+{1.0128964e+00},
+{1.1403075e+00},
+{1.1549599e+00},
+{1.1335031e+00},
+{8.6584651e-01},
+{6.8689154e-01},
+{5.7663890e-01},
+{8.4338430e-01},
+{1.0904343e+00},
+{1.1347127e+00},
+{1.2344704e+00},
+{1.0665197e+00},
+{8.1831436e-01},
+{6.0374950e-01},
+{5.6609914e-01},
+{9.0609488e-01},
+{1.0837698e+00},
+{1.0903349e+00},
+{1.2068005e+00},
+{1.0215332e+00},
+{8.5834739e-01},
+{6.4797779e-01},
+{6.6278967e-01},
+{9.5567807e-01},
+{1.1370612e+00},
+{1.1868501e+00},
+{1.2426235e+00},
+{9.6133342e-01},
+{7.1189926e-01},
+{5.0582127e-01},
+{6.4642134e-01},
+{9.8585814e-01},
+{1.0428580e+00},
+{1.0831242e+00},
+{1.1568123e+00},
+{1.0097872e+00},
+{9.0412446e-01},
+{6.9144384e-01},
+{7.4452934e-01},
+{9.5158341e-01},
+{1.1512270e+00},
+{1.2509608e+00},
+{1.2807229e+00},
+{9.7601316e-01},
+{6.6959369e-01},
+{4.5362019e-01},
+{5.8397806e-01},
+{9.3866865e-01},
+{9.7211974e-01},
+{9.9154526e-01},
+{1.1440232e+00},
+{1.1182310e+00},
+{1.1159711e+00},
+{8.6902975e-01},
+{7.1839537e-01},
+{6.3437176e-01},
+{8.7058758e-01},
+{1.1155207e+00},
+{1.1929730e+00},
+{1.2750340e+00},
+{1.0511137e+00},
+{7.5075715e-01},
+{5.2249794e-01},
+{5.2857771e-01},
+{9.0479637e-01},
+{1.0201490e+00},
+{1.0078239e+00},
+{1.1602784e+00},
+{1.0762699e+00},
+{1.0328279e+00},
+{8.1754050e-01},
+{7.1739458e-01},
+{7.6521302e-01},
+{1.0063562e+00},
+{1.1829441e+00},
+{1.2880301e+00},
+{1.2505618e+00},
+{9.0963666e-01},
+{6.0373594e-01},
+{4.2059572e-01},
+{6.5552332e-01},
+{9.5216646e-01},
+{9.3915492e-01},
+{1.0073402e+00},
+{1.1402595e+00},
+{1.1555473e+00},
+{1.1400569e+00},
+{8.7240707e-01},
+{6.8972093e-01},
+{5.7304964e-01},
+{8.3155186e-01},
+{1.0852244e+00},
+{1.1309096e+00},
+{1.2300408e+00},
+{1.0756716e+00},
+{8.2836037e-01},
+{6.1503305e-01},
+{5.6289537e-01},
+{8.9596963e-01},
+{1.0857176e+00},
+{1.0933045e+00},
+{1.2103223e+00},
+{1.0266092e+00},
+{8.5466111e-01},
+{6.4485312e-01},
+{6.5137619e-01},
+{9.5039035e-01},
+{1.1326982e+00},
+{1.1771304e+00},
+{1.2406618e+00},
+{9.6686921e-01},
+{7.2402007e-01},
+{5.1657512e-01},
+{6.4610863e-01},
+{9.8716024e-01},
+{1.0536774e+00},
+{1.0920775e+00},
+{1.1611436e+00},
+{9.9694608e-01},
+{8.7913715e-01},
+{6.7096137e-01},
+{7.4646346e-01},
+{9.8211586e-01},
+{1.1596887e+00},
+{1.2506463e+00},
+{1.2528610e+00},
+{9.3574881e-01},
+{6.4708026e-01},
+{4.5058777e-01},
+{6.4326949e-01},
+{9.6585146e-01},
+{9.7825812e-01},
+{1.0299115e+00},
+{1.1430802e+00},
+{1.1005190e+00},
+{1.0609387e+00},
+{8.1379890e-01},
+{7.1122428e-01},
+{6.9156533e-01},
+{9.7259709e-01},
+{1.1655186e+00},
+{1.2452699e+00},
+{1.2619116e+00},
+{9.4482161e-01},
+{6.4801701e-01},
+{4.4907240e-01},
+{6.2485209e-01},
+{9.5564190e-01},
+{9.7288683e-01},
+{1.0147847e+00},
+{1.1443809e+00},
+{1.1120870e+00},
+{1.0877802e+00},
+{8.3639407e-01},
+{7.0935594e-01},
+{6.5684224e-01},
+{9.2695542e-01},
+{1.1418485e+00},
+{1.2155793e+00},
+{1.2744439e+00},
+{9.9526406e-01},
+{6.9858658e-01},
+{4.8225678e-01},
+{5.7551868e-01},
+{9.3953863e-01},
+{1.0000682e+00},
+{1.0105854e+00},
+{1.1531271e+00},
+{1.0852683e+00},
+{1.0562598e+00},
+{8.2024340e-01},
+{7.2070006e-01},
+{7.2200828e-01},
+{9.7907123e-01},
+{1.1713283e+00},
+{1.2668075e+00},
+{1.2685662e+00},
+{9.4120299e-01},
+{6.3302397e-01},
+{4.3403723e-01},
+{6.1877701e-01},
+{9.4622798e-01},
+{9.5365292e-01},
+{9.9618857e-01},
+{1.1414351e+00},
+{1.1389950e+00},
+{1.1349258e+00},
+{8.7553815e-01},
+{7.0489527e-01},
+{5.9575516e-01},
+{8.3938416e-01},
+{1.0946321e+00},
+{1.1549299e+00},
+{1.2478627e+00},
+{1.0727433e+00},
+{8.0007945e-01},
+{5.7879852e-01},
+{5.4142544e-01},
+{8.9584895e-01},
+{1.0605852e+00},
+{1.0558398e+00},
+{1.1875826e+00},
+{1.0434789e+00},
+{9.2439267e-01},
+{7.1612758e-01},
+{6.8218882e-01},
+{9.0102182e-01},
+{1.1275375e+00},
+{1.2109971e+00},
+{1.2892493e+00},
+{1.0360675e+00},
+{7.3214326e-01},
+{4.9603224e-01},
+{5.2859768e-01},
+{9.0839931e-01},
+{9.9967438e-01},
+{9.8761933e-01},
+{1.1495807e+00},
+{1.0955451e+00},
+{1.0837190e+00},
+{8.6306190e-01},
+{7.2864571e-01},
+{6.9570443e-01},
+{9.1466309e-01},
+{1.1416079e+00},
+{1.2423455e+00},
+{1.2979661e+00},
+{1.0158501e+00},
+{6.9306586e-01},
+{4.6540187e-01},
+{5.3429520e-01},
+{9.1176535e-01},
+{9.7214664e-01},
+{9.6587930e-01},
+{1.1395672e+00},
+{1.1254350e+00},
+{1.1438751e+00},
+{9.1306791e-01},
+{7.3239337e-01},
+{6.1798523e-01},
+{7.9591503e-01},
+{1.0777494e+00},
+{1.1677842e+00},
+{1.2502967e+00},
+{1.1151699e+00},
+{8.1642087e-01},
+{5.8442000e-01},
+{5.0055038e-01},
+{8.4650946e-01},
+{1.0385843e+00},
+{1.0234916e+00},
+{1.1635033e+00},
+{1.0803258e+00},
+{9.9050756e-01},
+{8.0394987e-01},
+{6.9093478e-01},
+{8.1258118e-01},
+{1.0510811e+00},
+{1.1928214e+00},
+{1.2964341e+00},
+{1.1903709e+00},
+{8.5006682e-01},
+{5.6609363e-01},
+{4.2789827e-01},
+{7.4508986e-01},
+{9.7546850e-01},
+{9.4304490e-01},
+{1.0657257e+00},
+{1.1344752e+00},
+{1.1448680e+00},
+{1.0604924e+00},
+{8.0946851e-01},
+{6.6897242e-01},
+{6.3751840e-01},
+{9.5203759e-01},
+{1.1383222e+00},
+{1.1857882e+00},
+{1.2429358e+00},
+{9.6640521e-01},
+{7.0943525e-01},
+{5.0606242e-01},
+{6.3814517e-01},
+{9.8050653e-01},
+{1.0400252e+00},
+{1.0768445e+00},
+{1.1586073e+00},
+{1.0171349e+00},
+{9.1652446e-01},
+{7.0015343e-01},
+{7.3826470e-01},
+{9.3314098e-01},
+{1.1436325e+00},
+{1.2463125e+00},
+{1.2921798e+00},
+{1.0004180e+00},
+{6.8706555e-01},
+{4.6091370e-01},
+{5.5360860e-01},
+{9.2333217e-01},
+{9.7324082e-01},
+{9.7644851e-01},
+{1.1422917e+00},
+{1.1211038e+00},
+{1.1312591e+00},
+{8.9312684e-01},
+{7.2669146e-01},
+{6.2634170e-01},
+{8.3089176e-01},
+{1.0962164e+00},
+{1.1808500e+00},
+{1.2661262e+00},
+{1.0871224e+00},
+{7.8484345e-01},
+{5.5241172e-01},
+{5.0720010e-01},
+{8.7433135e-01},
+{1.0293171e+00},
+{1.0110677e+00},
+{1.1612664e+00},
+{1.0781429e+00},
+{1.0169296e+00},
+{8.1818733e-01},
+{7.0825239e-01},
+{7.8555548e-01},
+{1.0202406e+00},
+{1.1861871e+00},
+{1.2927766e+00},
+{1.2345608e+00},
+{8.9196638e-01},
+{5.9165129e-01},
+{4.1993302e-01},
+{6.8133251e-01},
+{9.5902336e-01},
+{9.3840491e-01},
+{1.0229760e+00},
+{1.1397483e+00},
+{1.1549910e+00},
+{1.1221729e+00},
+{8.5521466e-01},
+{6.8171599e-01},
+{5.8253142e-01},
+{8.6249156e-01},
+{1.0984374e+00},
+{1.1402897e+00},
+{1.2397438e+00},
+{1.0509675e+00},
+{8.0267914e-01},
+{5.8719202e-01},
+{5.7423177e-01},
+{9.2225657e-01},
+{1.0807070e+00},
+{1.0878295e+00},
+{1.2011335e+00},
+{1.0137713e+00},
+{8.6200406e-01},
+{6.5063788e-01},
+{6.7962388e-01},
+{9.6415425e-01},
+{1.1427244e+00},
+{1.2001432e+00},
+{1.2435862e+00},
+{9.5255718e-01},
+{6.9548843e-01},
+{4.9228114e-01},
+{6.4975070e-01},
+{9.8475452e-01},
+{1.0290189e+00},
+{1.0735305e+00},
+{1.1514964e+00},
+{1.0265685e+00},
+{9.3450570e-01},
+{7.1609613e-01},
+{7.4066401e-01},
+{9.0672547e-01},
+{1.1323663e+00},
+{1.2457251e+00},
+{1.3080265e+00},
+{1.0368462e+00},
+{7.0922252e-01},
+{4.6922499e-01},
+{5.0971665e-01},
+{8.9530783e-01},
+{9.6897032e-01},
+{9.5144881e-01},
+{1.1327578e+00},
+{1.1313397e+00},
+{1.1615669e+00},
+{9.4490349e-01},
+{7.4435097e-01},
+{6.0879030e-01},
+{7.4201167e-01},
+{1.0475442e+00},
+{1.1489683e+00},
+{1.2189341e+00},
+{1.1527726e+00},
+{8.6373864e-01},
+{6.3765290e-01},
+{5.0482479e-01},
+{7.9976041e-01},
+{1.0463811e+00},
+{1.0486243e+00},
+{1.1650654e+00},
+{1.0937932e+00},
+{9.5242412e-01},
+{7.7776887e-01},
+{6.5337298e-01},
+{8.3412675e-01},
+{1.0842165e+00},
+{1.1876958e+00},
+{1.2860798e+00},
+{1.1277640e+00},
+{8.0705117e-01},
+{5.4933954e-01},
+{4.6409423e-01},
+{8.2407983e-01},
+{1.0029510e+00},
+{9.7182671e-01},
+{1.1248927e+00},
+{1.1108497e+00},
+{1.0927585e+00},
+{9.3345740e-01},
+{7.4563087e-01},
+{6.9815644e-01},
+{8.2911579e-01},
+{1.0975320e+00},
+{1.2225208e+00},
+{1.3041931e+00},
+{1.1107874e+00},
+{7.6954799e-01},
+{5.1381033e-01},
+{4.5656108e-01},
+{8.3803614e-01},
+{9.8059578e-01},
+{9.4343837e-01},
+{1.1139527e+00},
+{1.1272959e+00},
+{1.1505047e+00},
+{9.8802150e-01},
+{7.6846480e-01},
+{6.4059710e-01},
+{7.0404249e-01},
+{1.0213995e+00},
+{1.1571646e+00},
+{1.2167098e+00},
+{1.1922700e+00},
+{8.8891917e-01},
+{6.4610240e-01},
+{4.8423413e-01},
+{7.4237703e-01},
+{1.0194305e+00},
+{1.0263817e+00},
+{1.1223002e+00},
+{1.1218476e+00},
+{1.0047937e+00},
+{8.6916869e-01},
+{6.8761628e-01},
+{7.7272726e-01},
+{9.8680374e-01},
+{1.1662112e+00},
+{1.2718586e+00},
+{1.2599891e+00},
+{9.3374084e-01},
+{6.3070745e-01},
+{4.3512068e-01},
+{6.3400337e-01},
+{9.5387123e-01},
+{9.5725486e-01},
+{1.0083783e+00},
+{1.1414776e+00},
+{1.1320033e+00},
+{1.1156485e+00},
+{8.5730304e-01},
+{7.0257566e-01},
+{6.1385070e-01},
+{8.7645096e-01},
+{1.1135407e+00},
+{1.1743915e+00},
+{1.2617479e+00},
+{1.0416530e+00},
+{7.6141001e-01},
+{5.3947941e-01},
+{5.5263397e-01},
+{9.2079176e-01},
+{1.0423877e+00},
+{1.0391593e+00},
+{1.1741828e+00},
+{1.0475738e+00},
+{9.6528247e-01},
+{7.4824631e-01},
+{7.0765109e-01},
+{8.6076413e-01},
+{1.1015853e+00},
+{1.2180296e+00},
+{1.3087379e+00},
+{1.1050105e+00},
+{7.7144492e-01},
+{5.1073157e-01},
+{4.5959721e-01},
+{8.4138746e-01},
+{9.8058403e-01},
+{9.4385625e-01},
+{1.1155190e+00},
+{1.1265194e+00},
+{1.1505430e+00},
+{9.8480260e-01},
+{7.6753361e-01},
+{6.3998096e-01},
+{7.0790430e-01},
+{1.0242649e+00},
+{1.1582776e+00},
+{1.2187970e+00},
+{1.1895283e+00},
+{8.8519343e-01},
+{6.4254017e-01},
+{4.8336487e-01},
+{7.4700679e-01},
+{1.0202300e+00},
+{1.0250636e+00},
+{1.1237335e+00},
+{1.1201468e+00},
+{1.0057497e+00},
+{8.6867488e-01},
+{6.8876595e-01},
+{7.7314271e-01},
+{9.8646241e-01},
+{1.1663720e+00},
+{1.2725046e+00},
+{1.2607985e+00},
+{9.3432428e-01},
+{6.3055002e-01},
+{4.3462242e-01},
+{6.3267663e-01},
+{9.5306639e-01},
+{9.5647018e-01},
+{1.0069834e+00},
+{1.1414283e+00},
+{1.1332454e+00},
+{1.1183329e+00},
+{8.5964718e-01},
+{7.0259273e-01},
+{6.1086847e-01},
+{8.7145976e-01},
+{1.1109278e+00},
+{1.1713319e+00},
+{1.2600859e+00},
+{1.0459933e+00},
+{7.6697548e-01},
+{5.4492361e-01},
+{5.5082792e-01},
+{9.1787603e-01},
+{1.0454451e+00},
+{1.0416026e+00},
+{1.1762039e+00},
+{1.0460129e+00},
+{9.5856257e-01},
+{7.4291843e-01},
+{7.0478730e-01},
+{8.6904294e-01},
+{1.1074327e+00},
+{1.2185136e+00},
+{1.3067057e+00},
+{1.0916662e+00},
+{7.6226341e-01},
+{5.0599582e-01},
+{4.7004755e-01},
+{8.5459323e-01},
+{9.8292600e-01},
+{9.4923741e-01},
+{1.1230180e+00},
+{1.1230727e+00},
+{1.1436380e+00},
+{9.6517685e-01},
+{7.5906667e-01},
+{6.4229098e-01},
+{7.3739829e-01},
+{1.0441989e+00},
+{1.1689429e+00},
+{1.2377221e+00},
+{1.1702644e+00},
+{8.5776744e-01},
+{6.1283507e-01},
+{4.7508171e-01},
+{7.7650778e-01},
+{1.0199875e+00},
+{1.0098181e+00},
+{1.1277738e+00},
+{1.1115547e+00},
+{1.0256012e+00},
+{8.8156161e-01},
+{7.0600708e-01},
+{7.6171841e-01},
+{9.5613909e-01},
+{1.1569502e+00},
+{1.2691300e+00},
+{1.2887802e+00},
+{9.7384680e-01},
+{6.5493328e-01},
+{4.3953117e-01},
+{5.7648851e-01},
+{9.2999054e-01},
+{9.5436230e-01},
+{9.7297008e-01},
+{1.1391325e+00},
+{1.1416064e+00},
+{1.1590944e+00},
+{9.0850247e-01},
+{7.1895834e-01},
+{5.8564424e-01},
+{7.8301903e-01},
+{1.0675300e+00},
+{1.1390766e+00},
+{1.2237314e+00},
+{1.1158432e+00},
+{8.4615038e-01},
+{6.2929929e-01},
+{5.3024321e-01},
+{8.4771779e-01},
+{1.0679772e+00},
+{1.0707805e+00},
+{1.1942615e+00},
+{1.0628072e+00},
+{9.0277875e-01},
+{7.0464579e-01},
+{6.4124982e-01},
+{8.9445063e-01},
+{1.1236998e+00},
+{1.1838208e+00},
+{1.2721938e+00},
+{1.0302053e+00},
+{7.4928918e-01},
+{5.2054789e-01},
+{5.5300914e-01},
+{9.2450978e-01},
+{1.0290172e+00},
+{1.0254177e+00},
+{1.1658431e+00},
+{1.0585030e+00},
+{9.9937151e-01},
+{7.7845423e-01},
+{7.1727834e-01},
+{8.1473462e-01},
+{1.0635825e+00},
+{1.2081434e+00},
+{1.3087387e+00},
+{1.1774543e+00},
+{8.2930325e-01},
+{5.4568406e-01},
+{4.2252006e-01},
+{7.6155262e-01},
+{9.6902023e-01},
+{9.2946430e-01},
+{1.0663917e+00},
+{1.1373062e+00},
+{1.1667915e+00},
+{1.0769457e+00},
+{8.1823128e-01},
+{6.5190054e-01},
+{6.0082155e-01},
+{9.2122516e-01},
+{1.1147361e+00},
+{1.1467530e+00},
+{1.2352757e+00},
+{9.9993521e-01},
+{7.6890308e-01},
+{5.5857496e-01},
+{6.2725763e-01},
+{9.7318317e-01},
+{1.0840117e+00},
+{1.1108847e+00},
+{1.1857549e+00},
+{9.7757101e-01},
+{8.2394503e-01},
+{6.1941336e-01},
+{7.2410931e-01},
+{1.0158088e+00},
+{1.1491174e+00},
+{1.2188178e+00},
+{1.2007209e+00},
+{8.9859946e-01},
+{6.5456633e-01},
+{4.8391373e-01},
+{7.3135136e-01},
+{1.0176181e+00},
+{1.0277501e+00},
+{1.1176213e+00},
+{1.1248859e+00},
+{1.0041498e+00},
+{8.7364691e-01},
+{6.8812425e-01},
+{7.7228478e-01},
+{9.8423833e-01},
+{1.1655135e+00},
+{1.2710944e+00},
+{1.2619166e+00},
+{9.3651452e-01},
+{6.3284215e-01},
+{4.3578889e-01},
+{6.3021849e-01},
+{9.5269846e-01},
+{9.5770175e-01},
+{1.0064613e+00},
+{1.1416014e+00},
+{1.1318041e+00},
+{1.1173687e+00},
+{8.5933718e-01},
+{7.0364317e-01},
+{6.1326177e-01},
+{8.7318554e-01},
+{1.1121947e+00},
+{1.1737687e+00},
+{1.2616019e+00},
+{1.0447114e+00},
+{7.6386287e-01},
+{5.4149208e-01},
+{5.5006680e-01},
+{9.1816862e-01},
+{1.0427545e+00},
+{1.0385725e+00},
+{1.1744959e+00},
+{1.0484442e+00},
+{9.6566520e-01},
+{7.4941645e-01},
+{7.0654030e-01},
+{8.5978495e-01},
+{1.1007328e+00},
+{1.2172148e+00},
+{1.3084224e+00},
+{1.1066295e+00},
+{7.7306455e-01},
+{5.1195750e-01},
+{4.5881820e-01},
+{8.3991753e-01},
+{9.8090418e-01},
+{9.4402667e-01},
+{1.1150495e+00},
+{1.1263864e+00},
+{1.1498512e+00},
+{9.8537193e-01},
+{7.6788821e-01},
+{6.4101222e-01},
+{7.0798171e-01},
+{1.0241973e+00},
+{1.1588402e+00},
+{1.2194902e+00},
+{1.1900225e+00},
+{8.8503290e-01},
+{6.4170616e-01},
+{4.8247262e-01},
+{7.4633801e-01},
+{1.0194608e+00},
+{1.0238758e+00},
+{1.1225142e+00},
+{1.1204876e+00},
+{1.0078894e+00},
+{8.7195748e-01},
+{6.9071922e-01},
+{7.7128559e-01},
+{9.8171063e-01},
+{1.1648359e+00},
+{1.2716060e+00},
+{1.2653194e+00},
+{9.4044785e-01},
+{6.3462126e-01},
+{4.3541986e-01},
+{6.2397592e-01},
+{9.4996429e-01},
+{9.5654324e-01},
+{1.0018949e+00},
+{1.1415375e+00},
+{1.1340702e+00},
+{1.1242483e+00},
+{8.6601272e-01},
+{7.0479002e-01},
+{6.0700568e-01},
+{8.6003770e-01},
+{1.1056434e+00},
+{1.1671804e+00},
+{1.2575999e+00},
+{1.0561104e+00},
+{7.7723774e-01},
+{5.5451638e-01},
+{5.4470017e-01},
+{9.0953268e-01},
+{1.0489983e+00},
+{1.0432715e+00},
+{1.1787522e+00},
+{1.0466535e+00},
+{9.5253913e-01},
+{7.3976965e-01},
+{6.9910727e-01},
+{8.7457184e-01},
+{1.1111747e+00},
+{1.2168058e+00},
+{1.3037145e+00},
+{1.0820947e+00},
+{7.5710433e-01},
+{5.0441461e-01},
+{4.7923251e-01},
+{8.6434525e-01},
+{9.8624111e-01},
+{9.5555561e-01},
+{1.1291297e+00},
+{1.1187232e+00},
+{1.1339455e+00},
+{9.4624297e-01},
+{7.5185473e-01},
+{6.4886735e-01},
+{7.6947931e-01},
+{1.0640658e+00},
+{1.1819490e+00},
+{1.2581006e+00},
+{1.1479357e+00},
+{8.2795383e-01},
+{5.8084914e-01},
+{4.6968322e-01},
+{8.0540679e-01},
+{1.0147037e+00},
+{9.9267552e-01},
+{1.1297166e+00},
+{1.1074520e+00},
+{1.0535732e+00},
+{8.9989357e-01},
+{7.2414622e-01},
+{7.3710872e-01},
+{9.0842211e-01},
+{1.1372436e+00},
+{1.2550645e+00},
+{1.3118017e+00},
+{1.0309191e+00},
+{6.9715233e-01},
+{4.6014528e-01},
+{5.1093338e-01},
+{8.9602085e-01},
+{9.6063866e-01},
+{9.4454964e-01},
+{1.1299822e+00},
+{1.1400660e+00},
+{1.1784050e+00},
+{9.5942169e-01},
+{7.4592605e-01},
+{5.9179210e-01},
+{7.0833096e-01},
+{1.0269127e+00},
+{1.1280089e+00},
+{1.1874924e+00},
+{1.1668412e+00},
+{8.9924653e-01},
+{6.8916581e-01},
+{5.3047422e-01},
+{7.7534076e-01},
+{1.0549099e+00},
+{1.0847312e+00},
+{1.1818109e+00},
+{1.1071479e+00},
+{9.0609669e-01},
+{7.2016981e-01},
+{5.9922569e-01},
+{8.4631545e-01},
+{1.1007330e+00},
+{1.1539455e+00},
+{1.2548057e+00},
+{1.0707369e+00},
+{7.9955359e-01},
+{5.7211183e-01},
+{5.3729384e-01},
+{8.9511329e-01},
+{1.0559775e+00},
+{1.0482488e+00},
+{1.1833103e+00},
+{1.0467011e+00},
+{9.3892077e-01},
+{7.3109756e-01},
+{6.8881096e-01},
+{8.8724202e-01},
+{1.1196405e+00},
+{1.2137632e+00},
+{1.2969341e+00},
+{1.0598913e+00},
+{7.4476987e-01},
+{5.0025043e-01},
+{5.0175473e-01},
+{8.8612613e-01},
+{9.9295902e-01},
+{9.7027740e-01},
+{1.1406663e+00},
+{1.1082236e+00},
+{1.1111857e+00},
+{9.0519862e-01},
+{7.3853971e-01},
+{6.6752554e-01},
+{8.4076984e-01},
+{1.1041197e+00},
+{1.2107499e+00},
+{1.2910787e+00},
+{1.0889124e+00},
+{7.6218879e-01},
+{5.1854183e-01},
+{4.8212027e-01},
+{8.6343438e-01},
+{9.9664176e-01},
+{9.6786348e-01},
+{1.1354766e+00},
+{1.1100558e+00},
+{1.1078273e+00},
+{9.1950063e-01},
+{7.4186814e-01},
+{6.7554741e-01},
+{8.2771704e-01},
+{1.0970261e+00},
+{1.2115055e+00},
+{1.2926801e+00},
+{1.1044430e+00},
+{7.7268354e-01},
+{5.2367729e-01},
+{4.6962326e-01},
+{8.4775775e-01},
+{9.9325612e-01},
+{9.6094332e-01},
+{1.1271528e+00},
+{1.1156670e+00},
+{1.1183008e+00},
+{9.4351589e-01},
+{7.5035067e-01},
+{6.6773972e-01},
+{7.8886291e-01},
+{1.0750322e+00},
+{1.1971741e+00},
+{1.2770426e+00},
+{1.1387571e+00},
+{8.0837143e-01},
+{5.5509702e-01},
+{4.5955065e-01},
+{8.1398530e-01},
+{1.0008314e+00},
+{9.7057086e-01},
+{1.1195985e+00},
+{1.1149111e+00},
+{1.0957539e+00},
+{9.4451157e-01},
+{7.4819097e-01},
+{6.9474604e-01},
+{8.1250200e-01},
+{1.0876804e+00},
+{1.2158509e+00},
+{1.2988266e+00},
+{1.1270851e+00},
+{7.8595861e-01},
+{5.2690470e-01},
+{4.5032342e-01},
+{8.2266007e-01},
+{9.8371303e-01},
+{9.4630598e-01},
+{1.1090276e+00}};
+
+    private static readonly Dataset defaultDataset;
+    private static readonly IEnumerable<string> defaultAllowedInputVariables;
+    private static readonly string defaultTargetVariable;
+
+    static TimeSeriesPrognosisProblemData() {
+      defaultDataset = new Dataset(new string[] { "x" }, mackey_glass_17);
+      defaultDataset.Name = "Mackey-Glass (t=17) Time Series Benchmark Dataset";
+      defaultAllowedInputVariables = Enumerable.Empty<string>();
+      defaultTargetVariable = "x";
+    }
+    #endregion
+
+    private const string TrainingHorizonParameterName = "Training Horizon";
+    private const string TestHorizonParameterName = "Test Horizon";
+
+    public IFixedValueParameter<IntValue> TrainingHorizonParameter {
+      get { return (IFixedValueParameter<IntValue>)Parameters[TrainingHorizonParameterName]; }
+    }
+    public IFixedValueParameter<IntValue> TestHorizonParameter {
+      get { return (IFixedValueParameter<IntValue>)Parameters[TestHorizonParameterName]; }
+    }
+
+    #region Properties
+    public int TrainingHorizon {
+      get { return TrainingHorizonParameter.Value.Value; }
+      set { TrainingHorizonParameter.Value.Value = value; }
+    }
+
+    public int TestHorizon {
+      get { return TestHorizonParameter.Value.Value; }
+      set { TestHorizonParameter.Value.Value = value; }
+    }
+    #endregion
+
+    [StorableConstructor]
+    protected TimeSeriesPrognosisProblemData(bool deserializing) : base(deserializing) { }
+
+    protected TimeSeriesPrognosisProblemData(TimeSeriesPrognosisProblemData original, Cloner cloner) : base(original, cloner) { }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new TimeSeriesPrognosisProblemData(this, cloner);
+    }
+
+    public TimeSeriesPrognosisProblemData()
+      : this(defaultDataset, defaultAllowedInputVariables, defaultTargetVariable) {
+      TrainingPartition.Start = 50;
+    }
+    public TimeSeriesPrognosisProblemData(IDataset dataset, IEnumerable<string> allowedInputVariables, string targetVariable, IEnumerable<ITransformation> transformations = null)
+      : base(dataset, allowedInputVariables, targetVariable, transformations ?? Enumerable.Empty<ITransformation>()) {
+      Parameters.Add(new FixedValueParameter<IntValue>(TrainingHorizonParameterName, "Specifies the horizon (how far the prognosis reaches in the future) for each training sample.", new IntValue(1)));
+      Parameters.Add(new FixedValueParameter<IntValue>(TestHorizonParameterName, "Specifies the horizon (how far the prognosis reaches in the future) for each test sample.", new IntValue(1)));
+
+      TrainingHorizonParameter.Hidden = true;
+      TestHorizonParameter.Hidden = true;
+
+      TrainingPartition.Start = Math.Min((int)(TrainingPartition.Size * 0.2), 50);
+
+      RegisterParameterEventHandlers();
+    }
+
+    public TimeSeriesPrognosisProblemData(ITimeSeriesPrognosisProblemData timeseriesProblemData)
+      : this(timeseriesProblemData.Dataset, timeseriesProblemData.AllowedInputVariables, timeseriesProblemData.TargetVariable) {
+
+      TrainingPartition.Start = timeseriesProblemData.TrainingPartition.Start;
+      TrainingPartition.End = timeseriesProblemData.TrainingPartition.End;
+      TestPartition.Start = timeseriesProblemData.TestPartition.Start;
+      TestPartition.End = timeseriesProblemData.TestPartition.End;
+
+      TrainingHorizon = timeseriesProblemData.TrainingHorizon;
+      TestHorizon = timeseriesProblemData.TestHorizon;
+    }
+
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() {
+      RegisterParameterEventHandlers();
+    }
+
+    private void RegisterParameterEventHandlers() {
+      TrainingHorizonParameter.Value.ValueChanged += new System.EventHandler(Parameter_ValueChanged);
+      TestHorizonParameter.Value.ValueChanged += new System.EventHandler(Parameter_ValueChanged);
+    }
+
+    private void Parameter_ValueChanged(object sender, EventArgs e) {
+      OnChanged();
+    }
+
+    protected override bool IsProblemDataCompatible(IDataAnalysisProblemData problemData, out string errorMessage) {
+      if (problemData == null) throw new ArgumentNullException("problemData", "The provided problemData is null.");
+      ITimeSeriesPrognosisProblemData timeseriesProblemData = problemData as ITimeSeriesPrognosisProblemData;
+      if (timeseriesProblemData == null)
+        throw new ArgumentException("The problem data is not a time-series problem data. Instead a " + problemData.GetType().GetPrettyName() + " was provided.", "problemData");
+
+      var returnValue = base.IsProblemDataCompatible(problemData, out errorMessage);
+      //check targetVariable
+      if (problemData.InputVariables.All(var => var.Value != TargetVariable)) {
+        errorMessage = string.Format("The target variable {0} is not present in the new problem data.", TargetVariable)
+                       + Environment.NewLine + errorMessage;
+        return false;
+      }
+      return returnValue;
+    }
+
+    public override void AdjustProblemDataProperties(IDataAnalysisProblemData problemData) {
+      TimeSeriesPrognosisProblemData timeSeriesProblemData = problemData as TimeSeriesPrognosisProblemData;
+      if (timeSeriesProblemData == null)
+        throw new ArgumentException("The problem data is not a timeseries problem data. Instead a " + problemData.GetType().GetPrettyName() + " was provided.", "problemData");
+
+      var trainingDataStart = TrainingIndices.First();
+
+      base.AdjustProblemDataProperties(problemData);
+
+      TestPartition.Start = trainingDataStart;
+
+      TrainingHorizon = timeSeriesProblemData.TrainingHorizon;
+      TestHorizon = timeSeriesProblemData.TestHorizon;
+    }
+
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/TimeSeriesPrognosis/TimeSeriesPrognosisResults.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/TimeSeriesPrognosis/TimeSeriesPrognosisResults.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/TimeSeriesPrognosis/TimeSeriesPrognosisResults.cs	(revision 13819)
@@ -0,0 +1,468 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Optimization;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  [StorableClass]
+  [Item("Prognosis Results", "Represents a collection of time series prognosis results.")]
+  public class TimeSeriesPrognosisResults : ResultCollection {
+    #region result names
+    protected const string PrognosisTrainingMeanSquaredErrorResultName = "Mean squared error (training)";
+    protected const string PrognosisTestMeanSquaredErrorResultName = "Mean squared error (test)";
+    protected const string PrognosisTrainingMeanAbsoluteErrorResultName = "Mean absolute error (training)";
+    protected const string PrognosisTestMeanAbsoluteErrorResultName = "Mean absolute error (test)";
+    protected const string PrognosisTrainingSquaredCorrelationResultName = "Pearson's R² (training)";
+    protected const string PrognosisTestSquaredCorrelationResultName = "Pearson's R² (test)";
+    protected const string PrognosisTrainingRelativeErrorResultName = "Average relative error (training)";
+    protected const string PrognosisTestRelativeErrorResultName = "Average relative error (test)";
+    protected const string PrognosisTrainingNormalizedMeanSquaredErrorResultName = "Normalized mean squared error (training)";
+    protected const string PrognosisTestNormalizedMeanSquaredErrorResultName = "Normalized mean squared error (test)";
+    protected const string PrognosisTrainingMeanErrorResultName = "Mean error (training)";
+    protected const string PrognosisTestMeanErrorResultName = "Mean error (test)";
+
+    protected const string PrognosisTrainingDirectionalSymmetryResultName = "Average directional symmetry (training)";
+    protected const string PrognosisTestDirectionalSymmetryResultName = "Average directional symmetry (test)";
+    protected const string PrognosisTrainingWeightedDirectionalSymmetryResultName = "Average weighted directional symmetry (training)";
+    protected const string PrognosisTestWeightedDirectionalSymmetryResultName = "Average weighted directional symmetry (test)";
+    protected const string PrognosisTrainingTheilsUStatisticAR1ResultName = "Theil's U2 (AR1) (training)";
+    protected const string PrognosisTestTheilsUStatisticAR1ResultName = "Theil's U2 (AR1) (test)";
+    protected const string PrognosisTrainingTheilsUStatisticMeanResultName = "Theil's U2 (mean) (training)";
+    protected const string PrognosisTestTheilsUStatisticMeanResultName = "Theil's U2 (mean) (test)";
+    #endregion
+
+    #region result descriptions
+    protected const string PrognosisTrainingMeanSquaredErrorResultDescription = "Mean of squared errors of the model on the training partition";
+    protected const string PrognosisTestMeanSquaredErrorResultDescription = "Mean of squared errors of the model on the test partition";
+    protected const string PrognosisTrainingMeanAbsoluteErrorResultDescription = "Mean of absolute errors of the model on the training partition";
+    protected const string PrognosisTestMeanAbsoluteErrorResultDescription = "Mean of absolute errors of the model on the test partition";
+    protected const string PrognosisTrainingSquaredCorrelationResultDescription = "Squared Pearson's correlation coefficient of the model output and the actual values on the training partition";
+    protected const string PrognosisTestSquaredCorrelationResultDescription = "Squared Pearson's correlation coefficient of the model output and the actual values on the test partition";
+    protected const string PrognosisTrainingRelativeErrorResultDescription = "Average of the relative errors of the model output and the actual values on the training partition";
+    protected const string PrognosisTestRelativeErrorResultDescription = "Average of the relative errors of the model output and the actual values on the test partition";
+    protected const string PrognosisTrainingNormalizedMeanSquaredErrorResultDescription = "Normalized mean of squared errors of the model on the training partition";
+    protected const string PrognosisTestNormalizedMeanSquaredErrorResultDescription = "Normalized mean of squared errors of the model on the test partition";
+    protected const string PrognosisTrainingMeanErrorResultDescription = "Mean of errors of the model on the training partition";
+    protected const string PrognosisTestMeanErrorResultDescription = "Mean of errors of the model on the test partition";
+
+    protected const string PrognosisTrainingDirectionalSymmetryResultDescription = "The average directional symmetry of the forecasts of the model on the training partition";
+    protected const string PrognosisTestDirectionalSymmetryResultDescription = "The average directional symmetry of the forecasts of the model on the test partition";
+    protected const string PrognosisTrainingWeightedDirectionalSymmetryResultDescription = "The average weighted directional symmetry of the forecasts of the model on the training partition";
+    protected const string PrognosisTestWeightedDirectionalSymmetryResultDescription = "The average weighted directional symmetry of the forecasts of the model on the test partition";
+    protected const string PrognosisTrainingTheilsUStatisticAR1ResultDescription = "The Theil's U statistic (reference: AR1 model) of the forecasts of the model on the training partition";
+    protected const string PrognosisTestTheilsUStatisticAR1ResultDescription = "The Theil's U statistic (reference: AR1 model) of the forecasts of the model on the test partition";
+    protected const string PrognosisTrainingTheilsUStatisticMeanResultDescription = "The Theil's U statistic (reference: mean model) of the forecasts of the model on the training partition";
+    protected const string PrognosisTestTheilsUStatisticMeanResultDescription = "The Theil's U statistic (reference: mean value) of the forecasts of the model on the test partition";
+    #endregion
+
+    #region result properties
+    //prognosis results for different horizons
+    public double PrognosisTrainingMeanSquaredError {
+      get {
+        if (!ContainsKey(PrognosisTrainingMeanSquaredErrorResultName)) return double.NaN;
+        return ((DoubleValue)this[PrognosisTrainingMeanSquaredErrorResultName].Value).Value;
+      }
+      private set {
+        if (!ContainsKey(PrognosisTrainingMeanSquaredErrorResultName)) Add(new Result(PrognosisTrainingMeanSquaredErrorResultName, PrognosisTrainingMeanSquaredErrorResultDescription, new DoubleValue()));
+        ((DoubleValue)this[PrognosisTrainingMeanSquaredErrorResultName].Value).Value = value;
+      }
+    }
+
+    public double PrognosisTestMeanSquaredError {
+      get {
+        if (!ContainsKey(PrognosisTestMeanSquaredErrorResultName)) return double.NaN;
+        return ((DoubleValue)this[PrognosisTestMeanSquaredErrorResultName].Value).Value;
+      }
+      private set {
+        if (!ContainsKey(PrognosisTestMeanSquaredErrorResultName)) Add(new Result(PrognosisTestMeanSquaredErrorResultName, PrognosisTestMeanSquaredErrorResultDescription, new DoubleValue()));
+        ((DoubleValue)this[PrognosisTestMeanSquaredErrorResultName].Value).Value = value;
+      }
+    }
+
+    public double PrognosisTrainingMeanAbsoluteError {
+      get {
+        if (!ContainsKey(PrognosisTrainingMeanAbsoluteErrorResultName)) return double.NaN;
+        return ((DoubleValue)this[PrognosisTrainingMeanAbsoluteErrorResultName].Value).Value;
+      }
+      private set {
+        if (!ContainsKey(PrognosisTrainingMeanAbsoluteErrorResultName)) Add(new Result(PrognosisTrainingMeanAbsoluteErrorResultName, PrognosisTrainingMeanAbsoluteErrorResultDescription, new DoubleValue()));
+        ((DoubleValue)this[PrognosisTrainingMeanAbsoluteErrorResultName].Value).Value = value;
+      }
+    }
+
+    public double PrognosisTestMeanAbsoluteError {
+      get {
+        if (!ContainsKey(PrognosisTestMeanAbsoluteErrorResultName)) return double.NaN;
+        return ((DoubleValue)this[PrognosisTestMeanAbsoluteErrorResultName].Value).Value;
+      }
+      private set {
+        if (!ContainsKey(PrognosisTestMeanAbsoluteErrorResultName)) Add(new Result(PrognosisTestMeanAbsoluteErrorResultName, PrognosisTestMeanAbsoluteErrorResultDescription, new DoubleValue()));
+        ((DoubleValue)this[PrognosisTestMeanAbsoluteErrorResultName].Value).Value = value;
+      }
+    }
+
+    public double PrognosisTrainingRSquared {
+      get {
+        if (!ContainsKey(PrognosisTrainingSquaredCorrelationResultName)) return double.NaN;
+        return ((DoubleValue)this[PrognosisTrainingSquaredCorrelationResultName].Value).Value;
+      }
+      private set {
+        if (!ContainsKey(PrognosisTrainingSquaredCorrelationResultName)) Add(new Result(PrognosisTrainingSquaredCorrelationResultName, PrognosisTrainingSquaredCorrelationResultDescription, new DoubleValue()));
+        ((DoubleValue)this[PrognosisTrainingSquaredCorrelationResultName].Value).Value = value;
+      }
+    }
+
+    public double PrognosisTestRSquared {
+      get {
+        if (!ContainsKey(PrognosisTestSquaredCorrelationResultName)) return double.NaN;
+        return ((DoubleValue)this[PrognosisTestSquaredCorrelationResultName].Value).Value;
+      }
+      private set {
+        if (!ContainsKey(PrognosisTestSquaredCorrelationResultName)) Add(new Result(PrognosisTestSquaredCorrelationResultName, PrognosisTestSquaredCorrelationResultDescription, new DoubleValue()));
+        ((DoubleValue)this[PrognosisTestSquaredCorrelationResultName].Value).Value = value;
+      }
+    }
+
+    public double PrognosisTrainingRelativeError {
+      get {
+        if (!ContainsKey(PrognosisTrainingRelativeErrorResultName)) return double.NaN;
+        return ((DoubleValue)this[PrognosisTrainingRelativeErrorResultName].Value).Value;
+      }
+      private set {
+        if (!ContainsKey(PrognosisTrainingRelativeErrorResultName)) Add(new Result(PrognosisTrainingRelativeErrorResultName, PrognosisTrainingRelativeErrorResultDescription, new DoubleValue()));
+        ((DoubleValue)this[PrognosisTrainingRelativeErrorResultName].Value).Value = value;
+      }
+    }
+
+    public double PrognosisTestRelativeError {
+      get {
+        if (!ContainsKey(PrognosisTestRelativeErrorResultName)) return double.NaN;
+        return ((DoubleValue)this[PrognosisTestRelativeErrorResultName].Value).Value;
+      }
+      private set {
+        if (!ContainsKey(PrognosisTestRelativeErrorResultName)) Add(new Result(PrognosisTestRelativeErrorResultName, PrognosisTestRelativeErrorResultDescription, new DoubleValue()));
+        ((DoubleValue)this[PrognosisTestRelativeErrorResultName].Value).Value = value;
+      }
+    }
+
+    public double PrognosisTrainingNormalizedMeanSquaredError {
+      get {
+        if (!ContainsKey(PrognosisTrainingNormalizedMeanSquaredErrorResultName)) return double.NaN;
+        return ((DoubleValue)this[PrognosisTrainingNormalizedMeanSquaredErrorResultName].Value).Value;
+      }
+      private set {
+        if (!ContainsKey(PrognosisTrainingNormalizedMeanSquaredErrorResultName)) Add(new Result(PrognosisTrainingNormalizedMeanSquaredErrorResultName, PrognosisTrainingNormalizedMeanSquaredErrorResultDescription, new DoubleValue()));
+        ((DoubleValue)this[PrognosisTrainingNormalizedMeanSquaredErrorResultName].Value).Value = value;
+      }
+    }
+
+    public double PrognosisTestNormalizedMeanSquaredError {
+      get {
+        if (!ContainsKey(PrognosisTestNormalizedMeanSquaredErrorResultName)) return double.NaN;
+        return ((DoubleValue)this[PrognosisTestNormalizedMeanSquaredErrorResultName].Value).Value;
+      }
+      private set {
+        if (!ContainsKey(PrognosisTestNormalizedMeanSquaredErrorResultName)) Add(new Result(PrognosisTestNormalizedMeanSquaredErrorResultName, PrognosisTestNormalizedMeanSquaredErrorResultDescription, new DoubleValue()));
+        ((DoubleValue)this[PrognosisTestNormalizedMeanSquaredErrorResultName].Value).Value = value;
+      }
+    }
+
+    public double PrognosisTrainingMeanError {
+      get {
+        if (!ContainsKey(PrognosisTrainingMeanErrorResultName)) return double.NaN;
+        return ((DoubleValue)this[PrognosisTrainingMeanErrorResultName].Value).Value;
+      }
+      private set {
+        if (!ContainsKey(PrognosisTrainingMeanErrorResultName)) Add(new Result(PrognosisTrainingMeanErrorResultName, PrognosisTrainingMeanErrorResultDescription, new DoubleValue()));
+        ((DoubleValue)this[PrognosisTrainingMeanErrorResultName].Value).Value = value;
+      }
+    }
+
+    public double PrognosisTestMeanError {
+      get {
+        if (!ContainsKey(PrognosisTestMeanErrorResultName)) return double.NaN;
+        return ((DoubleValue)this[PrognosisTestMeanErrorResultName].Value).Value;
+      }
+      private set {
+        if (!ContainsKey(PrognosisTestMeanErrorResultName)) Add(new Result(PrognosisTestMeanErrorResultName, PrognosisTestMeanErrorResultDescription, new DoubleValue()));
+        ((DoubleValue)this[PrognosisTestMeanErrorResultName].Value).Value = value;
+      }
+    }
+
+
+    public double PrognosisTrainingDirectionalSymmetry {
+      get {
+        if (!ContainsKey(PrognosisTrainingDirectionalSymmetryResultName)) return double.NaN;
+        return ((DoubleValue)this[PrognosisTrainingDirectionalSymmetryResultName].Value).Value;
+      }
+      private set {
+        if (!ContainsKey(PrognosisTrainingDirectionalSymmetryResultName)) Add(new Result(PrognosisTrainingDirectionalSymmetryResultName, PrognosisTrainingDirectionalSymmetryResultDescription, new DoubleValue()));
+        ((DoubleValue)this[PrognosisTrainingDirectionalSymmetryResultName].Value).Value = value;
+      }
+    }
+    public double PrognosisTestDirectionalSymmetry {
+      get {
+        if (!ContainsKey(PrognosisTestDirectionalSymmetryResultName)) return double.NaN;
+        return ((DoubleValue)this[PrognosisTestDirectionalSymmetryResultName].Value).Value;
+      }
+      private set {
+        if (!ContainsKey(PrognosisTestDirectionalSymmetryResultName)) Add(new Result(PrognosisTestDirectionalSymmetryResultName, PrognosisTestDirectionalSymmetryResultDescription, new DoubleValue()));
+        ((DoubleValue)this[PrognosisTestDirectionalSymmetryResultName].Value).Value = value;
+      }
+    }
+    public double PrognosisTrainingWeightedDirectionalSymmetry {
+      get {
+        if (!ContainsKey(PrognosisTrainingWeightedDirectionalSymmetryResultName)) return double.NaN;
+        return ((DoubleValue)this[PrognosisTrainingWeightedDirectionalSymmetryResultName].Value).Value;
+      }
+      private set {
+        if (!ContainsKey(PrognosisTrainingWeightedDirectionalSymmetryResultName)) Add(new Result(PrognosisTrainingWeightedDirectionalSymmetryResultName, PrognosisTrainingWeightedDirectionalSymmetryResultDescription, new DoubleValue()));
+        ((DoubleValue)this[PrognosisTrainingWeightedDirectionalSymmetryResultName].Value).Value = value;
+      }
+    }
+    public double PrognosisTestWeightedDirectionalSymmetry {
+      get {
+        if (!ContainsKey(PrognosisTestWeightedDirectionalSymmetryResultName)) return double.NaN;
+        return ((DoubleValue)this[PrognosisTestWeightedDirectionalSymmetryResultName].Value).Value;
+      }
+      private set {
+        if (!ContainsKey(PrognosisTestWeightedDirectionalSymmetryResultName)) Add(new Result(PrognosisTestWeightedDirectionalSymmetryResultName, PrognosisTestWeightedDirectionalSymmetryResultDescription, new DoubleValue()));
+        ((DoubleValue)this[PrognosisTestWeightedDirectionalSymmetryResultName].Value).Value = value;
+      }
+    }
+    public double PrognosisTrainingTheilsUStatisticAR1 {
+      get {
+        if (!ContainsKey(PrognosisTrainingTheilsUStatisticAR1ResultName)) return double.NaN;
+        return ((DoubleValue)this[PrognosisTrainingTheilsUStatisticAR1ResultName].Value).Value;
+      }
+      private set {
+        if (!ContainsKey(PrognosisTrainingTheilsUStatisticAR1ResultName)) Add(new Result(PrognosisTrainingTheilsUStatisticAR1ResultName, PrognosisTrainingTheilsUStatisticAR1ResultDescription, new DoubleValue()));
+        ((DoubleValue)this[PrognosisTrainingTheilsUStatisticAR1ResultName].Value).Value = value;
+      }
+    }
+    public double PrognosisTestTheilsUStatisticAR1 {
+      get {
+        if (!ContainsKey(PrognosisTestTheilsUStatisticAR1ResultName)) return double.NaN;
+        return ((DoubleValue)this[PrognosisTestTheilsUStatisticAR1ResultName].Value).Value;
+      }
+      private set {
+        if (!ContainsKey(PrognosisTestTheilsUStatisticAR1ResultName)) Add(new Result(PrognosisTestTheilsUStatisticAR1ResultName, PrognosisTestTheilsUStatisticAR1ResultDescription, new DoubleValue()));
+        ((DoubleValue)this[PrognosisTestTheilsUStatisticAR1ResultName].Value).Value = value;
+      }
+    }
+    public double PrognosisTrainingTheilsUStatisticMean {
+      get {
+        if (!ContainsKey(PrognosisTrainingTheilsUStatisticMeanResultName)) return double.NaN;
+        return ((DoubleValue)this[PrognosisTrainingTheilsUStatisticMeanResultName].Value).Value;
+      }
+      private set {
+        if (!ContainsKey(PrognosisTrainingTheilsUStatisticMeanResultName)) Add(new Result(PrognosisTrainingTheilsUStatisticMeanResultName, PrognosisTrainingTheilsUStatisticMeanResultDescription, new DoubleValue()));
+        ((DoubleValue)this[PrognosisTrainingTheilsUStatisticMeanResultName].Value).Value = value;
+      }
+    }
+    public double PrognosisTestTheilsUStatisticMean {
+      get {
+        if (!ContainsKey(PrognosisTestTheilsUStatisticMeanResultName)) return double.NaN;
+        return ((DoubleValue)this[PrognosisTestTheilsUStatisticMeanResultName].Value).Value;
+      }
+      private set {
+        if (!ContainsKey(PrognosisTestTheilsUStatisticMeanResultName)) Add(new Result(PrognosisTestTheilsUStatisticMeanResultName, PrognosisTestTheilsUStatisticMeanResultDescription, new DoubleValue()));
+        ((DoubleValue)this[PrognosisTestTheilsUStatisticMeanResultName].Value).Value = value;
+      }
+    }
+    #endregion
+
+    [Storable]
+    private int trainingHorizon;
+    public int TrainingHorizon {
+      get { return trainingHorizon; }
+      set {
+        if (trainingHorizon != value) {
+          trainingHorizon = value;
+          OnTrainingHorizonChanged();
+        }
+      }
+    }
+
+    [Storable]
+    private int testHorizon;
+    public int TestHorizon {
+      get { return testHorizon; }
+      set {
+        if (testHorizon != value) {
+          testHorizon = value;
+          OnTestHorizonChanged();
+        }
+      }
+    }
+
+    private ITimeSeriesPrognosisSolution solution;
+    [Storable]
+    public ITimeSeriesPrognosisSolution Solution {
+      get { return solution; }
+      private set { solution = value; } //necessary for persistence
+    }
+
+    [StorableConstructor]
+    public TimeSeriesPrognosisResults(bool deserializing) : base(deserializing) { }
+    protected TimeSeriesPrognosisResults(TimeSeriesPrognosisResults original, Cloner cloner)
+      : base(original, cloner) {
+      this.trainingHorizon = original.trainingHorizon;
+      this.testHorizon = original.testHorizon;
+      this.solution = cloner.Clone(original.solution);
+    }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new TimeSeriesPrognosisResults(this, cloner);
+    }
+
+    public TimeSeriesPrognosisResults(int trainingHorizon, int testHorizon, ITimeSeriesPrognosisSolution solution)
+      : base() {
+      this.trainingHorizon = trainingHorizon;
+      this.testHorizon = testHorizon;
+      this.solution = solution;
+      CalculateTrainingPrognosisResults();
+      CalculateTestPrognosisResults();
+    }
+
+    #region events
+    public event EventHandler TrainingHorizonChanged;
+    protected virtual void OnTrainingHorizonChanged() {
+      CalculateTrainingPrognosisResults();
+      var handler = TrainingHorizonChanged;
+      if (handler != null) handler(this, EventArgs.Empty);
+    }
+
+    public event EventHandler TestHorizonChanged;
+    protected virtual void OnTestHorizonChanged() {
+      CalculateTestPrognosisResults();
+      var handler = TestHorizonChanged;
+      if (handler != null) handler(this, EventArgs.Empty);
+    }
+    #endregion
+
+    private void CalculateTrainingPrognosisResults() {
+      OnlineCalculatorError errorState;
+      var problemData = Solution.ProblemData;
+      if (!problemData.TrainingIndices.Any()) return;
+      var model = Solution.Model;
+      //mean model
+      double trainingMean = problemData.Dataset.GetDoubleValues(problemData.TargetVariable, problemData.TrainingIndices).Average();
+      var meanModel = new ConstantModel(trainingMean);
+
+      //AR1 model
+      double alpha, beta;
+      IEnumerable<double> trainingStartValues = problemData.Dataset.GetDoubleValues(problemData.TargetVariable, problemData.TrainingIndices.Select(r => r - 1).Where(r => r > 0)).ToList();
+      OnlineLinearScalingParameterCalculator.Calculate(problemData.Dataset.GetDoubleValues(problemData.TargetVariable, problemData.TrainingIndices.Where(x => x > 0)), trainingStartValues, out alpha, out beta, out errorState);
+      var AR1model = new TimeSeriesPrognosisAutoRegressiveModel(problemData.TargetVariable, new double[] { beta }, alpha);
+
+      var trainingHorizions = problemData.TrainingIndices.Select(r => Math.Min(trainingHorizon, problemData.TrainingPartition.End - r)).ToList();
+      IEnumerable<IEnumerable<double>> trainingTargetValues = problemData.TrainingIndices.Zip(trainingHorizions, Enumerable.Range).Select(r => problemData.Dataset.GetDoubleValues(problemData.TargetVariable, r)).ToList();
+      IEnumerable<IEnumerable<double>> trainingEstimatedValues = model.GetPrognosedValues(problemData.Dataset, problemData.TrainingIndices, trainingHorizions).ToList();
+      IEnumerable<IEnumerable<double>> trainingMeanModelPredictions = meanModel.GetPrognosedValues(problemData.Dataset, problemData.TrainingIndices, trainingHorizions).ToList();
+      IEnumerable<IEnumerable<double>> trainingAR1ModelPredictions = AR1model.GetPrognosedValues(problemData.Dataset, problemData.TrainingIndices, trainingHorizions).ToList();
+
+      IEnumerable<double> originalTrainingValues = trainingTargetValues.SelectMany(x => x).ToList();
+      IEnumerable<double> estimatedTrainingValues = trainingEstimatedValues.SelectMany(x => x).ToList();
+
+      double trainingMSE = OnlineMeanSquaredErrorCalculator.Calculate(originalTrainingValues, estimatedTrainingValues, out errorState);
+      PrognosisTrainingMeanSquaredError = errorState == OnlineCalculatorError.None ? trainingMSE : double.NaN;
+      double trainingMAE = OnlineMeanAbsoluteErrorCalculator.Calculate(originalTrainingValues, estimatedTrainingValues, out errorState);
+      PrognosisTrainingMeanAbsoluteError = errorState == OnlineCalculatorError.None ? trainingMAE : double.NaN;
+      double trainingR = OnlinePearsonsRCalculator.Calculate(originalTrainingValues, estimatedTrainingValues, out errorState);
+      PrognosisTrainingRSquared = errorState == OnlineCalculatorError.None ? trainingR*trainingR : double.NaN;
+      double trainingRelError = OnlineMeanAbsolutePercentageErrorCalculator.Calculate(originalTrainingValues, estimatedTrainingValues, out errorState);
+      PrognosisTrainingRelativeError = errorState == OnlineCalculatorError.None ? trainingRelError : double.NaN;
+      double trainingNMSE = OnlineNormalizedMeanSquaredErrorCalculator.Calculate(originalTrainingValues, estimatedTrainingValues, out errorState);
+      PrognosisTrainingNormalizedMeanSquaredError = errorState == OnlineCalculatorError.None ? trainingNMSE : double.NaN;
+      double trainingME = OnlineMeanErrorCalculator.Calculate(originalTrainingValues, estimatedTrainingValues, out errorState);
+      PrognosisTrainingMeanError = errorState == OnlineCalculatorError.None ? trainingME : double.NaN;
+
+      PrognosisTrainingDirectionalSymmetry = OnlineDirectionalSymmetryCalculator.Calculate(trainingStartValues, trainingTargetValues, trainingEstimatedValues, out errorState);
+      PrognosisTrainingDirectionalSymmetry = errorState == OnlineCalculatorError.None ? PrognosisTrainingDirectionalSymmetry : 0.0;
+      PrognosisTrainingWeightedDirectionalSymmetry = OnlineWeightedDirectionalSymmetryCalculator.Calculate(trainingStartValues, trainingTargetValues, trainingEstimatedValues, out errorState);
+      PrognosisTrainingWeightedDirectionalSymmetry = errorState == OnlineCalculatorError.None ? PrognosisTrainingWeightedDirectionalSymmetry : 0.0;
+      PrognosisTrainingTheilsUStatisticAR1 = OnlineTheilsUStatisticCalculator.Calculate(trainingStartValues, trainingTargetValues, trainingAR1ModelPredictions, trainingEstimatedValues, out errorState);
+      PrognosisTrainingTheilsUStatisticAR1 = errorState == OnlineCalculatorError.None ? PrognosisTrainingTheilsUStatisticAR1 : double.PositiveInfinity;
+      PrognosisTrainingTheilsUStatisticMean = OnlineTheilsUStatisticCalculator.Calculate(trainingStartValues, trainingTargetValues, trainingMeanModelPredictions, trainingEstimatedValues, out errorState);
+      PrognosisTrainingTheilsUStatisticMean = errorState == OnlineCalculatorError.None ? PrognosisTrainingTheilsUStatisticMean : double.PositiveInfinity;
+    }
+
+    private void CalculateTestPrognosisResults() {
+      OnlineCalculatorError errorState;
+      var problemData = Solution.ProblemData;
+      if (!problemData.TestIndices.Any()) return;
+      var model = Solution.Model;
+      var testHorizions = problemData.TestIndices.Select(r => Math.Min(testHorizon, problemData.TestPartition.End - r)).ToList();
+      IEnumerable<IEnumerable<double>> testTargetValues = problemData.TestIndices.Zip(testHorizions, Enumerable.Range).Select(r => problemData.Dataset.GetDoubleValues(problemData.TargetVariable, r)).ToList();
+      IEnumerable<IEnumerable<double>> testEstimatedValues = model.GetPrognosedValues(problemData.Dataset, problemData.TestIndices, testHorizions).ToList();
+      IEnumerable<double> testStartValues = problemData.Dataset.GetDoubleValues(problemData.TargetVariable, problemData.TestIndices.Select(r => r - 1).Where(r => r > 0)).ToList();
+
+      IEnumerable<double> originalTestValues = testTargetValues.SelectMany(x => x).ToList();
+      IEnumerable<double> estimatedTestValues = testEstimatedValues.SelectMany(x => x).ToList();
+
+      double testMSE = OnlineMeanSquaredErrorCalculator.Calculate(originalTestValues, estimatedTestValues, out errorState);
+      PrognosisTestMeanSquaredError = errorState == OnlineCalculatorError.None ? testMSE : double.NaN;
+      double testMAE = OnlineMeanAbsoluteErrorCalculator.Calculate(originalTestValues, estimatedTestValues, out errorState);
+      PrognosisTestMeanAbsoluteError = errorState == OnlineCalculatorError.None ? testMAE : double.NaN;
+      double testR = OnlinePearsonsRCalculator.Calculate(originalTestValues, estimatedTestValues, out errorState);
+      PrognosisTestRSquared = errorState == OnlineCalculatorError.None ? testR*testR : double.NaN;
+      double testRelError = OnlineMeanAbsolutePercentageErrorCalculator.Calculate(originalTestValues, estimatedTestValues, out errorState);
+      PrognosisTestRelativeError = errorState == OnlineCalculatorError.None ? testRelError : double.NaN;
+      double testNMSE = OnlineNormalizedMeanSquaredErrorCalculator.Calculate(originalTestValues, estimatedTestValues, out errorState);
+      PrognosisTestNormalizedMeanSquaredError = errorState == OnlineCalculatorError.None ? testNMSE : double.NaN;
+      double testME = OnlineMeanErrorCalculator.Calculate(originalTestValues, estimatedTestValues, out errorState);
+      PrognosisTestMeanError = errorState == OnlineCalculatorError.None ? testME : double.NaN;
+
+      PrognosisTestDirectionalSymmetry = OnlineDirectionalSymmetryCalculator.Calculate(testStartValues, testTargetValues, testEstimatedValues, out errorState);
+      PrognosisTestDirectionalSymmetry = errorState == OnlineCalculatorError.None ? PrognosisTestDirectionalSymmetry : 0.0;
+      PrognosisTestWeightedDirectionalSymmetry = OnlineWeightedDirectionalSymmetryCalculator.Calculate(testStartValues, testTargetValues, testEstimatedValues, out errorState);
+      PrognosisTestWeightedDirectionalSymmetry = errorState == OnlineCalculatorError.None ? PrognosisTestWeightedDirectionalSymmetry : 0.0;
+
+
+      if (problemData.TrainingIndices.Any()) {
+        //mean model
+        double trainingMean = problemData.Dataset.GetDoubleValues(problemData.TargetVariable, problemData.TrainingIndices).Average();
+        var meanModel = new ConstantModel(trainingMean);
+
+        //AR1 model
+        double alpha, beta;
+        IEnumerable<double> trainingStartValues = problemData.Dataset.GetDoubleValues(problemData.TargetVariable, problemData.TrainingIndices.Select(r => r - 1).Where(r => r > 0)).ToList();
+        OnlineLinearScalingParameterCalculator.Calculate(problemData.Dataset.GetDoubleValues(problemData.TargetVariable, problemData.TrainingIndices.Where(x => x > 0)), trainingStartValues, out alpha, out beta, out errorState);
+        var AR1model = new TimeSeriesPrognosisAutoRegressiveModel(problemData.TargetVariable, new double[] { beta }, alpha);
+
+        IEnumerable<IEnumerable<double>> testMeanModelPredictions = meanModel.GetPrognosedValues(problemData.Dataset, problemData.TestIndices, testHorizions).ToList();
+        IEnumerable<IEnumerable<double>> testAR1ModelPredictions = AR1model.GetPrognosedValues(problemData.Dataset, problemData.TestIndices, testHorizions).ToList();
+
+        PrognosisTestTheilsUStatisticAR1 = OnlineTheilsUStatisticCalculator.Calculate(testStartValues, testTargetValues, testAR1ModelPredictions, testEstimatedValues, out errorState);
+        PrognosisTestTheilsUStatisticAR1 = errorState == OnlineCalculatorError.None ? PrognosisTestTheilsUStatisticAR1 : double.PositiveInfinity;
+        PrognosisTestTheilsUStatisticMean = OnlineTheilsUStatisticCalculator.Calculate(testStartValues, testTargetValues, testMeanModelPredictions, testEstimatedValues, out errorState);
+        PrognosisTestTheilsUStatisticMean = errorState == OnlineCalculatorError.None ? PrognosisTestTheilsUStatisticMean : double.PositiveInfinity;
+      }
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/TimeSeriesPrognosis/TimeSeriesPrognosisSolution.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/TimeSeriesPrognosis/TimeSeriesPrognosisSolution.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/TimeSeriesPrognosis/TimeSeriesPrognosisSolution.cs	(revision 13819)
@@ -0,0 +1,46 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Collections.Generic;
+using HeuristicLab.Common;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  /// <summary>
+  /// Represents a time series prognosis data analysis solution
+  /// </summary>
+  [StorableClass]
+  public class TimeSeriesPrognosisSolution : TimeSeriesPrognosisSolutionBase {
+    [StorableConstructor]
+    protected TimeSeriesPrognosisSolution(bool deserializing) : base(deserializing) { }
+    protected TimeSeriesPrognosisSolution(TimeSeriesPrognosisSolution original, Cloner cloner) : base(original, cloner) { }
+    protected internal TimeSeriesPrognosisSolution(ITimeSeriesPrognosisModel model, ITimeSeriesPrognosisProblemData problemData)
+      : base(model, problemData) {
+      CalculateRegressionResults();
+      CalculateTimeSeriesResults();
+      CalculateTimeSeriesResults(ProblemData.TrainingHorizon, ProblemData.TestHorizon);
+    }
+
+    public override IEnumerable<IEnumerable<double>> GetPrognosedValues(IEnumerable<int> rows, IEnumerable<int> horizons) {
+      return Model.GetPrognosedValues(ProblemData.Dataset, rows, horizons);
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/TimeSeriesPrognosis/TimeSeriesPrognosisSolutionBase.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/TimeSeriesPrognosis/TimeSeriesPrognosisSolutionBase.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/TimeSeriesPrognosis/TimeSeriesPrognosisSolutionBase.cs	(revision 13819)
@@ -0,0 +1,201 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Data;
+using HeuristicLab.Optimization;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  [StorableClass]
+  public abstract class TimeSeriesPrognosisSolutionBase : RegressionSolutionBase, ITimeSeriesPrognosisSolution {
+    #region result names
+    protected const string TrainingDirectionalSymmetryResultName = "Average directional symmetry (training)";
+    protected const string TestDirectionalSymmetryResultName = "Average directional symmetry (test)";
+    protected const string TrainingWeightedDirectionalSymmetryResultName = "Average weighted directional symmetry (training)";
+    protected const string TestWeightedDirectionalSymmetryResultName = "Average weighted directional symmetry (test)";
+    protected const string TrainingTheilsUStatisticAR1ResultName = "Theil's U2 (AR1) (training)";
+    protected const string TestTheilsUStatisticLastResultName = "Theil's U2 (AR1) (test)";
+    protected const string TrainingTheilsUStatisticMeanResultName = "Theil's U2 (mean) (training)";
+    protected const string TestTheilsUStatisticMeanResultName = "Theil's U2 (mean) (test)";
+    protected const string TimeSeriesPrognosisResultName = "Prognosis Results";
+    #endregion
+
+    #region result descriptions
+    protected const string TrainingDirectionalSymmetryResultDescription = "The average directional symmetry of the forecasts of the model on the training partition";
+    protected const string TestDirectionalSymmetryResultDescription = "The average directional symmetry of the forecasts of the model on the test partition";
+    protected const string TrainingWeightedDirectionalSymmetryResultDescription = "The average weighted directional symmetry of the forecasts of the model on the training partition";
+    protected const string TestWeightedDirectionalSymmetryResultDescription = "The average weighted directional symmetry of the forecasts of the model on the test partition";
+    protected const string TrainingTheilsUStatisticAR1ResultDescription = "The Theil's U statistic (reference: AR1 model) of the forecasts of the model on the training partition";
+    protected const string TestTheilsUStatisticAR1ResultDescription = "The Theil's U statistic (reference: AR1 model) of the forecasts of the model on the test partition";
+    protected const string TrainingTheilsUStatisticMeanResultDescription = "The Theil's U statistic (reference: mean model) of the forecasts of the model on the training partition";
+    protected const string TestTheilsUStatisticMeanResultDescription = "The Theil's U statistic (reference: mean value) of the forecasts of the model on the test partition";
+    protected const string TimeSeriesPrognosisResultDescription = "The calculated results of predictions in the future.";
+    #endregion
+
+    public new ITimeSeriesPrognosisModel Model {
+      get { return (ITimeSeriesPrognosisModel)base.Model; }
+      protected set { base.Model = value; }
+    }
+
+    public new ITimeSeriesPrognosisProblemData ProblemData {
+      get { return (ITimeSeriesPrognosisProblemData)base.ProblemData; }
+      set { base.ProblemData = value; }
+    }
+
+    public abstract IEnumerable<IEnumerable<double>> GetPrognosedValues(IEnumerable<int> rows, IEnumerable<int> horizon);
+
+    #region Results
+    public double TrainingDirectionalSymmetry {
+      get { return ((DoubleValue)this[TrainingDirectionalSymmetryResultName].Value).Value; }
+      private set { ((DoubleValue)this[TrainingDirectionalSymmetryResultName].Value).Value = value; }
+    }
+    public double TestDirectionalSymmetry {
+      get { return ((DoubleValue)this[TestDirectionalSymmetryResultName].Value).Value; }
+      private set { ((DoubleValue)this[TestDirectionalSymmetryResultName].Value).Value = value; }
+    }
+    public double TrainingWeightedDirectionalSymmetry {
+      get { return ((DoubleValue)this[TrainingWeightedDirectionalSymmetryResultName].Value).Value; }
+      private set { ((DoubleValue)this[TrainingWeightedDirectionalSymmetryResultName].Value).Value = value; }
+    }
+    public double TestWeightedDirectionalSymmetry {
+      get { return ((DoubleValue)this[TestWeightedDirectionalSymmetryResultName].Value).Value; }
+      private set { ((DoubleValue)this[TestWeightedDirectionalSymmetryResultName].Value).Value = value; }
+    }
+    public double TrainingTheilsUStatisticAR1 {
+      get { return ((DoubleValue)this[TrainingTheilsUStatisticAR1ResultName].Value).Value; }
+      private set { ((DoubleValue)this[TrainingTheilsUStatisticAR1ResultName].Value).Value = value; }
+    }
+    public double TestTheilsUStatisticAR1 {
+      get { return ((DoubleValue)this[TestTheilsUStatisticLastResultName].Value).Value; }
+      private set { ((DoubleValue)this[TestTheilsUStatisticLastResultName].Value).Value = value; }
+    }
+    public double TrainingTheilsUStatisticMean {
+      get { return ((DoubleValue)this[TrainingTheilsUStatisticMeanResultName].Value).Value; }
+      private set { ((DoubleValue)this[TrainingTheilsUStatisticMeanResultName].Value).Value = value; }
+    }
+    public double TestTheilsUStatisticMean {
+      get { return ((DoubleValue)this[TestTheilsUStatisticMeanResultName].Value).Value; }
+      private set { ((DoubleValue)this[TestTheilsUStatisticMeanResultName].Value).Value = value; }
+    }
+
+    public TimeSeriesPrognosisResults TimeSeriesPrognosisResults {
+      get {
+        if (!ContainsKey(TimeSeriesPrognosisResultName)) return null;
+        return (TimeSeriesPrognosisResults)this[TimeSeriesPrognosisResultName];
+      }
+      set {
+        if (ContainsKey(TimeSeriesPrognosisResultName)) Remove(TimeSeriesPrognosisResultName);
+        Add(new Result(TimeSeriesPrognosisResultName, TimeSeriesPrognosisResultDescription, value));
+      }
+    }
+    #endregion
+
+
+    public override IEnumerable<double> EstimatedValues {
+      get { return GetEstimatedValues(Enumerable.Range(0, ProblemData.Dataset.Rows)); }
+    }
+    public override IEnumerable<double> EstimatedTrainingValues {
+      get { return GetEstimatedValues(ProblemData.TrainingIndices); }
+    }
+    public override IEnumerable<double> EstimatedTestValues {
+      get { return GetEstimatedValues(ProblemData.TestIndices); }
+    }
+    public override IEnumerable<double> GetEstimatedValues(IEnumerable<int> rows) {
+      return Model.GetEstimatedValues(ProblemData.Dataset, rows);
+    }
+
+    [StorableConstructor]
+    protected TimeSeriesPrognosisSolutionBase(bool deserializing) : base(deserializing) { }
+    protected TimeSeriesPrognosisSolutionBase(TimeSeriesPrognosisSolutionBase original, Cloner cloner) : base(original, cloner) { }
+    protected TimeSeriesPrognosisSolutionBase(ITimeSeriesPrognosisModel model, ITimeSeriesPrognosisProblemData problemData)
+      : base(model, problemData) {
+      Add(new Result(TrainingDirectionalSymmetryResultName, TrainingDirectionalSymmetryResultDescription, new DoubleValue()));
+      Add(new Result(TestDirectionalSymmetryResultName, TestDirectionalSymmetryResultDescription, new DoubleValue()));
+      Add(new Result(TrainingWeightedDirectionalSymmetryResultName, TrainingWeightedDirectionalSymmetryResultDescription, new DoubleValue()));
+      Add(new Result(TestWeightedDirectionalSymmetryResultName, TestWeightedDirectionalSymmetryResultDescription, new DoubleValue()));
+      Add(new Result(TrainingTheilsUStatisticAR1ResultName, TrainingTheilsUStatisticAR1ResultDescription, new DoubleValue()));
+      Add(new Result(TestTheilsUStatisticLastResultName, TestTheilsUStatisticAR1ResultDescription, new DoubleValue()));
+      Add(new Result(TrainingTheilsUStatisticMeanResultName, TrainingTheilsUStatisticMeanResultDescription, new DoubleValue()));
+      Add(new Result(TestTheilsUStatisticMeanResultName, TestTheilsUStatisticMeanResultDescription, new DoubleValue()));
+    }
+
+    protected override void RecalculateResults() {
+      base.RecalculateResults();
+      CalculateTimeSeriesResults();
+      CalculateTimeSeriesResults(ProblemData.TrainingHorizon, ProblemData.TestHorizon);
+    }
+
+    protected void CalculateTimeSeriesResults() {
+      OnlineCalculatorError errorState;
+      double trainingMean = ProblemData.TrainingIndices.Any() ? ProblemData.Dataset.GetDoubleValues(ProblemData.TargetVariable, ProblemData.TrainingIndices).Average() : double.NaN;
+      var meanModel = new ConstantModel(trainingMean);
+
+      double alpha, beta;
+      IEnumerable<double> trainingStartValues = ProblemData.Dataset.GetDoubleValues(ProblemData.TargetVariable, ProblemData.TrainingIndices.Select(r => r - 1).Where(r => r > 0)).ToList();
+      OnlineLinearScalingParameterCalculator.Calculate(ProblemData.Dataset.GetDoubleValues(ProblemData.TargetVariable, ProblemData.TrainingIndices.Where(x => x > 0)), trainingStartValues, out alpha, out beta, out errorState);
+      var AR1model = new TimeSeriesPrognosisAutoRegressiveModel(ProblemData.TargetVariable, new double[] { beta }, alpha);
+
+
+      #region Calculate training quality measures
+      if (ProblemData.TrainingIndices.Any()) {
+        IEnumerable<double> trainingTargetValues = ProblemData.Dataset.GetDoubleValues(ProblemData.TargetVariable, ProblemData.TrainingIndices).ToList();
+        IEnumerable<double> trainingEstimatedValues = EstimatedTrainingValues.ToList();
+        IEnumerable<double> trainingMeanModelPredictions = meanModel.GetEstimatedValues(ProblemData.Dataset, ProblemData.TrainingIndices).ToList();
+        IEnumerable<double> trainingAR1ModelPredictions = AR1model.GetEstimatedValues(ProblemData.Dataset, ProblemData.TrainingIndices).ToList();
+
+        TrainingDirectionalSymmetry = OnlineDirectionalSymmetryCalculator.Calculate(trainingTargetValues.First(), trainingTargetValues, trainingEstimatedValues, out errorState);
+        TrainingDirectionalSymmetry = errorState == OnlineCalculatorError.None ? TrainingDirectionalSymmetry : 0.0;
+        TrainingWeightedDirectionalSymmetry = OnlineWeightedDirectionalSymmetryCalculator.Calculate(trainingTargetValues.First(), trainingTargetValues, trainingEstimatedValues, out errorState);
+        TrainingWeightedDirectionalSymmetry = errorState == OnlineCalculatorError.None ? TrainingWeightedDirectionalSymmetry : 0.0;
+        TrainingTheilsUStatisticAR1 = OnlineTheilsUStatisticCalculator.Calculate(trainingTargetValues.First(), trainingTargetValues, trainingAR1ModelPredictions, trainingEstimatedValues, out errorState);
+        TrainingTheilsUStatisticAR1 = errorState == OnlineCalculatorError.None ? TrainingTheilsUStatisticAR1 : double.PositiveInfinity;
+        TrainingTheilsUStatisticMean = OnlineTheilsUStatisticCalculator.Calculate(trainingTargetValues.First(), trainingTargetValues, trainingMeanModelPredictions, trainingEstimatedValues, out errorState);
+        TrainingTheilsUStatisticMean = errorState == OnlineCalculatorError.None ? TrainingTheilsUStatisticMean : double.PositiveInfinity;
+      }
+      #endregion
+
+      #region Calculate test quality measures
+      if (ProblemData.TestIndices.Any()) {
+        IEnumerable<double> testTargetValues = ProblemData.Dataset.GetDoubleValues(ProblemData.TargetVariable, ProblemData.TestIndices).ToList();
+        IEnumerable<double> testEstimatedValues = EstimatedTestValues.ToList();
+        IEnumerable<double> testMeanModelPredictions = meanModel.GetEstimatedValues(ProblemData.Dataset, ProblemData.TestIndices).ToList();
+        IEnumerable<double> testAR1ModelPredictions = AR1model.GetEstimatedValues(ProblemData.Dataset, ProblemData.TestIndices).ToList();
+
+        TestDirectionalSymmetry = OnlineDirectionalSymmetryCalculator.Calculate(testTargetValues.First(), testTargetValues, testEstimatedValues, out errorState);
+        TestDirectionalSymmetry = errorState == OnlineCalculatorError.None ? TestDirectionalSymmetry : 0.0;
+        TestWeightedDirectionalSymmetry = OnlineWeightedDirectionalSymmetryCalculator.Calculate(testTargetValues.First(), testTargetValues, testEstimatedValues, out errorState);
+        TestWeightedDirectionalSymmetry = errorState == OnlineCalculatorError.None ? TestWeightedDirectionalSymmetry : 0.0;
+        TestTheilsUStatisticAR1 = OnlineTheilsUStatisticCalculator.Calculate(testTargetValues.First(), testTargetValues, testAR1ModelPredictions, testEstimatedValues, out errorState);
+        TestTheilsUStatisticAR1 = errorState == OnlineCalculatorError.None ? TestTheilsUStatisticAR1 : double.PositiveInfinity;
+        TestTheilsUStatisticMean = OnlineTheilsUStatisticCalculator.Calculate(testTargetValues.First(), testTargetValues, testMeanModelPredictions, testEstimatedValues, out errorState);
+        TestTheilsUStatisticMean = errorState == OnlineCalculatorError.None ? TestTheilsUStatisticMean : double.PositiveInfinity;
+      }
+      #endregion
+    }
+
+    protected void CalculateTimeSeriesResults(int trainingHorizon, int testHorizon) {
+      TimeSeriesPrognosisResults = new TimeSeriesPrognosisResults(trainingHorizon, testHorizon, this);
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Transformations/CopyColumnTransformation.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Transformations/CopyColumnTransformation.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Transformations/CopyColumnTransformation.cs	(revision 13819)
@@ -0,0 +1,65 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  [StorableClass]
+  [Item("CopyColumnTransformation", "Represents a transformation which represents a copied Column.")]
+  public class CopyColumnTransformation : Transformation {
+    protected const string CopiedColumnNameParameterName = "CopiedColumnName";
+
+    #region Parameters
+    public IValueParameter<StringValue> CopiedColumnNameParameter {
+      get { return (IValueParameter<StringValue>)Parameters[CopiedColumnNameParameterName]; }
+    }
+    #endregion
+
+    #region properties
+    public override string ShortName {
+      get { return "Cpy"; }
+    }
+    public string CopiedColumnName {
+      get { return CopiedColumnNameParameter.Value.Value; }
+    }
+    #endregion
+
+    [StorableConstructor]
+    protected CopyColumnTransformation(bool deserializing) : base(deserializing) { }
+    protected CopyColumnTransformation(CopyColumnTransformation original, Cloner cloner)
+      : base(original, cloner) {
+    }
+    public CopyColumnTransformation()
+      : base(Enumerable.Empty<string>()) {
+      Parameters.Add(new ValueParameter<StringValue>(CopiedColumnNameParameterName, "Name for the copied column", new StringValue()));
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new CopyColumnTransformation(this, cloner);
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Transformations/ExponentialTransformation.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Transformations/ExponentialTransformation.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Transformations/ExponentialTransformation.cs	(revision 13819)
@@ -0,0 +1,56 @@
+﻿using System;
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  [StorableClass]
+  [Item("Exponential Transformation", "f(x) = b ^ x | Represents a exponential transformation.")]
+  public class ExponentialTransformation : Transformation<double> {
+    protected const string BaseParameterName = "Base";
+
+    #region Parameters
+    public IValueParameter<DoubleValue> BaseParameter {
+      get { return (IValueParameter<DoubleValue>)Parameters[BaseParameterName]; }
+    }
+    #endregion
+
+    #region properties
+    public override string ShortName {
+      get { return "Exp"; }
+    }
+    public double Base {
+      get { return BaseParameter.Value.Value; }
+    }
+    #endregion
+
+    [StorableConstructor]
+    protected ExponentialTransformation(bool deserializing) : base(deserializing) { }
+
+    protected ExponentialTransformation(ExponentialTransformation original, Cloner cloner)
+      : base(original, cloner) {
+    }
+
+    public ExponentialTransformation(IEnumerable<string> allowedColumns)
+      : base(allowedColumns) {
+      Parameters.Add(new ValueParameter<DoubleValue>(BaseParameterName, "b | Base of exp-function", new DoubleValue(Math.E)));
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new ExponentialTransformation(this, cloner);
+    }
+
+    public override IEnumerable<double> Apply(IEnumerable<double> data) {
+      return data.Select(d => Math.Pow(Base, d));
+    }
+
+    public override bool Check(IEnumerable<double> data, out string errorMsg) {
+      errorMsg = "";
+      return true;
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Transformations/LinearTransformation.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Transformations/LinearTransformation.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Transformations/LinearTransformation.cs	(revision 13819)
@@ -0,0 +1,97 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  [StorableClass]
+  [Item("Linear Transformation", "f(x) = k * x + d | Represents a linear transformation with multiplication and addition.")]
+  public class LinearTransformation : Transformation<double> {
+    protected const string MultiplierParameterName = "Multiplier";
+    protected const string AddendParameterName = "Addend";
+
+    #region Parameters
+    public IValueParameter<DoubleValue> MultiplierParameter {
+      get { return (IValueParameter<DoubleValue>)Parameters[MultiplierParameterName]; }
+    }
+    public IValueParameter<DoubleValue> AddendParameter {
+      get { return (IValueParameter<DoubleValue>)Parameters[AddendParameterName]; }
+    }
+    #endregion
+
+    #region properties
+    public override string ShortName {
+      get { return "Lin"; }
+    }
+    public double Multiplier {
+      get { return MultiplierParameter.Value.Value; }
+      protected set {
+        MultiplierParameter.Value.Value = value;
+      }
+    }
+
+    public double Addend {
+      get { return AddendParameter.Value.Value; }
+      protected set {
+        AddendParameter.Value.Value = value;
+      }
+    }
+    #endregion
+
+    [StorableConstructor]
+    protected LinearTransformation(bool deserializing) : base(deserializing) { }
+    protected LinearTransformation(LinearTransformation original, Cloner cloner)
+      : base(original, cloner) {
+    }
+    public LinearTransformation(IEnumerable<string> allowedColumns)
+      : base(allowedColumns) {
+      Parameters.Add(new ValueParameter<DoubleValue>(MultiplierParameterName, "k | Multiplier for linear transformation", new DoubleValue(1.0)));
+      Parameters.Add(new ValueParameter<DoubleValue>(AddendParameterName, "d | Addend for linear transformation", new DoubleValue(0.0)));
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new LinearTransformation(this, cloner);
+    }
+
+    public override IEnumerable<double> Apply(IEnumerable<double> data) {
+      var m = Multiplier;
+      var a = Addend;
+      return data.Select(e => e * m + a);
+    }
+
+    public override bool Check(IEnumerable<double> data, out string errorMsg) {
+      errorMsg = null;
+      if (Multiplier.IsAlmost(0.0)) {
+        errorMsg = String.Format("Multiplicand is 0, all {0} entries will be set to {1}. Inverse apply will not be possible (division by 0).", data.Count(), Addend);
+        return false;
+      }
+      return true;
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Transformations/LogarithmicTransformation.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Transformations/LogarithmicTransformation.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Transformations/LogarithmicTransformation.cs	(revision 13819)
@@ -0,0 +1,61 @@
+﻿using System;
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  [StorableClass]
+  [Item("Logarithmic Transformation", "f(x) = log(x, b) | Represents a logarithmic transformation.")]
+  public class LogarithmicTransformation : Transformation<double> {
+    protected const string BaseParameterName = "Base";
+
+    #region Parameters
+    public IValueParameter<DoubleValue> BaseParameter {
+      get { return (IValueParameter<DoubleValue>)Parameters[BaseParameterName]; }
+    }
+    #endregion
+
+    #region properties
+    public override string ShortName {
+      get { return "Log"; }
+    }
+    public double Base {
+      get { return BaseParameter.Value.Value; }
+    }
+    #endregion
+
+    [StorableConstructor]
+    protected LogarithmicTransformation(bool deserializing) : base(deserializing) { }
+    protected LogarithmicTransformation(LogarithmicTransformation original, Cloner cloner)
+      : base(original, cloner) {
+    }
+    public LogarithmicTransformation(IEnumerable<string> allowedColumns)
+      : base(allowedColumns) {
+      Parameters.Add(new ValueParameter<DoubleValue>(BaseParameterName, "b | Base of log-function", new DoubleValue(Math.E)));
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new LogarithmicTransformation(this, cloner);
+    }
+
+    public override IEnumerable<double> Apply(IEnumerable<double> data) {
+      var b = Base;
+      return data.Select(d => d > 0.0 ? Math.Log(d, b) : d);
+    }
+
+    public override bool Check(IEnumerable<double> data, out string errorMsg) {
+      errorMsg = null;
+      int errorCounter = data.Count(i => i <= 0.0);
+      if (errorCounter > 0) {
+        errorMsg = String.Format("{0} values are zero or below zero. Logarithm can not be applied onto these values", errorCounter);
+        return false;
+      }
+      return true;
+    }
+
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Transformations/PowerTransformation.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Transformations/PowerTransformation.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Transformations/PowerTransformation.cs	(revision 13819)
@@ -0,0 +1,55 @@
+﻿using System;
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  [StorableClass]
+  [Item("Power Transformation", "f(x) = x ^ exp | Represents a power transformation.")]
+  public class PowerTransformation : Transformation<double> {
+    protected const string ExponentParameterName = "Exponent";
+
+    #region Parameters
+    public IValueParameter<DoubleValue> ExponentParameter {
+      get { return (IValueParameter<DoubleValue>)Parameters[ExponentParameterName]; }
+    }
+    #endregion
+
+    #region properties
+    public override string ShortName {
+      get { return "Pow"; }
+    }
+    public double Exponent {
+      get { return ExponentParameter.Value.Value; }
+    }
+    #endregion
+
+    [StorableConstructor]
+    protected PowerTransformation(bool deserializing) : base(deserializing) { }
+    protected PowerTransformation(PowerTransformation original, Cloner cloner)
+      : base(original, cloner) {
+    }
+    public PowerTransformation(IEnumerable<string> allowedColumns)
+      : base(allowedColumns) {
+      Parameters.Add(new ValueParameter<DoubleValue>(ExponentParameterName, "exp | Exponent for Exponentation", new DoubleValue(2.0)));
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new PowerTransformation(this, cloner);
+    }
+
+    public override IEnumerable<double> Apply(IEnumerable<double> data) {
+      return data.Select(i => Math.Pow(i, Exponent));
+    }
+
+    public override bool Check(IEnumerable<double> data, out string errorMsg) {
+      errorMsg = "";
+      return true;
+    }
+
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Transformations/ReciprocalTransformation.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Transformations/ReciprocalTransformation.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Transformations/ReciprocalTransformation.cs	(revision 13819)
@@ -0,0 +1,46 @@
+﻿
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+namespace HeuristicLab.Problems.DataAnalysis {
+  [StorableClass]
+  [Item("Reciprocal Transformation", "f(x) = 1 / x | Represents a reciprocal transformation.")]
+  public class ReciprocalTransformation : Transformation<double> {
+
+    #region properties
+    public override string ShortName {
+      get { return "Inv"; }
+    }
+    #endregion
+
+    [StorableConstructor]
+    protected ReciprocalTransformation(bool deserializing) : base(deserializing) { }
+    protected ReciprocalTransformation(ReciprocalTransformation original, Cloner cloner)
+      : base(original, cloner) {
+    }
+    public ReciprocalTransformation(IEnumerable<string> allowedColumns)
+      : base(allowedColumns) {
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new ReciprocalTransformation(this, cloner);
+    }
+
+    public override IEnumerable<double> Apply(IEnumerable<double> data) {
+      return data.Select(d => d > 0 ? 1.0 / d : d);
+    }
+
+    public override bool Check(IEnumerable<double> data, out string errorMsg) {
+      errorMsg = null;
+      int errorCounter = data.Count(i => i <= 0.0);
+      if (errorCounter > 0) {
+        errorMsg = String.Format("{0} values are zero or below zero. 1/x can not be applied onto these values", errorCounter);
+        return false;
+      }
+      return true;
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Transformations/ShiftStandardDistributionTransformation.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Transformations/ShiftStandardDistributionTransformation.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Transformations/ShiftStandardDistributionTransformation.cs	(revision 13819)
@@ -0,0 +1,101 @@
+﻿using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  [StorableClass]
+  [Item("Shift Standard Distribution Transformation", "f(x) = ((x - m_org) / s_org ) * s_tar + m_tar | Represents Transformation to unit standard deviation and additional linear transformation to a target Mean and Standard deviation")]
+  public class ShiftStandardDistributionTransformation : Transformation<double> {
+    protected const string OriginalMeanParameterName = "Original Mean";
+    protected const string OriginalStandardDeviationParameterName = "Original Standard Deviation";
+    protected const string MeanParameterName = "Mean";
+    protected const string StandardDeviationParameterName = "Standard Deviation";
+
+    #region Parameters
+    public IValueParameter<DoubleValue> OriginalMeanParameter {
+      get { return (IValueParameter<DoubleValue>)Parameters[OriginalMeanParameterName]; }
+    }
+    public IValueParameter<DoubleValue> OriginalStandardDeviationParameter {
+      get { return (IValueParameter<DoubleValue>)Parameters[OriginalStandardDeviationParameterName]; }
+    }
+    public IValueParameter<DoubleValue> MeanParameter {
+      get { return (IValueParameter<DoubleValue>)Parameters[MeanParameterName]; }
+    }
+    public IValueParameter<DoubleValue> StandardDeviationParameter {
+      get { return (IValueParameter<DoubleValue>)Parameters[StandardDeviationParameterName]; }
+    }
+    #endregion
+
+    #region properties
+    public override string ShortName {
+      get { return "Std"; }
+    }
+    public double OriginalMean {
+      get { return OriginalMeanParameter.Value.Value; }
+      set { OriginalMeanParameter.Value.Value = value; }
+    }
+    public double OriginalStandardDeviation {
+      get { return OriginalStandardDeviationParameter.Value.Value; }
+      set { OriginalStandardDeviationParameter.Value.Value = value; }
+    }
+    public double Mean {
+      get { return MeanParameter.Value.Value; }
+    }
+    public double StandardDeviation {
+      get { return StandardDeviationParameter.Value.Value; }
+    }
+    #endregion
+
+    [StorableConstructor]
+    protected ShiftStandardDistributionTransformation(bool deserializing) : base(deserializing) { }
+    protected ShiftStandardDistributionTransformation(ShiftStandardDistributionTransformation original, Cloner cloner)
+      : base(original, cloner) {
+    }
+    public ShiftStandardDistributionTransformation(IEnumerable<string> allowedColumns)
+      : base(allowedColumns) {
+      Parameters.Add(new ValueParameter<DoubleValue>(OriginalMeanParameterName, "m_org | Mean value of the original data's deviation.", new DoubleValue()));
+      Parameters.Add(new ValueParameter<DoubleValue>(OriginalStandardDeviationParameterName, "s_org | Standard deviation of the original data.", new DoubleValue()));
+      OriginalMeanParameter.Hidden = true;
+      OriginalStandardDeviationParameter.Hidden = true;
+      Parameters.Add(new ValueParameter<DoubleValue>(MeanParameterName, "m_tar | Mean value for the target deviation.", new DoubleValue(0.0)));
+      Parameters.Add(new ValueParameter<DoubleValue>(StandardDeviationParameterName, "s_tar | Standard deviation for the target data.", new DoubleValue(1.0)));
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new ShiftStandardDistributionTransformation(this, cloner);
+    }
+
+    public override IEnumerable<double> Apply(IEnumerable<double> data) {
+      ConfigureParameters(data);
+      if (OriginalStandardDeviation.IsAlmost(0.0)) {
+        return data;
+      }
+      var old_m = OriginalMean;
+      var old_s = OriginalStandardDeviation;
+      var m = Mean;
+      var s = StandardDeviation;
+      return data
+        .Select(d => (d - old_m) / old_s) // standardized
+        .Select(d => d * s + m);
+    }
+
+    public override bool Check(IEnumerable<double> data, out string errorMsg) {
+      ConfigureParameters(data);
+      errorMsg = "";
+      if (OriginalStandardDeviation.IsAlmost(0.0)) {
+        errorMsg = "Standard deviaton for the original data is 0.0, Transformation cannot be applied onto these values.";
+        return false;
+      }
+      return true;
+    }
+
+    protected void ConfigureParameters(IEnumerable<double> data) {
+      OriginalStandardDeviation = data.StandardDeviation();
+      OriginalMean = data.Average();
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Transformations/ShiftToRangeTransformation.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Transformations/ShiftToRangeTransformation.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Transformations/ShiftToRangeTransformation.cs	(revision 13819)
@@ -0,0 +1,67 @@
+﻿using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  [StorableClass]
+  [Item("Shift to Range Transformation", "f(x) = k * x + d, start <= f(x) <= end | Represents a linear Transformation using Parameters defining a target range")]
+  public class ShiftToRangeTransformation : LinearTransformation {
+    protected const string RangeParameterName = "Range";
+
+    #region Parameters
+    public IValueParameter<DoubleRange> RangeParameter {
+      get { return (IValueParameter<DoubleRange>)Parameters[RangeParameterName]; }
+    }
+    #endregion
+
+    #region properties
+    public override string ShortName {
+      get { return "Sft"; }
+    }
+    public DoubleRange Range {
+      get { return RangeParameter.Value; }
+    }
+    #endregion
+
+    [StorableConstructor]
+    protected ShiftToRangeTransformation(bool deserializing) : base(deserializing) { }
+    protected ShiftToRangeTransformation(ShiftToRangeTransformation original, Cloner cloner)
+      : base(original, cloner) {
+    }
+    public ShiftToRangeTransformation(IEnumerable<string> allowedColumns)
+      : base(allowedColumns) {
+      MultiplierParameter.Hidden = true;
+      AddendParameter.Hidden = true;
+      Parameters.Add(new ValueParameter<DoubleRange>(RangeParameterName, "start, end | Range for the target window of the linear transformation", new DoubleRange(0.0, 1.0)));
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new ShiftToRangeTransformation(this, cloner);
+    }
+
+    public override IEnumerable<double> Apply(IEnumerable<double> data) {
+      ConfigureParameters(data);
+      return base.Apply(data);
+    }
+
+    public override bool Check(IEnumerable<double> data, out string errorMsg) {
+      ConfigureParameters(data);
+      return base.Check(data, out errorMsg);
+    }
+
+    protected void ConfigureParameters(IEnumerable<double> data) {
+      double originalRangeStart = data.Min();
+      double originalRangeEnd = data.Max();
+
+      double originalRangeWidth = originalRangeEnd - originalRangeStart;
+      double targetRangeWidth = Range.End - Range.Start;
+
+      Multiplier = targetRangeWidth / originalRangeWidth;
+      Addend = Range.Start - originalRangeStart * Multiplier;
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Transformations/Transformation.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Transformations/Transformation.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Transformations/Transformation.cs	(revision 13819)
@@ -0,0 +1,72 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+
+  [Item("Transformation", "Represents the base class for a transformation.")]
+  [StorableClass]
+  public abstract class Transformation : ParameterizedNamedItem, ITransformation {
+    protected const string ColumnParameterName = "Column";
+    #region parameter properties
+    public IConstrainedValueParameter<StringValue> ColumnParameter {
+      get { return (IConstrainedValueParameter<StringValue>)Parameters[ColumnParameterName]; }
+    }
+    #endregion
+
+    #region properties
+    public abstract string ShortName { get; }
+
+    public string Column {
+      get { return ColumnParameter.Value.Value; }
+    }
+    #endregion
+
+    [StorableConstructor]
+    protected Transformation(bool deserializing) : base(deserializing) { }
+    protected Transformation(Transformation original, Cloner cloner) : base(original, cloner) { }
+    protected Transformation(IEnumerable<string> allowedColumns) {
+      var allowed = new ItemSet<StringValue>(allowedColumns.Select(e => new StringValue(e)));
+      Parameters.Add(new ConstrainedValueParameter<StringValue>(ColumnParameterName, "Column used for the Transformation", allowed));
+    }
+  }
+
+  [Item("Transformation", "Represents the base class for a transformation.")]
+  [StorableClass]
+  public abstract class Transformation<T> : Transformation, ITransformation<T> {
+
+    [StorableConstructor]
+    protected Transformation(bool deserializing) : base(deserializing) { }
+    protected Transformation(Transformation<T> original, Cloner cloner) : base(original, cloner) { }
+    protected Transformation(IEnumerable<string> allowedColumns) : base(allowedColumns) { }
+
+    public abstract IEnumerable<T> Apply(IEnumerable<T> data);
+
+    public abstract bool Check(IEnumerable<T> data, out string errorMsg);
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Classification/IClassificationEnsembleModel.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Classification/IClassificationEnsembleModel.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Classification/IClassificationEnsembleModel.cs	(revision 13819)
@@ -0,0 +1,30 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Collections.Generic;
+namespace HeuristicLab.Problems.DataAnalysis {
+  public interface IClassificationEnsembleModel : IClassificationModel {
+    void Add(IClassificationModel model);
+    void Remove(IClassificationModel model);
+    IEnumerable<IClassificationModel> Models { get; }
+    IEnumerable<IEnumerable<double>> GetEstimatedClassValueVectors(IDataset dataset, IEnumerable<int> rows);
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Classification/IClassificationEnsembleSolution.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Classification/IClassificationEnsembleSolution.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Classification/IClassificationEnsembleSolution.cs	(revision 13819)
@@ -0,0 +1,30 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Collections.Generic;
+using HeuristicLab.Core;
+namespace HeuristicLab.Problems.DataAnalysis {
+  public interface IClassificationEnsembleSolution : IClassificationSolution {
+    new IClassificationEnsembleModel Model { get; }
+    IItemCollection<IClassificationSolution> ClassificationSolutions { get; }
+    IEnumerable<IEnumerable<double>> GetEstimatedClassValueVectors(IDataset dataset, IEnumerable<int> rows);
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Classification/IClassificationModel.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Classification/IClassificationModel.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Classification/IClassificationModel.cs	(revision 13819)
@@ -0,0 +1,28 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Collections.Generic;
+namespace HeuristicLab.Problems.DataAnalysis {
+  public interface IClassificationModel : IDataAnalysisModel {
+    IEnumerable<double> GetEstimatedClassValues(IDataset dataset, IEnumerable<int> rows);
+    IClassificationSolution CreateClassificationSolution(IClassificationProblemData problemData);
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Classification/IClassificationProblem.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Classification/IClassificationProblem.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Classification/IClassificationProblem.cs	(revision 13819)
@@ -0,0 +1,25 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  public interface IClassificationProblem : IDataAnalysisProblem<IClassificationProblemData> {
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Classification/IClassificationProblemData.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Classification/IClassificationProblemData.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Classification/IClassificationProblemData.cs	(revision 13819)
@@ -0,0 +1,41 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Collections.Generic;
+namespace HeuristicLab.Problems.DataAnalysis {
+  public interface IClassificationProblemData : IDataAnalysisProblemData {
+    string TargetVariable { get; set; }
+
+    IEnumerable<string> ClassNames { get; }
+    string PositiveClass { get; set; }
+    IEnumerable<double> ClassValues { get; }
+    int Classes { get; }
+
+    string GetClassName(double classValue);
+    double GetClassValue(string className);
+    void SetClassName(double classValue, string className);
+
+    double GetClassificationPenalty(string correctClass, string estimatedClass);
+    double GetClassificationPenalty(double correctClassValue, double estimatedClassValue);
+    void SetClassificationPenalty(string correctClassName, string estimatedClassName, double penalty);
+    void SetClassificationPenalty(double correctClassValue, double estimatedClassValue, double penalty);
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Classification/IClassificationSolution.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Classification/IClassificationSolution.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Classification/IClassificationSolution.cs	(revision 13819)
@@ -0,0 +1,36 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Collections.Generic;
+namespace HeuristicLab.Problems.DataAnalysis {
+  public interface IClassificationSolution : IDataAnalysisSolution {
+    new IClassificationModel Model { get; }
+    new IClassificationProblemData ProblemData { get; set; }
+
+    IEnumerable<double> EstimatedClassValues { get; }
+    IEnumerable<double> EstimatedTrainingClassValues { get; }
+    IEnumerable<double> EstimatedTestClassValues { get; }
+    IEnumerable<double> GetEstimatedClassValues(IEnumerable<int> rows);
+
+    double TrainingAccuracy { get; }
+    double TestAccuracy { get; }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Classification/IDiscriminantFunctionClassificationModel.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Classification/IDiscriminantFunctionClassificationModel.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Classification/IDiscriminantFunctionClassificationModel.cs	(revision 13819)
@@ -0,0 +1,38 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+namespace HeuristicLab.Problems.DataAnalysis {
+  public interface IDiscriminantFunctionClassificationModel : IClassificationModel {
+    IEnumerable<double> Thresholds { get; }
+    IEnumerable<double> ClassValues { get; }
+    IDiscriminantFunctionThresholdCalculator ThresholdCalculator { get; }
+    void RecalculateModelParameters(IClassificationProblemData problemData, IEnumerable<int> rows);
+    // class values and thresholds can only be assigned simultanously
+    void SetThresholdsAndClassValues(IEnumerable<double> thresholds, IEnumerable<double> classValues);
+    IEnumerable<double> GetEstimatedValues(IDataset dataset, IEnumerable<int> rows);
+
+    event EventHandler ThresholdsChanged;
+
+    IDiscriminantFunctionClassificationSolution CreateDiscriminantFunctionClassificationSolution(IClassificationProblemData problemData);
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Classification/IDiscriminantFunctionClassificationSolution.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Classification/IDiscriminantFunctionClassificationSolution.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Classification/IDiscriminantFunctionClassificationSolution.cs	(revision 13819)
@@ -0,0 +1,33 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+namespace HeuristicLab.Problems.DataAnalysis {
+  public interface IDiscriminantFunctionClassificationSolution : IClassificationSolution {
+    new IDiscriminantFunctionClassificationModel Model { get; }
+
+    IEnumerable<double> EstimatedValues { get; }
+    IEnumerable<double> EstimatedTrainingValues { get; }
+    IEnumerable<double> EstimatedTestValues { get; }
+    IEnumerable<double> GetEstimatedValues(IEnumerable<int> rows);
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Classification/IDiscriminantFunctionThresholdCalculator.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Classification/IDiscriminantFunctionThresholdCalculator.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Classification/IDiscriminantFunctionThresholdCalculator.cs	(revision 13819)
@@ -0,0 +1,28 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Collections.Generic;
+using HeuristicLab.Core;
+namespace HeuristicLab.Problems.DataAnalysis {
+  public interface IDiscriminantFunctionThresholdCalculator : INamedItem {
+    void Calculate(IClassificationProblemData problemData, IEnumerable<double> estimatedValues, IEnumerable<double> targetClassValues, out double[] classValues, out double[] thresholds);
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Clustering/IClusteringModel.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Clustering/IClusteringModel.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Clustering/IClusteringModel.cs	(revision 13819)
@@ -0,0 +1,27 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Collections.Generic;
+namespace HeuristicLab.Problems.DataAnalysis {
+  public interface IClusteringModel : IDataAnalysisModel {
+    IEnumerable<int> GetClusterValues(IDataset dataset, IEnumerable<int> rows);
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Clustering/IClusteringProblem.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Clustering/IClusteringProblem.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Clustering/IClusteringProblem.cs	(revision 13819)
@@ -0,0 +1,25 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  public interface IClusteringProblem : IDataAnalysisProblem<IClusteringProblemData> {
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Clustering/IClusteringProblemData.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Clustering/IClusteringProblemData.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Clustering/IClusteringProblemData.cs	(revision 13819)
@@ -0,0 +1,25 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  public interface IClusteringProblemData : IDataAnalysisProblemData {
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Clustering/IClusteringSolution.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Clustering/IClusteringSolution.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Clustering/IClusteringSolution.cs	(revision 13819)
@@ -0,0 +1,33 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Collections.Generic;
+namespace HeuristicLab.Problems.DataAnalysis {
+  public interface IClusteringSolution : IDataAnalysisSolution {
+    new IClusteringModel Model { get; }
+    new IClusteringProblemData ProblemData { get; set; }
+
+    IEnumerable<int> ClusterValues { get; }
+    IEnumerable<int> TrainingClusterValues { get; }
+    IEnumerable<int> TestClusterValues { get; }
+    IEnumerable<int> GetClusterValues(IEnumerable<int> rows);
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/IDataAnalysisModel.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/IDataAnalysisModel.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/IDataAnalysisModel.cs	(revision 13819)
@@ -0,0 +1,27 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using HeuristicLab.Core;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  public interface IDataAnalysisModel : INamedItem {
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/IDataAnalysisProblem.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/IDataAnalysisProblem.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/IDataAnalysisProblem.cs	(revision 13819)
@@ -0,0 +1,38 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using HeuristicLab.Core;
+using HeuristicLab.Optimization;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  public interface IDataAnalysisProblem : IProblem {
+    IParameter ProblemDataParameter { get; }
+    IDataAnalysisProblemData ProblemData { get; }
+    event EventHandler ProblemDataChanged;
+  }
+
+  public interface IDataAnalysisProblem<T> : IDataAnalysisProblem
+  where T : class, IDataAnalysisProblemData {
+    new IValueParameter<T> ProblemDataParameter { get; }
+    new T ProblemData { get; set; }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/IDataAnalysisProblemData.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/IDataAnalysisProblemData.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/IDataAnalysisProblemData.cs	(revision 13819)
@@ -0,0 +1,51 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  public interface IDataAnalysisProblemData : INamedItem {
+    bool IsEmpty { get; }
+
+    IDataset Dataset { get; }
+    ICheckedItemList<StringValue> InputVariables { get; }
+    IEnumerable<string> AllowedInputVariables { get; }
+
+    IntRange TrainingPartition { get; }
+    IntRange TestPartition { get; }
+
+    IEnumerable<int> AllIndices { get; }
+    IEnumerable<int> TrainingIndices { get; }
+    IEnumerable<int> TestIndices { get; }
+
+    IEnumerable<ITransformation> Transformations { get; }
+
+    bool IsTrainingSample(int index);
+    bool IsTestSample(int index);
+
+    event EventHandler Changed;
+
+    void AdjustProblemDataProperties(IDataAnalysisProblemData problemData);
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/IDataAnalysisSolution.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/IDataAnalysisSolution.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/IDataAnalysisSolution.cs	(revision 13819)
@@ -0,0 +1,34 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  public interface IDataAnalysisSolution : INamedItem, IStorableContent {
+    IDataAnalysisModel Model { get; }
+    IDataAnalysisProblemData ProblemData { get; set; }
+
+    event EventHandler ModelChanged;
+    event EventHandler ProblemDataChanged;
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/IDataAnalysisSolutionExporter.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/IDataAnalysisSolutionExporter.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/IDataAnalysisSolutionExporter.cs	(revision 13819)
@@ -0,0 +1,32 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  public interface IDataAnalysisSolutionExporter {
+    string FileTypeFilter { get; }
+    bool Supports(IDataAnalysisSolution solution);
+    void Export(IDataAnalysisSolution solution, string fileName);
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/IDataset.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/IDataset.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/IDataset.cs	(revision 13819)
@@ -0,0 +1,41 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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.Collections.ObjectModel;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  public interface IDataset : IItem, IStringConvertibleMatrix {
+    IEnumerable<string> VariableNames { get; }
+    IEnumerable<string> DoubleVariables { get; }
+
+    double GetDoubleValue(string variableName, int row);
+    IEnumerable<double> GetDoubleValues(string variableName);
+    IEnumerable<double> GetDoubleValues(string variableName, IEnumerable<int> rows);
+    ReadOnlyCollection<double> GetReadOnlyDoubleValues(string variableName);
+
+    IEnumerable<string> GetStringValues(string variableName);
+    IEnumerable<DateTime> GetDateTimeValues(string variableName);
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/IDependencyCalculator.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/IDependencyCalculator.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/IDependencyCalculator.cs	(revision 13819)
@@ -0,0 +1,32 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Collections.Generic;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  public interface IDependencyCalculator {
+    double Maximum { get; }
+    double Minimum { get; }
+    string Name { get; }
+
+    double Calculate(IEnumerable<double> originalValues, IEnumerable<double> estimatedValues, out OnlineCalculatorError errorState);
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/IOnlineCalculator.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/IOnlineCalculator.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/IOnlineCalculator.cs	(revision 13819)
@@ -0,0 +1,46 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+
+using System;
+namespace HeuristicLab.Problems.DataAnalysis {
+  [Flags]
+  public enum OnlineCalculatorError {
+    /// <summary>
+    /// No error occurred
+    /// </summary>
+    None = 0,
+    /// <summary>
+    /// An invalid value has been added (often +/- Infinity and NaN are invalid values)
+    /// </summary>
+    InvalidValueAdded = 1,
+    /// <summary>
+    /// The number of elements added to the evaluator is not sufficient to calculate the result value
+    /// </summary>
+    InsufficientElementsAdded = 2
+  }
+  public interface IOnlineCalculator {
+    OnlineCalculatorError ErrorState { get; }
+    double Value { get; }
+    void Reset();
+    void Add(double original, double estimated);
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/ITransformation.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/ITransformation.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/ITransformation.cs	(revision 13819)
@@ -0,0 +1,34 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Collections.Generic;
+using HeuristicLab.Core;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  public interface ITransformation : IParameterizedItem {
+    string ShortName { get; }
+    string Column { get; }
+  }
+
+  public interface ITransformation<T> : ITransformation {
+    IEnumerable<T> Apply(IEnumerable<T> data);
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/ITransformationMapper.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/ITransformationMapper.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/ITransformationMapper.cs	(revision 13819)
@@ -0,0 +1,28 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  public interface ITransformationMapper<out T> {
+    T GenerateModel(ITransformation transformation);
+    T GenerateInverseModel(ITransformation transformation);
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Regression/IRegressionEnsembleModel.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Regression/IRegressionEnsembleModel.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Regression/IRegressionEnsembleModel.cs	(revision 13819)
@@ -0,0 +1,47 @@
+﻿#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;
+namespace HeuristicLab.Problems.DataAnalysis {
+  public interface IRegressionEnsembleModel : IRegressionModel {
+    void Add(IRegressionModel model);
+    void Add(IRegressionModel model, double weight);
+    void AddRange(IEnumerable<IRegressionModel> models);
+    void AddRange(IEnumerable<IRegressionModel> models, IEnumerable<double> weights);
+
+    void Remove(IRegressionModel model);
+    void RemoveRange(IEnumerable<IRegressionModel> models);
+
+    IEnumerable<IRegressionModel> Models { get; }
+    IEnumerable<double> ModelWeights { get; }
+
+    double GetModelWeight(IRegressionModel model);
+    void SetModelWeight(IRegressionModel model, double weight);
+
+    bool AverageModelEstimates { get; set; }
+
+    event EventHandler Changed;
+
+    IEnumerable<IEnumerable<double>> GetEstimatedValueVectors(IDataset dataset, IEnumerable<int> rows);
+    IEnumerable<double> GetEstimatedValues(IDataset dataset, IEnumerable<int> rows, Func<int, IRegressionModel, bool> modelSelectionPredicate);
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Regression/IRegressionEnsembleSolution.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Regression/IRegressionEnsembleSolution.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Regression/IRegressionEnsembleSolution.cs	(revision 13819)
@@ -0,0 +1,31 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Collections.Generic;
+using HeuristicLab.Core;
+namespace HeuristicLab.Problems.DataAnalysis {
+  public interface IRegressionEnsembleSolution : IRegressionSolution {
+    new IRegressionEnsembleModel Model { get; }
+    new RegressionEnsembleProblemData ProblemData { get; set; }
+    IItemCollection<IRegressionSolution> RegressionSolutions { get; }
+    IEnumerable<IEnumerable<double>> GetEstimatedValueVectors(IEnumerable<int> rows);
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Regression/IRegressionModel.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Regression/IRegressionModel.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Regression/IRegressionModel.cs	(revision 13819)
@@ -0,0 +1,28 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Collections.Generic;
+namespace HeuristicLab.Problems.DataAnalysis {
+  public interface IRegressionModel : IDataAnalysisModel {
+    IEnumerable<double> GetEstimatedValues(IDataset dataset, IEnumerable<int> rows);
+    IRegressionSolution CreateRegressionSolution(IRegressionProblemData problemData);
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Regression/IRegressionProblem.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Regression/IRegressionProblem.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Regression/IRegressionProblem.cs	(revision 13819)
@@ -0,0 +1,25 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  public interface IRegressionProblem : IDataAnalysisProblem<IRegressionProblemData> {
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Regression/IRegressionProblemData.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Regression/IRegressionProblemData.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Regression/IRegressionProblemData.cs	(revision 13819)
@@ -0,0 +1,32 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Collections.Generic;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  public interface IRegressionProblemData : IDataAnalysisProblemData {
+    string TargetVariable { get; set; }
+
+    IEnumerable<double> TargetVariableValues { get; }
+    IEnumerable<double> TargetVariableTrainingValues { get; }
+    IEnumerable<double> TargetVariableTestValues { get; }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Regression/IRegressionSolution.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Regression/IRegressionSolution.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Regression/IRegressionSolution.cs	(revision 13819)
@@ -0,0 +1,46 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Collections.Generic;
+namespace HeuristicLab.Problems.DataAnalysis {
+  public interface IRegressionSolution : IDataAnalysisSolution {
+    new IRegressionModel Model { get; }
+    new IRegressionProblemData ProblemData { get; set; }
+
+    IEnumerable<double> EstimatedValues { get; }
+    IEnumerable<double> EstimatedTrainingValues { get; }
+    IEnumerable<double> EstimatedTestValues { get; }
+    IEnumerable<double> GetEstimatedValues(IEnumerable<int> rows);
+
+    double TrainingMeanSquaredError { get; }
+    double TestMeanSquaredError { get; }
+    double TrainingMeanAbsoluteError { get; }
+    double TestMeanAbsoluteError { get; }
+    double TrainingRSquared { get; }
+    double TestRSquared { get; }
+    double TrainingRelativeError { get; }
+    double TestRelativeError { get; }
+    double TrainingNormalizedMeanSquaredError { get; }
+    double TestNormalizedMeanSquaredError { get; }
+    double TrainingRootMeanSquaredError { get; }
+    double TestRootMeanSquaredError { get; }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/TimeSeriesPrognosis/IOnlineTimeSeriesCalculator.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/TimeSeriesPrognosis/IOnlineTimeSeriesCalculator.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/TimeSeriesPrognosis/IOnlineTimeSeriesCalculator.cs	(revision 13819)
@@ -0,0 +1,33 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+
+using System;
+using System.Collections.Generic;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  public interface IOnlineTimeSeriesCalculator {
+    OnlineCalculatorError ErrorState { get; }
+    double Value { get; }
+    void Reset();
+    void Add(double startValue, IEnumerable<double> actualContinuation, IEnumerable<double> predictedContinuation);
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/TimeSeriesPrognosis/ITimeSeriesPrognosisModel.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/TimeSeriesPrognosis/ITimeSeriesPrognosisModel.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/TimeSeriesPrognosis/ITimeSeriesPrognosisModel.cs	(revision 13819)
@@ -0,0 +1,28 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Collections.Generic;
+namespace HeuristicLab.Problems.DataAnalysis {
+  public interface ITimeSeriesPrognosisModel : IRegressionModel {
+    IEnumerable<IEnumerable<double>> GetPrognosedValues(IDataset dataset, IEnumerable<int> rows, IEnumerable<int> horizons);
+    ITimeSeriesPrognosisSolution CreateTimeSeriesPrognosisSolution(ITimeSeriesPrognosisProblemData problemData);
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/TimeSeriesPrognosis/ITimeSeriesPrognosisProblem.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/TimeSeriesPrognosis/ITimeSeriesPrognosisProblem.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/TimeSeriesPrognosis/ITimeSeriesPrognosisProblem.cs	(revision 13819)
@@ -0,0 +1,25 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  public interface ITimeSeriesPrognosisProblem : IDataAnalysisProblem<ITimeSeriesPrognosisProblemData> {
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/TimeSeriesPrognosis/ITimeSeriesPrognosisProblemData.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/TimeSeriesPrognosis/ITimeSeriesPrognosisProblemData.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/TimeSeriesPrognosis/ITimeSeriesPrognosisProblemData.cs	(revision 13819)
@@ -0,0 +1,27 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  public interface ITimeSeriesPrognosisProblemData : IRegressionProblemData {
+    int TrainingHorizon { get; set; }
+    int TestHorizon { get; set; }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/TimeSeriesPrognosis/ITimeSeriesPrognosisSolution.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/TimeSeriesPrognosis/ITimeSeriesPrognosisSolution.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/TimeSeriesPrognosis/ITimeSeriesPrognosisSolution.cs	(revision 13819)
@@ -0,0 +1,39 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Collections.Generic;
+namespace HeuristicLab.Problems.DataAnalysis {
+  public interface ITimeSeriesPrognosisSolution : IRegressionSolution {
+    new ITimeSeriesPrognosisModel Model { get; }
+    new ITimeSeriesPrognosisProblemData ProblemData { get; set; }
+
+    IEnumerable<IEnumerable<double>> GetPrognosedValues(IEnumerable<int> rows, IEnumerable<int> horizon);
+
+    double TrainingTheilsUStatisticAR1 { get; }
+    double TestTheilsUStatisticAR1 { get; }
+    double TrainingTheilsUStatisticMean { get; }
+    double TestTheilsUStatisticMean { get; }
+    double TrainingDirectionalSymmetry { get; }
+    double TestDirectionalSymmetry { get; }
+    double TrainingWeightedDirectionalSymmetry { get; }
+    double TestWeightedDirectionalSymmetry { get; }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/ModifiableDataset.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/ModifiableDataset.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/ModifiableDataset.cs	(revision 13819)
@@ -0,0 +1,223 @@
+﻿#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;
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  [Item("ModifiableDataset", "Represents a dataset containing data that should be analyzed, which can be modified by adding or replacing variables and values.")]
+  [StorableClass]
+  public sealed class ModifiableDataset : Dataset, IStringConvertibleMatrix {
+    [StorableConstructor]
+    private ModifiableDataset(bool deserializing) : base(deserializing) { }
+
+    private ModifiableDataset(ModifiableDataset original, Cloner cloner) : base(original, cloner) {
+      var variables = variableValues.Keys.ToList();
+      foreach (var v in variables) {
+        var type = GetVariableType(v);
+        if (type == typeof(DateTime)) {
+          variableValues[v] = GetDateTimeValues(v).ToList();
+        } else if (type == typeof(double)) {
+          variableValues[v] = GetDoubleValues(v).ToList();
+        } else if (type == typeof(string)) {
+          variableValues[v] = GetStringValues(v).ToList();
+        } else {
+          throw new ArgumentException("Unsupported type " + type + " for variable " + v);
+        }
+      }
+    }
+    public override IDeepCloneable Clone(Cloner cloner) { return new ModifiableDataset(this, cloner); }
+    public ModifiableDataset() : base() { }
+
+    public ModifiableDataset(IEnumerable<string> variableNames, IEnumerable<IList> variableValues) : base(variableNames, variableValues) { }
+
+    public void ReplaceRow(int row, IEnumerable<object> values) {
+      var list = values.ToList();
+      if (list.Count != variableNames.Count)
+        throw new ArgumentException("The number of values must be equal to the number of variable names.");
+      // check if all the values are of the correct type
+      for (int i = 0; i < list.Count; ++i) {
+        if (list[i].GetType() != GetVariableType(variableNames[i])) {
+          throw new ArgumentException("The type of the provided value does not match the variable type.");
+        }
+      }
+      // replace values
+      for (int i = 0; i < list.Count; ++i) {
+        variableValues[variableNames[i]][row] = list[i];
+      }
+      OnReset();
+    }
+
+    public void ReplaceVariable(string variableName, IList values) {
+      if (!variableValues.ContainsKey(variableName))
+        throw new ArgumentException(string.Format("Variable {0} is not present in the dataset."), variableName);
+      if (values.Count != variableValues[variableName].Count)
+        throw new ArgumentException("The number of values must coincide with the number of dataset rows.");
+      if (GetVariableType(variableName) != values[0].GetType())
+        throw new ArgumentException("The type of the provided value does not match the variable type.");
+      variableValues[variableName] = values;
+    }
+
+    public void AddRow(IEnumerable<object> values) {
+      var list = values.ToList();
+      if (list.Count != variableNames.Count)
+        throw new ArgumentException("The number of values must be equal to the number of variable names.");
+      // check if all the values are of the correct type
+      for (int i = 0; i < list.Count; ++i) {
+        if (list[i].GetType() != GetVariableType(variableNames[i])) {
+          throw new ArgumentException("The type of the provided value does not match the variable type.");
+        }
+      }
+      // add values
+      for (int i = 0; i < list.Count; ++i) {
+        variableValues[variableNames[i]].Add(list[i]);
+      }
+      rows++;
+      OnRowsChanged();
+      OnReset();
+    }
+
+    // adds a new variable to the dataset
+    public void AddVariable<T>(string variableName, IEnumerable<T> values) {
+      if (variableValues.ContainsKey(variableName))
+        throw new ArgumentException("Variable " + variableName + " is already present in the dataset.");
+      int count = values.Count();
+      if (count != rows)
+        throw new ArgumentException("The number of values must exactly match the number of rows in the dataset.");
+      variableValues[variableName] = new List<T>(values);
+      variableNames.Add(variableName);
+      OnColumnsChanged();
+      OnColumnNamesChanged();
+      OnReset();
+    }
+
+    public void RemoveVariable(string variableName) {
+      if (!variableValues.ContainsKey(variableName))
+        throw new ArgumentException("The variable " + variableName + " does not exist in the dataset.");
+      variableValues.Remove(variableName);
+      variableNames.Remove(variableName);
+      OnColumnsChanged();
+      OnColumnNamesChanged();
+      OnReset();
+    }
+
+    // slow, avoid to use this
+    public void RemoveRow(int row) {
+      foreach (var list in variableValues.Values)
+        list.RemoveAt(row);
+      rows--;
+      OnRowsChanged();
+      OnReset();
+    }
+
+    public void SetVariableValue(object value, string variableName, int row) {
+      IList list;
+      variableValues.TryGetValue(variableName, out list);
+      if (list == null)
+        throw new ArgumentException("The variable " + variableName + " does not exist in the dataset.");
+      if (row < 0 || list.Count < row)
+        throw new ArgumentOutOfRangeException("Invalid row value");
+      if (GetVariableType(variableName) != value.GetType())
+        throw new ArgumentException("The type of the provided value does not match the variable type.");
+
+      list[row] = value;
+      OnItemChanged(row, variableNames.IndexOf(variableName));
+    }
+
+    private Type GetVariableType(string variableName) {
+      IList list;
+      variableValues.TryGetValue(variableName, out list);
+      if (list == null)
+        throw new ArgumentException("The variable " + variableName + " does not exist in the dataset.");
+      return list.GetType().GetGenericArguments()[0];
+    }
+
+    bool IStringConvertibleMatrix.SetValue(string value, int rowIndex, int columnIndex) {
+      var variableName = variableNames[columnIndex];
+      // if value represents a double
+      double dv;
+      if (double.TryParse(value, out dv)) {
+        SetVariableValue(dv, variableName, rowIndex);
+        return true;
+      }
+      // if value represents a DateTime object
+      DateTime dt;
+      if (DateTime.TryParse(value, out dt)) {
+        SetVariableValue(dt, variableName, rowIndex);
+        return true;
+      }
+      // if value is simply a string
+      SetVariableValue(value, variableName, rowIndex);
+      return true;
+    }
+
+    bool IStringConvertibleMatrix.Validate(string value, out string errorMessage) {
+      errorMessage = string.Empty;
+      return true;
+    }
+
+    #region event handlers
+    public override event EventHandler RowsChanged;
+    private void OnRowsChanged() {
+      var handler = RowsChanged;
+      if (handler != null)
+        handler(this, EventArgs.Empty);
+    }
+
+    public override event EventHandler ColumnsChanged;
+    private void OnColumnsChanged() {
+      var handler = ColumnsChanged;
+      if (handler != null)
+        handler(this, EventArgs.Empty);
+    }
+
+    public override event EventHandler ColumnNamesChanged;
+    private void OnColumnNamesChanged() {
+      var handler = ColumnNamesChanged;
+      if (handler != null)
+        handler(this, EventArgs.Empty);
+    }
+
+    public override event EventHandler Reset;
+    private void OnReset() {
+      var handler = Reset;
+      if (handler != null)
+        handler(this, EventArgs.Empty);
+    }
+
+    public override event EventHandler<EventArgs<int, int>> ItemChanged;
+    private void OnItemChanged(int rowIndex, int columnIndex) {
+      var handler = ItemChanged;
+      if (handler != null) {
+        handler(this, new EventArgs<int, int>(rowIndex, columnIndex));
+      }
+    }
+    #endregion
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/AutoCorrelationCalculator.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/AutoCorrelationCalculator.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/AutoCorrelationCalculator.cs	(revision 13819)
@@ -0,0 +1,38 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Linq;
+
+namespace HeuristicLab.Problems.DataAnalysis.OnlineCalculators {
+  public class AutoCorrelationCalculator {
+    public static double[] Calculate(double[] values, out OnlineCalculatorError error) {
+      error = OnlineCalculatorError.None;
+      if (values.Any(x => double.IsNaN(x) || double.IsInfinity(x))) {
+        error = OnlineCalculatorError.InvalidValueAdded;
+        return new double[0];
+      }
+
+      double[] correlations = new double[values.Length];
+      alglib.corr.corrr1dcircular(values, values.Length, values, values.Length, ref correlations);
+      return correlations;
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/ClassificationPerformanceMeasuresCalculator.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/ClassificationPerformanceMeasuresCalculator.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/ClassificationPerformanceMeasuresCalculator.cs	(revision 13819)
@@ -0,0 +1,141 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using HeuristicLab.Common;
+using HeuristicLab.Problems.DataAnalysis.OnlineCalculators;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  public class ClassificationPerformanceMeasuresCalculator {
+
+    public ClassificationPerformanceMeasuresCalculator(string positiveClassName, double positiveClassValue) {
+      this.positiveClassName = positiveClassName;
+      this.positiveClassValue = positiveClassValue;
+      Reset();
+    }
+
+    #region Properties
+    private int truePositiveCount, falsePositiveCount, trueNegativeCount, falseNegativeCount;
+
+    private readonly string positiveClassName;
+    public string PositiveClassName {
+      get { return positiveClassName; }
+    }
+
+    private readonly double positiveClassValue;
+    public double PositiveClassValue {
+      get { return positiveClassValue; }
+    }
+    public double TruePositiveRate {
+      get {
+        double divisor = truePositiveCount + falseNegativeCount;
+        return divisor.IsAlmost(0) ? double.NaN : truePositiveCount / divisor;
+      }
+    }
+    public double TrueNegativeRate {
+      get {
+        double divisor = falsePositiveCount + trueNegativeCount;
+        return divisor.IsAlmost(0) ? double.NaN : trueNegativeCount / divisor;
+      }
+    }
+    public double PositivePredictiveValue {
+      get {
+        double divisor = truePositiveCount + falsePositiveCount;
+        return divisor.IsAlmost(0) ? double.NaN : truePositiveCount / divisor;
+      }
+    }
+    public double NegativePredictiveValue {
+      get {
+        double divisor = trueNegativeCount + falseNegativeCount;
+        return divisor.IsAlmost(0) ? double.NaN : trueNegativeCount / divisor;
+      }
+    }
+    public double FalsePositiveRate {
+      get {
+        double divisor = falsePositiveCount + trueNegativeCount;
+        return divisor.IsAlmost(0) ? double.NaN : falsePositiveCount / divisor;
+      }
+    }
+    public double FalseDiscoveryRate {
+      get {
+        double divisor = falsePositiveCount + truePositiveCount;
+        return divisor.IsAlmost(0) ? double.NaN : falsePositiveCount / divisor;
+      }
+    }
+
+    private OnlineCalculatorError errorState;
+    public OnlineCalculatorError ErrorState {
+      get { return errorState; }
+    }
+    #endregion
+
+    public void Reset() {
+      truePositiveCount = 0;
+      falseNegativeCount = 0;
+      trueNegativeCount = 0;
+      falseNegativeCount = 0;
+      errorState = OnlineCalculatorError.InsufficientElementsAdded;
+    }
+
+    public void Add(double originalClassValue, double estimatedClassValue) {
+      // ignore cases where original is NaN completely 
+      if (double.IsNaN(originalClassValue)) return;
+
+      if (originalClassValue.IsAlmost(positiveClassValue)
+            || estimatedClassValue.IsAlmost(positiveClassValue)) { //positive class/positive class estimation
+        if (estimatedClassValue.IsAlmost(originalClassValue)) {
+          truePositiveCount++;
+        } else {
+          if (estimatedClassValue.IsAlmost(positiveClassValue)) //misclassification of the negative class
+            falsePositiveCount++;
+          else //misclassification of the positive class
+            falseNegativeCount++;
+        }
+      } else { //negative class/negative class estimation
+        //In a multiclass classification all misclassifications of the negative class
+        //will be treated as true negatives except on positive class estimations
+        trueNegativeCount++;
+      }
+
+      errorState = OnlineCalculatorError.None; // number of (non-NaN) samples >= 1
+    }
+
+    public void Calculate(IEnumerable<double> originalClassValues, IEnumerable<double> estimatedClassValues) {
+      IEnumerator<double> originalEnumerator = originalClassValues.GetEnumerator();
+      IEnumerator<double> estimatedEnumerator = estimatedClassValues.GetEnumerator();
+
+      // always move forward both enumerators (do not use short-circuit evaluation!)
+      while (originalEnumerator.MoveNext() & estimatedEnumerator.MoveNext()) {
+        double original = originalEnumerator.Current;
+        double estimated = estimatedEnumerator.Current;
+        Add(original, estimated);
+        if (ErrorState != OnlineCalculatorError.None) break;
+      }
+
+      // check if both enumerators are at the end to make sure both enumerations have the same length
+      if (ErrorState == OnlineCalculatorError.None && (estimatedEnumerator.MoveNext() || originalEnumerator.MoveNext())) {
+        throw new ArgumentException("Number of elements in originalValues and estimatedValues enumerations doesn't match.");
+      }
+      errorState = ErrorState;
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/ConfusionMatrixCalculator.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/ConfusionMatrixCalculator.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/ConfusionMatrixCalculator.cs	(revision 13819)
@@ -0,0 +1,73 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  public class ConfusionMatrixCalculator {
+    public static double[,] Calculate(IEnumerable<double> originalValues, IEnumerable<double> estimatedValues, out OnlineCalculatorError errorState) {
+      if (!originalValues.Any() || !estimatedValues.Any()) {
+        errorState = OnlineCalculatorError.InsufficientElementsAdded;
+        return null;
+      }
+
+      Dictionary<double, int> classValueIndexMapping = new Dictionary<double, int>();
+      int index = 0;
+      foreach (double classValue in originalValues.OrderBy(x => x)) {
+        if (!classValueIndexMapping.ContainsKey(classValue)) {
+          classValueIndexMapping.Add(classValue, index);
+          index++;
+        }
+      }
+
+      int classes = classValueIndexMapping.Count;
+      double[,] confusionMatrix = new double[classes, classes];
+
+
+      IEnumerator<double> originalEnumerator = originalValues.GetEnumerator();
+      IEnumerator<double> estimatedEnumerator = estimatedValues.GetEnumerator();
+      int originalIndex;
+      int estimatedIndex;
+      while (originalEnumerator.MoveNext() & estimatedEnumerator.MoveNext()) {
+        if (!classValueIndexMapping.TryGetValue(originalEnumerator.Current, out originalIndex)) {
+          errorState = OnlineCalculatorError.InvalidValueAdded;
+          return null;
+        }
+        if (!classValueIndexMapping.TryGetValue(estimatedEnumerator.Current, out estimatedIndex)) {
+          errorState = OnlineCalculatorError.InvalidValueAdded;
+          return null;
+        }
+
+        confusionMatrix[estimatedIndex, originalIndex] += 1;
+      }
+
+      if (originalEnumerator.MoveNext() || estimatedEnumerator.MoveNext()) {
+        throw new ArgumentException("Number of elements in originalValues and estimatedValues enumerations doesn't match.");
+
+      }
+
+      errorState = OnlineCalculatorError.None;
+      return confusionMatrix;
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/DependencyCalculator/HoeffdingsDependenceCalculator.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/DependencyCalculator/HoeffdingsDependenceCalculator.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/DependencyCalculator/HoeffdingsDependenceCalculator.cs	(revision 13819)
@@ -0,0 +1,139 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  public class HoeffdingsDependenceCalculator : IDependencyCalculator {
+
+    public double Maximum { get { return 1.0; } }
+
+    public double Minimum { get { return -0.5; } }
+
+    public string Name { get { return "Hoeffdings Dependence"; } }
+
+    public double Calculate(IEnumerable<double> originalValues, IEnumerable<double> estimatedValues, out OnlineCalculatorError errorState) {
+      return HoeffdingsDependenceCalculator.CalculateHoeffdings(originalValues, estimatedValues, out errorState);
+    }
+
+    public static double CalculateHoeffdings(IEnumerable<double> originalValues, IEnumerable<double> estimatedValues, out OnlineCalculatorError errorState) {
+      double d = HoeffD(originalValues, estimatedValues, out errorState);
+      if (errorState != OnlineCalculatorError.None) return double.NaN;
+      return d;
+    }
+
+    /// <summary>
+    /// computes Hoeffding's dependence coefficient. 
+    /// Source: hoeffd.r from R package hmisc http://cran.r-project.org/web/packages/Hmisc/index.html
+    /// </summary>
+    private static double HoeffD(IEnumerable<double> xs, IEnumerable<double> ys, out OnlineCalculatorError errorState) {
+      double[] rx = TiedRank(xs);
+      double[] ry = TiedRank(ys);
+      if (rx.Length != ry.Length) throw new ArgumentException("The number of elements in xs and ys does not match");
+      double[] rxy = TiedRank(xs, ys);
+
+      int n = rx.Length;
+      double q = 0, r = 0, s = 0;
+      double scaling = 1.0 / (n * (n - 1));
+      for (int i = 0; i < n; i++) {
+        q += (rx[i] - 1) * (rx[i] - 2) * (ry[i] - 1) * (ry[i] - 2) * scaling;
+        r += (rx[i] - 2) * (ry[i] - 2) * rxy[i] * scaling;
+        s += rxy[i] * (rxy[i] - 1) * scaling;
+      }
+      errorState = OnlineCalculatorError.None;
+      // return 30.0 * (q - 2 * (n - 2) * r + (n - 2) * (n - 3) * s) / n / (n - 1) / (n - 2) / (n - 3) / (n - 4);
+      double t0 = q / (n - 2) / (n - 3) / (n - 4);
+      double t1 = 2 * r / (n - 3) / (n - 4);
+      double t2 = s / (n - 4);
+      return 30.0 * (t0 - t1 + t2);
+    }
+
+    private static double[] TiedRank(IEnumerable<double> xs) {
+      var xsArr = xs.ToArray();
+      var idx = Enumerable.Range(1, xsArr.Length).ToArray();
+      Array.Sort(xsArr, idx);
+      CRank(xsArr);
+      Array.Sort(idx, xsArr);
+      return xsArr;
+    }
+
+    /// <summary>
+    /// Calculates the joint rank with midranks for ties. Source: hoeffd.r from R package hmisc http://cran.r-project.org/web/packages/Hmisc/index.html
+    /// </summary>
+    /// <param name="xs"></param>
+    /// <param name="ys"></param>
+    /// <returns></returns>
+    private static double[] TiedRank(IEnumerable<double> xs, IEnumerable<double> ys) {
+      var xsArr = xs.ToArray();
+      var ysArr = ys.ToArray();
+      var r = new double[xsArr.Length];
+      int n = r.Length;
+      for (int i = 0; i < n; i++) {
+        var xi = xsArr[i];
+        var yi = ysArr[i];
+        double ri = 0.0;
+        for (int j = 0; j < n; j++) {
+          if (i != j) {
+            double cx;
+            if (xsArr[j] < xi) cx = 1.0;
+            else if (xsArr[j] > xi) cx = 0.0;
+            else cx = 0.5;  // eq
+            double cy;
+            if (ysArr[j] < yi) cy = 1.0;
+            else if (ysArr[j] > yi) cy = 0.0;
+            else cy = 0.5; // eq
+            ri = ri + cx * cy;
+          }
+        }
+        r[i] = ri;
+      }
+      return r;
+    }
+
+    /// <summary>
+    /// Calculates midranks. Source: Numerical Recipes in C. p 642
+    /// </summary>
+    /// <param name="w">Sorted array of elements, replaces the elements by their rank, including midranking of ties</param>
+    /// <returns></returns>
+    private static void CRank(double[] w) {
+      int i = 0;
+      int n = w.Length;
+      while (i < n - 1) {
+        if (w[i + 1] > w[i]) {    // w[i+1] must be larger or equal w[i] as w must be sorted
+          // not a tie
+          w[i] = i + 1;
+          i++;
+        } else {
+          int j;
+          for (j = i + 1; j < n && w[j] <= w[i]; j++) ; // how far does it go (<= effectively means == as w must be sorted, side-step equality for double values)
+          double rank = 1 + 0.5 * (i + j - 1);
+          int k;
+          for (k = i; k < j; k++) w[k] = rank; // set the rank for all tied entries
+          i = j;
+        }
+      }
+
+      if (i == n - 1) w[n - 1] = n;   // if the last element was not tied, this is its rank
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/DependencyCalculator/PearsonsRDependenceCalculator.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/DependencyCalculator/PearsonsRDependenceCalculator.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/DependencyCalculator/PearsonsRDependenceCalculator.cs	(revision 13819)
@@ -0,0 +1,38 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  public class PearsonsRDependenceCalculator : IDependencyCalculator {
+
+    public double Maximum { get { return 1.0; } }
+
+    public double Minimum { get { return -1.0; } }
+
+    public string Name { get { return "Pearsons R"; } }
+
+    public double Calculate(IEnumerable<double> originalValues, IEnumerable<double> estimatedValues, out OnlineCalculatorError errorState) {
+      return OnlinePearsonsRCalculator.Calculate(originalValues, estimatedValues, out errorState);
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/DependencyCalculator/PearsonsRSquaredDependenceCalculator.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/DependencyCalculator/PearsonsRSquaredDependenceCalculator.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/DependencyCalculator/PearsonsRSquaredDependenceCalculator.cs	(revision 13819)
@@ -0,0 +1,38 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Collections.Generic;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  public class PearsonsRSquaredDependenceCalculator : IDependencyCalculator {
+
+    public double Maximum { get { return 1.0; } }
+
+    public double Minimum { get { return 0.0; } }
+
+    public string Name { get { return "Pearsons R Squared"; } }
+
+    public double Calculate(IEnumerable<double> originalValues, IEnumerable<double> estimatedValues, out OnlineCalculatorError errorState) {
+      var r = OnlinePearsonsRCalculator.Calculate(originalValues, estimatedValues, out errorState);
+      return r * r;
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/DependencyCalculator/SpearmansRankCorrelationCoefficientCalculator.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/DependencyCalculator/SpearmansRankCorrelationCoefficientCalculator.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/DependencyCalculator/SpearmansRankCorrelationCoefficientCalculator.cs	(revision 13819)
@@ -0,0 +1,53 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Collections.Generic;
+using System.Linq;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  public class SpearmansRankCorrelationCoefficientCalculator : IDependencyCalculator {
+
+    public double Maximum { get { return 1.0; } }
+
+    public double Minimum { get { return -1.0; } }
+
+    public string Name { get { return "Spearmans Rank"; } }
+
+    public double Calculate(IEnumerable<double> originalValues, IEnumerable<double> estimatedValues, out OnlineCalculatorError errorState) {
+      return SpearmansRankCorrelationCoefficientCalculator.CalculateSpearmansRank(originalValues, estimatedValues, out errorState);
+    }
+
+    public static double CalculateSpearmansRank(IEnumerable<double> originalValues, IEnumerable<double> estimatedValues, out OnlineCalculatorError errorState) {
+      double rs = double.NaN;
+      try {
+        var original = originalValues.ToArray();
+        var estimated = estimatedValues.ToArray();
+        rs = alglib.basestat.spearmancorr2(original, estimated, original.Length);
+        errorState = OnlineCalculatorError.None;
+      }
+      catch (alglib.alglibexception) {
+        errorState = OnlineCalculatorError.InvalidValueAdded;
+      }
+
+      return rs;
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/FOneScoreCalculator.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/FOneScoreCalculator.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/FOneScoreCalculator.cs	(revision 13819)
@@ -0,0 +1,53 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  public class FOneScoreCalculator {
+    public static double Calculate(IEnumerable<double> originalValues, IEnumerable<double> estimatedValues, out OnlineCalculatorError errorState) {
+      if (originalValues.Distinct().Skip(2).Any()) {
+        // TODO: we could use ClassificationPerformanceMeasuresCalculator instead of the ConfusionMatrixCalculator below to handle multi-class problems
+        throw new ArgumentException("F1 score can only be calculated for binary classification.");
+      }
+
+      var confusionMatrix = ConfusionMatrixCalculator.Calculate(originalValues, estimatedValues, out errorState);
+      if (!errorState.Equals(OnlineCalculatorError.None)) {
+        return double.NaN;
+      }
+      //only one class has been present => F1 score cannot be calculated
+      if (confusionMatrix.GetLength(0) != 2 || confusionMatrix.GetLength(1) != 2) {
+        return double.NaN;
+      }
+
+      return CalculateFOne(confusionMatrix);
+    }
+
+    private static double CalculateFOne(double[,] confusionMatrix) {
+      double precision = confusionMatrix[0, 0] / (confusionMatrix[0, 0] + confusionMatrix[0, 1]);
+      double recall = confusionMatrix[0, 0] / (confusionMatrix[0, 0] + confusionMatrix[1, 0]);
+
+      return 2 * ((precision * recall) / (precision + recall));
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/MatthewsCorrelationCoefficientCalculator.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/MatthewsCorrelationCoefficientCalculator.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/MatthewsCorrelationCoefficientCalculator.cs	(revision 13819)
@@ -0,0 +1,79 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+
+namespace HeuristicLab.Problems.DataAnalysis.OnlineCalculators {
+  public class MatthewsCorrelationCoefficientCalculator {
+    public static double Calculate(IEnumerable<double> originalValues, IEnumerable<double> estimatedValues, out OnlineCalculatorError errorState) {
+      var confusionMatrix = ConfusionMatrixCalculator.Calculate(originalValues, estimatedValues, out errorState);
+      if (!errorState.Equals(OnlineCalculatorError.None)) {
+        return double.NaN;
+      }
+      return CalculateMCC(confusionMatrix);
+    }
+
+    private static double CalculateMCC(double[,] confusionMatrix) {
+      if (confusionMatrix.GetLength(0) != confusionMatrix.GetLength(1)) {
+        throw new ArgumentException("Confusion matrix is not a square matrix.");
+      }
+
+      int classes = confusionMatrix.GetLength(0);
+      double numerator = 0;
+      for (int k = 0; k < classes; k++) {
+        for (int l = 0; l < classes; l++) {
+          for (int m = 0; m < classes; m++) {
+            numerator += confusionMatrix[k, k] * confusionMatrix[m, l] - confusionMatrix[l, k] * confusionMatrix[k, m];
+          }
+        }
+      }
+
+      double denominator1 = 0;
+      double denominator2 = 0;
+      for (int k = 0; k < classes; k++) {
+        double clk = 0;
+        double cgf = 0;
+        double ckl = 0;
+        double cfg = 0;
+        for (int l = 0; l < classes; l++) {
+          clk += confusionMatrix[l, k];
+          ckl += confusionMatrix[k, l];
+        }
+        for (int f = 0; f < classes; f++) {
+          if (f == k) {
+            continue;
+          }
+          for (int g = 0; g < classes; g++) {
+            cgf += confusionMatrix[g, f];
+            cfg += confusionMatrix[f, g];
+          }
+        }
+        denominator1 += clk * cgf;
+        denominator2 += ckl * cfg;
+      }
+      denominator1 = Math.Sqrt(denominator1);
+      denominator2 = Math.Sqrt(denominator2);
+
+      return numerator / (denominator1 * denominator2);
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/NormalizedGiniCalculator.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/NormalizedGiniCalculator.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/NormalizedGiniCalculator.cs	(revision 13819)
@@ -0,0 +1,65 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  public class NormalizedGiniCalculator {
+
+    public static double Calculate(IEnumerable<double> originalValues, IEnumerable<double> estimatedValues, out OnlineCalculatorError errorState) {
+      var originalValuesArr = originalValues.ToArray();
+      var estimatedValuesArr = estimatedValues.ToArray();
+      if (originalValuesArr.Count() != estimatedValuesArr.Count()) {
+        throw new ArgumentException("Number of elements in originalValues and estimatedValues enumerations doesn't match.");
+      }
+      double oe = Gini(originalValuesArr, estimatedValuesArr, out errorState);
+      if (errorState != OnlineCalculatorError.None) return double.NaN;
+
+      return oe / (Gini(originalValuesArr, originalValuesArr, out errorState));
+    }
+
+    private static double Gini(IEnumerable<double> original, IEnumerable<double> estimated, out OnlineCalculatorError errorState) {
+      var pairs =
+        estimated.Zip(original, (e, o) => new { e, o })
+          .OrderByDescending(p => p.e);
+      if (pairs.Any()) errorState = OnlineCalculatorError.None;
+      else errorState = OnlineCalculatorError.InsufficientElementsAdded;
+      double giniSum = 0.0;
+      double sumOriginal = 0.0;
+      int n = 0;
+      foreach (var p in pairs) {
+        if (double.IsNaN(p.o) || double.IsNaN(p.e)) {
+          errorState = OnlineCalculatorError.InvalidValueAdded;
+          return double.NaN;
+        }
+        sumOriginal += p.o;
+        giniSum += sumOriginal;
+        n++;
+      }
+      giniSum /= sumOriginal;
+
+      return (giniSum - ((n + 1) / 2.0)) / n;
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineAccuracyCalculator.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineAccuracyCalculator.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineAccuracyCalculator.cs	(revision 13819)
@@ -0,0 +1,93 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using HeuristicLab.Common;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  public class OnlineAccuracyCalculator : IOnlineCalculator {
+
+    private int correctlyClassified;
+    private int n;
+    public double Accuracy {
+      get {
+        return correctlyClassified / (double)n;
+      }
+    }
+
+    public OnlineAccuracyCalculator() {
+      Reset();
+    }
+
+    #region IOnlineCalculator Members
+    private OnlineCalculatorError errorState;
+    public OnlineCalculatorError ErrorState {
+      get { return errorState; }
+    }
+    public double Value {
+      get { return Accuracy; }
+    }
+    public void Reset() {
+      n = 0;
+      correctlyClassified = 0;
+      errorState = OnlineCalculatorError.InsufficientElementsAdded;
+    }
+
+    public void Add(double original, double estimated) {
+      // ignore cases where original is NaN completly 
+      if (!double.IsNaN(original)) {
+        // increment number of observed samples
+        n++;
+        if (original.IsAlmost(estimated)) {
+          // original = estimated = +Inf counts as correctly classified
+          // original = estimated = -Inf counts as correctly classified
+          correctlyClassified++;
+        }
+        errorState = OnlineCalculatorError.None; // number of (non-NaN) samples >= 1
+      }
+    }
+    #endregion
+
+    public static double Calculate(IEnumerable<double> originalValues, IEnumerable<double> estimatedValues, out OnlineCalculatorError errorState) {
+      IEnumerator<double> originalEnumerator = originalValues.GetEnumerator();
+      IEnumerator<double> estimatedEnumerator = estimatedValues.GetEnumerator();
+      OnlineAccuracyCalculator accuracyCalculator = new OnlineAccuracyCalculator();
+
+      // always move forward both enumerators (do not use short-circuit evaluation!)
+      while (originalEnumerator.MoveNext() & estimatedEnumerator.MoveNext()) {
+        double original = originalEnumerator.Current;
+        double estimated = estimatedEnumerator.Current;
+        accuracyCalculator.Add(original, estimated);
+        if (accuracyCalculator.ErrorState != OnlineCalculatorError.None) break;
+      }
+
+      // check if both enumerators are at the end to make sure both enumerations have the same length
+      if (accuracyCalculator.ErrorState == OnlineCalculatorError.None &&
+          (estimatedEnumerator.MoveNext() || originalEnumerator.MoveNext())) {
+        throw new ArgumentException("Number of elements in originalValues and estimatedValues enumerations doesn't match.");
+      } else {
+        errorState = accuracyCalculator.ErrorState;
+        return accuracyCalculator.Accuracy;
+      }
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineBoundedMeanSquaredErrorCalculator.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineBoundedMeanSquaredErrorCalculator.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineBoundedMeanSquaredErrorCalculator.cs	(revision 13819)
@@ -0,0 +1,99 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  public class OnlineBoundedMeanSquaredErrorCalculator : IOnlineCalculator {
+
+    private double errorSum;
+    private int n;
+    public double BoundedMeanSquaredError {
+      get {
+        return n > 0 ? errorSum / n : 0.0;
+      }
+    }
+
+    public double LowerBound { get; private set; }
+    public double UpperBound { get; private set; }
+
+
+    public OnlineBoundedMeanSquaredErrorCalculator(double lowerBound, double upperbound) {
+      LowerBound = lowerBound;
+      UpperBound = upperbound;
+      Reset();
+    }
+
+    #region IOnlineCalculator Members
+    private OnlineCalculatorError errorState;
+    public OnlineCalculatorError ErrorState {
+      get { return errorState; }
+    }
+    public double Value {
+      get { return BoundedMeanSquaredError; }
+    }
+    public void Reset() {
+      n = 0;
+      errorSum = 0.0;
+      errorState = OnlineCalculatorError.InsufficientElementsAdded;
+    }
+
+    public void Add(double original, double estimated) {
+      if (double.IsNaN(estimated) || double.IsInfinity(estimated) ||
+          double.IsNaN(original) || double.IsInfinity(original) || (errorState & OnlineCalculatorError.InvalidValueAdded) > 0) {
+        errorState = errorState | OnlineCalculatorError.InvalidValueAdded;
+      } else {
+        double error = estimated - original;
+        if (estimated < LowerBound || estimated > UpperBound)
+          errorSum += Math.Abs(error);
+        else
+          errorSum += error * error;
+        n++;
+        errorState = errorState & (~OnlineCalculatorError.InsufficientElementsAdded);        // n >= 1
+      }
+    }
+    #endregion
+
+    public static double Calculate(IEnumerable<double> originalValues, IEnumerable<double> estimatedValues, double lowerBound, double upperBound, out OnlineCalculatorError errorState) {
+      IEnumerator<double> originalEnumerator = originalValues.GetEnumerator();
+      IEnumerator<double> estimatedEnumerator = estimatedValues.GetEnumerator();
+      OnlineBoundedMeanSquaredErrorCalculator boundedMseCalculator = new OnlineBoundedMeanSquaredErrorCalculator(lowerBound, upperBound);
+
+      // always move forward both enumerators (do not use short-circuit evaluation!)
+      while (originalEnumerator.MoveNext() & estimatedEnumerator.MoveNext()) {
+        double original = originalEnumerator.Current;
+        double estimated = estimatedEnumerator.Current;
+        boundedMseCalculator.Add(original, estimated);
+        if (boundedMseCalculator.ErrorState != OnlineCalculatorError.None) break;
+      }
+
+      // check if both enumerators are at the end to make sure both enumerations have the same length
+      if (boundedMseCalculator.ErrorState == OnlineCalculatorError.None &&
+         (estimatedEnumerator.MoveNext() || originalEnumerator.MoveNext())) {
+        throw new ArgumentException("Number of elements in originalValues and estimatedValues enumerations doesn't match.");
+      } else {
+        errorState = boundedMseCalculator.ErrorState;
+        return boundedMseCalculator.BoundedMeanSquaredError;
+      }
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineCovarianceCalculator.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineCovarianceCalculator.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineCovarianceCalculator.cs	(revision 13819)
@@ -0,0 +1,97 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  public class OnlineCovarianceCalculator : IOnlineCalculator {
+
+    private double xMean, yMean, Cn;
+    private int n;
+    public double Covariance {
+      get {
+        return n > 0 ? Cn / n : 0.0;
+      }
+    }
+
+    public OnlineCovarianceCalculator() {
+      Reset();
+    }
+
+    #region IOnlineCalculator Members
+    private OnlineCalculatorError errorState;
+    public OnlineCalculatorError ErrorState {
+      get { return errorState; }
+    }
+    public double Value {
+      get { return Covariance; }
+    }
+    public void Reset() {
+      n = 0;
+      Cn = 0.0;
+      xMean = 0.0;
+      yMean = 0.0;
+      errorState = OnlineCalculatorError.InsufficientElementsAdded;
+    }
+
+    public void Add(double x, double y) {
+      if (double.IsNaN(y) || double.IsInfinity(y) || double.IsNaN(x) || double.IsInfinity(x) || (errorState & OnlineCalculatorError.InvalidValueAdded) > 0) {
+        errorState = errorState | OnlineCalculatorError.InvalidValueAdded;
+      } else {
+        n++;
+        errorState = errorState & (~OnlineCalculatorError.InsufficientElementsAdded);        // n >= 1
+
+        // online calculation of tMean
+        xMean = xMean + (x - xMean) / n;
+        double delta = y - yMean; // delta = (y - yMean(n-1))
+        yMean = yMean + delta / n;
+
+        // online calculation of covariance
+        Cn = Cn + delta * (x - xMean); // C(n) = C(n-1) + (y - yMean(n-1)) (t - tMean(n))       
+      }
+    }
+    #endregion
+
+    public static double Calculate(IEnumerable<double> first, IEnumerable<double> second, out OnlineCalculatorError errorState) {
+      IEnumerator<double> firstEnumerator = first.GetEnumerator();
+      IEnumerator<double> secondEnumerator = second.GetEnumerator();
+      OnlineCovarianceCalculator covarianceCalculator = new OnlineCovarianceCalculator();
+
+      // always move forward both enumerators (do not use short-circuit evaluation!)
+      while (firstEnumerator.MoveNext() & secondEnumerator.MoveNext()) {
+        double x = secondEnumerator.Current;
+        double y = firstEnumerator.Current;
+        covarianceCalculator.Add(x, y);
+        if (covarianceCalculator.ErrorState != OnlineCalculatorError.None) break;
+      }
+
+      // check if both enumerators are at the end to make sure both enumerations have the same length
+      if (covarianceCalculator.ErrorState == OnlineCalculatorError.None &&
+          (secondEnumerator.MoveNext() || firstEnumerator.MoveNext())) {
+        throw new ArgumentException("Number of elements in first and second enumeration doesn't match.");
+      } else {
+        errorState = covarianceCalculator.ErrorState;
+        return covarianceCalculator.Covariance;
+      }
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineDirectionalSymmetryCalculator.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineDirectionalSymmetryCalculator.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineDirectionalSymmetryCalculator.cs	(revision 13819)
@@ -0,0 +1,119 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using HeuristicLab.Common;
+
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  public class OnlineDirectionalSymmetryCalculator : IOnlineTimeSeriesCalculator {
+    private int n;
+    private int nCorrect;
+
+    public double DirectionalSymmetry {
+      get {
+        if (n < 1) return 0.0;
+        return (double)nCorrect / n;
+      }
+    }
+
+    public OnlineDirectionalSymmetryCalculator() {
+      Reset();
+    }
+
+    public double Value {
+      get { return DirectionalSymmetry; }
+    }
+
+    private OnlineCalculatorError errorState;
+    public OnlineCalculatorError ErrorState {
+      get { return errorState; }
+    }
+
+    public void Add(double startValue, IEnumerable<double> actualContinuation, IEnumerable<double> predictedContinuation) {
+      if (double.IsNaN(startValue) || (errorState & OnlineCalculatorError.InvalidValueAdded) > 0) {
+        errorState = errorState | OnlineCalculatorError.InvalidValueAdded;
+      } else {
+        var actualEnumerator = actualContinuation.GetEnumerator();
+        var predictedEnumerator = predictedContinuation.GetEnumerator();
+        double prevActual = startValue;
+        double prevPredicted = startValue;
+        while (actualEnumerator.MoveNext() & predictedEnumerator.MoveNext() & errorState != OnlineCalculatorError.InvalidValueAdded) {
+          double actual = actualEnumerator.Current;
+          double predicted = predictedEnumerator.Current;
+          if (double.IsNaN(actual) || double.IsNaN(predicted)) {
+            errorState = errorState | OnlineCalculatorError.InvalidValueAdded;
+          } else {
+            // count a prediction correct if the trend (positive/negative/no change) is predicted correctly
+            if ((actual - prevActual) * (predicted - prevPredicted) > 0.0 ||
+                (actual - prevActual).IsAlmost(predicted - prevPredicted)
+              ) {
+              nCorrect++;
+            }
+            n++;
+          }
+        }
+        // check if both enumerators are at the end to make sure both enumerations have the same length
+        if (actualEnumerator.MoveNext() || predictedEnumerator.MoveNext()) {
+          errorState = errorState | OnlineCalculatorError.InvalidValueAdded;
+        } else {
+          errorState = errorState & (~OnlineCalculatorError.InsufficientElementsAdded); // n >= 1
+        }
+      }
+    }
+
+    public void Reset() {
+      n = 0;
+      nCorrect = 0;
+      errorState = OnlineCalculatorError.InsufficientElementsAdded;
+    }
+
+    public static double Calculate(double startValue, IEnumerable<double> actualContinuation, IEnumerable<double> predictedContinuation, out OnlineCalculatorError errorState) {
+      OnlineDirectionalSymmetryCalculator dsCalculator = new OnlineDirectionalSymmetryCalculator();
+      dsCalculator.Add(startValue, actualContinuation, predictedContinuation);
+      errorState = dsCalculator.ErrorState;
+      return dsCalculator.DirectionalSymmetry;
+    }
+    
+    public static double Calculate(IEnumerable<double> startValues, IEnumerable<IEnumerable<double>> actualContinuations, IEnumerable<IEnumerable<double>> predictedContinuations, out OnlineCalculatorError errorState) {
+      IEnumerator<double> startValueEnumerator = startValues.GetEnumerator();
+      IEnumerator<IEnumerable<double>> actualContinuationsEnumerator = actualContinuations.GetEnumerator();
+      IEnumerator<IEnumerable<double>> predictedContinuationsEnumerator = predictedContinuations.GetEnumerator();
+      OnlineDirectionalSymmetryCalculator dsCalculator = new OnlineDirectionalSymmetryCalculator();
+
+      // always move forward all enumerators (do not use short-circuit evaluation!)
+      while (startValueEnumerator.MoveNext() & actualContinuationsEnumerator.MoveNext() & predictedContinuationsEnumerator.MoveNext()) {
+        dsCalculator.Add(startValueEnumerator.Current, actualContinuationsEnumerator.Current, predictedContinuationsEnumerator.Current);
+        if (dsCalculator.ErrorState != OnlineCalculatorError.None) break;
+      }
+
+      // check if all enumerators are at the end to make sure both enumerations have the same length
+      if (dsCalculator.ErrorState == OnlineCalculatorError.None &&
+          (startValueEnumerator.MoveNext() || actualContinuationsEnumerator.MoveNext() || predictedContinuationsEnumerator.MoveNext())) {
+        throw new ArgumentException("Number of elements in startValues, actualContinuations and estimatedValues predictedContinuations doesn't match.");
+      } else {
+        errorState = dsCalculator.ErrorState;
+        return dsCalculator.DirectionalSymmetry;
+      }
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineLinearScalingParameterCalculator.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineLinearScalingParameterCalculator.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineLinearScalingParameterCalculator.cs	(revision 13819)
@@ -0,0 +1,120 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using HeuristicLab.Common;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  public class OnlineLinearScalingParameterCalculator {
+
+    /// <summary>
+    /// Additive constant
+    /// </summary>
+    public double Alpha {
+      get {
+        return targetMeanCalculator.Mean - Beta * originalMeanAndVarianceCalculator.Mean;
+      }
+    }
+
+    /// <summary>
+    /// Multiplicative factor
+    /// </summary>
+    public double Beta {
+      get {
+        if (originalMeanAndVarianceCalculator.PopulationVariance.IsAlmost(0.0))
+          return 1;
+        else
+          return originalTargetCovarianceCalculator.Covariance / originalMeanAndVarianceCalculator.PopulationVariance;
+      }
+    }
+
+    public OnlineCalculatorError ErrorState {
+      get {
+        return targetMeanCalculator.MeanErrorState | originalMeanAndVarianceCalculator.MeanErrorState |
+          originalMeanAndVarianceCalculator.PopulationVarianceErrorState | originalTargetCovarianceCalculator.ErrorState;
+      }
+    }
+
+    private OnlineMeanAndVarianceCalculator targetMeanCalculator;
+    private OnlineMeanAndVarianceCalculator originalMeanAndVarianceCalculator;
+    private OnlineCovarianceCalculator originalTargetCovarianceCalculator;
+
+    public OnlineLinearScalingParameterCalculator() {
+      targetMeanCalculator = new OnlineMeanAndVarianceCalculator();
+      originalMeanAndVarianceCalculator = new OnlineMeanAndVarianceCalculator();
+      originalTargetCovarianceCalculator = new OnlineCovarianceCalculator();
+      Reset();
+    }
+
+    public void Reset() {
+      targetMeanCalculator.Reset();
+      originalMeanAndVarianceCalculator.Reset();
+      originalTargetCovarianceCalculator.Reset();
+    }
+
+    /// <summary>
+    /// Calculates linear scaling parameters in one pass.
+    /// The formulas to calculate the scaling parameters were taken from Scaled Symblic Regression by Maarten Keijzer.
+    /// http://www.springerlink.com/content/x035121165125175/
+    /// </summary>
+    public void Add(double original, double target) {
+      // validity of values is checked in mean calculator and covariance calculator
+      targetMeanCalculator.Add(target);
+      originalMeanAndVarianceCalculator.Add(original);
+      originalTargetCovarianceCalculator.Add(original, target);
+
+    }
+
+    /// <summary>
+    /// Calculates alpha and beta parameters to linearly scale elements of original to the scale and location of target
+    /// original[i] * beta + alpha
+    /// </summary>
+    /// <param name="original">Values that should be scaled</param>
+    /// <param name="target">Target values to which the original values should be scaled</param>
+    /// <param name="alpha">Additive constant for the linear scaling</param>
+    /// <param name="beta">Multiplicative factor for the linear scaling</param>
+    /// <param name="errorState">Flag that indicates if errors occurred in the calculation of the linea scaling parameters.</param>
+    public static void Calculate(IEnumerable<double> original, IEnumerable<double> target, out double alpha, out double beta, out OnlineCalculatorError errorState) {
+      OnlineLinearScalingParameterCalculator calculator = new OnlineLinearScalingParameterCalculator();
+      IEnumerator<double> originalEnumerator = original.GetEnumerator();
+      IEnumerator<double> targetEnumerator = target.GetEnumerator();
+
+      // always move forward both enumerators (do not use short-circuit evaluation!)
+      while (originalEnumerator.MoveNext() & targetEnumerator.MoveNext()) {
+        double originalElement = originalEnumerator.Current;
+        double targetElement = targetEnumerator.Current;
+        calculator.Add(originalElement, targetElement);
+        if (calculator.ErrorState != OnlineCalculatorError.None) break;
+      }
+
+      // check if both enumerators are at the end to make sure both enumerations have the same length
+      if (calculator.ErrorState == OnlineCalculatorError.None &&
+            (originalEnumerator.MoveNext() || targetEnumerator.MoveNext())) {
+        throw new ArgumentException("Number of elements in original and target enumeration do not match.");
+      } else {
+        errorState = calculator.ErrorState;
+        alpha = calculator.Alpha;
+        beta = calculator.Beta;
+      }
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineMaxAbsoluteErrorCalculator.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineMaxAbsoluteErrorCalculator.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineMaxAbsoluteErrorCalculator.cs	(revision 13819)
@@ -0,0 +1,91 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  public class OnlineMaxAbsoluteErrorCalculator : IOnlineCalculator {
+
+    private double mae;
+    private int n;
+    public double MaxAbsoluteError {
+      get {
+        return n > 0 ? mae : 0.0;
+      }
+    }
+
+    public OnlineMaxAbsoluteErrorCalculator() {
+      Reset();
+    }
+
+    #region IOnlineCalculator Members
+    private OnlineCalculatorError errorState;
+    public OnlineCalculatorError ErrorState {
+      get { return errorState; }
+    }
+    public double Value {
+      get { return MaxAbsoluteError; }
+    }
+    public void Reset() {
+      n = 0;
+      mae = double.MinValue;
+      errorState = OnlineCalculatorError.InsufficientElementsAdded;
+    }
+
+    public void Add(double original, double estimated) {
+      if (double.IsNaN(estimated) || double.IsInfinity(estimated) ||
+          double.IsNaN(original) || double.IsInfinity(original) || (errorState & OnlineCalculatorError.InvalidValueAdded) > 0) {
+        errorState = errorState | OnlineCalculatorError.InvalidValueAdded;
+      } else {
+        double error = Math.Abs(estimated - original);
+        if (error > mae)
+          mae = error;
+        n++;
+        errorState = errorState & (~OnlineCalculatorError.InsufficientElementsAdded);        // n >= 1
+      }
+    }
+    #endregion
+
+    public static double Calculate(IEnumerable<double> originalValues, IEnumerable<double> estimatedValues, out OnlineCalculatorError errorState) {
+      IEnumerator<double> originalEnumerator = originalValues.GetEnumerator();
+      IEnumerator<double> estimatedEnumerator = estimatedValues.GetEnumerator();
+      OnlineMaxAbsoluteErrorCalculator maeCalculator = new OnlineMaxAbsoluteErrorCalculator();
+
+      // always move forward both enumerators (do not use short-circuit evaluation!)
+      while (originalEnumerator.MoveNext() & estimatedEnumerator.MoveNext()) {
+        double original = originalEnumerator.Current;
+        double estimated = estimatedEnumerator.Current;
+        maeCalculator.Add(original, estimated);
+        if (maeCalculator.ErrorState != OnlineCalculatorError.None) break;
+      }
+
+      // check if both enumerators are at the end to make sure both enumerations have the same length
+      if (maeCalculator.ErrorState == OnlineCalculatorError.None &&
+         (estimatedEnumerator.MoveNext() || originalEnumerator.MoveNext())) {
+        throw new ArgumentException("Number of elements in originalValues and estimatedValues enumerations doesn't match.");
+      } else {
+        errorState = maeCalculator.ErrorState;
+        return maeCalculator.MaxAbsoluteError;
+      }
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineMeanAbsoluteErrorCalculator.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineMeanAbsoluteErrorCalculator.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineMeanAbsoluteErrorCalculator.cs	(revision 13819)
@@ -0,0 +1,90 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  public class OnlineMeanAbsoluteErrorCalculator : IOnlineCalculator {
+
+    private double sae;
+    private int n;
+    public double MeanAbsoluteError {
+      get {
+        return n > 0 ? sae / n : 0.0;
+      }
+    }
+
+    public OnlineMeanAbsoluteErrorCalculator() {
+      Reset();
+    }
+
+    #region IOnlineCalculator Members
+    private OnlineCalculatorError errorState;
+    public OnlineCalculatorError ErrorState {
+      get { return errorState; }
+    }
+    public double Value {
+      get { return MeanAbsoluteError; }
+    }
+    public void Reset() {
+      n = 0;
+      sae = 0.0;
+      errorState = OnlineCalculatorError.InsufficientElementsAdded;
+    }
+
+    public void Add(double original, double estimated) {
+      if (double.IsNaN(estimated) || double.IsInfinity(estimated) ||
+          double.IsNaN(original) || double.IsInfinity(original) || (errorState & OnlineCalculatorError.InvalidValueAdded) > 0) {
+        errorState = errorState | OnlineCalculatorError.InvalidValueAdded;
+      } else {
+        double error = estimated - original;
+        sae += Math.Abs(error);
+        n++;
+        errorState = errorState & (~OnlineCalculatorError.InsufficientElementsAdded);        // n >= 1
+      }
+    }
+    #endregion
+
+    public static double Calculate(IEnumerable<double> originalValues, IEnumerable<double> estimatedValues, out OnlineCalculatorError errorState) {
+      IEnumerator<double> originalEnumerator = originalValues.GetEnumerator();
+      IEnumerator<double> estimatedEnumerator = estimatedValues.GetEnumerator();
+      OnlineMeanAbsoluteErrorCalculator maeCalculator = new OnlineMeanAbsoluteErrorCalculator();
+
+      // always move forward both enumerators (do not use short-circuit evaluation!)
+      while (originalEnumerator.MoveNext() & estimatedEnumerator.MoveNext()) {
+        double original = originalEnumerator.Current;
+        double estimated = estimatedEnumerator.Current;
+        maeCalculator.Add(original, estimated);
+        if (maeCalculator.ErrorState != OnlineCalculatorError.None) break;
+      }
+
+      // check if both enumerators are at the end to make sure both enumerations have the same length
+      if (maeCalculator.ErrorState == OnlineCalculatorError.None &&
+         (estimatedEnumerator.MoveNext() || originalEnumerator.MoveNext())) {
+        throw new ArgumentException("Number of elements in originalValues and estimatedValues enumerations doesn't match.");
+      } else {
+        errorState = maeCalculator.ErrorState;
+        return maeCalculator.MeanAbsoluteError;
+      }
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineMeanAbsolutePercentageErrorCalculator.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineMeanAbsolutePercentageErrorCalculator.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineMeanAbsolutePercentageErrorCalculator.cs	(revision 13819)
@@ -0,0 +1,92 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using HeuristicLab.Common;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  public class OnlineMeanAbsolutePercentageErrorCalculator : IOnlineCalculator {
+
+    private double sre;
+    private int n;
+    public double MeanAbsolutePercentageError {
+      get {
+        return n > 0 ? sre / n : 0.0;
+      }
+    }
+
+    public OnlineMeanAbsolutePercentageErrorCalculator() {
+      Reset();
+    }
+
+    #region IOnlineCalculator Members
+    private OnlineCalculatorError errorState;
+    public OnlineCalculatorError ErrorState {
+      get { return errorState; }
+    }
+    public double Value {
+      get { return MeanAbsolutePercentageError; }
+    }
+    public void Reset() {
+      n = 0;
+      sre = 0.0;
+      errorState = OnlineCalculatorError.InsufficientElementsAdded;
+    }
+
+    public void Add(double original, double estimated) {
+      if (double.IsNaN(estimated) || double.IsInfinity(estimated) ||
+          double.IsNaN(original) || double.IsInfinity(original) ||
+        original.IsAlmost(0.0)) {
+        errorState = errorState | OnlineCalculatorError.InvalidValueAdded;
+      } else {
+        sre += Math.Abs((estimated - original) / original);
+        n++;
+        errorState = errorState & (~OnlineCalculatorError.InsufficientElementsAdded);        // n >= 1
+      }
+    }
+
+    #endregion
+
+    public static double Calculate(IEnumerable<double> originalValues, IEnumerable<double> estimatedValues, out OnlineCalculatorError errorState) {
+      IEnumerator<double> originalEnumerator = originalValues.GetEnumerator();
+      IEnumerator<double> estimatedEnumerator = estimatedValues.GetEnumerator();
+      OnlineMeanAbsolutePercentageErrorCalculator calculator = new OnlineMeanAbsolutePercentageErrorCalculator();
+
+      // always move forward both enumerators (do not use short-circuit evaluation!)
+      while (originalEnumerator.MoveNext() & estimatedEnumerator.MoveNext()) {
+        double original = originalEnumerator.Current;
+        double estimated = estimatedEnumerator.Current;
+        calculator.Add(original, estimated);
+        if (calculator.ErrorState != OnlineCalculatorError.None) break;
+      }
+
+      // check if both enumerators are at the end to make sure both enumerations have the same length
+      if (calculator.ErrorState == OnlineCalculatorError.None &&
+            (estimatedEnumerator.MoveNext() || originalEnumerator.MoveNext())) {
+        throw new ArgumentException("Number of elements in originalValues and second estimatedValues doesn't match.");
+      } else {
+        errorState = calculator.ErrorState;
+        return calculator.MeanAbsolutePercentageError;
+      }
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineMeanAndVarianceCalculator.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineMeanAndVarianceCalculator.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineMeanAndVarianceCalculator.cs	(revision 13819)
@@ -0,0 +1,109 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Collections.Generic;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  public class OnlineMeanAndVarianceCalculator {
+
+    private double m_oldM, m_newM, m_oldS, m_newS;
+    private int n;
+
+    private OnlineCalculatorError varianceErrorState;
+    public OnlineCalculatorError VarianceErrorState {
+      get { return varianceErrorState; }
+    }
+
+    public double Variance {
+      get {
+        return (n > 1) ? m_newS / (n - 1) : 0.0;
+      }
+    }
+
+    private OnlineCalculatorError errorState;
+    public OnlineCalculatorError PopulationVarianceErrorState {
+      get { return errorState; }
+    }
+    public double PopulationVariance {
+      get {
+        return (n > 0) ? m_newS / n : 0.0;
+      }
+    }
+
+    public OnlineCalculatorError MeanErrorState {
+      get { return errorState; }
+    }
+    public double Mean {
+      get {
+        return (n > 0) ? m_newM : 0.0;
+      }
+    }
+
+    public int Count {
+      get { return n; }
+    }
+
+    public OnlineMeanAndVarianceCalculator() {
+      Reset();
+    }
+
+    public void Reset() {
+      n = 0;
+      errorState = OnlineCalculatorError.InsufficientElementsAdded;
+      varianceErrorState = OnlineCalculatorError.InsufficientElementsAdded;
+    }
+
+    public void Add(double x) {
+      if (double.IsNaN(x) || double.IsInfinity(x) || x > 1E13 || x < -1E13 || (errorState & OnlineCalculatorError.InvalidValueAdded) > 0) {
+        errorState = errorState | OnlineCalculatorError.InvalidValueAdded;
+        varianceErrorState = errorState | OnlineCalculatorError.InvalidValueAdded;
+      } else {
+        n++;
+        // See Knuth TAOCP vol 2, 3rd edition, page 232
+        if (n == 1) {
+          m_oldM = m_newM = x;
+          m_oldS = 0.0;
+          errorState = errorState & (~OnlineCalculatorError.InsufficientElementsAdded);        // n >= 1
+        } else {
+
+          varianceErrorState = varianceErrorState & (~OnlineCalculatorError.InsufficientElementsAdded);        // n >= 2
+          m_newM = m_oldM + (x - m_oldM) / n;
+          m_newS = m_oldS + (x - m_oldM) * (x - m_newM);
+
+          // set up for next iteration
+          m_oldM = m_newM;
+          m_oldS = m_newS;
+        }
+      }
+    }
+
+    public static void Calculate(IEnumerable<double> x, out double mean, out double variance, out OnlineCalculatorError meanErrorState, out OnlineCalculatorError varianceErrorState) {
+      OnlineMeanAndVarianceCalculator meanAndVarianceCalculator = new OnlineMeanAndVarianceCalculator();
+      foreach (double xi in x) {
+        meanAndVarianceCalculator.Add(xi);
+      }
+      mean = meanAndVarianceCalculator.Mean;
+      variance = meanAndVarianceCalculator.Variance;
+      meanErrorState = meanAndVarianceCalculator.MeanErrorState;
+      varianceErrorState = meanAndVarianceCalculator.VarianceErrorState;
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineMeanErrorCalculator.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineMeanErrorCalculator.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineMeanErrorCalculator.cs	(revision 13819)
@@ -0,0 +1,77 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  public class OnlineMeanErrorCalculator : IOnlineCalculator {
+
+    private readonly OnlineMeanAndVarianceCalculator meanAndVarianceCalculator;
+    public double MeanError {
+      get { return meanAndVarianceCalculator.Mean; }
+    }
+
+    public OnlineMeanErrorCalculator() {
+      meanAndVarianceCalculator = new OnlineMeanAndVarianceCalculator();
+      Reset();
+    }
+
+    #region IOnlineCalculator Members
+    public OnlineCalculatorError ErrorState {
+      get { return meanAndVarianceCalculator.MeanErrorState; }
+    }
+    public double Value {
+      get { return MeanError; }
+    }
+    public void Reset() {
+      meanAndVarianceCalculator.Reset();
+    }
+
+    public void Add(double original, double estimated) {
+      meanAndVarianceCalculator.Add(estimated - original);
+    }
+    #endregion
+
+    public static double Calculate(IEnumerable<double> originalValues, IEnumerable<double> estimatedValues, out OnlineCalculatorError errorState) {
+      IEnumerator<double> originalEnumerator = originalValues.GetEnumerator();
+      IEnumerator<double> estimatedEnumerator = estimatedValues.GetEnumerator();
+      OnlineMeanErrorCalculator meCalculator = new OnlineMeanErrorCalculator();
+
+      // always move forward both enumerators (do not use short-circuit evaluation!)
+      while (originalEnumerator.MoveNext() & estimatedEnumerator.MoveNext()) {
+        double original = originalEnumerator.Current;
+        double estimated = estimatedEnumerator.Current;
+        meCalculator.Add(original, estimated);
+        if (meCalculator.ErrorState != OnlineCalculatorError.None) break;
+      }
+
+      // check if both enumerators are at the end to make sure both enumerations have the same length
+      if (meCalculator.ErrorState == OnlineCalculatorError.None &&
+         (estimatedEnumerator.MoveNext() || originalEnumerator.MoveNext())) {
+        throw new ArgumentException("Number of elements in originalValues and estimatedValues enumerations doesn't match.");
+      } else {
+        errorState = meCalculator.ErrorState;
+        return meCalculator.MeanError;
+      }
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineMeanSquaredErrorCalculator.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineMeanSquaredErrorCalculator.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineMeanSquaredErrorCalculator.cs	(revision 13819)
@@ -0,0 +1,90 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  public class OnlineMeanSquaredErrorCalculator : IOnlineCalculator {
+
+    private double sse;
+    private int n;
+    public double MeanSquaredError {
+      get {
+        return n > 0 ? sse / n : 0.0;
+      }
+    }
+
+    public OnlineMeanSquaredErrorCalculator() {
+      Reset();
+    }
+
+    #region IOnlineCalculator Members
+    private OnlineCalculatorError errorState;
+    public OnlineCalculatorError ErrorState {
+      get { return errorState; }
+    }
+    public double Value {
+      get { return MeanSquaredError; }
+    }
+    public void Reset() {
+      n = 0;
+      sse = 0.0;
+      errorState = OnlineCalculatorError.InsufficientElementsAdded;
+    }
+
+    public void Add(double original, double estimated) {
+      if (double.IsNaN(estimated) || double.IsInfinity(estimated) ||
+          double.IsNaN(original) || double.IsInfinity(original) || (errorState & OnlineCalculatorError.InvalidValueAdded) > 0) {
+        errorState = errorState | OnlineCalculatorError.InvalidValueAdded;
+      } else {
+        double error = estimated - original;
+        sse += error * error;
+        n++;
+        errorState = errorState & (~OnlineCalculatorError.InsufficientElementsAdded);        // n >= 1
+      }
+    }
+    #endregion
+
+    public static double Calculate(IEnumerable<double> originalValues, IEnumerable<double> estimatedValues, out OnlineCalculatorError errorState) {
+      IEnumerator<double> originalEnumerator = originalValues.GetEnumerator();
+      IEnumerator<double> estimatedEnumerator = estimatedValues.GetEnumerator();
+      OnlineMeanSquaredErrorCalculator mseCalculator = new OnlineMeanSquaredErrorCalculator();
+
+      // always move forward both enumerators (do not use short-circuit evaluation!)
+      while (originalEnumerator.MoveNext() & estimatedEnumerator.MoveNext()) {
+        double original = originalEnumerator.Current;
+        double estimated = estimatedEnumerator.Current;
+        mseCalculator.Add(original, estimated);
+        if (mseCalculator.ErrorState != OnlineCalculatorError.None) break;
+      }
+
+      // check if both enumerators are at the end to make sure both enumerations have the same length
+      if (mseCalculator.ErrorState == OnlineCalculatorError.None &&
+         (estimatedEnumerator.MoveNext() || originalEnumerator.MoveNext())) {
+        throw new ArgumentException("Number of elements in originalValues and estimatedValues enumerations doesn't match.");
+      } else {
+        errorState = mseCalculator.ErrorState;
+        return mseCalculator.MeanSquaredError;
+      }
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineNormalizedMeanSquaredErrorCalculator.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineNormalizedMeanSquaredErrorCalculator.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineNormalizedMeanSquaredErrorCalculator.cs	(revision 13819)
@@ -0,0 +1,95 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  public class OnlineNormalizedMeanSquaredErrorCalculator : IOnlineCalculator {
+    private OnlineMeanAndVarianceCalculator meanSquaredErrorCalculator;
+    private OnlineMeanAndVarianceCalculator originalVarianceCalculator;
+
+    public double NormalizedMeanSquaredError {
+      get {
+        double var = originalVarianceCalculator.Variance;
+        double m = meanSquaredErrorCalculator.Mean;
+        return var > 0 ? m / var : 0.0;
+      }
+    }
+
+    public OnlineNormalizedMeanSquaredErrorCalculator() {
+      meanSquaredErrorCalculator = new OnlineMeanAndVarianceCalculator();
+      originalVarianceCalculator = new OnlineMeanAndVarianceCalculator();
+      Reset();
+    }
+
+    #region IOnlineCalculator Members
+    public OnlineCalculatorError ErrorState {
+      get { return meanSquaredErrorCalculator.MeanErrorState | originalVarianceCalculator.VarianceErrorState; }
+    }
+    public double Value {
+      get { return NormalizedMeanSquaredError; }
+    }
+
+    public void Reset() {
+      meanSquaredErrorCalculator.Reset();
+      originalVarianceCalculator.Reset();
+    }
+
+    public void Add(double original, double estimated) {
+      // no need to check for validity of values explicitly as it is checked in the meanAndVariance calculator anyway
+      double error = estimated - original;
+      meanSquaredErrorCalculator.Add(error * error);
+      originalVarianceCalculator.Add(original);
+    }
+    #endregion
+
+    public static double Calculate(IEnumerable<double> originalValues, IEnumerable<double> estimatedValues, out OnlineCalculatorError errorState) {
+      IEnumerator<double> originalEnumerator = originalValues.GetEnumerator();
+      IEnumerator<double> estimatedEnumerator = estimatedValues.GetEnumerator();
+      OnlineNormalizedMeanSquaredErrorCalculator normalizedMSECalculator = new OnlineNormalizedMeanSquaredErrorCalculator();
+
+      //needed because otherwise the normalizedMSECalculator is in ErrorState.InsufficientValuesAdded
+      if (originalEnumerator.MoveNext() & estimatedEnumerator.MoveNext()) {
+        double original = originalEnumerator.Current;
+        double estimated = estimatedEnumerator.Current;
+        normalizedMSECalculator.Add(original, estimated);
+      }
+
+      // always move forward both enumerators (do not use short-circuit evaluation!)
+      while (originalEnumerator.MoveNext() & estimatedEnumerator.MoveNext()) {
+        double original = originalEnumerator.Current;
+        double estimated = estimatedEnumerator.Current;
+        normalizedMSECalculator.Add(original, estimated);
+        if (normalizedMSECalculator.ErrorState != OnlineCalculatorError.None) break;
+      }
+
+      // check if both enumerators are at the end to make sure both enumerations have the same length
+      if (normalizedMSECalculator.ErrorState == OnlineCalculatorError.None &&
+           (estimatedEnumerator.MoveNext() || originalEnumerator.MoveNext())) {
+        throw new ArgumentException("Number of elements in originalValues and estimatedValues enumeration doesn't match.");
+      } else {
+        errorState = normalizedMSECalculator.ErrorState;
+        return normalizedMSECalculator.NormalizedMeanSquaredError;
+      }
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlinePearsonsRCalculator.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlinePearsonsRCalculator.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlinePearsonsRCalculator.cs	(revision 13819)
@@ -0,0 +1,94 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using HeuristicLab.Common;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  public class OnlinePearsonsRCalculator : IOnlineCalculator {
+    private OnlineCovarianceCalculator covCalculator = new OnlineCovarianceCalculator();
+    private OnlineMeanAndVarianceCalculator sxCalculator = new OnlineMeanAndVarianceCalculator();
+    private OnlineMeanAndVarianceCalculator syCalculator = new OnlineMeanAndVarianceCalculator();
+
+    public double R {
+      get {
+        double xVar = sxCalculator.PopulationVariance;
+        double yVar = syCalculator.PopulationVariance;
+        if (xVar.IsAlmost(0.0) || yVar.IsAlmost(0.0)) {
+          return 0.0;
+        } else {
+          var r = covCalculator.Covariance / (Math.Sqrt(xVar) * Math.Sqrt(yVar));
+          if (r < -1.0) r = -1.0;
+          else if (r > 1.0) r = 1.0;
+          return r;
+        }
+      }
+    }
+
+    public OnlinePearsonsRCalculator() { }
+
+    #region IOnlineCalculator Members
+    public OnlineCalculatorError ErrorState {
+      get { return covCalculator.ErrorState | sxCalculator.PopulationVarianceErrorState | syCalculator.PopulationVarianceErrorState; }
+    }
+    public double Value {
+      get { return R; }
+    }
+    public void Reset() {
+      covCalculator.Reset();
+      sxCalculator.Reset();
+      syCalculator.Reset();
+    }
+
+    public void Add(double x, double y) {
+      // no need to check validity of values explicitly here as it is checked in all three evaluators 
+      covCalculator.Add(x, y);
+      sxCalculator.Add(x);
+      syCalculator.Add(y);
+    }
+
+    #endregion
+
+    public static double Calculate(IEnumerable<double> first, IEnumerable<double> second, out OnlineCalculatorError errorState) {
+      IEnumerator<double> firstEnumerator = first.GetEnumerator();
+      IEnumerator<double> secondEnumerator = second.GetEnumerator();
+      var calculator = new OnlinePearsonsRCalculator();
+
+      // always move forward both enumerators (do not use short-circuit evaluation!)
+      while (firstEnumerator.MoveNext() & secondEnumerator.MoveNext()) {
+        double original = firstEnumerator.Current;
+        double estimated = secondEnumerator.Current;
+        calculator.Add(original, estimated);
+        if (calculator.ErrorState != OnlineCalculatorError.None) break;
+      }
+
+      // check if both enumerators are at the end to make sure both enumerations have the same length
+      if (calculator.ErrorState == OnlineCalculatorError.None &&
+           (secondEnumerator.MoveNext() || firstEnumerator.MoveNext())) {
+        throw new ArgumentException("Number of elements in first and second enumeration doesn't match.");
+      } else {
+        errorState = calculator.ErrorState;
+        return calculator.R;
+      }
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlinePearsonsRSquaredCalculator.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlinePearsonsRSquaredCalculator.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlinePearsonsRSquaredCalculator.cs	(revision 13819)
@@ -0,0 +1,62 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using HeuristicLab.Common;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  [Obsolete("Use OnlinePearsonsRCalculator directly")]
+  public class OnlinePearsonsRSquaredCalculator : IOnlineCalculator {
+    private readonly OnlinePearsonsRCalculator rCalculator = new OnlinePearsonsRCalculator();
+
+    public double RSquared {
+      get {
+        if (rCalculator.ErrorState != OnlineCalculatorError.None) return 0.0;
+        else return rCalculator.R * rCalculator.R;
+      }
+    }
+
+    public OnlinePearsonsRSquaredCalculator() { }
+
+    #region IOnlineCalculator Members
+    public OnlineCalculatorError ErrorState {
+      get { return rCalculator.ErrorState; }
+    }
+    public double Value {
+      get { return RSquared; }
+    }
+    public void Reset() {
+      rCalculator.Reset();
+    }
+
+    public void Add(double x, double y) {
+      rCalculator.Add(x, y);
+    }
+
+    #endregion
+
+    public static double Calculate(IEnumerable<double> first, IEnumerable<double> second, out OnlineCalculatorError errorState) {
+      var r = OnlinePearsonsRCalculator.Calculate(first, second, out errorState);
+      return r * r;
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineTheilsUStatisticCalculator.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineTheilsUStatisticCalculator.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineTheilsUStatisticCalculator.cs	(revision 13819)
@@ -0,0 +1,128 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  public class OnlineTheilsUStatisticCalculator : IOnlineTimeSeriesCalculator {
+    private OnlineMeanAndVarianceCalculator squaredErrorMeanCalculator;
+    private OnlineMeanAndVarianceCalculator unbiasedEstimatorMeanCalculator;
+
+    public double TheilsUStatistic {
+      get {
+        return Math.Sqrt(squaredErrorMeanCalculator.Mean) / Math.Sqrt(unbiasedEstimatorMeanCalculator.Mean);
+      }
+    }
+
+    private OnlineCalculatorError errorState;
+    public OnlineCalculatorError ErrorState {
+      get { return errorState | squaredErrorMeanCalculator.MeanErrorState | unbiasedEstimatorMeanCalculator.MeanErrorState; }
+    }
+
+    public OnlineTheilsUStatisticCalculator() {
+      squaredErrorMeanCalculator = new OnlineMeanAndVarianceCalculator();
+      unbiasedEstimatorMeanCalculator = new OnlineMeanAndVarianceCalculator();
+      Reset();
+    }
+
+    #region IOnlineEvaluator Members
+    public double Value {
+      get { return TheilsUStatistic; }
+    }
+
+    public void Add(double startValue, IEnumerable<double> actualContinuation, IEnumerable<double> predictedContinuation) {
+      throw new NotSupportedException();
+    }
+
+    public void Add(double startValue, IEnumerable<double> actualContinuation, IEnumerable<double> referenceContinuation, IEnumerable<double> predictedContinuation) {
+      if (double.IsNaN(startValue) || (errorState & OnlineCalculatorError.InvalidValueAdded) > 0) {
+        errorState = errorState | OnlineCalculatorError.InvalidValueAdded;
+      } else {
+        var actualEnumerator = actualContinuation.GetEnumerator();
+        var predictedEnumerator = predictedContinuation.GetEnumerator();
+        var referenceEnumerator = referenceContinuation.GetEnumerator();
+        while (actualEnumerator.MoveNext() & predictedEnumerator.MoveNext() & referenceEnumerator.MoveNext()
+          & ErrorState != OnlineCalculatorError.InvalidValueAdded) {
+          double actual = actualEnumerator.Current;
+          double predicted = predictedEnumerator.Current;
+          double reference = referenceEnumerator.Current;
+          if (double.IsNaN(actual) || double.IsNaN(predicted) || double.IsNaN(reference)) {
+            errorState = errorState | OnlineCalculatorError.InvalidValueAdded;
+          } else {
+            // error of predicted change
+            double errorPredictedChange = (predicted - startValue) - (actual - startValue);
+            squaredErrorMeanCalculator.Add(errorPredictedChange * errorPredictedChange);
+
+            double errorReference = (reference - startValue) - (actual - startValue);
+            unbiasedEstimatorMeanCalculator.Add(errorReference * errorReference);
+          }
+        }
+        // check if both enumerators are at the end to make sure both enumerations have the same length
+        if (actualEnumerator.MoveNext() || predictedEnumerator.MoveNext() || referenceEnumerator.MoveNext()) {
+          errorState = errorState | OnlineCalculatorError.InvalidValueAdded;
+        } else {
+          errorState = errorState & (~OnlineCalculatorError.InsufficientElementsAdded); // n >= 1
+        }
+      }
+    }
+
+
+    public void Reset() {
+      squaredErrorMeanCalculator.Reset();
+      unbiasedEstimatorMeanCalculator.Reset();
+      errorState = OnlineCalculatorError.InsufficientElementsAdded;
+    }
+
+    #endregion
+
+    public static double Calculate(double startValue, IEnumerable<double> actualContinuation, IEnumerable<double> referenceContinuation, IEnumerable<double> predictedContinuation, out OnlineCalculatorError errorState) {
+      OnlineTheilsUStatisticCalculator calculator = new OnlineTheilsUStatisticCalculator();
+      calculator.Add(startValue, actualContinuation, referenceContinuation, predictedContinuation);
+      errorState = calculator.ErrorState;
+      return calculator.TheilsUStatistic;
+    }
+
+    public static double Calculate(IEnumerable<double> startValues, IEnumerable<IEnumerable<double>> actualContinuations, IEnumerable<IEnumerable<double>> referenceContinuations, IEnumerable<IEnumerable<double>> predictedContinuations, out OnlineCalculatorError errorState) {
+      IEnumerator<double> startValueEnumerator = startValues.GetEnumerator();
+      IEnumerator<IEnumerable<double>> actualContinuationsEnumerator = actualContinuations.GetEnumerator();
+      IEnumerator<IEnumerable<double>> referenceContinuationsEnumerator = referenceContinuations.GetEnumerator();
+      IEnumerator<IEnumerable<double>> predictedContinuationsEnumerator = predictedContinuations.GetEnumerator();
+
+      OnlineTheilsUStatisticCalculator calculator = new OnlineTheilsUStatisticCalculator();
+
+      // always move forward all enumerators (do not use short-circuit evaluation!)
+      while (startValueEnumerator.MoveNext() & actualContinuationsEnumerator.MoveNext() & referenceContinuationsEnumerator.MoveNext() & predictedContinuationsEnumerator.MoveNext()) {
+        calculator.Add(startValueEnumerator.Current, actualContinuationsEnumerator.Current, referenceContinuationsEnumerator.Current, predictedContinuationsEnumerator.Current);
+        if (calculator.ErrorState != OnlineCalculatorError.None) break;
+      }
+
+      // check if all enumerators are at the end to make sure both enumerations have the same length
+      if (calculator.ErrorState == OnlineCalculatorError.None &&
+          (startValueEnumerator.MoveNext() || actualContinuationsEnumerator.MoveNext() || referenceContinuationsEnumerator.MoveNext() || predictedContinuationsEnumerator.MoveNext())) {
+        throw new ArgumentException("Number of elements in startValues, actualContinuations, referenceContinuation and estimatedValues predictedContinuations doesn't match.");
+      } else {
+        errorState = calculator.ErrorState;
+        return calculator.TheilsUStatistic;
+      }
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineWeightedDirectionalSymmetryCalculator.cs
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineWeightedDirectionalSymmetryCalculator.cs	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/OnlineWeightedDirectionalSymmetryCalculator.cs	(revision 13819)
@@ -0,0 +1,121 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using HeuristicLab.Common;
+
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  public class OnlineWeightedDirectionalSymmetryCalculator : IOnlineTimeSeriesCalculator {
+    private int n;
+    private double correctSum;
+    private double incorrectSum;
+
+    public double WeightedDirectionalSymmetry {
+      get {
+        if (n <= 1) return 0.0;
+        return incorrectSum / correctSum;
+      }
+    }
+
+    public OnlineWeightedDirectionalSymmetryCalculator() {
+      Reset();
+    }
+
+    public double Value {
+      get { return WeightedDirectionalSymmetry; }
+    }
+
+    private OnlineCalculatorError errorState;
+    public OnlineCalculatorError ErrorState {
+      get { return errorState; }
+    }
+
+    public void Add(double startValue, IEnumerable<double> actualContinuation, IEnumerable<double> predictedContinuation) {
+      if (double.IsNaN(startValue) || (errorState & OnlineCalculatorError.InvalidValueAdded) > 0) {
+        errorState = errorState | OnlineCalculatorError.InvalidValueAdded;
+      } else {
+        var actualEnumerator = actualContinuation.GetEnumerator();
+        var predictedEnumerator = predictedContinuation.GetEnumerator();
+        while (actualEnumerator.MoveNext() & predictedEnumerator.MoveNext() & errorState != OnlineCalculatorError.InvalidValueAdded) {
+          double actual = actualEnumerator.Current;
+          double predicted = predictedEnumerator.Current;
+          if (double.IsNaN(actual) || double.IsNaN(predicted)) {
+            errorState = errorState | OnlineCalculatorError.InvalidValueAdded;
+          } else {
+            double err = Math.Abs(actual - predicted);
+            // count as correct only if the trend (positive/negative/no change) is predicted correctly
+            if ((actual - startValue) * (predicted - startValue) > 0.0 ||
+              (actual - startValue).IsAlmost(predicted - startValue)) {
+              correctSum += err;
+            } else {
+              incorrectSum += err;
+            }
+            n++;
+          }
+        }
+        // check if both enumerators are at the end to make sure both enumerations have the same length
+        if (actualEnumerator.MoveNext() || predictedEnumerator.MoveNext()) {
+          errorState = errorState | OnlineCalculatorError.InvalidValueAdded;
+        } else {
+          errorState = errorState & (~OnlineCalculatorError.InsufficientElementsAdded); // n >= 1
+        }
+      }
+    }
+
+    public void Reset() {
+      n = 0;
+      correctSum = 0;
+      incorrectSum = 0;
+      errorState = OnlineCalculatorError.InsufficientElementsAdded;
+    }
+
+    public static double Calculate(double startValue, IEnumerable<double> actualContinuation, IEnumerable<double> predictedContinuation, out OnlineCalculatorError errorState) {
+      OnlineWeightedDirectionalSymmetryCalculator calculator = new OnlineWeightedDirectionalSymmetryCalculator();
+      calculator.Add(startValue, actualContinuation, predictedContinuation);
+      errorState = calculator.ErrorState;
+      return calculator.WeightedDirectionalSymmetry;
+    }
+
+    public static double Calculate(IEnumerable<double> startValues, IEnumerable<IEnumerable<double>> actualContinuations, IEnumerable<IEnumerable<double>> predictedContinuations, out OnlineCalculatorError errorState) {
+      IEnumerator<double> startValueEnumerator = startValues.GetEnumerator();
+      IEnumerator<IEnumerable<double>> actualContinuationsEnumerator = actualContinuations.GetEnumerator();
+      IEnumerator<IEnumerable<double>> predictedContinuationsEnumerator = predictedContinuations.GetEnumerator();
+      OnlineWeightedDirectionalSymmetryCalculator calculator = new OnlineWeightedDirectionalSymmetryCalculator();
+
+      // always move forward all enumerators (do not use short-circuit evaluation!)
+      while (startValueEnumerator.MoveNext() & actualContinuationsEnumerator.MoveNext() & predictedContinuationsEnumerator.MoveNext()) {
+        calculator.Add(startValueEnumerator.Current, actualContinuationsEnumerator.Current, predictedContinuationsEnumerator.Current);
+        if (calculator.ErrorState != OnlineCalculatorError.None) break;
+      }
+
+      // check if all enumerators are at the end to make sure both enumerations have the same length
+      if (calculator.ErrorState == OnlineCalculatorError.None &&
+          (startValueEnumerator.MoveNext() || actualContinuationsEnumerator.MoveNext() || predictedContinuationsEnumerator.MoveNext())) {
+        throw new ArgumentException("Number of elements in startValues, actualContinuations and estimatedValues predictedContinuations doesn't match.");
+      } else {
+        errorState = calculator.ErrorState;
+        return calculator.WeightedDirectionalSymmetry;
+      }
+    }
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Plugin.cs.frame
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Plugin.cs.frame	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Plugin.cs.frame	(revision 13819)
@@ -0,0 +1,42 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using HeuristicLab.PluginInfrastructure;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  [Plugin("HeuristicLab.Problems.DataAnalysis","Provides base classes for data analysis tasks.", "3.4.9.$WCREV$")]
+  [PluginFile("HeuristicLab.Problems.DataAnalysis-3.4.dll", PluginFileType.Assembly)]
+  [PluginDependency("HeuristicLab.ALGLIB","3.7.0")]
+  [PluginDependency("HeuristicLab.Collections", "3.3")]
+  [PluginDependency("HeuristicLab.Common", "3.3")]
+  [PluginDependency("HeuristicLab.Common.Resources", "3.3")]
+  [PluginDependency("HeuristicLab.Core", "3.3")]
+  [PluginDependency("HeuristicLab.Data", "3.3")]
+  [PluginDependency("HeuristicLab.Optimization","3.3")]
+  [PluginDependency("HeuristicLab.Parameters", "3.3")]
+  [PluginDependency("HeuristicLab.Persistence", "3.3")]
+  [PluginDependency("HeuristicLab.Problems.Instances", "3.3")]  
+  public class HeuristicLabProblemsDataAnalysisPlugin : PluginBase {
+  }
+}
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Properties/AssemblyInfo.cs.frame
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Properties/AssemblyInfo.cs.frame	(revision 13819)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.Problems.DataAnalysis/3.4/Properties/AssemblyInfo.cs.frame	(revision 13819)
@@ -0,0 +1,55 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Reflection;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following 
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("HeuristicLab.Problems.DataAnalysis")]
+[assembly: AssemblyDescription("Provides base classes for data analysis tasks.")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("HeuristicLab")]
+[assembly: AssemblyCopyright("(c) 2002-2015 HEAL")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible 
+// to COM components.  If you need to access a type in this assembly from 
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("460C6FC6-FFBB-4286-B781-06D9F56A202D")]
+
+// Version information for an assembly consists of the following four values:
+//
+//      Major Version
+//      Minor Version 
+//      Build Number
+//      Revision
+//
+// You can specify all the values or you can default the Revision and Build Numbers 
+// by using the '*' as shown below:
+[assembly: AssemblyVersion("3.4.0.0")]
+[assembly: AssemblyFileVersion("3.4.9.$WCREV$")]
Index: /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.RegressionSolutionGradientView.sln
===================================================================
--- /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.RegressionSolutionGradientView.sln	(revision 13818)
+++ /branches/HeuristicLab.RegressionSolutionGradientView/HeuristicLab.RegressionSolutionGradientView.sln	(revision 13819)
@@ -7,4 +7,8 @@
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HeuristicLab.Algorithms.DataAnalysis.Views-3.4", "HeuristicLab.Algorithms.DataAnalysis.Views\3.4\HeuristicLab.Algorithms.DataAnalysis.Views-3.4.csproj", "{A2330DB0-413D-4424-B4E6-591118E2B9F8}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HeuristicLab.Algorithms.DataAnalysis-3.4", "HeuristicLab.Algorithms.DataAnalysis\3.4\HeuristicLab.Algorithms.DataAnalysis-3.4.csproj", "{2E782078-FA81-4B70-B56F-74CE38DAC6C8}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HeuristicLab.Problems.DataAnalysis-3.4", "HeuristicLab.Problems.DataAnalysis\3.4\HeuristicLab.Problems.DataAnalysis-3.4.csproj", "{DF87C13E-A889-46FF-8153-66DCAA8C5674}"
 EndProject
 Global
@@ -42,4 +46,28 @@
 		{A2330DB0-413D-4424-B4E6-591118E2B9F8}.Release|x86.ActiveCfg = Release|x86
 		{A2330DB0-413D-4424-B4E6-591118E2B9F8}.Release|x86.Build.0 = Release|x86
+		{2E782078-FA81-4B70-B56F-74CE38DAC6C8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{2E782078-FA81-4B70-B56F-74CE38DAC6C8}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{2E782078-FA81-4B70-B56F-74CE38DAC6C8}.Debug|x64.ActiveCfg = Debug|x64
+		{2E782078-FA81-4B70-B56F-74CE38DAC6C8}.Debug|x64.Build.0 = Debug|x64
+		{2E782078-FA81-4B70-B56F-74CE38DAC6C8}.Debug|x86.ActiveCfg = Debug|x86
+		{2E782078-FA81-4B70-B56F-74CE38DAC6C8}.Debug|x86.Build.0 = Debug|x86
+		{2E782078-FA81-4B70-B56F-74CE38DAC6C8}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{2E782078-FA81-4B70-B56F-74CE38DAC6C8}.Release|Any CPU.Build.0 = Release|Any CPU
+		{2E782078-FA81-4B70-B56F-74CE38DAC6C8}.Release|x64.ActiveCfg = Release|x64
+		{2E782078-FA81-4B70-B56F-74CE38DAC6C8}.Release|x64.Build.0 = Release|x64
+		{2E782078-FA81-4B70-B56F-74CE38DAC6C8}.Release|x86.ActiveCfg = Release|x86
+		{2E782078-FA81-4B70-B56F-74CE38DAC6C8}.Release|x86.Build.0 = Release|x86
+		{DF87C13E-A889-46FF-8153-66DCAA8C5674}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{DF87C13E-A889-46FF-8153-66DCAA8C5674}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{DF87C13E-A889-46FF-8153-66DCAA8C5674}.Debug|x64.ActiveCfg = Debug|x64
+		{DF87C13E-A889-46FF-8153-66DCAA8C5674}.Debug|x64.Build.0 = Debug|x64
+		{DF87C13E-A889-46FF-8153-66DCAA8C5674}.Debug|x86.ActiveCfg = Debug|x86
+		{DF87C13E-A889-46FF-8153-66DCAA8C5674}.Debug|x86.Build.0 = Debug|x86
+		{DF87C13E-A889-46FF-8153-66DCAA8C5674}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{DF87C13E-A889-46FF-8153-66DCAA8C5674}.Release|Any CPU.Build.0 = Release|Any CPU
+		{DF87C13E-A889-46FF-8153-66DCAA8C5674}.Release|x64.ActiveCfg = Release|x64
+		{DF87C13E-A889-46FF-8153-66DCAA8C5674}.Release|x64.Build.0 = Release|x64
+		{DF87C13E-A889-46FF-8153-66DCAA8C5674}.Release|x86.ActiveCfg = Release|x86
+		{DF87C13E-A889-46FF-8153-66DCAA8C5674}.Release|x86.Build.0 = Release|x86
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
