Index: /trunk/sources/HeuristicLab.Problems.DataAnalysis.Views/3.4/Classification/ClassificationSolutionConfusionMatrixView.cs
===================================================================
--- /trunk/sources/HeuristicLab.Problems.DataAnalysis.Views/3.4/Classification/ClassificationSolutionConfusionMatrixView.cs	(revision 6519)
+++ /trunk/sources/HeuristicLab.Problems.DataAnalysis.Views/3.4/Classification/ClassificationSolutionConfusionMatrixView.cs	(revision 6520)
@@ -78,6 +78,6 @@
           dataGridView.ColumnCount = 1;
         } else {
-          dataGridView.ColumnCount = Content.ProblemData.Classes;
-          dataGridView.RowCount = Content.ProblemData.Classes;
+          dataGridView.ColumnCount = Content.ProblemData.Classes + 1;
+          dataGridView.RowCount = Content.ProblemData.Classes + 1;
 
           int i = 0;
@@ -87,4 +87,7 @@
             i++;
           }
+          dataGridView.Columns[i].HeaderText = "Actual not classified";
+          dataGridView.Rows[i].HeaderCell.Value = "Predicted not classified";
+
           dataGridView.AutoResizeColumns(DataGridViewAutoSizeColumnsMode.ColumnHeader);
           dataGridView.AutoResizeRowHeadersWidth(DataGridViewRowHeadersWidthSizeMode.AutoSizeToAllHeaders);
@@ -100,5 +103,5 @@
         if (Content == null) return;
 
-        double[,] confusionMatrix = new double[Content.ProblemData.Classes, Content.ProblemData.Classes];
+        double[,] confusionMatrix = new double[Content.ProblemData.Classes + 1, Content.ProblemData.Classes + 1];
         IEnumerable<int> rows;
 
@@ -109,5 +112,5 @@
         } else if (cmbSamples.SelectedItem.ToString() == TestSamples) {
           rows = Content.ProblemData.TestIndizes;
-          predictedValues = Content.EstimatedTestClassValues.ToArray();          
+          predictedValues = Content.EstimatedTestClassValues.ToArray();
         } else throw new InvalidOperationException();
 
@@ -124,6 +127,12 @@
           double targetValue = targetValues[i];
           double predictedValue = predictedValues[i];
-          int targetIndex = classValueIndexMapping[targetValue];
-          int predictedIndex = classValueIndexMapping[predictedValue];
+          int targetIndex;
+          int predictedIndex;
+          if (!classValueIndexMapping.TryGetValue(targetValue, out targetIndex)) {
+            targetIndex = Content.ProblemData.Classes;
+          }
+          if (!classValueIndexMapping.TryGetValue(predictedValue, out predictedIndex)) {
+            predictedIndex = Content.ProblemData.Classes;
+          }
 
           confusionMatrix[predictedIndex, targetIndex] += 1;
Index: /trunk/sources/HeuristicLab.Problems.DataAnalysis.Views/3.4/HeuristicLab.Problems.DataAnalysis.Views-3.4.csproj
===================================================================
--- /trunk/sources/HeuristicLab.Problems.DataAnalysis.Views/3.4/HeuristicLab.Problems.DataAnalysis.Views-3.4.csproj	(revision 6519)
+++ /trunk/sources/HeuristicLab.Problems.DataAnalysis.Views/3.4/HeuristicLab.Problems.DataAnalysis.Views-3.4.csproj	(revision 6520)
@@ -181,4 +181,5 @@
     </Compile>
     <Compile Include="Interfaces\IRegressionSolutionEvaluationView.cs" />
+    <Compile Include="MenuItems\CreateEnsembleMenuItem.cs" />
     <Compile Include="RegressionSolutionView.cs">
       <SubType>UserControl</SubType>
@@ -269,4 +270,8 @@
       <Project>{14AB8D24-25BC-400C-A846-4627AA945192}</Project>
       <Name>HeuristicLab.Optimization-3.3</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\..\HeuristicLab.Optimizer\3.3\HeuristicLab.Optimizer-3.3.csproj">
+      <Project>{C664305E-497C-4533-A140-967DEDB05C19}</Project>
+      <Name>HeuristicLab.Optimizer-3.3</Name>
     </ProjectReference>
     <ProjectReference Include="..\..\HeuristicLab.Parameters.Views\3.3\HeuristicLab.Parameters.Views-3.3.csproj">
Index: /trunk/sources/HeuristicLab.Problems.DataAnalysis.Views/3.4/HeuristicLabProblemsDataAnalysisViewsPlugin.cs.frame
===================================================================
--- /trunk/sources/HeuristicLab.Problems.DataAnalysis.Views/3.4/HeuristicLabProblemsDataAnalysisViewsPlugin.cs.frame	(revision 6519)
+++ /trunk/sources/HeuristicLab.Problems.DataAnalysis.Views/3.4/HeuristicLabProblemsDataAnalysisViewsPlugin.cs.frame	(revision 6520)
@@ -39,4 +39,5 @@
   [PluginDependency("HeuristicLab.Optimization","3.3")]
   [PluginDependency("HeuristicLab.Optimization.Views","3.3")]
+  [PluginDependency("HeuristicLab.Optimizer", "3.3")]
   [PluginDependency("HeuristicLab.Problems.DataAnalysis", "3.4")]
   [PluginDependency("HeuristicLab.Visualization.ChartControlsExtensions", "3.3")]
Index: /trunk/sources/HeuristicLab.Problems.DataAnalysis.Views/3.4/MenuItems/CreateEnsembleMenuItem.cs
===================================================================
--- /trunk/sources/HeuristicLab.Problems.DataAnalysis.Views/3.4/MenuItems/CreateEnsembleMenuItem.cs	(revision 6520)
+++ /trunk/sources/HeuristicLab.Problems.DataAnalysis.Views/3.4/MenuItems/CreateEnsembleMenuItem.cs	(revision 6520)
@@ -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.Linq;
+using System.Collections.Generic;
+using System.Windows.Forms;
+using HeuristicLab.MainForm;
+using HeuristicLab.Optimization;
+using HeuristicLab.Optimizer;
+using HeuristicLab.Core;
+
+namespace HeuristicLab.Problems.DataAnalysis.MenuItems {
+  internal class CreateEnsembleMenuItem : HeuristicLab.MainForm.WindowsForms.MenuItem, IOptimizerUserInterfaceItemProvider {
+    public override string Name {
+      get { return "Create &Solution Ensembles"; }
+    }
+    public override IEnumerable<string> Structure {
+      get { return new string[] { "&Edit" }; }
+    }
+    public override int Position {
+      get { return 2500; }
+    }
+    public override string ToolTipText {
+      get { return "Create ensembles of data analysis solutions from the solutions in the current optimizer."; }
+    }
+
+    protected override void OnToolStripItemSet(EventArgs e) {
+      ToolStripItem.Enabled = false;
+    }
+    protected override void OnActiveViewChanged(object sender, EventArgs e) {
+      IContentView activeView = MainFormManager.MainForm.ActiveView as IContentView;
+      if ((activeView != null) && (activeView.Content != null) && (activeView.Content is IOptimizer) && !activeView.Locked) {
+        var optimizer = activeView.Content as IOptimizer;
+        ToolStripItem.Enabled = GetDataAnalysisResults(optimizer).Any();
+      } else {
+        ToolStripItem.Enabled = false;
+      }
+    }
+
+    public override void Execute() {
+      IContentView activeView = MainFormManager.MainForm.ActiveView as IContentView;
+      if ((activeView != null) && (activeView.Content != null) && (activeView.Content is IOptimizer) && !activeView.Locked) {
+        var optimizer = activeView.Content as IOptimizer;
+        var solutionGroups = from pair in GetDataAnalysisResults(optimizer)
+                             group pair.Value by new { pair.Key } into g
+                             select g;
+        foreach (var group in solutionGroups) {
+          // check if all solutions in the group are either only regression or only classification solutions
+          if (group.All(s => s is IRegressionSolution)) {
+            // show all regression ensembles
+            // clone problemdata (N.B. this assumes all solutions are based on the same problem data!)
+            var problemData = (RegressionProblemData)group
+              .OfType<IRegressionSolution>()
+              .First()
+              .ProblemData.Clone();
+            var ensemble = new RegressionEnsembleSolution(Enumerable.Empty<IRegressionModel>(), problemData);
+            ensemble.Name = group.Key + " ensemble";
+            ensemble.AddModelsAndParitions(group.OfType<IRegressionSolution>());
+            MainFormManager.MainForm.ShowContent(ensemble);
+          } else if (group.All(s => s is IClassificationSolution)) {
+            // show all classification ensembles
+            var problemData = (ClassificationProblemData)group
+              .OfType<IClassificationSolution>()
+              .First()
+              .ProblemData.Clone();
+            var ensemble = new ClassificationEnsembleSolution(Enumerable.Empty<IClassificationModel>(), problemData);
+            ensemble.Name = group.Key + " ensemble";
+            ensemble.AddModelsAndParitions(group.OfType<IClassificationSolution>());
+            MainFormManager.MainForm.ShowContent(ensemble);
+          }
+        }
+      }
+    }
+
+    private IEnumerable<KeyValuePair<string, IItem>> GetDataAnalysisResults(IOptimizer optimizer) {
+      var allResults = from r in optimizer.Runs
+                       select r.Results;
+      return from r in allResults
+             from result in r
+             let s = result.Value as IDataAnalysisSolution
+             where s != null
+             select result;
+    }
+  }
+}
Index: /trunk/sources/HeuristicLab.Problems.DataAnalysis.Views/3.4/Regression/RegressionSolutionLineChartView.cs
===================================================================
--- /trunk/sources/HeuristicLab.Problems.DataAnalysis.Views/3.4/Regression/RegressionSolutionLineChartView.cs	(revision 6519)
+++ /trunk/sources/HeuristicLab.Problems.DataAnalysis.Views/3.4/Regression/RegressionSolutionLineChartView.cs	(revision 6520)
@@ -198,5 +198,5 @@
       // strip range is [start .. end] inclusive, but we evaluate [start..end[ (end is exclusive)
       // the strip should be by one longer (starting at start - 0.5 and ending at end + 0.5)
-      stripLine.StripWidth = end - start; 
+      stripLine.StripWidth = end - start;
       stripLine.IntervalOffset = start - 0.5; // start slightly to the left of the first point to clearly indicate the first point in the partition
       this.chart.ChartAreas[0].AxisX.StripLines.Add(stripLine);
Index: /trunk/sources/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ClassificationEnsembleModel.cs
===================================================================
--- /trunk/sources/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ClassificationEnsembleModel.cs	(revision 6519)
+++ /trunk/sources/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ClassificationEnsembleModel.cs	(revision 6520)
@@ -58,4 +58,7 @@
 
     #region IClassificationEnsembleModel Members
+    public void Add(IClassificationModel model) {
+      models.Add(model);
+    }
 
     public IEnumerable<IEnumerable<double>> GetEstimatedClassValueVectors(Dataset dataset, IEnumerable<int> rows) {
Index: /trunk/sources/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ClassificationEnsembleProblemData.cs
===================================================================
--- /trunk/sources/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ClassificationEnsembleProblemData.cs	(revision 6519)
+++ /trunk/sources/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ClassificationEnsembleProblemData.cs	(revision 6520)
@@ -37,5 +37,5 @@
     public override IEnumerable<int> TrainingIndizes {
       get {
-        return Enumerable.Range(TrainingPartition.Start, TestPartition.End - TestPartition.Start);
+        return Enumerable.Range(TrainingPartition.Start, TrainingPartition.End - TrainingPartition.Start);
       }
     }
Index: /trunk/sources/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ClassificationEnsembleSolution.cs
===================================================================
--- /trunk/sources/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ClassificationEnsembleSolution.cs	(revision 6519)
+++ /trunk/sources/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ClassificationEnsembleSolution.cs	(revision 6520)
@@ -79,14 +79,7 @@
       this.trainingPartitions = new Dictionary<IClassificationModel, IntRange>();
       this.testPartitions = new Dictionary<IClassificationModel, IntRange>();
-      var modelEnumerator = models.GetEnumerator();
-      var trainingPartitionEnumerator = trainingPartitions.GetEnumerator();
-      var testPartitionEnumerator = testPartitions.GetEnumerator();
-      while (modelEnumerator.MoveNext() & trainingPartitionEnumerator.MoveNext() & testPartitionEnumerator.MoveNext()) {
-        this.trainingPartitions[modelEnumerator.Current] = (IntRange)trainingPartitionEnumerator.Current.Clone();
-        this.testPartitions[modelEnumerator.Current] = (IntRange)testPartitionEnumerator.Current.Clone();
-      }
-      if (modelEnumerator.MoveNext() | trainingPartitionEnumerator.MoveNext() | testPartitionEnumerator.MoveNext()) {
-        throw new ArgumentException();
-      }
+      AddModelsAndParitions(models,
+        trainingPartitions,
+        testPartitions);
       RecalculateResults();
     }
@@ -169,4 +162,42 @@
       .First();
     }
+
+    public void AddModelsAndParitions(IEnumerable<IClassificationSolution> solutions) {
+      foreach (var solution in solutions) {
+        var ensembleSolution = solution as ClassificationEnsembleSolution;
+        if (ensembleSolution != null) {
+          var data = from m in ensembleSolution.Model.Models
+                     let train = ensembleSolution.trainingPartitions[m]
+                     let test = ensembleSolution.testPartitions[m]
+                     select new { m, train, test };
+
+          foreach (var d in data) {
+            Model.Add(d.m);
+            trainingPartitions[d.m] = (IntRange)d.train.Clone();
+            testPartitions[d.m] = (IntRange)d.test.Clone();
+          }
+        } else {
+          Model.Add(solution.Model);
+          trainingPartitions[solution.Model] = (IntRange)solution.ProblemData.TrainingPartition.Clone();
+          testPartitions[solution.Model] = (IntRange)solution.ProblemData.TestPartition.Clone();
+        }
+      }
+
+      RecalculateResults();
+    }
+
+    private void AddModelsAndParitions(IEnumerable<IClassificationModel> models, IEnumerable<IntRange> trainingPartitions, IEnumerable<IntRange> testPartitions) {
+      var modelEnumerator = models.GetEnumerator();
+      var trainingPartitionEnumerator = trainingPartitions.GetEnumerator();
+      var testPartitionEnumerator = testPartitions.GetEnumerator();
+
+      while (modelEnumerator.MoveNext() & trainingPartitionEnumerator.MoveNext() & testPartitionEnumerator.MoveNext()) {
+        this.trainingPartitions[modelEnumerator.Current] = (IntRange)trainingPartitionEnumerator.Current.Clone();
+        this.testPartitions[modelEnumerator.Current] = (IntRange)testPartitionEnumerator.Current.Clone();
+      }
+      if (modelEnumerator.MoveNext() | trainingPartitionEnumerator.MoveNext() | testPartitionEnumerator.MoveNext()) {
+        throw new ArgumentException();
+      }
+    }
   }
 }
Index: /trunk/sources/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/RegressionEnsembleModel.cs
===================================================================
--- /trunk/sources/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/RegressionEnsembleModel.cs	(revision 6519)
+++ /trunk/sources/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/RegressionEnsembleModel.cs	(revision 6520)
@@ -58,4 +58,8 @@
     #region IRegressionEnsembleModel Members
 
+    public void Add(IRegressionModel model) {
+      models.Add(model);
+    }
+
     public IEnumerable<IEnumerable<double>> GetEstimatedValueVectors(Dataset dataset, IEnumerable<int> rows) {
       var estimatedValuesEnumerators = (from model in models
Index: /trunk/sources/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/RegressionEnsembleSolution.cs
===================================================================
--- /trunk/sources/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/RegressionEnsembleSolution.cs	(revision 6519)
+++ /trunk/sources/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/RegressionEnsembleSolution.cs	(revision 6520)
@@ -64,8 +64,7 @@
       trainingPartitions = new Dictionary<IRegressionModel, IntRange>();
       testPartitions = new Dictionary<IRegressionModel, IntRange>();
-      foreach (var model in models) {
-        trainingPartitions[model] = (IntRange)problemData.TrainingPartition.Clone();
-        testPartitions[model] = (IntRange)problemData.TestPartition.Clone();
-      }
+      AddModelsAndParitions(models,
+        from m in models select (IntRange)problemData.TrainingPartition.Clone(),
+        from m in models select (IntRange)problemData.TestPartition.Clone());
       RecalculateResults();
     }
@@ -75,14 +74,5 @@
       this.trainingPartitions = new Dictionary<IRegressionModel, IntRange>();
       this.testPartitions = new Dictionary<IRegressionModel, IntRange>();
-      var modelEnumerator = models.GetEnumerator();
-      var trainingPartitionEnumerator = trainingPartitions.GetEnumerator();
-      var testPartitionEnumerator = testPartitions.GetEnumerator();
-      while (modelEnumerator.MoveNext() & trainingPartitionEnumerator.MoveNext() & testPartitionEnumerator.MoveNext()) {
-        this.trainingPartitions[modelEnumerator.Current] = (IntRange)trainingPartitionEnumerator.Current.Clone();
-        this.testPartitions[modelEnumerator.Current] = (IntRange)testPartitionEnumerator.Current.Clone();
-      }
-      if (modelEnumerator.MoveNext() | trainingPartitionEnumerator.MoveNext() | testPartitionEnumerator.MoveNext()) {
-        throw new ArgumentException();
-      }
+      AddModelsAndParitions(models, trainingPartitions, testPartitions);
       RecalculateResults();
     }
@@ -160,4 +150,43 @@
       return estimatedValues.DefaultIfEmpty(double.NaN).Average();
     }
+
+
+    public void AddModelsAndParitions(IEnumerable<IRegressionSolution> solutions) {
+      foreach (var solution in solutions) {
+        var ensembleSolution = solution as RegressionEnsembleSolution;
+        if (ensembleSolution != null) {
+          var data = from m in ensembleSolution.Model.Models
+                     let train = ensembleSolution.trainingPartitions[m]
+                     let test = ensembleSolution.testPartitions[m]
+                     select new { m, train, test };
+
+          foreach (var d in data) {
+            Model.Add(d.m);
+            trainingPartitions[d.m] = (IntRange)d.train.Clone();
+            testPartitions[d.m] = (IntRange)d.test.Clone();
+          }
+        } else {
+          Model.Add(solution.Model);
+          trainingPartitions[solution.Model] = (IntRange)solution.ProblemData.TrainingPartition.Clone();
+          testPartitions[solution.Model] = (IntRange)solution.ProblemData.TestPartition.Clone();
+        }
+      }
+
+      RecalculateResults();
+    }
+
+    private void AddModelsAndParitions(IEnumerable<IRegressionModel> models, IEnumerable<IntRange> trainingPartitions, IEnumerable<IntRange> testPartitions) {
+      var modelEnumerator = models.GetEnumerator();
+      var trainingPartitionEnumerator = trainingPartitions.GetEnumerator();
+      var testPartitionEnumerator = testPartitions.GetEnumerator();
+
+      while (modelEnumerator.MoveNext() & trainingPartitionEnumerator.MoveNext() & testPartitionEnumerator.MoveNext()) {
+        this.trainingPartitions[modelEnumerator.Current] = (IntRange)trainingPartitionEnumerator.Current.Clone();
+        this.testPartitions[modelEnumerator.Current] = (IntRange)testPartitionEnumerator.Current.Clone();
+      }
+      if (modelEnumerator.MoveNext() | trainingPartitionEnumerator.MoveNext() | testPartitionEnumerator.MoveNext()) {
+        throw new ArgumentException();
+      }
+    }
   }
 }
Index: /trunk/sources/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Classification/IClassificationEnsembleModel.cs
===================================================================
--- /trunk/sources/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Classification/IClassificationEnsembleModel.cs	(revision 6519)
+++ /trunk/sources/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Classification/IClassificationEnsembleModel.cs	(revision 6520)
@@ -23,4 +23,5 @@
 namespace HeuristicLab.Problems.DataAnalysis {
   public interface IClassificationEnsembleModel : IClassificationModel {
+    void Add(IClassificationModel model);
     IEnumerable<IClassificationModel> Models { get; }
     IEnumerable<IEnumerable<double>> GetEstimatedClassValueVectors(Dataset dataset, IEnumerable<int> rows);
Index: /trunk/sources/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Regression/IRegressionEnsembleModel.cs
===================================================================
--- /trunk/sources/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Regression/IRegressionEnsembleModel.cs	(revision 6519)
+++ /trunk/sources/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/Regression/IRegressionEnsembleModel.cs	(revision 6520)
@@ -23,4 +23,5 @@
 namespace HeuristicLab.Problems.DataAnalysis {
   public interface IRegressionEnsembleModel : IRegressionModel {
+    void Add(IRegressionModel model);
     IEnumerable<IRegressionModel> Models { get; }
     IEnumerable<IEnumerable<double>> GetEstimatedValueVectors(Dataset dataset, IEnumerable<int> rows);
