Index: /branches/QAPAlgorithms/HeuristicLab.Algorithms.DataAnalysis/3.4/HeuristicLab.Algorithms.DataAnalysis-3.4.csproj
===================================================================
--- /branches/QAPAlgorithms/HeuristicLab.Algorithms.DataAnalysis/3.4/HeuristicLab.Algorithms.DataAnalysis-3.4.csproj	(revision 6610)
+++ /branches/QAPAlgorithms/HeuristicLab.Algorithms.DataAnalysis/3.4/HeuristicLab.Algorithms.DataAnalysis-3.4.csproj	(revision 6611)
@@ -107,4 +107,5 @@
   </ItemGroup>
   <ItemGroup>
+    <Compile Include="RegressionWorkbench.cs" />
     <Compile Include="CrossValidation.cs">
       <SubType>Code</SubType>
@@ -112,4 +113,13 @@
     <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" />
@@ -129,7 +139,22 @@
       <SubType>Code</SubType>
     </Compile>
-    <Compile Include="Linear\LogitClassificationSolution.cs" />
-    <Compile Include="Linear\LogitModel.cs" />
     <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" />
Index: /branches/QAPAlgorithms/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/INearestNeighbourClassificationSolution.cs
===================================================================
--- /branches/QAPAlgorithms/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/INearestNeighbourClassificationSolution.cs	(revision 6611)
+++ /branches/QAPAlgorithms/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/INearestNeighbourClassificationSolution.cs	(revision 6611)
@@ -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/QAPAlgorithms/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/INearestNeighbourModel.cs
===================================================================
--- /branches/QAPAlgorithms/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/INearestNeighbourModel.cs	(revision 6611)
+++ /branches/QAPAlgorithms/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/INearestNeighbourModel.cs	(revision 6611)
@@ -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/QAPAlgorithms/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/INearestNeighbourRegressionSolution.cs
===================================================================
--- /branches/QAPAlgorithms/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/INearestNeighbourRegressionSolution.cs	(revision 6611)
+++ /branches/QAPAlgorithms/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/INearestNeighbourRegressionSolution.cs	(revision 6611)
@@ -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/QAPAlgorithms/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/INeuralNetworkClassificationSolution.cs
===================================================================
--- /branches/QAPAlgorithms/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/INeuralNetworkClassificationSolution.cs	(revision 6611)
+++ /branches/QAPAlgorithms/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/INeuralNetworkClassificationSolution.cs	(revision 6611)
@@ -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/QAPAlgorithms/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/INeuralNetworkEnsembleClassificationSolution.cs
===================================================================
--- /branches/QAPAlgorithms/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/INeuralNetworkEnsembleClassificationSolution.cs	(revision 6611)
+++ /branches/QAPAlgorithms/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/INeuralNetworkEnsembleClassificationSolution.cs	(revision 6611)
@@ -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/QAPAlgorithms/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/INeuralNetworkEnsembleModel.cs
===================================================================
--- /branches/QAPAlgorithms/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/INeuralNetworkEnsembleModel.cs	(revision 6611)
+++ /branches/QAPAlgorithms/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/INeuralNetworkEnsembleModel.cs	(revision 6611)
@@ -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/QAPAlgorithms/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/INeuralNetworkEnsembleRegressionSolution.cs
===================================================================
--- /branches/QAPAlgorithms/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/INeuralNetworkEnsembleRegressionSolution.cs	(revision 6611)
+++ /branches/QAPAlgorithms/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/INeuralNetworkEnsembleRegressionSolution.cs	(revision 6611)
@@ -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/QAPAlgorithms/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/INeuralNetworkModel.cs
===================================================================
--- /branches/QAPAlgorithms/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/INeuralNetworkModel.cs	(revision 6611)
+++ /branches/QAPAlgorithms/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/INeuralNetworkModel.cs	(revision 6611)
@@ -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/QAPAlgorithms/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/INeuralNetworkRegressionSolution.cs
===================================================================
--- /branches/QAPAlgorithms/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/INeuralNetworkRegressionSolution.cs	(revision 6611)
+++ /branches/QAPAlgorithms/HeuristicLab.Algorithms.DataAnalysis/3.4/Interfaces/INeuralNetworkRegressionSolution.cs	(revision 6611)
@@ -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: anches/QAPAlgorithms/HeuristicLab.Algorithms.DataAnalysis/3.4/Linear/LogitClassificationSolution.cs
===================================================================
--- /branches/QAPAlgorithms/HeuristicLab.Algorithms.DataAnalysis/3.4/Linear/LogitClassificationSolution.cs	(revision 6610)
+++ 	(revision )
@@ -1,57 +1,0 @@
-#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.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("LogitClassificationSolution", "Represents a multinomial logit solution for a classification problem which can be visualized in the GUI.")]
-  [StorableClass]
-  public sealed class LogitClassificationSolution : ClassificationSolution {
-
-    public new LogitModel Model {
-      get { return (LogitModel)base.Model; }
-      set { base.Model = value; }
-    }
-
-    [StorableConstructor]
-    private LogitClassificationSolution(bool deserializing) : base(deserializing) { }
-    private LogitClassificationSolution(LogitClassificationSolution original, Cloner cloner)
-      : base(original, cloner) {
-    }
-    public LogitClassificationSolution(IClassificationProblemData problemData, LogitModel logitModel)
-      : base(logitModel, problemData) {
-    }
-
-    public override IDeepCloneable Clone(Cloner cloner) {
-      return new LogitClassificationSolution(this, cloner);
-    }
-  }
-}
Index: anches/QAPAlgorithms/HeuristicLab.Algorithms.DataAnalysis/3.4/Linear/LogitModel.cs
===================================================================
--- /branches/QAPAlgorithms/HeuristicLab.Algorithms.DataAnalysis/3.4/Linear/LogitModel.cs	(revision 6610)
+++ 	(revision )
@@ -1,134 +1,0 @@
-#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.IO;
-using System.Linq;
-using System.Text;
-using HeuristicLab.Common;
-using HeuristicLab.Core;
-using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
-using HeuristicLab.Problems.DataAnalysis;
-using SVM;
-
-namespace HeuristicLab.Algorithms.DataAnalysis {
-  /// <summary>
-  /// Represents a multinomial logit model for classification
-  /// </summary>
-  [StorableClass]
-  [Item("LogitModel", "Represents a multinomial logit model for classification.")]
-  public sealed class LogitModel : 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 LogitModel(bool deserializing)
-      : base(deserializing) {
-      if (deserializing)
-        logitModel = new alglib.logitmodel();
-    }
-    private LogitModel(LogitModel 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();
-      this.classValues = (double[])original.classValues.Clone();
-    }
-    public LogitModel(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 LogitModel(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];
-      }
-    }
-
-    #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/QAPAlgorithms/HeuristicLab.Algorithms.DataAnalysis/3.4/Linear/MultinomialLogitClassification.cs
===================================================================
--- /branches/QAPAlgorithms/HeuristicLab.Algorithms.DataAnalysis/3.4/Linear/MultinomialLogitClassification.cs	(revision 6610)
+++ /branches/QAPAlgorithms/HeuristicLab.Algorithms.DataAnalysis/3.4/Linear/MultinomialLogitClassification.cs	(revision 6611)
@@ -37,5 +37,5 @@
   /// Multinomial logit regression data analysis algorithm.
   /// </summary>
-  [Item("Multinomial logit classification", "Multinomial logit classification data analysis algorithm (wrapper for ALGLIB).")]
+  [Item("Multinomial Logit Classification", "Multinomial logit classification data analysis algorithm (wrapper for ALGLIB).")]
   [Creatable("Data Analysis")]
   [StorableClass]
@@ -98,5 +98,5 @@
       relClassError = alglib.mnlrelclserror(lm, inputMatrix, nRows);
 
-      LogitClassificationSolution solution = new LogitClassificationSolution(problemData, new LogitModel(lm, targetVariable, allowedInputVariables, classValues));
+      MultinomialLogitClassificationSolution solution = new MultinomialLogitClassificationSolution(problemData, new MultinomialLogitModel(lm, targetVariable, allowedInputVariables, classValues));
       return solution;
     }
Index: /branches/QAPAlgorithms/HeuristicLab.Algorithms.DataAnalysis/3.4/Linear/MultinomialLogitClassificationSolution.cs
===================================================================
--- /branches/QAPAlgorithms/HeuristicLab.Algorithms.DataAnalysis/3.4/Linear/MultinomialLogitClassificationSolution.cs	(revision 6611)
+++ /branches/QAPAlgorithms/HeuristicLab.Algorithms.DataAnalysis/3.4/Linear/MultinomialLogitClassificationSolution.cs	(revision 6611)
@@ -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/QAPAlgorithms/HeuristicLab.Algorithms.DataAnalysis/3.4/Linear/MultinomialLogitModel.cs
===================================================================
--- /branches/QAPAlgorithms/HeuristicLab.Algorithms.DataAnalysis/3.4/Linear/MultinomialLogitModel.cs	(revision 6611)
+++ /branches/QAPAlgorithms/HeuristicLab.Algorithms.DataAnalysis/3.4/Linear/MultinomialLogitModel.cs	(revision 6611)
@@ -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();
+      this.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/QAPAlgorithms/HeuristicLab.Algorithms.DataAnalysis/3.4/NearestNeighbour/NearestNeighbourClassification.cs
===================================================================
--- /branches/QAPAlgorithms/HeuristicLab.Algorithms.DataAnalysis/3.4/NearestNeighbour/NearestNeighbourClassification.cs	(revision 6611)
+++ /branches/QAPAlgorithms/HeuristicLab.Algorithms.DataAnalysis/3.4/NearestNeighbour/NearestNeighbourClassification.cs	(revision 6611)
@@ -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.GetVariableValues(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);
+
+      return new NearestNeighbourClassificationSolution(problemData, new NearestNeighbourModel(kdtree, k, targetVariable, allowedInputVariables, problemData.ClassValues.ToArray()));
+    }
+    #endregion
+  }
+}
Index: /branches/QAPAlgorithms/HeuristicLab.Algorithms.DataAnalysis/3.4/NearestNeighbour/NearestNeighbourClassificationSolution.cs
===================================================================
--- /branches/QAPAlgorithms/HeuristicLab.Algorithms.DataAnalysis/3.4/NearestNeighbour/NearestNeighbourClassificationSolution.cs	(revision 6611)
+++ /branches/QAPAlgorithms/HeuristicLab.Algorithms.DataAnalysis/3.4/NearestNeighbour/NearestNeighbourClassificationSolution.cs	(revision 6611)
@@ -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/QAPAlgorithms/HeuristicLab.Algorithms.DataAnalysis/3.4/NearestNeighbour/NearestNeighbourModel.cs
===================================================================
--- /branches/QAPAlgorithms/HeuristicLab.Algorithms.DataAnalysis/3.4/NearestNeighbour/NearestNeighbourModel.cs	(revision 6611)
+++ /branches/QAPAlgorithms/HeuristicLab.Algorithms.DataAnalysis/3.4/NearestNeighbour/NearestNeighbourModel.cs	(revision 6611)
@@ -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/QAPAlgorithms/HeuristicLab.Algorithms.DataAnalysis/3.4/NearestNeighbour/NearestNeighbourRegression.cs
===================================================================
--- /branches/QAPAlgorithms/HeuristicLab.Algorithms.DataAnalysis/3.4/NearestNeighbour/NearestNeighbourRegression.cs	(revision 6611)
+++ /branches/QAPAlgorithms/HeuristicLab.Algorithms.DataAnalysis/3.4/NearestNeighbour/NearestNeighbourRegression.cs	(revision 6611)
@@ -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(problemData, new NearestNeighbourModel(kdtree, k, targetVariable, allowedInputVariables));
+    }
+    #endregion
+  }
+}
Index: /branches/QAPAlgorithms/HeuristicLab.Algorithms.DataAnalysis/3.4/NearestNeighbour/NearestNeighbourRegressionSolution.cs
===================================================================
--- /branches/QAPAlgorithms/HeuristicLab.Algorithms.DataAnalysis/3.4/NearestNeighbour/NearestNeighbourRegressionSolution.cs	(revision 6611)
+++ /branches/QAPAlgorithms/HeuristicLab.Algorithms.DataAnalysis/3.4/NearestNeighbour/NearestNeighbourRegressionSolution.cs	(revision 6611)
@@ -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/QAPAlgorithms/HeuristicLab.Algorithms.DataAnalysis/3.4/NeuralNetwork/NeuralNetworkClassification.cs
===================================================================
--- /branches/QAPAlgorithms/HeuristicLab.Algorithms.DataAnalysis/3.4/NeuralNetwork/NeuralNetworkClassification.cs	(revision 6611)
+++ /branches/QAPAlgorithms/HeuristicLab.Algorithms.DataAnalysis/3.4/NeuralNetwork/NeuralNetworkClassification.cs	(revision 6611)
@@ -0,0 +1,194 @@
+#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) {
+    }
+    public NeuralNetworkClassification()
+      : base() {
+      var validHiddenLayerValues = new ItemSet<IntValue>(new IntValue[] { new IntValue(0), new IntValue(1), new IntValue(2) });
+      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)));
+
+      Problem = new ClassificationProblem();
+    }
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() { }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new NeuralNetworkClassification(this, cloner);
+    }
+
+    #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.GetVariableValues(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;
+
+      return new NeuralNetworkClassificationSolution(problemData, new NeuralNetworkModel(multiLayerPerceptron, targetVariable, allowedInputVariables, problemData.ClassValues.ToArray()));
+    }
+    #endregion
+  }
+}
Index: /branches/QAPAlgorithms/HeuristicLab.Algorithms.DataAnalysis/3.4/NeuralNetwork/NeuralNetworkClassificationSolution.cs
===================================================================
--- /branches/QAPAlgorithms/HeuristicLab.Algorithms.DataAnalysis/3.4/NeuralNetwork/NeuralNetworkClassificationSolution.cs	(revision 6611)
+++ /branches/QAPAlgorithms/HeuristicLab.Algorithms.DataAnalysis/3.4/NeuralNetwork/NeuralNetworkClassificationSolution.cs	(revision 6611)
@@ -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/QAPAlgorithms/HeuristicLab.Algorithms.DataAnalysis/3.4/NeuralNetwork/NeuralNetworkEnsembleClassification.cs
===================================================================
--- /branches/QAPAlgorithms/HeuristicLab.Algorithms.DataAnalysis/3.4/NeuralNetwork/NeuralNetworkEnsembleClassification.cs	(revision 6611)
+++ /branches/QAPAlgorithms/HeuristicLab.Algorithms.DataAnalysis/3.4/NeuralNetwork/NeuralNetworkEnsembleClassification.cs	(revision 6611)
@@ -0,0 +1,205 @@
+#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[] { new IntValue(0), new IntValue(1), new IntValue(2) });
+      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)));
+
+      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.GetVariableValues(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);
+
+      return new NeuralNetworkEnsembleClassificationSolution(problemData, new NeuralNetworkEnsembleModel(mlpEnsemble, targetVariable, allowedInputVariables, problemData.ClassValues.ToArray()));
+    }
+    #endregion
+  }
+}
Index: /branches/QAPAlgorithms/HeuristicLab.Algorithms.DataAnalysis/3.4/NeuralNetwork/NeuralNetworkEnsembleClassificationSolution.cs
===================================================================
--- /branches/QAPAlgorithms/HeuristicLab.Algorithms.DataAnalysis/3.4/NeuralNetwork/NeuralNetworkEnsembleClassificationSolution.cs	(revision 6611)
+++ /branches/QAPAlgorithms/HeuristicLab.Algorithms.DataAnalysis/3.4/NeuralNetwork/NeuralNetworkEnsembleClassificationSolution.cs	(revision 6611)
@@ -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/QAPAlgorithms/HeuristicLab.Algorithms.DataAnalysis/3.4/NeuralNetwork/NeuralNetworkEnsembleModel.cs
===================================================================
--- /branches/QAPAlgorithms/HeuristicLab.Algorithms.DataAnalysis/3.4/NeuralNetwork/NeuralNetworkEnsembleModel.cs	(revision 6611)
+++ /branches/QAPAlgorithms/HeuristicLab.Algorithms.DataAnalysis/3.4/NeuralNetwork/NeuralNetworkEnsembleModel.cs	(revision 6611)
@@ -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/QAPAlgorithms/HeuristicLab.Algorithms.DataAnalysis/3.4/NeuralNetwork/NeuralNetworkEnsembleRegression.cs
===================================================================
--- /branches/QAPAlgorithms/HeuristicLab.Algorithms.DataAnalysis/3.4/NeuralNetwork/NeuralNetworkEnsembleRegression.cs	(revision 6611)
+++ /branches/QAPAlgorithms/HeuristicLab.Algorithms.DataAnalysis/3.4/NeuralNetwork/NeuralNetworkEnsembleRegression.cs	(revision 6611)
@@ -0,0 +1,191 @@
+#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[] { new IntValue(0), new IntValue(1), new IntValue(2) });
+      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)));
+
+      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(problemData, new NeuralNetworkEnsembleModel(mlpEnsemble, targetVariable, allowedInputVariables));
+    }
+    #endregion
+  }
+}
Index: /branches/QAPAlgorithms/HeuristicLab.Algorithms.DataAnalysis/3.4/NeuralNetwork/NeuralNetworkEnsembleRegressionSolution.cs
===================================================================
--- /branches/QAPAlgorithms/HeuristicLab.Algorithms.DataAnalysis/3.4/NeuralNetwork/NeuralNetworkEnsembleRegressionSolution.cs	(revision 6611)
+++ /branches/QAPAlgorithms/HeuristicLab.Algorithms.DataAnalysis/3.4/NeuralNetwork/NeuralNetworkEnsembleRegressionSolution.cs	(revision 6611)
@@ -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/QAPAlgorithms/HeuristicLab.Algorithms.DataAnalysis/3.4/NeuralNetwork/NeuralNetworkModel.cs
===================================================================
--- /branches/QAPAlgorithms/HeuristicLab.Algorithms.DataAnalysis/3.4/NeuralNetwork/NeuralNetworkModel.cs	(revision 6611)
+++ /branches/QAPAlgorithms/HeuristicLab.Algorithms.DataAnalysis/3.4/NeuralNetwork/NeuralNetworkModel.cs	(revision 6611)
@@ -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/QAPAlgorithms/HeuristicLab.Algorithms.DataAnalysis/3.4/NeuralNetwork/NeuralNetworkRegression.cs
===================================================================
--- /branches/QAPAlgorithms/HeuristicLab.Algorithms.DataAnalysis/3.4/NeuralNetwork/NeuralNetworkRegression.cs	(revision 6611)
+++ /branches/QAPAlgorithms/HeuristicLab.Algorithms.DataAnalysis/3.4/NeuralNetwork/NeuralNetworkRegression.cs	(revision 6611)
@@ -0,0 +1,185 @@
+#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) {
+    }
+    public NeuralNetworkRegression()
+      : base() {
+      var validHiddenLayerValues = new ItemSet<IntValue>(new IntValue[] { new IntValue(0), new IntValue(1), new IntValue(2) });
+      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)));
+
+      Problem = new RegressionProblem();
+    }
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() { }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new NeuralNetworkRegression(this, cloner);
+    }
+
+    #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.");
+
+      double targetMin = problemData.Dataset.GetEnumeratedVariableValues(targetVariable).Min();
+      targetMin = targetMin - targetMin * 0.1; // -10%
+      double targetMax = problemData.Dataset.GetEnumeratedVariableValues(targetVariable).Max();
+      targetMax = targetMax + targetMax * 0.1; // + 10%
+
+      alglib.multilayerperceptron multiLayerPerceptron = null;
+      if (nLayers == 0) {
+        alglib.mlpcreater0(allowedInputVariables.Count(), 1, targetMin, targetMax, out multiLayerPerceptron);
+      } else if (nLayers == 1) {
+        alglib.mlpcreater1(allowedInputVariables.Count(), nHiddenNodes1, 1, targetMin, targetMax, out multiLayerPerceptron);
+      } else if (nLayers == 2) {
+        alglib.mlpcreater2(allowedInputVariables.Count(), nHiddenNodes1, nHiddenNodes2, 1, targetMin, targetMax, 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(problemData, new NeuralNetworkModel(multiLayerPerceptron, targetVariable, allowedInputVariables));
+    }
+    #endregion
+  }
+}
Index: /branches/QAPAlgorithms/HeuristicLab.Algorithms.DataAnalysis/3.4/NeuralNetwork/NeuralNetworkRegressionSolution.cs
===================================================================
--- /branches/QAPAlgorithms/HeuristicLab.Algorithms.DataAnalysis/3.4/NeuralNetwork/NeuralNetworkRegressionSolution.cs	(revision 6611)
+++ /branches/QAPAlgorithms/HeuristicLab.Algorithms.DataAnalysis/3.4/NeuralNetwork/NeuralNetworkRegressionSolution.cs	(revision 6611)
@@ -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/QAPAlgorithms/HeuristicLab.Algorithms.DataAnalysis/3.4/RandomForest/RandomForestClassificationSolution.cs
===================================================================
--- /branches/QAPAlgorithms/HeuristicLab.Algorithms.DataAnalysis/3.4/RandomForest/RandomForestClassificationSolution.cs	(revision 6610)
+++ /branches/QAPAlgorithms/HeuristicLab.Algorithms.DataAnalysis/3.4/RandomForest/RandomForestClassificationSolution.cs	(revision 6611)
@@ -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 RandomForestClassificationSolution(IClassificationProblemData problemData, IRandomForestModel randomForestModel)
       : base(randomForestModel, problemData) {
+      RecalculateResults();
     }
 
@@ -54,4 +51,8 @@
       return new RandomForestClassificationSolution(this, cloner);
     }
+
+    protected override void RecalculateResults() {
+      CalculateResults();
+    }
   }
 }
Index: /branches/QAPAlgorithms/HeuristicLab.Algorithms.DataAnalysis/3.4/RandomForest/RandomForestModel.cs
===================================================================
--- /branches/QAPAlgorithms/HeuristicLab.Algorithms.DataAnalysis/3.4/RandomForest/RandomForestModel.cs	(revision 6610)
+++ /branches/QAPAlgorithms/HeuristicLab.Algorithms.DataAnalysis/3.4/RandomForest/RandomForestModel.cs	(revision 6611)
@@ -22,12 +22,9 @@
 using System;
 using System.Collections.Generic;
-using System.IO;
 using System.Linq;
-using System.Text;
 using HeuristicLab.Common;
 using HeuristicLab.Core;
 using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
 using HeuristicLab.Problems.DataAnalysis;
-using SVM;
 
 namespace HeuristicLab.Algorithms.DataAnalysis {
@@ -134,4 +131,17 @@
     }
 
+    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;
Index: /branches/QAPAlgorithms/HeuristicLab.Algorithms.DataAnalysis/3.4/RandomForest/RandomForestRegressionSolution.cs
===================================================================
--- /branches/QAPAlgorithms/HeuristicLab.Algorithms.DataAnalysis/3.4/RandomForest/RandomForestRegressionSolution.cs	(revision 6610)
+++ /branches/QAPAlgorithms/HeuristicLab.Algorithms.DataAnalysis/3.4/RandomForest/RandomForestRegressionSolution.cs	(revision 6611)
@@ -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 RandomForestRegressionSolution(IRegressionProblemData problemData, IRandomForestModel randomForestModel)
       : base(randomForestModel, problemData) {
+      RecalculateResults();
     }
 
Index: /branches/QAPAlgorithms/HeuristicLab.Algorithms.DataAnalysis/3.4/RegressionWorkbench.cs
===================================================================
--- /branches/QAPAlgorithms/HeuristicLab.Algorithms.DataAnalysis/3.4/RegressionWorkbench.cs	(revision 6611)
+++ /branches/QAPAlgorithms/HeuristicLab.Algorithms.DataAnalysis/3.4/RegressionWorkbench.cs	(revision 6611)
@@ -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/QAPAlgorithms/HeuristicLab.Algorithms.DataAnalysis/3.4/SupportVectorMachine/SupportVectorClassificationSolution.cs
===================================================================
--- /branches/QAPAlgorithms/HeuristicLab.Algorithms.DataAnalysis/3.4/SupportVectorMachine/SupportVectorClassificationSolution.cs	(revision 6610)
+++ /branches/QAPAlgorithms/HeuristicLab.Algorithms.DataAnalysis/3.4/SupportVectorMachine/SupportVectorClassificationSolution.cs	(revision 6611)
@@ -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/QAPAlgorithms/HeuristicLab.Algorithms.DataAnalysis/3.4/SupportVectorMachine/SupportVectorMachineModel.cs
===================================================================
--- /branches/QAPAlgorithms/HeuristicLab.Algorithms.DataAnalysis/3.4/SupportVectorMachine/SupportVectorMachineModel.cs	(revision 6610)
+++ /branches/QAPAlgorithms/HeuristicLab.Algorithms.DataAnalysis/3.4/SupportVectorMachine/SupportVectorMachineModel.cs	(revision 6611)
@@ -126,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) {
@@ -147,4 +154,11 @@
       }
     }
+
+    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
Index: /branches/QAPAlgorithms/HeuristicLab.Algorithms.DataAnalysis/3.4/SupportVectorMachine/SupportVectorRegressionSolution.cs
===================================================================
--- /branches/QAPAlgorithms/HeuristicLab.Algorithms.DataAnalysis/3.4/SupportVectorMachine/SupportVectorRegressionSolution.cs	(revision 6610)
+++ /branches/QAPAlgorithms/HeuristicLab.Algorithms.DataAnalysis/3.4/SupportVectorMachine/SupportVectorRegressionSolution.cs	(revision 6611)
@@ -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/QAPAlgorithms/HeuristicLab.Operators.Views.GraphVisualization/3.3/OperatorGraphVisualization/OperatorGraphVisualizationInfo.cs
===================================================================
--- /branches/QAPAlgorithms/HeuristicLab.Operators.Views.GraphVisualization/3.3/OperatorGraphVisualization/OperatorGraphVisualizationInfo.cs	(revision 6610)
+++ /branches/QAPAlgorithms/HeuristicLab.Operators.Views.GraphVisualization/3.3/OperatorGraphVisualization/OperatorGraphVisualizationInfo.cs	(revision 6611)
@@ -65,5 +65,5 @@
         IOperatorShapeInfo shapeInfo = cloner.Clone(pair.Value);
         RegisterOperatorEvents(op);
-        operatorParameterCollectionMapping.Add(op, pair.Key.Parameters);
+        operatorParameterCollectionMapping.Add(op, op.Parameters);
         operatorShapeInfoMapping.Add(op, shapeInfo);
       }
Index: /branches/QAPAlgorithms/HeuristicLab.Optimization.Views/3.3/ExperimentTreeView.Designer.cs
===================================================================
--- /branches/QAPAlgorithms/HeuristicLab.Optimization.Views/3.3/ExperimentTreeView.Designer.cs	(revision 6610)
+++ /branches/QAPAlgorithms/HeuristicLab.Optimization.Views/3.3/ExperimentTreeView.Designer.cs	(revision 6611)
@@ -171,4 +171,5 @@
       this.treeView.AfterLabelEdit += new System.Windows.Forms.NodeLabelEditEventHandler(treeView_AfterLabelEdit);
       this.treeView.BeforeLabelEdit += new System.Windows.Forms.NodeLabelEditEventHandler(treeView_BeforeLabelEdit);
+      this.treeView.AfterSelect += new System.Windows.Forms.TreeViewEventHandler(treeView_AfterSelect);
       this.treeView.ItemDrag += new System.Windows.Forms.ItemDragEventHandler(this.optimizerTreeView_ItemDrag);
       this.treeView.NodeMouseClick += new System.Windows.Forms.TreeNodeMouseClickEventHandler(this.treeview_NodeMouseClick);
Index: /branches/QAPAlgorithms/HeuristicLab.Optimization.Views/3.3/ExperimentTreeView.cs
===================================================================
--- /branches/QAPAlgorithms/HeuristicLab.Optimization.Views/3.3/ExperimentTreeView.cs	(revision 6610)
+++ /branches/QAPAlgorithms/HeuristicLab.Optimization.Views/3.3/ExperimentTreeView.cs	(revision 6611)
@@ -265,20 +265,11 @@
 
       foreach (TreeNodeCollection parentNode in parentNodes) {
-        //get all effected child nodes
-        foreach (TreeNode childNode in parentNode.OfType<TreeNode>()
-          .Where(n => e.OldItems.Select(x => x.Value).Contains((IOptimizer)n.Tag)).ToList()) {
-          DisposeTreeNode(childNode);
-          childNode.Remove();
-        }
-
-        foreach (var childOptimizer in e.Items) {
-          TreeNode childNode = CreateTreeNode(childOptimizer.Value);
-          UpdateChildTreeNodes(childNode.Nodes, childOptimizer.Value);
-          childNode.ExpandAll();
-          parentNode.Insert(childOptimizer.Index, childNode);
-        }
-      }
-      RebuildImageList();
-      UpdateDetailsViewHost();
+        var backup = parentNode.OfType<TreeNode>().ToList();
+        foreach (var indexedItem in e.Items) {
+          var node = backup.Where(n => n.Tag == indexedItem.Value).First();
+          node.Remove();
+          parentNode.Insert(indexedItem.Index, node);
+        }
+      }
     }
     private void Optimizers_ItemsRemoved(object sender, CollectionItemsChangedEventArgs<IndexedItem<IOptimizer>> e) {
@@ -640,4 +631,13 @@
     }
 
+
+    private void treeView_AfterSelect(object sender, TreeViewEventArgs e) {
+      if (e.Action == TreeViewAction.ByKeyboard) {
+        UpdateDetailsViewHost();
+        //NOTE: necessary because algorithm view steals the focus
+        treeView.Focus();
+      }
+    }
+
     private bool rightClickOccured = true;
     private TreeNode toolStripMenuNode = null;
@@ -736,10 +736,9 @@
       else experiment = (Experiment)treeView.SelectedNode.Parent.Tag;
 
+      var selectedNode = treeView.SelectedNode;
       int index = treeView.SelectedNode.Index;
       experiment.Optimizers.Reverse(index - 1, 2);
-      treeView.SelectedNode = treeNodeTagMapping[optimizer].First();
+      treeView.SelectedNode = selectedNode;
       SetEnabledStateOfControls();
-      UpdateDetailsViewHost();
-      RebuildImageList();
     }
     private void moveDownButton_Click(object sender, EventArgs e) {
@@ -749,10 +748,9 @@
       else experiment = (Experiment)treeView.SelectedNode.Parent.Tag;
 
+      var selectedNode = treeView.SelectedNode;
       int index = treeView.SelectedNode.Index;
       experiment.Optimizers.Reverse(index, 2);
-      treeView.SelectedNode = treeNodeTagMapping[optimizer].First();
+      treeView.SelectedNode = selectedNode;
       SetEnabledStateOfControls();
-      UpdateDetailsViewHost();
-      RebuildImageList();
     }
 
@@ -885,4 +883,5 @@
       var topLevelNodes = treeView.Nodes.OfType<TreeNode>().ToArray();
       var nodes = IterateTreeNodes().ToList();
+      var selectedNode = treeView.SelectedNode;
       treeView.Nodes.Clear();
 
@@ -894,4 +893,5 @@
       }
       treeView.Nodes.AddRange(topLevelNodes);
+      treeView.SelectedNode = selectedNode;
       treeView.EndUpdate();
     }
Index: /branches/QAPAlgorithms/HeuristicLab.Optimization.Views/3.3/ResultCollectionView.cs
===================================================================
--- /branches/QAPAlgorithms/HeuristicLab.Optimization.Views/3.3/ResultCollectionView.cs	(revision 6610)
+++ /branches/QAPAlgorithms/HeuristicLab.Optimization.Views/3.3/ResultCollectionView.cs	(revision 6611)
@@ -34,7 +34,5 @@
       set { /*not needed because results are always readonly */}
     }
-    /// <summary>
-    /// Initializes a new instance of <see cref="VariablesScopeView"/> with caption "Variables Scope View".
-    /// </summary>
+
     public ResultCollectionView() {
       InitializeComponent();
Index: /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis.Symbolic.Classification/3.4/SymbolicClassificationModel.cs
===================================================================
--- /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis.Symbolic.Classification/3.4/SymbolicClassificationModel.cs	(revision 6610)
+++ /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis.Symbolic.Classification/3.4/SymbolicClassificationModel.cs	(revision 6611)
@@ -21,14 +21,8 @@
 
 using System.Collections.Generic;
-using System.Linq;
 using HeuristicLab.Common;
 using HeuristicLab.Core;
-using HeuristicLab.Data;
 using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
-using HeuristicLab.Operators;
-using HeuristicLab.Parameters;
 using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
-using HeuristicLab.Optimization;
-using System;
 
 namespace HeuristicLab.Problems.DataAnalysis.Symbolic.Classification {
@@ -55,4 +49,13 @@
       return Interpreter.GetSymbolicExpressionTreeValues(SymbolicExpressionTree, dataset, rows);
     }
+
+    public ISymbolicClassificationSolution CreateClassificationSolution(IClassificationProblemData problemData) {
+      return new SymbolicClassificationSolution(this, problemData);
+    }
+    IClassificationSolution IClassificationModel.CreateClassificationSolution(IClassificationProblemData problemData) {
+      return CreateClassificationSolution(problemData);
+    }
+
+
   }
 }
Index: /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis.Symbolic.Classification/3.4/SymbolicClassificationSolution.cs
===================================================================
--- /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis.Symbolic.Classification/3.4/SymbolicClassificationSolution.cs	(revision 6610)
+++ /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis.Symbolic.Classification/3.4/SymbolicClassificationSolution.cs	(revision 6611)
@@ -63,5 +63,5 @@
       Add(new Result(ModelLengthResultName, "Length of the symbolic classification model.", new IntValue()));
       Add(new Result(ModelDepthResultName, "Depth of the symbolic classification model.", new IntValue()));
-      CalculateResults();
+      RecalculateResults();
     }
 
@@ -71,11 +71,7 @@
 
     protected override void RecalculateResults() {
-      base.RecalculateResults();
-      CalculateResults();
-    }
-
-    private void CalculateResults() {
       ModelLength = Model.SymbolicExpressionTree.Length;
       ModelDepth = Model.SymbolicExpressionTree.Depth;
+      CalculateResults();
     }
   }
Index: /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis.Symbolic.Classification/3.4/SymbolicDiscriminantFunctionClassificationModel.cs
===================================================================
--- /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis.Symbolic.Classification/3.4/SymbolicDiscriminantFunctionClassificationModel.cs	(revision 6610)
+++ /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis.Symbolic.Classification/3.4/SymbolicDiscriminantFunctionClassificationModel.cs	(revision 6611)
@@ -104,4 +104,14 @@
     }
 
+    public SymbolicDiscriminantFunctionClassificationSolution CreateClassificationSolution(IClassificationProblemData problemData) {
+      return new SymbolicDiscriminantFunctionClassificationSolution(this, problemData);
+    }
+    IClassificationSolution IClassificationModel.CreateClassificationSolution(IClassificationProblemData problemData) {
+      return CreateClassificationSolution(problemData);
+    }
+    IDiscriminantFunctionClassificationSolution IDiscriminantFunctionClassificationModel.CreateDiscriminantFunctionClassificationSolution(IClassificationProblemData problemData) {
+      return CreateClassificationSolution(problemData);
+    }
+
     #region events
     public event EventHandler ThresholdsChanged;
Index: /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis.Symbolic.Classification/3.4/SymbolicDiscriminantFunctionClassificationSolution.cs
===================================================================
--- /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis.Symbolic.Classification/3.4/SymbolicDiscriminantFunctionClassificationSolution.cs	(revision 6610)
+++ /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis.Symbolic.Classification/3.4/SymbolicDiscriminantFunctionClassificationSolution.cs	(revision 6611)
@@ -66,5 +66,5 @@
       Add(new Result(ModelLengthResultName, "Length of the symbolic classification model.", new IntValue()));
       Add(new Result(ModelDepthResultName, "Depth of the symbolic classification model.", new IntValue()));
-      CalculateResults();
+      RecalculateResults();
     }
 
@@ -74,12 +74,10 @@
 
     protected override void RecalculateResults() {
-      base.RecalculateResults();
       CalculateResults();
-    }
-
-    private void CalculateResults() {
+      CalculateRegressionResults();
       ModelLength = Model.SymbolicExpressionTree.Length;
       ModelDepth = Model.SymbolicExpressionTree.Depth;
     }
+
   }
 }
Index: /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis.Symbolic.Regression/3.4/SymbolicRegressionModel.cs
===================================================================
--- /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis.Symbolic.Regression/3.4/SymbolicRegressionModel.cs	(revision 6610)
+++ /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis.Symbolic.Regression/3.4/SymbolicRegressionModel.cs	(revision 6611)
@@ -59,4 +59,11 @@
       return Interpreter.GetSymbolicExpressionTreeValues(SymbolicExpressionTree, dataset, rows)
         .LimitToRange(lowerEstimationLimit, upperEstimationLimit);
+    }
+
+    public ISymbolicRegressionSolution CreateRegressionSolution(IRegressionProblemData problemData) {
+      return new SymbolicRegressionSolution(this, problemData);
+    }
+    IRegressionSolution IRegressionModel.CreateRegressionSolution(IRegressionProblemData problemData) {
+      return CreateRegressionSolution(problemData);
     }
 
Index: /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis.Symbolic.Regression/3.4/SymbolicRegressionSolution.cs
===================================================================
--- /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis.Symbolic.Regression/3.4/SymbolicRegressionSolution.cs	(revision 6610)
+++ /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis.Symbolic.Regression/3.4/SymbolicRegressionSolution.cs	(revision 6611)
@@ -62,5 +62,5 @@
       Add(new Result(ModelLengthResultName, "Length of the symbolic regression model.", new IntValue()));
       Add(new Result(ModelDepthResultName, "Depth of the symbolic regression model.", new IntValue()));
-      CalculateResults();
+      RecalculateResults();
     }
 
@@ -71,8 +71,4 @@
     protected override void RecalculateResults() {
       base.RecalculateResults();
-      CalculateResults();
-    }
-
-    private void CalculateResults() {
       ModelLength = Model.SymbolicExpressionTree.Length;
       ModelDepth = Model.SymbolicExpressionTree.Depth;
Index: /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis.Symbolic.Views/3.4/Symbols/VariableView.cs
===================================================================
--- /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis.Symbolic.Views/3.4/Symbols/VariableView.cs	(revision 6610)
+++ /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis.Symbolic.Views/3.4/Symbols/VariableView.cs	(revision 6611)
@@ -58,5 +58,9 @@
       variableNamesView.Content.CheckedItemsChanged += new CollectionItemsChangedEventHandler<StringValue>(variableNames_Changed);
       variableNamesView.Content.CollectionReset += new CollectionItemsChangedEventHandler<StringValue>(variableNames_Changed);
-    }
+      foreach (var variable in variableNamesView.Content) {
+        variable.ValueChanged += new EventHandler(variable_ValueChanged);
+      }
+    }
+
 
     private void DeregisterVariableNamesViewContentEvents() {
@@ -65,4 +69,7 @@
       variableNamesView.Content.CheckedItemsChanged -= new CollectionItemsChangedEventHandler<StringValue>(variableNames_Changed);
       variableNamesView.Content.CollectionReset -= new CollectionItemsChangedEventHandler<StringValue>(variableNames_Changed);
+      foreach (var variable in variableNamesView.Content) {
+        variable.ValueChanged -= new EventHandler(variable_ValueChanged);
+      }
     }
 
@@ -104,4 +111,18 @@
     #region control event handlers
     private void variableNames_Changed(object sender, CollectionItemsChangedEventArgs<StringValue> args) {
+      if (args.Items != null)
+        foreach (var newVar in args.Items)
+          newVar.ValueChanged += new EventHandler(variable_ValueChanged);
+      if (args.OldItems != null)
+        foreach (var oldVar in args.OldItems)
+          oldVar.ValueChanged -= new EventHandler(variable_ValueChanged);
+      UpdateContent();
+    }
+
+    private void variable_ValueChanged(object sender, EventArgs e) {
+      UpdateContent();
+    }
+
+    private void UpdateContent() {
       if (Content != null) {
         Content.Changed -= new EventHandler(Content_Changed);
@@ -110,4 +131,5 @@
       }
     }
+
 
     private void weightMuTextBox_TextChanged(object sender, EventArgs e) {
Index: anches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis.Views/3.4/ClassificationSolutionView.Designer.cs
===================================================================
--- /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis.Views/3.4/ClassificationSolutionView.Designer.cs	(revision 6610)
+++ 	(revision )
@@ -1,53 +1,0 @@
-﻿#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
-
-namespace HeuristicLab.Problems.DataAnalysis.Views {
-  partial class ClassificationSolutionView {
-    /// <summary> 
-    /// Required designer variable.
-    /// </summary>
-    private System.ComponentModel.IContainer components = null;
-
-    /// <summary> 
-    /// Clean up any resources being used.
-    /// </summary>
-    /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
-    protected override void Dispose(bool disposing) {
-      if (disposing && (components != null)) {
-        components.Dispose();
-      }
-      base.Dispose(disposing);
-    }
-
-    #region Component Designer generated code
-
-    /// <summary> 
-    /// Required method for Designer support - do not modify 
-    /// the contents of this method with the code editor.
-    /// </summary>
-    private void InitializeComponent() {
-      components = new System.ComponentModel.Container();
-      this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
-    }
-
-    #endregion
-  }
-}
Index: anches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis.Views/3.4/ClassificationSolutionView.cs
===================================================================
--- /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis.Views/3.4/ClassificationSolutionView.cs	(revision 6610)
+++ 	(revision )
@@ -1,44 +1,0 @@
-﻿#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.Windows.Forms;
-using HeuristicLab.MainForm;
-using HeuristicLab.PluginInfrastructure;
-
-namespace HeuristicLab.Problems.DataAnalysis.Views {
-  [View("ClassificationSolution View")]
-  [Content(typeof(ClassificationSolution), true)]
-  public partial class ClassificationSolutionView : DataAnalysisSolutionView {
-    public ClassificationSolutionView() {
-      InitializeComponent();
-
-      var classificationSolutionEvaluationViewTypes = ApplicationManager.Manager.GetTypes(typeof(IClassificationSolutionEvaluationView), true);
-      foreach (Type viewType in classificationSolutionEvaluationViewTypes)
-        AddViewListViewItem(viewType);
-    }
-
-    public new ClassificationSolution Content {
-      get { return (ClassificationSolution)base.Content; }
-      set { base.Content = value; }
-    }
-  }
-}
Index: anches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis.Views/3.4/ClusteringSolutionView.Designer.cs
===================================================================
--- /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis.Views/3.4/ClusteringSolutionView.Designer.cs	(revision 6610)
+++ 	(revision )
@@ -1,87 +1,0 @@
-﻿#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
-
-namespace HeuristicLab.Problems.DataAnalysis.Views {
-  partial class ClusteringSolutionView {
-    /// <summary> 
-    /// Required designer variable.
-    /// </summary>
-    private System.ComponentModel.IContainer components = null;
-
-    /// <summary> 
-    /// Clean up any resources being used.
-    /// </summary>
-    /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
-    protected override void Dispose(bool disposing) {
-      if (disposing && (components != null)) {
-        components.Dispose();
-      }
-      base.Dispose(disposing);
-    }
-
-    #region Component Designer generated code
-
-    /// <summary> 
-    /// Required method for Designer support - do not modify 
-    /// the contents of this method with the code editor.
-    /// </summary>
-    private void InitializeComponent() {
-      ((System.ComponentModel.ISupportInitialize)(this.splitContainer)).BeginInit();
-      this.splitContainer.Panel1.SuspendLayout();
-      this.splitContainer.Panel2.SuspendLayout();
-      this.splitContainer.SuspendLayout();
-      this.itemsGroupBox.SuspendLayout();
-      this.detailsGroupBox.SuspendLayout();
-      this.SuspendLayout();
-      // 
-      // splitContainer
-      // 
-      // 
-      // itemsGroupBox
-      // 
-      this.itemsGroupBox.Text = "Regression Solution";
-      // 
-      // addButton
-      // 
-      this.toolTip.SetToolTip(this.addButton, "Add");
-      // 
-      // removeButton
-      // 
-      this.toolTip.SetToolTip(this.removeButton, "Remove");
-      // 
-      // RegressionSolutionView
-      // 
-      this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
-      this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
-      this.Name = "RegressionSolutionView";
-      this.splitContainer.Panel1.ResumeLayout(false);
-      this.splitContainer.Panel2.ResumeLayout(false);
-      ((System.ComponentModel.ISupportInitialize)(this.splitContainer)).EndInit();
-      this.splitContainer.ResumeLayout(false);
-      this.itemsGroupBox.ResumeLayout(false);
-      this.detailsGroupBox.ResumeLayout(false);
-      this.ResumeLayout(false);
-
-    }
-
-    #endregion
-  }
-}
Index: anches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis.Views/3.4/ClusteringSolutionView.cs
===================================================================
--- /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis.Views/3.4/ClusteringSolutionView.cs	(revision 6610)
+++ 	(revision )
@@ -1,44 +1,0 @@
-﻿#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.Windows.Forms;
-using HeuristicLab.MainForm;
-using HeuristicLab.PluginInfrastructure;
-
-namespace HeuristicLab.Problems.DataAnalysis.Views {
-  [View("ClusteringSolution View")]
-  [Content(typeof(ClusteringSolution), true)]
-  public partial class ClusteringSolutionView : DataAnalysisSolutionView {
-    public ClusteringSolutionView() {
-      InitializeComponent();
-
-      var clusteringSolutionEvaluationViewTypes = ApplicationManager.Manager.GetTypes(typeof(IClusteringSolutionEvaluationView), true);
-      foreach (Type viewType in clusteringSolutionEvaluationViewTypes)
-        AddViewListViewItem(viewType);
-    }
-
-    public new ClusteringSolution Content {
-      get { return (ClusteringSolution)base.Content; }
-      set { base.Content = value; }
-    }
-  }
-}
Index: anches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis.Views/3.4/DataAnalysisSolutionView.Designer.cs
===================================================================
--- /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis.Views/3.4/DataAnalysisSolutionView.Designer.cs	(revision 6610)
+++ 	(revision )
@@ -1,87 +1,0 @@
-#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
-namespace HeuristicLab.Problems.DataAnalysis.Views {
-  partial class DataAnalysisSolutionView {
-    /// <summary> 
-    /// Required designer variable.
-    /// </summary>
-    private System.ComponentModel.IContainer components = null;
-
-    /// <summary> 
-    /// Clean up any resources being used.
-    /// </summary>
-    /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
-    protected override void Dispose(bool disposing) {
-      if (disposing && (components != null)) {
-        components.Dispose();
-      }
-      base.Dispose(disposing);
-    }
-
-    #region Component Designer generated code
-
-    /// <summary> 
-    /// Required method for Designer support - do not modify 
-    /// the contents of this method with the code editor.
-    /// </summary>
-    private void InitializeComponent() {
-      ((System.ComponentModel.ISupportInitialize)(this.splitContainer)).BeginInit();
-      this.splitContainer.Panel1.SuspendLayout();
-      this.splitContainer.Panel2.SuspendLayout();
-      this.splitContainer.SuspendLayout();
-      this.itemsGroupBox.SuspendLayout();
-      this.detailsGroupBox.SuspendLayout();
-      this.SuspendLayout();
-      // 
-      // splitContainer
-      // 
-      // 
-      // itemsGroupBox
-      // 
-      this.itemsGroupBox.Text = "Data Analysis Solution";
-      // 
-      // addButton
-      // 
-      this.toolTip.SetToolTip(this.addButton, "Add");
-      // 
-      // removeButton
-      // 
-      this.toolTip.SetToolTip(this.removeButton, "Remove");
-      // 
-      // DataAnalysisSolutionView
-      // 
-      this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
-      this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
-      this.Name = "DataAnalysisSolutionView";
-      this.splitContainer.Panel1.ResumeLayout(false);
-      this.splitContainer.Panel2.ResumeLayout(false);
-      ((System.ComponentModel.ISupportInitialize)(this.splitContainer)).EndInit();
-      this.splitContainer.ResumeLayout(false);
-      this.itemsGroupBox.ResumeLayout(false);
-      this.detailsGroupBox.ResumeLayout(false);
-      this.ResumeLayout(false);
-
-    }
-
-    #endregion
-
-  }
-}
Index: anches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis.Views/3.4/DataAnalysisSolutionView.cs
===================================================================
--- /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis.Views/3.4/DataAnalysisSolutionView.cs	(revision 6610)
+++ 	(revision )
@@ -1,111 +1,0 @@
-#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.Windows.Forms;
-using HeuristicLab.Common.Resources;
-using HeuristicLab.MainForm;
-using HeuristicLab.Optimization.Views;
-
-namespace HeuristicLab.Problems.DataAnalysis.Views {
-  [View("DataAnalysisSolution View")]
-  [Content(typeof(DataAnalysisSolution), true)]
-  public partial class DataAnalysisSolutionView : ResultCollectionView {
-    public DataAnalysisSolutionView() {
-      InitializeComponent();
-    }
-
-    public new DataAnalysisSolution Content {
-      get { return (DataAnalysisSolution)base.Content; }
-      set { base.Content = value; }
-    }
-
-    protected override void OnContentChanged() {
-      string selectedName = null;
-      if ((itemsListView.SelectedItems.Count == 1) && (itemsListView.SelectedItems[0].Tag != null && itemsListView.SelectedItems[0].Tag is Type))
-        selectedName = itemsListView.SelectedItems[0].Text;
-
-      //cache old viewTypes;
-      var viewTypes = new List<Type>();
-      foreach (ListViewItem item in ItemsListView.Items) {
-        var viewType = item.Tag as Type;
-        if (viewType != null) viewTypes.Add(viewType);
-      }
-
-      base.OnContentChanged();
-
-      //readd viewTypes
-      foreach (Type viewType in viewTypes)
-        AddViewListViewItem(viewType);
-
-      //recover selection
-      if (selectedName != null) {
-        foreach (ListViewItem item in itemsListView.Items) {
-          if (item.Tag != null && item.Tag is Type && item.Text == selectedName)
-            item.Selected = true;
-        }
-      }
-    }
-
-    protected override void itemsListView_DoubleClick(object sender, EventArgs e) {
-      if (itemsListView.SelectedItems.Count == 1 && itemsListView.SelectedItems[0].Tag is Type) {
-        Type viewType = (Type)itemsListView.SelectedItems[0].Tag;
-        MainFormManager.MainForm.ShowContent(Content, viewType);
-      } else
-        base.itemsListView_DoubleClick(sender, e);
-    }
-
-    protected override void itemsListView_SelectedIndexChanged(object sender, EventArgs e) {
-      if (itemsListView.SelectedItems.Count == 1 && itemsListView.SelectedItems[0].Tag is Type) {
-        detailsGroupBox.Enabled = true;
-        Type viewType = (Type)itemsListView.SelectedItems[0].Tag;
-        viewHost.ViewType = viewType;
-        viewHost.Content = Content;
-      } else
-        base.itemsListView_SelectedIndexChanged(sender, e);
-    }
-
-    protected void AddViewListViewItem(Type viewType) {
-      if (!typeof(IDataAnalysisSolutionEvaluationView).IsAssignableFrom(viewType))
-        throw new ArgumentException("Given type " + viewType + " is not a IDataAnalysisSolutionEvaluationView.");
-
-      ListViewItem listViewItem = new ListViewItem();
-      listViewItem.Text = ViewAttribute.GetViewName(viewType);
-      itemsListView.SmallImageList.Images.Add(VSImageLibrary.Graph);
-      listViewItem.ImageIndex = itemsListView.SmallImageList.Images.Count - 1;
-      listViewItem.Tag = viewType;
-      itemsListView.Items.Add(listViewItem);
-
-      AdjustListViewColumnSizes();
-    }
-
-    protected void RemoveViewListViewItem(Type viewType) {
-      List<ListViewItem> itemsToRemove = new List<ListViewItem>(); ;
-      foreach (ListViewItem item in itemsListView.Items)
-        if (item.Tag as Type == typeof(ClassificationSolutionEstimatedClassValuesView))
-          itemsToRemove.Add(item);
-
-      foreach (ListViewItem item in itemsToRemove)
-        itemsListView.Items.Remove(item);
-    }
-  }
-}
Index: anches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis.Views/3.4/DiscriminantFunctionClassificationSolutionView.Designer.cs
===================================================================
--- /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis.Views/3.4/DiscriminantFunctionClassificationSolutionView.Designer.cs	(revision 6610)
+++ 	(revision )
@@ -1,53 +1,0 @@
-﻿#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
-
-namespace HeuristicLab.Problems.DataAnalysis.Views {
-  partial class DiscriminantFunctionClassificationSolutionView {
-    /// <summary> 
-    /// Required designer variable.
-    /// </summary>
-    private System.ComponentModel.IContainer components = null;
-
-    /// <summary> 
-    /// Clean up any resources being used.
-    /// </summary>
-    /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
-    protected override void Dispose(bool disposing) {
-      if (disposing && (components != null)) {
-        components.Dispose();
-      }
-      base.Dispose(disposing);
-    }
-
-    #region Component Designer generated code
-
-    /// <summary> 
-    /// Required method for Designer support - do not modify 
-    /// the contents of this method with the code editor.
-    /// </summary>
-    private void InitializeComponent() {
-      components = new System.ComponentModel.Container();
-      this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
-    }
-
-    #endregion
-  }
-}
Index: anches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis.Views/3.4/DiscriminantFunctionClassificationSolutionView.cs
===================================================================
--- /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis.Views/3.4/DiscriminantFunctionClassificationSolutionView.cs	(revision 6610)
+++ 	(revision )
@@ -1,46 +1,0 @@
-﻿#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.Windows.Forms;
-using HeuristicLab.MainForm;
-using HeuristicLab.PluginInfrastructure;
-
-namespace HeuristicLab.Problems.DataAnalysis.Views {
-  [View("DiscriminantFunctionClassificationSolution View")]
-  [Content(typeof(DiscriminantFunctionClassificationSolution), true)]
-  public partial class DiscriminantFunctionClassificationSolutionView : ClassificationSolutionView {
-    public DiscriminantFunctionClassificationSolutionView() {
-      InitializeComponent();
-
-      var regressionSolutionEvaluationViewTypes = ApplicationManager.Manager.GetTypes(typeof(IDiscriminantFunctionClassificationSolutionEvaluationView), true);
-      foreach (Type viewType in regressionSolutionEvaluationViewTypes)
-        AddViewListViewItem(viewType);
-
-      RemoveViewListViewItem(typeof(ClassificationSolutionEstimatedClassValuesView));
-    }
-
-    public new DiscriminantFunctionClassificationSolution Content {
-      get { return (DiscriminantFunctionClassificationSolution)base.Content; }
-      set { base.Content = value; }
-    }
-  }
-}
Index: /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis.Views/3.4/HeuristicLab.Problems.DataAnalysis.Views-3.4.csproj
===================================================================
--- /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis.Views/3.4/HeuristicLab.Problems.DataAnalysis.Views-3.4.csproj	(revision 6610)
+++ /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis.Views/3.4/HeuristicLab.Problems.DataAnalysis.Views-3.4.csproj	(revision 6611)
@@ -110,8 +110,8 @@
   </ItemGroup>
   <ItemGroup>
-    <Compile Include="ClassificationSolutionView.cs">
-      <SubType>UserControl</SubType>
-    </Compile>
-    <Compile Include="ClassificationSolutionView.Designer.cs">
+    <Compile Include="Solution Views\ClassificationSolutionView.cs">
+      <SubType>UserControl</SubType>
+    </Compile>
+    <Compile Include="Solution Views\ClassificationSolutionView.Designer.cs">
       <DependentUpon>ClassificationSolutionView.cs</DependentUpon>
     </Compile>
@@ -152,14 +152,14 @@
       <DependentUpon>ClusteringSolutionEstimatedClusterView.cs</DependentUpon>
     </Compile>
-    <Compile Include="ClusteringSolutionView.cs">
-      <SubType>UserControl</SubType>
-    </Compile>
-    <Compile Include="ClusteringSolutionView.Designer.cs">
+    <Compile Include="Solution Views\ClusteringSolutionView.cs">
+      <SubType>UserControl</SubType>
+    </Compile>
+    <Compile Include="Solution Views\ClusteringSolutionView.Designer.cs">
       <DependentUpon>ClusteringSolutionView.cs</DependentUpon>
     </Compile>
-    <Compile Include="DiscriminantFunctionClassificationSolutionView.cs">
-      <SubType>UserControl</SubType>
-    </Compile>
-    <Compile Include="DiscriminantFunctionClassificationSolutionView.Designer.cs">
+    <Compile Include="Solution Views\DiscriminantFunctionClassificationSolutionView.cs">
+      <SubType>UserControl</SubType>
+    </Compile>
+    <Compile Include="Solution Views\DiscriminantFunctionClassificationSolutionView.Designer.cs">
       <DependentUpon>DiscriminantFunctionClassificationSolutionView.cs</DependentUpon>
     </Compile>
@@ -168,8 +168,8 @@
     <Compile Include="Interfaces\IClusteringSolutionEvaluationView.cs" />
     <Compile Include="Interfaces\IClassificationSolutionEvaluationView.cs" />
-    <Compile Include="DataAnalysisSolutionView.cs">
-      <SubType>UserControl</SubType>
-    </Compile>
-    <Compile Include="DataAnalysisSolutionView.Designer.cs">
+    <Compile Include="Solution Views\DataAnalysisSolutionView.cs">
+      <SubType>UserControl</SubType>
+    </Compile>
+    <Compile Include="Solution Views\DataAnalysisSolutionView.Designer.cs">
       <DependentUpon>DataAnalysisSolutionView.cs</DependentUpon>
     </Compile>
@@ -182,8 +182,8 @@
     <Compile Include="Interfaces\IRegressionSolutionEvaluationView.cs" />
     <Compile Include="MenuItems\CreateEnsembleMenuItem.cs" />
-    <Compile Include="RegressionSolutionView.cs">
-      <SubType>UserControl</SubType>
-    </Compile>
-    <Compile Include="RegressionSolutionView.Designer.cs">
+    <Compile Include="Solution Views\RegressionSolutionView.cs">
+      <SubType>UserControl</SubType>
+    </Compile>
+    <Compile Include="Solution Views\RegressionSolutionView.Designer.cs">
       <DependentUpon>RegressionSolutionView.cs</DependentUpon>
     </Compile>
Index: /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis.Views/3.4/MenuItems/CreateEnsembleMenuItem.cs
===================================================================
--- /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis.Views/3.4/MenuItems/CreateEnsembleMenuItem.cs	(revision 6610)
+++ /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis.Views/3.4/MenuItems/CreateEnsembleMenuItem.cs	(revision 6611)
@@ -62,5 +62,5 @@
         var optimizer = activeView.Content as IOptimizer;
         var solutionGroups = from pair in GetDataAnalysisResults(optimizer)
-                             group pair.Value by new { pair.Key } into g
+                             group pair.Value by pair.Key into g
                              select g;
         foreach (var group in solutionGroups) {
@@ -75,5 +75,5 @@
             var ensemble = new RegressionEnsembleSolution(Enumerable.Empty<IRegressionModel>(), problemData);
             ensemble.Name = group.Key + " ensemble";
-            ensemble.AddModelsAndParitions(group.OfType<IRegressionSolution>());
+            ensemble.AddModelsAndPartitions(group.OfType<IRegressionSolution>());
             MainFormManager.MainForm.ShowContent(ensemble);
           } else if (group.All(s => s is IClassificationSolution)) {
@@ -85,5 +85,5 @@
             var ensemble = new ClassificationEnsembleSolution(Enumerable.Empty<IClassificationModel>(), problemData);
             ensemble.Name = group.Key + " ensemble";
-            ensemble.AddModelsAndParitions(group.OfType<IClassificationSolution>());
+            ensemble.AddModelsAndPartitions(group.OfType<IClassificationSolution>());
             MainFormManager.MainForm.ShowContent(ensemble);
           }
Index: anches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis.Views/3.4/RegressionSolutionView.Designer.cs
===================================================================
--- /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis.Views/3.4/RegressionSolutionView.Designer.cs	(revision 6610)
+++ 	(revision )
@@ -1,87 +1,0 @@
-﻿#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
-
-namespace HeuristicLab.Problems.DataAnalysis.Views {
-  partial class RegressionSolutionView {
-    /// <summary> 
-    /// Required designer variable.
-    /// </summary>
-    private System.ComponentModel.IContainer components = null;
-
-    /// <summary> 
-    /// Clean up any resources being used.
-    /// </summary>
-    /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
-    protected override void Dispose(bool disposing) {
-      if (disposing && (components != null)) {
-        components.Dispose();
-      }
-      base.Dispose(disposing);
-    }
-
-    #region Component Designer generated code
-
-    /// <summary> 
-    /// Required method for Designer support - do not modify 
-    /// the contents of this method with the code editor.
-    /// </summary>
-    private void InitializeComponent() {
-      ((System.ComponentModel.ISupportInitialize)(this.splitContainer)).BeginInit();
-      this.splitContainer.Panel1.SuspendLayout();
-      this.splitContainer.Panel2.SuspendLayout();
-      this.splitContainer.SuspendLayout();
-      this.itemsGroupBox.SuspendLayout();
-      this.detailsGroupBox.SuspendLayout();
-      this.SuspendLayout();
-      // 
-      // splitContainer
-      // 
-      // 
-      // itemsGroupBox
-      // 
-      this.itemsGroupBox.Text = "Regression Solution";
-      // 
-      // addButton
-      // 
-      this.toolTip.SetToolTip(this.addButton, "Add");
-      // 
-      // removeButton
-      // 
-      this.toolTip.SetToolTip(this.removeButton, "Remove");
-      // 
-      // RegressionSolutionView
-      // 
-      this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
-      this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
-      this.Name = "RegressionSolutionView";
-      this.splitContainer.Panel1.ResumeLayout(false);
-      this.splitContainer.Panel2.ResumeLayout(false);
-      ((System.ComponentModel.ISupportInitialize)(this.splitContainer)).EndInit();
-      this.splitContainer.ResumeLayout(false);
-      this.itemsGroupBox.ResumeLayout(false);
-      this.detailsGroupBox.ResumeLayout(false);
-      this.ResumeLayout(false);
-
-    }
-
-    #endregion
-  }
-}
Index: anches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis.Views/3.4/RegressionSolutionView.cs
===================================================================
--- /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis.Views/3.4/RegressionSolutionView.cs	(revision 6610)
+++ 	(revision )
@@ -1,44 +1,0 @@
-﻿#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.Windows.Forms;
-using HeuristicLab.MainForm;
-using HeuristicLab.PluginInfrastructure;
-
-namespace HeuristicLab.Problems.DataAnalysis.Views {
-  [View("RegressionSolution View")]
-  [Content(typeof(RegressionSolution), true)]
-  public partial class RegressionSolutionView : DataAnalysisSolutionView {
-    public RegressionSolutionView() {
-      InitializeComponent();
-
-      var regressionSolutionEvaluationViewTypes = ApplicationManager.Manager.GetTypes(typeof(IRegressionSolutionEvaluationView), true);
-      foreach (Type viewType in regressionSolutionEvaluationViewTypes)
-        AddViewListViewItem(viewType);
-    }
-
-    public new RegressionSolution Content {
-      get { return (RegressionSolution)base.Content; }
-      set { base.Content = value; }
-    }
-  }
-}
Index: /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis.Views/3.4/Solution Views/ClassificationSolutionView.Designer.cs
===================================================================
--- /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis.Views/3.4/Solution Views/ClassificationSolutionView.Designer.cs	(revision 6611)
+++ /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis.Views/3.4/Solution Views/ClassificationSolutionView.Designer.cs	(revision 6611)
@@ -0,0 +1,53 @@
+﻿#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
+
+namespace HeuristicLab.Problems.DataAnalysis.Views {
+  partial class ClassificationSolutionView {
+    /// <summary> 
+    /// Required designer variable.
+    /// </summary>
+    private System.ComponentModel.IContainer components = null;
+
+    /// <summary> 
+    /// Clean up any resources being used.
+    /// </summary>
+    /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
+    protected override void Dispose(bool disposing) {
+      if (disposing && (components != null)) {
+        components.Dispose();
+      }
+      base.Dispose(disposing);
+    }
+
+    #region Component Designer generated code
+
+    /// <summary> 
+    /// Required method for Designer support - do not modify 
+    /// the contents of this method with the code editor.
+    /// </summary>
+    private void InitializeComponent() {
+      components = new System.ComponentModel.Container();
+      this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+    }
+
+    #endregion
+  }
+}
Index: /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis.Views/3.4/Solution Views/ClassificationSolutionView.cs
===================================================================
--- /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis.Views/3.4/Solution Views/ClassificationSolutionView.cs	(revision 6611)
+++ /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis.Views/3.4/Solution Views/ClassificationSolutionView.cs	(revision 6611)
@@ -0,0 +1,44 @@
+﻿#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.Windows.Forms;
+using HeuristicLab.MainForm;
+using HeuristicLab.PluginInfrastructure;
+
+namespace HeuristicLab.Problems.DataAnalysis.Views {
+  [View("ClassificationSolution View")]
+  [Content(typeof(ClassificationSolutionBase), true)]
+  public partial class ClassificationSolutionView : DataAnalysisSolutionView {
+    public ClassificationSolutionView() {
+      InitializeComponent();
+
+      var classificationSolutionEvaluationViewTypes = ApplicationManager.Manager.GetTypes(typeof(IClassificationSolutionEvaluationView), true);
+      foreach (Type viewType in classificationSolutionEvaluationViewTypes)
+        AddViewListViewItem(viewType);
+    }
+
+    public new ClassificationSolutionBase Content {
+      get { return (ClassificationSolutionBase)base.Content; }
+      set { base.Content = value; }
+    }
+  }
+}
Index: /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis.Views/3.4/Solution Views/ClusteringSolutionView.Designer.cs
===================================================================
--- /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis.Views/3.4/Solution Views/ClusteringSolutionView.Designer.cs	(revision 6611)
+++ /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis.Views/3.4/Solution Views/ClusteringSolutionView.Designer.cs	(revision 6611)
@@ -0,0 +1,86 @@
+﻿#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
+
+namespace HeuristicLab.Problems.DataAnalysis.Views {
+  partial class ClusteringSolutionView {
+    /// <summary> 
+    /// Required designer variable.
+    /// </summary>
+    private System.ComponentModel.IContainer components = null;
+
+    /// <summary> 
+    /// Clean up any resources being used.
+    /// </summary>
+    /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
+    protected override void Dispose(bool disposing) {
+      if (disposing && (components != null)) {
+        components.Dispose();
+      }
+      base.Dispose(disposing);
+    }
+
+    #region Component Designer generated code
+
+    /// <summary> 
+    /// Required method for Designer support - do not modify 
+    /// the contents of this method with the code editor.
+    /// </summary>
+    private void InitializeComponent() {
+      ((System.ComponentModel.ISupportInitialize)(this.splitContainer)).BeginInit();
+      this.splitContainer.Panel1.SuspendLayout();
+      this.splitContainer.Panel2.SuspendLayout();
+      this.splitContainer.SuspendLayout();
+      this.itemsGroupBox.SuspendLayout();
+      this.detailsGroupBox.SuspendLayout();
+      this.SuspendLayout();
+      // 
+      // splitContainer
+      // 
+      // 
+      // itemsGroupBox
+      // 
+      this.itemsGroupBox.Text = "Clustering Solution";
+      // 
+      // addButton
+      // 
+      this.toolTip.SetToolTip(this.addButton, "Add");
+      // 
+      // removeButton
+      // 
+      this.toolTip.SetToolTip(this.removeButton, "Remove");
+      // 
+      // RegressionSolutionView
+      // 
+      this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+      this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+      this.Name = "ClusteringSolutionView";
+      this.splitContainer.Panel1.ResumeLayout(false);
+      this.splitContainer.Panel2.ResumeLayout(false);
+      ((System.ComponentModel.ISupportInitialize)(this.splitContainer)).EndInit();
+      this.splitContainer.ResumeLayout(false);
+      this.itemsGroupBox.ResumeLayout(false);
+      this.detailsGroupBox.ResumeLayout(false);
+      this.ResumeLayout(false);
+    }
+
+    #endregion
+  }
+}
Index: /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis.Views/3.4/Solution Views/ClusteringSolutionView.cs
===================================================================
--- /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis.Views/3.4/Solution Views/ClusteringSolutionView.cs	(revision 6611)
+++ /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis.Views/3.4/Solution Views/ClusteringSolutionView.cs	(revision 6611)
@@ -0,0 +1,44 @@
+﻿#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.Windows.Forms;
+using HeuristicLab.MainForm;
+using HeuristicLab.PluginInfrastructure;
+
+namespace HeuristicLab.Problems.DataAnalysis.Views {
+  [View("ClusteringSolution View")]
+  [Content(typeof(ClusteringSolution), true)]
+  public partial class ClusteringSolutionView : DataAnalysisSolutionView {
+    public ClusteringSolutionView() {
+      InitializeComponent();
+
+      var clusteringSolutionEvaluationViewTypes = ApplicationManager.Manager.GetTypes(typeof(IClusteringSolutionEvaluationView), true);
+      foreach (Type viewType in clusteringSolutionEvaluationViewTypes)
+        AddViewListViewItem(viewType);
+    }
+
+    public new ClusteringSolution Content {
+      get { return (ClusteringSolution)base.Content; }
+      set { base.Content = value; }
+    }
+  }
+}
Index: /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis.Views/3.4/Solution Views/DataAnalysisSolutionView.Designer.cs
===================================================================
--- /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis.Views/3.4/Solution Views/DataAnalysisSolutionView.Designer.cs	(revision 6611)
+++ /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis.Views/3.4/Solution Views/DataAnalysisSolutionView.Designer.cs	(revision 6611)
@@ -0,0 +1,87 @@
+#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
+namespace HeuristicLab.Problems.DataAnalysis.Views {
+  partial class DataAnalysisSolutionView {
+    /// <summary> 
+    /// Required designer variable.
+    /// </summary>
+    private System.ComponentModel.IContainer components = null;
+
+    /// <summary> 
+    /// Clean up any resources being used.
+    /// </summary>
+    /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
+    protected override void Dispose(bool disposing) {
+      if (disposing && (components != null)) {
+        components.Dispose();
+      }
+      base.Dispose(disposing);
+    }
+
+    #region Component Designer generated code
+
+    /// <summary> 
+    /// Required method for Designer support - do not modify 
+    /// the contents of this method with the code editor.
+    /// </summary>
+    private void InitializeComponent() {
+      ((System.ComponentModel.ISupportInitialize)(this.splitContainer)).BeginInit();
+      this.splitContainer.Panel1.SuspendLayout();
+      this.splitContainer.Panel2.SuspendLayout();
+      this.splitContainer.SuspendLayout();
+      this.itemsGroupBox.SuspendLayout();
+      this.detailsGroupBox.SuspendLayout();
+      this.SuspendLayout();
+      // 
+      // splitContainer
+      // 
+      // 
+      // itemsGroupBox
+      // 
+      this.itemsGroupBox.Text = "Data Analysis Solution";
+      // 
+      // addButton
+      // 
+      this.toolTip.SetToolTip(this.addButton, "Add");
+      // 
+      // removeButton
+      // 
+      this.toolTip.SetToolTip(this.removeButton, "Remove");
+      // 
+      // DataAnalysisSolutionView
+      // 
+      this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+      this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+      this.Name = "DataAnalysisSolutionView";
+      this.splitContainer.Panel1.ResumeLayout(false);
+      this.splitContainer.Panel2.ResumeLayout(false);
+      ((System.ComponentModel.ISupportInitialize)(this.splitContainer)).EndInit();
+      this.splitContainer.ResumeLayout(false);
+      this.itemsGroupBox.ResumeLayout(false);
+      this.detailsGroupBox.ResumeLayout(false);
+      this.ResumeLayout(false);
+
+    }
+
+    #endregion
+
+  }
+}
Index: /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis.Views/3.4/Solution Views/DataAnalysisSolutionView.cs
===================================================================
--- /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis.Views/3.4/Solution Views/DataAnalysisSolutionView.cs	(revision 6611)
+++ /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis.Views/3.4/Solution Views/DataAnalysisSolutionView.cs	(revision 6611)
@@ -0,0 +1,111 @@
+#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.Windows.Forms;
+using HeuristicLab.Common.Resources;
+using HeuristicLab.MainForm;
+using HeuristicLab.Optimization.Views;
+
+namespace HeuristicLab.Problems.DataAnalysis.Views {
+  [View("DataAnalysisSolution View")]
+  [Content(typeof(DataAnalysisSolution), true)]
+  public partial class DataAnalysisSolutionView : ResultCollectionView {
+    public DataAnalysisSolutionView() {
+      InitializeComponent();
+    }
+
+    public new DataAnalysisSolution Content {
+      get { return (DataAnalysisSolution)base.Content; }
+      set { base.Content = value; }
+    }
+
+    protected override void OnContentChanged() {
+      string selectedName = null;
+      if ((itemsListView.SelectedItems.Count == 1) && (itemsListView.SelectedItems[0].Tag != null && itemsListView.SelectedItems[0].Tag is Type))
+        selectedName = itemsListView.SelectedItems[0].Text;
+
+      //cache old viewTypes;
+      var viewTypes = new List<Type>();
+      foreach (ListViewItem item in ItemsListView.Items) {
+        var viewType = item.Tag as Type;
+        if (viewType != null) viewTypes.Add(viewType);
+      }
+
+      base.OnContentChanged();
+
+      //readd viewTypes
+      foreach (Type viewType in viewTypes)
+        AddViewListViewItem(viewType);
+
+      //recover selection
+      if (selectedName != null) {
+        foreach (ListViewItem item in itemsListView.Items) {
+          if (item.Tag != null && item.Tag is Type && item.Text == selectedName)
+            item.Selected = true;
+        }
+      }
+    }
+
+    protected override void itemsListView_DoubleClick(object sender, EventArgs e) {
+      if (itemsListView.SelectedItems.Count == 1 && itemsListView.SelectedItems[0].Tag is Type) {
+        Type viewType = (Type)itemsListView.SelectedItems[0].Tag;
+        MainFormManager.MainForm.ShowContent(Content, viewType);
+      } else
+        base.itemsListView_DoubleClick(sender, e);
+    }
+
+    protected override void itemsListView_SelectedIndexChanged(object sender, EventArgs e) {
+      if (itemsListView.SelectedItems.Count == 1 && itemsListView.SelectedItems[0].Tag is Type) {
+        detailsGroupBox.Enabled = true;
+        Type viewType = (Type)itemsListView.SelectedItems[0].Tag;
+        viewHost.ViewType = viewType;
+        viewHost.Content = Content;
+      } else
+        base.itemsListView_SelectedIndexChanged(sender, e);
+    }
+
+    protected void AddViewListViewItem(Type viewType) {
+      if (!typeof(IDataAnalysisSolutionEvaluationView).IsAssignableFrom(viewType))
+        throw new ArgumentException("Given type " + viewType + " is not a IDataAnalysisSolutionEvaluationView.");
+
+      ListViewItem listViewItem = new ListViewItem();
+      listViewItem.Text = ViewAttribute.GetViewName(viewType);
+      itemsListView.SmallImageList.Images.Add(VSImageLibrary.Graph);
+      listViewItem.ImageIndex = itemsListView.SmallImageList.Images.Count - 1;
+      listViewItem.Tag = viewType;
+      itemsListView.Items.Add(listViewItem);
+
+      AdjustListViewColumnSizes();
+    }
+
+    protected void RemoveViewListViewItem(Type viewType) {
+      List<ListViewItem> itemsToRemove = new List<ListViewItem>(); ;
+      foreach (ListViewItem item in itemsListView.Items)
+        if (item.Tag as Type == typeof(IDataAnalysisSolutionEvaluationView))
+          itemsToRemove.Add(item);
+
+      foreach (ListViewItem item in itemsToRemove)
+        itemsListView.Items.Remove(item);
+    }
+  }
+}
Index: /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis.Views/3.4/Solution Views/DiscriminantFunctionClassificationSolutionView.Designer.cs
===================================================================
--- /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis.Views/3.4/Solution Views/DiscriminantFunctionClassificationSolutionView.Designer.cs	(revision 6611)
+++ /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis.Views/3.4/Solution Views/DiscriminantFunctionClassificationSolutionView.Designer.cs	(revision 6611)
@@ -0,0 +1,53 @@
+﻿#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
+
+namespace HeuristicLab.Problems.DataAnalysis.Views {
+  partial class DiscriminantFunctionClassificationSolutionView {
+    /// <summary> 
+    /// Required designer variable.
+    /// </summary>
+    private System.ComponentModel.IContainer components = null;
+
+    /// <summary> 
+    /// Clean up any resources being used.
+    /// </summary>
+    /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
+    protected override void Dispose(bool disposing) {
+      if (disposing && (components != null)) {
+        components.Dispose();
+      }
+      base.Dispose(disposing);
+    }
+
+    #region Component Designer generated code
+
+    /// <summary> 
+    /// Required method for Designer support - do not modify 
+    /// the contents of this method with the code editor.
+    /// </summary>
+    private void InitializeComponent() {
+      components = new System.ComponentModel.Container();
+      this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+    }
+
+    #endregion
+  }
+}
Index: /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis.Views/3.4/Solution Views/DiscriminantFunctionClassificationSolutionView.cs
===================================================================
--- /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis.Views/3.4/Solution Views/DiscriminantFunctionClassificationSolutionView.cs	(revision 6611)
+++ /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis.Views/3.4/Solution Views/DiscriminantFunctionClassificationSolutionView.cs	(revision 6611)
@@ -0,0 +1,49 @@
+﻿#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.Windows.Forms;
+using HeuristicLab.MainForm;
+using HeuristicLab.PluginInfrastructure;
+
+namespace HeuristicLab.Problems.DataAnalysis.Views {
+  [View("DiscriminantFunctionClassificationSolution View")]
+  [Content(typeof(DiscriminantFunctionClassificationSolutionBase), true)]
+  public partial class DiscriminantFunctionClassificationSolutionView : DataAnalysisSolutionView {
+    public DiscriminantFunctionClassificationSolutionView() {
+      InitializeComponent();
+
+      var classificationSolutionEvaluationViewTypes = ApplicationManager.Manager.GetTypes(typeof(IClassificationSolutionEvaluationView), true);
+      foreach (Type viewType in classificationSolutionEvaluationViewTypes)
+        AddViewListViewItem(viewType);
+      RemoveViewListViewItem(typeof(ClassificationSolutionEstimatedClassValuesView));
+
+      var regressionSolutionEvaluationViewTypes = ApplicationManager.Manager.GetTypes(typeof(IDiscriminantFunctionClassificationSolutionEvaluationView), true);
+      foreach (Type viewType in regressionSolutionEvaluationViewTypes)
+        AddViewListViewItem(viewType);
+    }
+
+    public new DiscriminantFunctionClassificationSolutionBase Content {
+      get { return (DiscriminantFunctionClassificationSolutionBase)base.Content; }
+      set { base.Content = value; }
+    }
+  }
+}
Index: /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis.Views/3.4/Solution Views/RegressionSolutionView.Designer.cs
===================================================================
--- /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis.Views/3.4/Solution Views/RegressionSolutionView.Designer.cs	(revision 6611)
+++ /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis.Views/3.4/Solution Views/RegressionSolutionView.Designer.cs	(revision 6611)
@@ -0,0 +1,87 @@
+﻿#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
+
+namespace HeuristicLab.Problems.DataAnalysis.Views {
+  partial class RegressionSolutionView {
+    /// <summary> 
+    /// Required designer variable.
+    /// </summary>
+    private System.ComponentModel.IContainer components = null;
+
+    /// <summary> 
+    /// Clean up any resources being used.
+    /// </summary>
+    /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
+    protected override void Dispose(bool disposing) {
+      if (disposing && (components != null)) {
+        components.Dispose();
+      }
+      base.Dispose(disposing);
+    }
+
+    #region Component Designer generated code
+
+    /// <summary> 
+    /// Required method for Designer support - do not modify 
+    /// the contents of this method with the code editor.
+    /// </summary>
+    private void InitializeComponent() {
+      ((System.ComponentModel.ISupportInitialize)(this.splitContainer)).BeginInit();
+      this.splitContainer.Panel1.SuspendLayout();
+      this.splitContainer.Panel2.SuspendLayout();
+      this.splitContainer.SuspendLayout();
+      this.itemsGroupBox.SuspendLayout();
+      this.detailsGroupBox.SuspendLayout();
+      this.SuspendLayout();
+      // 
+      // splitContainer
+      // 
+      // 
+      // itemsGroupBox
+      // 
+      this.itemsGroupBox.Text = "Regression Solution";
+      // 
+      // addButton
+      // 
+      this.toolTip.SetToolTip(this.addButton, "Add");
+      // 
+      // removeButton
+      // 
+      this.toolTip.SetToolTip(this.removeButton, "Remove");
+      // 
+      // RegressionSolutionView
+      // 
+      this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+      this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+      this.Name = "RegressionSolutionView";
+      this.splitContainer.Panel1.ResumeLayout(false);
+      this.splitContainer.Panel2.ResumeLayout(false);
+      ((System.ComponentModel.ISupportInitialize)(this.splitContainer)).EndInit();
+      this.splitContainer.ResumeLayout(false);
+      this.itemsGroupBox.ResumeLayout(false);
+      this.detailsGroupBox.ResumeLayout(false);
+      this.ResumeLayout(false);
+
+    }
+
+    #endregion
+  }
+}
Index: /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis.Views/3.4/Solution Views/RegressionSolutionView.cs
===================================================================
--- /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis.Views/3.4/Solution Views/RegressionSolutionView.cs	(revision 6611)
+++ /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis.Views/3.4/Solution Views/RegressionSolutionView.cs	(revision 6611)
@@ -0,0 +1,44 @@
+﻿#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.Windows.Forms;
+using HeuristicLab.MainForm;
+using HeuristicLab.PluginInfrastructure;
+
+namespace HeuristicLab.Problems.DataAnalysis.Views {
+  [View("RegressionSolution View")]
+  [Content(typeof(RegressionSolutionBase), true)]
+  public partial class RegressionSolutionView : DataAnalysisSolutionView {
+    public RegressionSolutionView() {
+      InitializeComponent();
+
+      var regressionSolutionEvaluationViewTypes = ApplicationManager.Manager.GetTypes(typeof(IRegressionSolutionEvaluationView), true);
+      foreach (Type viewType in regressionSolutionEvaluationViewTypes)
+        AddViewListViewItem(viewType);
+    }
+
+    public new RegressionSolutionBase Content {
+      get { return (RegressionSolutionBase)base.Content; }
+      set { base.Content = value; }
+    }
+  }
+}
Index: /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis/3.4/HeuristicLab.Problems.DataAnalysis-3.4.csproj
===================================================================
--- /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis/3.4/HeuristicLab.Problems.DataAnalysis-3.4.csproj	(revision 6610)
+++ /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis/3.4/HeuristicLab.Problems.DataAnalysis-3.4.csproj	(revision 6611)
@@ -117,4 +117,6 @@
     <Compile Include="Implementation\Classification\ClassificationSolution.cs" />
     <Compile Include="Implementation\Classification\ClassificationEnsembleProblemData.cs" />
+    <Compile Include="Implementation\Classification\ClassificationSolutionBase.cs" />
+    <Compile Include="Implementation\Classification\DiscriminantFunctionClassificationSolutionBase.cs" />
     <Compile Include="Implementation\Clustering\ClusteringProblem.cs" />
     <Compile Include="Implementation\Clustering\ClusteringProblemData.cs" />
@@ -136,4 +138,5 @@
     </Compile>
     <Compile Include="Interfaces\Regression\IRegressionEnsembleSolution.cs" />
+    <Compile Include="Implementation\Regression\RegressionSolutionBase.cs" />
     <Compile Include="OnlineCalculators\OnlineLinearScalingParameterCalculator.cs" />
     <Compile Include="Implementation\Classification\DiscriminantFunctionClassificationModel.cs" />
Index: /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ClassificationEnsembleModel.cs
===================================================================
--- /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ClassificationEnsembleModel.cs	(revision 6610)
+++ /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ClassificationEnsembleModel.cs	(revision 6611)
@@ -89,4 +89,7 @@
     }
 
+    IClassificationSolution IClassificationModel.CreateClassificationSolution(IClassificationProblemData problemData) {
+      return new ClassificationEnsembleSolution(models, problemData);
+    }
     #endregion
   }
Index: /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ClassificationEnsembleSolution.cs
===================================================================
--- /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ClassificationEnsembleSolution.cs	(revision 6610)
+++ /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ClassificationEnsembleSolution.cs	(revision 6611)
@@ -20,11 +20,11 @@
 #endregion
 
+using System;
 using System.Collections.Generic;
 using System.Linq;
 using HeuristicLab.Common;
 using HeuristicLab.Core;
+using HeuristicLab.Data;
 using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
-using HeuristicLab.Data;
-using System;
 
 namespace HeuristicLab.Problems.DataAnalysis {
@@ -35,5 +35,5 @@
   [Item("Classification Ensemble Solution", "A classification solution that contains an ensemble of multiple classification models")]
   // [Creatable("Data Analysis")]
-  public class ClassificationEnsembleSolution : ClassificationSolution, IClassificationEnsembleSolution {
+  public sealed class ClassificationEnsembleSolution : ClassificationSolution, IClassificationEnsembleSolution {
 
     public new IClassificationEnsembleModel Model {
@@ -49,6 +49,6 @@
 
     [StorableConstructor]
-    protected ClassificationEnsembleSolution(bool deserializing) : base(deserializing) { }
-    protected ClassificationEnsembleSolution(ClassificationEnsembleSolution original, Cloner cloner)
+    private ClassificationEnsembleSolution(bool deserializing) : base(deserializing) { }
+    private ClassificationEnsembleSolution(ClassificationEnsembleSolution original, Cloner cloner)
       : base(original, cloner) {
       trainingPartitions = new Dictionary<IClassificationModel, IntRange>();
@@ -79,5 +79,5 @@
       this.trainingPartitions = new Dictionary<IClassificationModel, IntRange>();
       this.testPartitions = new Dictionary<IClassificationModel, IntRange>();
-      AddModelsAndParitions(models,
+      AddModelsAndPartitions(models,
         trainingPartitions,
         testPartitions);
@@ -87,4 +87,8 @@
     public override IDeepCloneable Clone(Cloner cloner) {
       return new ClassificationEnsembleSolution(this, cloner);
+    }
+
+    protected override void RecalculateResults() {
+      CalculateResults();
     }
 
@@ -163,5 +167,5 @@
     }
 
-    public void AddModelsAndParitions(IEnumerable<IClassificationSolution> solutions) {
+    public void AddModelsAndPartitions(IEnumerable<IClassificationSolution> solutions) {
       foreach (var solution in solutions) {
         var ensembleSolution = solution as ClassificationEnsembleSolution;
@@ -187,5 +191,5 @@
     }
 
-    private void AddModelsAndParitions(IEnumerable<IClassificationModel> models, IEnumerable<IntRange> trainingPartitions, IEnumerable<IntRange> testPartitions) {
+    private void AddModelsAndPartitions(IEnumerable<IClassificationModel> models, IEnumerable<IntRange> trainingPartitions, IEnumerable<IntRange> testPartitions) {
       var modelEnumerator = models.GetEnumerator();
       var trainingPartitionEnumerator = trainingPartitions.GetEnumerator();
Index: /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ClassificationSolution.cs
===================================================================
--- /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ClassificationSolution.cs	(revision 6610)
+++ /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ClassificationSolution.cs	(revision 6611)
@@ -23,6 +23,4 @@
 using System.Linq;
 using HeuristicLab.Common;
-using HeuristicLab.Data;
-using HeuristicLab.Optimization;
 using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
 
@@ -32,84 +30,51 @@
   /// </summary>
   [StorableClass]
-  public class ClassificationSolution : DataAnalysisSolution, IClassificationSolution {
-    private const string TrainingAccuracyResultName = "Accuracy (training)";
-    private const string TestAccuracyResultName = "Accuracy (test)";
-
-    public new IClassificationModel Model {
-      get { return (IClassificationModel)base.Model; }
-      protected set { base.Model = value; }
-    }
-
-    public new IClassificationProblemData ProblemData {
-      get { return (IClassificationProblemData)base.ProblemData; }
-      protected set { base.ProblemData = value; }
-    }
-
-    public double TrainingAccuracy {
-      get { return ((DoubleValue)this[TrainingAccuracyResultName].Value).Value; }
-      private set { ((DoubleValue)this[TrainingAccuracyResultName].Value).Value = value; }
-    }
-
-    public double TestAccuracy {
-      get { return ((DoubleValue)this[TestAccuracyResultName].Value).Value; }
-      private set { ((DoubleValue)this[TestAccuracyResultName].Value).Value = value; }
-    }
+  public abstract class ClassificationSolution : ClassificationSolutionBase {
+    protected readonly Dictionary<int, double> evaluationCache;
 
     [StorableConstructor]
-    protected ClassificationSolution(bool deserializing) : base(deserializing) { }
+    protected ClassificationSolution(bool deserializing)
+      : base(deserializing) {
+      evaluationCache = new Dictionary<int, double>();
+    }
     protected ClassificationSolution(ClassificationSolution original, Cloner cloner)
       : base(original, cloner) {
+      evaluationCache = new Dictionary<int, double>(original.evaluationCache);
     }
     public ClassificationSolution(IClassificationModel model, IClassificationProblemData problemData)
       : base(model, problemData) {
-      Add(new Result(TrainingAccuracyResultName, "Accuracy of the model on the training partition (percentage of correctly classified instances).", new PercentValue()));
-      Add(new Result(TestAccuracyResultName, "Accuracy of the model on the test partition (percentage of correctly classified instances).", new PercentValue()));
-      CalculateResults();
+      evaluationCache = new Dictionary<int, double>();
     }
 
-    public override IDeepCloneable Clone(Cloner cloner) {
-      return new ClassificationSolution(this, cloner);
+    public override IEnumerable<double> EstimatedClassValues {
+      get { return GetEstimatedClassValues(Enumerable.Range(0, ProblemData.Dataset.Rows)); }
+    }
+    public override IEnumerable<double> EstimatedTrainingClassValues {
+      get { return GetEstimatedClassValues(ProblemData.TrainingIndizes); }
+    }
+    public override IEnumerable<double> EstimatedTestClassValues {
+      get { return GetEstimatedClassValues(ProblemData.TestIndizes); }
     }
 
-    protected override void RecalculateResults() {
-      CalculateResults();
+    public override IEnumerable<double> GetEstimatedClassValues(IEnumerable<int> rows) {
+      var rowsToEvaluate = rows.Except(evaluationCache.Keys);
+      var rowsEnumerator = rowsToEvaluate.GetEnumerator();
+      var valuesEnumerator = Model.GetEstimatedClassValues(ProblemData.Dataset, rowsToEvaluate).GetEnumerator();
+
+      while (rowsEnumerator.MoveNext() & valuesEnumerator.MoveNext()) {
+        evaluationCache.Add(rowsEnumerator.Current, valuesEnumerator.Current);
+      }
+
+      return rows.Select(row => evaluationCache[row]);
     }
 
-    private void CalculateResults() {
-      double[] estimatedTrainingClassValues = EstimatedTrainingClassValues.ToArray(); // cache values
-      IEnumerable<double> originalTrainingClassValues = ProblemData.Dataset.GetEnumeratedVariableValues(ProblemData.TargetVariable, ProblemData.TrainingIndizes);
-      double[] estimatedTestClassValues = EstimatedTestClassValues.ToArray(); // cache values
-      IEnumerable<double> originalTestClassValues = ProblemData.Dataset.GetEnumeratedVariableValues(ProblemData.TargetVariable, ProblemData.TestIndizes);
-
-      OnlineCalculatorError errorState;
-      double trainingAccuracy = OnlineAccuracyCalculator.Calculate(estimatedTrainingClassValues, originalTrainingClassValues, out errorState);
-      if (errorState != OnlineCalculatorError.None) trainingAccuracy = double.NaN;
-      double testAccuracy = OnlineAccuracyCalculator.Calculate(estimatedTestClassValues, originalTestClassValues, out errorState);
-      if (errorState != OnlineCalculatorError.None) testAccuracy = double.NaN;
-
-      TrainingAccuracy = trainingAccuracy;
-      TestAccuracy = testAccuracy;
+    protected override void OnProblemDataChanged() {
+      evaluationCache.Clear();
+      base.OnProblemDataChanged();
     }
 
-    public virtual IEnumerable<double> EstimatedClassValues {
-      get {
-        return GetEstimatedClassValues(Enumerable.Range(0, ProblemData.Dataset.Rows));
-      }
-    }
-
-    public virtual IEnumerable<double> EstimatedTrainingClassValues {
-      get {
-        return GetEstimatedClassValues(ProblemData.TrainingIndizes);
-      }
-    }
-
-    public virtual IEnumerable<double> EstimatedTestClassValues {
-      get {
-        return GetEstimatedClassValues(ProblemData.TestIndizes);
-      }
-    }
-
-    public virtual IEnumerable<double> GetEstimatedClassValues(IEnumerable<int> rows) {
-      return Model.GetEstimatedClassValues(ProblemData.Dataset, rows);
+    protected override void OnModelChanged() {
+      evaluationCache.Clear();
+      base.OnModelChanged();
     }
   }
Index: /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ClassificationSolutionBase.cs
===================================================================
--- /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ClassificationSolutionBase.cs	(revision 6611)
+++ /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ClassificationSolutionBase.cs	(revision 6611)
@@ -0,0 +1,89 @@
+﻿#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.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Data;
+using HeuristicLab.Optimization;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  [StorableClass]
+  public abstract class ClassificationSolutionBase : DataAnalysisSolution, IClassificationSolution {
+    private const string TrainingAccuracyResultName = "Accuracy (training)";
+    private const string TestAccuracyResultName = "Accuracy (test)";
+
+    public new IClassificationModel Model {
+      get { return (IClassificationModel)base.Model; }
+      protected set { base.Model = value; }
+    }
+
+    public new IClassificationProblemData ProblemData {
+      get { return (IClassificationProblemData)base.ProblemData; }
+      protected set { base.ProblemData = value; }
+    }
+
+    #region Results
+    public double TrainingAccuracy {
+      get { return ((DoubleValue)this[TrainingAccuracyResultName].Value).Value; }
+      private set { ((DoubleValue)this[TrainingAccuracyResultName].Value).Value = value; }
+    }
+    public double TestAccuracy {
+      get { return ((DoubleValue)this[TestAccuracyResultName].Value).Value; }
+      private set { ((DoubleValue)this[TestAccuracyResultName].Value).Value = value; }
+    }
+    #endregion
+
+    [StorableConstructor]
+    protected ClassificationSolutionBase(bool deserializing) : base(deserializing) { }
+    protected ClassificationSolutionBase(ClassificationSolutionBase original, Cloner cloner)
+      : base(original, cloner) {
+    }
+    protected ClassificationSolutionBase(IClassificationModel model, IClassificationProblemData problemData)
+      : base(model, problemData) {
+      Add(new Result(TrainingAccuracyResultName, "Accuracy of the model on the training partition (percentage of correctly classified instances).", new PercentValue()));
+      Add(new Result(TestAccuracyResultName, "Accuracy of the model on the test partition (percentage of correctly classified instances).", new PercentValue()));
+    }
+
+    protected void CalculateResults() {
+      double[] estimatedTrainingClassValues = EstimatedTrainingClassValues.ToArray(); // cache values
+      double[] originalTrainingClassValues = ProblemData.Dataset.GetEnumeratedVariableValues(ProblemData.TargetVariable, ProblemData.TrainingIndizes).ToArray();
+      double[] estimatedTestClassValues = EstimatedTestClassValues.ToArray(); // cache values
+      double[] originalTestClassValues = ProblemData.Dataset.GetEnumeratedVariableValues(ProblemData.TargetVariable, ProblemData.TestIndizes).ToArray();
+
+      OnlineCalculatorError errorState;
+      double trainingAccuracy = OnlineAccuracyCalculator.Calculate(estimatedTrainingClassValues, originalTrainingClassValues, out errorState);
+      if (errorState != OnlineCalculatorError.None) trainingAccuracy = double.NaN;
+      double testAccuracy = OnlineAccuracyCalculator.Calculate(estimatedTestClassValues, originalTestClassValues, out errorState);
+      if (errorState != OnlineCalculatorError.None) testAccuracy = double.NaN;
+
+      TrainingAccuracy = trainingAccuracy;
+      TestAccuracy = testAccuracy;
+    }
+
+    public abstract IEnumerable<double> EstimatedClassValues { get; }
+    public abstract IEnumerable<double> EstimatedTrainingClassValues { get; }
+    public abstract IEnumerable<double> EstimatedTestClassValues { get; }
+
+    public abstract IEnumerable<double> GetEstimatedClassValues(IEnumerable<int> rows);
+  }
+}
Index: /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/DiscriminantFunctionClassificationModel.cs
===================================================================
--- /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/DiscriminantFunctionClassificationModel.cs	(revision 6610)
+++ /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/DiscriminantFunctionClassificationModel.cs	(revision 6611)
@@ -33,5 +33,5 @@
   [StorableClass]
   [Item("DiscriminantFunctionClassificationModel", "Represents a classification model that uses a discriminant function and classification thresholds.")]
-  public class DiscriminantFunctionClassificationModel : NamedItem, IDiscriminantFunctionClassificationModel {
+  public abstract class DiscriminantFunctionClassificationModel : NamedItem, IDiscriminantFunctionClassificationModel {
     [Storable]
     private IRegressionModel model;
@@ -70,8 +70,4 @@
     }
 
-    public override IDeepCloneable Clone(Cloner cloner) {
-      return new DiscriminantFunctionClassificationModel(this, cloner);
-    }
-
     public void SetThresholdsAndClassValues(IEnumerable<double> thresholds, IEnumerable<double> classValues) {
       var classValuesArr = classValues.ToArray();
@@ -106,4 +102,7 @@
     }
     #endregion
+
+    public abstract IDiscriminantFunctionClassificationSolution CreateDiscriminantFunctionClassificationSolution(IClassificationProblemData problemData);
+    public abstract IClassificationSolution CreateClassificationSolution(IClassificationProblemData problemData);
   }
 }
Index: /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/DiscriminantFunctionClassificationSolution.cs
===================================================================
--- /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/DiscriminantFunctionClassificationSolution.cs	(revision 6610)
+++ /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/DiscriminantFunctionClassificationSolution.cs	(revision 6611)
@@ -20,11 +20,8 @@
 #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;
 
@@ -35,147 +32,85 @@
   [StorableClass]
   [Item("DiscriminantFunctionClassificationSolution", "Represents a classification solution that uses a discriminant function and classification thresholds.")]
-  public class DiscriminantFunctionClassificationSolution : ClassificationSolution, IDiscriminantFunctionClassificationSolution {
-    private const string TrainingMeanSquaredErrorResultName = "Mean squared error (training)";
-    private const string TestMeanSquaredErrorResultName = "Mean squared error (test)";
-    private const string TrainingRSquaredResultName = "Pearson's R² (training)";
-    private const string TestRSquaredResultName = "Pearson's R² (test)";
+  public abstract class DiscriminantFunctionClassificationSolution : DiscriminantFunctionClassificationSolutionBase {
+    protected readonly Dictionary<int, double> valueEvaluationCache;
+    protected readonly Dictionary<int, double> classValueEvaluationCache;
 
-    public new IDiscriminantFunctionClassificationModel Model {
-      get { return (IDiscriminantFunctionClassificationModel)base.Model; }
-      protected set {
-        if (value != null && value != Model) {
-          if (Model != null) {
-            Model.ThresholdsChanged -= new EventHandler(Model_ThresholdsChanged);
-          }
-          value.ThresholdsChanged += new EventHandler(Model_ThresholdsChanged);
-          base.Model = value;
-        }
-      }
+    [StorableConstructor]
+    protected DiscriminantFunctionClassificationSolution(bool deserializing)
+      : base(deserializing) {
+      valueEvaluationCache = new Dictionary<int, double>();
+      classValueEvaluationCache = new Dictionary<int, double>();
+    }
+    protected DiscriminantFunctionClassificationSolution(DiscriminantFunctionClassificationSolution original, Cloner cloner)
+      : base(original, cloner) {
+      valueEvaluationCache = new Dictionary<int, double>(original.valueEvaluationCache);
+      classValueEvaluationCache = new Dictionary<int, double>(original.classValueEvaluationCache);
+    }
+    protected DiscriminantFunctionClassificationSolution(IDiscriminantFunctionClassificationModel model, IClassificationProblemData problemData)
+      : base(model, problemData) {
+      valueEvaluationCache = new Dictionary<int, double>();
+      classValueEvaluationCache = new Dictionary<int, double>();
+
+      SetAccuracyMaximizingThresholds();
     }
 
-    public double TrainingMeanSquaredError {
-      get { return ((DoubleValue)this[TrainingMeanSquaredErrorResultName].Value).Value; }
-      private set { ((DoubleValue)this[TrainingMeanSquaredErrorResultName].Value).Value = value; }
+    public override IEnumerable<double> EstimatedClassValues {
+      get { return GetEstimatedClassValues(Enumerable.Range(0, ProblemData.Dataset.Rows)); }
+    }
+    public override IEnumerable<double> EstimatedTrainingClassValues {
+      get { return GetEstimatedClassValues(ProblemData.TrainingIndizes); }
+    }
+    public override IEnumerable<double> EstimatedTestClassValues {
+      get { return GetEstimatedClassValues(ProblemData.TestIndizes); }
     }
 
-    public double TestMeanSquaredError {
-      get { return ((DoubleValue)this[TestMeanSquaredErrorResultName].Value).Value; }
-      private set { ((DoubleValue)this[TestMeanSquaredErrorResultName].Value).Value = value; }
+    public override IEnumerable<double> GetEstimatedClassValues(IEnumerable<int> rows) {
+      var rowsToEvaluate = rows.Except(classValueEvaluationCache.Keys);
+      var rowsEnumerator = rowsToEvaluate.GetEnumerator();
+      var valuesEnumerator = Model.GetEstimatedClassValues(ProblemData.Dataset, rowsToEvaluate).GetEnumerator();
+
+      while (rowsEnumerator.MoveNext() & valuesEnumerator.MoveNext()) {
+        classValueEvaluationCache.Add(rowsEnumerator.Current, valuesEnumerator.Current);
+      }
+
+      return rows.Select(row => classValueEvaluationCache[row]);
     }
 
-    public double TrainingRSquared {
-      get { return ((DoubleValue)this[TrainingRSquaredResultName].Value).Value; }
-      private set { ((DoubleValue)this[TrainingRSquaredResultName].Value).Value = value; }
-    }
 
-    public double TestRSquared {
-      get { return ((DoubleValue)this[TestRSquaredResultName].Value).Value; }
-      private set { ((DoubleValue)this[TestRSquaredResultName].Value).Value = value; }
-    }
-
-    [StorableConstructor]
-    protected DiscriminantFunctionClassificationSolution(bool deserializing) : base(deserializing) { }
-    protected DiscriminantFunctionClassificationSolution(DiscriminantFunctionClassificationSolution original, Cloner cloner)
-      : base(original, cloner) {
-      RegisterEventHandler();
-    }
-    public DiscriminantFunctionClassificationSolution(IRegressionModel model, IClassificationProblemData problemData)
-      : this(new DiscriminantFunctionClassificationModel(model), problemData) {
-    }
-    public DiscriminantFunctionClassificationSolution(IDiscriminantFunctionClassificationModel model, IClassificationProblemData problemData)
-      : base(model, problemData) {
-      Add(new Result(TrainingMeanSquaredErrorResultName, "Mean of squared errors of the model on the training partition", new DoubleValue()));
-      Add(new Result(TestMeanSquaredErrorResultName, "Mean of squared errors of the model on the test partition", new DoubleValue()));
-      Add(new Result(TrainingRSquaredResultName, "Squared Pearson's correlation coefficient of the model output and the actual values on the training partition", new DoubleValue()));
-      Add(new Result(TestRSquaredResultName, "Squared Pearson's correlation coefficient of the model output and the actual values on the test partition", new DoubleValue()));
-      SetAccuracyMaximizingThresholds();
-
-      //mkommend: important to recalculate accuracy because during the calculation before no thresholds were present     
-      base.RecalculateResults();
-      CalculateResults();
-      RegisterEventHandler();
-    }
-
-    [StorableHook(HookType.AfterDeserialization)]
-    private void AfterDeserialization() {
-      RegisterEventHandler();
-    }
-
-    protected override void OnModelChanged(EventArgs e) {
-      DeregisterEventHandler();
-      SetAccuracyMaximizingThresholds();
-      RegisterEventHandler();
-      base.OnModelChanged(e);
-    }
-
-    protected override void RecalculateResults() {
-      base.RecalculateResults();
-      CalculateResults();
-    }
-
-    private void CalculateResults() {
-      double[] estimatedTrainingValues = EstimatedTrainingValues.ToArray(); // cache values
-      IEnumerable<double> originalTrainingValues = ProblemData.Dataset.GetEnumeratedVariableValues(ProblemData.TargetVariable, ProblemData.TrainingIndizes);
-      double[] estimatedTestValues = EstimatedTestValues.ToArray(); // cache values
-      IEnumerable<double> originalTestValues = ProblemData.Dataset.GetEnumeratedVariableValues(ProblemData.TargetVariable, ProblemData.TestIndizes);
-
-      OnlineCalculatorError errorState;
-      double trainingMSE = OnlineMeanSquaredErrorCalculator.Calculate(estimatedTrainingValues, originalTrainingValues, out errorState);
-      TrainingMeanSquaredError = errorState == OnlineCalculatorError.None ? trainingMSE : double.NaN;
-      double testMSE = OnlineMeanSquaredErrorCalculator.Calculate(estimatedTestValues, originalTestValues, out errorState);
-      TestMeanSquaredError = errorState == OnlineCalculatorError.None ? testMSE : double.NaN;
-
-      double trainingR2 = OnlinePearsonsRSquaredCalculator.Calculate(estimatedTrainingValues, originalTrainingValues, out errorState);
-      TrainingRSquared = errorState == OnlineCalculatorError.None ? trainingR2 : double.NaN;
-      double testR2 = OnlinePearsonsRSquaredCalculator.Calculate(estimatedTestValues, originalTestValues, out errorState);
-      TestRSquared = errorState == OnlineCalculatorError.None ? testR2 : double.NaN;
-    }
-
-    private void RegisterEventHandler() {
-      Model.ThresholdsChanged += new EventHandler(Model_ThresholdsChanged);
-    }
-    private void DeregisterEventHandler() {
-      Model.ThresholdsChanged -= new EventHandler(Model_ThresholdsChanged);
-    }
-    private void Model_ThresholdsChanged(object sender, EventArgs e) {
-      OnModelThresholdsChanged(e);
-    }
-
-    public void SetAccuracyMaximizingThresholds() {
-      double[] classValues;
-      double[] thresholds;
-      var targetClassValues = ProblemData.Dataset.GetEnumeratedVariableValues(ProblemData.TargetVariable, ProblemData.TrainingIndizes);
-      AccuracyMaximizationThresholdCalculator.CalculateThresholds(ProblemData, EstimatedTrainingValues, targetClassValues, out classValues, out thresholds);
-
-      Model.SetThresholdsAndClassValues(thresholds, classValues);
-    }
-
-    public void SetClassDistibutionCutPointThresholds() {
-      double[] classValues;
-      double[] thresholds;
-      var targetClassValues = ProblemData.Dataset.GetEnumeratedVariableValues(ProblemData.TargetVariable, ProblemData.TrainingIndizes);
-      NormalDistributionCutPointsThresholdCalculator.CalculateThresholds(ProblemData, EstimatedTrainingValues, targetClassValues, out classValues, out thresholds);
-
-      Model.SetThresholdsAndClassValues(thresholds, classValues);
-    }
-
-    protected virtual void OnModelThresholdsChanged(EventArgs e) {
-      RecalculateResults();
-    }
-
-    public IEnumerable<double> EstimatedValues {
+    public override IEnumerable<double> EstimatedValues {
       get { return GetEstimatedValues(Enumerable.Range(0, ProblemData.Dataset.Rows)); }
     }
-
-    public IEnumerable<double> EstimatedTrainingValues {
+    public override IEnumerable<double> EstimatedTrainingValues {
       get { return GetEstimatedValues(ProblemData.TrainingIndizes); }
     }
-
-    public IEnumerable<double> EstimatedTestValues {
+    public override IEnumerable<double> EstimatedTestValues {
       get { return GetEstimatedValues(ProblemData.TestIndizes); }
     }
 
-    public IEnumerable<double> GetEstimatedValues(IEnumerable<int> rows) {
-      return Model.GetEstimatedValues(ProblemData.Dataset, rows);
+    public override IEnumerable<double> GetEstimatedValues(IEnumerable<int> rows) {
+      var rowsToEvaluate = rows.Except(valueEvaluationCache.Keys);
+      var rowsEnumerator = rowsToEvaluate.GetEnumerator();
+      var valuesEnumerator = Model.GetEstimatedValues(ProblemData.Dataset, rowsToEvaluate).GetEnumerator();
+
+      while (rowsEnumerator.MoveNext() & valuesEnumerator.MoveNext()) {
+        valueEvaluationCache.Add(rowsEnumerator.Current, valuesEnumerator.Current);
+      }
+
+      return rows.Select(row => valueEvaluationCache[row]);
+    }
+
+    protected override void OnModelChanged() {
+      valueEvaluationCache.Clear();
+      classValueEvaluationCache.Clear();
+      base.OnModelChanged();
+    }
+    protected override void OnModelThresholdsChanged(System.EventArgs e) {
+      classValueEvaluationCache.Clear();
+      base.OnModelThresholdsChanged(e);
+    }
+    protected override void OnProblemDataChanged() {
+      valueEvaluationCache.Clear();
+      classValueEvaluationCache.Clear();
+      base.OnProblemDataChanged();
     }
   }
Index: /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/DiscriminantFunctionClassificationSolutionBase.cs
===================================================================
--- /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/DiscriminantFunctionClassificationSolutionBase.cs	(revision 6611)
+++ /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/DiscriminantFunctionClassificationSolutionBase.cs	(revision 6611)
@@ -0,0 +1,159 @@
+﻿#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;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  /// <summary>
+  /// Represents a classification solution that uses a discriminant function and classification thresholds.
+  /// </summary>
+  [StorableClass]
+  [Item("DiscriminantFunctionClassificationSolution", "Represents a classification solution that uses a discriminant function and classification thresholds.")]
+  public abstract class DiscriminantFunctionClassificationSolutionBase : ClassificationSolutionBase, IDiscriminantFunctionClassificationSolution {
+    private const string TrainingMeanSquaredErrorResultName = "Mean squared error (training)";
+    private const string TestMeanSquaredErrorResultName = "Mean squared error (test)";
+    private const string TrainingRSquaredResultName = "Pearson's R² (training)";
+    private const string TestRSquaredResultName = "Pearson's R² (test)";
+
+    public new IDiscriminantFunctionClassificationModel Model {
+      get { return (IDiscriminantFunctionClassificationModel)base.Model; }
+      protected set {
+        if (value != null && value != Model) {
+          if (Model != null) {
+            Model.ThresholdsChanged -= new EventHandler(Model_ThresholdsChanged);
+          }
+          value.ThresholdsChanged += new EventHandler(Model_ThresholdsChanged);
+          base.Model = value;
+        }
+      }
+    }
+
+    #region Results
+    public double TrainingMeanSquaredError {
+      get { return ((DoubleValue)this[TrainingMeanSquaredErrorResultName].Value).Value; }
+      private set { ((DoubleValue)this[TrainingMeanSquaredErrorResultName].Value).Value = value; }
+    }
+    public double TestMeanSquaredError {
+      get { return ((DoubleValue)this[TestMeanSquaredErrorResultName].Value).Value; }
+      private set { ((DoubleValue)this[TestMeanSquaredErrorResultName].Value).Value = value; }
+    }
+    public double TrainingRSquared {
+      get { return ((DoubleValue)this[TrainingRSquaredResultName].Value).Value; }
+      private set { ((DoubleValue)this[TrainingRSquaredResultName].Value).Value = value; }
+    }
+    public double TestRSquared {
+      get { return ((DoubleValue)this[TestRSquaredResultName].Value).Value; }
+      private set { ((DoubleValue)this[TestRSquaredResultName].Value).Value = value; }
+    }
+    #endregion
+
+    [StorableConstructor]
+    protected DiscriminantFunctionClassificationSolutionBase(bool deserializing) : base(deserializing) { }
+    protected DiscriminantFunctionClassificationSolutionBase(DiscriminantFunctionClassificationSolutionBase original, Cloner cloner)
+      : base(original, cloner) {
+      RegisterEventHandler();
+    }
+    protected DiscriminantFunctionClassificationSolutionBase(IDiscriminantFunctionClassificationModel model, IClassificationProblemData problemData)
+      : base(model, problemData) {
+      Add(new Result(TrainingMeanSquaredErrorResultName, "Mean of squared errors of the model on the training partition", new DoubleValue()));
+      Add(new Result(TestMeanSquaredErrorResultName, "Mean of squared errors of the model on the test partition", new DoubleValue()));
+      Add(new Result(TrainingRSquaredResultName, "Squared Pearson's correlation coefficient of the model output and the actual values on the training partition", new DoubleValue()));
+      Add(new Result(TestRSquaredResultName, "Squared Pearson's correlation coefficient of the model output and the actual values on the test partition", new DoubleValue()));
+
+      RegisterEventHandler();
+    }
+
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() {
+      RegisterEventHandler();
+    }
+
+    protected override void OnModelChanged() {
+      DeregisterEventHandler();
+      SetAccuracyMaximizingThresholds();
+      RegisterEventHandler();
+      base.OnModelChanged();
+    }
+
+    protected void CalculateRegressionResults() {
+      double[] estimatedTrainingValues = EstimatedTrainingValues.ToArray(); // cache values
+      double[] originalTrainingValues = ProblemData.Dataset.GetEnumeratedVariableValues(ProblemData.TargetVariable, ProblemData.TrainingIndizes).ToArray();
+      double[] estimatedTestValues = EstimatedTestValues.ToArray(); // cache values
+      double[] originalTestValues = ProblemData.Dataset.GetEnumeratedVariableValues(ProblemData.TargetVariable, ProblemData.TestIndizes).ToArray();
+
+      OnlineCalculatorError errorState;
+      double trainingMSE = OnlineMeanSquaredErrorCalculator.Calculate(estimatedTrainingValues, originalTrainingValues, out errorState);
+      TrainingMeanSquaredError = errorState == OnlineCalculatorError.None ? trainingMSE : double.NaN;
+      double testMSE = OnlineMeanSquaredErrorCalculator.Calculate(estimatedTestValues, originalTestValues, out errorState);
+      TestMeanSquaredError = errorState == OnlineCalculatorError.None ? testMSE : double.NaN;
+
+      double trainingR2 = OnlinePearsonsRSquaredCalculator.Calculate(estimatedTrainingValues, originalTrainingValues, out errorState);
+      TrainingRSquared = errorState == OnlineCalculatorError.None ? trainingR2 : double.NaN;
+      double testR2 = OnlinePearsonsRSquaredCalculator.Calculate(estimatedTestValues, originalTestValues, out errorState);
+      TestRSquared = errorState == OnlineCalculatorError.None ? testR2 : double.NaN;
+    }
+
+    private void RegisterEventHandler() {
+      Model.ThresholdsChanged += new EventHandler(Model_ThresholdsChanged);
+    }
+    private void DeregisterEventHandler() {
+      Model.ThresholdsChanged -= new EventHandler(Model_ThresholdsChanged);
+    }
+    private void Model_ThresholdsChanged(object sender, EventArgs e) {
+      OnModelThresholdsChanged(e);
+    }
+
+    public void SetAccuracyMaximizingThresholds() {
+      double[] classValues;
+      double[] thresholds;
+      var targetClassValues = ProblemData.Dataset.GetEnumeratedVariableValues(ProblemData.TargetVariable, ProblemData.TrainingIndizes);
+      AccuracyMaximizationThresholdCalculator.CalculateThresholds(ProblemData, EstimatedTrainingValues, targetClassValues, out classValues, out thresholds);
+
+      Model.SetThresholdsAndClassValues(thresholds, classValues);
+    }
+
+    public void SetClassDistibutionCutPointThresholds() {
+      double[] classValues;
+      double[] thresholds;
+      var targetClassValues = ProblemData.Dataset.GetEnumeratedVariableValues(ProblemData.TargetVariable, ProblemData.TrainingIndizes);
+      NormalDistributionCutPointsThresholdCalculator.CalculateThresholds(ProblemData, EstimatedTrainingValues, targetClassValues, out classValues, out thresholds);
+
+      Model.SetThresholdsAndClassValues(thresholds, classValues);
+    }
+
+    protected virtual void OnModelThresholdsChanged(EventArgs e) {
+      CalculateResults();
+    }
+
+    public abstract IEnumerable<double> EstimatedValues { get; }
+    public abstract IEnumerable<double> EstimatedTrainingValues { get; }
+    public abstract IEnumerable<double> EstimatedTestValues { get; }
+
+    public abstract IEnumerable<double> GetEstimatedValues(IEnumerable<int> rows);
+  }
+}
Index: /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/DataAnalysisProblem.cs
===================================================================
--- /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/DataAnalysisProblem.cs	(revision 6610)
+++ /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/DataAnalysisProblem.cs	(revision 6611)
@@ -48,9 +48,12 @@
     public T ProblemData {
       get { return ProblemDataParameter.Value; }
-      protected set { ProblemDataParameter.Value = value; }
+      protected set {
+        ProblemDataParameter.Value = value;
+      }
     }
     #endregion
     protected DataAnalysisProblem(DataAnalysisProblem<T> original, Cloner cloner)
       : base(original, cloner) {
+      RegisterEventHandlers();
     }
     [StorableConstructor]
@@ -59,10 +62,19 @@
       : base() {
       Parameters.Add(new ValueParameter<T>(ProblemDataParameterName, ProblemDataParameterDescription));
+      RegisterEventHandlers();
+    }
+
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() {
+      RegisterEventHandlers();
     }
 
     private void RegisterEventHandlers() {
+      ProblemDataParameter.ValueChanged += new EventHandler(ProblemDataParameter_ValueChanged);
+      if (ProblemDataParameter.Value != null) ProblemDataParameter.Value.Changed += new EventHandler(ProblemDataParameter_ValueChanged);
+    }
+
+    private void ProblemDataParameter_ValueChanged(object sender, EventArgs e) {
       ProblemDataParameter.Value.Changed += new EventHandler(ProblemDataParameter_ValueChanged);
-    }
-    private void ProblemDataParameter_ValueChanged(object sender, EventArgs e) {
       OnProblemDataChanged();
       OnReset();
Index: /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/DataAnalysisProblemData.cs
===================================================================
--- /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/DataAnalysisProblemData.cs	(revision 6610)
+++ /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/DataAnalysisProblemData.cs	(revision 6611)
@@ -91,4 +91,8 @@
     [StorableConstructor]
     protected DataAnalysisProblemData(bool deserializing) : base(deserializing) { }
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() {
+      RegisterEventHandlers();
+    }
 
     protected DataAnalysisProblemData(Dataset dataset, IEnumerable<string> allowedInputVariables) {
Index: /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/DataAnalysisSolution.cs
===================================================================
--- /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/DataAnalysisSolution.cs	(revision 6610)
+++ /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/DataAnalysisSolution.cs	(revision 6611)
@@ -48,5 +48,5 @@
           if (value != null) {
             this[ModelResultName].Value = value;
-            OnModelChanged(EventArgs.Empty);
+            OnModelChanged();
           }
         }
@@ -62,5 +62,5 @@
             this[ProblemDataResultName].Value = value;
             ProblemData.Changed += new EventHandler(ProblemData_Changed);
-            OnProblemDataChanged(EventArgs.Empty);
+            OnProblemDataChanged();
           }
         }
@@ -80,6 +80,6 @@
       name = ItemName;
       description = ItemDescription;
-      Add(new Result(ModelResultName, "The symbolic data analysis model.", model));
-      Add(new Result(ProblemDataResultName, "The symbolic data analysis problem data.", problemData));
+      Add(new Result(ModelResultName, "The data analysis model.", model));
+      Add(new Result(ProblemDataResultName, "The data analysis problem data.", problemData));
 
       problemData.Changed += new EventHandler(ProblemData_Changed);
@@ -89,19 +89,19 @@
 
     private void ProblemData_Changed(object sender, EventArgs e) {
-      OnProblemDataChanged(e);
+      OnProblemDataChanged();
     }
 
     public event EventHandler ModelChanged;
-    protected virtual void OnModelChanged(EventArgs e) {
+    protected virtual void OnModelChanged() {
       RecalculateResults();
       var listeners = ModelChanged;
-      if (listeners != null) listeners(this, e);
+      if (listeners != null) listeners(this, EventArgs.Empty);
     }
 
     public event EventHandler ProblemDataChanged;
-    protected virtual void OnProblemDataChanged(EventArgs e) {
+    protected virtual void OnProblemDataChanged() {
       RecalculateResults();
       var listeners = ProblemDataChanged;
-      if (listeners != null) listeners(this, e);
+      if (listeners != null) listeners(this, EventArgs.Empty);
     }
 
Index: /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/RegressionEnsembleModel.cs
===================================================================
--- /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/RegressionEnsembleModel.cs	(revision 6610)
+++ /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/RegressionEnsembleModel.cs	(revision 6611)
@@ -34,9 +34,22 @@
   public class RegressionEnsembleModel : NamedItem, IRegressionEnsembleModel {
 
-    [Storable]
     private List<IRegressionModel> models;
     public IEnumerable<IRegressionModel> Models {
       get { return new List<IRegressionModel>(models); }
     }
+
+    [Storable(Name = "Models")]
+    private IEnumerable<IRegressionModel> StorableModels {
+      get { return models; }
+      set { models = value.ToList(); }
+    }
+
+    #region backwards compatiblity 3.3.5
+    [Storable(Name = "models", AllowOneWay = true)]
+    private List<IRegressionModel> OldStorableModels {
+      set { models = value; }
+    }
+    #endregion
+
     [StorableConstructor]
     protected RegressionEnsembleModel(bool deserializing) : base(deserializing) { }
@@ -83,4 +96,11 @@
     }
 
+    public RegressionEnsembleSolution CreateRegressionSolution(IRegressionProblemData problemData) {
+      return new RegressionEnsembleSolution(this.Models, problemData);
+    }
+    IRegressionSolution IRegressionModel.CreateRegressionSolution(IRegressionProblemData problemData) {
+      return CreateRegressionSolution(problemData);
+    }
+
     #endregion
   }
Index: /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/RegressionEnsembleSolution.cs
===================================================================
--- /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/RegressionEnsembleSolution.cs	(revision 6610)
+++ /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/RegressionEnsembleSolution.cs	(revision 6611)
@@ -20,11 +20,11 @@
 #endregion
 
+using System;
 using System.Collections.Generic;
 using System.Linq;
 using HeuristicLab.Common;
 using HeuristicLab.Core;
+using HeuristicLab.Data;
 using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
-using System;
-using HeuristicLab.Data;
 
 namespace HeuristicLab.Problems.DataAnalysis {
@@ -35,5 +35,5 @@
   [Item("Regression Ensemble Solution", "A regression solution that contains an ensemble of multiple regression models")]
   // [Creatable("Data Analysis")]
-  public class RegressionEnsembleSolution : RegressionSolution, IRegressionEnsembleSolution {
+  public sealed class RegressionEnsembleSolution : RegressionSolution, IRegressionEnsembleSolution {
     public new IRegressionEnsembleModel Model {
       get { return (IRegressionEnsembleModel)base.Model; }
@@ -46,6 +46,6 @@
 
     [StorableConstructor]
-    protected RegressionEnsembleSolution(bool deserializing) : base(deserializing) { }
-    protected RegressionEnsembleSolution(RegressionEnsembleSolution original, Cloner cloner)
+    private RegressionEnsembleSolution(bool deserializing) : base(deserializing) { }
+    private RegressionEnsembleSolution(RegressionEnsembleSolution original, Cloner cloner)
       : base(original, cloner) {
       trainingPartitions = new Dictionary<IRegressionModel, IntRange>();
@@ -64,5 +64,5 @@
       trainingPartitions = new Dictionary<IRegressionModel, IntRange>();
       testPartitions = new Dictionary<IRegressionModel, IntRange>();
-      AddModelsAndParitions(models,
+      AddModelsAndPartitions(models,
         from m in models select (IntRange)problemData.TrainingPartition.Clone(),
         from m in models select (IntRange)problemData.TestPartition.Clone());
@@ -74,5 +74,5 @@
       this.trainingPartitions = new Dictionary<IRegressionModel, IntRange>();
       this.testPartitions = new Dictionary<IRegressionModel, IntRange>();
-      AddModelsAndParitions(models, trainingPartitions, testPartitions);
+      AddModelsAndPartitions(models, trainingPartitions, testPartitions);
       RecalculateResults();
     }
@@ -80,4 +80,8 @@
     public override IDeepCloneable Clone(Cloner cloner) {
       return new RegressionEnsembleSolution(this, cloner);
+    }
+
+    protected override void RecalculateResults() {
+      CalculateResults();
     }
 
@@ -152,5 +156,5 @@
 
 
-    public void AddModelsAndParitions(IEnumerable<IRegressionSolution> solutions) {
+    public void AddModelsAndPartitions(IEnumerable<IRegressionSolution> solutions) {
       foreach (var solution in solutions) {
         var ensembleSolution = solution as RegressionEnsembleSolution;
@@ -176,5 +180,5 @@
     }
 
-    private void AddModelsAndParitions(IEnumerable<IRegressionModel> models, IEnumerable<IntRange> trainingPartitions, IEnumerable<IntRange> testPartitions) {
+    private void AddModelsAndPartitions(IEnumerable<IRegressionModel> models, IEnumerable<IntRange> trainingPartitions, IEnumerable<IntRange> testPartitions) {
       var modelEnumerator = models.GetEnumerator();
       var trainingPartitionEnumerator = trainingPartitions.GetEnumerator();
Index: /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/RegressionSolution.cs
===================================================================
--- /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/RegressionSolution.cs	(revision 6610)
+++ /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/RegressionSolution.cs	(revision 6611)
@@ -23,6 +23,4 @@
 using System.Linq;
 using HeuristicLab.Common;
-using HeuristicLab.Data;
-using HeuristicLab.Optimization;
 using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
 
@@ -32,86 +30,19 @@
   /// </summary>
   [StorableClass]
-  public class RegressionSolution : DataAnalysisSolution, IRegressionSolution {
-    private const string TrainingMeanSquaredErrorResultName = "Mean squared error (training)";
-    private const string TestMeanSquaredErrorResultName = "Mean squared error (test)";
-    private const string TrainingSquaredCorrelationResultName = "Pearson's R² (training)";
-    private const string TestSquaredCorrelationResultName = "Pearson's R² (test)";
-    private const string TrainingRelativeErrorResultName = "Average relative error (training)";
-    private const string TestRelativeErrorResultName = "Average relative error (test)";
-    private const string TrainingNormalizedMeanSquaredErrorResultName = "Normalized mean squared error (training)";
-    private const string TestNormalizedMeanSquaredErrorResultName = "Normalized mean squared error (test)";
-
-    public new IRegressionModel Model {
-      get { return (IRegressionModel)base.Model; }
-      protected set { base.Model = value; }
-    }
-
-    public new IRegressionProblemData ProblemData {
-      get { return (IRegressionProblemData)base.ProblemData; }
-      protected set { base.ProblemData = value; }
-    }
-
-    public double TrainingMeanSquaredError {
-      get { return ((DoubleValue)this[TrainingMeanSquaredErrorResultName].Value).Value; }
-      private set { ((DoubleValue)this[TrainingMeanSquaredErrorResultName].Value).Value = value; }
-    }
-
-    public double TestMeanSquaredError {
-      get { return ((DoubleValue)this[TestMeanSquaredErrorResultName].Value).Value; }
-      private set { ((DoubleValue)this[TestMeanSquaredErrorResultName].Value).Value = value; }
-    }
-
-    public double TrainingRSquared {
-      get { return ((DoubleValue)this[TrainingSquaredCorrelationResultName].Value).Value; }
-      private set { ((DoubleValue)this[TrainingSquaredCorrelationResultName].Value).Value = value; }
-    }
-
-    public double TestRSquared {
-      get { return ((DoubleValue)this[TestSquaredCorrelationResultName].Value).Value; }
-      private set { ((DoubleValue)this[TestSquaredCorrelationResultName].Value).Value = value; }
-    }
-
-    public double TrainingRelativeError {
-      get { return ((DoubleValue)this[TrainingRelativeErrorResultName].Value).Value; }
-      private set { ((DoubleValue)this[TrainingRelativeErrorResultName].Value).Value = value; }
-    }
-
-    public double TestRelativeError {
-      get { return ((DoubleValue)this[TestRelativeErrorResultName].Value).Value; }
-      private set { ((DoubleValue)this[TestRelativeErrorResultName].Value).Value = value; }
-    }
-
-    public double TrainingNormalizedMeanSquaredError {
-      get { return ((DoubleValue)this[TrainingNormalizedMeanSquaredErrorResultName].Value).Value; }
-      private set { ((DoubleValue)this[TrainingNormalizedMeanSquaredErrorResultName].Value).Value = value; }
-    }
-
-    public double TestNormalizedMeanSquaredError {
-      get { return ((DoubleValue)this[TestNormalizedMeanSquaredErrorResultName].Value).Value; }
-      private set { ((DoubleValue)this[TestNormalizedMeanSquaredErrorResultName].Value).Value = value; }
-    }
-
+  public abstract class RegressionSolution : RegressionSolutionBase {
+    protected readonly Dictionary<int, double> evaluationCache;
 
     [StorableConstructor]
-    protected RegressionSolution(bool deserializing) : base(deserializing) { }
+    protected RegressionSolution(bool deserializing)
+      : base(deserializing) {
+      evaluationCache = new Dictionary<int, double>();
+    }
     protected RegressionSolution(RegressionSolution original, Cloner cloner)
       : base(original, cloner) {
+      evaluationCache = new Dictionary<int, double>(original.evaluationCache);
     }
-    public RegressionSolution(IRegressionModel model, IRegressionProblemData problemData)
+    protected RegressionSolution(IRegressionModel model, IRegressionProblemData problemData)
       : base(model, problemData) {
-      Add(new Result(TrainingMeanSquaredErrorResultName, "Mean of squared errors of the model on the training partition", new DoubleValue()));
-      Add(new Result(TestMeanSquaredErrorResultName, "Mean of squared errors of the model on the test partition", new DoubleValue()));
-      Add(new Result(TrainingSquaredCorrelationResultName, "Squared Pearson's correlation coefficient of the model output and the actual values on the training partition", new DoubleValue()));
-      Add(new Result(TestSquaredCorrelationResultName, "Squared Pearson's correlation coefficient of the model output and the actual values on the test partition", new DoubleValue()));
-      Add(new Result(TrainingRelativeErrorResultName, "Average of the relative errors of the model output and the actual values on the training partition", new PercentValue()));
-      Add(new Result(TestRelativeErrorResultName, "Average of the relative errors of the model output and the actual values on the test partition", new PercentValue()));
-      Add(new Result(TrainingNormalizedMeanSquaredErrorResultName, "Normalized mean of squared errors of the model on the training partition", new DoubleValue()));
-      Add(new Result(TestNormalizedMeanSquaredErrorResultName, "Normalized mean of squared errors of the model on the test partition", new DoubleValue()));
-
-      CalculateResults();
-    }
-
-    public override IDeepCloneable Clone(Cloner cloner) {
-      return new RegressionSolution(this, cloner);
+      evaluationCache = new Dictionary<int, double>();
     }
 
@@ -120,52 +51,34 @@
     }
 
-    private void CalculateResults() {
-      double[] estimatedTrainingValues = EstimatedTrainingValues.ToArray(); // cache values
-      IEnumerable<double> originalTrainingValues = ProblemData.Dataset.GetEnumeratedVariableValues(ProblemData.TargetVariable, ProblemData.TrainingIndizes);
-      double[] estimatedTestValues = EstimatedTestValues.ToArray(); // cache values
-      IEnumerable<double> originalTestValues = ProblemData.Dataset.GetEnumeratedVariableValues(ProblemData.TargetVariable, ProblemData.TestIndizes);
-
-      OnlineCalculatorError errorState;
-      double trainingMSE = OnlineMeanSquaredErrorCalculator.Calculate(estimatedTrainingValues, originalTrainingValues, out errorState);
-      TrainingMeanSquaredError = errorState == OnlineCalculatorError.None ? trainingMSE : double.NaN;
-      double testMSE = OnlineMeanSquaredErrorCalculator.Calculate(estimatedTestValues, originalTestValues, out errorState);
-      TestMeanSquaredError = errorState == OnlineCalculatorError.None ? testMSE : double.NaN;
-
-      double trainingR2 = OnlinePearsonsRSquaredCalculator.Calculate(estimatedTrainingValues, originalTrainingValues, out errorState);
-      TrainingRSquared = errorState == OnlineCalculatorError.None ? trainingR2 : double.NaN;
-      double testR2 = OnlinePearsonsRSquaredCalculator.Calculate(estimatedTestValues, originalTestValues, out errorState);
-      TestRSquared = errorState == OnlineCalculatorError.None ? testR2 : double.NaN;
-
-      double trainingRelError = OnlineMeanAbsolutePercentageErrorCalculator.Calculate(estimatedTrainingValues, originalTrainingValues, out errorState);
-      TrainingRelativeError = errorState == OnlineCalculatorError.None ? trainingRelError : double.NaN;
-      double testRelError = OnlineMeanAbsolutePercentageErrorCalculator.Calculate(estimatedTestValues, originalTestValues, out errorState);
-      TestRelativeError = errorState == OnlineCalculatorError.None ? testRelError : double.NaN;
-
-      double trainingNMSE = OnlineNormalizedMeanSquaredErrorCalculator.Calculate(estimatedTrainingValues, originalTrainingValues, out errorState);
-      TrainingNormalizedMeanSquaredError = errorState == OnlineCalculatorError.None ? trainingNMSE : double.NaN;
-      double testNMSE = OnlineNormalizedMeanSquaredErrorCalculator.Calculate(estimatedTestValues, originalTestValues, out errorState);
-      TestNormalizedMeanSquaredError = errorState == OnlineCalculatorError.None ? testNMSE : double.NaN;
+    public override IEnumerable<double> EstimatedValues {
+      get { return GetEstimatedValues(Enumerable.Range(0, ProblemData.Dataset.Rows)); }
+    }
+    public override IEnumerable<double> EstimatedTrainingValues {
+      get { return GetEstimatedValues(ProblemData.TrainingIndizes); }
+    }
+    public override IEnumerable<double> EstimatedTestValues {
+      get { return GetEstimatedValues(ProblemData.TestIndizes); }
     }
 
-    public virtual IEnumerable<double> EstimatedValues {
-      get {
-        return GetEstimatedValues(Enumerable.Range(0, ProblemData.Dataset.Rows));
+    public override IEnumerable<double> GetEstimatedValues(IEnumerable<int> rows) {
+      var rowsToEvaluate = rows.Except(evaluationCache.Keys);
+      var rowsEnumerator = rowsToEvaluate.GetEnumerator();
+      var valuesEnumerator = Model.GetEstimatedValues(ProblemData.Dataset, rowsToEvaluate).GetEnumerator();
+
+      while (rowsEnumerator.MoveNext() & valuesEnumerator.MoveNext()) {
+        evaluationCache.Add(rowsEnumerator.Current, valuesEnumerator.Current);
       }
+
+      return rows.Select(row => evaluationCache[row]);
     }
 
-    public virtual IEnumerable<double> EstimatedTrainingValues {
-      get {
-        return GetEstimatedValues(ProblemData.TrainingIndizes);
-      }
+    protected override void OnProblemDataChanged() {
+      evaluationCache.Clear();
+      base.OnProblemDataChanged();
     }
 
-    public virtual IEnumerable<double> EstimatedTestValues {
-      get {
-        return GetEstimatedValues(ProblemData.TestIndizes);
-      }
-    }
-
-    public virtual IEnumerable<double> GetEstimatedValues(IEnumerable<int> rows) {
-      return Model.GetEstimatedValues(ProblemData.Dataset, rows);
+    protected override void OnModelChanged() {
+      evaluationCache.Clear();
+      base.OnModelChanged();
     }
   }
Index: /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/RegressionSolutionBase.cs
===================================================================
--- /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/RegressionSolutionBase.cs	(revision 6611)
+++ /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/RegressionSolutionBase.cs	(revision 6611)
@@ -0,0 +1,136 @@
+﻿#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.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Data;
+using HeuristicLab.Optimization;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  [StorableClass]
+  public abstract class RegressionSolutionBase : DataAnalysisSolution, IRegressionSolution {
+    private const string TrainingMeanSquaredErrorResultName = "Mean squared error (training)";
+    private const string TestMeanSquaredErrorResultName = "Mean squared error (test)";
+    private const string TrainingSquaredCorrelationResultName = "Pearson's R² (training)";
+    private const string TestSquaredCorrelationResultName = "Pearson's R² (test)";
+    private const string TrainingRelativeErrorResultName = "Average relative error (training)";
+    private const string TestRelativeErrorResultName = "Average relative error (test)";
+    private const string TrainingNormalizedMeanSquaredErrorResultName = "Normalized mean squared error (training)";
+    private const string TestNormalizedMeanSquaredErrorResultName = "Normalized mean squared error (test)";
+
+    public new IRegressionModel Model {
+      get { return (IRegressionModel)base.Model; }
+      protected set { base.Model = value; }
+    }
+
+    public new IRegressionProblemData ProblemData {
+      get { return (IRegressionProblemData)base.ProblemData; }
+      protected set { base.ProblemData = value; }
+    }
+
+    public abstract IEnumerable<double> EstimatedValues { get; }
+    public abstract IEnumerable<double> EstimatedTrainingValues { get; }
+    public abstract IEnumerable<double> EstimatedTestValues { get; }
+    public abstract IEnumerable<double> GetEstimatedValues(IEnumerable<int> rows);
+
+    #region Results
+    public double TrainingMeanSquaredError {
+      get { return ((DoubleValue)this[TrainingMeanSquaredErrorResultName].Value).Value; }
+      private set { ((DoubleValue)this[TrainingMeanSquaredErrorResultName].Value).Value = value; }
+    }
+    public double TestMeanSquaredError {
+      get { return ((DoubleValue)this[TestMeanSquaredErrorResultName].Value).Value; }
+      private set { ((DoubleValue)this[TestMeanSquaredErrorResultName].Value).Value = value; }
+    }
+    public double TrainingRSquared {
+      get { return ((DoubleValue)this[TrainingSquaredCorrelationResultName].Value).Value; }
+      private set { ((DoubleValue)this[TrainingSquaredCorrelationResultName].Value).Value = value; }
+    }
+    public double TestRSquared {
+      get { return ((DoubleValue)this[TestSquaredCorrelationResultName].Value).Value; }
+      private set { ((DoubleValue)this[TestSquaredCorrelationResultName].Value).Value = value; }
+    }
+    public double TrainingRelativeError {
+      get { return ((DoubleValue)this[TrainingRelativeErrorResultName].Value).Value; }
+      private set { ((DoubleValue)this[TrainingRelativeErrorResultName].Value).Value = value; }
+    }
+    public double TestRelativeError {
+      get { return ((DoubleValue)this[TestRelativeErrorResultName].Value).Value; }
+      private set { ((DoubleValue)this[TestRelativeErrorResultName].Value).Value = value; }
+    }
+    public double TrainingNormalizedMeanSquaredError {
+      get { return ((DoubleValue)this[TrainingNormalizedMeanSquaredErrorResultName].Value).Value; }
+      private set { ((DoubleValue)this[TrainingNormalizedMeanSquaredErrorResultName].Value).Value = value; }
+    }
+    public double TestNormalizedMeanSquaredError {
+      get { return ((DoubleValue)this[TestNormalizedMeanSquaredErrorResultName].Value).Value; }
+      private set { ((DoubleValue)this[TestNormalizedMeanSquaredErrorResultName].Value).Value = value; }
+    }
+    #endregion
+
+    [StorableConstructor]
+    protected RegressionSolutionBase(bool deserializing) : base(deserializing) { }
+    protected RegressionSolutionBase(RegressionSolutionBase original, Cloner cloner)
+      : base(original, cloner) {
+    }
+    protected RegressionSolutionBase(IRegressionModel model, IRegressionProblemData problemData)
+      : base(model, problemData) {
+      Add(new Result(TrainingMeanSquaredErrorResultName, "Mean of squared errors of the model on the training partition", new DoubleValue()));
+      Add(new Result(TestMeanSquaredErrorResultName, "Mean of squared errors of the model on the test partition", new DoubleValue()));
+      Add(new Result(TrainingSquaredCorrelationResultName, "Squared Pearson's correlation coefficient of the model output and the actual values on the training partition", new DoubleValue()));
+      Add(new Result(TestSquaredCorrelationResultName, "Squared Pearson's correlation coefficient of the model output and the actual values on the test partition", new DoubleValue()));
+      Add(new Result(TrainingRelativeErrorResultName, "Average of the relative errors of the model output and the actual values on the training partition", new PercentValue()));
+      Add(new Result(TestRelativeErrorResultName, "Average of the relative errors of the model output and the actual values on the test partition", new PercentValue()));
+      Add(new Result(TrainingNormalizedMeanSquaredErrorResultName, "Normalized mean of squared errors of the model on the training partition", new DoubleValue()));
+      Add(new Result(TestNormalizedMeanSquaredErrorResultName, "Normalized mean of squared errors of the model on the test partition", new DoubleValue()));
+    }
+
+    protected void CalculateResults() {
+      double[] estimatedTrainingValues = EstimatedTrainingValues.ToArray(); // cache values
+      double[] originalTrainingValues = ProblemData.Dataset.GetEnumeratedVariableValues(ProblemData.TargetVariable, ProblemData.TrainingIndizes).ToArray();
+      double[] estimatedTestValues = EstimatedTestValues.ToArray(); // cache values
+      double[] originalTestValues = ProblemData.Dataset.GetEnumeratedVariableValues(ProblemData.TargetVariable, ProblemData.TestIndizes).ToArray();
+
+      OnlineCalculatorError errorState;
+      double trainingMSE = OnlineMeanSquaredErrorCalculator.Calculate(estimatedTrainingValues, originalTrainingValues, out errorState);
+      TrainingMeanSquaredError = errorState == OnlineCalculatorError.None ? trainingMSE : double.NaN;
+      double testMSE = OnlineMeanSquaredErrorCalculator.Calculate(estimatedTestValues, originalTestValues, out errorState);
+      TestMeanSquaredError = errorState == OnlineCalculatorError.None ? testMSE : double.NaN;
+
+      double trainingR2 = OnlinePearsonsRSquaredCalculator.Calculate(estimatedTrainingValues, originalTrainingValues, out errorState);
+      TrainingRSquared = errorState == OnlineCalculatorError.None ? trainingR2 : double.NaN;
+      double testR2 = OnlinePearsonsRSquaredCalculator.Calculate(estimatedTestValues, originalTestValues, out errorState);
+      TestRSquared = errorState == OnlineCalculatorError.None ? testR2 : double.NaN;
+
+      double trainingRelError = OnlineMeanAbsolutePercentageErrorCalculator.Calculate(estimatedTrainingValues, originalTrainingValues, out errorState);
+      TrainingRelativeError = errorState == OnlineCalculatorError.None ? trainingRelError : double.NaN;
+      double testRelError = OnlineMeanAbsolutePercentageErrorCalculator.Calculate(estimatedTestValues, originalTestValues, out errorState);
+      TestRelativeError = errorState == OnlineCalculatorError.None ? testRelError : double.NaN;
+
+      double trainingNMSE = OnlineNormalizedMeanSquaredErrorCalculator.Calculate(estimatedTrainingValues, originalTrainingValues, out errorState);
+      TrainingNormalizedMeanSquaredError = errorState == OnlineCalculatorError.None ? trainingNMSE : double.NaN;
+      double testNMSE = OnlineNormalizedMeanSquaredErrorCalculator.Calculate(estimatedTestValues, originalTestValues, out errorState);
+      TestNormalizedMeanSquaredError = errorState == OnlineCalculatorError.None ? testNMSE : double.NaN;
+    }
+  }
+}
Index: /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Classification/IClassificationModel.cs
===================================================================
--- /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Classification/IClassificationModel.cs	(revision 6610)
+++ /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Classification/IClassificationModel.cs	(revision 6611)
@@ -24,4 +24,5 @@
   public interface IClassificationModel : IDataAnalysisModel {
     IEnumerable<double> GetEstimatedClassValues(Dataset dataset, IEnumerable<int> rows);
+    IClassificationSolution CreateClassificationSolution(IClassificationProblemData problemData);
   }
 }
Index: /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Classification/IDiscriminantFunctionClassificationModel.cs
===================================================================
--- /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Classification/IDiscriminantFunctionClassificationModel.cs	(revision 6610)
+++ /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Classification/IDiscriminantFunctionClassificationModel.cs	(revision 6611)
@@ -20,6 +20,6 @@
 #endregion
 
+using System;
 using System.Collections.Generic;
-using System;
 namespace HeuristicLab.Problems.DataAnalysis {
   public interface IDiscriminantFunctionClassificationModel : IClassificationModel {
@@ -27,8 +27,10 @@
     IEnumerable<double> ClassValues { get; }
     // class values and thresholds can only be assigned simultaniously
-    void SetThresholdsAndClassValues(IEnumerable<double> thresholds, IEnumerable<double> classValues); 
+    void SetThresholdsAndClassValues(IEnumerable<double> thresholds, IEnumerable<double> classValues);
     IEnumerable<double> GetEstimatedValues(Dataset dataset, IEnumerable<int> rows);
 
     event EventHandler ThresholdsChanged;
+
+    IDiscriminantFunctionClassificationSolution CreateDiscriminantFunctionClassificationSolution(IClassificationProblemData problemData);
   }
 }
Index: /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Regression/IRegressionModel.cs
===================================================================
--- /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Regression/IRegressionModel.cs	(revision 6610)
+++ /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Regression/IRegressionModel.cs	(revision 6611)
@@ -24,4 +24,5 @@
   public interface IRegressionModel : IDataAnalysisModel {
     IEnumerable<double> GetEstimatedValues(Dataset dataset, IEnumerable<int> rows);
+    IRegressionSolution CreateRegressionSolution(IRegressionProblemData problemData);
   }
 }
Index: /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Regression/IRegressionSolution.cs
===================================================================
--- /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Regression/IRegressionSolution.cs	(revision 6610)
+++ /branches/QAPAlgorithms/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Regression/IRegressionSolution.cs	(revision 6611)
@@ -37,4 +37,6 @@
     double TrainingRelativeError { get; }
     double TestRelativeError { get; }
+    double TrainingNormalizedMeanSquaredError { get; }
+    double TestNormalizedMeanSquaredError { get; }
   }
 }
Index: /branches/QAPAlgorithms/HeuristicLab.Problems.VehicleRouting/3.3/Encodings/Potvin/Crossovers/PotvinInsertionBasedCrossover.cs
===================================================================
--- /branches/QAPAlgorithms/HeuristicLab.Problems.VehicleRouting/3.3/Encodings/Potvin/Crossovers/PotvinInsertionBasedCrossover.cs	(revision 6611)
+++ /branches/QAPAlgorithms/HeuristicLab.Problems.VehicleRouting/3.3/Encodings/Potvin/Crossovers/PotvinInsertionBasedCrossover.cs	(revision 6611)
@@ -0,0 +1,292 @@
+﻿#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 System.Collections.Generic;
+using HeuristicLab.Data;
+using System;
+using HeuristicLab.Parameters;
+
+namespace HeuristicLab.Problems.VehicleRouting.Encodings.Potvin {
+  [Item("PotvinInsertionBasedCrossover", "The IBX crossover for VRP representations. It is implemented as described in Berger, J and Solois, M and Begin, R (1998). A hybrid genetic algorithm for the vehicle routing problem with time windows. LNCS 1418. Springer, London 114-127.")]
+  [StorableClass]
+  public sealed class PotvinInsertionBasedCrossover : PotvinCrossover {
+    public IValueParameter<IntValue> Length {
+      get { return (IValueParameter<IntValue>)Parameters["Length"]; }
+    }
+
+    [StorableConstructor]
+    private PotvinInsertionBasedCrossover(bool deserializing) : base(deserializing) { }
+    private PotvinInsertionBasedCrossover(PotvinInsertionBasedCrossover original, Cloner cloner)
+      : base(original, cloner) {
+    }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new PotvinInsertionBasedCrossover(this, cloner);
+    }
+    public PotvinInsertionBasedCrossover()
+      : base() {
+      Parameters.Add(new ValueParameter<IntValue>("Length", "The maximum length of the replaced route.", new IntValue(1)));
+    }
+
+    private static int SelectRandomTourBiasedByLength(IRandom random, PotvinEncoding individual) {
+      int tourIndex = -1;
+
+      double sum = 0.0;
+      double[] probabilities = new double[individual.Tours.Count];
+      for (int i = 0; i < individual.Tours.Count; i++) {
+        probabilities[i] = 1.0 / ((double)individual.Tours[i].Cities.Count / (double)individual.Cities);
+        sum += probabilities[i];
+      }
+
+      double rand = random.NextDouble() * sum;
+      double cumulatedProbabilities = 0.0;
+      int index = 0;
+      while (tourIndex == -1 && index < probabilities.Length) {
+        if (cumulatedProbabilities <= rand && rand <= cumulatedProbabilities + probabilities[index])
+          tourIndex = index;
+
+        cumulatedProbabilities += probabilities[index];
+        index++;
+      }
+
+      return tourIndex;
+    }
+
+    private double CalculateCentroidDistance(Tour t1, Tour t2, DoubleMatrix coordinates) {
+      double xSum = 0;
+      double ySum = 0;
+      double c1X, c1Y, c2X, c2Y;
+
+      for (int i = 0; i < t1.Cities.Count; i++) {
+        xSum += coordinates[t1.Cities[i], 0];
+        ySum += coordinates[t1.Cities[i], 1];
+      }
+      c1X = xSum / t1.Cities.Count;
+      c1Y = ySum / t1.Cities.Count;
+
+      for (int i = 0; i < t2.Cities.Count; i++) {
+        xSum += coordinates[t2.Cities[i], 0];
+        ySum += coordinates[t2.Cities[i], 1];
+      }
+      c2X = xSum / t1.Cities.Count;
+      c2Y = ySum / t1.Cities.Count;
+
+      return Math.Sqrt(
+           (c1X - c2X) * (c1X - c2X) +
+           (c1Y - c2Y) * (c1Y - c2Y));
+    }
+
+    private double CalculateMeanCentroidDistance(Tour t1, IList<Tour> tours, DoubleMatrix coordinates) {
+      double sum = 0;
+
+      for (int i = 0; i < tours.Count; i++) {
+        sum += CalculateCentroidDistance(t1, tours[i], coordinates);
+      }
+
+      return sum / tours.Count;
+    }
+
+    private int SelectCityBiasedByNeighborDistance(IRandom random, Tour tour, DistanceMatrix distMatrix) {
+      int cityIndex = -1;
+
+      double sum = 0.0;
+      double[] probabilities = new double[tour.Cities.Count];
+      for (int i = 0; i < tour.Cities.Count; i++) {
+        int next;
+        if (i + 1 >= tour.Cities.Count)
+          next = 0;
+        else
+          next = tour.Cities[i + 1];
+        double distance = VRPUtilities.GetDistance(
+          tour.Cities[i], next, distMatrix);
+
+        int prev;
+        if (i - 1 < 0)
+          prev = 0;
+        else
+          prev = tour.Cities[i - 1];
+        distance += VRPUtilities.GetDistance(
+          tour.Cities[i], prev, distMatrix);
+
+        probabilities[i] = distance;
+        sum += probabilities[i];
+      }
+
+      double rand = random.NextDouble() * sum;
+      double cumulatedProbabilities = 0.0;
+      int index = 0;
+      while (cityIndex == -1 && index < probabilities.Length) {
+        if (cumulatedProbabilities <= rand && rand <= cumulatedProbabilities + probabilities[index])
+          cityIndex = index;
+
+        cumulatedProbabilities += probabilities[index];
+        index++;
+      }
+
+      return cityIndex;
+    }
+
+    private bool FindRouteInsertionPlace(
+      Tour tour,
+      DoubleArray dueTimeArray,
+      DoubleArray serviceTimeArray, DoubleArray readyTimeArray, DoubleArray demandArray, DoubleValue capacity,
+      DistanceMatrix distMatrix, int city, bool allowInfeasible, out int place) {
+      place = -1;
+      bool bestFeasible = false;
+      double minDetour = 0;
+
+      for (int i = 0; i <= tour.Cities.Count; i++) {
+        double length = tour.GetLength(distMatrix);
+
+        tour.Cities.Insert(i, city);
+
+        bool feasible = tour.Feasible(dueTimeArray, serviceTimeArray, readyTimeArray, demandArray,
+          capacity, distMatrix);
+
+        if (feasible || allowInfeasible && !bestFeasible) {
+          double newLength = tour.GetLength(distMatrix);
+          double detour = newLength - length;
+
+          if (place < 0 || detour < minDetour || feasible && !bestFeasible) {
+            place = i;
+            minDetour = detour;
+
+            if (feasible)
+              bestFeasible = true;
+          }
+        }
+
+        tour.Cities.RemoveAt(i);
+      }
+
+      return place >= 0;
+    }
+
+    private ICollection<int> GetUnrouted(PotvinEncoding solution, int cities) {
+      HashSet<int> undiscovered = new HashSet<int>();
+      for (int i = 1; i <= cities; i++) {
+        undiscovered.Add(i);
+      }
+
+      foreach (Tour tour in solution.Tours) {
+        foreach (int city in tour.Cities)
+          undiscovered.Remove(city);
+      }
+
+      return undiscovered;
+    }
+
+    protected override PotvinEncoding Crossover(IRandom random, PotvinEncoding parent1, PotvinEncoding parent2) {
+      PotvinEncoding child = new PotvinEncoding();
+
+      BoolValue useDistanceMatrix = UseDistanceMatrixParameter.ActualValue;
+      DoubleMatrix coordinates = CoordinatesParameter.ActualValue;
+      DistanceMatrix distMatrix = VRPUtilities.GetDistanceMatrix(coordinates, DistanceMatrixParameter, useDistanceMatrix);
+      DoubleArray dueTime = DueTimeParameter.ActualValue;
+      DoubleArray readyTime = ReadyTimeParameter.ActualValue;
+      DoubleArray serviceTime = ServiceTimeParameter.ActualValue;
+      DoubleArray demand = DemandParameter.ActualValue;
+      DoubleValue capacity = CapacityParameter.ActualValue;
+
+      bool allowInfeasible = AllowInfeasibleSolutions.Value.Value;
+
+      List<Tour> R1 = new List<Tour>();
+      PotvinEncoding p1Clone = parent1.Clone() as PotvinEncoding;
+
+      int length = Math.Min(Length.Value.Value, parent1.Tours.Count) + 1;
+      int k = random.Next(1, length);
+      for (int i = 0; i < k; i++) {
+        int index = SelectRandomTourBiasedByLength(random, p1Clone);
+        R1.Add(p1Clone.Tours[index]);
+        p1Clone.Tours.RemoveAt(index);
+      }
+
+      foreach (Tour r1 in R1) {
+        List<int> R2 = new List<int>();
+
+        double r = CalculateMeanCentroidDistance(r1, parent2.Tours, coordinates);
+        foreach (Tour tour in parent2.Tours) {
+          if (CalculateCentroidDistance(r1, tour, coordinates) <= r) {
+            R2.AddRange(tour.Cities);
+          }
+        }
+
+        Tour childTour = new Tour();
+        childTour.Cities.AddRange(r1.Cities);
+
+        //DESTROY - remove cities from r1
+        int removed = random.Next(1, r1.Cities.Count + 1);
+        for (int i = 0; i < removed; i++) {
+          childTour.Cities.RemoveAt(SelectCityBiasedByNeighborDistance(random, childTour, distMatrix));
+        }
+
+        //REPAIR - add cities from R2
+        int maxCount = random.Next(1, Math.Min(5, R2.Count));
+        int count = 0;
+
+        while (count < maxCount && R2.Count != 0) {
+          PotvinEncoding newChild = child.Clone() as PotvinEncoding;
+          newChild.Tours.Add(childTour);
+
+          int index = random.Next(R2.Count);
+          int city = R2[index];
+          R2.RemoveAt(index);
+
+          int place = -1;
+          if (FindRouteInsertionPlace(childTour, dueTime, serviceTime, readyTime,
+            demand, capacity, distMatrix, city, allowInfeasible, out place)) {
+            childTour.Cities.Insert(place, city);
+
+            if (!Repair(random, child, childTour, distMatrix, dueTime, readyTime, serviceTime, demand, capacity, allowInfeasible)) {
+              childTour.Cities.RemoveAt(place);
+            } else {
+              count++;
+            }
+          }
+        }
+
+        child.Tours.Add(childTour);
+        Repair(random, child, childTour, distMatrix, dueTime, readyTime, serviceTime, demand, capacity, allowInfeasible);
+      }
+
+      for (int i = 0; i < p1Clone.Tours.Count; i++) {
+        Tour childTour = p1Clone.Tours[i].Clone() as Tour;
+        child.Tours.Add(childTour);
+        Repair(random, child, childTour, distMatrix, dueTime, readyTime, serviceTime, demand, capacity, allowInfeasible);
+      }
+
+      //route unrouted customers
+      child.Unrouted.AddRange(GetUnrouted(child, Cities));
+      bool success = RouteUnrouted(child, distMatrix, dueTime, readyTime, serviceTime, demand, capacity, allowInfeasible);
+
+      if (success || allowInfeasible)
+        return child;
+      else {
+        if (random.NextDouble() < 0.5)
+          return parent1.Clone() as PotvinEncoding;
+        else
+          return parent2.Clone() as PotvinEncoding;
+      }
+    }
+  }
+}
Index: /branches/QAPAlgorithms/HeuristicLab.Problems.VehicleRouting/3.3/Encodings/Potvin/PotvinEncoding.cs
===================================================================
--- /branches/QAPAlgorithms/HeuristicLab.Problems.VehicleRouting/3.3/Encodings/Potvin/PotvinEncoding.cs	(revision 6610)
+++ /branches/QAPAlgorithms/HeuristicLab.Problems.VehicleRouting/3.3/Encodings/Potvin/PotvinEncoding.cs	(revision 6611)
@@ -75,5 +75,5 @@
       place = -1;
       bool bestFeasible = false;
-      double minDetour = 0;
+      double minDetour = double.MaxValue;
 
       for (int tour = 0; tour < Tours.Count; tour++) {
@@ -87,10 +87,9 @@
               capacity, distMatrix);
 
-            if ((!allowInfeasible && feasible) || (allowInfeasible && (!bestFeasible || feasible))) {
+            if (feasible || allowInfeasible && !bestFeasible) {
               double newLength = Tours[tour].GetLength(distMatrix);
               double detour = newLength - length;
 
-              if (route <= 0 || detour < minDetour ||
-                (allowInfeasible && ((!(bestFeasible && !feasible)) && detour < minDetour || (feasible && !bestFeasible)))) {
+              if (route < 0 || detour < minDetour || feasible && !bestFeasible) {
                 route = tour;
                 place = i;
Index: /branches/QAPAlgorithms/HeuristicLab.Problems.VehicleRouting/3.3/HeuristicLab.Problems.VehicleRouting-3.3.csproj
===================================================================
--- /branches/QAPAlgorithms/HeuristicLab.Problems.VehicleRouting/3.3/HeuristicLab.Problems.VehicleRouting-3.3.csproj	(revision 6610)
+++ /branches/QAPAlgorithms/HeuristicLab.Problems.VehicleRouting/3.3/HeuristicLab.Problems.VehicleRouting-3.3.csproj	(revision 6611)
@@ -114,4 +114,5 @@
     <Compile Include="Encodings\Alba\LocalImprovement\AlbaLambdaInterchangeLocalImprovementOperator.cs" />
     <Compile Include="Encodings\General\Creators\IterativeInsertionCreator.cs" />
+    <Compile Include="Encodings\Potvin\Crossovers\PotvinInsertionBasedCrossover.cs" />
     <Compile Include="Encodings\Potvin\Manipulators\PotvinLocalSearchManipulator.cs" />
     <Compile Include="Interfaces\IVRPMultiNeighborhoodShakingOperator.cs" />
Index: /branches/QAPAlgorithms/HeuristicLab/3.3/Tests/SamplesTest.cs
===================================================================
--- /branches/QAPAlgorithms/HeuristicLab/3.3/Tests/SamplesTest.cs	(revision 6610)
+++ /branches/QAPAlgorithms/HeuristicLab/3.3/Tests/SamplesTest.cs	(revision 6611)
@@ -121,6 +121,6 @@
       RunAlgorithm(ga);
       Assert.AreEqual(1828.9368669428336, GetDoubleResult(ga, "BestQuality"));
-      Assert.AreEqual(1829.6829520983711, GetDoubleResult(ga, "CurrentAverageQuality"));
-      Assert.AreEqual(1867.8378222145707, GetDoubleResult(ga, "CurrentWorstQuality"));
+      Assert.AreEqual(1831.5504074358635, GetDoubleResult(ga, "CurrentAverageQuality"));
+      Assert.AreEqual(1895.8980772167054, GetDoubleResult(ga, "CurrentWorstQuality"));
       Assert.AreEqual(99100, GetIntResult(ga, "EvaluatedSolutions"));
     }
