Index: trunk/sources/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ClassificationEnsembleModel.cs
===================================================================
--- trunk/sources/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ClassificationEnsembleModel.cs	(revision 6606)
+++ trunk/sources/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ClassificationEnsembleModel.cs	(revision 6613)
@@ -61,4 +61,7 @@
       models.Add(model);
     }
+    public void Remove(IClassificationModel model) {
+      models.Remove(model);
+    }
 
     public IEnumerable<IEnumerable<double>> GetEstimatedClassValueVectors(Dataset dataset, IEnumerable<int> rows) {
Index: trunk/sources/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ClassificationEnsembleSolution.cs
===================================================================
--- trunk/sources/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ClassificationEnsembleSolution.cs	(revision 6606)
+++ trunk/sources/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ClassificationEnsembleSolution.cs	(revision 6613)
@@ -23,4 +23,5 @@
 using System.Collections.Generic;
 using System.Linq;
+using HeuristicLab.Collections;
 using HeuristicLab.Common;
 using HeuristicLab.Core;
@@ -36,8 +37,11 @@
   // [Creatable("Data Analysis")]
   public sealed class ClassificationEnsembleSolution : ClassificationSolution, IClassificationEnsembleSolution {
-
     public new IClassificationEnsembleModel Model {
-      set { base.Model = value; }
       get { return (IClassificationEnsembleModel)base.Model; }
+    }
+
+    private readonly ItemCollection<IClassificationSolution> classificationSolutions;
+    public IItemCollection<IClassificationSolution> ClassificationSolutions {
+      get { return classificationSolutions; }
     }
 
@@ -47,7 +51,23 @@
     private Dictionary<IClassificationModel, IntRange> testPartitions;
 
-
     [StorableConstructor]
-    private ClassificationEnsembleSolution(bool deserializing) : base(deserializing) { }
+    private ClassificationEnsembleSolution(bool deserializing)
+      : base(deserializing) {
+      classificationSolutions = new ItemCollection<IClassificationSolution>();
+    }
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() {
+      foreach (var model in Model.Models) {
+        IClassificationProblemData problemData = (IClassificationProblemData)ProblemData.Clone();
+        problemData.TrainingPartition.Start = trainingPartitions[model].Start;
+        problemData.TrainingPartition.End = trainingPartitions[model].End;
+        problemData.TestPartition.Start = testPartitions[model].Start;
+        problemData.TestPartition.End = testPartitions[model].End;
+
+        classificationSolutions.Add(model.CreateClassificationSolution(problemData));
+      }
+      RegisterClassificationSolutionsEventHandler();
+    }
+
     private ClassificationEnsembleSolution(ClassificationEnsembleSolution original, Cloner cloner)
       : base(original, cloner) {
@@ -60,27 +80,41 @@
         testPartitions[cloner.Clone(pair.Key)] = cloner.Clone(pair.Value);
       }
-      RecalculateResults();
-    }
+
+      classificationSolutions = cloner.Clone(original.classificationSolutions);
+      RegisterClassificationSolutionsEventHandler();
+    }
+
     public ClassificationEnsembleSolution(IEnumerable<IClassificationModel> models, IClassificationProblemData problemData)
-      : base(new ClassificationEnsembleModel(models), new ClassificationEnsembleProblemData(problemData)) {
-      this.name = ItemName;
-      this.description = ItemDescription;
-      trainingPartitions = new Dictionary<IClassificationModel, IntRange>();
-      testPartitions = new Dictionary<IClassificationModel, IntRange>();
-      foreach (var model in models) {
-        trainingPartitions[model] = (IntRange)problemData.TrainingPartition.Clone();
-        testPartitions[model] = (IntRange)problemData.TestPartition.Clone();
-      }
-      RecalculateResults();
-    }
+      : this(models, problemData,
+             models.Select(m => (IntRange)problemData.TrainingPartition.Clone()),
+             models.Select(m => (IntRange)problemData.TestPartition.Clone())
+      ) { }
 
     public ClassificationEnsembleSolution(IEnumerable<IClassificationModel> models, IClassificationProblemData problemData, IEnumerable<IntRange> trainingPartitions, IEnumerable<IntRange> testPartitions)
-      : base(new ClassificationEnsembleModel(models), new ClassificationEnsembleProblemData(problemData)) {
+      : base(new ClassificationEnsembleModel(Enumerable.Empty<IClassificationModel>()), new ClassificationEnsembleProblemData(problemData)) {
       this.trainingPartitions = new Dictionary<IClassificationModel, IntRange>();
       this.testPartitions = new Dictionary<IClassificationModel, IntRange>();
-      AddModelsAndPartitions(models,
-        trainingPartitions,
-        testPartitions);
-      RecalculateResults();
+      this.classificationSolutions = new ItemCollection<IClassificationSolution>();
+
+      List<IClassificationSolution> solutions = new List<IClassificationSolution>();
+      var modelEnumerator = models.GetEnumerator();
+      var trainingPartitionEnumerator = trainingPartitions.GetEnumerator();
+      var testPartitionEnumerator = testPartitions.GetEnumerator();
+
+      while (modelEnumerator.MoveNext() & trainingPartitionEnumerator.MoveNext() & testPartitionEnumerator.MoveNext()) {
+        var p = (IClassificationProblemData)problemData.Clone();
+        p.TrainingPartition.Start = trainingPartitionEnumerator.Current.Start;
+        p.TrainingPartition.End = trainingPartitionEnumerator.Current.End;
+        p.TestPartition.Start = testPartitionEnumerator.Current.Start;
+        p.TestPartition.End = testPartitionEnumerator.Current.End;
+
+        solutions.Add(modelEnumerator.Current.CreateClassificationSolution(p));
+      }
+      if (modelEnumerator.MoveNext() | trainingPartitionEnumerator.MoveNext() | testPartitionEnumerator.MoveNext()) {
+        throw new ArgumentException();
+      }
+
+      RegisterClassificationSolutionsEventHandler();
+      classificationSolutions.AddRange(solutions);
     }
 
@@ -88,4 +122,9 @@
       return new ClassificationEnsembleSolution(this, cloner);
     }
+    private void RegisterClassificationSolutionsEventHandler() {
+      classificationSolutions.ItemsAdded += new CollectionItemsChangedEventHandler<IClassificationSolution>(classificationSolutions_ItemsAdded);
+      classificationSolutions.ItemsRemoved += new CollectionItemsChangedEventHandler<IClassificationSolution>(classificationSolutions_ItemsRemoved);
+      classificationSolutions.CollectionReset += new CollectionItemsChangedEventHandler<IClassificationSolution>(classificationSolutions_CollectionReset);
+    }
 
     protected override void RecalculateResults() {
@@ -93,4 +132,5 @@
     }
 
+    #region Evaluation
     public override IEnumerable<double> EstimatedTrainingClassValues {
       get {
@@ -166,41 +206,39 @@
       .First();
     }
-
-    public void AddModelsAndPartitions(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();
-        }
-      }
-
+    #endregion
+
+    public void AddClassificationSolutions(IEnumerable<IClassificationSolution> solutions) {
+      classificationSolutions.AddRange(solutions);
+    }
+    public void RemoveClassificationSolutions(IEnumerable<IClassificationSolution> solutions) {
+      classificationSolutions.RemoveRange(solutions);
+    }
+
+    private void classificationSolutions_ItemsAdded(object sender, CollectionItemsChangedEventArgs<IClassificationSolution> e) {
+      foreach (var solution in e.Items) AddClassificationSolution(solution);
       RecalculateResults();
     }
-
-    private void AddModelsAndPartitions(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();
-      }
+    private void classificationSolutions_ItemsRemoved(object sender, CollectionItemsChangedEventArgs<IClassificationSolution> e) {
+      foreach (var solution in e.Items) RemoveClassificationSolution(solution);
+      RecalculateResults();
+    }
+    private void classificationSolutions_CollectionReset(object sender, CollectionItemsChangedEventArgs<IClassificationSolution> e) {
+      foreach (var solution in e.OldItems) RemoveClassificationSolution(solution);
+      foreach (var solution in e.Items) AddClassificationSolution(solution);
+      RecalculateResults();
+    }
+
+    private void AddClassificationSolution(IClassificationSolution solution) {
+      if (Model.Models.Contains(solution.Model)) throw new ArgumentException();
+      Model.Add(solution.Model);
+      trainingPartitions[solution.Model] = solution.ProblemData.TrainingPartition;
+      testPartitions[solution.Model] = solution.ProblemData.TestPartition;
+    }
+
+    private void RemoveClassificationSolution(IClassificationSolution solution) {
+      if (!Model.Models.Contains(solution.Model)) throw new ArgumentException();
+      Model.Remove(solution.Model);
+      trainingPartitions.Remove(solution.Model);
+      testPartitions.Remove(solution.Model);
     }
   }
