Index: branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.3/HeuristicLabAlgorithmsDataAnalysisPlugin.cs.frame
===================================================================
--- branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.3/HeuristicLabAlgorithmsDataAnalysisPlugin.cs.frame	(revision 6228)
+++ branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.3/HeuristicLabAlgorithmsDataAnalysisPlugin.cs.frame	(revision 6760)
@@ -26,5 +26,5 @@
   /// Plugin class for HeuristicLab.Algorithms.DataAnalysis plugin.
   /// </summary>
-  [Plugin("HeuristicLab.Algorithms.DataAnalysis", "3.3.4.$WCREV$")]
+  [Plugin("HeuristicLab.Algorithms.DataAnalysis", "3.3.5.$WCREV$")]
   [PluginFile("HeuristicLab.Algorithms.DataAnalysis-3.3.dll", PluginFileType.Assembly)]
   [PluginDependency("HeuristicLab.Collections", "3.3")]
Index: branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.3/Properties/AssemblyInfo.frame
===================================================================
--- branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.3/Properties/AssemblyInfo.frame	(revision 6228)
+++ branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.3/Properties/AssemblyInfo.frame	(revision 6760)
@@ -53,3 +53,3 @@
 // by using the '*' as shown below:
 [assembly: AssemblyVersion("3.3.0.0")]
-[assembly: AssemblyFileVersion("3.3.4.$WCREV$")]
+[assembly: AssemblyFileVersion("3.3.5.$WCREV$")]
Index: branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/CrossValidation.cs
===================================================================
--- branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/CrossValidation.cs	(revision 6228)
+++ branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/CrossValidation.cs	(revision 6760)
@@ -34,5 +34,5 @@
 
 namespace HeuristicLab.Algorithms.DataAnalysis {
-  [Item("Cross Validation", "Cross Validation wrapper for data analysis algorithms.")]
+  [Item("Cross Validation", "Cross-validation wrapper for data analysis algorithms.")]
   [Creatable("Data Analysis")]
   [StorableClass]
@@ -363,4 +363,11 @@
 
     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) {
       Dictionary<string, List<double>> resultValues = new Dictionary<string, List<double>>();
       IEnumerable<IRun> runs = clonedAlgorithms.Select(alg => alg.Runs.FirstOrDefault()).Where(run => run != null);
@@ -374,4 +381,7 @@
         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);
       }
@@ -394,14 +404,66 @@
       List<IResult> aggregatedResults = new List<IResult>();
       foreach (KeyValuePair<string, List<IRegressionSolution>> solutions in resultSolutions) {
-        var problemDataClone = (IRegressionProblemData)Problem.ProblemData.Clone();
+        // 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;
-        var ensembleSolution = new RegressionEnsembleSolution(solutions.Value.Select(x => x.Model), problemDataClone,
-          solutions.Value.Select(x => x.ProblemData.TrainingPartition),
-          solutions.Value.Select(x => x.ProblemData.TestPartition));
-
-        aggregatedResults.Add(new Result(solutions.Key, ensembleSolution));
-      }
-      return aggregatedResults;
+        // clone models
+        var ensembleSolution = new RegressionEnsembleSolution(
+          solutions.Value.Select(x => cloner.Clone(x.Model)),
+          problemDataClone,
+          solutions.Value.Select(x => cloner.Clone(x.ProblemData.TrainingPartition)),
+          solutions.Value.Select(x => cloner.Clone(x.ProblemData.TestPartition)));
+
+        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(
+          solutions.Value.Select(x => cloner.Clone(x.Model)),
+          problemDataClone,
+          solutions.Value.Select(x => cloner.Clone(x.ProblemData.TrainingPartition)),
+          solutions.Value.Select(x => cloner.Clone(x.ProblemData.TestPartition)));
+
+        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);
+        }
+      }
     }
 
@@ -428,7 +490,7 @@
       foreach (KeyValuePair<string, List<double>> resultValue in resultValues) {
         doubleValue.Value = resultValue.Value.Average();
-        aggregatedResults.Add(new Result(resultValue.Key, (IItem)doubleValue.Clone()));
+        aggregatedResults.Add(new Result(resultValue.Key + " (average)", (IItem)doubleValue.Clone()));
         doubleValue.Value = resultValue.Value.StandardDeviation();
-        aggregatedResults.Add(new Result(resultValue.Key + " StdDev", (IItem)doubleValue.Clone()));
+        aggregatedResults.Add(new Result(resultValue.Key + " (std.dev.)", (IItem)doubleValue.Clone()));
       }
       return aggregatedResults;
@@ -481,4 +543,5 @@
         throw new ArgumentException("A cross validation algorithm can only contain DataAnalysisProblems.");
       }
+      algorithm.Problem.Reset += (x,y) => OnProblemChanged();
       problem = (IDataAnalysisProblem)algorithm.Problem;
       OnProblemChanged();
@@ -491,5 +554,4 @@
       SamplesStart.Value = 0;
       if (Problem != null) {
-        Problem.ProblemDataChanged += (object sender, EventArgs e) => OnProblemChanged();
         SamplesEnd.Value = Problem.ProblemData.Dataset.Rows;
 
@@ -510,4 +572,7 @@
       } else
         SamplesEnd.Value = 0;
+
+      SamplesStart_ValueChanged(this, EventArgs.Empty);
+      SamplesEnd_ValueChanged(this, EventArgs.Empty);
     }
 
@@ -656,5 +721,5 @@
       stopPending = false;
       Dictionary<string, IItem> collectedResults = new Dictionary<string, IItem>();
-      CollectResultValues(collectedResults);
+      AggregateResultValues(collectedResults);
       results.AddRange(collectedResults.Select(x => new Result(x.Key, x.Value)).Cast<IResult>().ToArray());
       runsCounter++;
Index: branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/FixedDataAnalysisAlgorithm.cs
===================================================================
--- branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/FixedDataAnalysisAlgorithm.cs	(revision 6228)
+++ branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/FixedDataAnalysisAlgorithm.cs	(revision 6760)
@@ -21,17 +21,10 @@
 
 using System;
-using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
 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 HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
-using System.Collections.Generic;
-using HeuristicLab.Problems.DataAnalysis.Symbolic;
-using System.Threading.Tasks;
-using System.Threading;
 
 namespace HeuristicLab.Algorithms.DataAnalysis {
@@ -57,5 +50,5 @@
     }
     #endregion
-    
+
     private DateTime lastUpdateTime;
 
@@ -103,5 +96,4 @@
     private void Run(object state) {
       CancellationToken cancellationToken = (CancellationToken)state;
-      OnStarted();
       lastUpdateTime = DateTime.Now;
       System.Timers.Timer timer = new System.Timers.Timer(250);
Index: branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/HeuristicLab.Algorithms.DataAnalysis-3.4.csproj
===================================================================
--- branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/HeuristicLab.Algorithms.DataAnalysis-3.4.csproj	(revision 6228)
+++ branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/HeuristicLab.Algorithms.DataAnalysis-3.4.csproj	(revision 6760)
@@ -107,4 +107,5 @@
   </ItemGroup>
   <ItemGroup>
+    <Compile Include="RegressionWorkbench.cs" />
     <Compile Include="CrossValidation.cs">
       <SubType>Code</SubType>
@@ -112,4 +113,16 @@
     <Compile Include="HeuristicLabAlgorithmsDataAnalysisPlugin.cs" />
     <Compile Include="FixedDataAnalysisAlgorithm.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" />
@@ -126,5 +139,28 @@
       <SubType>Code</SubType>
     </Compile>
+    <Compile Include="Linear\MultinomialLogitClassification.cs" />
+    <Compile Include="Linear\MultinomialLogitClassificationSolution.cs" />
+    <Compile Include="Linear\MultinomialLogitModel.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="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="SupportVectorMachine\SupportVectorClassification.cs" />
     <Compile Include="SupportVectorMachine\SupportVectorClassificationSolution.cs" />
Index: branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/HeuristicLabAlgorithmsDataAnalysisPlugin.cs.frame
===================================================================
--- branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/HeuristicLabAlgorithmsDataAnalysisPlugin.cs.frame	(revision 6228)
+++ branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/HeuristicLabAlgorithmsDataAnalysisPlugin.cs.frame	(revision 6760)
@@ -26,5 +26,5 @@
   /// 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.0.$WCREV$")]
+  [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.1.$WCREV$")]
   [PluginFile("HeuristicLab.Algorithms.DataAnalysis-3.4.dll", PluginFileType.Assembly)]
   [PluginDependency("HeuristicLab.ALGLIB", "3.1.0")]
Index: branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/INearestNeighbourClassificationSolution.cs
===================================================================
--- branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/INearestNeighbourClassificationSolution.cs	(revision 6760)
+++ branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/INearestNeighbourClassificationSolution.cs	(revision 6760)
@@ -0,0 +1,33 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2011 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using 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/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/INearestNeighbourModel.cs
===================================================================
--- branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/INearestNeighbourModel.cs	(revision 6760)
+++ branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/INearestNeighbourModel.cs	(revision 6760)
@@ -0,0 +1,33 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2011 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using 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/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/INearestNeighbourRegressionSolution.cs
===================================================================
--- branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/INearestNeighbourRegressionSolution.cs	(revision 6760)
+++ branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/INearestNeighbourRegressionSolution.cs	(revision 6760)
@@ -0,0 +1,33 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2011 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using 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/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/INeuralNetworkClassificationSolution.cs
===================================================================
--- branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/INeuralNetworkClassificationSolution.cs	(revision 6760)
+++ branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/INeuralNetworkClassificationSolution.cs	(revision 6760)
@@ -0,0 +1,33 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2011 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using 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/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/INeuralNetworkEnsembleClassificationSolution.cs
===================================================================
--- branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/INeuralNetworkEnsembleClassificationSolution.cs	(revision 6760)
+++ branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/INeuralNetworkEnsembleClassificationSolution.cs	(revision 6760)
@@ -0,0 +1,33 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2011 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using 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/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/INeuralNetworkEnsembleModel.cs
===================================================================
--- branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/INeuralNetworkEnsembleModel.cs	(revision 6760)
+++ branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/INeuralNetworkEnsembleModel.cs	(revision 6760)
@@ -0,0 +1,33 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2011 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using 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/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/INeuralNetworkEnsembleRegressionSolution.cs
===================================================================
--- branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/INeuralNetworkEnsembleRegressionSolution.cs	(revision 6760)
+++ branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/INeuralNetworkEnsembleRegressionSolution.cs	(revision 6760)
@@ -0,0 +1,33 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2011 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using 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/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/INeuralNetworkModel.cs
===================================================================
--- branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/INeuralNetworkModel.cs	(revision 6760)
+++ branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/INeuralNetworkModel.cs	(revision 6760)
@@ -0,0 +1,33 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2011 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using 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/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/INeuralNetworkRegressionSolution.cs
===================================================================
--- branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/INeuralNetworkRegressionSolution.cs	(revision 6760)
+++ branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/INeuralNetworkRegressionSolution.cs	(revision 6760)
@@ -0,0 +1,33 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2011 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using 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/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/IRandomForestClassificationSolution.cs
===================================================================
--- branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/IRandomForestClassificationSolution.cs	(revision 6760)
+++ branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/IRandomForestClassificationSolution.cs	(revision 6760)
@@ -0,0 +1,33 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2011 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using 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/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/IRandomForestModel.cs
===================================================================
--- branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/IRandomForestModel.cs	(revision 6760)
+++ branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/IRandomForestModel.cs	(revision 6760)
@@ -0,0 +1,33 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2011 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using 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/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/IRandomForestRegressionSolution.cs
===================================================================
--- branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/IRandomForestRegressionSolution.cs	(revision 6760)
+++ branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/IRandomForestRegressionSolution.cs	(revision 6760)
@@ -0,0 +1,33 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2011 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using 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/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/Linear/AlglibUtil.cs
===================================================================
--- branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/Linear/AlglibUtil.cs	(revision 6228)
+++ branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/Linear/AlglibUtil.cs	(revision 6760)
@@ -31,11 +31,16 @@
 
       double[,] matrix = new double[rowsList.Count, variablesList.Count];
-      for (int row = 0; row < rowsList.Count; row++) {
-        int col = 0;
-        foreach (string column in variables) {
-          matrix[row, col] = dataset[column, rowsList[row]];
-          col++;
+
+      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;
     }
Index: branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/Linear/LinearDiscriminantAnalysis.cs
===================================================================
--- branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/Linear/LinearDiscriminantAnalysis.cs	(revision 6228)
+++ branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/Linear/LinearDiscriminantAnalysis.cs	(revision 6760)
@@ -36,5 +36,5 @@
   /// Linear discriminant analysis classification algorithm.
   /// </summary>
-  [Item("Linear Discriminant Analysis", "Linear discriminant analysis classification algorithm.")]
+  [Item("Linear Discriminant Analysis", "Linear discriminant analysis classification algorithm (wrapper for ALGLIB).")]
   [Creatable("Data Analysis")]
   [StorableClass]
@@ -104,5 +104,5 @@
 
       var model = LinearDiscriminantAnalysis.CreateDiscriminantFunctionModel(tree, new SymbolicDataAnalysisExpressionTreeInterpreter(), problemData, rows);
-      SymbolicDiscriminantFunctionClassificationSolution solution = new SymbolicDiscriminantFunctionClassificationSolution(model, problemData);
+      SymbolicDiscriminantFunctionClassificationSolution solution = new SymbolicDiscriminantFunctionClassificationSolution(model, (IClassificationProblemData)problemData.Clone());
 
       return solution;
Index: branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/Linear/LinearRegression.cs
===================================================================
--- branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/Linear/LinearRegression.cs	(revision 6228)
+++ branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/Linear/LinearRegression.cs	(revision 6760)
@@ -37,5 +37,5 @@
   /// Linear regression data analysis algorithm.
   /// </summary>
-  [Item("Linear Regression", "Linear regression data analysis algorithm.")]
+  [Item("Linear Regression", "Linear regression data analysis algorithm (wrapper for ALGLIB).")]
   [Creatable("Data Analysis")]
   [StorableClass]
@@ -108,5 +108,6 @@
       addition.AddSubtree(cNode);
 
-      SymbolicRegressionSolution solution = new SymbolicRegressionSolution(new SymbolicRegressionModel(tree, new SymbolicDataAnalysisExpressionTreeInterpreter()), problemData);
+      SymbolicRegressionSolution solution = new SymbolicRegressionSolution(new SymbolicRegressionModel(tree, new SymbolicDataAnalysisExpressionTreeInterpreter()), (IRegressionProblemData)problemData.Clone());
+      solution.Model.Name = "Linear Regression Model";
       return solution;
     }
Index: branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/Linear/MultinomialLogitClassification.cs
===================================================================
--- branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/Linear/MultinomialLogitClassification.cs	(revision 6760)
+++ branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/Linear/MultinomialLogitClassification.cs	(revision 6760)
@@ -0,0 +1,102 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2011 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.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", "Multinomial logit classification data analysis algorithm (wrapper for ALGLIB).")]
+  [Creatable("Data Analysis")]
+  [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) {
+      Dataset dataset = problemData.Dataset;
+      string targetVariable = problemData.TargetVariable;
+      IEnumerable<string> allowedInputVariables = problemData.AllowedInputVariables;
+      IEnumerable<int> rows = problemData.TrainingIndizes;
+      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> classIndizes = new Dictionary<double, double>();
+      for (int i = 0; i < nClasses; i++) {
+        classIndizes[classValues[i]] = i;
+      }
+      for (int row = 0; row < nRows; row++) {
+        inputMatrix[row, nFeatures] = classIndizes[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/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/Linear/MultinomialLogitClassificationSolution.cs
===================================================================
--- branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/Linear/MultinomialLogitClassificationSolution.cs	(revision 6760)
+++ branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/Linear/MultinomialLogitClassificationSolution.cs	(revision 6760)
@@ -0,0 +1,58 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2011 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+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) {
+      RecalculateResults();
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new MultinomialLogitClassificationSolution(this, cloner);
+    }
+
+    protected override void RecalculateResults() {
+      CalculateResults();
+    }
+  }
+}
Index: branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/Linear/MultinomialLogitModel.cs
===================================================================
--- branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/Linear/MultinomialLogitModel.cs	(revision 6760)
+++ branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/Linear/MultinomialLogitModel.cs	(revision 6760)
@@ -0,0 +1,138 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2011 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.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(Dataset 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(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/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/NearestNeighbour/NearestNeighbourClassification.cs
===================================================================
--- branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/NearestNeighbour/NearestNeighbourClassification.cs	(revision 6760)
+++ branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/NearestNeighbour/NearestNeighbourClassification.cs	(revision 6760)
@@ -0,0 +1,114 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2011 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.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;
+using HeuristicLab.Parameters;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  /// <summary>
+  /// Nearest neighbour classification data analysis algorithm.
+  /// </summary>
+  [Item("Nearest Neighbour Classification", "Nearest neighbour classification data analysis algorithm (wrapper for ALGLIB).")]
+  [Creatable("Data Analysis")]
+  [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) {
+      Dataset dataset = problemData.Dataset;
+      string targetVariable = problemData.TargetVariable;
+      IEnumerable<string> allowedInputVariables = problemData.AllowedInputVariables;
+      IEnumerable<int> rows = problemData.TrainingIndizes;
+      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("Nearest neighbour classification does not support NaN or infinity values in the input dataset.");
+
+      alglib.nearestneighbor.kdtree kdtree = new alglib.nearestneighbor.kdtree();
+
+      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> classIndizes = new Dictionary<double, double>();
+      for (int i = 0; i < nClasses; i++) {
+        classIndizes[classValues[i]] = i;
+      }
+      for (int row = 0; row < nRows; row++) {
+        inputMatrix[row, nFeatures] = classIndizes[inputMatrix[row, nFeatures]];
+      }
+      alglib.nearestneighbor.kdtreebuild(inputMatrix, nRows, inputMatrix.GetLength(1) - 1, 1, 2, kdtree);
+      var problemDataClone = (IClassificationProblemData) problemData.Clone();
+      return new NearestNeighbourClassificationSolution(problemDataClone, new NearestNeighbourModel(kdtree, k, targetVariable, allowedInputVariables, problemDataClone.ClassValues.ToArray()));
+    }
+    #endregion
+  }
+}
Index: branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/NearestNeighbour/NearestNeighbourClassificationSolution.cs
===================================================================
--- branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/NearestNeighbour/NearestNeighbourClassificationSolution.cs	(revision 6760)
+++ branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/NearestNeighbour/NearestNeighbourClassificationSolution.cs	(revision 6760)
@@ -0,0 +1,58 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2011 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+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) {
+      RecalculateResults();
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new NearestNeighbourClassificationSolution(this, cloner);
+    }
+
+    protected override void RecalculateResults() {
+      CalculateResults();
+    }
+  }
+}
Index: branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/NearestNeighbour/NearestNeighbourModel.cs
===================================================================
--- branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/NearestNeighbour/NearestNeighbourModel.cs	(revision 6760)
+++ branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/NearestNeighbour/NearestNeighbourModel.cs	(revision 6760)
@@ -0,0 +1,324 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2011 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.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 neural network 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.distmatrixtype = original.kdTree.distmatrixtype;
+      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(alglib.nearestneighbor.kdtree kdTree, int k, string targetVariable, IEnumerable<string> allowedInputVariables, double[] classValues = null)
+      : base() {
+      this.name = ItemName;
+      this.description = ItemDescription;
+      this.kdTree = kdTree;
+      this.k = k;
+      this.targetVariable = targetVariable;
+      this.allowedInputVariables = allowedInputVariables.ToArray();
+      if (classValues != null)
+        this.classValues = (double[])classValues.Clone();
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new NearestNeighbourModel(this, cloner);
+    }
+
+    public IEnumerable<double> GetEstimatedValues(Dataset 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(Dataset 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];
+      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(problemData, this);
+    }
+    IRegressionSolution IRegressionModel.CreateRegressionSolution(IRegressionProblemData problemData) {
+      return CreateRegressionSolution(problemData);
+    }
+    public INearestNeighbourClassificationSolution CreateClassificationSolution(IClassificationProblemData problemData) {
+      return new NearestNeighbourClassificationSolution(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 KDTreeDistMatrixType {
+      get { return kdTree.distmatrixtype; }
+      set { kdTree.distmatrixtype = 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/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/NearestNeighbour/NearestNeighbourRegression.cs
===================================================================
--- branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/NearestNeighbour/NearestNeighbourRegression.cs	(revision 6760)
+++ branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/NearestNeighbour/NearestNeighbourRegression.cs	(revision 6760)
@@ -0,0 +1,104 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2011 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.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;
+using HeuristicLab.Parameters;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  /// <summary>
+  /// Nearest neighbour regression data analysis algorithm.
+  /// </summary>
+  [Item("Nearest Neighbour Regression", "Nearest neighbour regression data analysis algorithm (wrapper for ALGLIB).")]
+  [Creatable("Data Analysis")]
+  [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) {
+      Dataset dataset = problemData.Dataset;
+      string targetVariable = problemData.TargetVariable;
+      IEnumerable<string> allowedInputVariables = problemData.AllowedInputVariables;
+      IEnumerable<int> rows = problemData.TrainingIndizes;
+      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("Nearest neighbour regression does not support NaN or infinity values in the input dataset.");
+
+      alglib.nearestneighbor.kdtree kdtree = new alglib.nearestneighbor.kdtree();
+
+      int nRows = inputMatrix.GetLength(0);
+
+      alglib.nearestneighbor.kdtreebuild(inputMatrix, nRows, inputMatrix.GetLength(1) - 1, 1, 2, kdtree);
+
+      return new NearestNeighbourRegressionSolution((IRegressionProblemData)problemData.Clone(), new NearestNeighbourModel(kdtree, k, targetVariable, allowedInputVariables));
+    }
+    #endregion
+  }
+}
Index: branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/NearestNeighbour/NearestNeighbourRegressionSolution.cs
===================================================================
--- branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/NearestNeighbour/NearestNeighbourRegressionSolution.cs	(revision 6760)
+++ branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/NearestNeighbour/NearestNeighbourRegressionSolution.cs	(revision 6760)
@@ -0,0 +1,54 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2011 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+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) {
+      RecalculateResults();
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new NearestNeighbourRegressionSolution(this, cloner);
+    }
+  }
+}
Index: branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/NeuralNetwork/NeuralNetworkClassification.cs
===================================================================
--- branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/NeuralNetwork/NeuralNetworkClassification.cs	(revision 6760)
+++ branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/NeuralNetwork/NeuralNetworkClassification.cs	(revision 6760)
@@ -0,0 +1,229 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2011 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.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;
+using HeuristicLab.Parameters;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  /// <summary>
+  /// Neural network classification data analysis algorithm.
+  /// </summary>
+  [Item("Neural Network Classification", "Neural network classification data analysis algorithm (wrapper for ALGLIB). Further documentation: http://www.alglib.net/dataanalysis/neuralnetworks.php")]
+  [Creatable("Data Analysis")]
+  [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 NeuralNetworkRegressionModelResultName = "Neural network classification solution";
+
+    #region parameter properties
+    public IFixedValueParameter<DoubleValue> DecayParameter {
+      get { return (IFixedValueParameter<DoubleValue>)Parameters[DecayParameterName]; }
+    }
+    public ConstrainedValueParameter<IntValue> HiddenLayersParameter {
+      get { return (ConstrainedValueParameter<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(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)));
+      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) {
+      Dataset dataset = problemData.Dataset;
+      string targetVariable = problemData.TargetVariable;
+      IEnumerable<string> allowedInputVariables = problemData.AllowedInputVariables;
+      IEnumerable<int> rows = problemData.TrainingIndizes;
+      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> classIndizes = new Dictionary<double, double>();
+      for (int i = 0; i < nClasses; i++) {
+        classIndizes[classValues[i]] = i;
+      }
+      for (int row = 0; row < nRows; row++) {
+        inputMatrix[row, nFeatures] = classIndizes[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/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/NeuralNetwork/NeuralNetworkClassificationSolution.cs
===================================================================
--- branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/NeuralNetwork/NeuralNetworkClassificationSolution.cs	(revision 6760)
+++ branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/NeuralNetwork/NeuralNetworkClassificationSolution.cs	(revision 6760)
@@ -0,0 +1,58 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2011 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+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) {
+      RecalculateResults();
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new NeuralNetworkClassificationSolution(this, cloner);
+    }
+
+    protected override void RecalculateResults() {
+      CalculateResults();
+    }
+  }
+}
Index: branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/NeuralNetwork/NeuralNetworkEnsembleClassification.cs
===================================================================
--- branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/NeuralNetwork/NeuralNetworkEnsembleClassification.cs	(revision 6760)
+++ branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/NeuralNetwork/NeuralNetworkEnsembleClassification.cs	(revision 6760)
@@ -0,0 +1,213 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2011 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.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;
+using HeuristicLab.Parameters;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  /// <summary>
+  /// Neural network ensemble classification data analysis algorithm.
+  /// </summary>
+  [Item("Neural Network Ensemble Classification", "Neural network ensemble classification data analysis algorithm (wrapper for ALGLIB). Further documentation: http://www.alglib.net/dataanalysis/mlpensembles.php")]
+  [Creatable("Data Analysis")]
+  [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 ConstrainedValueParameter<IntValue> HiddenLayersParameter {
+      get { return (ConstrainedValueParameter<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 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)));
+      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) {
+      Dataset dataset = problemData.Dataset;
+      string targetVariable = problemData.TargetVariable;
+      IEnumerable<string> allowedInputVariables = problemData.AllowedInputVariables;
+      IEnumerable<int> rows = problemData.TrainingIndizes;
+      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> classIndizes = new Dictionary<double, double>();
+      for (int i = 0; i < nClasses; i++) {
+        classIndizes[classValues[i]] = i;
+      }
+      for (int row = 0; row < nRows; row++) {
+        inputMatrix[row, nFeatures] = classIndizes[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 regression 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/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/NeuralNetwork/NeuralNetworkEnsembleClassificationSolution.cs
===================================================================
--- branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/NeuralNetwork/NeuralNetworkEnsembleClassificationSolution.cs	(revision 6760)
+++ branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/NeuralNetwork/NeuralNetworkEnsembleClassificationSolution.cs	(revision 6760)
@@ -0,0 +1,58 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2011 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+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) {
+      RecalculateResults();
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new NeuralNetworkEnsembleClassificationSolution(this, cloner);
+    }
+
+    protected override void RecalculateResults() {
+      CalculateResults();
+    }
+  }
+}
Index: branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/NeuralNetwork/NeuralNetworkEnsembleModel.cs
===================================================================
--- branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/NeuralNetwork/NeuralNetworkEnsembleModel.cs	(revision 6760)
+++ branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/NeuralNetwork/NeuralNetworkEnsembleModel.cs	(revision 6760)
@@ -0,0 +1,334 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2011 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.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();
+      mlpEnsemble.innerobj.columnmeans = (double[])original.mlpEnsemble.innerobj.columnmeans.Clone();
+      mlpEnsemble.innerobj.columnsigmas = (double[])original.mlpEnsemble.innerobj.columnsigmas.Clone();
+      mlpEnsemble.innerobj.dfdnet = (double[])original.mlpEnsemble.innerobj.dfdnet.Clone();
+      mlpEnsemble.innerobj.ensemblesize = original.mlpEnsemble.innerobj.ensemblesize;
+      mlpEnsemble.innerobj.issoftmax = original.mlpEnsemble.innerobj.issoftmax;
+      mlpEnsemble.innerobj.neurons = (double[])original.mlpEnsemble.innerobj.neurons.Clone();
+      mlpEnsemble.innerobj.nin = original.mlpEnsemble.innerobj.nin;
+      mlpEnsemble.innerobj.nout = original.mlpEnsemble.innerobj.nout;
+      mlpEnsemble.innerobj.postprocessing = original.mlpEnsemble.innerobj.postprocessing;
+      mlpEnsemble.innerobj.serializedlen = original.mlpEnsemble.innerobj.serializedlen;
+      mlpEnsemble.innerobj.serializedmlp = (double[])original.mlpEnsemble.innerobj.serializedmlp.Clone();
+      mlpEnsemble.innerobj.structinfo = (int[])original.mlpEnsemble.innerobj.structinfo.Clone();
+      mlpEnsemble.innerobj.tmpmeans = (double[])original.mlpEnsemble.innerobj.tmpmeans.Clone();
+      mlpEnsemble.innerobj.tmpsigmas = (double[])original.mlpEnsemble.innerobj.tmpsigmas.Clone();
+      mlpEnsemble.innerobj.tmpweights = (double[])original.mlpEnsemble.innerobj.tmpweights.Clone();
+      mlpEnsemble.innerobj.wcount = original.mlpEnsemble.innerobj.wcount;
+      mlpEnsemble.innerobj.weights = (double[])original.mlpEnsemble.innerobj.weights.Clone();
+      mlpEnsemble.innerobj.y = (double[])original.mlpEnsemble.innerobj.y.Clone();
+      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(Dataset 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(Dataset 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(problemData, this);
+    }
+    IRegressionSolution IRegressionModel.CreateRegressionSolution(IRegressionProblemData problemData) {
+      return CreateRegressionSolution(problemData);
+    }
+    public INeuralNetworkEnsembleClassificationSolution CreateClassificationSolution(IClassificationProblemData problemData) {
+      return new NeuralNetworkEnsembleClassificationSolution(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[] MultiLayerPerceptronEnsembleColumnMeans {
+      get {
+        return mlpEnsemble.innerobj.columnmeans;
+      }
+      set {
+        mlpEnsemble.innerobj.columnmeans = value;
+      }
+    }
+    [Storable]
+    private double[] MultiLayerPerceptronEnsembleColumnSigmas {
+      get {
+        return mlpEnsemble.innerobj.columnsigmas;
+      }
+      set {
+        mlpEnsemble.innerobj.columnsigmas = value;
+      }
+    }
+    [Storable]
+    private double[] MultiLayerPerceptronEnsembleDfdnet {
+      get {
+        return mlpEnsemble.innerobj.dfdnet;
+      }
+      set {
+        mlpEnsemble.innerobj.dfdnet = value;
+      }
+    }
+    [Storable]
+    private int MultiLayerPerceptronEnsembleSize {
+      get {
+        return mlpEnsemble.innerobj.ensemblesize;
+      }
+      set {
+        mlpEnsemble.innerobj.ensemblesize = value;
+      }
+    }
+    [Storable]
+    private bool MultiLayerPerceptronEnsembleIsSoftMax {
+      get {
+        return mlpEnsemble.innerobj.issoftmax;
+      }
+      set {
+        mlpEnsemble.innerobj.issoftmax = value;
+      }
+    }
+    [Storable]
+    private double[] MultiLayerPerceptronEnsembleNeurons {
+      get {
+        return mlpEnsemble.innerobj.neurons;
+      }
+      set {
+        mlpEnsemble.innerobj.neurons = value;
+      }
+    }
+    [Storable]
+    private int MultiLayerPerceptronEnsembleNin {
+      get {
+        return mlpEnsemble.innerobj.nin;
+      }
+      set {
+        mlpEnsemble.innerobj.nin = value;
+      }
+    }
+    [Storable]
+    private int MultiLayerPerceptronEnsembleNout {
+      get {
+        return mlpEnsemble.innerobj.nout;
+      }
+      set {
+        mlpEnsemble.innerobj.nout = value;
+      }
+    }
+    [Storable]
+    private bool MultiLayerPerceptronEnsemblePostprocessing {
+      get {
+        return mlpEnsemble.innerobj.postprocessing;
+      }
+      set {
+        mlpEnsemble.innerobj.postprocessing = value;
+      }
+    }
+    [Storable]
+    private int MultiLayerPerceptronEnsembleSerializedLen {
+      get {
+        return mlpEnsemble.innerobj.serializedlen;
+      }
+      set {
+        mlpEnsemble.innerobj.serializedlen = value;
+      }
+    }
+    [Storable]
+    private double[] MultiLayerPerceptronEnsembleSerializedMlp {
+      get {
+        return mlpEnsemble.innerobj.serializedmlp;
+      }
+      set {
+        mlpEnsemble.innerobj.serializedmlp = value;
+      }
+    }
+    [Storable]
+    private int[] MultiLayerPerceptronStuctinfo {
+      get {
+        return mlpEnsemble.innerobj.structinfo;
+      }
+      set {
+        mlpEnsemble.innerobj.structinfo = value;
+      }
+    }
+    [Storable]
+    private double[] MultiLayerPerceptronEnsembleTmpMeans {
+      get {
+        return mlpEnsemble.innerobj.tmpmeans;
+      }
+      set {
+        mlpEnsemble.innerobj.tmpmeans = value;
+      }
+    }
+    [Storable]
+    private double[] MultiLayerPerceptronEnsembleTmpSigmas {
+      get {
+        return mlpEnsemble.innerobj.tmpsigmas;
+      }
+      set {
+        mlpEnsemble.innerobj.tmpsigmas = value;
+      }
+    }
+    [Storable]
+    private double[] MultiLayerPerceptronEnsembleTmpWeights {
+      get {
+        return mlpEnsemble.innerobj.tmpweights;
+      }
+      set {
+        mlpEnsemble.innerobj.tmpweights = value;
+      }
+    }
+    [Storable]
+    private int MultiLayerPerceptronEnsembleWCount {
+      get {
+        return mlpEnsemble.innerobj.wcount;
+      }
+      set {
+        mlpEnsemble.innerobj.wcount = value;
+      }
+    }
+
+    [Storable]
+    private double[] MultiLayerPerceptronWeights {
+      get {
+        return mlpEnsemble.innerobj.weights;
+      }
+      set {
+        mlpEnsemble.innerobj.weights = value;
+      }
+    }
+    [Storable]
+    private double[] MultiLayerPerceptronY {
+      get {
+        return mlpEnsemble.innerobj.y;
+      }
+      set {
+        mlpEnsemble.innerobj.y = value;
+      }
+    }
+    #endregion
+  }
+}
Index: branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/NeuralNetwork/NeuralNetworkEnsembleRegression.cs
===================================================================
--- branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/NeuralNetwork/NeuralNetworkEnsembleRegression.cs	(revision 6760)
+++ branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/NeuralNetwork/NeuralNetworkEnsembleRegression.cs	(revision 6760)
@@ -0,0 +1,199 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2011 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.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;
+using HeuristicLab.Parameters;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  /// <summary>
+  /// Neural network ensemble regression data analysis algorithm.
+  /// </summary>
+  [Item("Neural Network Ensemble Regression", "Neural network ensemble regression data analysis algorithm (wrapper for ALGLIB). Further documentation: http://www.alglib.net/dataanalysis/mlpensembles.php")]
+  [Creatable("Data Analysis")]
+  [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 ConstrainedValueParameter<IntValue> HiddenLayersParameter {
+      get { return (ConstrainedValueParameter<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) {
+      Dataset dataset = problemData.Dataset;
+      string targetVariable = problemData.TargetVariable;
+      IEnumerable<string> allowedInputVariables = problemData.AllowedInputVariables;
+      IEnumerable<int> rows = problemData.TrainingIndizes;
+      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/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/NeuralNetwork/NeuralNetworkEnsembleRegressionSolution.cs
===================================================================
--- branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/NeuralNetwork/NeuralNetworkEnsembleRegressionSolution.cs	(revision 6760)
+++ branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/NeuralNetwork/NeuralNetworkEnsembleRegressionSolution.cs	(revision 6760)
@@ -0,0 +1,54 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2011 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+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/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/NeuralNetwork/NeuralNetworkModel.cs
===================================================================
--- branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/NeuralNetwork/NeuralNetworkModel.cs	(revision 6760)
+++ branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/NeuralNetwork/NeuralNetworkModel.cs	(revision 6760)
@@ -0,0 +1,263 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2011 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.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(Dataset 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(Dataset 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(problemData, this);
+    }
+    IRegressionSolution IRegressionModel.CreateRegressionSolution(IRegressionProblemData problemData) {
+      return CreateRegressionSolution(problemData);
+    }
+    public INeuralNetworkClassificationSolution CreateClassificationSolution(IClassificationProblemData problemData) {
+      return new NeuralNetworkClassificationSolution(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/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/NeuralNetwork/NeuralNetworkRegression.cs
===================================================================
--- branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/NeuralNetwork/NeuralNetworkRegression.cs	(revision 6760)
+++ branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/NeuralNetwork/NeuralNetworkRegression.cs	(revision 6760)
@@ -0,0 +1,216 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2011 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.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;
+using HeuristicLab.Parameters;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  /// <summary>
+  /// Neural network regression data analysis algorithm.
+  /// </summary>
+  [Item("Neural Network Regression", "Neural network regression data analysis algorithm (wrapper for ALGLIB). Further documentation: http://www.alglib.net/dataanalysis/neuralnetworks.php")]
+  [Creatable("Data Analysis")]
+  [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 ConstrainedValueParameter<IntValue> HiddenLayersParameter {
+      get { return (ConstrainedValueParameter<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) {
+      Dataset dataset = problemData.Dataset;
+      string targetVariable = problemData.TargetVariable;
+      IEnumerable<string> allowedInputVariables = problemData.AllowedInputVariables;
+      IEnumerable<int> rows = problemData.TrainingIndizes;
+      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/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/NeuralNetwork/NeuralNetworkRegressionSolution.cs
===================================================================
--- branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/NeuralNetwork/NeuralNetworkRegressionSolution.cs	(revision 6760)
+++ branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/NeuralNetwork/NeuralNetworkRegressionSolution.cs	(revision 6760)
@@ -0,0 +1,54 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2011 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+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) {
+      RecalculateResults();
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new NeuralNetworkRegressionSolution(this, cloner);
+    }
+  }
+}
Index: branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/Properties/AssemblyInfo.frame
===================================================================
--- branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/Properties/AssemblyInfo.frame	(revision 6228)
+++ branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/Properties/AssemblyInfo.frame	(revision 6760)
@@ -53,3 +53,3 @@
 // by using the '*' as shown below:
 [assembly: AssemblyVersion("3.4.0.0")]
-[assembly: AssemblyFileVersion("3.4.0.$WCREV$")]
+[assembly: AssemblyFileVersion("3.4.1.$WCREV$")]
Index: branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/RandomForest/RandomForestClassification.cs
===================================================================
--- branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/RandomForest/RandomForestClassification.cs	(revision 6760)
+++ branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/RandomForest/RandomForestClassification.cs	(revision 6760)
@@ -0,0 +1,132 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2011 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.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;
+using HeuristicLab.Parameters;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  /// <summary>
+  /// Random forest classification data analysis algorithm.
+  /// </summary>
+  [Item("Random Forest Classification", "Random forest classification data analysis algorithm (wrapper for ALGLIB).")]
+  [Creatable("Data Analysis")]
+  [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";
+    #region parameter properties
+    public IValueParameter<IntValue> NumberOfTreesParameter {
+      get { return (IValueParameter<IntValue>)Parameters[NumberOfTreesParameterName]; }
+    }
+    public IValueParameter<DoubleValue> RParameter {
+      get { return (IValueParameter<DoubleValue>)Parameters[RParameterName]; }
+    }
+    #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; }
+    }
+    #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)));
+      Problem = new ClassificationProblem();
+    }
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() { }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new RandomForestClassification(this, cloner);
+    }
+
+    #region random forest
+    protected override void Run() {
+      double rmsError, relClassificationError, outOfBagRmsError, outOfBagRelClassificationError;
+      var solution = CreateRandomForestClassificationSolution(Problem.ProblemData, NumberOfTrees, R, out rmsError, out relClassificationError, out outOfBagRmsError, out outOfBagRelClassificationError);
+      Results.Add(new Result(RandomForestClassificationModelResultName, "The random forest classification solution.", solution));
+      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)));
+    }
+
+    public static IClassificationSolution CreateRandomForestClassificationSolution(IClassificationProblemData problemData, int nTrees, double r,
+      out double rmsError, out double relClassificationError, out double outOfBagRmsError, out double outOfBagRelClassificationError) {
+      Dataset dataset = problemData.Dataset;
+      string targetVariable = problemData.TargetVariable;
+      IEnumerable<string> allowedInputVariables = problemData.AllowedInputVariables;
+      IEnumerable<int> rows = problemData.TrainingIndizes;
+      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("Random forest classification does not support NaN or infinity values in the input dataset.");
+
+
+      alglib.decisionforest dforest;
+      alglib.dfreport rep;
+      int nRows = inputMatrix.GetLength(0);
+      int nCols = inputMatrix.GetLength(1);
+      int info;
+      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> classIndizes = new Dictionary<double, double>();
+      for (int i = 0; i < nClasses; i++) {
+        classIndizes[classValues[i]] = i;
+      }
+      for (int row = 0; row < nRows; row++) {
+        inputMatrix[row, nCols - 1] = classIndizes[inputMatrix[row, nCols - 1]];
+      }
+      // execute random forest algorithm
+      alglib.dfbuildrandomdecisionforest(inputMatrix, nRows, nCols - 1, nClasses, nTrees, r, out info, out dforest, out rep);
+      if (info != 1) throw new ArgumentException("Error in calculation of random forest classification solution");
+
+      rmsError = rep.rmserror;
+      outOfBagRmsError = rep.oobrmserror;
+      relClassificationError = rep.relclserror;
+      outOfBagRelClassificationError = rep.oobrelclserror;
+      return new RandomForestClassificationSolution((IClassificationProblemData)problemData.Clone(), new RandomForestModel(dforest, targetVariable, allowedInputVariables, classValues));
+    }
+    #endregion
+  }
+}
Index: branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/RandomForest/RandomForestClassificationSolution.cs
===================================================================
--- branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/RandomForest/RandomForestClassificationSolution.cs	(revision 6760)
+++ branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/RandomForest/RandomForestClassificationSolution.cs	(revision 6760)
@@ -0,0 +1,58 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2011 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+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) {
+      RecalculateResults();
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new RandomForestClassificationSolution(this, cloner);
+    }
+
+    protected override void RecalculateResults() {
+      CalculateResults();
+    }
+  }
+}
Index: branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/RandomForest/RandomForestModel.cs
===================================================================
--- branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/RandomForest/RandomForestModel.cs	(revision 6760)
+++ branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/RandomForest/RandomForestModel.cs	(revision 6760)
@@ -0,0 +1,203 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2011 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.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 {
+
+    private alglib.decisionforest randomForest;
+    public alglib.decisionforest RandomForest {
+      get { return randomForest; }
+      set {
+        if (value != randomForest) {
+          if (value == null) throw new ArgumentNullException();
+          randomForest = value;
+          OnChanged(EventArgs.Empty);
+        }
+      }
+    }
+
+    [Storable]
+    private string targetVariable;
+    [Storable]
+    private string[] allowedInputVariables;
+    [Storable]
+    private double[] classValues;
+    [StorableConstructor]
+    private RandomForestModel(bool deserializing)
+      : base(deserializing) {
+      if (deserializing)
+        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;
+      randomForest.innerobj.trees = (double[])original.randomForest.innerobj.trees.Clone();
+      targetVariable = original.targetVariable;
+      allowedInputVariables = (string[])original.allowedInputVariables.Clone();
+      if (original.classValues != null)
+        this.classValues = (double[])original.classValues.Clone();
+    }
+    public RandomForestModel(alglib.decisionforest randomForest, string targetVariable, IEnumerable<string> allowedInputVariables, double[] classValues = null)
+      : base() {
+      this.name = ItemName;
+      this.description = ItemDescription;
+      this.randomForest = randomForest;
+      this.targetVariable = targetVariable;
+      this.allowedInputVariables = allowedInputVariables.ToArray();
+      if (classValues != null)
+        this.classValues = (double[])classValues.Clone();
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new RandomForestModel(this, cloner);
+    }
+
+    public IEnumerable<double> GetEstimatedValues(Dataset 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.dfprocess(randomForest, x, ref y);
+        yield return y[0];
+      }
+    }
+
+    public IEnumerable<double> GetEstimatedClassValues(Dataset 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[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(problemData, this);
+    }
+    IRegressionSolution IRegressionModel.CreateRegressionSolution(IRegressionProblemData problemData) {
+      return CreateRegressionSolution(problemData);
+    }
+    public IRandomForestClassificationSolution CreateClassificationSolution(IClassificationProblemData problemData) {
+      return new RandomForestClassificationSolution(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 int RandomForestBufSize {
+      get {
+        return randomForest.innerobj.bufsize;
+      }
+      set {
+        randomForest.innerobj.bufsize = value;
+      }
+    }
+    [Storable]
+    private int RandomForestNClasses {
+      get {
+        return randomForest.innerobj.nclasses;
+      }
+      set {
+        randomForest.innerobj.nclasses = value;
+      }
+    }
+    [Storable]
+    private int RandomForestNTrees {
+      get {
+        return randomForest.innerobj.ntrees;
+      }
+      set {
+        randomForest.innerobj.ntrees = value;
+      }
+    }
+    [Storable]
+    private int RandomForestNVars {
+      get {
+        return randomForest.innerobj.nvars;
+      }
+      set {
+        randomForest.innerobj.nvars = value;
+      }
+    }
+    [Storable]
+    private double[] RandomForestTrees {
+      get {
+        return randomForest.innerobj.trees;
+      }
+      set {
+        randomForest.innerobj.trees = value;
+      }
+    }
+    #endregion
+  }
+}
Index: branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/RandomForest/RandomForestRegression.cs
===================================================================
--- branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/RandomForest/RandomForestRegression.cs	(revision 6760)
+++ branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/RandomForest/RandomForestRegression.cs	(revision 6760)
@@ -0,0 +1,122 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2011 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.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;
+using HeuristicLab.Parameters;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  /// <summary>
+  /// Random forest regression data analysis algorithm.
+  /// </summary>
+  [Item("Random Forest Regression", "Random forest regression data analysis algorithm (wrapper for ALGLIB).")]
+  [Creatable("Data Analysis")]
+  [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";
+    #region parameter properties
+    public IValueParameter<IntValue> NumberOfTreesParameter {
+      get { return (IValueParameter<IntValue>)Parameters[NumberOfTreesParameterName]; }
+    }
+    public IValueParameter<DoubleValue> RParameter {
+      get { return (IValueParameter<DoubleValue>)Parameters[RParameterName]; }
+    }
+    #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; }
+    }
+    #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)));
+      Problem = new RegressionProblem();
+    }
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() { }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new RandomForestRegression(this, cloner);
+    }
+
+    #region random forest
+    protected override void Run() {
+      double rmsError, avgRelError, outOfBagRmsError, outOfBagAvgRelError;
+      var solution = CreateRandomForestRegressionSolution(Problem.ProblemData, NumberOfTrees, R, out rmsError, out avgRelError, out outOfBagRmsError, out outOfBagAvgRelError);
+      Results.Add(new Result(RandomForestRegressionModelResultName, "The random forest regression solution.", solution));
+      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)));
+    }
+
+    public static IRegressionSolution CreateRandomForestRegressionSolution(IRegressionProblemData problemData, int nTrees, double r,
+      out double rmsError, out double avgRelError, out double outOfBagRmsError, out double outOfBagAvgRelError) {
+      Dataset dataset = problemData.Dataset;
+      string targetVariable = problemData.TargetVariable;
+      IEnumerable<string> allowedInputVariables = problemData.AllowedInputVariables;
+      IEnumerable<int> rows = problemData.TrainingIndizes;
+      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("Random forest regression does not support NaN or infinity values in the input dataset.");
+
+
+      alglib.decisionforest dforest;
+      alglib.dfreport rep;
+      int nRows = inputMatrix.GetLength(0);
+
+      int info;
+      alglib.dfbuildrandomdecisionforest(inputMatrix, nRows, allowedInputVariables.Count(), 1, nTrees, r, out info, out dforest, out rep);
+      if (info != 1) throw new ArgumentException("Error in calculation of random forest regression solution");
+
+      rmsError = rep.rmserror;
+      avgRelError = rep.avgrelerror;
+      outOfBagAvgRelError = rep.oobavgrelerror;
+      outOfBagRmsError = rep.oobrmserror;
+
+      return new RandomForestRegressionSolution((IRegressionProblemData)problemData.Clone(), new RandomForestModel(dforest, targetVariable, allowedInputVariables));
+    }
+    #endregion
+  }
+}
Index: branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/RandomForest/RandomForestRegressionSolution.cs
===================================================================
--- branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/RandomForest/RandomForestRegressionSolution.cs	(revision 6760)
+++ branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/RandomForest/RandomForestRegressionSolution.cs	(revision 6760)
@@ -0,0 +1,54 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2011 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+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) {
+      RecalculateResults();
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new RandomForestRegressionSolution(this, cloner);
+    }
+  }
+}
Index: branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/RegressionWorkbench.cs
===================================================================
--- branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/RegressionWorkbench.cs	(revision 6760)
+++ branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/RegressionWorkbench.cs	(revision 6760)
@@ -0,0 +1,226 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2011 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Linq;
+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;
+using HeuristicLab.Parameters;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  [Item("Regression Workbench", "Experiment containing multiple algorithms for regression analysis.")]
+  [Creatable("Data Analysis")]
+  [StorableClass]
+  public sealed class RegressionWorkbench : ParameterizedNamedItem, IOptimizer, IStorableContent {
+    public string Filename { get; set; }
+
+    private const string ProblemDataParameterName = "ProblemData";
+
+    #region parameter properties
+    public IValueParameter<IRegressionProblemData> ProblemDataParameter {
+      get { return (IValueParameter<IRegressionProblemData>)Parameters[ProblemDataParameterName]; }
+    }
+    #endregion
+    #region properties
+    public IRegressionProblemData ProblemData {
+      get { return ProblemDataParameter.Value; }
+      set { ProblemDataParameter.Value = value; }
+    }
+    #endregion
+    [Storable]
+    private Experiment experiment;
+
+    [StorableConstructor]
+    private RegressionWorkbench(bool deserializing)
+      : base(deserializing) {
+    }
+    private RegressionWorkbench(RegressionWorkbench original, Cloner cloner)
+      : base(original, cloner) {
+      experiment = cloner.Clone(original.experiment);
+      RegisterEventHandlers();
+    }
+    public RegressionWorkbench()
+      : base() {
+      name = ItemName;
+      description = ItemDescription;
+
+      Parameters.Add(new ValueParameter<IRegressionProblemData>(ProblemDataParameterName, "The regression problem data that should be used for modeling.", new RegressionProblemData()));
+
+      experiment = new Experiment();
+
+      //var svmExperiments = CreateSvmExperiment();
+      var rfExperiments = CreateRandomForestExperiments();
+
+      experiment.Optimizers.Add(new LinearRegression());
+      experiment.Optimizers.Add(rfExperiments);
+      //experiment.Optimizers.Add(svmExperiments);
+
+      RegisterEventHandlers();
+    }
+
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() {
+      RegisterEventHandlers();
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new RegressionWorkbench(this, cloner);
+    }
+
+    private void RegisterEventHandlers() {
+      ProblemDataParameter.ValueChanged += ProblemDataParameterValueChanged;
+
+      experiment.ExceptionOccurred += (sender, e) => OnExceptionOccured(e);
+      experiment.ExecutionStateChanged += (sender, e) => OnExecutionStateChanged(e);
+      experiment.ExecutionTimeChanged += (sender, e) => OnExecutionTimeChanged(e);
+      experiment.Paused += (sender, e) => OnPaused(e);
+      experiment.Prepared += (sender, e) => OnPrepared(e);
+      experiment.Started += (sender, e) => OnStarted(e);
+      experiment.Stopped += (sender, e) => OnStopped(e);
+    }
+
+    private IOptimizer CreateRandomForestExperiments() {
+      var exp = new Experiment();
+      double[] rs = new double[] { 0.2, 0.3, 0.4, 0.5, 0.6, 0.65 };
+      foreach (var r in rs) {
+        var cv = new CrossValidation();
+        var rf = new RandomForestRegression();
+        rf.R = r;
+        cv.Algorithm = rf;
+        cv.Folds.Value = 5;
+        exp.Optimizers.Add(cv);
+      }
+      return exp;
+    }
+
+    private IOptimizer CreateSvmExperiment() {
+      var exp = new Experiment();
+      var costs = new double[] { Math.Pow(2, -5), Math.Pow(2, -3), Math.Pow(2, -1), Math.Pow(2, 1), Math.Pow(2, 3), Math.Pow(2, 5), Math.Pow(2, 7), Math.Pow(2, 9), Math.Pow(2, 11), Math.Pow(2, 13), Math.Pow(2, 15) };
+      var gammas = new double[] { Math.Pow(2, -15), Math.Pow(2, -13), Math.Pow(2, -11), Math.Pow(2, -9), Math.Pow(2, -7), Math.Pow(2, -5), Math.Pow(2, -3), Math.Pow(2, -1), Math.Pow(2, 1), Math.Pow(2, 3) };
+      var nus = new double[] { 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9 };
+      foreach (var gamma in gammas)
+        foreach (var cost in costs)
+          foreach (var nu in nus) {
+            var cv = new CrossValidation();
+            var svr = new SupportVectorRegression();        
+            svr.Nu.Value = nu;
+            svr.Cost.Value = cost;
+            svr.Gamma.Value = gamma;
+            cv.Algorithm = svr;
+            cv.Folds.Value = 5;
+            exp.Optimizers.Add(cv);
+          }
+      return exp;
+    }
+
+    public RunCollection Runs {
+      get { return experiment.Runs; }
+    }
+
+    public void Prepare(bool clearRuns) {
+      experiment.Prepare(clearRuns);
+    }
+
+    public IEnumerable<IOptimizer> NestedOptimizers {
+      get { return experiment.NestedOptimizers; }
+    }
+
+    public ExecutionState ExecutionState {
+      get { return experiment.ExecutionState; }
+    }
+
+    public TimeSpan ExecutionTime {
+      get { return experiment.ExecutionTime; }
+    }
+
+    public void Prepare() {
+      experiment.Prepare();
+    }
+
+    public void Start() {
+      experiment.Start();
+    }
+
+    public void Pause() {
+      experiment.Pause();
+    }
+
+    public void Stop() {
+      experiment.Stop();
+    }
+
+    public event EventHandler ExecutionStateChanged;
+    private void OnExecutionStateChanged(EventArgs e) {
+      var handler = ExecutionStateChanged;
+      if (handler != null) handler(this, e);
+    }
+
+    public event EventHandler ExecutionTimeChanged;
+    private void OnExecutionTimeChanged(EventArgs e) {
+      var handler = ExecutionTimeChanged;
+      if (handler != null) handler(this, e);
+    }
+
+    public event EventHandler Prepared;
+    private void OnPrepared(EventArgs e) {
+      var handler = Prepared;
+      if (handler != null) handler(this, e);
+    }
+
+    public event EventHandler Started;
+    private void OnStarted(EventArgs e) {
+      var handler = Started;
+      if (handler != null) handler(this, e);
+    }
+
+    public event EventHandler Paused;
+    private void OnPaused(EventArgs e) {
+      var handler = Paused;
+      if (handler != null) handler(this, e);
+    }
+
+    public event EventHandler Stopped;
+    private void OnStopped(EventArgs e) {
+      var handler = Stopped;
+      if (handler != null) handler(this, e);
+    }
+
+    public event EventHandler<EventArgs<Exception>> ExceptionOccurred;
+    private void OnExceptionOccured(EventArgs<Exception> e) {
+      var handler = ExceptionOccurred;
+      if (handler != null) handler(this, e);
+    }
+
+    public void ProblemDataParameterValueChanged(object source, EventArgs e) {
+      foreach (var op in NestedOptimizers.OfType<IDataAnalysisAlgorithm<IRegressionProblem>>()) {
+        op.Problem.ProblemDataParameter.Value = ProblemData;
+      }
+    }
+  }
+}
Index: branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/SupportVectorMachine/SupportVectorClassification.cs
===================================================================
--- branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/SupportVectorMachine/SupportVectorClassification.cs	(revision 6228)
+++ branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/SupportVectorMachine/SupportVectorClassification.cs	(revision 6760)
@@ -35,5 +35,5 @@
   /// Support vector machine classification data analysis algorithm.
   /// </summary>
-  [Item("Support Vector Classification", "Support vector machine classification data analysis algorithm.")]
+  [Item("Support Vector Classification", "Support vector machine classification data analysis algorithm (wrapper for libSVM).")]
   [Creatable("Data Analysis")]
   [StorableClass]
Index: branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/SupportVectorMachine/SupportVectorClassificationSolution.cs
===================================================================
--- branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/SupportVectorMachine/SupportVectorClassificationSolution.cs	(revision 6228)
+++ branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/SupportVectorMachine/SupportVectorClassificationSolution.cs	(revision 6760)
@@ -20,8 +20,4 @@
 #endregion
 
-using System;
-using System.Collections.Generic;
-using System.Drawing;
-using System.Linq;
 using HeuristicLab.Common;
 using HeuristicLab.Core;
@@ -49,4 +45,5 @@
     public SupportVectorClassificationSolution(SupportVectorMachineModel model, IClassificationProblemData problemData)
       : base(model, problemData) {
+      RecalculateResults();
     }
 
@@ -54,4 +51,8 @@
       return new SupportVectorClassificationSolution(this, cloner);
     }
+
+    protected override void RecalculateResults() {
+      CalculateResults();
+    }
   }
 }
Index: branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/SupportVectorMachine/SupportVectorMachineModel.cs
===================================================================
--- branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/SupportVectorMachine/SupportVectorMachineModel.cs	(revision 6228)
+++ branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/SupportVectorMachine/SupportVectorMachineModel.cs	(revision 6760)
@@ -98,4 +98,7 @@
       this.targetVariable = original.targetVariable;
       this.allowedInputVariables = (string[])original.allowedInputVariables.Clone();
+      foreach (var dataset in original.cachedPredictions.Keys) {
+        this.cachedPredictions.Add(cloner.Clone(dataset), (double[])original.cachedPredictions[dataset].Clone());
+      }
       if (original.classValues != null)
         this.classValues = (double[])original.classValues.Clone();
@@ -123,5 +126,12 @@
       return GetEstimatedValuesHelper(dataset, rows);
     }
-    #endregion
+    public SupportVectorRegressionSolution CreateRegressionSolution(IRegressionProblemData problemData) {
+      return new SupportVectorRegressionSolution(this, problemData);
+    }
+    IRegressionSolution IRegressionModel.CreateRegressionSolution(IRegressionProblemData problemData) {
+      return CreateRegressionSolution(problemData);
+    }
+    #endregion
+
     #region IClassificationModel Members
     public IEnumerable<double> GetEstimatedClassValues(Dataset dataset, IEnumerable<int> rows) {
@@ -144,16 +154,58 @@
       }
     }
-    #endregion
+
+    public SupportVectorClassificationSolution CreateClassificationSolution(IClassificationProblemData problemData) {
+      return new SupportVectorClassificationSolution(this, problemData);
+    }
+    IClassificationSolution IClassificationModel.CreateClassificationSolution(IClassificationProblemData problemData) {
+      return CreateClassificationSolution(problemData);
+    }
+    #endregion
+    // cache for predictions, which is cloned but not persisted, must be cleared when the model is changed
+    private Dictionary<Dataset, double[]> cachedPredictions = new Dictionary<Dataset, double[]>();
     private IEnumerable<double> GetEstimatedValuesHelper(Dataset dataset, IEnumerable<int> rows) {
+      if (!cachedPredictions.ContainsKey(dataset)) {
+        // create an array of cached predictions which is initially filled with NaNs
+        double[] predictions = Enumerable.Repeat(double.NaN, dataset.Rows).ToArray();
+        CalculatePredictions(dataset, rows, predictions);
+        cachedPredictions.Add(dataset, predictions);
+      }
+      // get the array of predictions and select the subset of requested rows
+      double[] p = cachedPredictions[dataset];
+      var requestedPredictions = from r in rows
+                                 select p[r];
+      // check if the requested predictions contain NaNs 
+      // (this means for the request rows some predictions have not been cached)
+      if (requestedPredictions.Any(x => double.IsNaN(x))) {
+        // updated the predictions for currently requested rows
+        CalculatePredictions(dataset, rows, p);
+        cachedPredictions[dataset] = p;
+        // now we can be sure that for the current rows all predictions are available
+        return from r in rows
+               select p[r];
+      } else {
+        // there were no NaNs => just return the cached predictions
+        return requestedPredictions;
+      }
+    }
+
+    private void CalculatePredictions(Dataset dataset, IEnumerable<int> rows, double[] predictions) {
+      // calculate and cache predictions for the currently requested rows
       SVM.Problem problem = SupportVectorMachineUtil.CreateSvmProblem(dataset, targetVariable, allowedInputVariables, rows);
       SVM.Problem scaledProblem = Scaling.Scale(RangeTransform, problem);
 
-      foreach (var row in Enumerable.Range(0, scaledProblem.Count)) {
-        yield return SVM.Prediction.Predict(Model, scaledProblem.X[row]);
-      }
-    }
+      // row is the index in the original dataset, 
+      // i is the index in the scaled dataset (containing only the necessary rows)
+      int i = 0;
+      foreach (var row in rows) {
+        predictions[row] = SVM.Prediction.Predict(Model, scaledProblem.X[i]);
+        i++;
+      }
+    }
+
     #region events
     public event EventHandler Changed;
     private void OnChanged(EventArgs e) {
+      cachedPredictions.Clear();
       var handlers = Changed;
       if (handlers != null)
Index: branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/SupportVectorMachine/SupportVectorMachineUtil.cs
===================================================================
--- branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/SupportVectorMachine/SupportVectorMachineUtil.cs	(revision 6228)
+++ branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/SupportVectorMachine/SupportVectorMachineUtil.cs	(revision 6760)
@@ -34,6 +34,5 @@
     public static SVM.Problem CreateSvmProblem(Dataset dataset, string targetVariable, IEnumerable<string> inputVariables, IEnumerable<int> rowIndices) {
       double[] targetVector =
-        dataset.GetEnumeratedVariableValues(targetVariable, rowIndices)
-        .ToArray();
+        dataset.GetDoubleValues(targetVariable, rowIndices).ToArray();
 
       SVM.Node[][] nodes = new SVM.Node[targetVector.Length][];
@@ -46,5 +45,5 @@
         int colIndex = 1; // make sure the smallest node index for SVM = 1
         foreach (var inputVariable in inputVariablesList) {
-          double value = dataset[row, dataset.GetVariableIndex(inputVariable)];
+          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
Index: branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/SupportVectorMachine/SupportVectorRegression.cs
===================================================================
--- branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/SupportVectorMachine/SupportVectorRegression.cs	(revision 6228)
+++ branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/SupportVectorMachine/SupportVectorRegression.cs	(revision 6760)
@@ -35,5 +35,5 @@
   /// Support vector machine regression data analysis algorithm.
   /// </summary>
-  [Item("Support Vector Regression", "Support vector machine regression data analysis algorithm.")]
+  [Item("Support Vector Regression", "Support vector machine regression data analysis algorithm (wrapper for libSVM).")]
   [Creatable("Data Analysis")]
   [StorableClass]
Index: branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/SupportVectorMachine/SupportVectorRegressionSolution.cs
===================================================================
--- branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/SupportVectorMachine/SupportVectorRegressionSolution.cs	(revision 6228)
+++ branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/SupportVectorMachine/SupportVectorRegressionSolution.cs	(revision 6760)
@@ -20,8 +20,4 @@
 #endregion
 
-using System;
-using System.Collections.Generic;
-using System.Drawing;
-using System.Linq;
 using HeuristicLab.Common;
 using HeuristicLab.Core;
@@ -49,4 +45,5 @@
     public SupportVectorRegressionSolution(SupportVectorMachineModel model, IRegressionProblemData problemData)
       : base(model, problemData) {
+      RecalculateResults();
     }
 
Index: branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/kMeans/KMeansClustering.cs
===================================================================
--- branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/kMeans/KMeansClustering.cs	(revision 6228)
+++ branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/kMeans/KMeansClustering.cs	(revision 6760)
@@ -35,5 +35,5 @@
   /// k-Means clustering algorithm data analysis algorithm.
   /// </summary>
-  [Item("k-Means", "The k-Means clustering algorithm.")]
+  [Item("k-Means", "The k-Means clustering algorithm (wrapper for ALGLIB).")]
   [Creatable("Data Analysis")]
   [StorableClass]
Index: branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/kMeans/KMeansClusteringUtil.cs
===================================================================
--- branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/kMeans/KMeansClusteringUtil.cs	(revision 6228)
+++ branches/PersistenceSpeedUp/HeuristicLab.Algorithms.DataAnalysis/3.4/kMeans/KMeansClusteringUtil.cs	(revision 6760)
@@ -20,8 +20,8 @@
 #endregion
 
+using System;
 using System.Collections.Generic;
 using System.Linq;
 using HeuristicLab.Problems.DataAnalysis;
-using System;
 
 namespace HeuristicLab.Algorithms.DataAnalysis {
@@ -42,5 +42,5 @@
           int col = 0;
           foreach (var inputVariable in allowedInputVariables) {
-            double d = center[col++] - dataset[inputVariable, row];
+            double d = center[col++] - dataset.GetDoubleValue(inputVariable, row);
             d = d * d; // square;
             centerDistance += d;
@@ -73,5 +73,5 @@
         double[] p = new double[allowedInputVariables.Count];
         for (int i = 0; i < nCols; i++) {
-          p[i] = dataset[allowedInputVariables[i], row];
+          p[i] = dataset.GetDoubleValue(allowedInputVariables[i], row);
         }
         clusterPoints[clusterValues[clusterValueIndex++]].Add(p);
