Index: trunk/sources/HeuristicLab.Analysis/3.3/Allele.cs
===================================================================
--- trunk/sources/HeuristicLab.Analysis/3.3/Allele.cs	(revision 4870)
+++ 	(revision )
@@ -1,87 +1,0 @@
-#region License Information
-/* HeuristicLab
- * Copyright (C) 2002-2010 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
- *
- * This file is part of HeuristicLab.
- *
- * HeuristicLab is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * HeuristicLab is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
- */
-#endregion
-
-using HeuristicLab.Common;
-using HeuristicLab.Core;
-using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
-
-namespace HeuristicLab.Analysis {
-  /// <summary>
-  /// Represents an allele of a solution which is used for allele analysis.
-  /// </summary>
-  [Item("Allele", "Represents an allele of a solution which is used for allele analysis.")]
-  [StorableClass]
-  public class Allele : Item {
-    private string id;
-    public string Id {
-      get { return id; }
-    }
-    private double impact;
-    public double Impact {
-      get { return impact; }
-    }
-
-    #region Storable Properties
-    [Storable(Name = "Id")]
-    private string StorableId {
-      get { return id; }
-      set { id = value; }
-    }
-    [Storable(Name = "Impact")]
-    private double StorableImpact {
-      get { return impact; }
-      set { impact = value; }
-    }
-    #endregion
-
-    #region Storing & Cloning
-    [StorableConstructor]
-    protected Allele(bool deserializing) : base(deserializing) { }
-    protected Allele(Allele original, Cloner cloner)
-      : base(original, cloner) {
-      this.id = original.id;
-      this.impact = original.impact;
-    }
-    public override IDeepCloneable Clone(Cloner cloner) {
-      return new Allele(this, cloner);
-    }
-    #endregion
-    public Allele()
-      : base() {
-      this.id = string.Empty;
-      this.impact = 0;
-    }
-    public Allele(string id)
-      : base() {
-      this.id = id;
-      this.impact = 0;
-    }
-    public Allele(string id, double impact)
-      : base() {
-      this.id = id;
-      this.impact = impact;
-    }
-
-    public override string ToString() {
-      return id + " (" + impact + ")";
-    }
-  }
-}
Index: trunk/sources/HeuristicLab.Analysis/3.3/AlleleFrequency.cs
===================================================================
--- trunk/sources/HeuristicLab.Analysis/3.3/AlleleFrequency.cs	(revision 4870)
+++ 	(revision )
@@ -1,130 +1,0 @@
-#region License Information
-/* HeuristicLab
- * Copyright (C) 2002-2010 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
- *
- * This file is part of HeuristicLab.
- *
- * HeuristicLab is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * HeuristicLab is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
- */
-#endregion
-
-using HeuristicLab.Common;
-using HeuristicLab.Core;
-using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
-
-namespace HeuristicLab.Analysis {
-  /// <summary>
-  /// Represents the frequency of an allele.
-  /// </summary>
-  [Item("AlleleFrequency", "Represents the frequency of an allele.")]
-  [StorableClass]
-  public class AlleleFrequency : Item {
-    private string id;
-    public string Id {
-      get { return id; }
-    }
-    private double frequency;
-    public double Frequency {
-      get { return frequency; }
-    }
-    private double averageImpact;
-    public double AverageImpact {
-      get { return averageImpact; }
-    }
-    private double averageSolutionQuality;
-    public double AverageSolutionQuality {
-      get { return averageSolutionQuality; }
-    }
-    private bool containedInBestKnownSolution;
-    public bool ContainedInBestKnownSolution {
-      get { return containedInBestKnownSolution; }
-    }
-    private bool containedInBestSolution;
-    public bool ContainedInBestSolution {
-      get { return containedInBestSolution; }
-    }
-
-    #region Storable Properties
-    [Storable(Name = "Id")]
-    private string StorableId {
-      get { return id; }
-      set { id = value; }
-    }
-    [Storable(Name = "Frequency")]
-    private double StorableFrequency {
-      get { return frequency; }
-      set { frequency = value; }
-    }
-    [Storable(Name = "AverageImpact")]
-    private double StorableAverageImpact {
-      get { return averageImpact; }
-      set { averageImpact = value; }
-    }
-    [Storable(Name = "AverageSolutionQuality")]
-    private double StorableAverageSolutionQuality {
-      get { return averageSolutionQuality; }
-      set { averageSolutionQuality = value; }
-    }
-    [Storable(Name = "ContainedInBestKnownSolution")]
-    private bool StorableContainedInBestKnownSolution {
-      get { return containedInBestKnownSolution; }
-      set { containedInBestKnownSolution = value; }
-    }
-    [Storable(Name = "ContainedInBestSolution")]
-    private bool StorableContainedInBestSolution {
-      get { return containedInBestSolution; }
-      set { containedInBestSolution = value; }
-    }
-    #endregion
-
-    #region Storing & Cloning
-    [StorableConstructor]
-    protected AlleleFrequency(bool deserializing) : base(deserializing) { }
-    protected AlleleFrequency(AlleleFrequency original, Cloner cloner)
-      : base(original, cloner) {
-      this.id = original.id;
-      this.frequency = original.frequency;
-      this.averageImpact = original.averageImpact;
-      this.averageSolutionQuality = original.averageSolutionQuality;
-      this.containedInBestKnownSolution = original.containedInBestKnownSolution;
-      this.containedInBestSolution = original.containedInBestSolution;
-    }
-    public override IDeepCloneable Clone(Cloner cloner) {
-      return new AlleleFrequency(this, cloner);
-    }
-    #endregion
-    public AlleleFrequency()
-      : base() {
-      id = string.Empty;
-      frequency = 0;
-      averageImpact = 0;
-      averageSolutionQuality = 0;
-      containedInBestKnownSolution = false;
-      containedInBestSolution = false;
-    }
-    public AlleleFrequency(string id, double frequency, double averageImpact, double averageSolutionQuality, bool containedInBestKnownSolution, bool containedInBestSolution)
-      : base() {
-      this.id = id;
-      this.frequency = frequency;
-      this.averageImpact = averageImpact;
-      this.averageSolutionQuality = averageSolutionQuality;
-      this.containedInBestKnownSolution = containedInBestKnownSolution;
-      this.containedInBestSolution = containedInBestSolution;
-    }
-
-    public override string ToString() {
-      return id;
-    }
-  }
-}
Index: trunk/sources/HeuristicLab.Analysis/3.3/AlleleFrequencyAnalysis/Allele.cs
===================================================================
--- trunk/sources/HeuristicLab.Analysis/3.3/AlleleFrequencyAnalysis/Allele.cs	(revision 4887)
+++ trunk/sources/HeuristicLab.Analysis/3.3/AlleleFrequencyAnalysis/Allele.cs	(revision 4887)
@@ -0,0 +1,87 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2010 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Analysis {
+  /// <summary>
+  /// Represents an allele of a solution which is used for allele analysis.
+  /// </summary>
+  [Item("Allele", "Represents an allele of a solution which is used for allele analysis.")]
+  [StorableClass]
+  public class Allele : Item {
+    private string id;
+    public string Id {
+      get { return id; }
+    }
+    private double impact;
+    public double Impact {
+      get { return impact; }
+    }
+
+    #region Storable Properties
+    [Storable(Name = "Id")]
+    private string StorableId {
+      get { return id; }
+      set { id = value; }
+    }
+    [Storable(Name = "Impact")]
+    private double StorableImpact {
+      get { return impact; }
+      set { impact = value; }
+    }
+    #endregion
+
+    #region Storing & Cloning
+    [StorableConstructor]
+    protected Allele(bool deserializing) : base(deserializing) { }
+    protected Allele(Allele original, Cloner cloner)
+      : base(original, cloner) {
+      this.id = original.id;
+      this.impact = original.impact;
+    }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new Allele(this, cloner);
+    }
+    #endregion
+    public Allele()
+      : base() {
+      this.id = string.Empty;
+      this.impact = 0;
+    }
+    public Allele(string id)
+      : base() {
+      this.id = id;
+      this.impact = 0;
+    }
+    public Allele(string id, double impact)
+      : base() {
+      this.id = id;
+      this.impact = impact;
+    }
+
+    public override string ToString() {
+      return id + " (" + impact + ")";
+    }
+  }
+}
Index: trunk/sources/HeuristicLab.Analysis/3.3/AlleleFrequencyAnalysis/AlleleFrequency.cs
===================================================================
--- trunk/sources/HeuristicLab.Analysis/3.3/AlleleFrequencyAnalysis/AlleleFrequency.cs	(revision 4887)
+++ trunk/sources/HeuristicLab.Analysis/3.3/AlleleFrequencyAnalysis/AlleleFrequency.cs	(revision 4887)
@@ -0,0 +1,130 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2010 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Analysis {
+  /// <summary>
+  /// Represents the frequency of an allele.
+  /// </summary>
+  [Item("AlleleFrequency", "Represents the frequency of an allele.")]
+  [StorableClass]
+  public class AlleleFrequency : Item {
+    private string id;
+    public string Id {
+      get { return id; }
+    }
+    private double frequency;
+    public double Frequency {
+      get { return frequency; }
+    }
+    private double averageImpact;
+    public double AverageImpact {
+      get { return averageImpact; }
+    }
+    private double averageSolutionQuality;
+    public double AverageSolutionQuality {
+      get { return averageSolutionQuality; }
+    }
+    private bool containedInBestKnownSolution;
+    public bool ContainedInBestKnownSolution {
+      get { return containedInBestKnownSolution; }
+    }
+    private bool containedInBestSolution;
+    public bool ContainedInBestSolution {
+      get { return containedInBestSolution; }
+    }
+
+    #region Storable Properties
+    [Storable(Name = "Id")]
+    private string StorableId {
+      get { return id; }
+      set { id = value; }
+    }
+    [Storable(Name = "Frequency")]
+    private double StorableFrequency {
+      get { return frequency; }
+      set { frequency = value; }
+    }
+    [Storable(Name = "AverageImpact")]
+    private double StorableAverageImpact {
+      get { return averageImpact; }
+      set { averageImpact = value; }
+    }
+    [Storable(Name = "AverageSolutionQuality")]
+    private double StorableAverageSolutionQuality {
+      get { return averageSolutionQuality; }
+      set { averageSolutionQuality = value; }
+    }
+    [Storable(Name = "ContainedInBestKnownSolution")]
+    private bool StorableContainedInBestKnownSolution {
+      get { return containedInBestKnownSolution; }
+      set { containedInBestKnownSolution = value; }
+    }
+    [Storable(Name = "ContainedInBestSolution")]
+    private bool StorableContainedInBestSolution {
+      get { return containedInBestSolution; }
+      set { containedInBestSolution = value; }
+    }
+    #endregion
+
+    #region Storing & Cloning
+    [StorableConstructor]
+    protected AlleleFrequency(bool deserializing) : base(deserializing) { }
+    protected AlleleFrequency(AlleleFrequency original, Cloner cloner)
+      : base(original, cloner) {
+      this.id = original.id;
+      this.frequency = original.frequency;
+      this.averageImpact = original.averageImpact;
+      this.averageSolutionQuality = original.averageSolutionQuality;
+      this.containedInBestKnownSolution = original.containedInBestKnownSolution;
+      this.containedInBestSolution = original.containedInBestSolution;
+    }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new AlleleFrequency(this, cloner);
+    }
+    #endregion
+    public AlleleFrequency()
+      : base() {
+      id = string.Empty;
+      frequency = 0;
+      averageImpact = 0;
+      averageSolutionQuality = 0;
+      containedInBestKnownSolution = false;
+      containedInBestSolution = false;
+    }
+    public AlleleFrequency(string id, double frequency, double averageImpact, double averageSolutionQuality, bool containedInBestKnownSolution, bool containedInBestSolution)
+      : base() {
+      this.id = id;
+      this.frequency = frequency;
+      this.averageImpact = averageImpact;
+      this.averageSolutionQuality = averageSolutionQuality;
+      this.containedInBestKnownSolution = containedInBestKnownSolution;
+      this.containedInBestSolution = containedInBestSolution;
+    }
+
+    public override string ToString() {
+      return id;
+    }
+  }
+}
Index: trunk/sources/HeuristicLab.Analysis/3.3/AlleleFrequencyAnalysis/AlleleFrequencyAnalyzer.cs
===================================================================
--- trunk/sources/HeuristicLab.Analysis/3.3/AlleleFrequencyAnalysis/AlleleFrequencyAnalyzer.cs	(revision 4887)
+++ trunk/sources/HeuristicLab.Analysis/3.3/AlleleFrequencyAnalysis/AlleleFrequencyAnalyzer.cs	(revision 4887)
@@ -0,0 +1,245 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2010 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Operators;
+using HeuristicLab.Optimization;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Analysis {
+  /// <summary>
+  /// An operator for analyzing the frequency of alleles.
+  /// </summary>
+  [Item("AlleleFrequencyAnalyzer", "An operator for analyzing the frequency of alleles.")]
+  [StorableClass]
+  public abstract class AlleleFrequencyAnalyzer<T> : SingleSuccessorOperator, IAnalyzer where T : class, IItem {
+    public LookupParameter<BoolValue> MaximizationParameter {
+      get { return (LookupParameter<BoolValue>)Parameters["Maximization"]; }
+    }
+    public ScopeTreeLookupParameter<T> SolutionParameter {
+      get { return (ScopeTreeLookupParameter<T>)Parameters["Solution"]; }
+    }
+    public ScopeTreeLookupParameter<DoubleValue> QualityParameter {
+      get { return (ScopeTreeLookupParameter<DoubleValue>)Parameters["Quality"]; }
+    }
+    public LookupParameter<T> BestKnownSolutionParameter {
+      get { return (LookupParameter<T>)Parameters["BestKnownSolution"]; }
+    }
+    public ValueLookupParameter<ResultCollection> ResultsParameter {
+      get { return (ValueLookupParameter<ResultCollection>)Parameters["Results"]; }
+    }
+    public ValueParameter<BoolValue> StoreHistoryParameter {
+      get { return (ValueParameter<BoolValue>)Parameters["StoreHistory"]; }
+    }
+    public ValueParameter<IntValue> UpdateIntervalParameter {
+      get { return (ValueParameter<IntValue>)Parameters["UpdateInterval"]; }
+    }
+    public LookupParameter<IntValue> UpdateCounterParameter {
+      get { return (LookupParameter<IntValue>)Parameters["UpdateCounter"]; }
+    }
+
+    [StorableConstructor]
+    protected AlleleFrequencyAnalyzer(bool deserializing) : base(deserializing) { }
+    protected AlleleFrequencyAnalyzer(AlleleFrequencyAnalyzer<T> original, Cloner cloner) : base(original, cloner) { }
+    public AlleleFrequencyAnalyzer()
+      : base() {
+      Parameters.Add(new LookupParameter<BoolValue>("Maximization", "True if the problem is a maximization problem."));
+      Parameters.Add(new ScopeTreeLookupParameter<T>("Solution", "The solutions whose alleles should be analyzed."));
+      Parameters.Add(new ScopeTreeLookupParameter<DoubleValue>("Quality", "The qualities of the solutions which should be analyzed."));
+      Parameters.Add(new LookupParameter<T>("BestKnownSolution", "The best known solution."));
+      Parameters.Add(new ValueLookupParameter<ResultCollection>("Results", "The result collection where the allele frequency analysis results should be stored."));
+      Parameters.Add(new ValueParameter<BoolValue>("StoreHistory", "True if the history of the allele frequency analysis should be stored.", new BoolValue(false)));
+      Parameters.Add(new ValueParameter<IntValue>("UpdateInterval", "The interval in which the allele frequency analysis should be applied.", new IntValue(1)));
+      Parameters.Add(new LookupParameter<IntValue>("UpdateCounter", "The value which counts how many times the operator was called since the last update.", "AlleleFrequencyAnalyzerUpdateCounter"));
+    }
+
+    #region AlleleFrequencyIdEqualityComparer
+    private class AlleleFrequencyIdEqualityComparer : IEqualityComparer<AlleleFrequency> {
+      public bool Equals(AlleleFrequency x, AlleleFrequency y) {
+        return x.Id == y.Id;
+      }
+      public int GetHashCode(AlleleFrequency obj) {
+        return obj.Id.GetHashCode();
+      }
+    }
+    #endregion
+
+    public override IOperation Apply() {
+      int updateInterval = UpdateIntervalParameter.Value.Value;
+      IntValue updateCounter = UpdateCounterParameter.ActualValue;
+      if (updateCounter == null) {
+        updateCounter = new IntValue(updateInterval);
+        UpdateCounterParameter.ActualValue = updateCounter;
+      } else updateCounter.Value++;
+
+      if (updateCounter.Value == updateInterval) {
+        updateCounter.Value = 0;
+
+        bool max = MaximizationParameter.ActualValue.Value;
+        ItemArray<T> solutions = SolutionParameter.ActualValue;
+        ItemArray<DoubleValue> qualities = QualityParameter.ActualValue;
+        T bestKnownSolution = BestKnownSolutionParameter.ActualValue;
+        bool storeHistory = StoreHistoryParameter.Value.Value;
+
+        // calculate index of current best solution
+        int bestIndex = -1;
+        if (!max) {
+          bestIndex = qualities
+            .Select((x, index) => new { index, x.Value })
+            .OrderBy(x => x.Value)
+            .First().index;
+        } else {
+          bestIndex = qualities
+            .Select((x, index) => new { index, x.Value })
+            .OrderByDescending(x => x.Value)
+            .First().index;
+        }
+
+        // calculate allels of current best and (if available) best known solution
+        Allele[] bestAlleles = CalculateAlleles(solutions[bestIndex]);
+        Allele[] bestKnownAlleles = null;
+        if (bestKnownSolution != null)
+          bestKnownAlleles = CalculateAlleles(bestKnownSolution);
+
+        // calculate allele frequencies
+        var frequencies = solutions.SelectMany((s, index) => CalculateAlleles(s).Select(a => new { Allele = a, Quality = qualities[index] })).
+                          GroupBy(x => x.Allele.Id).
+                          Select(x => new AlleleFrequency(x.Key,
+                                                          x.Count() / ((double)solutions.Length),
+                                                          x.Average(a => a.Allele.Impact),
+                                                          x.Average(a => a.Quality.Value),
+                                                          bestKnownAlleles == null ? false : bestKnownAlleles.Any(a => a.Id == x.Key),
+                                                          bestAlleles.Any(a => a.Id == x.Key)));
+
+        // calculate dummy allele frequencies of alleles of best known solution which did not occur
+        if (bestKnownAlleles != null) {
+          var bestKnownFrequencies = bestKnownAlleles.Select(x => new AlleleFrequency(x.Id, 0, x.Impact, 0, true, false)).Except(frequencies, new AlleleFrequencyIdEqualityComparer());
+          frequencies = frequencies.Concat(bestKnownFrequencies);
+        }
+
+        // fetch results collection
+        ResultCollection results;
+        if (!ResultsParameter.ActualValue.ContainsKey("Allele Frequency Analysis Results")) {
+          results = new ResultCollection();
+          ResultsParameter.ActualValue.Add(new Result("Allele Frequency Analysis Results", results));
+        } else {
+          results = (ResultCollection)ResultsParameter.ActualValue["Allele Frequency Analysis Results"].Value;
+        }
+
+        // store allele frequencies
+        AlleleFrequencyCollection frequenciesCollection = new AlleleFrequencyCollection(frequencies);
+        if (!results.ContainsKey("Allele Frequencies"))
+          results.Add(new Result("Allele Frequencies", frequenciesCollection));
+        else
+          results["Allele Frequencies"].Value = frequenciesCollection;
+
+        // store allele frequencies history
+        if (storeHistory) {
+          if (!results.ContainsKey("Allele Frequencies History")) {
+            AlleleFrequencyCollectionHistory history = new AlleleFrequencyCollectionHistory();
+            history.Add(frequenciesCollection);
+            results.Add(new Result("Allele Frequencies History", history));
+          } else {
+            ((AlleleFrequencyCollectionHistory)results["Allele Frequencies History"].Value).Add(frequenciesCollection);
+          }
+        }
+
+        // store alleles data table
+        DataTable allelesTable;
+        if (!results.ContainsKey("Alleles")) {
+          allelesTable = new DataTable("Alleles");
+          allelesTable.VisualProperties.XAxisTitle = "Iteration";
+          allelesTable.VisualProperties.YAxisTitle = "Number of Alleles";
+          allelesTable.VisualProperties.SecondYAxisTitle = "Number of Alleles";
+
+          allelesTable.Rows.Add(new DataRow("Unique Alleles"));
+          allelesTable.Rows["Unique Alleles"].VisualProperties.StartIndexZero = true;
+
+          allelesTable.Rows.Add(new DataRow("Unique Alleles of Best Known Solution", null));
+          allelesTable.Rows["Unique Alleles of Best Known Solution"].VisualProperties.SecondYAxis = true;
+          allelesTable.Rows["Unique Alleles of Best Known Solution"].VisualProperties.StartIndexZero = true;
+
+          allelesTable.Rows.Add(new DataRow("Fixed Alleles", null));
+          allelesTable.Rows["Fixed Alleles"].VisualProperties.SecondYAxis = true;
+          allelesTable.Rows["Fixed Alleles"].VisualProperties.StartIndexZero = true;
+
+          allelesTable.Rows.Add(new DataRow("Fixed Alleles of Best Known Solution", null));
+          allelesTable.Rows["Fixed Alleles of Best Known Solution"].VisualProperties.SecondYAxis = true;
+          allelesTable.Rows["Fixed Alleles of Best Known Solution"].VisualProperties.StartIndexZero = true;
+
+          allelesTable.Rows.Add(new DataRow("Lost Alleles of Best Known Solution", null));
+          allelesTable.Rows["Lost Alleles of Best Known Solution"].VisualProperties.SecondYAxis = true;
+          allelesTable.Rows["Lost Alleles of Best Known Solution"].VisualProperties.StartIndexZero = true;
+
+          results.Add(new Result("Alleles", allelesTable));
+        } else {
+          allelesTable = (DataTable)results["Alleles"].Value;
+        }
+
+        int fixedAllelesCount = frequenciesCollection.Where(x => x.Frequency == 1).Count();
+        var relevantAlleles = frequenciesCollection.Where(x => x.ContainedInBestKnownSolution);
+        int relevantAllelesCount = relevantAlleles.Count();
+        int fixedRelevantAllelesCount = relevantAlleles.Where(x => x.Frequency == 1).Count();
+        int lostRelevantAllelesCount = relevantAlleles.Where(x => x.Frequency == 0).Count();
+        int uniqueRelevantAllelesCount = relevantAllelesCount - lostRelevantAllelesCount;
+        allelesTable.Rows["Unique Alleles"].Values.Add(frequenciesCollection.Count);
+        allelesTable.Rows["Unique Alleles of Best Known Solution"].Values.Add(uniqueRelevantAllelesCount);
+        allelesTable.Rows["Fixed Alleles"].Values.Add(fixedAllelesCount);
+        allelesTable.Rows["Fixed Alleles of Best Known Solution"].Values.Add(fixedRelevantAllelesCount);
+        allelesTable.Rows["Lost Alleles of Best Known Solution"].Values.Add(lostRelevantAllelesCount);
+
+        // store alleles values
+        if (!results.ContainsKey("Unique Alleles"))
+          results.Add(new Result("Unique Alleles", new DoubleValue(frequenciesCollection.Count)));
+        else
+          ((DoubleValue)results["Unique Alleles"].Value).Value = frequenciesCollection.Count;
+
+        if (!results.ContainsKey("Unique Alleles of Best Known Solution"))
+          results.Add(new Result("Unique Alleles of Best Known Solution", new DoubleValue(uniqueRelevantAllelesCount)));
+        else
+          ((DoubleValue)results["Unique Alleles of Best Known Solution"].Value).Value = uniqueRelevantAllelesCount;
+
+        if (!results.ContainsKey("Fixed Alleles"))
+          results.Add(new Result("Fixed Alleles", new DoubleValue(fixedAllelesCount)));
+        else
+          ((DoubleValue)results["Fixed Alleles"].Value).Value = fixedAllelesCount;
+
+        if (!results.ContainsKey("Fixed Alleles of Best Known Solution"))
+          results.Add(new Result("Fixed Alleles of Best Known Solution", new DoubleValue(fixedRelevantAllelesCount)));
+        else
+          ((DoubleValue)results["Fixed Alleles of Best Known Solution"].Value).Value = fixedRelevantAllelesCount;
+
+        if (!results.ContainsKey("Lost Alleles of Best Known Solution"))
+          results.Add(new Result("Lost Alleles of Best Known Solution", new DoubleValue(lostRelevantAllelesCount)));
+        else
+          ((DoubleValue)results["Lost Alleles of Best Known Solution"].Value).Value = lostRelevantAllelesCount;
+      }
+      return base.Apply();
+    }
+
+    protected abstract Allele[] CalculateAlleles(T solution);
+  }
+}
Index: trunk/sources/HeuristicLab.Analysis/3.3/AlleleFrequencyAnalysis/AlleleFrequencyCollection.cs
===================================================================
--- trunk/sources/HeuristicLab.Analysis/3.3/AlleleFrequencyAnalysis/AlleleFrequencyCollection.cs	(revision 4887)
+++ trunk/sources/HeuristicLab.Analysis/3.3/AlleleFrequencyAnalysis/AlleleFrequencyCollection.cs	(revision 4887)
@@ -0,0 +1,49 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2010 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Collections.Generic;
+using System.Drawing;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Analysis {
+  /// <summary>
+  /// Represents a collection of allele frequencies.
+  /// </summary>
+  [Item("AlleleFrequencyCollection", "Represents a collection of allele frequencies.")]
+  [StorableClass]
+  public class AlleleFrequencyCollection : ReadOnlyItemCollection<AlleleFrequency> {
+    public override Image ItemImage {
+      get { return HeuristicLab.Common.Resources.VS2008ImageLibrary.Statistics; }
+    }
+
+    [StorableConstructor]
+    protected AlleleFrequencyCollection(bool deserializing) : base(deserializing) { }
+    protected AlleleFrequencyCollection(AlleleFrequencyCollection original, Cloner cloner) : base(original, cloner) { }
+    public AlleleFrequencyCollection() : base() { }
+    public AlleleFrequencyCollection(IEnumerable<AlleleFrequency> frequencies) : base(new ItemCollection<AlleleFrequency>(frequencies)) { }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new AlleleFrequencyCollection(this, cloner);
+    }
+  }
+}
Index: trunk/sources/HeuristicLab.Analysis/3.3/AlleleFrequencyAnalysis/AlleleFrequencyCollectionHistory.cs
===================================================================
--- trunk/sources/HeuristicLab.Analysis/3.3/AlleleFrequencyAnalysis/AlleleFrequencyCollectionHistory.cs	(revision 4887)
+++ trunk/sources/HeuristicLab.Analysis/3.3/AlleleFrequencyAnalysis/AlleleFrequencyCollectionHistory.cs	(revision 4887)
@@ -0,0 +1,49 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2010 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Collections.Generic;
+using System.Drawing;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Analysis {
+  /// <summary>
+  /// Represents history values of allele frequencies collections.
+  /// </summary>
+  [Item("AlleleFrequencyCollectionHistory", "Represents history values of allele frequencies collections.")]
+  [StorableClass]
+  public class AlleleFrequencyCollectionHistory : ItemCollection<AlleleFrequencyCollection> {
+    public override Image ItemImage {
+      get { return HeuristicLab.Common.Resources.VS2008ImageLibrary.Cab; }
+    }
+
+    [StorableConstructor]
+    protected AlleleFrequencyCollectionHistory(bool deserializing) : base(deserializing) { }
+    protected AlleleFrequencyCollectionHistory(AlleleFrequencyCollectionHistory original, Cloner cloner) : base(original, cloner) { }
+    public AlleleFrequencyCollectionHistory() : base() { }
+    public AlleleFrequencyCollectionHistory(IEnumerable<AlleleFrequencyCollection> collections) : base(new ItemCollection<AlleleFrequencyCollection>(collections)) { }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new AlleleFrequencyCollectionHistory(this, cloner);
+    }
+  }
+}
Index: trunk/sources/HeuristicLab.Analysis/3.3/AlleleFrequencyAnalyzer.cs
===================================================================
--- trunk/sources/HeuristicLab.Analysis/3.3/AlleleFrequencyAnalyzer.cs	(revision 4870)
+++ 	(revision )
@@ -1,245 +1,0 @@
-#region License Information
-/* HeuristicLab
- * Copyright (C) 2002-2010 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
- *
- * This file is part of HeuristicLab.
- *
- * HeuristicLab is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * HeuristicLab is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
- */
-#endregion
-
-using System.Collections.Generic;
-using System.Linq;
-using HeuristicLab.Common;
-using HeuristicLab.Core;
-using HeuristicLab.Data;
-using HeuristicLab.Operators;
-using HeuristicLab.Optimization;
-using HeuristicLab.Parameters;
-using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
-
-namespace HeuristicLab.Analysis {
-  /// <summary>
-  /// An operator for analyzing the frequency of alleles.
-  /// </summary>
-  [Item("AlleleFrequencyAnalyzer", "An operator for analyzing the frequency of alleles.")]
-  [StorableClass]
-  public abstract class AlleleFrequencyAnalyzer<T> : SingleSuccessorOperator, IAnalyzer where T : class, IItem {
-    public LookupParameter<BoolValue> MaximizationParameter {
-      get { return (LookupParameter<BoolValue>)Parameters["Maximization"]; }
-    }
-    public ScopeTreeLookupParameter<T> SolutionParameter {
-      get { return (ScopeTreeLookupParameter<T>)Parameters["Solution"]; }
-    }
-    public ScopeTreeLookupParameter<DoubleValue> QualityParameter {
-      get { return (ScopeTreeLookupParameter<DoubleValue>)Parameters["Quality"]; }
-    }
-    public LookupParameter<T> BestKnownSolutionParameter {
-      get { return (LookupParameter<T>)Parameters["BestKnownSolution"]; }
-    }
-    public ValueLookupParameter<ResultCollection> ResultsParameter {
-      get { return (ValueLookupParameter<ResultCollection>)Parameters["Results"]; }
-    }
-    public ValueParameter<BoolValue> StoreHistoryParameter {
-      get { return (ValueParameter<BoolValue>)Parameters["StoreHistory"]; }
-    }
-    public ValueParameter<IntValue> UpdateIntervalParameter {
-      get { return (ValueParameter<IntValue>)Parameters["UpdateInterval"]; }
-    }
-    public LookupParameter<IntValue> UpdateCounterParameter {
-      get { return (LookupParameter<IntValue>)Parameters["UpdateCounter"]; }
-    }
-
-    [StorableConstructor]
-    protected AlleleFrequencyAnalyzer(bool deserializing) : base(deserializing) { }
-    protected AlleleFrequencyAnalyzer(AlleleFrequencyAnalyzer<T> original, Cloner cloner) : base(original, cloner) { }
-    public AlleleFrequencyAnalyzer()
-      : base() {
-      Parameters.Add(new LookupParameter<BoolValue>("Maximization", "True if the problem is a maximization problem."));
-      Parameters.Add(new ScopeTreeLookupParameter<T>("Solution", "The solutions whose alleles should be analyzed."));
-      Parameters.Add(new ScopeTreeLookupParameter<DoubleValue>("Quality", "The qualities of the solutions which should be analyzed."));
-      Parameters.Add(new LookupParameter<T>("BestKnownSolution", "The best known solution."));
-      Parameters.Add(new ValueLookupParameter<ResultCollection>("Results", "The result collection where the allele frequency analysis results should be stored."));
-      Parameters.Add(new ValueParameter<BoolValue>("StoreHistory", "True if the history of the allele frequency analysis should be stored.", new BoolValue(false)));
-      Parameters.Add(new ValueParameter<IntValue>("UpdateInterval", "The interval in which the allele frequency analysis should be applied.", new IntValue(1)));
-      Parameters.Add(new LookupParameter<IntValue>("UpdateCounter", "The value which counts how many times the operator was called since the last update.", "AlleleFrequencyAnalyzerUpdateCounter"));
-    }
-
-    #region AlleleFrequencyIdEqualityComparer
-    private class AlleleFrequencyIdEqualityComparer : IEqualityComparer<AlleleFrequency> {
-      public bool Equals(AlleleFrequency x, AlleleFrequency y) {
-        return x.Id == y.Id;
-      }
-      public int GetHashCode(AlleleFrequency obj) {
-        return obj.Id.GetHashCode();
-      }
-    }
-    #endregion
-
-    public override IOperation Apply() {
-      int updateInterval = UpdateIntervalParameter.Value.Value;
-      IntValue updateCounter = UpdateCounterParameter.ActualValue;
-      if (updateCounter == null) {
-        updateCounter = new IntValue(updateInterval);
-        UpdateCounterParameter.ActualValue = updateCounter;
-      } else updateCounter.Value++;
-
-      if (updateCounter.Value == updateInterval) {
-        updateCounter.Value = 0;
-
-        bool max = MaximizationParameter.ActualValue.Value;
-        ItemArray<T> solutions = SolutionParameter.ActualValue;
-        ItemArray<DoubleValue> qualities = QualityParameter.ActualValue;
-        T bestKnownSolution = BestKnownSolutionParameter.ActualValue;
-        bool storeHistory = StoreHistoryParameter.Value.Value;
-
-        // calculate index of current best solution
-        int bestIndex = -1;
-        if (!max) {
-          bestIndex = qualities
-            .Select((x, index) => new { index, x.Value })
-            .OrderBy(x => x.Value)
-            .First().index;
-        } else {
-          bestIndex = qualities
-            .Select((x, index) => new { index, x.Value })
-            .OrderByDescending(x => x.Value)
-            .First().index;
-        }
-
-        // calculate allels of current best and (if available) best known solution
-        Allele[] bestAlleles = CalculateAlleles(solutions[bestIndex]);
-        Allele[] bestKnownAlleles = null;
-        if (bestKnownSolution != null)
-          bestKnownAlleles = CalculateAlleles(bestKnownSolution);
-
-        // calculate allele frequencies
-        var frequencies = solutions.SelectMany((s, index) => CalculateAlleles(s).Select(a => new { Allele = a, Quality = qualities[index] })).
-                          GroupBy(x => x.Allele.Id).
-                          Select(x => new AlleleFrequency(x.Key,
-                                                          x.Count() / ((double)solutions.Length),
-                                                          x.Average(a => a.Allele.Impact),
-                                                          x.Average(a => a.Quality.Value),
-                                                          bestKnownAlleles == null ? false : bestKnownAlleles.Any(a => a.Id == x.Key),
-                                                          bestAlleles.Any(a => a.Id == x.Key)));
-
-        // calculate dummy allele frequencies of alleles of best known solution which did not occur
-        if (bestKnownAlleles != null) {
-          var bestKnownFrequencies = bestKnownAlleles.Select(x => new AlleleFrequency(x.Id, 0, x.Impact, 0, true, false)).Except(frequencies, new AlleleFrequencyIdEqualityComparer());
-          frequencies = frequencies.Concat(bestKnownFrequencies);
-        }
-
-        // fetch results collection
-        ResultCollection results;
-        if (!ResultsParameter.ActualValue.ContainsKey("Allele Frequency Analysis Results")) {
-          results = new ResultCollection();
-          ResultsParameter.ActualValue.Add(new Result("Allele Frequency Analysis Results", results));
-        } else {
-          results = (ResultCollection)ResultsParameter.ActualValue["Allele Frequency Analysis Results"].Value;
-        }
-
-        // store allele frequencies
-        AlleleFrequencyCollection frequenciesCollection = new AlleleFrequencyCollection(frequencies);
-        if (!results.ContainsKey("Allele Frequencies"))
-          results.Add(new Result("Allele Frequencies", frequenciesCollection));
-        else
-          results["Allele Frequencies"].Value = frequenciesCollection;
-
-        // store allele frequencies history
-        if (storeHistory) {
-          if (!results.ContainsKey("Allele Frequencies History")) {
-            AlleleFrequencyCollectionHistory history = new AlleleFrequencyCollectionHistory();
-            history.Add(frequenciesCollection);
-            results.Add(new Result("Allele Frequencies History", history));
-          } else {
-            ((AlleleFrequencyCollectionHistory)results["Allele Frequencies History"].Value).Add(frequenciesCollection);
-          }
-        }
-
-        // store alleles data table
-        DataTable allelesTable;
-        if (!results.ContainsKey("Alleles")) {
-          allelesTable = new DataTable("Alleles");
-          allelesTable.VisualProperties.XAxisTitle = "Iteration";
-          allelesTable.VisualProperties.YAxisTitle = "Number of Alleles";
-          allelesTable.VisualProperties.SecondYAxisTitle = "Number of Alleles";
-
-          allelesTable.Rows.Add(new DataRow("Unique Alleles"));
-          allelesTable.Rows["Unique Alleles"].VisualProperties.StartIndexZero = true;
-
-          allelesTable.Rows.Add(new DataRow("Unique Alleles of Best Known Solution", null));
-          allelesTable.Rows["Unique Alleles of Best Known Solution"].VisualProperties.SecondYAxis = true;
-          allelesTable.Rows["Unique Alleles of Best Known Solution"].VisualProperties.StartIndexZero = true;
-
-          allelesTable.Rows.Add(new DataRow("Fixed Alleles", null));
-          allelesTable.Rows["Fixed Alleles"].VisualProperties.SecondYAxis = true;
-          allelesTable.Rows["Fixed Alleles"].VisualProperties.StartIndexZero = true;
-
-          allelesTable.Rows.Add(new DataRow("Fixed Alleles of Best Known Solution", null));
-          allelesTable.Rows["Fixed Alleles of Best Known Solution"].VisualProperties.SecondYAxis = true;
-          allelesTable.Rows["Fixed Alleles of Best Known Solution"].VisualProperties.StartIndexZero = true;
-
-          allelesTable.Rows.Add(new DataRow("Lost Alleles of Best Known Solution", null));
-          allelesTable.Rows["Lost Alleles of Best Known Solution"].VisualProperties.SecondYAxis = true;
-          allelesTable.Rows["Lost Alleles of Best Known Solution"].VisualProperties.StartIndexZero = true;
-
-          results.Add(new Result("Alleles", allelesTable));
-        } else {
-          allelesTable = (DataTable)results["Alleles"].Value;
-        }
-
-        int fixedAllelesCount = frequenciesCollection.Where(x => x.Frequency == 1).Count();
-        var relevantAlleles = frequenciesCollection.Where(x => x.ContainedInBestKnownSolution);
-        int relevantAllelesCount = relevantAlleles.Count();
-        int fixedRelevantAllelesCount = relevantAlleles.Where(x => x.Frequency == 1).Count();
-        int lostRelevantAllelesCount = relevantAlleles.Where(x => x.Frequency == 0).Count();
-        int uniqueRelevantAllelesCount = relevantAllelesCount - lostRelevantAllelesCount;
-        allelesTable.Rows["Unique Alleles"].Values.Add(frequenciesCollection.Count);
-        allelesTable.Rows["Unique Alleles of Best Known Solution"].Values.Add(uniqueRelevantAllelesCount);
-        allelesTable.Rows["Fixed Alleles"].Values.Add(fixedAllelesCount);
-        allelesTable.Rows["Fixed Alleles of Best Known Solution"].Values.Add(fixedRelevantAllelesCount);
-        allelesTable.Rows["Lost Alleles of Best Known Solution"].Values.Add(lostRelevantAllelesCount);
-
-        // store alleles values
-        if (!results.ContainsKey("Unique Alleles"))
-          results.Add(new Result("Unique Alleles", new DoubleValue(frequenciesCollection.Count)));
-        else
-          ((DoubleValue)results["Unique Alleles"].Value).Value = frequenciesCollection.Count;
-
-        if (!results.ContainsKey("Unique Alleles of Best Known Solution"))
-          results.Add(new Result("Unique Alleles of Best Known Solution", new DoubleValue(uniqueRelevantAllelesCount)));
-        else
-          ((DoubleValue)results["Unique Alleles of Best Known Solution"].Value).Value = uniqueRelevantAllelesCount;
-
-        if (!results.ContainsKey("Fixed Alleles"))
-          results.Add(new Result("Fixed Alleles", new DoubleValue(fixedAllelesCount)));
-        else
-          ((DoubleValue)results["Fixed Alleles"].Value).Value = fixedAllelesCount;
-
-        if (!results.ContainsKey("Fixed Alleles of Best Known Solution"))
-          results.Add(new Result("Fixed Alleles of Best Known Solution", new DoubleValue(fixedRelevantAllelesCount)));
-        else
-          ((DoubleValue)results["Fixed Alleles of Best Known Solution"].Value).Value = fixedRelevantAllelesCount;
-
-        if (!results.ContainsKey("Lost Alleles of Best Known Solution"))
-          results.Add(new Result("Lost Alleles of Best Known Solution", new DoubleValue(lostRelevantAllelesCount)));
-        else
-          ((DoubleValue)results["Lost Alleles of Best Known Solution"].Value).Value = lostRelevantAllelesCount;
-      }
-      return base.Apply();
-    }
-
-    protected abstract Allele[] CalculateAlleles(T solution);
-  }
-}
Index: trunk/sources/HeuristicLab.Analysis/3.3/AlleleFrequencyCollection.cs
===================================================================
--- trunk/sources/HeuristicLab.Analysis/3.3/AlleleFrequencyCollection.cs	(revision 4870)
+++ 	(revision )
@@ -1,49 +1,0 @@
-#region License Information
-/* HeuristicLab
- * Copyright (C) 2002-2010 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
- *
- * This file is part of HeuristicLab.
- *
- * HeuristicLab is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * HeuristicLab is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
- */
-#endregion
-
-using System.Collections.Generic;
-using System.Drawing;
-using HeuristicLab.Common;
-using HeuristicLab.Core;
-using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
-
-namespace HeuristicLab.Analysis {
-  /// <summary>
-  /// Represents a collection of allele frequencies.
-  /// </summary>
-  [Item("AlleleFrequencyCollection", "Represents a collection of allele frequencies.")]
-  [StorableClass]
-  public class AlleleFrequencyCollection : ReadOnlyItemCollection<AlleleFrequency> {
-    public override Image ItemImage {
-      get { return HeuristicLab.Common.Resources.VS2008ImageLibrary.Statistics; }
-    }
-
-    [StorableConstructor]
-    protected AlleleFrequencyCollection(bool deserializing) : base(deserializing) { }
-    protected AlleleFrequencyCollection(AlleleFrequencyCollection original, Cloner cloner) : base(original, cloner) { }
-    public AlleleFrequencyCollection() : base() { }
-    public AlleleFrequencyCollection(IEnumerable<AlleleFrequency> frequencies) : base(new ItemCollection<AlleleFrequency>(frequencies)) { }
-
-    public override IDeepCloneable Clone(Cloner cloner) {
-      return new AlleleFrequencyCollection(this, cloner);
-    }
-  }
-}
Index: trunk/sources/HeuristicLab.Analysis/3.3/AlleleFrequencyCollectionHistory.cs
===================================================================
--- trunk/sources/HeuristicLab.Analysis/3.3/AlleleFrequencyCollectionHistory.cs	(revision 4870)
+++ 	(revision )
@@ -1,49 +1,0 @@
-#region License Information
-/* HeuristicLab
- * Copyright (C) 2002-2010 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
- *
- * This file is part of HeuristicLab.
- *
- * HeuristicLab is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * HeuristicLab is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
- */
-#endregion
-
-using System.Collections.Generic;
-using System.Drawing;
-using HeuristicLab.Common;
-using HeuristicLab.Core;
-using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
-
-namespace HeuristicLab.Analysis {
-  /// <summary>
-  /// Represents history values of allele frequencies collections.
-  /// </summary>
-  [Item("AlleleFrequencyCollectionHistory", "Represents history values of allele frequencies collections.")]
-  [StorableClass]
-  public class AlleleFrequencyCollectionHistory : ItemCollection<AlleleFrequencyCollection> {
-    public override Image ItemImage {
-      get { return HeuristicLab.Common.Resources.VS2008ImageLibrary.Cab; }
-    }
-
-    [StorableConstructor]
-    protected AlleleFrequencyCollectionHistory(bool deserializing) : base(deserializing) { }
-    protected AlleleFrequencyCollectionHistory(AlleleFrequencyCollectionHistory original, Cloner cloner) : base(original, cloner) { }
-    public AlleleFrequencyCollectionHistory() : base() { }
-    public AlleleFrequencyCollectionHistory(IEnumerable<AlleleFrequencyCollection> collections) : base(new ItemCollection<AlleleFrequencyCollection>(collections)) { }
-
-    public override IDeepCloneable Clone(Cloner cloner) {
-      return new AlleleFrequencyCollectionHistory(this, cloner);
-    }
-  }
-}
Index: trunk/sources/HeuristicLab.Analysis/3.3/BestAverageWorstQualityAnalyzer.cs
===================================================================
--- trunk/sources/HeuristicLab.Analysis/3.3/BestAverageWorstQualityAnalyzer.cs	(revision 4870)
+++ 	(revision )
@@ -1,179 +1,0 @@
-#region License Information
-/* HeuristicLab
- * Copyright (C) 2002-2010 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
- *
- * This file is part of HeuristicLab.
- *
- * HeuristicLab is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * HeuristicLab is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
- */
-#endregion
-
-using System;
-using HeuristicLab.Common;
-using HeuristicLab.Core;
-using HeuristicLab.Data;
-using HeuristicLab.Operators;
-using HeuristicLab.Optimization;
-using HeuristicLab.Optimization.Operators;
-using HeuristicLab.Parameters;
-using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
-
-namespace HeuristicLab.Analysis {
-  /// <summary>
-  /// An operator which analyzes the best, average and worst quality of solutions in the scope tree.
-  /// </summary>
-  [Item("BestAverageWorstQualityAnalyzer", "An operator which analyzes the best, average and worst quality of solutions in the scope tree.")]
-  [StorableClass]
-  public sealed class BestAverageWorstQualityAnalyzer : AlgorithmOperator, IAnalyzer {
-    #region Parameter properties
-    public ValueLookupParameter<BoolValue> MaximizationParameter {
-      get { return (ValueLookupParameter<BoolValue>)Parameters["Maximization"]; }
-    }
-    public ScopeTreeLookupParameter<DoubleValue> QualityParameter {
-      get { return (ScopeTreeLookupParameter<DoubleValue>)Parameters["Quality"]; }
-    }
-    public ValueLookupParameter<DoubleValue> BestKnownQualityParameter {
-      get { return (ValueLookupParameter<DoubleValue>)Parameters["BestKnownQuality"]; }
-    }
-    public ValueLookupParameter<DoubleValue> BestQualityParameter {
-      get { return (ValueLookupParameter<DoubleValue>)Parameters["BestQuality"]; }
-    }
-    public ValueLookupParameter<DoubleValue> CurrentBestQualityParameter {
-      get { return (ValueLookupParameter<DoubleValue>)Parameters["CurrentBestQuality"]; }
-    }
-    public ValueLookupParameter<DoubleValue> CurrentAverageQualityParameter {
-      get { return (ValueLookupParameter<DoubleValue>)Parameters["CurrentAverageQuality"]; }
-    }
-    public ValueLookupParameter<DoubleValue> CurrentWorstQualityParameter {
-      get { return (ValueLookupParameter<DoubleValue>)Parameters["CurrentWorstQuality"]; }
-    }
-    public ValueLookupParameter<DataTable> QualitiesParameter {
-      get { return (ValueLookupParameter<DataTable>)Parameters["Qualities"]; }
-    }
-    public ValueLookupParameter<DoubleValue> AbsoluteDifferenceBestKnownToBestParameter {
-      get { return (ValueLookupParameter<DoubleValue>)Parameters["AbsoluteDifferenceBestKnownToBest"]; }
-    }
-    public ValueLookupParameter<PercentValue> RelativeDifferenceBestKnownToBestParameter {
-      get { return (ValueLookupParameter<PercentValue>)Parameters["RelativeDifferenceBestKnownToBest"]; }
-    }
-    public ValueLookupParameter<VariableCollection> ResultsParameter {
-      get { return (ValueLookupParameter<VariableCollection>)Parameters["Results"]; }
-    }
-    #endregion
-
-    #region Properties
-    private BestQualityMemorizer BestQualityMemorizer {
-      get { return (BestQualityMemorizer)OperatorGraph.InitialOperator; }
-    }
-    private BestAverageWorstQualityCalculator BestAverageWorstQualityCalculator {
-      get { return (BestAverageWorstQualityCalculator)BestQualityMemorizer.Successor; }
-    }
-    #endregion
-
-    #region Storing & Cloning
-    [StorableConstructor]
-    private BestAverageWorstQualityAnalyzer(bool deserializing) : base(deserializing) { }
-    private BestAverageWorstQualityAnalyzer(BestAverageWorstQualityAnalyzer original, Cloner cloner)
-      : base(original, cloner) {
-      Initialize();
-    }
-    public override IDeepCloneable Clone(Cloner cloner) {
-      return new BestAverageWorstQualityAnalyzer(this, cloner);
-    }
-    #endregion
-    public BestAverageWorstQualityAnalyzer()
-      : base() {
-      #region Create parameters
-      Parameters.Add(new ValueLookupParameter<BoolValue>("Maximization", "True if the problem is a maximization problem, otherwise false."));
-      Parameters.Add(new ScopeTreeLookupParameter<DoubleValue>("Quality", "The value which represents the quality of a solution."));
-      Parameters.Add(new ValueLookupParameter<DoubleValue>("BestKnownQuality", "The best known quality value found so far."));
-      Parameters.Add(new ValueLookupParameter<DoubleValue>("BestQuality", "The best quality value found in the current run."));
-      Parameters.Add(new ValueLookupParameter<DoubleValue>("CurrentBestQuality", "The best quality value found in the current population."));
-      Parameters.Add(new ValueLookupParameter<DoubleValue>("CurrentAverageQuality", "The average quality value of all solutions in the current population."));
-      Parameters.Add(new ValueLookupParameter<DoubleValue>("CurrentWorstQuality", "The worst quality value found in the current population."));
-      Parameters.Add(new ValueLookupParameter<DataTable>("Qualities", "The data table to store the current best, current average, current worst, best and best known quality value."));
-      Parameters.Add(new ValueLookupParameter<DoubleValue>("AbsoluteDifferenceBestKnownToBest", "The absolute difference of the best known quality value to the best quality value."));
-      Parameters.Add(new ValueLookupParameter<PercentValue>("RelativeDifferenceBestKnownToBest", "The relative difference of the best known quality value to the best quality value."));
-      Parameters.Add(new ValueLookupParameter<VariableCollection>("Results", "The results collection where the analysis values should be stored."));
-      #endregion
-
-      #region Create operators
-      BestQualityMemorizer bestQualityMemorizer = new BestQualityMemorizer();
-      BestAverageWorstQualityCalculator bestAverageWorstQualityCalculator = new BestAverageWorstQualityCalculator();
-      DataTableValuesCollector dataTableValuesCollector = new DataTableValuesCollector();
-      QualityDifferenceCalculator qualityDifferenceCalculator = new QualityDifferenceCalculator();
-      ResultsCollector resultsCollector = new ResultsCollector();
-
-      bestQualityMemorizer.BestQualityParameter.ActualName = BestQualityParameter.Name;
-      bestQualityMemorizer.MaximizationParameter.ActualName = MaximizationParameter.Name;
-      bestQualityMemorizer.QualityParameter.ActualName = QualityParameter.Name;
-      bestQualityMemorizer.QualityParameter.Depth = QualityParameter.Depth;
-
-      bestAverageWorstQualityCalculator.AverageQualityParameter.ActualName = CurrentAverageQualityParameter.Name;
-      bestAverageWorstQualityCalculator.BestQualityParameter.ActualName = CurrentBestQualityParameter.Name;
-      bestAverageWorstQualityCalculator.MaximizationParameter.ActualName = MaximizationParameter.Name;
-      bestAverageWorstQualityCalculator.QualityParameter.ActualName = QualityParameter.Name;
-      bestAverageWorstQualityCalculator.QualityParameter.Depth = QualityParameter.Depth;
-      bestAverageWorstQualityCalculator.WorstQualityParameter.ActualName = CurrentWorstQualityParameter.Name;
-
-      dataTableValuesCollector.CollectedValues.Add(new LookupParameter<DoubleValue>("CurrentBestQuality", null, CurrentBestQualityParameter.Name));
-      dataTableValuesCollector.CollectedValues.Add(new LookupParameter<DoubleValue>("CurrentAverageQuality", null, CurrentAverageQualityParameter.Name));
-      dataTableValuesCollector.CollectedValues.Add(new LookupParameter<DoubleValue>("CurrentWorstQuality", null, CurrentWorstQualityParameter.Name));
-      dataTableValuesCollector.CollectedValues.Add(new LookupParameter<DoubleValue>("BestQuality", null, BestQualityParameter.Name));
-      dataTableValuesCollector.CollectedValues.Add(new LookupParameter<DoubleValue>("BestKnownQuality", null, BestKnownQualityParameter.Name));
-      dataTableValuesCollector.DataTableParameter.ActualName = QualitiesParameter.Name;
-
-      qualityDifferenceCalculator.AbsoluteDifferenceParameter.ActualName = AbsoluteDifferenceBestKnownToBestParameter.Name;
-      qualityDifferenceCalculator.FirstQualityParameter.ActualName = BestKnownQualityParameter.Name;
-      qualityDifferenceCalculator.RelativeDifferenceParameter.ActualName = RelativeDifferenceBestKnownToBestParameter.Name;
-      qualityDifferenceCalculator.SecondQualityParameter.ActualName = BestQualityParameter.Name;
-
-      resultsCollector.CollectedValues.Add(new LookupParameter<DoubleValue>("CurrentBestQuality", null, CurrentBestQualityParameter.Name));
-      resultsCollector.CollectedValues.Add(new LookupParameter<DoubleValue>("CurrentAverageQuality", null, CurrentAverageQualityParameter.Name));
-      resultsCollector.CollectedValues.Add(new LookupParameter<DoubleValue>("CurrentWorstQuality", null, CurrentWorstQualityParameter.Name));
-      resultsCollector.CollectedValues.Add(new LookupParameter<DoubleValue>("BestQuality", null, BestQualityParameter.Name));
-      resultsCollector.CollectedValues.Add(new LookupParameter<DoubleValue>("BestKnownQuality", null, BestKnownQualityParameter.Name));
-      resultsCollector.CollectedValues.Add(new LookupParameter<DoubleValue>("AbsoluteDifferenceBestKnownToBest", null, AbsoluteDifferenceBestKnownToBestParameter.Name));
-      resultsCollector.CollectedValues.Add(new LookupParameter<PercentValue>("RelativeDifferenceBestKnownToBest", null, RelativeDifferenceBestKnownToBestParameter.Name));
-      resultsCollector.CollectedValues.Add(new LookupParameter<DataTable>(QualitiesParameter.Name));
-      resultsCollector.ResultsParameter.ActualName = ResultsParameter.Name;
-      #endregion
-
-      #region Create operator graph
-      OperatorGraph.InitialOperator = bestQualityMemorizer;
-      bestQualityMemorizer.Successor = bestAverageWorstQualityCalculator;
-      bestAverageWorstQualityCalculator.Successor = dataTableValuesCollector;
-      dataTableValuesCollector.Successor = qualityDifferenceCalculator;
-      qualityDifferenceCalculator.Successor = resultsCollector;
-      resultsCollector.Successor = null;
-      #endregion
-
-      Initialize();
-    }
-
-    [StorableHook(HookType.AfterDeserialization)]
-    private void AfterDeserialization() {
-      Initialize();
-    }
-    
-    private void Initialize() {
-      QualityParameter.DepthChanged += new EventHandler(QualityParameter_DepthChanged);
-    }
-
-    private void QualityParameter_DepthChanged(object sender, System.EventArgs e) {
-      BestQualityMemorizer.QualityParameter.Depth = QualityParameter.Depth;
-      BestAverageWorstQualityCalculator.QualityParameter.Depth = QualityParameter.Depth;
-    }
-  }
-}
Index: trunk/sources/HeuristicLab.Analysis/3.3/BestAverageWorstQualityCalculator.cs
===================================================================
--- trunk/sources/HeuristicLab.Analysis/3.3/BestAverageWorstQualityCalculator.cs	(revision 4870)
+++ 	(revision )
@@ -1,100 +1,0 @@
-#region License Information
-/* HeuristicLab
- * Copyright (C) 2002-2010 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
- *
- * This file is part of HeuristicLab.
- *
- * HeuristicLab is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * HeuristicLab is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
- */
-#endregion
-
-using HeuristicLab.Common;
-using HeuristicLab.Core;
-using HeuristicLab.Data;
-using HeuristicLab.Operators;
-using HeuristicLab.Parameters;
-using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
-
-namespace HeuristicLab.Analysis {
-  /// <summary>
-  /// An operator which calculates the best, average and worst quality of solutions in the scope tree.
-  /// </summary>
-  [Item("BestAverageWorstQualityCalculator", "An operator which calculates the best, average and worst quality of solutions in the scope tree.")]
-  [StorableClass]
-  public sealed class BestAverageWorstQualityCalculator : SingleSuccessorOperator {
-    public ValueLookupParameter<BoolValue> MaximizationParameter {
-      get { return (ValueLookupParameter<BoolValue>)Parameters["Maximization"]; }
-    }
-    public ScopeTreeLookupParameter<DoubleValue> QualityParameter {
-      get { return (ScopeTreeLookupParameter<DoubleValue>)Parameters["Quality"]; }
-    }
-    public ValueLookupParameter<DoubleValue> BestQualityParameter {
-      get { return (ValueLookupParameter<DoubleValue>)Parameters["BestQuality"]; }
-    }
-    public ValueLookupParameter<DoubleValue> AverageQualityParameter {
-      get { return (ValueLookupParameter<DoubleValue>)Parameters["AverageQuality"]; }
-    }
-    public ValueLookupParameter<DoubleValue> WorstQualityParameter {
-      get { return (ValueLookupParameter<DoubleValue>)Parameters["WorstQuality"]; }
-    }
-
-    #region Storing & Cloning
-    [StorableConstructor]
-    private BestAverageWorstQualityCalculator(bool deserializing) : base(deserializing) { }
-    private BestAverageWorstQualityCalculator(BestAverageWorstQualityCalculator original, Cloner cloner) : base(original, cloner) { }
-    public override IDeepCloneable Clone(Cloner cloner) {
-      return new BestAverageWorstQualityCalculator(this, cloner);
-    }
-    #endregion
-    public BestAverageWorstQualityCalculator()
-      : base() {
-      Parameters.Add(new ValueLookupParameter<BoolValue>("Maximization", "True if the current problem is a maximization problem, otherwise false."));
-      Parameters.Add(new ScopeTreeLookupParameter<DoubleValue>("Quality", "The value contained in the scope tree which represents the solution quality."));
-      Parameters.Add(new ValueLookupParameter<DoubleValue>("BestQuality", "The quality value of the best solution."));
-      Parameters.Add(new ValueLookupParameter<DoubleValue>("AverageQuality", "The average quality of all solutions."));
-      Parameters.Add(new ValueLookupParameter<DoubleValue>("WorstQuality", "The quality value of the worst solution."));
-    }
-
-
-    public override IOperation Apply() {
-      ItemArray<DoubleValue> qualities = QualityParameter.ActualValue;
-      bool maximization = MaximizationParameter.ActualValue.Value;
-
-      if (qualities.Length > 0) {
-        double min = double.MaxValue, max = double.MinValue, sum = 0.0;
-        for (int i = 0; i < qualities.Length; i++) {
-          if (qualities[i].Value < min) min = qualities[i].Value;
-          if (qualities[i].Value > max) max = qualities[i].Value;
-          sum += qualities[i].Value;
-        }
-        if (!maximization) {
-          double temp = min;
-          min = max;
-          max = temp;
-        }
-
-        DoubleValue best = BestQualityParameter.ActualValue;
-        if (best == null) BestQualityParameter.ActualValue = new DoubleValue(max);
-        else best.Value = max;
-        DoubleValue average = AverageQualityParameter.ActualValue;
-        if (average == null) AverageQualityParameter.ActualValue = new DoubleValue(sum / qualities.Length);
-        else average.Value = sum / qualities.Length;
-        DoubleValue worst = WorstQualityParameter.ActualValue;
-        if (worst == null) WorstQualityParameter.ActualValue = new DoubleValue(min);
-        else worst.Value = min;
-      }
-      return base.Apply();
-    }
-  }
-}
Index: trunk/sources/HeuristicLab.Analysis/3.3/BestQualityMemorizer.cs
===================================================================
--- trunk/sources/HeuristicLab.Analysis/3.3/BestQualityMemorizer.cs	(revision 4870)
+++ 	(revision )
@@ -1,79 +1,0 @@
-﻿#region License Information
-/* HeuristicLab
- * Copyright (C) 2002-2010 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
- *
- * This file is part of HeuristicLab.
- *
- * HeuristicLab is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * HeuristicLab is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
- */
-#endregion
-
-using HeuristicLab.Common;
-using HeuristicLab.Core;
-using HeuristicLab.Data;
-using HeuristicLab.Operators;
-using HeuristicLab.Parameters;
-using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
-
-namespace HeuristicLab.Analysis {
-  /// <summary>
-  /// An operator that updates the best quality found so far with those qualities contained in the scope tree.
-  /// </summary>
-  [Item("BestQualityMemorizer", "An operator that updates the best quality found so far with those qualities contained in the scope tree.")]
-  [StorableClass]
-  public class BestQualityMemorizer : SingleSuccessorOperator {
-    public ValueLookupParameter<BoolValue> MaximizationParameter {
-      get { return (ValueLookupParameter<BoolValue>)Parameters["Maximization"]; }
-    }
-    public ScopeTreeLookupParameter<DoubleValue> QualityParameter {
-      get { return (ScopeTreeLookupParameter<DoubleValue>)Parameters["Quality"]; }
-    }
-    public ValueLookupParameter<DoubleValue> BestQualityParameter {
-      get { return (ValueLookupParameter<DoubleValue>)Parameters["BestQuality"]; }
-    }
-
-    #region Storing & Cloning
-    [StorableConstructor]
-    protected BestQualityMemorizer(bool deserializing) : base(deserializing) { }
-    protected BestQualityMemorizer(BestQualityMemorizer original, Cloner cloner) : base(original, cloner) { }
-    public override IDeepCloneable Clone(Cloner cloner) {
-      return new BestQualityMemorizer(this, cloner);
-    }
-    #endregion
-    public BestQualityMemorizer()
-      : base() {
-      Parameters.Add(new ValueLookupParameter<BoolValue>("Maximization", "True if the current problem is a maximization problem, otherwise false."));
-      Parameters.Add(new ScopeTreeLookupParameter<DoubleValue>("Quality", "The value contained in the scope tree which represents the solution quality."));
-      Parameters.Add(new ValueLookupParameter<DoubleValue>("BestQuality", "The quality value of the best solution."));
-    }
-
-    public override IOperation Apply() {
-      ItemArray<DoubleValue> qualities = QualityParameter.ActualValue;
-      bool maximization = MaximizationParameter.ActualValue.Value;
-      DoubleValue best = BestQualityParameter.ActualValue;
-      double max = (best != null) ? (best.Value) : ((maximization) ? (double.MinValue) : (double.MaxValue));
-
-      foreach (DoubleValue quality in qualities)
-        if (IsBetter(maximization, quality.Value, max)) max = quality.Value;
-
-      if (best == null) BestQualityParameter.ActualValue = new DoubleValue(max);
-      else best.Value = max;
-      return base.Apply();
-    }
-
-    private bool IsBetter(bool maximization, double quality, double max) {
-      return (maximization && quality > max || !maximization && quality < max);
-    }
-  }
-}
Index: trunk/sources/HeuristicLab.Analysis/3.3/DataRow.cs
===================================================================
--- trunk/sources/HeuristicLab.Analysis/3.3/DataRow.cs	(revision 4870)
+++ 	(revision )
@@ -1,118 +1,0 @@
-#region License Information
-/* HeuristicLab
- * Copyright (C) 2002-2010 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
- *
- * This file is part of HeuristicLab.
- *
- * HeuristicLab is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * HeuristicLab is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You 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.ComponentModel;
-using HeuristicLab.Collections;
-using HeuristicLab.Common;
-using HeuristicLab.Core;
-using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
-
-namespace HeuristicLab.Analysis {
-  /// <summary>
-  /// A row of data values.
-  /// </summary>
-  [Item("DataRow", "A row of data values.")]
-  [StorableClass]
-  public sealed class DataRow : NamedItem {
-    private DataRowVisualProperties visualProperties;
-    public DataRowVisualProperties VisualProperties {
-      get { return visualProperties; }
-      set {
-        if (visualProperties != value) {
-          if (value == null) throw new ArgumentNullException("VisualProperties");
-          if (visualProperties != null) visualProperties.PropertyChanged -= new PropertyChangedEventHandler(VisualProperties_PropertyChanged);
-          visualProperties = value;
-          visualProperties.PropertyChanged += new PropertyChangedEventHandler(VisualProperties_PropertyChanged);
-          OnVisualPropertiesChanged();
-        }
-      }
-    }
-    private ObservableList<double> values;
-    public ObservableList<double> Values {
-      get { return values; }
-    }
-
-    #region Persistence Properties
-    [Storable(Name = "VisualProperties")]
-    private DataRowVisualProperties StorableVisualProperties {
-      get { return VisualProperties; }
-      set { VisualProperties = value; }
-    }
-    [Storable(Name = "values")]
-    private IEnumerable<double> StorableValues {
-      get { return values; }
-      set { values = new ObservableList<double>(value); }
-    }
-    #endregion
-
-    [StorableConstructor]
-    private DataRow(bool deserializing) : base(deserializing) { }
-    private DataRow(DataRow original, Cloner cloner)
-      : base(original, cloner) {
-      this.VisualProperties = (DataRowVisualProperties)cloner.Clone(original.visualProperties);
-      this.values = new ObservableList<double>(original.values);
-    }
-    public DataRow()
-      : base() {
-      VisualProperties = new DataRowVisualProperties();
-      values = new ObservableList<double>();
-    }
-    public DataRow(string name)
-      : base(name) {
-      VisualProperties = new DataRowVisualProperties();
-      values = new ObservableList<double>();
-    }
-    public DataRow(string name, string description)
-      : base(name, description) {
-      VisualProperties = new DataRowVisualProperties();
-      values = new ObservableList<double>();
-    }
-    public DataRow(string name, string description, IEnumerable<double> values)
-      : base(name, description) {
-      VisualProperties = new DataRowVisualProperties();
-      this.values = new ObservableList<double>(values);
-    }
-
-    // BackwardsCompatibility3.3
-    #region Backwards compatible code, remove with 3.4
-    [StorableHook(HookType.AfterDeserialization)]
-    private void AfterDeserialization() {
-      if (VisualProperties == null) VisualProperties = new DataRowVisualProperties();
-    }
-    #endregion
-
-    public override IDeepCloneable Clone(Cloner cloner) {
-      return new DataRow(this, cloner);
-    }
-
-    public event EventHandler VisualPropertiesChanged;
-    private void OnVisualPropertiesChanged() {
-      EventHandler handler = VisualPropertiesChanged;
-      if (handler != null) handler(this, EventArgs.Empty);
-    }
-
-    private void VisualProperties_PropertyChanged(object sender, PropertyChangedEventArgs e) {
-      OnVisualPropertiesChanged();
-    }
-  }
-}
Index: trunk/sources/HeuristicLab.Analysis/3.3/DataRowVisualProperties.cs
===================================================================
--- trunk/sources/HeuristicLab.Analysis/3.3/DataRowVisualProperties.cs	(revision 4870)
+++ 	(revision )
@@ -1,132 +1,0 @@
-#region License Information
-/* HeuristicLab
- * Copyright (C) 2002-2010 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
- *
- * This file is part of HeuristicLab.
- *
- * HeuristicLab is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * HeuristicLab is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You 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.ComponentModel;
-using System.Drawing;
-using HeuristicLab.Common;
-using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
-
-namespace HeuristicLab.Analysis {
-  /// <summary>
-  /// Visual properties of a DataRow.
-  /// </summary>
-  [StorableClass]
-  public class DataRowVisualProperties : DeepCloneable, INotifyPropertyChanged {
-    #region ChartType
-    public enum DataRowChartType {
-      Line,
-      Columns,
-      Points,
-      Bars
-    }
-    #endregion
-
-    private DataRowChartType chartType;
-    public DataRowChartType ChartType {
-      get { return chartType; }
-      set {
-        if (chartType != value) {
-          chartType = value;
-          OnPropertyChanged("ChartType");
-        }
-      }
-    }
-    private bool secondYAxis;
-    public bool SecondYAxis {
-      get { return secondYAxis; }
-      set {
-        if (secondYAxis != value) {
-          secondYAxis = value;
-          OnPropertyChanged("SecondYAxis");
-        }
-      }
-    }
-    private Color color;
-    public Color Color {
-      get { return color; }
-      set {
-        if (color != value) {
-          color = value;
-          OnPropertyChanged("Color");
-        }
-      }
-    }
-    private bool startIndexZero;
-    public bool StartIndexZero {
-      get { return startIndexZero; }
-      set {
-        if (startIndexZero != value) {
-          startIndexZero = value;
-          OnPropertyChanged("StartIndexZero");
-        }
-      }
-    }
-
-    #region Persistence Properties
-    [Storable(Name = "ChartType")]
-    private DataRowChartType StorableChartType {
-      get { return chartType; }
-      set { chartType = value; }
-    }
-    [Storable(Name = "SecondYAxis")]
-    private bool StorableSecondYAxis {
-      get { return secondYAxis; }
-      set { secondYAxis = value; }
-    }
-    [Storable(Name = "Color")]
-    private Color StorableColor {
-      get { return color; }
-      set { color = value; }
-    }
-    [Storable(Name = "StartIndexZero")]
-    private bool StorableStartIndexZero {
-      get { return startIndexZero; }
-      set { startIndexZero = value; }
-    }
-    #endregion
-
-    [StorableConstructor]
-    protected DataRowVisualProperties(bool deserializing) : base() { }
-    protected DataRowVisualProperties(DataRowVisualProperties original, Cloner cloner)
-      : base(original, cloner) {
-      this.chartType = original.chartType;
-      this.secondYAxis = original.secondYAxis;
-      this.color = original.color;
-      this.startIndexZero = original.startIndexZero;
-    }
-    public DataRowVisualProperties() {
-      chartType = DataRowChartType.Line;
-      secondYAxis = false;
-      color = Color.Empty;
-      startIndexZero = false;
-    }
-
-    public override IDeepCloneable Clone(Cloner cloner) {
-      return new DataRowVisualProperties(this, cloner);
-    }
-
-    public event PropertyChangedEventHandler PropertyChanged;
-    protected virtual void OnPropertyChanged(string propertyName) {
-      PropertyChangedEventHandler handler = PropertyChanged;
-      if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
-    }
-  }
-}
Index: trunk/sources/HeuristicLab.Analysis/3.3/DataTable.cs
===================================================================
--- trunk/sources/HeuristicLab.Analysis/3.3/DataTable.cs	(revision 4870)
+++ 	(revision )
@@ -1,262 +1,0 @@
-#region License Information
-/* HeuristicLab
- * Copyright (C) 2002-2010 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
- *
- * This file is part of HeuristicLab.
- *
- * HeuristicLab is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * HeuristicLab is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You 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.ComponentModel;
-using System.Drawing;
-using System.Linq;
-using HeuristicLab.Collections;
-using HeuristicLab.Common;
-using HeuristicLab.Core;
-using HeuristicLab.Data;
-using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
-
-namespace HeuristicLab.Analysis {
-  /// <summary>
-  /// A table of data values.
-  /// </summary>
-  [Item("DataTable", "A table of data values.")]
-  [StorableClass]
-  public sealed class DataTable : NamedItem, IStringConvertibleMatrix {
-    public override Image ItemImage {
-      get { return HeuristicLab.Common.Resources.VS2008ImageLibrary.Performance; }
-    }
-
-    private DataTableVisualProperties visualProperties;
-    public DataTableVisualProperties VisualProperties {
-      get { return visualProperties; }
-      set {
-        if (visualProperties != value) {
-          if (value == null) throw new ArgumentNullException("VisualProperties");
-          if (visualProperties != null) visualProperties.PropertyChanged -= new PropertyChangedEventHandler(VisualProperties_PropertyChanged);
-          visualProperties = value;
-          visualProperties.PropertyChanged += new PropertyChangedEventHandler(VisualProperties_PropertyChanged);
-          OnVisualPropertiesChanged();
-        }
-      }
-    }
-
-    private NamedItemCollection<DataRow> rows;
-    public NamedItemCollection<DataRow> Rows {
-      get { return rows; }
-    }
-
-    #region Persistence Properties
-    [Storable(Name = "VisualProperties")]
-    private DataTableVisualProperties StorableVisualProperties {
-      get { return VisualProperties; }
-      set { VisualProperties = value; }
-    }
-    [Storable(Name = "rows")]
-    private IEnumerable<DataRow> StorableRows {
-      get { return rows; }
-      set { rows = new NamedItemCollection<DataRow>(value); }
-    }
-    #endregion
-
-    [StorableConstructor]
-    private DataTable(bool deserializing) : base(deserializing) { }
-    private DataTable(DataTable original, Cloner cloner)
-      : base(original, cloner) {
-      this.VisualProperties = (DataTableVisualProperties)cloner.Clone(original.visualProperties);
-      this.rows = cloner.Clone(original.rows);
-      this.RegisterRowsEvents();
-    }
-    public DataTable()
-      : base() {
-      VisualProperties = new DataTableVisualProperties();
-      rows = new NamedItemCollection<DataRow>();
-      this.RegisterRowsEvents();
-    }
-    public DataTable(string name)
-      : base(name) {
-      VisualProperties = new DataTableVisualProperties();
-      rows = new NamedItemCollection<DataRow>();
-      this.RegisterRowsEvents();
-    }
-    public DataTable(string name, string description)
-      : base(name, description) {
-      VisualProperties = new DataTableVisualProperties();
-      rows = new NamedItemCollection<DataRow>();
-      this.RegisterRowsEvents();
-    }
-
-    // BackwardsCompatibility3.3
-    #region Backwards compatible code, remove with 3.4
-    [StorableHook(HookType.AfterDeserialization)]
-    private void AfterDeserialization() {
-      if (VisualProperties == null) VisualProperties = new DataTableVisualProperties();
-    }
-    #endregion
-
-    public override IDeepCloneable Clone(Cloner cloner) {
-      return new DataTable(this, cloner);
-    }
-
-    public event EventHandler VisualPropertiesChanged;
-    private void OnVisualPropertiesChanged() {
-      EventHandler handler = VisualPropertiesChanged;
-      if (handler != null) handler(this, EventArgs.Empty);
-    }
-
-    private void VisualProperties_PropertyChanged(object sender, PropertyChangedEventArgs e) {
-      OnVisualPropertiesChanged();
-    }
-
-    private void RegisterRowsEvents() {
-      rows.ItemsAdded += new CollectionItemsChangedEventHandler<DataRow>(rows_ItemsAdded);
-      rows.ItemsRemoved += new CollectionItemsChangedEventHandler<DataRow>(rows_ItemsRemoved);
-      rows.ItemsReplaced += new CollectionItemsChangedEventHandler<DataRow>(rows_ItemsReplaced);
-      rows.CollectionReset += new CollectionItemsChangedEventHandler<DataRow>(rows_CollectionReset);
-    }
-    private void rows_ItemsAdded(object sender, CollectionItemsChangedEventArgs<DataRow> e) {
-      foreach (DataRow row in e.Items)
-        this.RegisterRowEvents(row);
-      this.OnColumnNamesChanged();
-      this.OnReset();
-    }
-    private void rows_ItemsRemoved(object sender, CollectionItemsChangedEventArgs<DataRow> e) {
-      foreach (DataRow row in e.Items)
-        this.DeregisterRowEvents(row);
-      this.OnColumnNamesChanged();
-      this.OnReset();
-    }
-    private void rows_ItemsReplaced(object sender, CollectionItemsChangedEventArgs<DataRow> e) {
-      foreach (DataRow row in e.OldItems)
-        this.DeregisterRowEvents(row);
-      foreach (DataRow row in e.Items)
-        this.RegisterRowEvents(row);
-      this.OnColumnNamesChanged();
-      this.OnReset();
-    }
-    private void rows_CollectionReset(object sender, CollectionItemsChangedEventArgs<DataRow> e) {
-      foreach (DataRow row in e.OldItems)
-        this.DeregisterRowEvents(row);
-      foreach (DataRow row in e.Items)
-        this.RegisterRowEvents(row);
-      this.OnColumnNamesChanged();
-      this.OnReset();
-    }
-
-    private void RegisterRowEvents(DataRow row) {
-      row.Values.ItemsAdded += new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_ItemsAdded);
-      row.Values.ItemsMoved += new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_ItemsMoved);
-      row.Values.ItemsRemoved += new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_ItemsRemoved);
-      row.Values.ItemsReplaced += new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_ItemsReplaced);
-      row.Values.CollectionReset += new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_CollectionReset);
-    }
-    private void DeregisterRowEvents(DataRow row) {
-      row.Values.ItemsAdded -= new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_ItemsAdded);
-      row.Values.ItemsMoved -= new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_ItemsMoved);
-      row.Values.ItemsRemoved -= new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_ItemsRemoved);
-      row.Values.ItemsReplaced -= new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_ItemsReplaced);
-      row.Values.CollectionReset -= new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_CollectionReset);
-    }
-
-    private void Values_ItemsAdded(object sender, CollectionItemsChangedEventArgs<IndexedItem<double>> e) {
-      this.OnReset();
-    }
-    private void Values_ItemsMoved(object sender, CollectionItemsChangedEventArgs<IndexedItem<double>> e) {
-      this.OnReset();
-    }
-    private void Values_ItemsRemoved(object sender, CollectionItemsChangedEventArgs<IndexedItem<double>> e) {
-      this.OnReset();
-    }
-    private void Values_ItemsReplaced(object sender, CollectionItemsChangedEventArgs<IndexedItem<double>> e) {
-      this.OnReset();
-    }
-    private void Values_CollectionReset(object sender, CollectionItemsChangedEventArgs<IndexedItem<double>> e) {
-      this.OnReset();
-    }
-
-    #region IStringConvertibleMatrix Members
-
-    int IStringConvertibleMatrix.Rows {
-      get { return rows.Count == 0 ? 0 : rows.Max(r => r.Values.Count); }
-      set { throw new NotSupportedException(); }
-    }
-    int IStringConvertibleMatrix.Columns {
-      get { return rows.Count; }
-      set { throw new NotSupportedException(); }
-    }
-    IEnumerable<string> IStringConvertibleMatrix.ColumnNames {
-      get { return rows.Select(r => r.Name); }
-      set { throw new NotSupportedException(); }
-    }
-    IEnumerable<string> IStringConvertibleMatrix.RowNames {
-      get { return new List<string>(); }
-      set { throw new NotSupportedException(); }
-    }
-
-    bool IStringConvertibleMatrix.SortableView {
-      get { return true; }
-      set { throw new NotSupportedException(); }
-    }
-    bool IStringConvertibleMatrix.ReadOnly {
-      get { return true; }
-    }
-
-    string IStringConvertibleMatrix.GetValue(int rowIndex, int columnIndex) {
-      if (columnIndex < rows.Count) {
-        string columnName = ((IStringConvertibleMatrix)this).ColumnNames.ElementAt(columnIndex);
-        if (rows.ContainsKey(columnName) && rowIndex < rows[columnName].Values.Count)
-          return rows[columnName].Values[rowIndex].ToString();
-      }
-      return string.Empty;
-    }
-
-    bool IStringConvertibleMatrix.Validate(string value, out string errorMessage) {
-      throw new NotSupportedException();
-    }
-    bool IStringConvertibleMatrix.SetValue(string value, int rowIndex, int columnIndex) {
-      throw new NotSupportedException();
-    }
-
-    public event EventHandler<EventArgs<int, int>> ItemChanged;
-    private void OnItemChanged(int rowIndex, int columnIndex) {
-      var handler = ItemChanged;
-      if (handler != null) handler(this, new EventArgs<int, int>(rowIndex, columnIndex));
-      OnToStringChanged();
-    }
-    public event EventHandler Reset;
-    private void OnReset() {
-      var handler = Reset;
-      if (handler != null) handler(this, EventArgs.Empty);
-    }
-    public event EventHandler ColumnNamesChanged;
-    private void OnColumnNamesChanged() {
-      var handler = ColumnNamesChanged;
-      if (handler != null) handler(this, EventArgs.Empty);
-    }
-    public event EventHandler RowNamesChanged;
-    private void OnRowNamesChanged() {
-      var handler = RowNamesChanged;
-      if (handler != null) handler(this, EventArgs.Empty);
-    }
-    public event EventHandler SortableViewChanged;
-    private void OnSortableViewChanged() {
-      var handler = SortableViewChanged;
-      if (handler != null) handler(this, EventArgs.Empty);
-    }
-    #endregion
-  }
-}
Index: trunk/sources/HeuristicLab.Analysis/3.3/DataTableHistory.cs
===================================================================
--- trunk/sources/HeuristicLab.Analysis/3.3/DataTableHistory.cs	(revision 4870)
+++ 	(revision )
@@ -1,49 +1,0 @@
-#region License Information
-/* HeuristicLab
- * Copyright (C) 2002-2010 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
- *
- * This file is part of HeuristicLab.
- *
- * HeuristicLab is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * HeuristicLab is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
- */
-#endregion
-
-using System.Collections.Generic;
-using System.Drawing;
-using HeuristicLab.Common;
-using HeuristicLab.Core;
-using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
-
-namespace HeuristicLab.Analysis {
-  /// <summary>
-  /// Represents history values of data tables.
-  /// </summary>
-  [Item("DataTableHistory", "Represents history values of data tables.")]
-  [StorableClass]
-  public class DataTableHistory : ItemCollection<DataTable> {
-    public override Image ItemImage {
-      get { return HeuristicLab.Common.Resources.VS2008ImageLibrary.Cab; }
-    }
-
-    [StorableConstructor]
-    protected DataTableHistory(bool deserializing) : base(deserializing) { }
-    protected DataTableHistory(DataTableHistory original, Cloner cloner) : base(original, cloner) { }
-    public DataTableHistory() : base() { }
-    public DataTableHistory(IEnumerable<DataTable> collection) : base(new ItemCollection<DataTable>(collection)) { }
-
-    public override IDeepCloneable Clone(Cloner cloner) {
-      return new DataTableHistory(this, cloner);
-    }
-  }
-}
Index: trunk/sources/HeuristicLab.Analysis/3.3/DataTableValuesCollector.cs
===================================================================
--- trunk/sources/HeuristicLab.Analysis/3.3/DataTableValuesCollector.cs	(revision 4870)
+++ 	(revision )
@@ -1,113 +1,0 @@
-#region License Information
-/* HeuristicLab
- * Copyright (C) 2002-2010 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
- *
- * This file is part of HeuristicLab.
- *
- * HeuristicLab is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * HeuristicLab is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
- */
-#endregion
-
-using System.Collections.Generic;
-using System.Linq;
-using HeuristicLab.Common;
-using HeuristicLab.Core;
-using HeuristicLab.Data;
-using HeuristicLab.Operators;
-using HeuristicLab.Parameters;
-using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
-
-namespace HeuristicLab.Analysis {
-  /// <summary>
-  /// An operator which collects the actual values of parameters and adds them to a table of data values.
-  /// </summary>
-  [Item("DataTableValuesCollector", "An operator which collects the actual values of parameters and adds them to a table of data values.")]
-  [StorableClass]
-  public class DataTableValuesCollector : ValuesCollector {
-    public ValueLookupParameter<DataTable> DataTableParameter {
-      get { return (ValueLookupParameter<DataTable>)Parameters["DataTable"]; }
-    }
-
-    #region Storing & Cloning
-    [StorableConstructor]
-    protected DataTableValuesCollector(bool deserializing) : base(deserializing) { }
-    protected DataTableValuesCollector(DataTableValuesCollector original, Cloner cloner) : base(original, cloner) { }
-    public override IDeepCloneable Clone(Cloner cloner) {
-      return new DataTableValuesCollector(this, cloner);
-    }
-    #endregion
-    public DataTableValuesCollector()
-      : base() {
-      Parameters.Add(new ValueLookupParameter<DataTable>("DataTable", "The table of data values where the collected values should be stored."));
-    }
-
-    public override IOperation Apply() {
-      DataTable table = DataTableParameter.ActualValue;
-      if (table == null) {
-        table = new DataTable(DataTableParameter.ActualName);
-        DataTableParameter.ActualValue = table;
-      }
-
-      foreach (IParameter param in CollectedValues) {
-        ILookupParameter lookupParam = param as ILookupParameter;
-        string name = lookupParam != null ? lookupParam.TranslatedName : param.Name;
-
-        if (param.ActualValue is DoubleValue) {
-          AddValue(table, (param.ActualValue as DoubleValue).Value, name, param.Description);
-        } else if (param.ActualValue is IntValue) {
-          AddValue(table, (param.ActualValue as IntValue).Value, name, param.Description);
-        } else if (param.ActualValue is IEnumerable<DoubleValue>) {
-          IEnumerable<DoubleValue> values = (IEnumerable<DoubleValue>)param.ActualValue;
-          if (values.Count() <= 1) {
-            foreach (DoubleValue data in values)
-              AddValue(table, data != null ? data.Value : double.NaN, name, param.Description);
-          } else {
-            int counter = 1;
-            foreach (DoubleValue data in values) {
-              AddValue(table, data != null ? data.Value : double.NaN, name + " " + counter.ToString(), param.Description);
-              counter++;
-            }
-          }
-        } else if (param.ActualValue is IEnumerable<IntValue>) {
-          IEnumerable<IntValue> values = (IEnumerable<IntValue>)param.ActualValue;
-          if (values.Count() <= 1) {
-            foreach (IntValue data in values)
-              AddValue(table, data != null ? data.Value : double.NaN, name, param.Description);
-          } else {
-            int counter = 1;
-            foreach (IntValue data in values) {
-              AddValue(table, data != null ? data.Value : double.NaN, name + " " + counter.ToString(), param.Description);
-              counter++;
-            }
-          }
-        } else {
-          AddValue(table, double.NaN, name, param.Description);
-        }
-      }
-      return base.Apply();
-    }
-
-    private void AddValue(DataTable table, double data, string name, string description) {
-      DataRow row;
-      table.Rows.TryGetValue(name, out row);
-      if (row == null) {
-        row = new DataRow(name, description);
-        row.Values.Add(data);
-        table.Rows.Add(row);
-      } else {
-        row.Values.Add(data);
-      }
-    }
-  }
-}
Index: trunk/sources/HeuristicLab.Analysis/3.3/DataTableVisualProperties.cs
===================================================================
--- trunk/sources/HeuristicLab.Analysis/3.3/DataTableVisualProperties.cs	(revision 4870)
+++ 	(revision )
@@ -1,110 +1,0 @@
-#region License Information
-/* HeuristicLab
- * Copyright (C) 2002-2010 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
- *
- * This file is part of HeuristicLab.
- *
- * HeuristicLab is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * HeuristicLab is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You 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.ComponentModel;
-using HeuristicLab.Common;
-using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
-
-namespace HeuristicLab.Analysis {
-  /// <summary>
-  /// Visual properties of a DataTable.
-  /// </summary>
-  [StorableClass]
-  public class DataTableVisualProperties : DeepCloneable, INotifyPropertyChanged {
-    private string xAxisTitle;
-    public string XAxisTitle {
-      get { return xAxisTitle; }
-      set {
-        if (value == null) value = string.Empty;
-        if (xAxisTitle != value) {
-          xAxisTitle = value;
-          OnPropertyChanged("XAxisTitle");
-        }
-      }
-    }
-
-    private string yAxisTitle;
-    public string YAxisTitle {
-      get { return yAxisTitle; }
-      set {
-        if (value == null) value = string.Empty;
-        if (yAxisTitle != value) {
-          yAxisTitle = value;
-          OnPropertyChanged("YAxisTitle");
-        }
-      }
-    }
-
-    private string secondYAxisTitle;
-    public string SecondYAxisTitle {
-      get { return secondYAxisTitle; }
-      set {
-        if (value == null) value = string.Empty;
-        if (secondYAxisTitle != value) {
-          secondYAxisTitle = value;
-          OnPropertyChanged("SecondYAxisTitle");
-        }
-      }
-    }
-
-    #region Persistence Properties
-    [Storable(Name = "XAxisTitle")]
-    private string StorableXAxisTitle {
-      get { return xAxisTitle; }
-      set { xAxisTitle = value; }
-    }
-    [Storable(Name = "YAxisTitle")]
-    private string StorableYAxisTitle {
-      get { return yAxisTitle; }
-      set { yAxisTitle = value; }
-    }
-    [Storable(Name = "SecondYAxisTitle")]
-    private string StorableSecondYAxisTitle {
-      get { return secondYAxisTitle; }
-      set { secondYAxisTitle = value; }
-    }
-    #endregion
-
-    [StorableConstructor]
-    protected DataTableVisualProperties(bool deserializing) : base() { }
-    protected DataTableVisualProperties(DataTableVisualProperties original, Cloner cloner)
-      : base(original, cloner) {
-      this.xAxisTitle = original.xAxisTitle;
-      this.yAxisTitle = original.yAxisTitle;
-      this.secondYAxisTitle = original.secondYAxisTitle;
-    }
-    public DataTableVisualProperties() {
-      this.xAxisTitle = string.Empty;
-      this.yAxisTitle = string.Empty;
-      this.secondYAxisTitle = string.Empty;
-    }
-
-    public override IDeepCloneable Clone(Cloner cloner) {
-      return new DataTableVisualProperties(this, cloner);
-    }
-
-    public event PropertyChangedEventHandler PropertyChanged;
-    protected virtual void OnPropertyChanged(string propertyName) {
-      PropertyChangedEventHandler handler = PropertyChanged;
-      if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
-    }
-  }
-}
Index: trunk/sources/HeuristicLab.Analysis/3.3/DataVisualization/DataRow.cs
===================================================================
--- trunk/sources/HeuristicLab.Analysis/3.3/DataVisualization/DataRow.cs	(revision 4887)
+++ trunk/sources/HeuristicLab.Analysis/3.3/DataVisualization/DataRow.cs	(revision 4887)
@@ -0,0 +1,118 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2010 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You 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.ComponentModel;
+using HeuristicLab.Collections;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Analysis {
+  /// <summary>
+  /// A row of data values.
+  /// </summary>
+  [Item("DataRow", "A row of data values.")]
+  [StorableClass]
+  public sealed class DataRow : NamedItem {
+    private DataRowVisualProperties visualProperties;
+    public DataRowVisualProperties VisualProperties {
+      get { return visualProperties; }
+      set {
+        if (visualProperties != value) {
+          if (value == null) throw new ArgumentNullException("VisualProperties");
+          if (visualProperties != null) visualProperties.PropertyChanged -= new PropertyChangedEventHandler(VisualProperties_PropertyChanged);
+          visualProperties = value;
+          visualProperties.PropertyChanged += new PropertyChangedEventHandler(VisualProperties_PropertyChanged);
+          OnVisualPropertiesChanged();
+        }
+      }
+    }
+    private ObservableList<double> values;
+    public ObservableList<double> Values {
+      get { return values; }
+    }
+
+    #region Persistence Properties
+    [Storable(Name = "VisualProperties")]
+    private DataRowVisualProperties StorableVisualProperties {
+      get { return VisualProperties; }
+      set { VisualProperties = value; }
+    }
+    [Storable(Name = "values")]
+    private IEnumerable<double> StorableValues {
+      get { return values; }
+      set { values = new ObservableList<double>(value); }
+    }
+    #endregion
+
+    [StorableConstructor]
+    private DataRow(bool deserializing) : base(deserializing) { }
+    private DataRow(DataRow original, Cloner cloner)
+      : base(original, cloner) {
+      this.VisualProperties = (DataRowVisualProperties)cloner.Clone(original.visualProperties);
+      this.values = new ObservableList<double>(original.values);
+    }
+    public DataRow()
+      : base() {
+      VisualProperties = new DataRowVisualProperties();
+      values = new ObservableList<double>();
+    }
+    public DataRow(string name)
+      : base(name) {
+      VisualProperties = new DataRowVisualProperties();
+      values = new ObservableList<double>();
+    }
+    public DataRow(string name, string description)
+      : base(name, description) {
+      VisualProperties = new DataRowVisualProperties();
+      values = new ObservableList<double>();
+    }
+    public DataRow(string name, string description, IEnumerable<double> values)
+      : base(name, description) {
+      VisualProperties = new DataRowVisualProperties();
+      this.values = new ObservableList<double>(values);
+    }
+
+    // BackwardsCompatibility3.3
+    #region Backwards compatible code, remove with 3.4
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() {
+      if (VisualProperties == null) VisualProperties = new DataRowVisualProperties();
+    }
+    #endregion
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new DataRow(this, cloner);
+    }
+
+    public event EventHandler VisualPropertiesChanged;
+    private void OnVisualPropertiesChanged() {
+      EventHandler handler = VisualPropertiesChanged;
+      if (handler != null) handler(this, EventArgs.Empty);
+    }
+
+    private void VisualProperties_PropertyChanged(object sender, PropertyChangedEventArgs e) {
+      OnVisualPropertiesChanged();
+    }
+  }
+}
Index: trunk/sources/HeuristicLab.Analysis/3.3/DataVisualization/DataRowVisualProperties.cs
===================================================================
--- trunk/sources/HeuristicLab.Analysis/3.3/DataVisualization/DataRowVisualProperties.cs	(revision 4887)
+++ trunk/sources/HeuristicLab.Analysis/3.3/DataVisualization/DataRowVisualProperties.cs	(revision 4887)
@@ -0,0 +1,132 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2010 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You 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.ComponentModel;
+using System.Drawing;
+using HeuristicLab.Common;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Analysis {
+  /// <summary>
+  /// Visual properties of a DataRow.
+  /// </summary>
+  [StorableClass]
+  public class DataRowVisualProperties : DeepCloneable, INotifyPropertyChanged {
+    #region ChartType
+    public enum DataRowChartType {
+      Line,
+      Columns,
+      Points,
+      Bars
+    }
+    #endregion
+
+    private DataRowChartType chartType;
+    public DataRowChartType ChartType {
+      get { return chartType; }
+      set {
+        if (chartType != value) {
+          chartType = value;
+          OnPropertyChanged("ChartType");
+        }
+      }
+    }
+    private bool secondYAxis;
+    public bool SecondYAxis {
+      get { return secondYAxis; }
+      set {
+        if (secondYAxis != value) {
+          secondYAxis = value;
+          OnPropertyChanged("SecondYAxis");
+        }
+      }
+    }
+    private Color color;
+    public Color Color {
+      get { return color; }
+      set {
+        if (color != value) {
+          color = value;
+          OnPropertyChanged("Color");
+        }
+      }
+    }
+    private bool startIndexZero;
+    public bool StartIndexZero {
+      get { return startIndexZero; }
+      set {
+        if (startIndexZero != value) {
+          startIndexZero = value;
+          OnPropertyChanged("StartIndexZero");
+        }
+      }
+    }
+
+    #region Persistence Properties
+    [Storable(Name = "ChartType")]
+    private DataRowChartType StorableChartType {
+      get { return chartType; }
+      set { chartType = value; }
+    }
+    [Storable(Name = "SecondYAxis")]
+    private bool StorableSecondYAxis {
+      get { return secondYAxis; }
+      set { secondYAxis = value; }
+    }
+    [Storable(Name = "Color")]
+    private Color StorableColor {
+      get { return color; }
+      set { color = value; }
+    }
+    [Storable(Name = "StartIndexZero")]
+    private bool StorableStartIndexZero {
+      get { return startIndexZero; }
+      set { startIndexZero = value; }
+    }
+    #endregion
+
+    [StorableConstructor]
+    protected DataRowVisualProperties(bool deserializing) : base() { }
+    protected DataRowVisualProperties(DataRowVisualProperties original, Cloner cloner)
+      : base(original, cloner) {
+      this.chartType = original.chartType;
+      this.secondYAxis = original.secondYAxis;
+      this.color = original.color;
+      this.startIndexZero = original.startIndexZero;
+    }
+    public DataRowVisualProperties() {
+      chartType = DataRowChartType.Line;
+      secondYAxis = false;
+      color = Color.Empty;
+      startIndexZero = false;
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new DataRowVisualProperties(this, cloner);
+    }
+
+    public event PropertyChangedEventHandler PropertyChanged;
+    protected virtual void OnPropertyChanged(string propertyName) {
+      PropertyChangedEventHandler handler = PropertyChanged;
+      if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
+    }
+  }
+}
Index: trunk/sources/HeuristicLab.Analysis/3.3/DataVisualization/DataTable.cs
===================================================================
--- trunk/sources/HeuristicLab.Analysis/3.3/DataVisualization/DataTable.cs	(revision 4887)
+++ trunk/sources/HeuristicLab.Analysis/3.3/DataVisualization/DataTable.cs	(revision 4887)
@@ -0,0 +1,262 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2010 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You 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.ComponentModel;
+using System.Drawing;
+using System.Linq;
+using HeuristicLab.Collections;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Analysis {
+  /// <summary>
+  /// A table of data values.
+  /// </summary>
+  [Item("DataTable", "A table of data values.")]
+  [StorableClass]
+  public sealed class DataTable : NamedItem, IStringConvertibleMatrix {
+    public override Image ItemImage {
+      get { return HeuristicLab.Common.Resources.VS2008ImageLibrary.Performance; }
+    }
+
+    private DataTableVisualProperties visualProperties;
+    public DataTableVisualProperties VisualProperties {
+      get { return visualProperties; }
+      set {
+        if (visualProperties != value) {
+          if (value == null) throw new ArgumentNullException("VisualProperties");
+          if (visualProperties != null) visualProperties.PropertyChanged -= new PropertyChangedEventHandler(VisualProperties_PropertyChanged);
+          visualProperties = value;
+          visualProperties.PropertyChanged += new PropertyChangedEventHandler(VisualProperties_PropertyChanged);
+          OnVisualPropertiesChanged();
+        }
+      }
+    }
+
+    private NamedItemCollection<DataRow> rows;
+    public NamedItemCollection<DataRow> Rows {
+      get { return rows; }
+    }
+
+    #region Persistence Properties
+    [Storable(Name = "VisualProperties")]
+    private DataTableVisualProperties StorableVisualProperties {
+      get { return VisualProperties; }
+      set { VisualProperties = value; }
+    }
+    [Storable(Name = "rows")]
+    private IEnumerable<DataRow> StorableRows {
+      get { return rows; }
+      set { rows = new NamedItemCollection<DataRow>(value); }
+    }
+    #endregion
+
+    [StorableConstructor]
+    private DataTable(bool deserializing) : base(deserializing) { }
+    private DataTable(DataTable original, Cloner cloner)
+      : base(original, cloner) {
+      this.VisualProperties = (DataTableVisualProperties)cloner.Clone(original.visualProperties);
+      this.rows = cloner.Clone(original.rows);
+      this.RegisterRowsEvents();
+    }
+    public DataTable()
+      : base() {
+      VisualProperties = new DataTableVisualProperties();
+      rows = new NamedItemCollection<DataRow>();
+      this.RegisterRowsEvents();
+    }
+    public DataTable(string name)
+      : base(name) {
+      VisualProperties = new DataTableVisualProperties();
+      rows = new NamedItemCollection<DataRow>();
+      this.RegisterRowsEvents();
+    }
+    public DataTable(string name, string description)
+      : base(name, description) {
+      VisualProperties = new DataTableVisualProperties();
+      rows = new NamedItemCollection<DataRow>();
+      this.RegisterRowsEvents();
+    }
+
+    // BackwardsCompatibility3.3
+    #region Backwards compatible code, remove with 3.4
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() {
+      if (VisualProperties == null) VisualProperties = new DataTableVisualProperties();
+    }
+    #endregion
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new DataTable(this, cloner);
+    }
+
+    public event EventHandler VisualPropertiesChanged;
+    private void OnVisualPropertiesChanged() {
+      EventHandler handler = VisualPropertiesChanged;
+      if (handler != null) handler(this, EventArgs.Empty);
+    }
+
+    private void VisualProperties_PropertyChanged(object sender, PropertyChangedEventArgs e) {
+      OnVisualPropertiesChanged();
+    }
+
+    private void RegisterRowsEvents() {
+      rows.ItemsAdded += new CollectionItemsChangedEventHandler<DataRow>(rows_ItemsAdded);
+      rows.ItemsRemoved += new CollectionItemsChangedEventHandler<DataRow>(rows_ItemsRemoved);
+      rows.ItemsReplaced += new CollectionItemsChangedEventHandler<DataRow>(rows_ItemsReplaced);
+      rows.CollectionReset += new CollectionItemsChangedEventHandler<DataRow>(rows_CollectionReset);
+    }
+    private void rows_ItemsAdded(object sender, CollectionItemsChangedEventArgs<DataRow> e) {
+      foreach (DataRow row in e.Items)
+        this.RegisterRowEvents(row);
+      this.OnColumnNamesChanged();
+      this.OnReset();
+    }
+    private void rows_ItemsRemoved(object sender, CollectionItemsChangedEventArgs<DataRow> e) {
+      foreach (DataRow row in e.Items)
+        this.DeregisterRowEvents(row);
+      this.OnColumnNamesChanged();
+      this.OnReset();
+    }
+    private void rows_ItemsReplaced(object sender, CollectionItemsChangedEventArgs<DataRow> e) {
+      foreach (DataRow row in e.OldItems)
+        this.DeregisterRowEvents(row);
+      foreach (DataRow row in e.Items)
+        this.RegisterRowEvents(row);
+      this.OnColumnNamesChanged();
+      this.OnReset();
+    }
+    private void rows_CollectionReset(object sender, CollectionItemsChangedEventArgs<DataRow> e) {
+      foreach (DataRow row in e.OldItems)
+        this.DeregisterRowEvents(row);
+      foreach (DataRow row in e.Items)
+        this.RegisterRowEvents(row);
+      this.OnColumnNamesChanged();
+      this.OnReset();
+    }
+
+    private void RegisterRowEvents(DataRow row) {
+      row.Values.ItemsAdded += new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_ItemsAdded);
+      row.Values.ItemsMoved += new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_ItemsMoved);
+      row.Values.ItemsRemoved += new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_ItemsRemoved);
+      row.Values.ItemsReplaced += new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_ItemsReplaced);
+      row.Values.CollectionReset += new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_CollectionReset);
+    }
+    private void DeregisterRowEvents(DataRow row) {
+      row.Values.ItemsAdded -= new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_ItemsAdded);
+      row.Values.ItemsMoved -= new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_ItemsMoved);
+      row.Values.ItemsRemoved -= new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_ItemsRemoved);
+      row.Values.ItemsReplaced -= new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_ItemsReplaced);
+      row.Values.CollectionReset -= new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_CollectionReset);
+    }
+
+    private void Values_ItemsAdded(object sender, CollectionItemsChangedEventArgs<IndexedItem<double>> e) {
+      this.OnReset();
+    }
+    private void Values_ItemsMoved(object sender, CollectionItemsChangedEventArgs<IndexedItem<double>> e) {
+      this.OnReset();
+    }
+    private void Values_ItemsRemoved(object sender, CollectionItemsChangedEventArgs<IndexedItem<double>> e) {
+      this.OnReset();
+    }
+    private void Values_ItemsReplaced(object sender, CollectionItemsChangedEventArgs<IndexedItem<double>> e) {
+      this.OnReset();
+    }
+    private void Values_CollectionReset(object sender, CollectionItemsChangedEventArgs<IndexedItem<double>> e) {
+      this.OnReset();
+    }
+
+    #region IStringConvertibleMatrix Members
+
+    int IStringConvertibleMatrix.Rows {
+      get { return rows.Count == 0 ? 0 : rows.Max(r => r.Values.Count); }
+      set { throw new NotSupportedException(); }
+    }
+    int IStringConvertibleMatrix.Columns {
+      get { return rows.Count; }
+      set { throw new NotSupportedException(); }
+    }
+    IEnumerable<string> IStringConvertibleMatrix.ColumnNames {
+      get { return rows.Select(r => r.Name); }
+      set { throw new NotSupportedException(); }
+    }
+    IEnumerable<string> IStringConvertibleMatrix.RowNames {
+      get { return new List<string>(); }
+      set { throw new NotSupportedException(); }
+    }
+
+    bool IStringConvertibleMatrix.SortableView {
+      get { return true; }
+      set { throw new NotSupportedException(); }
+    }
+    bool IStringConvertibleMatrix.ReadOnly {
+      get { return true; }
+    }
+
+    string IStringConvertibleMatrix.GetValue(int rowIndex, int columnIndex) {
+      if (columnIndex < rows.Count) {
+        string columnName = ((IStringConvertibleMatrix)this).ColumnNames.ElementAt(columnIndex);
+        if (rows.ContainsKey(columnName) && rowIndex < rows[columnName].Values.Count)
+          return rows[columnName].Values[rowIndex].ToString();
+      }
+      return string.Empty;
+    }
+
+    bool IStringConvertibleMatrix.Validate(string value, out string errorMessage) {
+      throw new NotSupportedException();
+    }
+    bool IStringConvertibleMatrix.SetValue(string value, int rowIndex, int columnIndex) {
+      throw new NotSupportedException();
+    }
+
+    public event EventHandler<EventArgs<int, int>> ItemChanged;
+    private void OnItemChanged(int rowIndex, int columnIndex) {
+      var handler = ItemChanged;
+      if (handler != null) handler(this, new EventArgs<int, int>(rowIndex, columnIndex));
+      OnToStringChanged();
+    }
+    public event EventHandler Reset;
+    private void OnReset() {
+      var handler = Reset;
+      if (handler != null) handler(this, EventArgs.Empty);
+    }
+    public event EventHandler ColumnNamesChanged;
+    private void OnColumnNamesChanged() {
+      var handler = ColumnNamesChanged;
+      if (handler != null) handler(this, EventArgs.Empty);
+    }
+    public event EventHandler RowNamesChanged;
+    private void OnRowNamesChanged() {
+      var handler = RowNamesChanged;
+      if (handler != null) handler(this, EventArgs.Empty);
+    }
+    public event EventHandler SortableViewChanged;
+    private void OnSortableViewChanged() {
+      var handler = SortableViewChanged;
+      if (handler != null) handler(this, EventArgs.Empty);
+    }
+    #endregion
+  }
+}
Index: trunk/sources/HeuristicLab.Analysis/3.3/DataVisualization/DataTableHistory.cs
===================================================================
--- trunk/sources/HeuristicLab.Analysis/3.3/DataVisualization/DataTableHistory.cs	(revision 4887)
+++ trunk/sources/HeuristicLab.Analysis/3.3/DataVisualization/DataTableHistory.cs	(revision 4887)
@@ -0,0 +1,49 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2010 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Collections.Generic;
+using System.Drawing;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Analysis {
+  /// <summary>
+  /// Represents history values of data tables.
+  /// </summary>
+  [Item("DataTableHistory", "Represents history values of data tables.")]
+  [StorableClass]
+  public class DataTableHistory : ItemCollection<DataTable> {
+    public override Image ItemImage {
+      get { return HeuristicLab.Common.Resources.VS2008ImageLibrary.Cab; }
+    }
+
+    [StorableConstructor]
+    protected DataTableHistory(bool deserializing) : base(deserializing) { }
+    protected DataTableHistory(DataTableHistory original, Cloner cloner) : base(original, cloner) { }
+    public DataTableHistory() : base() { }
+    public DataTableHistory(IEnumerable<DataTable> collection) : base(new ItemCollection<DataTable>(collection)) { }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new DataTableHistory(this, cloner);
+    }
+  }
+}
Index: trunk/sources/HeuristicLab.Analysis/3.3/DataVisualization/DataTableValuesCollector.cs
===================================================================
--- trunk/sources/HeuristicLab.Analysis/3.3/DataVisualization/DataTableValuesCollector.cs	(revision 4887)
+++ trunk/sources/HeuristicLab.Analysis/3.3/DataVisualization/DataTableValuesCollector.cs	(revision 4887)
@@ -0,0 +1,113 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2010 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Operators;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Analysis {
+  /// <summary>
+  /// An operator which collects the actual values of parameters and adds them to a table of data values.
+  /// </summary>
+  [Item("DataTableValuesCollector", "An operator which collects the actual values of parameters and adds them to a table of data values.")]
+  [StorableClass]
+  public class DataTableValuesCollector : ValuesCollector {
+    public ValueLookupParameter<DataTable> DataTableParameter {
+      get { return (ValueLookupParameter<DataTable>)Parameters["DataTable"]; }
+    }
+
+    #region Storing & Cloning
+    [StorableConstructor]
+    protected DataTableValuesCollector(bool deserializing) : base(deserializing) { }
+    protected DataTableValuesCollector(DataTableValuesCollector original, Cloner cloner) : base(original, cloner) { }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new DataTableValuesCollector(this, cloner);
+    }
+    #endregion
+    public DataTableValuesCollector()
+      : base() {
+      Parameters.Add(new ValueLookupParameter<DataTable>("DataTable", "The table of data values where the collected values should be stored."));
+    }
+
+    public override IOperation Apply() {
+      DataTable table = DataTableParameter.ActualValue;
+      if (table == null) {
+        table = new DataTable(DataTableParameter.ActualName);
+        DataTableParameter.ActualValue = table;
+      }
+
+      foreach (IParameter param in CollectedValues) {
+        ILookupParameter lookupParam = param as ILookupParameter;
+        string name = lookupParam != null ? lookupParam.TranslatedName : param.Name;
+
+        if (param.ActualValue is DoubleValue) {
+          AddValue(table, (param.ActualValue as DoubleValue).Value, name, param.Description);
+        } else if (param.ActualValue is IntValue) {
+          AddValue(table, (param.ActualValue as IntValue).Value, name, param.Description);
+        } else if (param.ActualValue is IEnumerable<DoubleValue>) {
+          IEnumerable<DoubleValue> values = (IEnumerable<DoubleValue>)param.ActualValue;
+          if (values.Count() <= 1) {
+            foreach (DoubleValue data in values)
+              AddValue(table, data != null ? data.Value : double.NaN, name, param.Description);
+          } else {
+            int counter = 1;
+            foreach (DoubleValue data in values) {
+              AddValue(table, data != null ? data.Value : double.NaN, name + " " + counter.ToString(), param.Description);
+              counter++;
+            }
+          }
+        } else if (param.ActualValue is IEnumerable<IntValue>) {
+          IEnumerable<IntValue> values = (IEnumerable<IntValue>)param.ActualValue;
+          if (values.Count() <= 1) {
+            foreach (IntValue data in values)
+              AddValue(table, data != null ? data.Value : double.NaN, name, param.Description);
+          } else {
+            int counter = 1;
+            foreach (IntValue data in values) {
+              AddValue(table, data != null ? data.Value : double.NaN, name + " " + counter.ToString(), param.Description);
+              counter++;
+            }
+          }
+        } else {
+          AddValue(table, double.NaN, name, param.Description);
+        }
+      }
+      return base.Apply();
+    }
+
+    private void AddValue(DataTable table, double data, string name, string description) {
+      DataRow row;
+      table.Rows.TryGetValue(name, out row);
+      if (row == null) {
+        row = new DataRow(name, description);
+        row.Values.Add(data);
+        table.Rows.Add(row);
+      } else {
+        row.Values.Add(data);
+      }
+    }
+  }
+}
Index: trunk/sources/HeuristicLab.Analysis/3.3/DataVisualization/DataTableVisualProperties.cs
===================================================================
--- trunk/sources/HeuristicLab.Analysis/3.3/DataVisualization/DataTableVisualProperties.cs	(revision 4887)
+++ trunk/sources/HeuristicLab.Analysis/3.3/DataVisualization/DataTableVisualProperties.cs	(revision 4887)
@@ -0,0 +1,110 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2010 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You 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.ComponentModel;
+using HeuristicLab.Common;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Analysis {
+  /// <summary>
+  /// Visual properties of a DataTable.
+  /// </summary>
+  [StorableClass]
+  public class DataTableVisualProperties : DeepCloneable, INotifyPropertyChanged {
+    private string xAxisTitle;
+    public string XAxisTitle {
+      get { return xAxisTitle; }
+      set {
+        if (value == null) value = string.Empty;
+        if (xAxisTitle != value) {
+          xAxisTitle = value;
+          OnPropertyChanged("XAxisTitle");
+        }
+      }
+    }
+
+    private string yAxisTitle;
+    public string YAxisTitle {
+      get { return yAxisTitle; }
+      set {
+        if (value == null) value = string.Empty;
+        if (yAxisTitle != value) {
+          yAxisTitle = value;
+          OnPropertyChanged("YAxisTitle");
+        }
+      }
+    }
+
+    private string secondYAxisTitle;
+    public string SecondYAxisTitle {
+      get { return secondYAxisTitle; }
+      set {
+        if (value == null) value = string.Empty;
+        if (secondYAxisTitle != value) {
+          secondYAxisTitle = value;
+          OnPropertyChanged("SecondYAxisTitle");
+        }
+      }
+    }
+
+    #region Persistence Properties
+    [Storable(Name = "XAxisTitle")]
+    private string StorableXAxisTitle {
+      get { return xAxisTitle; }
+      set { xAxisTitle = value; }
+    }
+    [Storable(Name = "YAxisTitle")]
+    private string StorableYAxisTitle {
+      get { return yAxisTitle; }
+      set { yAxisTitle = value; }
+    }
+    [Storable(Name = "SecondYAxisTitle")]
+    private string StorableSecondYAxisTitle {
+      get { return secondYAxisTitle; }
+      set { secondYAxisTitle = value; }
+    }
+    #endregion
+
+    [StorableConstructor]
+    protected DataTableVisualProperties(bool deserializing) : base() { }
+    protected DataTableVisualProperties(DataTableVisualProperties original, Cloner cloner)
+      : base(original, cloner) {
+      this.xAxisTitle = original.xAxisTitle;
+      this.yAxisTitle = original.yAxisTitle;
+      this.secondYAxisTitle = original.secondYAxisTitle;
+    }
+    public DataTableVisualProperties() {
+      this.xAxisTitle = string.Empty;
+      this.yAxisTitle = string.Empty;
+      this.secondYAxisTitle = string.Empty;
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new DataTableVisualProperties(this, cloner);
+    }
+
+    public event PropertyChangedEventHandler PropertyChanged;
+    protected virtual void OnPropertyChanged(string propertyName) {
+      PropertyChangedEventHandler handler = PropertyChanged;
+      if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
+    }
+  }
+}
Index: trunk/sources/HeuristicLab.Analysis/3.3/DataVisualization/HeatMap.cs
===================================================================
--- trunk/sources/HeuristicLab.Analysis/3.3/DataVisualization/HeatMap.cs	(revision 4887)
+++ trunk/sources/HeuristicLab.Analysis/3.3/DataVisualization/HeatMap.cs	(revision 4887)
@@ -0,0 +1,159 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2010 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You 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.Drawing;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Analysis {
+  [Item("HeatMap", "Represents a heat map of double values.")]
+  [StorableClass]
+  public class HeatMap : DoubleMatrix {
+    public override Image ItemImage {
+      get { return HeuristicLab.Common.Resources.VS2008ImageLibrary.Gradient; }
+    }
+
+    private string title;
+    public string Title {
+      get { return title; }
+      set {
+        if (value == null) value = string.Empty;
+        if (title != value) {
+          title = value;
+          OnTitleChanged();
+        }
+      }
+    }
+    private double minimum;
+    public double Minimum {
+      get { return minimum; }
+      set {
+        if (minimum != value) {
+          minimum = value;
+          if (minimum >= maximum) Maximum = minimum + 1.0;
+          OnMinimumChanged();
+        }
+      }
+    }
+    private double maximum;
+    public double Maximum {
+      get { return maximum; }
+      set {
+        if (maximum != value) {
+          maximum = value;
+          if (maximum <= minimum) Minimum = maximum - 1.0;
+          OnMaximumChanged();
+        }
+      }
+    }
+
+    #region Storable Properties
+    [Storable(Name = "Title")]
+    private string StorableTitle {
+      get { return title; }
+      set { title = value; }
+    }
+    [Storable(Name = "Minimum")]
+    private double StorableMinimum {
+      get { return minimum; }
+      set { minimum = value; }
+    }
+    [Storable(Name = "Maximum")]
+    private double StorableMaximum {
+      get { return maximum; }
+      set { maximum = value; }
+    }
+    #endregion
+
+    [StorableConstructor]
+    protected HeatMap(bool deserializing) : base(deserializing) { }
+    protected HeatMap(HeatMap original, Cloner cloner)
+      : base(original, cloner) {
+      this.title = original.title;
+      this.minimum = original.minimum;
+      this.maximum = original.maximum;
+    }
+    public HeatMap()
+      : base() {
+      this.title = "Heat Map";
+      this.minimum = 0.0;
+      this.maximum = 1.0;
+    }
+    public HeatMap(int rows, int columns)
+      : base(rows, columns) {
+      this.title = "Heat Map";
+      this.minimum = 0.0;
+      this.maximum = 1.0;
+    }
+    public HeatMap(int rows, int columns, string title)
+      : base(rows, columns) {
+      this.title = title == null ? string.Empty : title;
+      this.minimum = 0.0;
+      this.maximum = 1.0;
+    }
+    public HeatMap(double[,] elements)
+      : base(elements) {
+      this.title = "Heat Map";
+      this.minimum = 0.0;
+      this.maximum = 1.0;
+    }
+    public HeatMap(double[,] elements, string title)
+      : base(elements) {
+      this.title = title == null ? string.Empty : title;
+      this.minimum = 0.0;
+      this.maximum = 1.0;
+    }
+    public HeatMap(double[,] elements, string title, double minimum, double maximum)
+      : base(elements) {
+      this.title = title == null ? string.Empty : title;
+      if (minimum >= maximum) throw new ArgumentException("Minimum is larger than or equal to maximum");
+      this.minimum = minimum;
+      this.maximum = maximum;
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new HeatMap(this, cloner);
+    }
+
+    public override string ToString() {
+      return Title;
+    }
+
+    public event EventHandler TitleChanged;
+    protected virtual void OnTitleChanged() {
+      var handler = TitleChanged;
+      if (handler != null) handler(this, EventArgs.Empty);
+    }
+    public event EventHandler MinimumChanged;
+    protected virtual void OnMinimumChanged() {
+      var handler = MinimumChanged;
+      if (handler != null) handler(this, EventArgs.Empty);
+    }
+    public event EventHandler MaximumChanged;
+    protected virtual void OnMaximumChanged() {
+      var handler = MaximumChanged;
+      if (handler != null) handler(this, EventArgs.Empty);
+    }
+  }
+}
Index: trunk/sources/HeuristicLab.Analysis/3.3/DataVisualization/HeatMapHistory.cs
===================================================================
--- trunk/sources/HeuristicLab.Analysis/3.3/DataVisualization/HeatMapHistory.cs	(revision 4887)
+++ trunk/sources/HeuristicLab.Analysis/3.3/DataVisualization/HeatMapHistory.cs	(revision 4887)
@@ -0,0 +1,49 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2010 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Collections.Generic;
+using System.Drawing;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Analysis {
+  /// <summary>
+  /// Represents history values of heat maps.
+  /// </summary>
+  [Item("HeatMapHistory", "Represents history values of heat maps.")]
+  [StorableClass]
+  public class HeatMapHistory : ItemCollection<HeatMap> {
+    public override Image ItemImage {
+      get { return HeuristicLab.Common.Resources.VS2008ImageLibrary.Cab; }
+    }
+
+    [StorableConstructor]
+    protected HeatMapHistory(bool deserializing) : base(deserializing) { }
+    protected HeatMapHistory(HeatMapHistory original, Cloner cloner) : base(original, cloner) { }
+    public HeatMapHistory() : base() { }
+    public HeatMapHistory(IEnumerable<HeatMap> collection) : base(new ItemCollection<HeatMap>(collection)) { }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new HeatMapHistory(this, cloner);
+    }
+  }
+}
Index: trunk/sources/HeuristicLab.Analysis/3.3/HeatMap.cs
===================================================================
--- trunk/sources/HeuristicLab.Analysis/3.3/HeatMap.cs	(revision 4870)
+++ 	(revision )
@@ -1,159 +1,0 @@
-#region License Information
-/* HeuristicLab
- * Copyright (C) 2002-2010 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
- *
- * This file is part of HeuristicLab.
- *
- * HeuristicLab is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * HeuristicLab is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You 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.Drawing;
-using HeuristicLab.Common;
-using HeuristicLab.Core;
-using HeuristicLab.Data;
-using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
-
-namespace HeuristicLab.Analysis {
-  [Item("HeatMap", "Represents a heat map of double values.")]
-  [StorableClass]
-  public class HeatMap : DoubleMatrix {
-    public override Image ItemImage {
-      get { return HeuristicLab.Common.Resources.VS2008ImageLibrary.Gradient; }
-    }
-
-    private string title;
-    public string Title {
-      get { return title; }
-      set {
-        if (value == null) value = string.Empty;
-        if (title != value) {
-          title = value;
-          OnTitleChanged();
-        }
-      }
-    }
-    private double minimum;
-    public double Minimum {
-      get { return minimum; }
-      set {
-        if (minimum != value) {
-          minimum = value;
-          if (minimum >= maximum) Maximum = minimum + 1.0;
-          OnMinimumChanged();
-        }
-      }
-    }
-    private double maximum;
-    public double Maximum {
-      get { return maximum; }
-      set {
-        if (maximum != value) {
-          maximum = value;
-          if (maximum <= minimum) Minimum = maximum - 1.0;
-          OnMaximumChanged();
-        }
-      }
-    }
-
-    #region Storable Properties
-    [Storable(Name = "Title")]
-    private string StorableTitle {
-      get { return title; }
-      set { title = value; }
-    }
-    [Storable(Name = "Minimum")]
-    private double StorableMinimum {
-      get { return minimum; }
-      set { minimum = value; }
-    }
-    [Storable(Name = "Maximum")]
-    private double StorableMaximum {
-      get { return maximum; }
-      set { maximum = value; }
-    }
-    #endregion
-
-    [StorableConstructor]
-    protected HeatMap(bool deserializing) : base(deserializing) { }
-    protected HeatMap(HeatMap original, Cloner cloner)
-      : base(original, cloner) {
-      this.title = original.title;
-      this.minimum = original.minimum;
-      this.maximum = original.maximum;
-    }
-    public HeatMap()
-      : base() {
-      this.title = "Heat Map";
-      this.minimum = 0.0;
-      this.maximum = 1.0;
-    }
-    public HeatMap(int rows, int columns)
-      : base(rows, columns) {
-      this.title = "Heat Map";
-      this.minimum = 0.0;
-      this.maximum = 1.0;
-    }
-    public HeatMap(int rows, int columns, string title)
-      : base(rows, columns) {
-      this.title = title == null ? string.Empty : title;
-      this.minimum = 0.0;
-      this.maximum = 1.0;
-    }
-    public HeatMap(double[,] elements)
-      : base(elements) {
-      this.title = "Heat Map";
-      this.minimum = 0.0;
-      this.maximum = 1.0;
-    }
-    public HeatMap(double[,] elements, string title)
-      : base(elements) {
-      this.title = title == null ? string.Empty : title;
-      this.minimum = 0.0;
-      this.maximum = 1.0;
-    }
-    public HeatMap(double[,] elements, string title, double minimum, double maximum)
-      : base(elements) {
-      this.title = title == null ? string.Empty : title;
-      if (minimum >= maximum) throw new ArgumentException("Minimum is larger than or equal to maximum");
-      this.minimum = minimum;
-      this.maximum = maximum;
-    }
-
-    public override IDeepCloneable Clone(Cloner cloner) {
-      return new HeatMap(this, cloner);
-    }
-
-    public override string ToString() {
-      return Title;
-    }
-
-    public event EventHandler TitleChanged;
-    protected virtual void OnTitleChanged() {
-      var handler = TitleChanged;
-      if (handler != null) handler(this, EventArgs.Empty);
-    }
-    public event EventHandler MinimumChanged;
-    protected virtual void OnMinimumChanged() {
-      var handler = MinimumChanged;
-      if (handler != null) handler(this, EventArgs.Empty);
-    }
-    public event EventHandler MaximumChanged;
-    protected virtual void OnMaximumChanged() {
-      var handler = MaximumChanged;
-      if (handler != null) handler(this, EventArgs.Empty);
-    }
-  }
-}
Index: trunk/sources/HeuristicLab.Analysis/3.3/HeatMapHistory.cs
===================================================================
--- trunk/sources/HeuristicLab.Analysis/3.3/HeatMapHistory.cs	(revision 4870)
+++ 	(revision )
@@ -1,49 +1,0 @@
-#region License Information
-/* HeuristicLab
- * Copyright (C) 2002-2010 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
- *
- * This file is part of HeuristicLab.
- *
- * HeuristicLab is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * HeuristicLab is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
- */
-#endregion
-
-using System.Collections.Generic;
-using System.Drawing;
-using HeuristicLab.Common;
-using HeuristicLab.Core;
-using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
-
-namespace HeuristicLab.Analysis {
-  /// <summary>
-  /// Represents history values of heat maps.
-  /// </summary>
-  [Item("HeatMapHistory", "Represents history values of heat maps.")]
-  [StorableClass]
-  public class HeatMapHistory : ItemCollection<HeatMap> {
-    public override Image ItemImage {
-      get { return HeuristicLab.Common.Resources.VS2008ImageLibrary.Cab; }
-    }
-
-    [StorableConstructor]
-    protected HeatMapHistory(bool deserializing) : base(deserializing) { }
-    protected HeatMapHistory(HeatMapHistory original, Cloner cloner) : base(original, cloner) { }
-    public HeatMapHistory() : base() { }
-    public HeatMapHistory(IEnumerable<HeatMap> collection) : base(new ItemCollection<HeatMap>(collection)) { }
-
-    public override IDeepCloneable Clone(Cloner cloner) {
-      return new HeatMapHistory(this, cloner);
-    }
-  }
-}
Index: trunk/sources/HeuristicLab.Analysis/3.3/HeuristicLab.Analysis-3.3.csproj
===================================================================
--- trunk/sources/HeuristicLab.Analysis/3.3/HeuristicLab.Analysis-3.3.csproj	(revision 4870)
+++ trunk/sources/HeuristicLab.Analysis/3.3/HeuristicLab.Analysis-3.3.csproj	(revision 4887)
@@ -110,30 +110,30 @@
   <ItemGroup>
     <None Include="HeuristicLabAnalysisPlugin.cs.frame" />
-    <Compile Include="AlleleFrequencyCollection.cs" />
-    <Compile Include="AlleleFrequencyCollectionHistory.cs" />
-    <Compile Include="BestAverageWorstQualityAnalyzer.cs" />
-    <Compile Include="BestAverageWorstQualityCalculator.cs" />
+    <Compile Include="AlleleFrequencyAnalysis\Allele.cs" />
+    <Compile Include="AlleleFrequencyAnalysis\AlleleFrequency.cs" />
+    <Compile Include="AlleleFrequencyAnalysis\AlleleFrequencyAnalyzer.cs" />
+    <Compile Include="AlleleFrequencyAnalysis\AlleleFrequencyCollection.cs" />
+    <Compile Include="AlleleFrequencyAnalysis\AlleleFrequencyCollectionHistory.cs" />
     <Compile Include="BestScopeSolutionAnalyzer.cs" />
-    <Compile Include="BestQualityMemorizer.cs" />
-    <Compile Include="Allele.cs" />
-    <Compile Include="AlleleFrequency.cs" />
-    <Compile Include="DataTableVisualProperties.cs" />
-    <Compile Include="DataTableHistory.cs" />
-    <Compile Include="HeatMapHistory.cs" />
-    <Compile Include="HeatMap.cs" />
-    <Compile Include="PopulationDiversityAnalyzer.cs" />
-    <Compile Include="DataRowVisualProperties.cs" />
-    <Compile Include="QualityAnalyzer.cs" />
-    <Compile Include="MinAverageMaxValueAnalyzer.cs" />
-    <Compile Include="MinAverageMaxValueCalculator.cs" />
+    <Compile Include="DataVisualization\DataRow.cs" />
+    <Compile Include="DataVisualization\DataRowVisualProperties.cs" />
+    <Compile Include="DataVisualization\DataTable.cs" />
+    <Compile Include="DataVisualization\DataTableHistory.cs" />
+    <Compile Include="DataVisualization\DataTableValuesCollector.cs" />
+    <Compile Include="DataVisualization\DataTableVisualProperties.cs" />
+    <Compile Include="DataVisualization\HeatMap.cs" />
+    <Compile Include="DataVisualization\HeatMapHistory.cs" />
+    <Compile Include="PopulationDiversityAnalysis\PopulationDiversityAnalyzer.cs" />
+    <Compile Include="QualityAnalysis\BestAverageWorstQualityAnalyzer.cs" />
+    <Compile Include="QualityAnalysis\BestAverageWorstQualityCalculator.cs" />
+    <Compile Include="QualityAnalysis\BestQualityMemorizer.cs" />
+    <Compile Include="QualityAnalysis\QualityAnalyzer.cs" />
+    <Compile Include="QualityAnalysis\QualityDifferenceCalculator.cs" />
     <Compile Include="MultiAnalyzer.cs" />
-    <Compile Include="QualityDifferenceCalculator.cs" />
-    <Compile Include="DataRow.cs" />
     <Compile Include="HeuristicLabAnalysisPlugin.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
-    <Compile Include="DataTable.cs" />
-    <Compile Include="DataTableValuesCollector.cs" />
-    <Compile Include="AlleleFrequencyAnalyzer.cs" />
-    <Compile Include="ValueAnalyzer.cs" />
+    <Compile Include="ValueAnalysis\MinAverageMaxValueAnalyzer.cs" />
+    <Compile Include="ValueAnalysis\MinAverageMaxValueCalculator.cs" />
+    <Compile Include="ValueAnalysis\ValueAnalyzer.cs" />
   </ItemGroup>
   <ItemGroup>
Index: trunk/sources/HeuristicLab.Analysis/3.3/MinAverageMaxValueAnalyzer.cs
===================================================================
--- trunk/sources/HeuristicLab.Analysis/3.3/MinAverageMaxValueAnalyzer.cs	(revision 4870)
+++ 	(revision )
@@ -1,220 +1,0 @@
-#region License Information
-/* HeuristicLab
- * Copyright (C) 2002-2010 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
- *
- * This file is part of HeuristicLab.
- *
- * HeuristicLab is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * HeuristicLab is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
- */
-#endregion
-
-using System;
-using HeuristicLab.Common;
-using HeuristicLab.Core;
-using HeuristicLab.Data;
-using HeuristicLab.Operators;
-using HeuristicLab.Optimization;
-using HeuristicLab.Optimization.Operators;
-using HeuristicLab.Parameters;
-using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
-
-namespace HeuristicLab.Analysis {
-  /// <summary>
-  /// An operator which analyzes the minimum, average and maximum of a value in the scope tree.
-  /// </summary>
-  [Item("MinAverageMaxValueAnalyzer", "An operator which analyzes the minimum, average and maximum of a value in the scope tree.")]
-  [StorableClass]
-  public sealed class MinAverageMaxValueAnalyzer : AlgorithmOperator, IAnalyzer {
-    #region Parameter properties
-    public ScopeTreeLookupParameter<DoubleValue> ValueParameter {
-      get { return (ScopeTreeLookupParameter<DoubleValue>)Parameters["Value"]; }
-    }
-    public ValueLookupParameter<DoubleValue> MinValueParameter {
-      get { return (ValueLookupParameter<DoubleValue>)Parameters["MinValue"]; }
-    }
-    public ValueLookupParameter<DoubleValue> AverageValueParameter {
-      get { return (ValueLookupParameter<DoubleValue>)Parameters["AverageValue"]; }
-    }
-    public ValueLookupParameter<DoubleValue> MaxValueParameter {
-      get { return (ValueLookupParameter<DoubleValue>)Parameters["MaxValue"]; }
-    }
-    public ValueLookupParameter<DataTable> ValuesParameter {
-      get { return (ValueLookupParameter<DataTable>)Parameters["Values"]; }
-    }
-    public ValueLookupParameter<VariableCollection> ResultsParameter {
-      get { return (ValueLookupParameter<VariableCollection>)Parameters["Results"]; }
-    }
-    public ValueParameter<BoolValue> CollectMinValueInResultsParameter {
-      get { return (ValueParameter<BoolValue>)Parameters["CollectMinValueInResults"]; }
-    }
-    public ValueParameter<BoolValue> CollectMaxValueInResultsParameter {
-      get { return (ValueParameter<BoolValue>)Parameters["CollectMaxValueInResults"]; }
-    }
-    public ValueParameter<BoolValue> CollectAverageValueInResultsParameter {
-      get { return (ValueParameter<BoolValue>)Parameters["CollectAverageValueInResults"]; }
-    }
-    #endregion
-
-    #region Properties
-    private MinAverageMaxValueCalculator MinAverageMaxValueCalculator {
-      get { return (MinAverageMaxValueCalculator)OperatorGraph.InitialOperator; }
-    }
-    private BoolValue CollectMinValueInResults {
-      get { return CollectMinValueInResultsParameter.Value; }
-    }
-    private BoolValue CollectMaxValueInResults {
-      get { return CollectMaxValueInResultsParameter.Value; }
-    }
-    private BoolValue CollectAverageValueInResults {
-      get { return CollectAverageValueInResultsParameter.Value; }
-    }
-    #endregion
-    [Storable]
-    private ResultsCollector resultsCollector;
-
-    #region Storing & Cloning
-    [StorableConstructor]
-    private MinAverageMaxValueAnalyzer(bool deserializing) : base(deserializing) { }
-    private MinAverageMaxValueAnalyzer(MinAverageMaxValueAnalyzer original, Cloner cloner)
-      : base(original, cloner) {
-      resultsCollector = cloner.Clone(original.resultsCollector);
-      Initialize();
-    }
-    public override IDeepCloneable Clone(Cloner cloner) {
-      return new MinAverageMaxValueAnalyzer(this, cloner);
-    }
-    #endregion
-    public MinAverageMaxValueAnalyzer()
-      : base() {
-      #region Create parameters
-      Parameters.Add(new ScopeTreeLookupParameter<DoubleValue>("Value", "The value contained in the scope tree which should be analyzed."));
-      Parameters.Add(new ValueLookupParameter<DoubleValue>("MinValue", "The minimum of the value."));
-      Parameters.Add(new ValueParameter<BoolValue>("CollectMinValueInResults", "Determines if the minimum of the value should also be stored in the results.", new BoolValue(true)));
-      Parameters.Add(new ValueLookupParameter<DoubleValue>("AverageValue", "The average of the value."));
-      Parameters.Add(new ValueParameter<BoolValue>("CollectAverageValueInResults", "Determines if the average of the value should also be stored in the results.", new BoolValue(true)));
-      Parameters.Add(new ValueLookupParameter<DoubleValue>("MaxValue", "The maximum of the value."));
-      Parameters.Add(new ValueParameter<BoolValue>("CollectMaxValueInResults", "Determines if the maximum of the value should also be stored in the results.", new BoolValue(true)));
-      Parameters.Add(new ValueLookupParameter<DataTable>("Values", "The data table to store the minimum, average and maximum of the value."));
-      Parameters.Add(new ValueLookupParameter<VariableCollection>("Results", "The results collection where the analysis values should be stored."));
-      #endregion
-
-      #region Create operators
-      MinAverageMaxValueCalculator minAverageMaxValueCalculator = new MinAverageMaxValueCalculator();
-      DataTableValuesCollector dataTableValuesCollector = new DataTableValuesCollector();
-      resultsCollector = new ResultsCollector();
-
-      minAverageMaxValueCalculator.AverageValueParameter.ActualName = AverageValueParameter.Name;
-      minAverageMaxValueCalculator.MaxValueParameter.ActualName = MaxValueParameter.Name;
-      minAverageMaxValueCalculator.MinValueParameter.ActualName = MinValueParameter.Name;
-      minAverageMaxValueCalculator.ValueParameter.ActualName = ValueParameter.Name;
-      minAverageMaxValueCalculator.ValueParameter.Depth = ValueParameter.Depth;
-
-      dataTableValuesCollector.CollectedValues.Add(new LookupParameter<DoubleValue>("MinValue", null, MinValueParameter.Name));
-      dataTableValuesCollector.CollectedValues.Add(new LookupParameter<DoubleValue>("AverageValue", null, AverageValueParameter.Name));
-      dataTableValuesCollector.CollectedValues.Add(new LookupParameter<DoubleValue>("MaxValue", null, MaxValueParameter.Name));
-      dataTableValuesCollector.DataTableParameter.ActualName = ValuesParameter.Name;
-
-      if (CollectMinValueInResults.Value)
-        resultsCollector.CollectedValues.Add(new LookupParameter<DoubleValue>("MinValue", null, MinValueParameter.Name));
-      if (CollectAverageValueInResults.Value)
-        resultsCollector.CollectedValues.Add(new LookupParameter<DoubleValue>("AverageValue", null, AverageValueParameter.Name));
-      if (CollectMaxValueInResults.Value)
-        resultsCollector.CollectedValues.Add(new LookupParameter<DoubleValue>("MaxValue", null, MaxValueParameter.Name));
-      resultsCollector.CollectedValues.Add(new LookupParameter<DataTable>(ValuesParameter.Name));
-      resultsCollector.ResultsParameter.ActualName = ResultsParameter.Name;
-      #endregion
-
-      #region Create operator graph
-      OperatorGraph.InitialOperator = minAverageMaxValueCalculator;
-      minAverageMaxValueCalculator.Successor = dataTableValuesCollector;
-      dataTableValuesCollector.Successor = resultsCollector;
-      resultsCollector.Successor = null;
-      #endregion
-
-      Initialize();
-    }
-
-    [StorableHook(HookType.AfterDeserialization)]
-    private void Initialize() {
-      ValueParameter.DepthChanged += new EventHandler(ValueParameter_DepthChanged);
-      CollectMinValueInResultsParameter.ValueChanged += new EventHandler(CollectMinValueInResultsParameter_ValueChanged);
-      CollectMinValueInResultsParameter.Value.ValueChanged += new EventHandler(CollectMinValueInResultsParameter_Value_ValueChanged);
-      CollectMaxValueInResultsParameter.ValueChanged += new EventHandler(CollectMaxValueInResultsParameter_ValueChanged);
-      CollectMaxValueInResultsParameter.Value.ValueChanged += new EventHandler(CollectMaxValueInResultsParameter_Value_ValueChanged);
-      CollectAverageValueInResultsParameter.ValueChanged += new EventHandler(CollectAverageValueInResultsParameter_ValueChanged);
-      CollectAverageValueInResultsParameter.Value.ValueChanged += new EventHandler(CollectAverageValueInResultsParameter_Value_ValueChanged);
-    }
-
-    private void CollectAverageValueInResultsParameter_ValueChanged(object sender, EventArgs e) {
-      IParameter avgValueParameter;
-      resultsCollector.CollectedValues.TryGetValue("AverageValue", out avgValueParameter);
-      if (CollectAverageValueInResults.Value && avgValueParameter == null)
-        resultsCollector.CollectedValues.Add(new LookupParameter<DoubleValue>("AverageValue", null, AverageValueParameter.Name));
-      else if (!CollectAverageValueInResults.Value && avgValueParameter != null)
-        resultsCollector.CollectedValues.Remove(avgValueParameter);
-      CollectAverageValueInResultsParameter.Value.ValueChanged += new EventHandler(CollectAverageValueInResultsParameter_Value_ValueChanged);
-    }
-
-    private void CollectAverageValueInResultsParameter_Value_ValueChanged(object sender, EventArgs e) {
-      IParameter avgValueParameter;
-      resultsCollector.CollectedValues.TryGetValue("AverageValue", out avgValueParameter);
-      if (CollectAverageValueInResults.Value && avgValueParameter == null)
-        resultsCollector.CollectedValues.Add(new LookupParameter<DoubleValue>("AverageValue", null, AverageValueParameter.Name));
-      else if (!CollectAverageValueInResults.Value && avgValueParameter != null)
-        resultsCollector.CollectedValues.Remove(avgValueParameter);
-    }
-
-    private void CollectMaxValueInResultsParameter_ValueChanged(object sender, EventArgs e) {
-      IParameter maxValueParameter;
-      resultsCollector.CollectedValues.TryGetValue("MaxValue", out maxValueParameter);
-      if (CollectMaxValueInResults.Value && maxValueParameter == null)
-        resultsCollector.CollectedValues.Add(new LookupParameter<DoubleValue>("MaxValue", null, MaxValueParameter.Name));
-      else if (!CollectMaxValueInResults.Value && maxValueParameter != null)
-        resultsCollector.CollectedValues.Remove(maxValueParameter);
-      CollectMaxValueInResultsParameter.Value.ValueChanged += new EventHandler(CollectMaxValueInResultsParameter_Value_ValueChanged);
-    }
-
-    private void CollectMaxValueInResultsParameter_Value_ValueChanged(object sender, EventArgs e) {
-      IParameter maxValueParameter;
-      resultsCollector.CollectedValues.TryGetValue("MaxValue", out maxValueParameter);
-      if (CollectMaxValueInResults.Value && maxValueParameter == null)
-        resultsCollector.CollectedValues.Add(new LookupParameter<DoubleValue>("MaxValue", null, MaxValueParameter.Name));
-      else if (!CollectMaxValueInResults.Value && maxValueParameter != null)
-        resultsCollector.CollectedValues.Remove(maxValueParameter);
-      }
-
-    private void CollectMinValueInResultsParameter_ValueChanged(object sender, EventArgs e) {
-      IParameter minValueParameter;
-      resultsCollector.CollectedValues.TryGetValue("MinValue", out minValueParameter);
-      if (CollectMinValueInResults.Value && minValueParameter == null)
-        resultsCollector.CollectedValues.Add(new LookupParameter<DoubleValue>("MinValue", null, MinValueParameter.Name));
-      else if (!CollectMinValueInResults.Value && minValueParameter != null)
-        resultsCollector.CollectedValues.Remove(minValueParameter);
-      CollectMinValueInResultsParameter.Value.ValueChanged += new EventHandler(CollectMinValueInResultsParameter_Value_ValueChanged);
-    }
-
-    private void CollectMinValueInResultsParameter_Value_ValueChanged(object sender, EventArgs e) {
-      IParameter minValueParameter;
-      resultsCollector.CollectedValues.TryGetValue("MinValue", out minValueParameter);
-      if (CollectMinValueInResults.Value && minValueParameter == null)
-        resultsCollector.CollectedValues.Add(new LookupParameter<DoubleValue>("MinValue", null, MinValueParameter.Name));
-      else if (!CollectMinValueInResults.Value && minValueParameter != null)
-        resultsCollector.CollectedValues.Remove(minValueParameter);
-    }
-
-    private void ValueParameter_DepthChanged(object sender, System.EventArgs e) {
-      MinAverageMaxValueCalculator.ValueParameter.Depth = ValueParameter.Depth;
-    }
-  }
-}
Index: trunk/sources/HeuristicLab.Analysis/3.3/MinAverageMaxValueCalculator.cs
===================================================================
--- trunk/sources/HeuristicLab.Analysis/3.3/MinAverageMaxValueCalculator.cs	(revision 4870)
+++ 	(revision )
@@ -1,89 +1,0 @@
-#region License Information
-/* HeuristicLab
- * Copyright (C) 2002-2010 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
- *
- * This file is part of HeuristicLab.
- *
- * HeuristicLab is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * HeuristicLab is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
- */
-#endregion
-
-using HeuristicLab.Common;
-using HeuristicLab.Core;
-using HeuristicLab.Data;
-using HeuristicLab.Operators;
-using HeuristicLab.Parameters;
-using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
-
-namespace HeuristicLab.Analysis {
-  /// <summary>
-  /// An operator which calculates the minimum, average and maximum of a value in the scope tree.
-  /// </summary>
-  [Item("MinAverageMaxValueCalculator", "An operator which calculates the minimum, average and maximum of a value in the scope tree.")]
-  [StorableClass]
-  public sealed class MinAverageMaxValueCalculator : SingleSuccessorOperator {
-    public ScopeTreeLookupParameter<DoubleValue> ValueParameter {
-      get { return (ScopeTreeLookupParameter<DoubleValue>)Parameters["Value"]; }
-    }
-    public ValueLookupParameter<DoubleValue> MinValueParameter {
-      get { return (ValueLookupParameter<DoubleValue>)Parameters["MinValue"]; }
-    }
-    public ValueLookupParameter<DoubleValue> AverageValueParameter {
-      get { return (ValueLookupParameter<DoubleValue>)Parameters["AverageValue"]; }
-    }
-    public ValueLookupParameter<DoubleValue> MaxValueParameter {
-      get { return (ValueLookupParameter<DoubleValue>)Parameters["MaxValue"]; }
-    }
-
-    #region Storing & Cloning
-    [StorableConstructor]
-    private MinAverageMaxValueCalculator(bool deserializing) : base(deserializing) { }
-    private MinAverageMaxValueCalculator(MinAverageMaxValueCalculator original, Cloner cloner) : base(original, cloner) { }
-    public override IDeepCloneable Clone(Cloner cloner) {
-      return new MinAverageMaxValueCalculator(this, cloner);
-    }
-    #endregion
-    public MinAverageMaxValueCalculator()
-      : base() {
-      Parameters.Add(new ScopeTreeLookupParameter<DoubleValue>("Value", "The value contained in the scope tree for which the minimum, average and maximum should be calculated."));
-      Parameters.Add(new ValueLookupParameter<DoubleValue>("MinValue", "The minimum of the value."));
-      Parameters.Add(new ValueLookupParameter<DoubleValue>("AverageValue", "The average of the value."));
-      Parameters.Add(new ValueLookupParameter<DoubleValue>("MaxValue", "The maximum of the value."));
-    }
-
-    public override IOperation Apply() {
-      ItemArray<DoubleValue> values = ValueParameter.ActualValue;
-
-      if (values.Length > 0) {
-        double min = double.MaxValue, max = double.MinValue, sum = 0.0;
-        for (int i = 0; i < values.Length; i++) {
-          if (values[i].Value < min) min = values[i].Value;
-          if (values[i].Value > max) max = values[i].Value;
-          sum += values[i].Value;
-        }
-
-        DoubleValue minValue = MinValueParameter.ActualValue;
-        if (minValue == null) MinValueParameter.ActualValue = new DoubleValue(min);
-        else minValue.Value = min;
-        DoubleValue averageValue = AverageValueParameter.ActualValue;
-        if (averageValue == null) AverageValueParameter.ActualValue = new DoubleValue(sum / values.Length);
-        else averageValue.Value = sum / values.Length;
-        DoubleValue maxValue = MaxValueParameter.ActualValue;
-        if (maxValue == null) MaxValueParameter.ActualValue = new DoubleValue(max);
-        else maxValue.Value = max;
-      }
-      return base.Apply();
-    }
-  }
-}
Index: trunk/sources/HeuristicLab.Analysis/3.3/PopulationDiversityAnalysis/PopulationDiversityAnalyzer.cs
===================================================================
--- trunk/sources/HeuristicLab.Analysis/3.3/PopulationDiversityAnalysis/PopulationDiversityAnalyzer.cs	(revision 4887)
+++ trunk/sources/HeuristicLab.Analysis/3.3/PopulationDiversityAnalysis/PopulationDiversityAnalyzer.cs	(revision 4887)
@@ -0,0 +1,237 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2010 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Operators;
+using HeuristicLab.Optimization;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Analysis {
+  /// <summary>
+  /// An operator for analyzing the solution diversity in a population.
+  /// </summary>
+  [Item("PopulationDiversityAnalyzer", "An operator for analyzing the solution diversity in a population.")]
+  [StorableClass]
+  public abstract class PopulationDiversityAnalyzer<T> : SingleSuccessorOperator, IAnalyzer where T : class, IItem {
+    public LookupParameter<BoolValue> MaximizationParameter {
+      get { return (LookupParameter<BoolValue>)Parameters["Maximization"]; }
+    }
+    public ScopeTreeLookupParameter<T> SolutionParameter {
+      get { return (ScopeTreeLookupParameter<T>)Parameters["Solution"]; }
+    }
+    public ScopeTreeLookupParameter<DoubleValue> QualityParameter {
+      get { return (ScopeTreeLookupParameter<DoubleValue>)Parameters["Quality"]; }
+    }
+    public ValueLookupParameter<ResultCollection> ResultsParameter {
+      get { return (ValueLookupParameter<ResultCollection>)Parameters["Results"]; }
+    }
+    public ValueParameter<BoolValue> StoreHistoryParameter {
+      get { return (ValueParameter<BoolValue>)Parameters["StoreHistory"]; }
+    }
+    public ValueParameter<IntValue> UpdateIntervalParameter {
+      get { return (ValueParameter<IntValue>)Parameters["UpdateInterval"]; }
+    }
+    public LookupParameter<IntValue> UpdateCounterParameter {
+      get { return (LookupParameter<IntValue>)Parameters["UpdateCounter"]; }
+    }
+
+    [StorableConstructor]
+    protected PopulationDiversityAnalyzer(bool deserializing) : base(deserializing) { }
+    protected PopulationDiversityAnalyzer(PopulationDiversityAnalyzer<T> original, Cloner cloner) : base(original, cloner) { }
+    public PopulationDiversityAnalyzer()
+      : base() {
+      Parameters.Add(new LookupParameter<BoolValue>("Maximization", "True if the problem is a maximization problem."));
+      Parameters.Add(new ScopeTreeLookupParameter<T>("Solution", "The solutions whose diversity should be analyzed."));
+      Parameters.Add(new ScopeTreeLookupParameter<DoubleValue>("Quality", "The qualities of the solutions which should be analyzed."));
+      Parameters.Add(new ValueLookupParameter<ResultCollection>("Results", "The result collection where the population diversity analysis results should be stored."));
+      Parameters.Add(new ValueParameter<BoolValue>("StoreHistory", "True if the history of the population diversity analysis should be stored.", new BoolValue(false)));
+      Parameters.Add(new ValueParameter<IntValue>("UpdateInterval", "The interval in which the population diversity analysis should be applied.", new IntValue(1)));
+      Parameters.Add(new LookupParameter<IntValue>("UpdateCounter", "The value which counts how many times the operator was called since the last update.", "PopulationDiversityAnalyzerUpdateCounter"));
+    }
+
+    public override IOperation Apply() {
+      int updateInterval = UpdateIntervalParameter.Value.Value;
+      IntValue updateCounter = UpdateCounterParameter.ActualValue;
+      // if counter does not yet exist then initialize it with update interval 
+      // to make sure the solutions are analyzed on the first application of this operator
+      if (updateCounter == null) {
+        updateCounter = new IntValue(updateInterval);
+        UpdateCounterParameter.ActualValue = updateCounter;
+      } else updateCounter.Value++;
+
+      //analyze solutions only every 'updateInterval' times
+      if (updateCounter.Value == updateInterval) {
+        updateCounter.Value = 0;
+
+        bool max = MaximizationParameter.ActualValue.Value;
+        ItemArray<T> solutions = SolutionParameter.ActualValue;
+        ItemArray<DoubleValue> qualities = QualityParameter.ActualValue;
+        bool storeHistory = StoreHistoryParameter.Value.Value;
+        int count = solutions.Length;
+
+        if (count > 1) {
+          // sort solutions by quality
+          T[] sortedSolutions = null;
+          if (max)
+            sortedSolutions = solutions
+              .Select((x, index) => new { Solution = x, Quality = qualities[index] })
+              .OrderByDescending(x => x.Quality)
+              .Select(x => x.Solution)
+              .ToArray();
+          else
+            sortedSolutions = solutions
+              .Select((x, index) => new { Solution = x, Quality = qualities[index] })
+              .OrderBy(x => x.Quality)
+              .Select(x => x.Solution)
+              .ToArray();
+
+          // calculate solution similarities
+          double[,] similarities = CalculateSimilarities(sortedSolutions);
+
+          // calculate minimum, average and maximum similarities
+          double similarity;
+          double[] minSimilarities = new double[count];
+          double[] avgSimilarities = new double[count];
+          double[] maxSimilarities = new double[count];
+          for (int i = 0; i < count; i++) {
+            minSimilarities[i] = 1;
+            avgSimilarities[i] = 0;
+            maxSimilarities[i] = 0;
+            for (int j = 0; j < count; j++) {
+              if (i != j) {
+                similarity = similarities[i, j];
+
+                if ((similarity < 0) || (similarity > 1))
+                  throw new InvalidOperationException("Solution similarities have to be in the interval [0;1].");
+
+                if (minSimilarities[i] > similarity) minSimilarities[i] = similarity;
+                avgSimilarities[i] += similarity;
+                if (maxSimilarities[i] < similarity) maxSimilarities[i] = similarity;
+              }
+            }
+            avgSimilarities[i] = avgSimilarities[i] / (count - 1);
+          }
+          double avgMinSimilarity = minSimilarities.Average();
+          double avgAvgSimilarity = avgSimilarities.Average();
+          double avgMaxSimilarity = maxSimilarities.Average();
+
+          // fetch results collection
+          ResultCollection results;
+          if (!ResultsParameter.ActualValue.ContainsKey("Population Diversity Analysis Results")) {
+            results = new ResultCollection();
+            ResultsParameter.ActualValue.Add(new Result("Population Diversity Analysis Results", results));
+          } else {
+            results = (ResultCollection)ResultsParameter.ActualValue["Population Diversity Analysis Results"].Value;
+          }
+
+          // store similarities
+          HeatMap similaritiesHeatMap = new HeatMap(similarities, "Solution Similarities", 0.0, 1.0);
+          if (!results.ContainsKey("Solution Similarities"))
+            results.Add(new Result("Solution Similarities", similaritiesHeatMap));
+          else
+            results["Solution Similarities"].Value = similaritiesHeatMap;
+
+          // store similarities history
+          if (storeHistory) {
+            if (!results.ContainsKey("Solution Similarities History")) {
+              HeatMapHistory history = new HeatMapHistory();
+              history.Add(similaritiesHeatMap);
+              results.Add(new Result("Solution Similarities History", history));
+            } else {
+              ((HeatMapHistory)results["Solution Similarities History"].Value).Add(similaritiesHeatMap);
+            }
+          }
+
+          // store average minimum, average and maximum similarity
+          if (!results.ContainsKey("Average Minimum Solution Similarity"))
+            results.Add(new Result("Average Minimum Solution Similarity", new DoubleValue(avgMinSimilarity)));
+          else
+            ((DoubleValue)results["Average Minimum Solution Similarity"].Value).Value = avgMinSimilarity;
+
+          if (!results.ContainsKey("Average Average Solution Similarity"))
+            results.Add(new Result("Average Average Solution Similarity", new DoubleValue(avgAvgSimilarity)));
+          else
+            ((DoubleValue)results["Average Average Solution Similarity"].Value).Value = avgAvgSimilarity;
+
+          if (!results.ContainsKey("Average Maximum Solution Similarity"))
+            results.Add(new Result("Average Maximum Solution Similarity", new DoubleValue(avgMaxSimilarity)));
+          else
+            ((DoubleValue)results["Average Maximum Solution Similarity"].Value).Value = avgMaxSimilarity;
+
+          // store average minimum, average and maximum solution similarity data table
+          DataTable minAvgMaxSimilarityDataTable;
+          if (!results.ContainsKey("Average Minimum/Average/Maximum Solution Similarity")) {
+            minAvgMaxSimilarityDataTable = new DataTable("Average Minimum/Average/Maximum Solution Similarity");
+            minAvgMaxSimilarityDataTable.VisualProperties.XAxisTitle = "Iteration";
+            minAvgMaxSimilarityDataTable.VisualProperties.YAxisTitle = "Solution Similarity";
+            minAvgMaxSimilarityDataTable.Rows.Add(new DataRow("Average Minimum Solution Similarity", null));
+            minAvgMaxSimilarityDataTable.Rows["Average Minimum Solution Similarity"].VisualProperties.StartIndexZero = true;
+            minAvgMaxSimilarityDataTable.Rows.Add(new DataRow("Average Average Solution Similarity", null));
+            minAvgMaxSimilarityDataTable.Rows["Average Average Solution Similarity"].VisualProperties.StartIndexZero = true;
+            minAvgMaxSimilarityDataTable.Rows.Add(new DataRow("Average Maximum Solution Similarity", null));
+            minAvgMaxSimilarityDataTable.Rows["Average Maximum Solution Similarity"].VisualProperties.StartIndexZero = true;
+            results.Add(new Result("Average Minimum/Average/Maximum Solution Similarity", minAvgMaxSimilarityDataTable));
+          } else {
+            minAvgMaxSimilarityDataTable = (DataTable)results["Average Minimum/Average/Maximum Solution Similarity"].Value;
+          }
+          minAvgMaxSimilarityDataTable.Rows["Average Minimum Solution Similarity"].Values.Add(avgMinSimilarity);
+          minAvgMaxSimilarityDataTable.Rows["Average Average Solution Similarity"].Values.Add(avgAvgSimilarity);
+          minAvgMaxSimilarityDataTable.Rows["Average Maximum Solution Similarity"].Values.Add(avgMaxSimilarity);
+
+          // store minimum, average, maximum similarities data table
+          DataTable minAvgMaxSimilaritiesDataTable = new DataTable("Minimum/Average/Maximum Solution Similarities");
+          minAvgMaxSimilaritiesDataTable.VisualProperties.XAxisTitle = "Solution Index";
+          minAvgMaxSimilaritiesDataTable.VisualProperties.YAxisTitle = "Solution Similarity";
+          minAvgMaxSimilaritiesDataTable.Rows.Add(new DataRow("Minimum Solution Similarity", null, minSimilarities));
+          minAvgMaxSimilaritiesDataTable.Rows["Minimum Solution Similarity"].VisualProperties.ChartType = DataRowVisualProperties.DataRowChartType.Points;
+          minAvgMaxSimilaritiesDataTable.Rows.Add(new DataRow("Average Solution Similarity", null, avgSimilarities));
+          minAvgMaxSimilaritiesDataTable.Rows["Average Solution Similarity"].VisualProperties.ChartType = DataRowVisualProperties.DataRowChartType.Points;
+          minAvgMaxSimilaritiesDataTable.Rows.Add(new DataRow("Maximum Solution Similarity", null, maxSimilarities));
+          minAvgMaxSimilaritiesDataTable.Rows["Maximum Solution Similarity"].VisualProperties.ChartType = DataRowVisualProperties.DataRowChartType.Points;
+          if (!results.ContainsKey("Minimum/Average/Maximum Solution Similarities")) {
+            results.Add(new Result("Minimum/Average/Maximum Solution Similarities", minAvgMaxSimilaritiesDataTable));
+          } else {
+            results["Minimum/Average/Maximum Solution Similarities"].Value = minAvgMaxSimilaritiesDataTable;
+          }
+
+          // store minimum, average, maximum similarities history
+          if (storeHistory) {
+            if (!results.ContainsKey("Minimum/Average/Maximum Solution Similarities History")) {
+              DataTableHistory history = new DataTableHistory();
+              history.Add(minAvgMaxSimilaritiesDataTable);
+              results.Add(new Result("Minimum/Average/Maximum Solution Similarities History", history));
+            } else {
+              ((DataTableHistory)results["Minimum/Average/Maximum Solution Similarities History"].Value).Add(minAvgMaxSimilaritiesDataTable);
+            }
+          }
+        }
+      }
+      return base.Apply();
+    }
+
+    protected abstract double[,] CalculateSimilarities(T[] solutions);
+  }
+}
Index: trunk/sources/HeuristicLab.Analysis/3.3/PopulationDiversityAnalyzer.cs
===================================================================
--- trunk/sources/HeuristicLab.Analysis/3.3/PopulationDiversityAnalyzer.cs	(revision 4870)
+++ 	(revision )
@@ -1,237 +1,0 @@
-#region License Information
-/* HeuristicLab
- * Copyright (C) 2002-2010 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
- *
- * This file is part of HeuristicLab.
- *
- * HeuristicLab is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * HeuristicLab is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
- */
-#endregion
-
-using System;
-using System.Linq;
-using HeuristicLab.Common;
-using HeuristicLab.Core;
-using HeuristicLab.Data;
-using HeuristicLab.Operators;
-using HeuristicLab.Optimization;
-using HeuristicLab.Parameters;
-using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
-
-namespace HeuristicLab.Analysis {
-  /// <summary>
-  /// An operator for analyzing the solution diversity in a population.
-  /// </summary>
-  [Item("PopulationDiversityAnalyzer", "An operator for analyzing the solution diversity in a population.")]
-  [StorableClass]
-  public abstract class PopulationDiversityAnalyzer<T> : SingleSuccessorOperator, IAnalyzer where T : class, IItem {
-    public LookupParameter<BoolValue> MaximizationParameter {
-      get { return (LookupParameter<BoolValue>)Parameters["Maximization"]; }
-    }
-    public ScopeTreeLookupParameter<T> SolutionParameter {
-      get { return (ScopeTreeLookupParameter<T>)Parameters["Solution"]; }
-    }
-    public ScopeTreeLookupParameter<DoubleValue> QualityParameter {
-      get { return (ScopeTreeLookupParameter<DoubleValue>)Parameters["Quality"]; }
-    }
-    public ValueLookupParameter<ResultCollection> ResultsParameter {
-      get { return (ValueLookupParameter<ResultCollection>)Parameters["Results"]; }
-    }
-    public ValueParameter<BoolValue> StoreHistoryParameter {
-      get { return (ValueParameter<BoolValue>)Parameters["StoreHistory"]; }
-    }
-    public ValueParameter<IntValue> UpdateIntervalParameter {
-      get { return (ValueParameter<IntValue>)Parameters["UpdateInterval"]; }
-    }
-    public LookupParameter<IntValue> UpdateCounterParameter {
-      get { return (LookupParameter<IntValue>)Parameters["UpdateCounter"]; }
-    }
-
-    [StorableConstructor]
-    protected PopulationDiversityAnalyzer(bool deserializing) : base(deserializing) { }
-    protected PopulationDiversityAnalyzer(PopulationDiversityAnalyzer<T> original, Cloner cloner) : base(original, cloner) { }
-    public PopulationDiversityAnalyzer()
-      : base() {
-      Parameters.Add(new LookupParameter<BoolValue>("Maximization", "True if the problem is a maximization problem."));
-      Parameters.Add(new ScopeTreeLookupParameter<T>("Solution", "The solutions whose diversity should be analyzed."));
-      Parameters.Add(new ScopeTreeLookupParameter<DoubleValue>("Quality", "The qualities of the solutions which should be analyzed."));
-      Parameters.Add(new ValueLookupParameter<ResultCollection>("Results", "The result collection where the population diversity analysis results should be stored."));
-      Parameters.Add(new ValueParameter<BoolValue>("StoreHistory", "True if the history of the population diversity analysis should be stored.", new BoolValue(false)));
-      Parameters.Add(new ValueParameter<IntValue>("UpdateInterval", "The interval in which the population diversity analysis should be applied.", new IntValue(1)));
-      Parameters.Add(new LookupParameter<IntValue>("UpdateCounter", "The value which counts how many times the operator was called since the last update.", "PopulationDiversityAnalyzerUpdateCounter"));
-    }
-
-    public override IOperation Apply() {
-      int updateInterval = UpdateIntervalParameter.Value.Value;
-      IntValue updateCounter = UpdateCounterParameter.ActualValue;
-      // if counter does not yet exist then initialize it with update interval 
-      // to make sure the solutions are analyzed on the first application of this operator
-      if (updateCounter == null) {
-        updateCounter = new IntValue(updateInterval);
-        UpdateCounterParameter.ActualValue = updateCounter;
-      } else updateCounter.Value++;
-
-      //analyze solutions only every 'updateInterval' times
-      if (updateCounter.Value == updateInterval) {
-        updateCounter.Value = 0;
-
-        bool max = MaximizationParameter.ActualValue.Value;
-        ItemArray<T> solutions = SolutionParameter.ActualValue;
-        ItemArray<DoubleValue> qualities = QualityParameter.ActualValue;
-        bool storeHistory = StoreHistoryParameter.Value.Value;
-        int count = solutions.Length;
-
-        if (count > 1) {
-          // sort solutions by quality
-          T[] sortedSolutions = null;
-          if (max)
-            sortedSolutions = solutions
-              .Select((x, index) => new { Solution = x, Quality = qualities[index] })
-              .OrderByDescending(x => x.Quality)
-              .Select(x => x.Solution)
-              .ToArray();
-          else
-            sortedSolutions = solutions
-              .Select((x, index) => new { Solution = x, Quality = qualities[index] })
-              .OrderBy(x => x.Quality)
-              .Select(x => x.Solution)
-              .ToArray();
-
-          // calculate solution similarities
-          double[,] similarities = CalculateSimilarities(sortedSolutions);
-
-          // calculate minimum, average and maximum similarities
-          double similarity;
-          double[] minSimilarities = new double[count];
-          double[] avgSimilarities = new double[count];
-          double[] maxSimilarities = new double[count];
-          for (int i = 0; i < count; i++) {
-            minSimilarities[i] = 1;
-            avgSimilarities[i] = 0;
-            maxSimilarities[i] = 0;
-            for (int j = 0; j < count; j++) {
-              if (i != j) {
-                similarity = similarities[i, j];
-
-                if ((similarity < 0) || (similarity > 1))
-                  throw new InvalidOperationException("Solution similarities have to be in the interval [0;1].");
-
-                if (minSimilarities[i] > similarity) minSimilarities[i] = similarity;
-                avgSimilarities[i] += similarity;
-                if (maxSimilarities[i] < similarity) maxSimilarities[i] = similarity;
-              }
-            }
-            avgSimilarities[i] = avgSimilarities[i] / (count - 1);
-          }
-          double avgMinSimilarity = minSimilarities.Average();
-          double avgAvgSimilarity = avgSimilarities.Average();
-          double avgMaxSimilarity = maxSimilarities.Average();
-
-          // fetch results collection
-          ResultCollection results;
-          if (!ResultsParameter.ActualValue.ContainsKey("Population Diversity Analysis Results")) {
-            results = new ResultCollection();
-            ResultsParameter.ActualValue.Add(new Result("Population Diversity Analysis Results", results));
-          } else {
-            results = (ResultCollection)ResultsParameter.ActualValue["Population Diversity Analysis Results"].Value;
-          }
-
-          // store similarities
-          HeatMap similaritiesHeatMap = new HeatMap(similarities, "Solution Similarities", 0.0, 1.0);
-          if (!results.ContainsKey("Solution Similarities"))
-            results.Add(new Result("Solution Similarities", similaritiesHeatMap));
-          else
-            results["Solution Similarities"].Value = similaritiesHeatMap;
-
-          // store similarities history
-          if (storeHistory) {
-            if (!results.ContainsKey("Solution Similarities History")) {
-              HeatMapHistory history = new HeatMapHistory();
-              history.Add(similaritiesHeatMap);
-              results.Add(new Result("Solution Similarities History", history));
-            } else {
-              ((HeatMapHistory)results["Solution Similarities History"].Value).Add(similaritiesHeatMap);
-            }
-          }
-
-          // store average minimum, average and maximum similarity
-          if (!results.ContainsKey("Average Minimum Solution Similarity"))
-            results.Add(new Result("Average Minimum Solution Similarity", new DoubleValue(avgMinSimilarity)));
-          else
-            ((DoubleValue)results["Average Minimum Solution Similarity"].Value).Value = avgMinSimilarity;
-
-          if (!results.ContainsKey("Average Average Solution Similarity"))
-            results.Add(new Result("Average Average Solution Similarity", new DoubleValue(avgAvgSimilarity)));
-          else
-            ((DoubleValue)results["Average Average Solution Similarity"].Value).Value = avgAvgSimilarity;
-
-          if (!results.ContainsKey("Average Maximum Solution Similarity"))
-            results.Add(new Result("Average Maximum Solution Similarity", new DoubleValue(avgMaxSimilarity)));
-          else
-            ((DoubleValue)results["Average Maximum Solution Similarity"].Value).Value = avgMaxSimilarity;
-
-          // store average minimum, average and maximum solution similarity data table
-          DataTable minAvgMaxSimilarityDataTable;
-          if (!results.ContainsKey("Average Minimum/Average/Maximum Solution Similarity")) {
-            minAvgMaxSimilarityDataTable = new DataTable("Average Minimum/Average/Maximum Solution Similarity");
-            minAvgMaxSimilarityDataTable.VisualProperties.XAxisTitle = "Iteration";
-            minAvgMaxSimilarityDataTable.VisualProperties.YAxisTitle = "Solution Similarity";
-            minAvgMaxSimilarityDataTable.Rows.Add(new DataRow("Average Minimum Solution Similarity", null));
-            minAvgMaxSimilarityDataTable.Rows["Average Minimum Solution Similarity"].VisualProperties.StartIndexZero = true;
-            minAvgMaxSimilarityDataTable.Rows.Add(new DataRow("Average Average Solution Similarity", null));
-            minAvgMaxSimilarityDataTable.Rows["Average Average Solution Similarity"].VisualProperties.StartIndexZero = true;
-            minAvgMaxSimilarityDataTable.Rows.Add(new DataRow("Average Maximum Solution Similarity", null));
-            minAvgMaxSimilarityDataTable.Rows["Average Maximum Solution Similarity"].VisualProperties.StartIndexZero = true;
-            results.Add(new Result("Average Minimum/Average/Maximum Solution Similarity", minAvgMaxSimilarityDataTable));
-          } else {
-            minAvgMaxSimilarityDataTable = (DataTable)results["Average Minimum/Average/Maximum Solution Similarity"].Value;
-          }
-          minAvgMaxSimilarityDataTable.Rows["Average Minimum Solution Similarity"].Values.Add(avgMinSimilarity);
-          minAvgMaxSimilarityDataTable.Rows["Average Average Solution Similarity"].Values.Add(avgAvgSimilarity);
-          minAvgMaxSimilarityDataTable.Rows["Average Maximum Solution Similarity"].Values.Add(avgMaxSimilarity);
-
-          // store minimum, average, maximum similarities data table
-          DataTable minAvgMaxSimilaritiesDataTable = new DataTable("Minimum/Average/Maximum Solution Similarities");
-          minAvgMaxSimilaritiesDataTable.VisualProperties.XAxisTitle = "Solution Index";
-          minAvgMaxSimilaritiesDataTable.VisualProperties.YAxisTitle = "Solution Similarity";
-          minAvgMaxSimilaritiesDataTable.Rows.Add(new DataRow("Minimum Solution Similarity", null, minSimilarities));
-          minAvgMaxSimilaritiesDataTable.Rows["Minimum Solution Similarity"].VisualProperties.ChartType = DataRowVisualProperties.DataRowChartType.Points;
-          minAvgMaxSimilaritiesDataTable.Rows.Add(new DataRow("Average Solution Similarity", null, avgSimilarities));
-          minAvgMaxSimilaritiesDataTable.Rows["Average Solution Similarity"].VisualProperties.ChartType = DataRowVisualProperties.DataRowChartType.Points;
-          minAvgMaxSimilaritiesDataTable.Rows.Add(new DataRow("Maximum Solution Similarity", null, maxSimilarities));
-          minAvgMaxSimilaritiesDataTable.Rows["Maximum Solution Similarity"].VisualProperties.ChartType = DataRowVisualProperties.DataRowChartType.Points;
-          if (!results.ContainsKey("Minimum/Average/Maximum Solution Similarities")) {
-            results.Add(new Result("Minimum/Average/Maximum Solution Similarities", minAvgMaxSimilaritiesDataTable));
-          } else {
-            results["Minimum/Average/Maximum Solution Similarities"].Value = minAvgMaxSimilaritiesDataTable;
-          }
-
-          // store minimum, average, maximum similarities history
-          if (storeHistory) {
-            if (!results.ContainsKey("Minimum/Average/Maximum Solution Similarities History")) {
-              DataTableHistory history = new DataTableHistory();
-              history.Add(minAvgMaxSimilaritiesDataTable);
-              results.Add(new Result("Minimum/Average/Maximum Solution Similarities History", history));
-            } else {
-              ((DataTableHistory)results["Minimum/Average/Maximum Solution Similarities History"].Value).Add(minAvgMaxSimilaritiesDataTable);
-            }
-          }
-        }
-      }
-      return base.Apply();
-    }
-
-    protected abstract double[,] CalculateSimilarities(T[] solutions);
-  }
-}
Index: trunk/sources/HeuristicLab.Analysis/3.3/QualityAnalysis/BestAverageWorstQualityAnalyzer.cs
===================================================================
--- trunk/sources/HeuristicLab.Analysis/3.3/QualityAnalysis/BestAverageWorstQualityAnalyzer.cs	(revision 4887)
+++ trunk/sources/HeuristicLab.Analysis/3.3/QualityAnalysis/BestAverageWorstQualityAnalyzer.cs	(revision 4887)
@@ -0,0 +1,179 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2010 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Operators;
+using HeuristicLab.Optimization;
+using HeuristicLab.Optimization.Operators;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Analysis {
+  /// <summary>
+  /// An operator which analyzes the best, average and worst quality of solutions in the scope tree.
+  /// </summary>
+  [Item("BestAverageWorstQualityAnalyzer", "An operator which analyzes the best, average and worst quality of solutions in the scope tree.")]
+  [StorableClass]
+  public sealed class BestAverageWorstQualityAnalyzer : AlgorithmOperator, IAnalyzer {
+    #region Parameter properties
+    public ValueLookupParameter<BoolValue> MaximizationParameter {
+      get { return (ValueLookupParameter<BoolValue>)Parameters["Maximization"]; }
+    }
+    public ScopeTreeLookupParameter<DoubleValue> QualityParameter {
+      get { return (ScopeTreeLookupParameter<DoubleValue>)Parameters["Quality"]; }
+    }
+    public ValueLookupParameter<DoubleValue> BestKnownQualityParameter {
+      get { return (ValueLookupParameter<DoubleValue>)Parameters["BestKnownQuality"]; }
+    }
+    public ValueLookupParameter<DoubleValue> BestQualityParameter {
+      get { return (ValueLookupParameter<DoubleValue>)Parameters["BestQuality"]; }
+    }
+    public ValueLookupParameter<DoubleValue> CurrentBestQualityParameter {
+      get { return (ValueLookupParameter<DoubleValue>)Parameters["CurrentBestQuality"]; }
+    }
+    public ValueLookupParameter<DoubleValue> CurrentAverageQualityParameter {
+      get { return (ValueLookupParameter<DoubleValue>)Parameters["CurrentAverageQuality"]; }
+    }
+    public ValueLookupParameter<DoubleValue> CurrentWorstQualityParameter {
+      get { return (ValueLookupParameter<DoubleValue>)Parameters["CurrentWorstQuality"]; }
+    }
+    public ValueLookupParameter<DataTable> QualitiesParameter {
+      get { return (ValueLookupParameter<DataTable>)Parameters["Qualities"]; }
+    }
+    public ValueLookupParameter<DoubleValue> AbsoluteDifferenceBestKnownToBestParameter {
+      get { return (ValueLookupParameter<DoubleValue>)Parameters["AbsoluteDifferenceBestKnownToBest"]; }
+    }
+    public ValueLookupParameter<PercentValue> RelativeDifferenceBestKnownToBestParameter {
+      get { return (ValueLookupParameter<PercentValue>)Parameters["RelativeDifferenceBestKnownToBest"]; }
+    }
+    public ValueLookupParameter<VariableCollection> ResultsParameter {
+      get { return (ValueLookupParameter<VariableCollection>)Parameters["Results"]; }
+    }
+    #endregion
+
+    #region Properties
+    private BestQualityMemorizer BestQualityMemorizer {
+      get { return (BestQualityMemorizer)OperatorGraph.InitialOperator; }
+    }
+    private BestAverageWorstQualityCalculator BestAverageWorstQualityCalculator {
+      get { return (BestAverageWorstQualityCalculator)BestQualityMemorizer.Successor; }
+    }
+    #endregion
+
+    #region Storing & Cloning
+    [StorableConstructor]
+    private BestAverageWorstQualityAnalyzer(bool deserializing) : base(deserializing) { }
+    private BestAverageWorstQualityAnalyzer(BestAverageWorstQualityAnalyzer original, Cloner cloner)
+      : base(original, cloner) {
+      Initialize();
+    }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new BestAverageWorstQualityAnalyzer(this, cloner);
+    }
+    #endregion
+    public BestAverageWorstQualityAnalyzer()
+      : base() {
+      #region Create parameters
+      Parameters.Add(new ValueLookupParameter<BoolValue>("Maximization", "True if the problem is a maximization problem, otherwise false."));
+      Parameters.Add(new ScopeTreeLookupParameter<DoubleValue>("Quality", "The value which represents the quality of a solution."));
+      Parameters.Add(new ValueLookupParameter<DoubleValue>("BestKnownQuality", "The best known quality value found so far."));
+      Parameters.Add(new ValueLookupParameter<DoubleValue>("BestQuality", "The best quality value found in the current run."));
+      Parameters.Add(new ValueLookupParameter<DoubleValue>("CurrentBestQuality", "The best quality value found in the current population."));
+      Parameters.Add(new ValueLookupParameter<DoubleValue>("CurrentAverageQuality", "The average quality value of all solutions in the current population."));
+      Parameters.Add(new ValueLookupParameter<DoubleValue>("CurrentWorstQuality", "The worst quality value found in the current population."));
+      Parameters.Add(new ValueLookupParameter<DataTable>("Qualities", "The data table to store the current best, current average, current worst, best and best known quality value."));
+      Parameters.Add(new ValueLookupParameter<DoubleValue>("AbsoluteDifferenceBestKnownToBest", "The absolute difference of the best known quality value to the best quality value."));
+      Parameters.Add(new ValueLookupParameter<PercentValue>("RelativeDifferenceBestKnownToBest", "The relative difference of the best known quality value to the best quality value."));
+      Parameters.Add(new ValueLookupParameter<VariableCollection>("Results", "The results collection where the analysis values should be stored."));
+      #endregion
+
+      #region Create operators
+      BestQualityMemorizer bestQualityMemorizer = new BestQualityMemorizer();
+      BestAverageWorstQualityCalculator bestAverageWorstQualityCalculator = new BestAverageWorstQualityCalculator();
+      DataTableValuesCollector dataTableValuesCollector = new DataTableValuesCollector();
+      QualityDifferenceCalculator qualityDifferenceCalculator = new QualityDifferenceCalculator();
+      ResultsCollector resultsCollector = new ResultsCollector();
+
+      bestQualityMemorizer.BestQualityParameter.ActualName = BestQualityParameter.Name;
+      bestQualityMemorizer.MaximizationParameter.ActualName = MaximizationParameter.Name;
+      bestQualityMemorizer.QualityParameter.ActualName = QualityParameter.Name;
+      bestQualityMemorizer.QualityParameter.Depth = QualityParameter.Depth;
+
+      bestAverageWorstQualityCalculator.AverageQualityParameter.ActualName = CurrentAverageQualityParameter.Name;
+      bestAverageWorstQualityCalculator.BestQualityParameter.ActualName = CurrentBestQualityParameter.Name;
+      bestAverageWorstQualityCalculator.MaximizationParameter.ActualName = MaximizationParameter.Name;
+      bestAverageWorstQualityCalculator.QualityParameter.ActualName = QualityParameter.Name;
+      bestAverageWorstQualityCalculator.QualityParameter.Depth = QualityParameter.Depth;
+      bestAverageWorstQualityCalculator.WorstQualityParameter.ActualName = CurrentWorstQualityParameter.Name;
+
+      dataTableValuesCollector.CollectedValues.Add(new LookupParameter<DoubleValue>("CurrentBestQuality", null, CurrentBestQualityParameter.Name));
+      dataTableValuesCollector.CollectedValues.Add(new LookupParameter<DoubleValue>("CurrentAverageQuality", null, CurrentAverageQualityParameter.Name));
+      dataTableValuesCollector.CollectedValues.Add(new LookupParameter<DoubleValue>("CurrentWorstQuality", null, CurrentWorstQualityParameter.Name));
+      dataTableValuesCollector.CollectedValues.Add(new LookupParameter<DoubleValue>("BestQuality", null, BestQualityParameter.Name));
+      dataTableValuesCollector.CollectedValues.Add(new LookupParameter<DoubleValue>("BestKnownQuality", null, BestKnownQualityParameter.Name));
+      dataTableValuesCollector.DataTableParameter.ActualName = QualitiesParameter.Name;
+
+      qualityDifferenceCalculator.AbsoluteDifferenceParameter.ActualName = AbsoluteDifferenceBestKnownToBestParameter.Name;
+      qualityDifferenceCalculator.FirstQualityParameter.ActualName = BestKnownQualityParameter.Name;
+      qualityDifferenceCalculator.RelativeDifferenceParameter.ActualName = RelativeDifferenceBestKnownToBestParameter.Name;
+      qualityDifferenceCalculator.SecondQualityParameter.ActualName = BestQualityParameter.Name;
+
+      resultsCollector.CollectedValues.Add(new LookupParameter<DoubleValue>("CurrentBestQuality", null, CurrentBestQualityParameter.Name));
+      resultsCollector.CollectedValues.Add(new LookupParameter<DoubleValue>("CurrentAverageQuality", null, CurrentAverageQualityParameter.Name));
+      resultsCollector.CollectedValues.Add(new LookupParameter<DoubleValue>("CurrentWorstQuality", null, CurrentWorstQualityParameter.Name));
+      resultsCollector.CollectedValues.Add(new LookupParameter<DoubleValue>("BestQuality", null, BestQualityParameter.Name));
+      resultsCollector.CollectedValues.Add(new LookupParameter<DoubleValue>("BestKnownQuality", null, BestKnownQualityParameter.Name));
+      resultsCollector.CollectedValues.Add(new LookupParameter<DoubleValue>("AbsoluteDifferenceBestKnownToBest", null, AbsoluteDifferenceBestKnownToBestParameter.Name));
+      resultsCollector.CollectedValues.Add(new LookupParameter<PercentValue>("RelativeDifferenceBestKnownToBest", null, RelativeDifferenceBestKnownToBestParameter.Name));
+      resultsCollector.CollectedValues.Add(new LookupParameter<DataTable>(QualitiesParameter.Name));
+      resultsCollector.ResultsParameter.ActualName = ResultsParameter.Name;
+      #endregion
+
+      #region Create operator graph
+      OperatorGraph.InitialOperator = bestQualityMemorizer;
+      bestQualityMemorizer.Successor = bestAverageWorstQualityCalculator;
+      bestAverageWorstQualityCalculator.Successor = dataTableValuesCollector;
+      dataTableValuesCollector.Successor = qualityDifferenceCalculator;
+      qualityDifferenceCalculator.Successor = resultsCollector;
+      resultsCollector.Successor = null;
+      #endregion
+
+      Initialize();
+    }
+
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() {
+      Initialize();
+    }
+    
+    private void Initialize() {
+      QualityParameter.DepthChanged += new EventHandler(QualityParameter_DepthChanged);
+    }
+
+    private void QualityParameter_DepthChanged(object sender, System.EventArgs e) {
+      BestQualityMemorizer.QualityParameter.Depth = QualityParameter.Depth;
+      BestAverageWorstQualityCalculator.QualityParameter.Depth = QualityParameter.Depth;
+    }
+  }
+}
Index: trunk/sources/HeuristicLab.Analysis/3.3/QualityAnalysis/BestAverageWorstQualityCalculator.cs
===================================================================
--- trunk/sources/HeuristicLab.Analysis/3.3/QualityAnalysis/BestAverageWorstQualityCalculator.cs	(revision 4887)
+++ trunk/sources/HeuristicLab.Analysis/3.3/QualityAnalysis/BestAverageWorstQualityCalculator.cs	(revision 4887)
@@ -0,0 +1,100 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2010 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Operators;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Analysis {
+  /// <summary>
+  /// An operator which calculates the best, average and worst quality of solutions in the scope tree.
+  /// </summary>
+  [Item("BestAverageWorstQualityCalculator", "An operator which calculates the best, average and worst quality of solutions in the scope tree.")]
+  [StorableClass]
+  public sealed class BestAverageWorstQualityCalculator : SingleSuccessorOperator {
+    public ValueLookupParameter<BoolValue> MaximizationParameter {
+      get { return (ValueLookupParameter<BoolValue>)Parameters["Maximization"]; }
+    }
+    public ScopeTreeLookupParameter<DoubleValue> QualityParameter {
+      get { return (ScopeTreeLookupParameter<DoubleValue>)Parameters["Quality"]; }
+    }
+    public ValueLookupParameter<DoubleValue> BestQualityParameter {
+      get { return (ValueLookupParameter<DoubleValue>)Parameters["BestQuality"]; }
+    }
+    public ValueLookupParameter<DoubleValue> AverageQualityParameter {
+      get { return (ValueLookupParameter<DoubleValue>)Parameters["AverageQuality"]; }
+    }
+    public ValueLookupParameter<DoubleValue> WorstQualityParameter {
+      get { return (ValueLookupParameter<DoubleValue>)Parameters["WorstQuality"]; }
+    }
+
+    #region Storing & Cloning
+    [StorableConstructor]
+    private BestAverageWorstQualityCalculator(bool deserializing) : base(deserializing) { }
+    private BestAverageWorstQualityCalculator(BestAverageWorstQualityCalculator original, Cloner cloner) : base(original, cloner) { }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new BestAverageWorstQualityCalculator(this, cloner);
+    }
+    #endregion
+    public BestAverageWorstQualityCalculator()
+      : base() {
+      Parameters.Add(new ValueLookupParameter<BoolValue>("Maximization", "True if the current problem is a maximization problem, otherwise false."));
+      Parameters.Add(new ScopeTreeLookupParameter<DoubleValue>("Quality", "The value contained in the scope tree which represents the solution quality."));
+      Parameters.Add(new ValueLookupParameter<DoubleValue>("BestQuality", "The quality value of the best solution."));
+      Parameters.Add(new ValueLookupParameter<DoubleValue>("AverageQuality", "The average quality of all solutions."));
+      Parameters.Add(new ValueLookupParameter<DoubleValue>("WorstQuality", "The quality value of the worst solution."));
+    }
+
+
+    public override IOperation Apply() {
+      ItemArray<DoubleValue> qualities = QualityParameter.ActualValue;
+      bool maximization = MaximizationParameter.ActualValue.Value;
+
+      if (qualities.Length > 0) {
+        double min = double.MaxValue, max = double.MinValue, sum = 0.0;
+        for (int i = 0; i < qualities.Length; i++) {
+          if (qualities[i].Value < min) min = qualities[i].Value;
+          if (qualities[i].Value > max) max = qualities[i].Value;
+          sum += qualities[i].Value;
+        }
+        if (!maximization) {
+          double temp = min;
+          min = max;
+          max = temp;
+        }
+
+        DoubleValue best = BestQualityParameter.ActualValue;
+        if (best == null) BestQualityParameter.ActualValue = new DoubleValue(max);
+        else best.Value = max;
+        DoubleValue average = AverageQualityParameter.ActualValue;
+        if (average == null) AverageQualityParameter.ActualValue = new DoubleValue(sum / qualities.Length);
+        else average.Value = sum / qualities.Length;
+        DoubleValue worst = WorstQualityParameter.ActualValue;
+        if (worst == null) WorstQualityParameter.ActualValue = new DoubleValue(min);
+        else worst.Value = min;
+      }
+      return base.Apply();
+    }
+  }
+}
Index: trunk/sources/HeuristicLab.Analysis/3.3/QualityAnalysis/BestQualityMemorizer.cs
===================================================================
--- trunk/sources/HeuristicLab.Analysis/3.3/QualityAnalysis/BestQualityMemorizer.cs	(revision 4887)
+++ trunk/sources/HeuristicLab.Analysis/3.3/QualityAnalysis/BestQualityMemorizer.cs	(revision 4887)
@@ -0,0 +1,79 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2010 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Operators;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Analysis {
+  /// <summary>
+  /// An operator that updates the best quality found so far with those qualities contained in the scope tree.
+  /// </summary>
+  [Item("BestQualityMemorizer", "An operator that updates the best quality found so far with those qualities contained in the scope tree.")]
+  [StorableClass]
+  public class BestQualityMemorizer : SingleSuccessorOperator {
+    public ValueLookupParameter<BoolValue> MaximizationParameter {
+      get { return (ValueLookupParameter<BoolValue>)Parameters["Maximization"]; }
+    }
+    public ScopeTreeLookupParameter<DoubleValue> QualityParameter {
+      get { return (ScopeTreeLookupParameter<DoubleValue>)Parameters["Quality"]; }
+    }
+    public ValueLookupParameter<DoubleValue> BestQualityParameter {
+      get { return (ValueLookupParameter<DoubleValue>)Parameters["BestQuality"]; }
+    }
+
+    #region Storing & Cloning
+    [StorableConstructor]
+    protected BestQualityMemorizer(bool deserializing) : base(deserializing) { }
+    protected BestQualityMemorizer(BestQualityMemorizer original, Cloner cloner) : base(original, cloner) { }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new BestQualityMemorizer(this, cloner);
+    }
+    #endregion
+    public BestQualityMemorizer()
+      : base() {
+      Parameters.Add(new ValueLookupParameter<BoolValue>("Maximization", "True if the current problem is a maximization problem, otherwise false."));
+      Parameters.Add(new ScopeTreeLookupParameter<DoubleValue>("Quality", "The value contained in the scope tree which represents the solution quality."));
+      Parameters.Add(new ValueLookupParameter<DoubleValue>("BestQuality", "The quality value of the best solution."));
+    }
+
+    public override IOperation Apply() {
+      ItemArray<DoubleValue> qualities = QualityParameter.ActualValue;
+      bool maximization = MaximizationParameter.ActualValue.Value;
+      DoubleValue best = BestQualityParameter.ActualValue;
+      double max = (best != null) ? (best.Value) : ((maximization) ? (double.MinValue) : (double.MaxValue));
+
+      foreach (DoubleValue quality in qualities)
+        if (IsBetter(maximization, quality.Value, max)) max = quality.Value;
+
+      if (best == null) BestQualityParameter.ActualValue = new DoubleValue(max);
+      else best.Value = max;
+      return base.Apply();
+    }
+
+    private bool IsBetter(bool maximization, double quality, double max) {
+      return (maximization && quality > max || !maximization && quality < max);
+    }
+  }
+}
Index: trunk/sources/HeuristicLab.Analysis/3.3/QualityAnalysis/QualityAnalyzer.cs
===================================================================
--- trunk/sources/HeuristicLab.Analysis/3.3/QualityAnalysis/QualityAnalyzer.cs	(revision 4887)
+++ trunk/sources/HeuristicLab.Analysis/3.3/QualityAnalysis/QualityAnalyzer.cs	(revision 4887)
@@ -0,0 +1,171 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2010 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Operators;
+using HeuristicLab.Optimization;
+using HeuristicLab.Optimization.Operators;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Analysis {
+  /// <summary>
+  /// An operator which analyzes the quality of solutions in the scope tree.
+  /// </summary>
+  [Item("QualityAnalyzer", "An operator which analyzes the quality of solutions in the scope tree.")]
+  [StorableClass]
+  public sealed class QualityAnalyzer : AlgorithmOperator, IAnalyzer {
+    #region Parameter properties
+    public ValueLookupParameter<BoolValue> MaximizationParameter {
+      get { return (ValueLookupParameter<BoolValue>)Parameters["Maximization"]; }
+    }
+    public ScopeTreeLookupParameter<DoubleValue> QualityParameter {
+      get { return (ScopeTreeLookupParameter<DoubleValue>)Parameters["Quality"]; }
+    }
+    public ValueLookupParameter<DoubleValue> BestKnownQualityParameter {
+      get { return (ValueLookupParameter<DoubleValue>)Parameters["BestKnownQuality"]; }
+    }
+    public ValueLookupParameter<DoubleValue> BestQualityParameter {
+      get { return (ValueLookupParameter<DoubleValue>)Parameters["BestQuality"]; }
+    }
+    public ValueLookupParameter<DataTable> QualitiesParameter {
+      get { return (ValueLookupParameter<DataTable>)Parameters["Qualities"]; }
+    }
+    public ValueLookupParameter<DoubleValue> AbsoluteDifferenceBestKnownToBestParameter {
+      get { return (ValueLookupParameter<DoubleValue>)Parameters["AbsoluteDifferenceBestKnownToBest"]; }
+    }
+    public ValueLookupParameter<PercentValue> RelativeDifferenceBestKnownToBestParameter {
+      get { return (ValueLookupParameter<PercentValue>)Parameters["RelativeDifferenceBestKnownToBest"]; }
+    }
+    public ValueLookupParameter<VariableCollection> ResultsParameter {
+      get { return (ValueLookupParameter<VariableCollection>)Parameters["Results"]; }
+    }
+    #endregion
+
+    #region Properties
+    private BestQualityMemorizer BestQualityMemorizer {
+      get { return (BestQualityMemorizer)OperatorGraph.InitialOperator; }
+    }
+    private BestQualityMemorizer BestKnownQualityMemorizer {
+      get { return (BestQualityMemorizer)BestQualityMemorizer.Successor; }
+    }
+    private DataTableValuesCollector DataTableValuesCollector {
+      get { return (DataTableValuesCollector)BestKnownQualityMemorizer.Successor; }
+    }
+    private ResultsCollector ResultsCollector {
+      get { return (ResultsCollector)((QualityDifferenceCalculator)DataTableValuesCollector.Successor).Successor; }
+    }
+    #endregion
+
+    #region Storing & Cloning
+    [StorableConstructor]
+    private QualityAnalyzer(bool deserializing) : base(deserializing) { }
+    private QualityAnalyzer(QualityAnalyzer original, Cloner cloner)
+      : base(original, cloner) {
+      Initialize();
+    }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new QualityAnalyzer(this, cloner);
+    }
+    #endregion
+    public QualityAnalyzer()
+      : base() {
+      #region Create parameters
+      Parameters.Add(new ValueLookupParameter<BoolValue>("Maximization", "True if the problem is a maximization problem, otherwise false."));
+      Parameters.Add(new ScopeTreeLookupParameter<DoubleValue>("Quality", "The value which represents the quality of a solution."));
+      Parameters.Add(new ValueLookupParameter<DoubleValue>("BestKnownQuality", "The best known quality value found so far."));
+      Parameters.Add(new ValueLookupParameter<DoubleValue>("BestQuality", "The best quality value found in the current run."));
+      Parameters.Add(new ValueLookupParameter<DataTable>("Qualities", "The data table to store the current best, current average, current worst, best and best known quality value."));
+      Parameters.Add(new ValueLookupParameter<DoubleValue>("AbsoluteDifferenceBestKnownToBest", "The absolute difference of the best known quality value to the best quality value."));
+      Parameters.Add(new ValueLookupParameter<PercentValue>("RelativeDifferenceBestKnownToBest", "The relative difference of the best known quality value to the best quality value."));
+      Parameters.Add(new ValueLookupParameter<VariableCollection>("Results", "The results collection where the analysis values should be stored."));
+      #endregion
+
+      #region Create operators
+      BestQualityMemorizer bestQualityMemorizer = new BestQualityMemorizer();
+      BestQualityMemorizer bestKnownQualityMemorizer = new BestQualityMemorizer();
+      DataTableValuesCollector dataTableValuesCollector = new DataTableValuesCollector();
+      QualityDifferenceCalculator qualityDifferenceCalculator = new QualityDifferenceCalculator();
+      ResultsCollector resultsCollector = new ResultsCollector();
+
+      bestQualityMemorizer.BestQualityParameter.ActualName = BestQualityParameter.Name;
+      bestQualityMemorizer.MaximizationParameter.ActualName = MaximizationParameter.Name;
+      bestQualityMemorizer.QualityParameter.ActualName = QualityParameter.Name;
+      bestQualityMemorizer.QualityParameter.Depth = QualityParameter.Depth;
+
+      bestKnownQualityMemorizer.BestQualityParameter.ActualName = BestKnownQualityParameter.Name;
+      bestKnownQualityMemorizer.MaximizationParameter.ActualName = MaximizationParameter.Name;
+      bestKnownQualityMemorizer.QualityParameter.ActualName = QualityParameter.Name;
+      bestKnownQualityMemorizer.QualityParameter.Depth = QualityParameter.Depth;
+
+      dataTableValuesCollector.CollectedValues.Add(new LookupParameter<DoubleValue>("BestQuality", null, BestQualityParameter.Name));
+      dataTableValuesCollector.CollectedValues.Add(new LookupParameter<DoubleValue>("BestKnownQuality", null, BestKnownQualityParameter.Name));
+      dataTableValuesCollector.CollectedValues.Add(new ScopeTreeLookupParameter<DoubleValue>("Quality", null, QualityParameter.Name));
+      ((ScopeTreeLookupParameter<DoubleValue>)dataTableValuesCollector.CollectedValues["Quality"]).Depth = QualityParameter.Depth;
+      dataTableValuesCollector.DataTableParameter.ActualName = QualitiesParameter.Name;
+
+      qualityDifferenceCalculator.AbsoluteDifferenceParameter.ActualName = AbsoluteDifferenceBestKnownToBestParameter.Name;
+      qualityDifferenceCalculator.FirstQualityParameter.ActualName = BestKnownQualityParameter.Name;
+      qualityDifferenceCalculator.RelativeDifferenceParameter.ActualName = RelativeDifferenceBestKnownToBestParameter.Name;
+      qualityDifferenceCalculator.SecondQualityParameter.ActualName = BestQualityParameter.Name;
+
+      resultsCollector.CollectedValues.Add(new LookupParameter<DoubleValue>("BestQuality", null, BestQualityParameter.Name));
+      resultsCollector.CollectedValues.Add(new LookupParameter<DoubleValue>("BestKnownQuality", null, BestKnownQualityParameter.Name));
+      resultsCollector.CollectedValues.Add(new ScopeTreeLookupParameter<DoubleValue>("Quality", null, QualityParameter.Name));
+      ((ScopeTreeLookupParameter<DoubleValue>)resultsCollector.CollectedValues["Quality"]).Depth = QualityParameter.Depth;
+      resultsCollector.CollectedValues.Add(new LookupParameter<DoubleValue>("AbsoluteDifferenceBestKnownToBest", null, AbsoluteDifferenceBestKnownToBestParameter.Name));
+      resultsCollector.CollectedValues.Add(new LookupParameter<PercentValue>("RelativeDifferenceBestKnownToBest", null, RelativeDifferenceBestKnownToBestParameter.Name));
+      resultsCollector.CollectedValues.Add(new LookupParameter<DataTable>(QualitiesParameter.Name));
+      resultsCollector.ResultsParameter.ActualName = ResultsParameter.Name;
+      #endregion
+
+      #region Create operator graph
+      OperatorGraph.InitialOperator = bestQualityMemorizer;
+      bestQualityMemorizer.Successor = bestKnownQualityMemorizer;
+      bestKnownQualityMemorizer.Successor = dataTableValuesCollector;
+      dataTableValuesCollector.Successor = qualityDifferenceCalculator;
+      qualityDifferenceCalculator.Successor = resultsCollector;
+      resultsCollector.Successor = null;
+      #endregion
+
+      Initialize();
+    }
+
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() {
+      Initialize();
+    }
+
+    private void Initialize() {
+      QualityParameter.DepthChanged += new EventHandler(QualityParameter_DepthChanged);
+    }
+
+    private void QualityParameter_DepthChanged(object sender, System.EventArgs e) {
+      BestQualityMemorizer.QualityParameter.Depth = QualityParameter.Depth;
+      BestKnownQualityMemorizer.QualityParameter.Depth = QualityParameter.Depth;
+      ((ScopeTreeLookupParameter<DoubleValue>)DataTableValuesCollector.CollectedValues["Quality"]).Depth = QualityParameter.Depth;
+      ((ScopeTreeLookupParameter<DoubleValue>)ResultsCollector.CollectedValues["Quality"]).Depth = QualityParameter.Depth;
+    }
+  }
+}
Index: trunk/sources/HeuristicLab.Analysis/3.3/QualityAnalysis/QualityDifferenceCalculator.cs
===================================================================
--- trunk/sources/HeuristicLab.Analysis/3.3/QualityAnalysis/QualityDifferenceCalculator.cs	(revision 4887)
+++ trunk/sources/HeuristicLab.Analysis/3.3/QualityAnalysis/QualityDifferenceCalculator.cs	(revision 4887)
@@ -0,0 +1,81 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2010 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Operators;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Analysis {
+  /// <summary>
+  /// An operator which calculates the absolute and relative difference of two quality values.
+  /// </summary>
+  [Item("QualityDifferenceCalculator", "An operator which calculates the absolute and relative difference of two quality values.")]
+  [StorableClass]
+  public class QualityDifferenceCalculator : SingleSuccessorOperator {
+    public IValueLookupParameter<DoubleValue> FirstQualityParameter {
+      get { return (IValueLookupParameter<DoubleValue>)Parameters["FirstQuality"]; }
+    }
+    public IValueLookupParameter<DoubleValue> SecondQualityParameter {
+      get { return (IValueLookupParameter<DoubleValue>)Parameters["SecondQuality"]; }
+    }
+    public IValueLookupParameter<DoubleValue> AbsoluteDifferenceParameter {
+      get { return (IValueLookupParameter<DoubleValue>)Parameters["AbsoluteDifference"]; }
+    }
+    public IValueLookupParameter<PercentValue> RelativeDifferenceParameter {
+      get { return (IValueLookupParameter<PercentValue>)Parameters["RelativeDifference"]; }
+    }
+
+    #region Storing & Cloning
+    [StorableConstructor]
+    protected QualityDifferenceCalculator(bool deserializing) : base(deserializing) { }
+    protected QualityDifferenceCalculator(QualityDifferenceCalculator original, Cloner cloner) : base(original, cloner) { }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new QualityDifferenceCalculator(this, cloner);
+    }
+    #endregion
+    public QualityDifferenceCalculator()
+      : base() {
+      Parameters.Add(new ValueLookupParameter<DoubleValue>("FirstQuality", "The first quality value from which the difference to the second quality value is calculated."));
+      Parameters.Add(new ValueLookupParameter<DoubleValue>("SecondQuality", "The second quality value from which the difference from the first quality value is calculated."));
+      Parameters.Add(new ValueLookupParameter<DoubleValue>("AbsoluteDifference", "The absolute difference of the first and second quality value."));
+      Parameters.Add(new ValueLookupParameter<PercentValue>("RelativeDifference", "The relative difference of the first and second quality value."));
+    }
+
+    public override IOperation Apply() {
+      DoubleValue first = FirstQualityParameter.ActualValue;
+      DoubleValue second = SecondQualityParameter.ActualValue;
+
+      if ((first != null) && (second != null)) {
+        double absolute = second.Value - first.Value;
+        double relative = first.Value == 0 ? double.NaN : absolute / first.Value;
+
+        if (AbsoluteDifferenceParameter.ActualValue == null) AbsoluteDifferenceParameter.ActualValue = new DoubleValue(absolute);
+        else AbsoluteDifferenceParameter.ActualValue.Value = absolute;
+        if (RelativeDifferenceParameter.ActualValue == null) RelativeDifferenceParameter.ActualValue = new PercentValue(relative);
+        else RelativeDifferenceParameter.ActualValue.Value = relative;
+      }
+      return base.Apply();
+    }
+  }
+}
Index: trunk/sources/HeuristicLab.Analysis/3.3/QualityAnalyzer.cs
===================================================================
--- trunk/sources/HeuristicLab.Analysis/3.3/QualityAnalyzer.cs	(revision 4870)
+++ 	(revision )
@@ -1,171 +1,0 @@
-#region License Information
-/* HeuristicLab
- * Copyright (C) 2002-2010 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
- *
- * This file is part of HeuristicLab.
- *
- * HeuristicLab is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * HeuristicLab is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
- */
-#endregion
-
-using System;
-using HeuristicLab.Common;
-using HeuristicLab.Core;
-using HeuristicLab.Data;
-using HeuristicLab.Operators;
-using HeuristicLab.Optimization;
-using HeuristicLab.Optimization.Operators;
-using HeuristicLab.Parameters;
-using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
-
-namespace HeuristicLab.Analysis {
-  /// <summary>
-  /// An operator which analyzes the quality of solutions in the scope tree.
-  /// </summary>
-  [Item("QualityAnalyzer", "An operator which analyzes the quality of solutions in the scope tree.")]
-  [StorableClass]
-  public sealed class QualityAnalyzer : AlgorithmOperator, IAnalyzer {
-    #region Parameter properties
-    public ValueLookupParameter<BoolValue> MaximizationParameter {
-      get { return (ValueLookupParameter<BoolValue>)Parameters["Maximization"]; }
-    }
-    public ScopeTreeLookupParameter<DoubleValue> QualityParameter {
-      get { return (ScopeTreeLookupParameter<DoubleValue>)Parameters["Quality"]; }
-    }
-    public ValueLookupParameter<DoubleValue> BestKnownQualityParameter {
-      get { return (ValueLookupParameter<DoubleValue>)Parameters["BestKnownQuality"]; }
-    }
-    public ValueLookupParameter<DoubleValue> BestQualityParameter {
-      get { return (ValueLookupParameter<DoubleValue>)Parameters["BestQuality"]; }
-    }
-    public ValueLookupParameter<DataTable> QualitiesParameter {
-      get { return (ValueLookupParameter<DataTable>)Parameters["Qualities"]; }
-    }
-    public ValueLookupParameter<DoubleValue> AbsoluteDifferenceBestKnownToBestParameter {
-      get { return (ValueLookupParameter<DoubleValue>)Parameters["AbsoluteDifferenceBestKnownToBest"]; }
-    }
-    public ValueLookupParameter<PercentValue> RelativeDifferenceBestKnownToBestParameter {
-      get { return (ValueLookupParameter<PercentValue>)Parameters["RelativeDifferenceBestKnownToBest"]; }
-    }
-    public ValueLookupParameter<VariableCollection> ResultsParameter {
-      get { return (ValueLookupParameter<VariableCollection>)Parameters["Results"]; }
-    }
-    #endregion
-
-    #region Properties
-    private BestQualityMemorizer BestQualityMemorizer {
-      get { return (BestQualityMemorizer)OperatorGraph.InitialOperator; }
-    }
-    private BestQualityMemorizer BestKnownQualityMemorizer {
-      get { return (BestQualityMemorizer)BestQualityMemorizer.Successor; }
-    }
-    private DataTableValuesCollector DataTableValuesCollector {
-      get { return (DataTableValuesCollector)BestKnownQualityMemorizer.Successor; }
-    }
-    private ResultsCollector ResultsCollector {
-      get { return (ResultsCollector)((QualityDifferenceCalculator)DataTableValuesCollector.Successor).Successor; }
-    }
-    #endregion
-
-    #region Storing & Cloning
-    [StorableConstructor]
-    private QualityAnalyzer(bool deserializing) : base(deserializing) { }
-    private QualityAnalyzer(QualityAnalyzer original, Cloner cloner)
-      : base(original, cloner) {
-      Initialize();
-    }
-    public override IDeepCloneable Clone(Cloner cloner) {
-      return new QualityAnalyzer(this, cloner);
-    }
-    #endregion
-    public QualityAnalyzer()
-      : base() {
-      #region Create parameters
-      Parameters.Add(new ValueLookupParameter<BoolValue>("Maximization", "True if the problem is a maximization problem, otherwise false."));
-      Parameters.Add(new ScopeTreeLookupParameter<DoubleValue>("Quality", "The value which represents the quality of a solution."));
-      Parameters.Add(new ValueLookupParameter<DoubleValue>("BestKnownQuality", "The best known quality value found so far."));
-      Parameters.Add(new ValueLookupParameter<DoubleValue>("BestQuality", "The best quality value found in the current run."));
-      Parameters.Add(new ValueLookupParameter<DataTable>("Qualities", "The data table to store the current best, current average, current worst, best and best known quality value."));
-      Parameters.Add(new ValueLookupParameter<DoubleValue>("AbsoluteDifferenceBestKnownToBest", "The absolute difference of the best known quality value to the best quality value."));
-      Parameters.Add(new ValueLookupParameter<PercentValue>("RelativeDifferenceBestKnownToBest", "The relative difference of the best known quality value to the best quality value."));
-      Parameters.Add(new ValueLookupParameter<VariableCollection>("Results", "The results collection where the analysis values should be stored."));
-      #endregion
-
-      #region Create operators
-      BestQualityMemorizer bestQualityMemorizer = new BestQualityMemorizer();
-      BestQualityMemorizer bestKnownQualityMemorizer = new BestQualityMemorizer();
-      DataTableValuesCollector dataTableValuesCollector = new DataTableValuesCollector();
-      QualityDifferenceCalculator qualityDifferenceCalculator = new QualityDifferenceCalculator();
-      ResultsCollector resultsCollector = new ResultsCollector();
-
-      bestQualityMemorizer.BestQualityParameter.ActualName = BestQualityParameter.Name;
-      bestQualityMemorizer.MaximizationParameter.ActualName = MaximizationParameter.Name;
-      bestQualityMemorizer.QualityParameter.ActualName = QualityParameter.Name;
-      bestQualityMemorizer.QualityParameter.Depth = QualityParameter.Depth;
-
-      bestKnownQualityMemorizer.BestQualityParameter.ActualName = BestKnownQualityParameter.Name;
-      bestKnownQualityMemorizer.MaximizationParameter.ActualName = MaximizationParameter.Name;
-      bestKnownQualityMemorizer.QualityParameter.ActualName = QualityParameter.Name;
-      bestKnownQualityMemorizer.QualityParameter.Depth = QualityParameter.Depth;
-
-      dataTableValuesCollector.CollectedValues.Add(new LookupParameter<DoubleValue>("BestQuality", null, BestQualityParameter.Name));
-      dataTableValuesCollector.CollectedValues.Add(new LookupParameter<DoubleValue>("BestKnownQuality", null, BestKnownQualityParameter.Name));
-      dataTableValuesCollector.CollectedValues.Add(new ScopeTreeLookupParameter<DoubleValue>("Quality", null, QualityParameter.Name));
-      ((ScopeTreeLookupParameter<DoubleValue>)dataTableValuesCollector.CollectedValues["Quality"]).Depth = QualityParameter.Depth;
-      dataTableValuesCollector.DataTableParameter.ActualName = QualitiesParameter.Name;
-
-      qualityDifferenceCalculator.AbsoluteDifferenceParameter.ActualName = AbsoluteDifferenceBestKnownToBestParameter.Name;
-      qualityDifferenceCalculator.FirstQualityParameter.ActualName = BestKnownQualityParameter.Name;
-      qualityDifferenceCalculator.RelativeDifferenceParameter.ActualName = RelativeDifferenceBestKnownToBestParameter.Name;
-      qualityDifferenceCalculator.SecondQualityParameter.ActualName = BestQualityParameter.Name;
-
-      resultsCollector.CollectedValues.Add(new LookupParameter<DoubleValue>("BestQuality", null, BestQualityParameter.Name));
-      resultsCollector.CollectedValues.Add(new LookupParameter<DoubleValue>("BestKnownQuality", null, BestKnownQualityParameter.Name));
-      resultsCollector.CollectedValues.Add(new ScopeTreeLookupParameter<DoubleValue>("Quality", null, QualityParameter.Name));
-      ((ScopeTreeLookupParameter<DoubleValue>)resultsCollector.CollectedValues["Quality"]).Depth = QualityParameter.Depth;
-      resultsCollector.CollectedValues.Add(new LookupParameter<DoubleValue>("AbsoluteDifferenceBestKnownToBest", null, AbsoluteDifferenceBestKnownToBestParameter.Name));
-      resultsCollector.CollectedValues.Add(new LookupParameter<PercentValue>("RelativeDifferenceBestKnownToBest", null, RelativeDifferenceBestKnownToBestParameter.Name));
-      resultsCollector.CollectedValues.Add(new LookupParameter<DataTable>(QualitiesParameter.Name));
-      resultsCollector.ResultsParameter.ActualName = ResultsParameter.Name;
-      #endregion
-
-      #region Create operator graph
-      OperatorGraph.InitialOperator = bestQualityMemorizer;
-      bestQualityMemorizer.Successor = bestKnownQualityMemorizer;
-      bestKnownQualityMemorizer.Successor = dataTableValuesCollector;
-      dataTableValuesCollector.Successor = qualityDifferenceCalculator;
-      qualityDifferenceCalculator.Successor = resultsCollector;
-      resultsCollector.Successor = null;
-      #endregion
-
-      Initialize();
-    }
-
-    [StorableHook(HookType.AfterDeserialization)]
-    private void AfterDeserialization() {
-      Initialize();
-    }
-
-    private void Initialize() {
-      QualityParameter.DepthChanged += new EventHandler(QualityParameter_DepthChanged);
-    }
-
-    private void QualityParameter_DepthChanged(object sender, System.EventArgs e) {
-      BestQualityMemorizer.QualityParameter.Depth = QualityParameter.Depth;
-      BestKnownQualityMemorizer.QualityParameter.Depth = QualityParameter.Depth;
-      ((ScopeTreeLookupParameter<DoubleValue>)DataTableValuesCollector.CollectedValues["Quality"]).Depth = QualityParameter.Depth;
-      ((ScopeTreeLookupParameter<DoubleValue>)ResultsCollector.CollectedValues["Quality"]).Depth = QualityParameter.Depth;
-    }
-  }
-}
Index: trunk/sources/HeuristicLab.Analysis/3.3/QualityDifferenceCalculator.cs
===================================================================
--- trunk/sources/HeuristicLab.Analysis/3.3/QualityDifferenceCalculator.cs	(revision 4870)
+++ 	(revision )
@@ -1,81 +1,0 @@
-﻿#region License Information
-/* HeuristicLab
- * Copyright (C) 2002-2010 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
- *
- * This file is part of HeuristicLab.
- *
- * HeuristicLab is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * HeuristicLab is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
- */
-#endregion
-
-using HeuristicLab.Common;
-using HeuristicLab.Core;
-using HeuristicLab.Data;
-using HeuristicLab.Operators;
-using HeuristicLab.Parameters;
-using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
-
-namespace HeuristicLab.Analysis {
-  /// <summary>
-  /// An operator which calculates the absolute and relative difference of two quality values.
-  /// </summary>
-  [Item("QualityDifferenceCalculator", "An operator which calculates the absolute and relative difference of two quality values.")]
-  [StorableClass]
-  public class QualityDifferenceCalculator : SingleSuccessorOperator {
-    public IValueLookupParameter<DoubleValue> FirstQualityParameter {
-      get { return (IValueLookupParameter<DoubleValue>)Parameters["FirstQuality"]; }
-    }
-    public IValueLookupParameter<DoubleValue> SecondQualityParameter {
-      get { return (IValueLookupParameter<DoubleValue>)Parameters["SecondQuality"]; }
-    }
-    public IValueLookupParameter<DoubleValue> AbsoluteDifferenceParameter {
-      get { return (IValueLookupParameter<DoubleValue>)Parameters["AbsoluteDifference"]; }
-    }
-    public IValueLookupParameter<PercentValue> RelativeDifferenceParameter {
-      get { return (IValueLookupParameter<PercentValue>)Parameters["RelativeDifference"]; }
-    }
-
-    #region Storing & Cloning
-    [StorableConstructor]
-    protected QualityDifferenceCalculator(bool deserializing) : base(deserializing) { }
-    protected QualityDifferenceCalculator(QualityDifferenceCalculator original, Cloner cloner) : base(original, cloner) { }
-    public override IDeepCloneable Clone(Cloner cloner) {
-      return new QualityDifferenceCalculator(this, cloner);
-    }
-    #endregion
-    public QualityDifferenceCalculator()
-      : base() {
-      Parameters.Add(new ValueLookupParameter<DoubleValue>("FirstQuality", "The first quality value from which the difference to the second quality value is calculated."));
-      Parameters.Add(new ValueLookupParameter<DoubleValue>("SecondQuality", "The second quality value from which the difference from the first quality value is calculated."));
-      Parameters.Add(new ValueLookupParameter<DoubleValue>("AbsoluteDifference", "The absolute difference of the first and second quality value."));
-      Parameters.Add(new ValueLookupParameter<PercentValue>("RelativeDifference", "The relative difference of the first and second quality value."));
-    }
-
-    public override IOperation Apply() {
-      DoubleValue first = FirstQualityParameter.ActualValue;
-      DoubleValue second = SecondQualityParameter.ActualValue;
-
-      if ((first != null) && (second != null)) {
-        double absolute = second.Value - first.Value;
-        double relative = first.Value == 0 ? double.NaN : absolute / first.Value;
-
-        if (AbsoluteDifferenceParameter.ActualValue == null) AbsoluteDifferenceParameter.ActualValue = new DoubleValue(absolute);
-        else AbsoluteDifferenceParameter.ActualValue.Value = absolute;
-        if (RelativeDifferenceParameter.ActualValue == null) RelativeDifferenceParameter.ActualValue = new PercentValue(relative);
-        else RelativeDifferenceParameter.ActualValue.Value = relative;
-      }
-      return base.Apply();
-    }
-  }
-}
Index: trunk/sources/HeuristicLab.Analysis/3.3/ValueAnalysis/MinAverageMaxValueAnalyzer.cs
===================================================================
--- trunk/sources/HeuristicLab.Analysis/3.3/ValueAnalysis/MinAverageMaxValueAnalyzer.cs	(revision 4887)
+++ trunk/sources/HeuristicLab.Analysis/3.3/ValueAnalysis/MinAverageMaxValueAnalyzer.cs	(revision 4887)
@@ -0,0 +1,220 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2010 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Operators;
+using HeuristicLab.Optimization;
+using HeuristicLab.Optimization.Operators;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Analysis {
+  /// <summary>
+  /// An operator which analyzes the minimum, average and maximum of a value in the scope tree.
+  /// </summary>
+  [Item("MinAverageMaxValueAnalyzer", "An operator which analyzes the minimum, average and maximum of a value in the scope tree.")]
+  [StorableClass]
+  public sealed class MinAverageMaxValueAnalyzer : AlgorithmOperator, IAnalyzer {
+    #region Parameter properties
+    public ScopeTreeLookupParameter<DoubleValue> ValueParameter {
+      get { return (ScopeTreeLookupParameter<DoubleValue>)Parameters["Value"]; }
+    }
+    public ValueLookupParameter<DoubleValue> MinValueParameter {
+      get { return (ValueLookupParameter<DoubleValue>)Parameters["MinValue"]; }
+    }
+    public ValueLookupParameter<DoubleValue> AverageValueParameter {
+      get { return (ValueLookupParameter<DoubleValue>)Parameters["AverageValue"]; }
+    }
+    public ValueLookupParameter<DoubleValue> MaxValueParameter {
+      get { return (ValueLookupParameter<DoubleValue>)Parameters["MaxValue"]; }
+    }
+    public ValueLookupParameter<DataTable> ValuesParameter {
+      get { return (ValueLookupParameter<DataTable>)Parameters["Values"]; }
+    }
+    public ValueLookupParameter<VariableCollection> ResultsParameter {
+      get { return (ValueLookupParameter<VariableCollection>)Parameters["Results"]; }
+    }
+    public ValueParameter<BoolValue> CollectMinValueInResultsParameter {
+      get { return (ValueParameter<BoolValue>)Parameters["CollectMinValueInResults"]; }
+    }
+    public ValueParameter<BoolValue> CollectMaxValueInResultsParameter {
+      get { return (ValueParameter<BoolValue>)Parameters["CollectMaxValueInResults"]; }
+    }
+    public ValueParameter<BoolValue> CollectAverageValueInResultsParameter {
+      get { return (ValueParameter<BoolValue>)Parameters["CollectAverageValueInResults"]; }
+    }
+    #endregion
+
+    #region Properties
+    private MinAverageMaxValueCalculator MinAverageMaxValueCalculator {
+      get { return (MinAverageMaxValueCalculator)OperatorGraph.InitialOperator; }
+    }
+    private BoolValue CollectMinValueInResults {
+      get { return CollectMinValueInResultsParameter.Value; }
+    }
+    private BoolValue CollectMaxValueInResults {
+      get { return CollectMaxValueInResultsParameter.Value; }
+    }
+    private BoolValue CollectAverageValueInResults {
+      get { return CollectAverageValueInResultsParameter.Value; }
+    }
+    #endregion
+    [Storable]
+    private ResultsCollector resultsCollector;
+
+    #region Storing & Cloning
+    [StorableConstructor]
+    private MinAverageMaxValueAnalyzer(bool deserializing) : base(deserializing) { }
+    private MinAverageMaxValueAnalyzer(MinAverageMaxValueAnalyzer original, Cloner cloner)
+      : base(original, cloner) {
+      resultsCollector = cloner.Clone(original.resultsCollector);
+      Initialize();
+    }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new MinAverageMaxValueAnalyzer(this, cloner);
+    }
+    #endregion
+    public MinAverageMaxValueAnalyzer()
+      : base() {
+      #region Create parameters
+      Parameters.Add(new ScopeTreeLookupParameter<DoubleValue>("Value", "The value contained in the scope tree which should be analyzed."));
+      Parameters.Add(new ValueLookupParameter<DoubleValue>("MinValue", "The minimum of the value."));
+      Parameters.Add(new ValueParameter<BoolValue>("CollectMinValueInResults", "Determines if the minimum of the value should also be stored in the results.", new BoolValue(true)));
+      Parameters.Add(new ValueLookupParameter<DoubleValue>("AverageValue", "The average of the value."));
+      Parameters.Add(new ValueParameter<BoolValue>("CollectAverageValueInResults", "Determines if the average of the value should also be stored in the results.", new BoolValue(true)));
+      Parameters.Add(new ValueLookupParameter<DoubleValue>("MaxValue", "The maximum of the value."));
+      Parameters.Add(new ValueParameter<BoolValue>("CollectMaxValueInResults", "Determines if the maximum of the value should also be stored in the results.", new BoolValue(true)));
+      Parameters.Add(new ValueLookupParameter<DataTable>("Values", "The data table to store the minimum, average and maximum of the value."));
+      Parameters.Add(new ValueLookupParameter<VariableCollection>("Results", "The results collection where the analysis values should be stored."));
+      #endregion
+
+      #region Create operators
+      MinAverageMaxValueCalculator minAverageMaxValueCalculator = new MinAverageMaxValueCalculator();
+      DataTableValuesCollector dataTableValuesCollector = new DataTableValuesCollector();
+      resultsCollector = new ResultsCollector();
+
+      minAverageMaxValueCalculator.AverageValueParameter.ActualName = AverageValueParameter.Name;
+      minAverageMaxValueCalculator.MaxValueParameter.ActualName = MaxValueParameter.Name;
+      minAverageMaxValueCalculator.MinValueParameter.ActualName = MinValueParameter.Name;
+      minAverageMaxValueCalculator.ValueParameter.ActualName = ValueParameter.Name;
+      minAverageMaxValueCalculator.ValueParameter.Depth = ValueParameter.Depth;
+
+      dataTableValuesCollector.CollectedValues.Add(new LookupParameter<DoubleValue>("MinValue", null, MinValueParameter.Name));
+      dataTableValuesCollector.CollectedValues.Add(new LookupParameter<DoubleValue>("AverageValue", null, AverageValueParameter.Name));
+      dataTableValuesCollector.CollectedValues.Add(new LookupParameter<DoubleValue>("MaxValue", null, MaxValueParameter.Name));
+      dataTableValuesCollector.DataTableParameter.ActualName = ValuesParameter.Name;
+
+      if (CollectMinValueInResults.Value)
+        resultsCollector.CollectedValues.Add(new LookupParameter<DoubleValue>("MinValue", null, MinValueParameter.Name));
+      if (CollectAverageValueInResults.Value)
+        resultsCollector.CollectedValues.Add(new LookupParameter<DoubleValue>("AverageValue", null, AverageValueParameter.Name));
+      if (CollectMaxValueInResults.Value)
+        resultsCollector.CollectedValues.Add(new LookupParameter<DoubleValue>("MaxValue", null, MaxValueParameter.Name));
+      resultsCollector.CollectedValues.Add(new LookupParameter<DataTable>(ValuesParameter.Name));
+      resultsCollector.ResultsParameter.ActualName = ResultsParameter.Name;
+      #endregion
+
+      #region Create operator graph
+      OperatorGraph.InitialOperator = minAverageMaxValueCalculator;
+      minAverageMaxValueCalculator.Successor = dataTableValuesCollector;
+      dataTableValuesCollector.Successor = resultsCollector;
+      resultsCollector.Successor = null;
+      #endregion
+
+      Initialize();
+    }
+
+    [StorableHook(HookType.AfterDeserialization)]
+    private void Initialize() {
+      ValueParameter.DepthChanged += new EventHandler(ValueParameter_DepthChanged);
+      CollectMinValueInResultsParameter.ValueChanged += new EventHandler(CollectMinValueInResultsParameter_ValueChanged);
+      CollectMinValueInResultsParameter.Value.ValueChanged += new EventHandler(CollectMinValueInResultsParameter_Value_ValueChanged);
+      CollectMaxValueInResultsParameter.ValueChanged += new EventHandler(CollectMaxValueInResultsParameter_ValueChanged);
+      CollectMaxValueInResultsParameter.Value.ValueChanged += new EventHandler(CollectMaxValueInResultsParameter_Value_ValueChanged);
+      CollectAverageValueInResultsParameter.ValueChanged += new EventHandler(CollectAverageValueInResultsParameter_ValueChanged);
+      CollectAverageValueInResultsParameter.Value.ValueChanged += new EventHandler(CollectAverageValueInResultsParameter_Value_ValueChanged);
+    }
+
+    private void CollectAverageValueInResultsParameter_ValueChanged(object sender, EventArgs e) {
+      IParameter avgValueParameter;
+      resultsCollector.CollectedValues.TryGetValue("AverageValue", out avgValueParameter);
+      if (CollectAverageValueInResults.Value && avgValueParameter == null)
+        resultsCollector.CollectedValues.Add(new LookupParameter<DoubleValue>("AverageValue", null, AverageValueParameter.Name));
+      else if (!CollectAverageValueInResults.Value && avgValueParameter != null)
+        resultsCollector.CollectedValues.Remove(avgValueParameter);
+      CollectAverageValueInResultsParameter.Value.ValueChanged += new EventHandler(CollectAverageValueInResultsParameter_Value_ValueChanged);
+    }
+
+    private void CollectAverageValueInResultsParameter_Value_ValueChanged(object sender, EventArgs e) {
+      IParameter avgValueParameter;
+      resultsCollector.CollectedValues.TryGetValue("AverageValue", out avgValueParameter);
+      if (CollectAverageValueInResults.Value && avgValueParameter == null)
+        resultsCollector.CollectedValues.Add(new LookupParameter<DoubleValue>("AverageValue", null, AverageValueParameter.Name));
+      else if (!CollectAverageValueInResults.Value && avgValueParameter != null)
+        resultsCollector.CollectedValues.Remove(avgValueParameter);
+    }
+
+    private void CollectMaxValueInResultsParameter_ValueChanged(object sender, EventArgs e) {
+      IParameter maxValueParameter;
+      resultsCollector.CollectedValues.TryGetValue("MaxValue", out maxValueParameter);
+      if (CollectMaxValueInResults.Value && maxValueParameter == null)
+        resultsCollector.CollectedValues.Add(new LookupParameter<DoubleValue>("MaxValue", null, MaxValueParameter.Name));
+      else if (!CollectMaxValueInResults.Value && maxValueParameter != null)
+        resultsCollector.CollectedValues.Remove(maxValueParameter);
+      CollectMaxValueInResultsParameter.Value.ValueChanged += new EventHandler(CollectMaxValueInResultsParameter_Value_ValueChanged);
+    }
+
+    private void CollectMaxValueInResultsParameter_Value_ValueChanged(object sender, EventArgs e) {
+      IParameter maxValueParameter;
+      resultsCollector.CollectedValues.TryGetValue("MaxValue", out maxValueParameter);
+      if (CollectMaxValueInResults.Value && maxValueParameter == null)
+        resultsCollector.CollectedValues.Add(new LookupParameter<DoubleValue>("MaxValue", null, MaxValueParameter.Name));
+      else if (!CollectMaxValueInResults.Value && maxValueParameter != null)
+        resultsCollector.CollectedValues.Remove(maxValueParameter);
+      }
+
+    private void CollectMinValueInResultsParameter_ValueChanged(object sender, EventArgs e) {
+      IParameter minValueParameter;
+      resultsCollector.CollectedValues.TryGetValue("MinValue", out minValueParameter);
+      if (CollectMinValueInResults.Value && minValueParameter == null)
+        resultsCollector.CollectedValues.Add(new LookupParameter<DoubleValue>("MinValue", null, MinValueParameter.Name));
+      else if (!CollectMinValueInResults.Value && minValueParameter != null)
+        resultsCollector.CollectedValues.Remove(minValueParameter);
+      CollectMinValueInResultsParameter.Value.ValueChanged += new EventHandler(CollectMinValueInResultsParameter_Value_ValueChanged);
+    }
+
+    private void CollectMinValueInResultsParameter_Value_ValueChanged(object sender, EventArgs e) {
+      IParameter minValueParameter;
+      resultsCollector.CollectedValues.TryGetValue("MinValue", out minValueParameter);
+      if (CollectMinValueInResults.Value && minValueParameter == null)
+        resultsCollector.CollectedValues.Add(new LookupParameter<DoubleValue>("MinValue", null, MinValueParameter.Name));
+      else if (!CollectMinValueInResults.Value && minValueParameter != null)
+        resultsCollector.CollectedValues.Remove(minValueParameter);
+    }
+
+    private void ValueParameter_DepthChanged(object sender, System.EventArgs e) {
+      MinAverageMaxValueCalculator.ValueParameter.Depth = ValueParameter.Depth;
+    }
+  }
+}
Index: trunk/sources/HeuristicLab.Analysis/3.3/ValueAnalysis/MinAverageMaxValueCalculator.cs
===================================================================
--- trunk/sources/HeuristicLab.Analysis/3.3/ValueAnalysis/MinAverageMaxValueCalculator.cs	(revision 4887)
+++ trunk/sources/HeuristicLab.Analysis/3.3/ValueAnalysis/MinAverageMaxValueCalculator.cs	(revision 4887)
@@ -0,0 +1,89 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2010 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Operators;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Analysis {
+  /// <summary>
+  /// An operator which calculates the minimum, average and maximum of a value in the scope tree.
+  /// </summary>
+  [Item("MinAverageMaxValueCalculator", "An operator which calculates the minimum, average and maximum of a value in the scope tree.")]
+  [StorableClass]
+  public sealed class MinAverageMaxValueCalculator : SingleSuccessorOperator {
+    public ScopeTreeLookupParameter<DoubleValue> ValueParameter {
+      get { return (ScopeTreeLookupParameter<DoubleValue>)Parameters["Value"]; }
+    }
+    public ValueLookupParameter<DoubleValue> MinValueParameter {
+      get { return (ValueLookupParameter<DoubleValue>)Parameters["MinValue"]; }
+    }
+    public ValueLookupParameter<DoubleValue> AverageValueParameter {
+      get { return (ValueLookupParameter<DoubleValue>)Parameters["AverageValue"]; }
+    }
+    public ValueLookupParameter<DoubleValue> MaxValueParameter {
+      get { return (ValueLookupParameter<DoubleValue>)Parameters["MaxValue"]; }
+    }
+
+    #region Storing & Cloning
+    [StorableConstructor]
+    private MinAverageMaxValueCalculator(bool deserializing) : base(deserializing) { }
+    private MinAverageMaxValueCalculator(MinAverageMaxValueCalculator original, Cloner cloner) : base(original, cloner) { }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new MinAverageMaxValueCalculator(this, cloner);
+    }
+    #endregion
+    public MinAverageMaxValueCalculator()
+      : base() {
+      Parameters.Add(new ScopeTreeLookupParameter<DoubleValue>("Value", "The value contained in the scope tree for which the minimum, average and maximum should be calculated."));
+      Parameters.Add(new ValueLookupParameter<DoubleValue>("MinValue", "The minimum of the value."));
+      Parameters.Add(new ValueLookupParameter<DoubleValue>("AverageValue", "The average of the value."));
+      Parameters.Add(new ValueLookupParameter<DoubleValue>("MaxValue", "The maximum of the value."));
+    }
+
+    public override IOperation Apply() {
+      ItemArray<DoubleValue> values = ValueParameter.ActualValue;
+
+      if (values.Length > 0) {
+        double min = double.MaxValue, max = double.MinValue, sum = 0.0;
+        for (int i = 0; i < values.Length; i++) {
+          if (values[i].Value < min) min = values[i].Value;
+          if (values[i].Value > max) max = values[i].Value;
+          sum += values[i].Value;
+        }
+
+        DoubleValue minValue = MinValueParameter.ActualValue;
+        if (minValue == null) MinValueParameter.ActualValue = new DoubleValue(min);
+        else minValue.Value = min;
+        DoubleValue averageValue = AverageValueParameter.ActualValue;
+        if (averageValue == null) AverageValueParameter.ActualValue = new DoubleValue(sum / values.Length);
+        else averageValue.Value = sum / values.Length;
+        DoubleValue maxValue = MaxValueParameter.ActualValue;
+        if (maxValue == null) MaxValueParameter.ActualValue = new DoubleValue(max);
+        else maxValue.Value = max;
+      }
+      return base.Apply();
+    }
+  }
+}
Index: trunk/sources/HeuristicLab.Analysis/3.3/ValueAnalysis/ValueAnalyzer.cs
===================================================================
--- trunk/sources/HeuristicLab.Analysis/3.3/ValueAnalysis/ValueAnalyzer.cs	(revision 4887)
+++ trunk/sources/HeuristicLab.Analysis/3.3/ValueAnalysis/ValueAnalyzer.cs	(revision 4887)
@@ -0,0 +1,116 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2010 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Operators;
+using HeuristicLab.Optimization;
+using HeuristicLab.Optimization.Operators;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Analysis {
+  /// <summary>
+  /// An operator which analyzes a value in the scope tree.
+  /// </summary>
+  [Item("ValueAnalyzer", "An operator which analyzes a value in the scope tree.")]
+  [StorableClass]
+  public sealed class ValueAnalyzer : AlgorithmOperator, IAnalyzer {
+    #region Parameter properties
+    public ScopeTreeLookupParameter<DoubleValue> ValueParameter {
+      get { return (ScopeTreeLookupParameter<DoubleValue>)Parameters["Value"]; }
+    }
+    public ValueLookupParameter<DataTable> ValuesParameter {
+      get { return (ValueLookupParameter<DataTable>)Parameters["Values"]; }
+    }
+    public ValueLookupParameter<VariableCollection> ResultsParameter {
+      get { return (ValueLookupParameter<VariableCollection>)Parameters["Results"]; }
+    }
+    #endregion
+
+    #region Properties
+    private DataTableValuesCollector DataTableValuesCollector {
+      get { return (DataTableValuesCollector)OperatorGraph.InitialOperator; }
+    }
+    private ResultsCollector ResultsCollector {
+      get { return (ResultsCollector)DataTableValuesCollector.Successor; }
+    }
+    #endregion
+
+    #region Storing & Cloning
+    [StorableConstructor]
+    private ValueAnalyzer(bool deserializing) : base(deserializing) { }
+    private ValueAnalyzer(ValueAnalyzer original, Cloner cloner)
+      : base(original, cloner) {
+        Initialize();
+    }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new ValueAnalyzer(this, cloner);
+    }
+    #endregion
+    public ValueAnalyzer()
+      : base() {
+      #region Create parameters
+      Parameters.Add(new ScopeTreeLookupParameter<DoubleValue>("Value", "The value contained in the scope tree which should be analyzed."));
+      Parameters.Add(new ValueLookupParameter<DataTable>("Values", "The data table to store the values."));
+      Parameters.Add(new ValueLookupParameter<VariableCollection>("Results", "The results collection where the analysis values should be stored."));
+      #endregion
+
+      #region Create operators
+      DataTableValuesCollector dataTableValuesCollector = new DataTableValuesCollector();
+      ResultsCollector resultsCollector = new ResultsCollector();
+
+      dataTableValuesCollector.CollectedValues.Add(new ScopeTreeLookupParameter<DoubleValue>("Value", null, ValueParameter.Name));
+      ((ScopeTreeLookupParameter<DoubleValue>)dataTableValuesCollector.CollectedValues["Value"]).Depth = ValueParameter.Depth;
+      dataTableValuesCollector.DataTableParameter.ActualName = ValuesParameter.Name;
+
+      resultsCollector.CollectedValues.Add(new ScopeTreeLookupParameter<DoubleValue>("Value", null, ValueParameter.Name));
+      ((ScopeTreeLookupParameter<DoubleValue>)resultsCollector.CollectedValues["Value"]).Depth = ValueParameter.Depth;
+      resultsCollector.CollectedValues.Add(new LookupParameter<DataTable>(ValuesParameter.Name));
+      resultsCollector.ResultsParameter.ActualName = ResultsParameter.Name;
+      #endregion
+
+      #region Create operator graph
+      OperatorGraph.InitialOperator = dataTableValuesCollector;
+      dataTableValuesCollector.Successor = resultsCollector;
+      resultsCollector.Successor = null;
+      #endregion
+
+      Initialize();
+    }
+
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() {
+      Initialize();
+    }
+
+    private void Initialize() {
+      ValueParameter.DepthChanged += new EventHandler(ValueParameter_DepthChanged);
+    }
+
+    private void ValueParameter_DepthChanged(object sender, System.EventArgs e) {
+      ((ScopeTreeLookupParameter<DoubleValue>)DataTableValuesCollector.CollectedValues["Value"]).Depth = ValueParameter.Depth;
+      ((ScopeTreeLookupParameter<DoubleValue>)ResultsCollector.CollectedValues["Value"]).Depth = ValueParameter.Depth;
+    }
+  }
+}
Index: trunk/sources/HeuristicLab.Analysis/3.3/ValueAnalyzer.cs
===================================================================
--- trunk/sources/HeuristicLab.Analysis/3.3/ValueAnalyzer.cs	(revision 4870)
+++ 	(revision )
@@ -1,116 +1,0 @@
-#region License Information
-/* HeuristicLab
- * Copyright (C) 2002-2010 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
- *
- * This file is part of HeuristicLab.
- *
- * HeuristicLab is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * HeuristicLab is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
- */
-#endregion
-
-using System;
-using HeuristicLab.Common;
-using HeuristicLab.Core;
-using HeuristicLab.Data;
-using HeuristicLab.Operators;
-using HeuristicLab.Optimization;
-using HeuristicLab.Optimization.Operators;
-using HeuristicLab.Parameters;
-using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
-
-namespace HeuristicLab.Analysis {
-  /// <summary>
-  /// An operator which analyzes a value in the scope tree.
-  /// </summary>
-  [Item("ValueAnalyzer", "An operator which analyzes a value in the scope tree.")]
-  [StorableClass]
-  public sealed class ValueAnalyzer : AlgorithmOperator, IAnalyzer {
-    #region Parameter properties
-    public ScopeTreeLookupParameter<DoubleValue> ValueParameter {
-      get { return (ScopeTreeLookupParameter<DoubleValue>)Parameters["Value"]; }
-    }
-    public ValueLookupParameter<DataTable> ValuesParameter {
-      get { return (ValueLookupParameter<DataTable>)Parameters["Values"]; }
-    }
-    public ValueLookupParameter<VariableCollection> ResultsParameter {
-      get { return (ValueLookupParameter<VariableCollection>)Parameters["Results"]; }
-    }
-    #endregion
-
-    #region Properties
-    private DataTableValuesCollector DataTableValuesCollector {
-      get { return (DataTableValuesCollector)OperatorGraph.InitialOperator; }
-    }
-    private ResultsCollector ResultsCollector {
-      get { return (ResultsCollector)DataTableValuesCollector.Successor; }
-    }
-    #endregion
-
-    #region Storing & Cloning
-    [StorableConstructor]
-    private ValueAnalyzer(bool deserializing) : base(deserializing) { }
-    private ValueAnalyzer(ValueAnalyzer original, Cloner cloner)
-      : base(original, cloner) {
-        Initialize();
-    }
-    public override IDeepCloneable Clone(Cloner cloner) {
-      return new ValueAnalyzer(this, cloner);
-    }
-    #endregion
-    public ValueAnalyzer()
-      : base() {
-      #region Create parameters
-      Parameters.Add(new ScopeTreeLookupParameter<DoubleValue>("Value", "The value contained in the scope tree which should be analyzed."));
-      Parameters.Add(new ValueLookupParameter<DataTable>("Values", "The data table to store the values."));
-      Parameters.Add(new ValueLookupParameter<VariableCollection>("Results", "The results collection where the analysis values should be stored."));
-      #endregion
-
-      #region Create operators
-      DataTableValuesCollector dataTableValuesCollector = new DataTableValuesCollector();
-      ResultsCollector resultsCollector = new ResultsCollector();
-
-      dataTableValuesCollector.CollectedValues.Add(new ScopeTreeLookupParameter<DoubleValue>("Value", null, ValueParameter.Name));
-      ((ScopeTreeLookupParameter<DoubleValue>)dataTableValuesCollector.CollectedValues["Value"]).Depth = ValueParameter.Depth;
-      dataTableValuesCollector.DataTableParameter.ActualName = ValuesParameter.Name;
-
-      resultsCollector.CollectedValues.Add(new ScopeTreeLookupParameter<DoubleValue>("Value", null, ValueParameter.Name));
-      ((ScopeTreeLookupParameter<DoubleValue>)resultsCollector.CollectedValues["Value"]).Depth = ValueParameter.Depth;
-      resultsCollector.CollectedValues.Add(new LookupParameter<DataTable>(ValuesParameter.Name));
-      resultsCollector.ResultsParameter.ActualName = ResultsParameter.Name;
-      #endregion
-
-      #region Create operator graph
-      OperatorGraph.InitialOperator = dataTableValuesCollector;
-      dataTableValuesCollector.Successor = resultsCollector;
-      resultsCollector.Successor = null;
-      #endregion
-
-      Initialize();
-    }
-
-    [StorableHook(HookType.AfterDeserialization)]
-    private void AfterDeserialization() {
-      Initialize();
-    }
-
-    private void Initialize() {
-      ValueParameter.DepthChanged += new EventHandler(ValueParameter_DepthChanged);
-    }
-
-    private void ValueParameter_DepthChanged(object sender, System.EventArgs e) {
-      ((ScopeTreeLookupParameter<DoubleValue>)DataTableValuesCollector.CollectedValues["Value"]).Depth = ValueParameter.Depth;
-      ((ScopeTreeLookupParameter<DoubleValue>)ResultsCollector.CollectedValues["Value"]).Depth = ValueParameter.Depth;
-    }
-  }
-}
