Index: branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/AlleleFrequencyAnalysis/Allele.cs
===================================================================
--- branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/AlleleFrequencyAnalysis/Allele.cs	(revision 9280)
+++ branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/AlleleFrequencyAnalysis/Allele.cs	(revision 9280)
@@ -0,0 +1,87 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 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: branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/AlleleFrequencyAnalysis/AlleleFrequency.cs
===================================================================
--- branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/AlleleFrequencyAnalysis/AlleleFrequency.cs	(revision 9280)
+++ branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/AlleleFrequencyAnalysis/AlleleFrequency.cs	(revision 9280)
@@ -0,0 +1,130 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 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: branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/AlleleFrequencyAnalysis/AlleleFrequencyAnalyzer.cs
===================================================================
--- branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/AlleleFrequencyAnalysis/AlleleFrequencyAnalyzer.cs	(revision 9280)
+++ branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/AlleleFrequencyAnalysis/AlleleFrequencyAnalyzer.cs	(revision 9280)
@@ -0,0 +1,312 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.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 virtual bool EnabledByDefault {
+      get { return false; }
+    }
+
+    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"));
+
+      MaximizationParameter.Hidden = true;
+      SolutionParameter.Hidden = true;
+      QualityParameter.Hidden = true;
+      BestKnownSolutionParameter.Hidden = true;
+      ResultsParameter.Hidden = true;
+      UpdateCounterParameter.Hidden = true;
+    }
+
+    #region Equality Comparers
+    private class AlleleIdEqualityComparer : IEqualityComparer<Allele> {
+      public bool Equals(Allele x, Allele y) {
+        return x.Id == y.Id;
+      }
+      public int GetHashCode(Allele obj) {
+        return obj.Id.GetHashCode();
+      }
+    }
+    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;
+        double[] qualities = QualityParameter.ActualValue.Select(x => x.Value).ToArray();
+        T bestKnownSolution = BestKnownSolutionParameter.ActualValue;
+        bool storeHistory = StoreHistoryParameter.Value.Value;
+
+        // calculate index of current best solution
+        int bestIndex = -1;
+        if (!max) {
+          bestIndex = qualities
+            .Select((x, i) => new { Index = i, Value = x })
+            .OrderBy(x => x.Value)
+            .First().Index;
+        } else {
+          bestIndex = qualities
+            .Select((x, i) => new { Index = i, Value = x })
+            .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),
+                                                          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(Name + " Results")) {
+          results = new ResultCollection();
+          ResultsParameter.ActualValue.Add(new Result(Name + " Results", results));
+        } else {
+          results = (ResultCollection)ResultsParameter.ActualValue[Name + " 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;
+
+        // calculate contained alleles of best known solution and relative quality
+        if (bestKnownAlleles != null) {
+          double qualityRange = Math.Abs(qualities.Max() - qualities.Min());
+          var points = solutions.Select((s, index) => new Point2D<double>(CalculateAlleles(s).Intersect(bestKnownAlleles, new AlleleIdEqualityComparer()).Count(),
+                                                                          Math.Abs(qualities[index] - qualities[bestIndex]) / qualityRange));
+          var avgContainedReleventAlleles = points.Select(x => x.X).Average();
+
+          var plot = new ScatterPlot("Contained Alleles of Best Known Solution and Relative Solution Qualtiy", null);
+          plot.VisualProperties.XAxisTitle = "Contained Alleles of Best Known Solution";
+          plot.VisualProperties.YAxisTitle = "Relative Solution Quality";
+          plot.VisualProperties.XAxisMinimumAuto = false;
+          plot.VisualProperties.XAxisMinimumFixedValue = 0.0;
+          plot.VisualProperties.XAxisMaximumAuto = false;
+          plot.VisualProperties.XAxisMaximumFixedValue = bestKnownAlleles.Length;
+          plot.VisualProperties.YAxisMinimumAuto = false;
+          plot.VisualProperties.YAxisMinimumFixedValue = 0.0;
+          plot.VisualProperties.YAxisMaximumAuto = false;
+          plot.VisualProperties.YAxisMaximumFixedValue = 1.0;
+          var row = new ScatterPlotDataRow("Solutions of Current Generation", null, points);
+          row.VisualProperties.PointStyle = ScatterPlotDataRowVisualProperties.ScatterPlotDataRowPointStyle.Circle;
+          row.VisualProperties.PointSize = 5;
+          plot.Rows.Add(row);
+
+          if (!results.ContainsKey("Scatter Plot"))
+            results.Add(new Result("Scatter Plot", plot));
+          else
+            results["Scatter Plot"].Value = plot;
+          if (storeHistory) {
+            if (!results.ContainsKey("Scatter Plot History")) {
+              results.Add(new Result("Scatter Plot History", new ScatterPlotHistory()));
+            }
+            ((ScatterPlotHistory)results["Scatter Plot History"].Value).Add(plot);
+          }
+
+          if (!allelesTable.Rows.ContainsKey("Average Contained Alleles of Best Known Solution")) {
+            allelesTable.Rows.Add(new DataRow("Average Contained Alleles of Best Known Solution", null));
+            allelesTable.Rows["Average Contained Alleles of Best Known Solution"].VisualProperties.SecondYAxis = true;
+            allelesTable.Rows["Average Contained Alleles of Best Known Solution"].VisualProperties.StartIndexZero = true;
+          }
+          allelesTable.Rows["Average Contained Alleles of Best Known Solution"].Values.Add(avgContainedReleventAlleles);
+
+          if (!results.ContainsKey("Average Contained Alleles of Best Known Solution"))
+            results.Add(new Result("Average Contained Alleles of Best Known Solution", new DoubleValue(avgContainedReleventAlleles)));
+          else
+            ((DoubleValue)results["Average Contained Alleles of Best Known Solution"].Value).Value = avgContainedReleventAlleles;
+        }
+      }
+      return base.Apply();
+    }
+
+    protected abstract Allele[] CalculateAlleles(T solution);
+  }
+}
Index: branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/AlleleFrequencyAnalysis/AlleleFrequencyCollection.cs
===================================================================
--- branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/AlleleFrequencyAnalysis/AlleleFrequencyCollection.cs	(revision 9280)
+++ branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/AlleleFrequencyAnalysis/AlleleFrequencyCollection.cs	(revision 9280)
@@ -0,0 +1,49 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 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 static new Image StaticItemImage {
+      get { return HeuristicLab.Common.Resources.VSImageLibrary.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: branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/AlleleFrequencyAnalysis/AlleleFrequencyCollectionHistory.cs
===================================================================
--- branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/AlleleFrequencyAnalysis/AlleleFrequencyCollectionHistory.cs	(revision 9280)
+++ branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/AlleleFrequencyAnalysis/AlleleFrequencyCollectionHistory.cs	(revision 9280)
@@ -0,0 +1,49 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 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 static new Image StaticItemImage {
+      get { return HeuristicLab.Common.Resources.VSImageLibrary.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: branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/BestScopeSolutionAnalyzer.cs
===================================================================
--- branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/BestScopeSolutionAnalyzer.cs	(revision 9280)
+++ branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/BestScopeSolutionAnalyzer.cs	(revision 9280)
@@ -0,0 +1,124 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 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 that extracts (clones) the scope containing the best quality.
+  /// </summary>
+  [Item("BestScopeSolutionAnalyzer", "An operator that extracts the scope containing the best quality.")]
+  [StorableClass]
+  public class BestScopeSolutionAnalyzer : SingleSuccessorOperator, IAnalyzer {
+    public virtual bool EnabledByDefault {
+      get { return true; }
+    }
+
+    public LookupParameter<BoolValue> MaximizationParameter {
+      get { return (LookupParameter<BoolValue>)Parameters["Maximization"]; }
+    }
+    public ScopeTreeLookupParameter<DoubleValue> QualityParameter {
+      get { return (ScopeTreeLookupParameter<DoubleValue>)Parameters["Quality"]; }
+    }
+    public ILookupParameter<IScope> BestSolutionParameter {
+      get { return (ILookupParameter<IScope>)Parameters["BestSolution"]; }
+    }
+    public ILookupParameter<IScope> BestKnownSolutionParameter {
+      get { return (ILookupParameter<IScope>)Parameters["BestKnownSolution"]; }
+    }
+    public ILookupParameter<DoubleValue> BestKnownQualityParameter {
+      get { return (ILookupParameter<DoubleValue>)Parameters["BestKnownQuality"]; }
+    }
+    public IValueLookupParameter<ResultCollection> ResultsParameter {
+      get { return (IValueLookupParameter<ResultCollection>)Parameters["Results"]; }
+    }
+
+    #region Storing & Cloning
+    [StorableConstructor]
+    protected BestScopeSolutionAnalyzer(bool deserializing) : base(deserializing) { }
+    protected BestScopeSolutionAnalyzer(BestScopeSolutionAnalyzer original, Cloner cloner) : base(original, cloner) { }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new BestScopeSolutionAnalyzer(this, cloner);
+    }
+    #endregion
+    public BestScopeSolutionAnalyzer()
+      : base() {
+      Parameters.Add(new LookupParameter<BoolValue>("Maximization", "True if the problem is a maximization problem."));
+      Parameters.Add(new ScopeTreeLookupParameter<DoubleValue>("Quality", "The qualities of the solutions."));
+      Parameters.Add(new LookupParameter<IScope>("BestSolution", "The best solution."));
+      Parameters.Add(new LookupParameter<IScope>("BestKnownSolution", "The best known solution."));
+      Parameters.Add(new LookupParameter<DoubleValue>("BestKnownQuality", "The quality of the best known solution."));
+      Parameters.Add(new ValueLookupParameter<ResultCollection>("Results", "The result collection where the solution should be stored."));
+    }
+
+    public override IOperation Apply() {
+      ItemArray<DoubleValue> qualities = QualityParameter.ActualValue;
+      ResultCollection results = ResultsParameter.ActualValue;
+      bool max = MaximizationParameter.ActualValue.Value;
+      DoubleValue bestKnownQuality = BestKnownQualityParameter.ActualValue;
+
+      int i = -1;
+      if (!max)
+        i = qualities.Select((x, index) => new { index, x.Value }).OrderBy(x => x.Value).First().index;
+      else i = qualities.Select((x, index) => new { index, x.Value }).OrderByDescending(x => x.Value).First().index;
+
+      IEnumerable<IScope> scopes = new IScope[] { ExecutionContext.Scope };
+      for (int j = 0; j < QualityParameter.Depth; j++)
+        scopes = scopes.Select(x => (IEnumerable<IScope>)x.SubScopes).Aggregate((a, b) => a.Concat(b));
+      IScope currentBestScope = scopes.ToList()[i];
+
+      if (bestKnownQuality == null ||
+          max && qualities[i].Value > bestKnownQuality.Value
+          || !max && qualities[i].Value < bestKnownQuality.Value) {
+        BestKnownQualityParameter.ActualValue = new DoubleValue(qualities[i].Value);
+        BestKnownSolutionParameter.ActualValue = (IScope)currentBestScope.Clone();
+      }
+
+      IScope solution = BestSolutionParameter.ActualValue;
+      if (solution == null) {
+        solution = (IScope)currentBestScope.Clone();
+        BestSolutionParameter.ActualValue = solution;
+        results.Add(new Result("Best Solution", solution));
+      } else {
+        string qualityName = QualityParameter.TranslatedName;
+        if (solution.Variables.ContainsKey(qualityName)) {
+          double bestSoFarQuality = (solution.Variables[qualityName].Value as DoubleValue).Value;
+          if (max && qualities[i].Value > bestSoFarQuality
+            || !max && qualities[i].Value < bestSoFarQuality) {
+            solution = (IScope)currentBestScope.Clone();
+            BestSolutionParameter.ActualValue = solution;
+            results["Best Solution"].Value = solution;
+          }
+        }
+      }
+
+      return base.Apply();
+    }
+  }
+}
Index: branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/DataVisualization/DataRow.cs
===================================================================
--- branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/DataVisualization/DataRow.cs	(revision 9280)
+++ branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/DataVisualization/DataRow.cs	(revision 9280)
@@ -0,0 +1,121 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 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 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;
+        visualProperties.PropertyChanged += new PropertyChangedEventHandler(VisualProperties_PropertyChanged);
+      }
+    }
+    [Storable(Name = "values")]
+    private IEnumerable<double> StorableValues {
+      get { return values; }
+      set { values = new ObservableList<double>(value); }
+    }
+    #endregion
+
+    [StorableConstructor]
+    protected DataRow(bool deserializing) : base(deserializing) { }
+    protected 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(name);
+      values = new ObservableList<double>();
+    }
+    public DataRow(string name, string description)
+      : base(name, description) {
+      VisualProperties = new DataRowVisualProperties(name);
+      values = new ObservableList<double>();
+    }
+    public DataRow(string name, string description, IEnumerable<double> values)
+      : base(name, description) {
+      VisualProperties = new DataRowVisualProperties(name);
+      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;
+    protected virtual void OnVisualPropertiesChanged() {
+      EventHandler handler = VisualPropertiesChanged;
+      if (handler != null) handler(this, EventArgs.Empty);
+    }
+
+    private void VisualProperties_PropertyChanged(object sender, PropertyChangedEventArgs e) {
+      OnVisualPropertiesChanged();
+    }
+  }
+}
Index: branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/DataVisualization/DataRowVisualProperties.cs
===================================================================
--- branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/DataVisualization/DataRowVisualProperties.cs	(revision 9280)
+++ branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/DataVisualization/DataRowVisualProperties.cs	(revision 9280)
@@ -0,0 +1,308 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 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.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,
+      Histogram,
+      StepLine
+    }
+    #endregion
+    #region LineStyle
+    public enum DataRowLineStyle {
+      Dash,
+      DashDot,
+      DashDotDot,
+      Dot,
+      NotSet,
+      Solid
+    }
+    #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 bool secondXAxis;
+    public bool SecondXAxis {
+      get { return secondXAxis; }
+      set {
+        if (secondXAxis != value) {
+          secondXAxis = value;
+          OnPropertyChanged("SecondXAxis");
+        }
+      }
+    }
+    private Color color;
+    public Color Color {
+      get { return color; }
+      set {
+        if (color != value) {
+          color = value;
+          OnPropertyChanged("Color");
+        }
+      }
+    }
+    private DataRowLineStyle lineStyle;
+    public DataRowLineStyle LineStyle {
+      get { return lineStyle; }
+      set {
+        if (lineStyle != value) {
+          lineStyle = value;
+          OnPropertyChanged("LineStyle");
+        }
+      }
+    }
+    private bool startIndexZero;
+    public bool StartIndexZero {
+      get { return startIndexZero; }
+      set {
+        if (startIndexZero != value) {
+          startIndexZero = value;
+          OnPropertyChanged("StartIndexZero");
+        }
+      }
+    }
+    private int lineWidth;
+    public int LineWidth {
+      get { return lineWidth; }
+      set {
+        if (lineWidth != value) {
+          lineWidth = value;
+          OnPropertyChanged("LineWidth");
+        }
+      }
+    }
+    private int bins;
+    public int Bins {
+      get { return bins; }
+      set {
+        if (bins != value) {
+          bins = value;
+          OnPropertyChanged("Bins");
+        }
+      }
+    }
+    private bool exactBins;
+    public bool ExactBins {
+      get { return exactBins; }
+      set {
+        if (exactBins != value) {
+          exactBins = value;
+          OnPropertyChanged("ExactBins");
+        }
+      }
+    }
+    private double scaleFactor;
+    public double ScaleFactor {
+      get { return scaleFactor; }
+      set {
+        if (scaleFactor != value) {
+          scaleFactor = value;
+          OnPropertyChanged("ScaleFactor");
+        }
+      }
+    }
+    private bool isVisibleInLegend;
+    public bool IsVisibleInLegend {
+      get { return isVisibleInLegend; }
+      set {
+        if (isVisibleInLegend != value) {
+          isVisibleInLegend = value;
+          OnPropertyChanged("IsVisibleInLegend");
+        }
+      }
+    }
+    private string displayName;
+    public string DisplayName {
+      get { return displayName == null ? String.Empty : displayName; }
+      set {
+        if (displayName != value) {
+          if (value == null && displayName != String.Empty) {
+            displayName = String.Empty;
+            OnPropertyChanged("DisplayName");
+          } else if (value != null) {
+            displayName = value;
+            OnPropertyChanged("DisplayName");
+          }
+        }
+      }
+    }
+
+    #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 = "SecondXAxis")]
+    private bool StorableSecondXAxis {
+      get { return secondXAxis; }
+      set { secondXAxis = value; }
+    }
+    [Storable(Name = "Color")]
+    private Color StorableColor {
+      get { return color; }
+      set { color = value; }
+    }
+    [Storable(Name = "LineStyle")]
+    private DataRowLineStyle StorableLineStyle {
+      get { return lineStyle; }
+      set { lineStyle = value; }
+    }
+    [Storable(Name = "StartIndexZero")]
+    private bool StorableStartIndexZero {
+      get { return startIndexZero; }
+      set { startIndexZero = value; }
+    }
+    [Storable(Name = "LineWidth")]
+    private int StorableLineWidth {
+      get { return lineWidth; }
+      set { lineWidth = value; }
+    }
+    [Storable(Name = "Bins")]
+    private int StorableBins {
+      get { return bins; }
+      set { bins = value; }
+    }
+    [Storable(Name = "ExactBins")]
+    private bool StorableExactBins {
+      get { return exactBins; }
+      set { exactBins = value; }
+    }
+    [Storable(Name = "ScaleFactor")]
+    private double StorableScaleFactor {
+      get { return scaleFactor; }
+      set { scaleFactor = value; }
+    }
+    [Storable(Name = "IsVisibleInLegend", DefaultValue = true)]
+    private bool StorableIsVisibleInLegend {
+      get { return isVisibleInLegend; }
+      set { isVisibleInLegend = value; }
+    }
+    [Storable(Name = "DisplayName")]
+    private string StorableDisplayName {
+      get { return displayName; }
+      set { displayName = 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.secondXAxis = original.secondXAxis;
+      this.color = original.color;
+      this.lineStyle = original.lineStyle;
+      this.startIndexZero = original.startIndexZero;
+      this.lineWidth = original.lineWidth;
+      this.bins = original.bins;
+      this.exactBins = original.exactBins;
+      this.scaleFactor = original.scaleFactor;
+      this.displayName = original.displayName;
+      this.isVisibleInLegend = original.isVisibleInLegend;
+    }
+    public DataRowVisualProperties() {
+      chartType = DataRowChartType.Line;
+      secondYAxis = false;
+      secondXAxis = false;
+      color = Color.Empty;
+      lineStyle = DataRowLineStyle.Solid;
+      startIndexZero = false;
+      lineWidth = 1;
+      bins = 10;
+      exactBins = false;
+      scaleFactor = 1.0;
+      displayName = String.Empty;
+      isVisibleInLegend = true;
+    }
+    public DataRowVisualProperties(string displayName)
+      : this() {
+      this.displayName = displayName;
+    }
+
+    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));
+    }
+
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() {
+      // BackwardsCompatibility3.3
+      #region Backwards compatible code, remove with 3.4
+      if (secondXAxis == default(bool)
+        && lineStyle == default(DataRowLineStyle)
+        && lineWidth == default(int) && bins == default(int) && exactBins == default(bool)
+        && displayName == default(string)) {
+        secondXAxis = false;
+        lineStyle = DataRowLineStyle.Solid;
+        lineWidth = 1;
+        bins = 10;
+        exactBins = false;
+        displayName = String.Empty;
+      }
+      #endregion
+    }
+  }
+}
Index: branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/DataVisualization/DataTable.cs
===================================================================
--- branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/DataVisualization/DataTable.cs	(revision 9280)
+++ branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/DataVisualization/DataTable.cs	(revision 9280)
@@ -0,0 +1,286 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 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 class DataTable : NamedItem, IStringConvertibleMatrix {
+    public static new Image StaticItemImage {
+      get { return HeuristicLab.Common.Resources.VSImageLibrary.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; }
+      private set {
+        if (rows != null) throw new InvalidOperationException("Rows already set");
+        rows = value;
+        if (rows != null) RegisterRowsEvents();
+      }
+    }
+
+    #region Persistence Properties
+    [Storable(Name = "VisualProperties")]
+    private DataTableVisualProperties StorableVisualProperties {
+      get { return visualProperties; }
+      set {
+        visualProperties = value;
+        visualProperties.PropertyChanged += new PropertyChangedEventHandler(VisualProperties_PropertyChanged);
+      }
+    }
+    [Storable(Name = "rows")]
+    private IEnumerable<DataRow> StorableRows {
+      get { return rows; }
+      set { Rows = new NamedItemCollection<DataRow>(value); }
+    }
+    #endregion
+
+    [StorableConstructor]
+    protected DataTable(bool deserializing) : base(deserializing) { }
+    protected DataTable(DataTable original, Cloner cloner)
+      : base(original, cloner) {
+      VisualProperties = (DataTableVisualProperties)cloner.Clone(original.visualProperties);
+      Rows = cloner.Clone(original.rows);
+    }
+    public DataTable()
+      : base() {
+      VisualProperties = new DataTableVisualProperties();
+      Rows = new NamedItemCollection<DataRow>();
+    }
+    public DataTable(string name)
+      : base(name) {
+      VisualProperties = new DataTableVisualProperties(name);
+      Rows = new NamedItemCollection<DataRow>();
+    }
+    public DataTable(string name, string description)
+      : base(name, description) {
+      VisualProperties = new DataTableVisualProperties(name);
+      Rows = new NamedItemCollection<DataRow>();
+    }
+
+    // BackwardsCompatibility3.3
+    #region Backwards compatible code, remove with 3.4
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() {
+      if (VisualProperties == null) VisualProperties = new DataTableVisualProperties(name);
+      if (VisualProperties.Title == null) VisualProperties.Title = name;
+    }
+    #endregion
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new DataTable(this, cloner);
+    }
+
+    public event EventHandler VisualPropertiesChanged;
+    protected virtual void OnVisualPropertiesChanged() {
+      EventHandler handler = VisualPropertiesChanged;
+      if (handler != null) handler(this, EventArgs.Empty);
+    }
+
+    private void VisualProperties_PropertyChanged(object sender, PropertyChangedEventArgs e) {
+      OnVisualPropertiesChanged();
+    }
+
+    protected virtual 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.OnColumnsChanged();
+      this.OnColumnNamesChanged();
+      this.OnReset();
+    }
+    private void rows_ItemsRemoved(object sender, CollectionItemsChangedEventArgs<DataRow> e) {
+      foreach (DataRow row in e.Items)
+        this.DeregisterRowEvents(row);
+
+      this.OnColumnsChanged();
+      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.OnColumnsChanged();
+      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);
+
+      if (e.OldItems.Count() != e.Items.Count())
+        this.OnColumnsChanged();
+      this.OnColumnNamesChanged();
+      this.OnReset();
+    }
+
+    protected virtual 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);
+    }
+    protected virtual 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 Enumerable.Empty<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;
+    protected virtual 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;
+    protected virtual void OnReset() {
+      var handler = Reset;
+      if (handler != null) handler(this, EventArgs.Empty);
+    }
+    public event EventHandler ColumnsChanged;
+    protected virtual void OnColumnsChanged() {
+      var handler = ColumnsChanged;
+      if (handler != null) handler(this, EventArgs.Empty);
+    }
+    public event EventHandler RowsChanged;
+    protected virtual void OnRowsChanged() {
+      var handler = RowsChanged;
+      if (handler != null) handler(this, EventArgs.Empty);
+    }
+    public event EventHandler ColumnNamesChanged;
+    protected virtual void OnColumnNamesChanged() {
+      var handler = ColumnNamesChanged;
+      if (handler != null) handler(this, EventArgs.Empty);
+    }
+    public event EventHandler RowNamesChanged;
+    protected virtual void OnRowNamesChanged() {
+      var handler = RowNamesChanged;
+      if (handler != null) handler(this, EventArgs.Empty);
+    }
+    public event EventHandler SortableViewChanged;
+    protected virtual void OnSortableViewChanged() {
+      var handler = SortableViewChanged;
+      if (handler != null) handler(this, EventArgs.Empty);
+    }
+    #endregion
+  }
+}
Index: branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/DataVisualization/DataTableHistory.cs
===================================================================
--- branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/DataVisualization/DataTableHistory.cs	(revision 9280)
+++ branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/DataVisualization/DataTableHistory.cs	(revision 9280)
@@ -0,0 +1,49 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 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 static new Image StaticItemImage {
+      get { return HeuristicLab.Common.Resources.VSImageLibrary.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: branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/DataVisualization/DataTableValuesCollector.cs
===================================================================
--- branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/DataVisualization/DataTableValuesCollector.cs	(revision 9280)
+++ branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/DataVisualization/DataTableValuesCollector.cs	(revision 9280)
@@ -0,0 +1,135 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 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"]; }
+    }
+    private IFixedValueParameter<BoolValue> StartIndexZeroParameter {
+      get { return (FixedValueParameter<BoolValue>)Parameters["StartIndexZero"]; }
+    }
+
+    public bool StartIndexZero {
+      get { return StartIndexZeroParameter.Value.Value; }
+      set { StartIndexZeroParameter.Value.Value = value; }
+    }
+
+    #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."));
+      Parameters.Add(new FixedValueParameter<BoolValue>("StartIndexZero", "True, if the collected data values should start with index 0, otherwise false.", new BoolValue(true), false));
+      StartIndexZeroParameter.Hidden = true;
+    }
+
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() {
+      // BackwardsCompatibility3.3
+      #region Backwards compatible code (remove with 3.4)
+      if (!Parameters.ContainsKey("StartIndexZero")) {
+        Parameters.Add(new FixedValueParameter<BoolValue>("StartIndexZero", "True, if the collected data values should start with index 0, otherwise false.", new BoolValue(true), false));
+        StartIndexZeroParameter.Hidden = true;
+      }
+      #endregion
+    }
+
+    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.VisualProperties.StartIndexZero = StartIndexZero;
+        row.Values.Add(data);
+        table.Rows.Add(row);
+      } else {
+        row.Values.Add(data);
+      }
+    }
+  }
+}
Index: branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/DataVisualization/DataTableVisualProperties.cs
===================================================================
--- branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/DataVisualization/DataTableVisualProperties.cs	(revision 9280)
+++ branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/DataVisualization/DataTableVisualProperties.cs	(revision 9280)
@@ -0,0 +1,621 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 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.Persistence.Default.CompositeSerializers.Storable;
+using System.ComponentModel;
+using System.Drawing;
+
+namespace HeuristicLab.Analysis {
+  /// <summary>
+  /// Visual properties of a DataTable.
+  /// </summary>
+  [StorableClass]
+  public class DataTableVisualProperties : DeepCloneable, INotifyPropertyChanged {
+    private Font titleFont;
+    public Font TitleFont {
+      get { return titleFont; }
+      set {
+        if (titleFont == null || value == null
+          || titleFont.Name != value.Name || titleFont.Size != value.Size || titleFont.Style != value.Style) {
+          titleFont = value;
+          OnPropertyChanged("TitleFont");
+        }
+      }
+    }
+    private Color titleColor;
+    public Color TitleColor {
+      get { return titleColor; }
+      set {
+        if (titleColor != value) {
+          titleColor = value;
+          OnPropertyChanged("TitleFontColor");
+        }
+      }
+    }
+    private string title;
+    public string Title {
+      get { return title; }
+      set {
+        if (title != value) {
+          title = value;
+          OnPropertyChanged("Title");
+        }
+      }
+    }
+    private Font axisTitleFont;
+    public Font AxisTitleFont {
+      get { return axisTitleFont; }
+      set {
+        if (axisTitleFont == null || axisTitleFont == null
+          || axisTitleFont.Name != value.Name || axisTitleFont.Size != value.Size || axisTitleFont.Style != value.Style) {
+          axisTitleFont = value;
+          OnPropertyChanged("AxisTitleFont");
+        }
+      }
+    }
+    private Color axisTitleColor;
+    public Color AxisTitleColor {
+      get { return axisTitleColor; }
+      set {
+        if (axisTitleColor != value) {
+          axisTitleColor = value;
+          OnPropertyChanged("AxisTitleColor");
+        }
+      }
+    }
+    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 secondXAxisTitle;
+    public string SecondXAxisTitle {
+      get { return secondXAxisTitle; }
+      set {
+        if (value == null) value = string.Empty;
+        if (secondXAxisTitle != value) {
+          secondXAxisTitle = value;
+          OnPropertyChanged("SecondXAxisTitle");
+        }
+      }
+    }
+
+    private string secondYAxisTitle;
+    public string SecondYAxisTitle {
+      get { return secondYAxisTitle; }
+      set {
+        if (value == null) value = string.Empty;
+        if (secondYAxisTitle != value) {
+          secondYAxisTitle = value;
+          OnPropertyChanged("SecondYAxisTitle");
+        }
+      }
+    }
+
+    private bool xAxisMinimumAuto;
+    public bool XAxisMinimumAuto {
+      get { return xAxisMinimumAuto; }
+      set {
+        if (xAxisMinimumAuto != value) {
+          xAxisMinimumAuto = value;
+          if (value) xAxisMinimumFixedValue = double.NaN;
+          OnPropertyChanged("XAxisMinimumAuto");
+        }
+      }
+    }
+
+    private bool xAxisMaximumAuto;
+    public bool XAxisMaximumAuto {
+      get { return xAxisMaximumAuto; }
+      set {
+        if (xAxisMaximumAuto != value) {
+          xAxisMaximumAuto = value;
+          if (value) xAxisMaximumFixedValue = double.NaN;
+          OnPropertyChanged("XAxisMaximumAuto");
+        }
+      }
+    }
+
+    private double xAxisMinimumFixedValue;
+    public double XAxisMinimumFixedValue {
+      get { return xAxisMinimumFixedValue; }
+      set {
+        if (xAxisMinimumFixedValue != value) {
+          xAxisMinimumFixedValue = value;
+          OnPropertyChanged("XAxisMinimumFixedValue");
+        }
+      }
+    }
+
+    private double xAxisMaximumFixedValue;
+    public double XAxisMaximumFixedValue {
+      get { return xAxisMaximumFixedValue; }
+      set {
+        if (xAxisMaximumFixedValue != value) {
+          xAxisMaximumFixedValue = value;
+          OnPropertyChanged("XAxisMaximumFixedValue");
+        }
+      }
+    }
+
+    private bool secondXAxisMinimumAuto;
+    public bool SecondXAxisMinimumAuto {
+      get { return secondXAxisMinimumAuto; }
+      set {
+        if (secondXAxisMinimumAuto != value) {
+          secondXAxisMinimumAuto = value;
+          if (value) secondXAxisMinimumFixedValue = double.NaN;
+          OnPropertyChanged("SecondXAxisMinimumAuto");
+        }
+      }
+    }
+
+    private bool secondXAxisMaximumAuto;
+    public bool SecondXAxisMaximumAuto {
+      get { return secondXAxisMaximumAuto; }
+      set {
+        if (secondXAxisMaximumAuto != value) {
+          secondXAxisMaximumAuto = value;
+          if (value) secondXAxisMaximumFixedValue = double.NaN;
+          OnPropertyChanged("SecondXAxisMaximumAuto");
+        }
+      }
+    }
+
+    private double secondXAxisMinimumFixedValue;
+    public double SecondXAxisMinimumFixedValue {
+      get { return secondXAxisMinimumFixedValue; }
+      set {
+        if (secondXAxisMinimumFixedValue != value) {
+          secondXAxisMinimumFixedValue = value;
+          OnPropertyChanged("SecondXAxisMinimumFixedValue");
+        }
+      }
+    }
+
+    private double secondXAxisMaximumFixedValue;
+    public double SecondXAxisMaximumFixedValue {
+      get { return secondXAxisMaximumFixedValue; }
+      set {
+        if (secondXAxisMaximumFixedValue != value) {
+          secondXAxisMaximumFixedValue = value;
+          OnPropertyChanged("SecondXAxisMaximumFixedValue");
+        }
+      }
+    }
+
+    private bool yAxisMinimumAuto;
+    public bool YAxisMinimumAuto {
+      get { return yAxisMinimumAuto; }
+      set {
+        if (yAxisMinimumAuto != value) {
+          yAxisMinimumAuto = value;
+          if (value) yAxisMinimumFixedValue = double.NaN;
+          OnPropertyChanged("YAxisMinimumAuto");
+        }
+      }
+    }
+
+    private bool yAxisMaximumAuto;
+    public bool YAxisMaximumAuto {
+      get { return yAxisMaximumAuto; }
+      set {
+        if (yAxisMaximumAuto != value) {
+          yAxisMaximumAuto = value;
+          if (value) yAxisMaximumFixedValue = double.NaN;
+          OnPropertyChanged("YAxisMaximumAuto");
+        }
+      }
+    }
+
+    private double yAxisMinimumFixedValue;
+    public double YAxisMinimumFixedValue {
+      get { return yAxisMinimumFixedValue; }
+      set {
+        if (yAxisMinimumFixedValue != value) {
+          yAxisMinimumFixedValue = value;
+          OnPropertyChanged("YAxisMinimumFixedValue");
+        }
+      }
+    }
+
+    private double yAxisMaximumFixedValue;
+    public double YAxisMaximumFixedValue {
+      get { return yAxisMaximumFixedValue; }
+      set {
+        if (yAxisMaximumFixedValue != value) {
+          yAxisMaximumFixedValue = value;
+          OnPropertyChanged("YAxisMaximumFixedValue");
+        }
+      }
+    }
+
+    private bool secondYAxisMinimumAuto;
+    public bool SecondYAxisMinimumAuto {
+      get { return secondYAxisMinimumAuto; }
+      set {
+        if (secondYAxisMinimumAuto != value) {
+          secondYAxisMinimumAuto = value;
+          if (value) secondYAxisMinimumFixedValue = double.NaN;
+          OnPropertyChanged("SecondYAxisMinimumAuto");
+        }
+      }
+    }
+
+    private bool secondYAxisMaximumAuto;
+    public bool SecondYAxisMaximumAuto {
+      get { return secondYAxisMaximumAuto; }
+      set {
+        if (secondYAxisMaximumAuto != value) {
+          secondYAxisMaximumAuto = value;
+          if (value) secondYAxisMaximumFixedValue = double.NaN;
+          OnPropertyChanged("SecondYAxisMaximumAuto");
+        }
+      }
+    }
+
+    private double secondYAxisMinimumFixedValue;
+    public double SecondYAxisMinimumFixedValue {
+      get { return secondYAxisMinimumFixedValue; }
+      set {
+        if (secondYAxisMinimumFixedValue != value) {
+          secondYAxisMinimumFixedValue = value;
+          OnPropertyChanged("SecondYAxisMinimumFixedValue");
+        }
+      }
+    }
+
+    private double secondYAxisMaximumFixedValue;
+    public double SecondYAxisMaximumFixedValue {
+      get { return secondYAxisMaximumFixedValue; }
+      set {
+        if (secondYAxisMaximumFixedValue != value) {
+          secondYAxisMaximumFixedValue = value;
+          OnPropertyChanged("SecondYAxisMaximumFixedValue");
+        }
+      }
+    }
+
+    private bool xAxisLogScale;
+    public bool XAxisLogScale {
+      get { return xAxisLogScale; }
+      set {
+        if (xAxisLogScale == value) return;
+        xAxisLogScale = value;
+        OnPropertyChanged("XAxisLogScale");
+      }
+    }
+
+    private bool secondXAxisLogScale;
+    public bool SecondXAxisLogScale {
+      get { return secondXAxisLogScale; }
+      set {
+        if (secondXAxisLogScale == value) return;
+        secondXAxisLogScale = value;
+        OnPropertyChanged("SecondXAxisLogScale");
+      }
+    }
+
+    private bool yAxisLogScale;
+    public bool YAxisLogScale {
+      get { return yAxisLogScale; }
+      set {
+        if (yAxisLogScale == value) return;
+        yAxisLogScale = value;
+        OnPropertyChanged("YAxisLogScale");
+      }
+    }
+
+    private bool secondYAxisLogScale;
+    public bool SecondYAxisLogScale {
+      get { return secondYAxisLogScale; }
+      set {
+        if (secondYAxisLogScale == value) return;
+        secondYAxisLogScale = value;
+        OnPropertyChanged("SecondYAxisLogScale");
+      }
+    }
+
+    #region Persistence Properties
+    [Storable(Name = "TitleFont")]
+    private Font StorableTitleFont {
+      get { return titleFont; }
+      set { titleFont = value; }
+    }
+    [Storable(Name = "TitleColor")]
+    private Color StorableTitleColor {
+      get { return titleColor; }
+      set { titleColor = value; }
+    }
+    [Storable(Name = "Title")]
+    private string StorableTitle {
+      get { return title; }
+      set { title = value; }
+    }
+    [Storable(Name = "AxisTitleFont")]
+    private Font StorableAxisTitleFont {
+      get { return axisTitleFont; }
+      set { axisTitleFont = value; }
+    }
+    [Storable(Name = "AxisTitleColor")]
+    private Color StorableAxisTitleColor {
+      get { return axisTitleColor; }
+      set { axisTitleColor = value; }
+    }
+    [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 = "SecondXAxisTitle")]
+    private string StorableSecondXAxisTitle {
+      get { return secondXAxisTitle; }
+      set { secondXAxisTitle = value; }
+    }
+    [Storable(Name = "SecondYAxisTitle")]
+    private string StorableSecondYAxisTitle {
+      get { return secondYAxisTitle; }
+      set { secondYAxisTitle = value; }
+    }
+    [Storable(Name = "XAxisMinimumAuto")]
+    private bool StorableXAxisMinimumAuto {
+      get { return xAxisMinimumAuto; }
+      set { xAxisMinimumAuto = value; }
+    }
+    [Storable(Name = "XAxisMaximumAuto")]
+    private bool StorableXAxisMaximumAuto {
+      get { return xAxisMaximumAuto; }
+      set { xAxisMaximumAuto = value; }
+    }
+    [Storable(Name = "XAxisMinimumFixedValue")]
+    private double StorableXAxisMinimumFixedValue {
+      get { return xAxisMinimumFixedValue; }
+      set { xAxisMinimumFixedValue = value; }
+    }
+    [Storable(Name = "XAxisMaximumFixedValue")]
+    private double StorableXAxisMaximumFixedValue {
+      get { return xAxisMaximumFixedValue; }
+      set { xAxisMaximumFixedValue = value; }
+    }
+    [Storable(Name = "SecondXAxisMinimumAuto")]
+    private bool StorableSecondXAxisMinimumAuto {
+      get { return secondXAxisMinimumAuto; }
+      set { secondXAxisMinimumAuto = value; }
+    }
+    [Storable(Name = "SecondXAxisMaximumAuto")]
+    private bool StorableSecondXAxisMaximumAuto {
+      get { return secondXAxisMaximumAuto; }
+      set { secondXAxisMaximumAuto = value; }
+    }
+    [Storable(Name = "SecondXAxisMinimumFixedValue")]
+    private double StorableSecondXAxisMinimumFixedValue {
+      get { return secondXAxisMinimumFixedValue; }
+      set { secondXAxisMinimumFixedValue = value; }
+    }
+    [Storable(Name = "SecondXAxisMaximumFixedValue")]
+    private double StorableSecondXAxisMaximumFixedValue {
+      get { return secondXAxisMaximumFixedValue; }
+      set { secondXAxisMaximumFixedValue = value; }
+    }
+    [Storable(Name = "YAxisMinimumAuto")]
+    private bool StorableYAxisMinimumAuto {
+      get { return yAxisMinimumAuto; }
+      set { yAxisMinimumAuto = value; }
+    }
+    [Storable(Name = "YAxisMaximumAuto")]
+    private bool StorableYAxisMaximumAuto {
+      get { return yAxisMaximumAuto; }
+      set { yAxisMaximumAuto = value; }
+    }
+    [Storable(Name = "YAxisMinimumFixedValue")]
+    private double StorableYAxisMinimumFixedValue {
+      get { return yAxisMinimumFixedValue; }
+      set { yAxisMinimumFixedValue = value; }
+    }
+    [Storable(Name = "YAxisMaximumFixedValue")]
+    private double StorableYAxisMaximumFixedValue {
+      get { return yAxisMaximumFixedValue; }
+      set { yAxisMaximumFixedValue = value; }
+    }
+    [Storable(Name = "SecondYAxisMinimumAuto")]
+    private bool StorableSecondYAxisMinimumAuto {
+      get { return secondYAxisMinimumAuto; }
+      set { secondYAxisMinimumAuto = value; }
+    }
+    [Storable(Name = "SecondYAxisMaximumAuto")]
+    private bool StorableSecondYAxisMaximumAuto {
+      get { return secondYAxisMaximumAuto; }
+      set { secondYAxisMaximumAuto = value; }
+    }
+    [Storable(Name = "SecondYAxisMinimumFixedValue")]
+    private double StorableSecondYAxisMinimumFixedValue {
+      get { return secondYAxisMinimumFixedValue; }
+      set { secondYAxisMinimumFixedValue = value; }
+    }
+    [Storable(Name = "SecondYAxisMaximumFixedValue")]
+    private double StorableSecondYAxisMaximumFixedValue {
+      get { return secondYAxisMaximumFixedValue; }
+      set { secondYAxisMaximumFixedValue = value; }
+    }
+    [Storable(Name = "XAxisLogScale")]
+    private bool StorableXAxisLogScale {
+      get { return xAxisLogScale; }
+      set { xAxisLogScale = value; }
+    }
+    [Storable(Name = "SecondXAxisLogScale")]
+    private bool StorableSecondXAxisLogScale {
+      get { return secondXAxisLogScale; }
+      set { secondXAxisLogScale = value; }
+    }
+    [Storable(Name = "YAxisLogScale")]
+    private bool StorableYAxisLogScale {
+      get { return yAxisLogScale; }
+      set { yAxisLogScale = value; }
+    }
+    [Storable(Name = "SecondYAxisLogScale")]
+    private bool StorableSecondYAxisLogScale {
+      get { return secondYAxisLogScale; }
+      set { secondYAxisLogScale = value; }
+    }
+    #endregion
+
+    [StorableConstructor]
+    protected DataTableVisualProperties(bool deserializing) : base() { }
+    protected DataTableVisualProperties(DataTableVisualProperties original, Cloner cloner)
+      : base(original, cloner) {
+      if (original.titleFont != null)
+        this.titleFont = (Font)original.titleFont.Clone();
+      if (original.axisTitleFont != null)
+        this.axisTitleFont = (Font)original.axisTitleFont.Clone();
+      this.title = original.title;
+      this.xAxisTitle = original.xAxisTitle;
+      this.yAxisTitle = original.yAxisTitle;
+      this.secondXAxisTitle = original.secondXAxisTitle;
+      this.secondYAxisTitle = original.secondYAxisTitle;
+      this.xAxisMinimumAuto = original.xAxisMinimumAuto;
+      this.xAxisMinimumFixedValue = original.xAxisMinimumFixedValue;
+      this.xAxisMaximumAuto = original.xAxisMaximumAuto;
+      this.xAxisMaximumFixedValue = original.xAxisMaximumFixedValue;
+      this.secondXAxisMinimumAuto = original.secondXAxisMinimumAuto;
+      this.secondXAxisMinimumFixedValue = original.secondXAxisMinimumFixedValue;
+      this.secondXAxisMaximumAuto = original.secondXAxisMaximumAuto;
+      this.secondXAxisMaximumFixedValue = original.secondXAxisMaximumFixedValue;
+      this.yAxisMinimumAuto = original.yAxisMinimumAuto;
+      this.yAxisMinimumFixedValue = original.yAxisMinimumFixedValue;
+      this.yAxisMaximumAuto = original.yAxisMaximumAuto;
+      this.yAxisMaximumFixedValue = original.yAxisMaximumFixedValue;
+      this.secondYAxisMinimumAuto = original.secondYAxisMinimumAuto;
+      this.secondYAxisMinimumFixedValue = original.secondYAxisMinimumFixedValue;
+      this.secondYAxisMaximumAuto = original.secondYAxisMaximumAuto;
+      this.secondYAxisMaximumFixedValue = original.secondYAxisMaximumFixedValue;
+      this.xAxisLogScale = original.xAxisLogScale;
+      this.secondXAxisLogScale = original.secondXAxisLogScale;
+      this.yAxisLogScale = original.yAxisLogScale;
+      this.secondYAxisLogScale = original.secondYAxisLogScale;
+    }
+    public DataTableVisualProperties() {
+      this.titleColor = Color.Black;
+      this.axisTitleColor = Color.Black;
+      this.title = string.Empty;
+      this.xAxisTitle = string.Empty;
+      this.yAxisTitle = string.Empty;
+      this.secondXAxisTitle = string.Empty;
+      this.secondYAxisTitle = string.Empty;
+      this.xAxisMinimumAuto = true;
+      this.xAxisMinimumFixedValue = double.NaN;
+      this.xAxisMaximumAuto = true;
+      this.xAxisMaximumFixedValue = double.NaN;
+      this.secondXAxisMinimumAuto = true;
+      this.secondXAxisMinimumFixedValue = double.NaN;
+      this.secondXAxisMaximumAuto = true;
+      this.secondXAxisMaximumFixedValue = double.NaN;
+      this.yAxisMinimumAuto = true;
+      this.yAxisMinimumFixedValue = double.NaN;
+      this.yAxisMaximumAuto = true;
+      this.yAxisMaximumFixedValue = double.NaN;
+      this.secondYAxisMinimumAuto = true;
+      this.secondYAxisMinimumFixedValue = double.NaN;
+      this.secondYAxisMaximumAuto = true;
+      this.secondYAxisMaximumFixedValue = double.NaN;
+      this.xAxisLogScale = false;
+      this.secondXAxisLogScale = false;
+      this.yAxisLogScale = false;
+      this.secondYAxisLogScale = false;
+    }
+    public DataTableVisualProperties(string title)
+      : this() {
+      this.title = title;
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new DataTableVisualProperties(this, cloner);
+    }
+
+    public event PropertyChangedEventHandler PropertyChanged;
+    protected virtual void OnPropertyChanged(string propertyName) {
+      var handler = PropertyChanged;
+      if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
+    }
+
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() {
+      // BackwardsCompatibility3.3
+      #region Backwards compatible code, remove with 3.4
+      // check if most of the properties that were added in Mai'11 were set to their default values, then we want to reset them to our default values
+      if (xAxisMinimumAuto == default(bool) && xAxisMaximumAuto == default(bool)
+        && yAxisMinimumAuto == default(bool) && yAxisMaximumAuto == default(bool)
+        && secondXAxisMinimumAuto == default(bool) && secondXAxisMaximumAuto == default(bool)
+        && secondYAxisMinimumAuto == default(bool) && secondYAxisMaximumAuto == default(bool)
+        && titleColor == default(Color) && axisTitleColor == default(Color)
+        && secondXAxisTitle == default(string)
+        && xAxisMinimumFixedValue == default(double) && xAxisMaximumFixedValue == default(double)
+        && yAxisMinimumFixedValue == default(double) && yAxisMaximumFixedValue == default(double)
+        && secondXAxisMinimumFixedValue == default(double) && secondXAxisMaximumFixedValue == default(double)
+        && secondYAxisMinimumFixedValue == default(double) && secondYAxisMaximumFixedValue == default(double)) {
+        titleColor = Color.Black;
+        axisTitleColor = Color.Black;
+        this.secondXAxisTitle = string.Empty;
+        this.xAxisMinimumAuto = true;
+        this.xAxisMinimumFixedValue = double.NaN;
+        this.xAxisMaximumAuto = true;
+        this.xAxisMaximumFixedValue = double.NaN;
+        this.secondXAxisMinimumAuto = true;
+        this.secondXAxisMinimumFixedValue = double.NaN;
+        this.secondXAxisMaximumAuto = true;
+        this.secondXAxisMaximumFixedValue = double.NaN;
+        this.yAxisMinimumAuto = true;
+        this.yAxisMinimumFixedValue = double.NaN;
+        this.yAxisMaximumAuto = true;
+        this.yAxisMaximumFixedValue = double.NaN;
+        this.secondYAxisMinimumAuto = true;
+        this.secondYAxisMinimumFixedValue = double.NaN;
+        this.secondYAxisMaximumAuto = true;
+        this.secondYAxisMaximumFixedValue = double.NaN;
+      }
+      #endregion
+    }
+  }
+}
Index: branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/DataVisualization/HeatMap.cs
===================================================================
--- branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/DataVisualization/HeatMap.cs	(revision 9280)
+++ branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/DataVisualization/HeatMap.cs	(revision 9280)
@@ -0,0 +1,159 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 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 static new Image StaticItemImage {
+      get { return HeuristicLab.Common.Resources.VSImageLibrary.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: branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/DataVisualization/HeatMapHistory.cs
===================================================================
--- branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/DataVisualization/HeatMapHistory.cs	(revision 9280)
+++ branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/DataVisualization/HeatMapHistory.cs	(revision 9280)
@@ -0,0 +1,49 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 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 static new Image StaticItemImage {
+      get { return HeuristicLab.Common.Resources.VSImageLibrary.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: branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/DataVisualization/ScatterPlot.cs
===================================================================
--- branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/DataVisualization/ScatterPlot.cs	(revision 9280)
+++ branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/DataVisualization/ScatterPlot.cs	(revision 9280)
@@ -0,0 +1,300 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 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 {
+  [Item("ScatterPlot", "A scatter plot of 2D data")]
+  [StorableClass]
+  public class ScatterPlot : NamedItem, IStringConvertibleMatrix {
+    public static new Image StaticItemImage {
+      get { return HeuristicLab.Common.Resources.VSImageLibrary.Performance; }
+    }
+
+    private ScatterPlotVisualProperties visualProperties;
+    public ScatterPlotVisualProperties 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<ScatterPlotDataRow> rows;
+    public NamedItemCollection<ScatterPlotDataRow> Rows {
+      get { return rows; }
+      private set {
+        if (rows != null) throw new InvalidOperationException("Rows already set");
+        rows = value;
+        if (rows != null) RegisterRowsEvents();
+      }
+    }
+
+    #region Persistence Properties
+    [Storable(Name = "VisualProperties")]
+    private ScatterPlotVisualProperties StorableVisualProperties {
+      get { return visualProperties; }
+      set {
+        visualProperties = value;
+        visualProperties.PropertyChanged += new PropertyChangedEventHandler(VisualProperties_PropertyChanged);
+      }
+    }
+    [Storable(Name = "Rows")]
+    private IEnumerable<ScatterPlotDataRow> StorableRows {
+      get { return rows; }
+      set { Rows = new NamedItemCollection<ScatterPlotDataRow>(value); }
+    }
+    #endregion
+
+    [StorableConstructor]
+    protected ScatterPlot(bool deserializing) : base(deserializing) { }
+    protected ScatterPlot(ScatterPlot original, Cloner cloner)
+      : base(original, cloner) {
+      VisualProperties = cloner.Clone(original.visualProperties);
+      Rows = cloner.Clone(original.rows);
+    }
+    public ScatterPlot()
+      : base() {
+      VisualProperties = new ScatterPlotVisualProperties();
+      Rows = new NamedItemCollection<ScatterPlotDataRow>();
+    }
+    public ScatterPlot(string name, string description)
+      : base(name, description) {
+      VisualProperties = new ScatterPlotVisualProperties(name);
+      Rows = new NamedItemCollection<ScatterPlotDataRow>();
+    }
+    public ScatterPlot(string name, string description, ScatterPlotVisualProperties visualProperties)
+      : base(name, description) {
+      VisualProperties = visualProperties;
+      Rows = new NamedItemCollection<ScatterPlotDataRow>();
+    }
+
+    // BackwardsCompatibility3.3
+    #region Backwards compatible code, remove with 3.4
+    private ObservableList<PointF> points;
+    [Storable(Name = "points", AllowOneWay = true)]
+    private ObservableList<PointF> StorablePoints {
+      set { points = value; }
+    }
+    private string xAxisName;
+    [Storable(Name = "xAxisName", AllowOneWay = true)]
+    private string StorableXAxisName {
+      set { xAxisName = value; }
+    }
+    private string yAxisName;
+    [Storable(Name = "yAxisName", AllowOneWay = true)]
+    private string StorableYAxisName {
+      set { yAxisName = value; }
+    }
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() {
+      if (VisualProperties == null) VisualProperties = new ScatterPlotVisualProperties(name);
+      if (string.IsNullOrEmpty(VisualProperties.XAxisTitle) && !string.IsNullOrEmpty(xAxisName)) VisualProperties.XAxisTitle = xAxisName;
+      if (string.IsNullOrEmpty(VisualProperties.YAxisTitle) && !string.IsNullOrEmpty(yAxisName)) VisualProperties.YAxisTitle = yAxisName;
+      if (rows == null) Rows = new NamedItemCollection<ScatterPlotDataRow>();
+      if ((Rows.Count == 0) && (points != null)) Rows.Add(new ScatterPlotDataRow(name, null, points.Select(p => new Point2D<double>(p.X, p.Y))));
+    }
+    #endregion
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new ScatterPlot(this, cloner);
+    }
+
+    public event EventHandler VisualPropertiesChanged;
+    protected virtual void OnVisualPropertiesChanged() {
+      EventHandler handler = VisualPropertiesChanged;
+      if (handler != null) handler(this, EventArgs.Empty);
+    }
+
+    private void VisualProperties_PropertyChanged(object sender, PropertyChangedEventArgs e) {
+      OnVisualPropertiesChanged();
+    }
+
+    protected virtual void RegisterRowsEvents() {
+      rows.ItemsAdded += new CollectionItemsChangedEventHandler<ScatterPlotDataRow>(rows_ItemsAdded);
+      rows.ItemsRemoved += new CollectionItemsChangedEventHandler<ScatterPlotDataRow>(rows_ItemsRemoved);
+      rows.ItemsReplaced += new CollectionItemsChangedEventHandler<ScatterPlotDataRow>(rows_ItemsReplaced);
+      rows.CollectionReset += new CollectionItemsChangedEventHandler<ScatterPlotDataRow>(rows_CollectionReset);
+    }
+    private void rows_ItemsAdded(object sender, CollectionItemsChangedEventArgs<ScatterPlotDataRow> e) {
+      foreach (ScatterPlotDataRow row in e.Items)
+        this.RegisterRowEvents(row);
+
+      this.OnColumnsChanged();
+      this.OnColumnNamesChanged();
+      this.OnReset();
+    }
+    private void rows_ItemsRemoved(object sender, CollectionItemsChangedEventArgs<ScatterPlotDataRow> e) {
+      foreach (ScatterPlotDataRow row in e.Items)
+        this.DeregisterRowEvents(row);
+
+      this.OnColumnsChanged();
+      this.OnColumnNamesChanged();
+      this.OnReset();
+    }
+    private void rows_ItemsReplaced(object sender, CollectionItemsChangedEventArgs<ScatterPlotDataRow> e) {
+      foreach (ScatterPlotDataRow row in e.OldItems)
+        this.DeregisterRowEvents(row);
+      foreach (ScatterPlotDataRow row in e.Items)
+        this.RegisterRowEvents(row);
+
+      this.OnColumnsChanged();
+      this.OnColumnNamesChanged();
+      this.OnReset();
+    }
+    private void rows_CollectionReset(object sender, CollectionItemsChangedEventArgs<ScatterPlotDataRow> e) {
+      foreach (ScatterPlotDataRow row in e.OldItems)
+        this.DeregisterRowEvents(row);
+      foreach (ScatterPlotDataRow row in e.Items)
+        this.RegisterRowEvents(row);
+
+      if (e.OldItems.Count() != e.Items.Count())
+        this.OnColumnsChanged();
+      this.OnColumnNamesChanged();
+      this.OnReset();
+    }
+
+    protected virtual void RegisterRowEvents(ScatterPlotDataRow row) {
+      row.Points.ItemsAdded += new CollectionItemsChangedEventHandler<IndexedItem<Point2D<double>>>(Points_ItemsAdded);
+      row.Points.ItemsMoved += new CollectionItemsChangedEventHandler<IndexedItem<Point2D<double>>>(Points_ItemsMoved);
+      row.Points.ItemsRemoved += new CollectionItemsChangedEventHandler<IndexedItem<Point2D<double>>>(Points_ItemsRemoved);
+      row.Points.ItemsReplaced += new CollectionItemsChangedEventHandler<IndexedItem<Point2D<double>>>(Points_ItemsReplaced);
+      row.Points.CollectionReset += new CollectionItemsChangedEventHandler<IndexedItem<Point2D<double>>>(Points_CollectionReset);
+    }
+    protected virtual void DeregisterRowEvents(ScatterPlotDataRow row) {
+      row.Points.ItemsAdded -= new CollectionItemsChangedEventHandler<IndexedItem<Point2D<double>>>(Points_ItemsAdded);
+      row.Points.ItemsMoved -= new CollectionItemsChangedEventHandler<IndexedItem<Point2D<double>>>(Points_ItemsMoved);
+      row.Points.ItemsRemoved -= new CollectionItemsChangedEventHandler<IndexedItem<Point2D<double>>>(Points_ItemsRemoved);
+      row.Points.ItemsReplaced -= new CollectionItemsChangedEventHandler<IndexedItem<Point2D<double>>>(Points_ItemsReplaced);
+      row.Points.CollectionReset -= new CollectionItemsChangedEventHandler<IndexedItem<Point2D<double>>>(Points_CollectionReset);
+    }
+
+    private void Points_ItemsAdded(object sender, CollectionItemsChangedEventArgs<IndexedItem<Point2D<double>>> e) {
+      this.OnReset();
+    }
+    private void Points_ItemsMoved(object sender, CollectionItemsChangedEventArgs<IndexedItem<Point2D<double>>> e) {
+      this.OnReset();
+    }
+    private void Points_ItemsRemoved(object sender, CollectionItemsChangedEventArgs<IndexedItem<Point2D<double>>> e) {
+      this.OnReset();
+    }
+    private void Points_ItemsReplaced(object sender, CollectionItemsChangedEventArgs<IndexedItem<Point2D<double>>> e) {
+      this.OnReset();
+    }
+    private void Points_CollectionReset(object sender, CollectionItemsChangedEventArgs<IndexedItem<Point2D<double>>> e) {
+      this.OnReset();
+    }
+
+    #region IStringConvertibleMatrix Members
+    int IStringConvertibleMatrix.Rows {
+      get { return rows.Count == 0 ? 0 : rows.Max(r => r.Points.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 Enumerable.Empty<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].Points.Count)
+          return string.Format("{0};{1}", rows[columnName].Points[rowIndex].X, rows[columnName].Points[rowIndex].Y);
+      }
+      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;
+    protected virtual 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;
+    protected virtual void OnReset() {
+      var handler = Reset;
+      if (handler != null) handler(this, EventArgs.Empty);
+    }
+    public event EventHandler ColumnsChanged;
+    protected virtual void OnColumnsChanged() {
+      var handler = ColumnsChanged;
+      if (handler != null) handler(this, EventArgs.Empty);
+    }
+    public event EventHandler RowsChanged;
+    protected virtual void OnRowsChanged() {
+      var handler = RowsChanged;
+      if (handler != null) handler(this, EventArgs.Empty);
+    }
+    public event EventHandler ColumnNamesChanged;
+    protected virtual void OnColumnNamesChanged() {
+      var handler = ColumnNamesChanged;
+      if (handler != null) handler(this, EventArgs.Empty);
+    }
+    public event EventHandler RowNamesChanged;
+    protected virtual void OnRowNamesChanged() {
+      var handler = RowNamesChanged;
+      if (handler != null) handler(this, EventArgs.Empty);
+    }
+    public event EventHandler SortableViewChanged;
+    protected virtual void OnSortableViewChanged() {
+      var handler = SortableViewChanged;
+      if (handler != null) handler(this, EventArgs.Empty);
+    }
+    #endregion
+  }
+}
Index: branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/DataVisualization/ScatterPlotDataRow.cs
===================================================================
--- branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/DataVisualization/ScatterPlotDataRow.cs	(revision 9280)
+++ branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/DataVisualization/ScatterPlotDataRow.cs	(revision 9280)
@@ -0,0 +1,108 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 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 for a scatter plot.
+  /// </summary>
+  [Item("ScatterPlotDataRow", "A row of data values for a scatter plot.")]
+  [StorableClass]
+  public class ScatterPlotDataRow : NamedItem {
+    private ScatterPlotDataRowVisualProperties visualProperties;
+    public ScatterPlotDataRowVisualProperties 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<Point2D<double>> points;
+    public ObservableList<Point2D<double>> Points {
+      get { return points; }
+    }
+
+    #region Persistence Properties
+    [Storable(Name = "VisualProperties")]
+    private ScatterPlotDataRowVisualProperties StorableVisualProperties {
+      get { return visualProperties; }
+      set {
+        visualProperties = value;
+        visualProperties.PropertyChanged += new PropertyChangedEventHandler(VisualProperties_PropertyChanged);
+      }
+    }
+    [Storable(Name = "Points")]
+    private IEnumerable<Point2D<double>> StorablePoints {
+      get { return points; }
+      set { points = new ObservableList<Point2D<double>>(value); }
+    }
+    #endregion
+
+    [StorableConstructor]
+    protected ScatterPlotDataRow(bool deserializing) : base(deserializing) { }
+    protected ScatterPlotDataRow(ScatterPlotDataRow original, Cloner cloner)
+      : base(original, cloner) {
+      VisualProperties = cloner.Clone(original.visualProperties);
+      points = new ObservableList<Point2D<double>>(original.points);
+    }
+    public ScatterPlotDataRow()
+      : base() {
+      VisualProperties = new ScatterPlotDataRowVisualProperties();
+      points = new ObservableList<Point2D<double>>();
+    }
+    public ScatterPlotDataRow(string name, string description, IEnumerable<Point2D<double>> points)
+      : base(name, description) {
+      VisualProperties = new ScatterPlotDataRowVisualProperties(name);
+      this.points = new ObservableList<Point2D<double>>(points);
+    }
+    public ScatterPlotDataRow(string name, string description, IEnumerable<Point2D<double>> points, ScatterPlotDataRowVisualProperties visualProperties)
+      : base(name, description) {
+      VisualProperties = visualProperties;
+      this.points = new ObservableList<Point2D<double>>(points);
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new ScatterPlotDataRow(this, cloner);
+    }
+
+    public event EventHandler VisualPropertiesChanged;
+    protected virtual void OnVisualPropertiesChanged() {
+      EventHandler handler = VisualPropertiesChanged;
+      if (handler != null) handler(this, EventArgs.Empty);
+    }
+
+    private void VisualProperties_PropertyChanged(object sender, PropertyChangedEventArgs e) {
+      OnVisualPropertiesChanged();
+    }
+  }
+}
Index: branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/DataVisualization/ScatterPlotDataRowVisualProperties.cs
===================================================================
--- branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/DataVisualization/ScatterPlotDataRowVisualProperties.cs	(revision 9280)
+++ branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/DataVisualization/ScatterPlotDataRowVisualProperties.cs	(revision 9280)
@@ -0,0 +1,164 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 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.ComponentModel;
+using System.Drawing;
+using HeuristicLab.Common;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Analysis {
+  /// <summary>
+  /// Visual properties of a ScatterPlotDataRow.
+  /// </summary>
+  [StorableClass]
+  public class ScatterPlotDataRowVisualProperties : DeepCloneable, INotifyPropertyChanged {
+    #region PointStyle
+    public enum ScatterPlotDataRowPointStyle {
+      Circle,
+      Cross,
+      Diamond,
+      Square,
+      Star4,
+      Star5,
+      Star6,
+      Star10,
+      Triangle
+    }
+    #endregion
+
+    private Color color;
+    public Color Color {
+      get { return color; }
+      set {
+        if (color != value) {
+          color = value;
+          OnPropertyChanged("Color");
+        }
+      }
+    }
+    private ScatterPlotDataRowPointStyle pointStyle;
+    public ScatterPlotDataRowPointStyle PointStyle {
+      get { return pointStyle; }
+      set {
+        if (pointStyle != value) {
+          pointStyle = value;
+          OnPropertyChanged("PointStyle");
+        }
+      }
+    }
+    private int pointSize;
+    public int PointSize {
+      get { return pointSize; }
+      set {
+        if (pointSize != value) {
+          pointSize = value;
+          OnPropertyChanged("PointSize");
+        }
+      }
+    }
+    private bool isVisibleInLegend;
+    public bool IsVisibleInLegend {
+      get { return isVisibleInLegend; }
+      set {
+        if (isVisibleInLegend != value) {
+          isVisibleInLegend = value;
+          OnPropertyChanged("IsVisibleInLegend");
+        }
+      }
+    }
+    private string displayName;
+    public string DisplayName {
+      get { return displayName == null ? String.Empty : displayName; }
+      set {
+        if (displayName != value) {
+          if (value == null && displayName != String.Empty) {
+            displayName = String.Empty;
+            OnPropertyChanged("DisplayName");
+          } else if (value != null) {
+            displayName = value;
+            OnPropertyChanged("DisplayName");
+          }
+        }
+      }
+    }
+
+    #region Persistence Properties
+    [Storable(Name = "Color")]
+    private Color StorableColor {
+      get { return color; }
+      set { color = value; }
+    }
+    [Storable(Name = "PointStyle")]
+    private ScatterPlotDataRowPointStyle StorablePointStyle {
+      get { return pointStyle; }
+      set { pointStyle = value; }
+    }
+    [Storable(Name = "PointSize")]
+    private int StorablePointSize {
+      get { return pointSize; }
+      set { pointSize = value; }
+    }
+    [Storable(Name = "IsVisibleInLegend")]
+    private bool StorableIsVisibleInLegend {
+      get { return isVisibleInLegend; }
+      set { isVisibleInLegend = value; }
+    }
+    [Storable(Name = "DisplayName")]
+    private string StorableDisplayName {
+      get { return displayName; }
+      set { displayName = value; }
+    }
+    #endregion
+
+    [StorableConstructor]
+    protected ScatterPlotDataRowVisualProperties(bool deserializing) : base() { }
+    protected ScatterPlotDataRowVisualProperties(ScatterPlotDataRowVisualProperties original, Cloner cloner)
+      : base(original, cloner) {
+      this.color = original.color;
+      this.pointStyle = original.pointStyle;
+      this.pointSize = original.pointSize;
+      this.displayName = original.displayName;
+      this.isVisibleInLegend = original.isVisibleInLegend;
+    }
+    public ScatterPlotDataRowVisualProperties() {
+      color = Color.Empty;
+      pointStyle = ScatterPlotDataRowPointStyle.Circle;
+      pointSize = 3;
+      displayName = String.Empty;
+      isVisibleInLegend = true;
+    }
+    public ScatterPlotDataRowVisualProperties(string displayName)
+      : this() {
+      this.displayName = displayName;
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new ScatterPlotDataRowVisualProperties(this, cloner);
+    }
+
+    public event PropertyChangedEventHandler PropertyChanged;
+    protected virtual void OnPropertyChanged(string propertyName) {
+      PropertyChangedEventHandler handler = PropertyChanged;
+      if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
+    }
+  }
+}
Index: branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/DataVisualization/ScatterPlotHistory.cs
===================================================================
--- branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/DataVisualization/ScatterPlotHistory.cs	(revision 9280)
+++ branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/DataVisualization/ScatterPlotHistory.cs	(revision 9280)
@@ -0,0 +1,49 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 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 scatter plots.
+  /// </summary>
+  [Item("ScatterPlotHistory", "Represents history values of scatter plots.")]
+  [StorableClass]
+  public class ScatterPlotHistory : ItemCollection<ScatterPlot> {
+    public static new Image StaticItemImage {
+      get { return HeuristicLab.Common.Resources.VSImageLibrary.Cab; }
+    }
+
+    [StorableConstructor]
+    protected ScatterPlotHistory(bool deserializing) : base(deserializing) { }
+    protected ScatterPlotHistory(ScatterPlotHistory original, Cloner cloner) : base(original, cloner) { }
+    public ScatterPlotHistory() : base() { }
+    public ScatterPlotHistory(IEnumerable<ScatterPlot> scatterPlots) : base(new ItemCollection<ScatterPlot>(scatterPlots)) { }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new ScatterPlotHistory(this, cloner);
+    }
+  }
+}
Index: branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/DataVisualization/ScatterPlotVisualProperties.cs
===================================================================
--- branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/DataVisualization/ScatterPlotVisualProperties.cs	(revision 9280)
+++ branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/DataVisualization/ScatterPlotVisualProperties.cs	(revision 9280)
@@ -0,0 +1,365 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 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 ScatterPlot.
+  /// </summary>
+  [StorableClass]
+  public class ScatterPlotVisualProperties : DeepCloneable, INotifyPropertyChanged {
+    private Font titleFont;
+    public Font TitleFont {
+      get { return titleFont; }
+      set {
+        if (titleFont == null || value == null
+          || titleFont.Name != value.Name || titleFont.Size != value.Size || titleFont.Style != value.Style) {
+          titleFont = value;
+          OnPropertyChanged("TitleFont");
+        }
+      }
+    }
+    private Color titleColor;
+    public Color TitleColor {
+      get { return titleColor; }
+      set {
+        if (titleColor != value) {
+          titleColor = value;
+          OnPropertyChanged("TitleFontColor");
+        }
+      }
+    }
+    private string title;
+    public string Title {
+      get { return title; }
+      set {
+        if (title != value) {
+          title = value;
+          OnPropertyChanged("Title");
+        }
+      }
+    }
+    private Font axisTitleFont;
+    public Font AxisTitleFont {
+      get { return axisTitleFont; }
+      set {
+        if (axisTitleFont == null || axisTitleFont == null
+          || axisTitleFont.Name != value.Name || axisTitleFont.Size != value.Size || axisTitleFont.Style != value.Style) {
+          axisTitleFont = value;
+          OnPropertyChanged("AxisTitleFont");
+        }
+      }
+    }
+    private Color axisTitleColor;
+    public Color AxisTitleColor {
+      get { return axisTitleColor; }
+      set {
+        if (axisTitleColor != value) {
+          axisTitleColor = value;
+          OnPropertyChanged("AxisTitleColor");
+        }
+      }
+    }
+    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 bool xAxisGrid;
+    public bool XAxisGrid {
+      get { return xAxisGrid; }
+      set {
+        if (xAxisGrid != value) {
+          xAxisGrid = value;
+          OnPropertyChanged("XAxisGrid");
+        }
+      }
+    }
+
+    private bool yAxisGrid;
+    public bool YAxisGrid {
+      get { return yAxisGrid; }
+      set {
+        if (yAxisGrid != value) {
+          yAxisGrid = value;
+          OnPropertyChanged("YAxisGrid");
+        }
+      }
+    }
+
+    private bool xAxisMinimumAuto;
+    public bool XAxisMinimumAuto {
+      get { return xAxisMinimumAuto; }
+      set {
+        if (xAxisMinimumAuto != value) {
+          xAxisMinimumAuto = value;
+          if (value) xAxisMinimumFixedValue = double.NaN;
+          OnPropertyChanged("XAxisMinimumAuto");
+        }
+      }
+    }
+
+    private bool xAxisMaximumAuto;
+    public bool XAxisMaximumAuto {
+      get { return xAxisMaximumAuto; }
+      set {
+        if (xAxisMaximumAuto != value) {
+          xAxisMaximumAuto = value;
+          if (value) xAxisMaximumFixedValue = double.NaN;
+          OnPropertyChanged("XAxisMaximumAuto");
+        }
+      }
+    }
+
+    private double xAxisMinimumFixedValue;
+    public double XAxisMinimumFixedValue {
+      get { return xAxisMinimumFixedValue; }
+      set {
+        if (xAxisMinimumFixedValue != value) {
+          xAxisMinimumFixedValue = value;
+          OnPropertyChanged("XAxisMinimumFixedValue");
+        }
+      }
+    }
+
+    private double xAxisMaximumFixedValue;
+    public double XAxisMaximumFixedValue {
+      get { return xAxisMaximumFixedValue; }
+      set {
+        if (xAxisMaximumFixedValue != value) {
+          xAxisMaximumFixedValue = value;
+          OnPropertyChanged("XAxisMaximumFixedValue");
+        }
+      }
+    }
+
+    private bool yAxisMinimumAuto;
+    public bool YAxisMinimumAuto {
+      get { return yAxisMinimumAuto; }
+      set {
+        if (yAxisMinimumAuto != value) {
+          yAxisMinimumAuto = value;
+          if (value) yAxisMinimumFixedValue = double.NaN;
+          OnPropertyChanged("YAxisMinimumAuto");
+        }
+      }
+    }
+
+    private bool yAxisMaximumAuto;
+    public bool YAxisMaximumAuto {
+      get { return yAxisMaximumAuto; }
+      set {
+        if (yAxisMaximumAuto != value) {
+          yAxisMaximumAuto = value;
+          if (value) yAxisMaximumFixedValue = double.NaN;
+          OnPropertyChanged("YAxisMaximumAuto");
+        }
+      }
+    }
+
+    private double yAxisMinimumFixedValue;
+    public double YAxisMinimumFixedValue {
+      get { return yAxisMinimumFixedValue; }
+      set {
+        if (yAxisMinimumFixedValue != value) {
+          yAxisMinimumFixedValue = value;
+          OnPropertyChanged("YAxisMinimumFixedValue");
+        }
+      }
+    }
+
+    private double yAxisMaximumFixedValue;
+    public double YAxisMaximumFixedValue {
+      get { return yAxisMaximumFixedValue; }
+      set {
+        if (yAxisMaximumFixedValue != value) {
+          yAxisMaximumFixedValue = value;
+          OnPropertyChanged("YAxisMaximumFixedValue");
+        }
+      }
+    }
+
+    #region Persistence Properties
+    [Storable(Name = "TitleFont")]
+    private Font StorableTitleFont {
+      get { return titleFont; }
+      set { titleFont = value; }
+    }
+    [Storable(Name = "TitleColor")]
+    private Color StorableTitleColor {
+      get { return titleColor; }
+      set { titleColor = value; }
+    }
+    [Storable(Name = "Title")]
+    private string StorableTitle {
+      get { return title; }
+      set { title = value; }
+    }
+    [Storable(Name = "AxisTitleFont")]
+    private Font StorableAxisTitleFont {
+      get { return axisTitleFont; }
+      set { axisTitleFont = value; }
+    }
+    [Storable(Name = "AxisTitleColor")]
+    private Color StorableAxisTitleColor {
+      get { return axisTitleColor; }
+      set { axisTitleColor = value; }
+    }
+    [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 = "XAxisGrid")]
+    private bool StorableXAxisGrid {
+      get { return xAxisGrid; }
+      set { xAxisGrid = value; }
+    }
+    [Storable(Name = "YAxisGrid")]
+    private bool StorableYAxisGrid {
+      get { return yAxisGrid; }
+      set { yAxisGrid = value; }
+    }
+    [Storable(Name = "XAxisMinimumAuto")]
+    private bool StorableXAxisMinimumAuto {
+      get { return xAxisMinimumAuto; }
+      set { xAxisMinimumAuto = value; }
+    }
+    [Storable(Name = "XAxisMaximumAuto")]
+    private bool StorableXAxisMaximumAuto {
+      get { return xAxisMaximumAuto; }
+      set { xAxisMaximumAuto = value; }
+    }
+    [Storable(Name = "XAxisMinimumFixedValue")]
+    private double StorableXAxisMinimumFixedValue {
+      get { return xAxisMinimumFixedValue; }
+      set { xAxisMinimumFixedValue = value; }
+    }
+    [Storable(Name = "XAxisMaximumFixedValue")]
+    private double StorableXAxisMaximumFixedValue {
+      get { return xAxisMaximumFixedValue; }
+      set { xAxisMaximumFixedValue = value; }
+    }
+    [Storable(Name = "YAxisMinimumAuto")]
+    private bool StorableYAxisMinimumAuto {
+      get { return yAxisMinimumAuto; }
+      set { yAxisMinimumAuto = value; }
+    }
+    [Storable(Name = "YAxisMaximumAuto")]
+    private bool StorableYAxisMaximumAuto {
+      get { return yAxisMaximumAuto; }
+      set { yAxisMaximumAuto = value; }
+    }
+    [Storable(Name = "YAxisMinimumFixedValue")]
+    private double StorableYAxisMinimumFixedValue {
+      get { return yAxisMinimumFixedValue; }
+      set { yAxisMinimumFixedValue = value; }
+    }
+    [Storable(Name = "YAxisMaximumFixedValue")]
+    private double StorableYAxisMaximumFixedValue {
+      get { return yAxisMaximumFixedValue; }
+      set { yAxisMaximumFixedValue = value; }
+    }
+    #endregion
+
+    [StorableConstructor]
+    protected ScatterPlotVisualProperties(bool deserializing) : base() { }
+    protected ScatterPlotVisualProperties(ScatterPlotVisualProperties original, Cloner cloner)
+      : base(original, cloner) {
+      if (original.titleFont != null)
+        this.titleFont = (Font)original.titleFont.Clone();
+      if (original.axisTitleFont != null)
+        this.axisTitleFont = (Font)original.axisTitleFont.Clone();
+      this.title = original.title;
+      this.xAxisTitle = original.xAxisTitle;
+      this.yAxisTitle = original.yAxisTitle;
+      this.xAxisGrid = original.xAxisGrid;
+      this.yAxisGrid = original.yAxisGrid;
+      this.xAxisMinimumAuto = original.xAxisMinimumAuto;
+      this.xAxisMinimumFixedValue = original.xAxisMinimumFixedValue;
+      this.xAxisMaximumAuto = original.xAxisMaximumAuto;
+      this.xAxisMaximumFixedValue = original.xAxisMaximumFixedValue;
+      this.yAxisMinimumAuto = original.yAxisMinimumAuto;
+      this.yAxisMinimumFixedValue = original.yAxisMinimumFixedValue;
+      this.yAxisMaximumAuto = original.yAxisMaximumAuto;
+      this.yAxisMaximumFixedValue = original.yAxisMaximumFixedValue;
+    }
+    public ScatterPlotVisualProperties() {
+      this.titleColor = Color.Black;
+      this.axisTitleColor = Color.Black;
+      this.title = string.Empty;
+      this.xAxisTitle = string.Empty;
+      this.yAxisTitle = string.Empty;
+      this.xAxisGrid = true;
+      this.yAxisGrid = true;
+      this.xAxisMinimumAuto = true;
+      this.xAxisMinimumFixedValue = double.NaN;
+      this.xAxisMaximumAuto = true;
+      this.xAxisMaximumFixedValue = double.NaN;
+      this.yAxisMinimumAuto = true;
+      this.yAxisMinimumFixedValue = double.NaN;
+      this.yAxisMaximumAuto = true;
+      this.yAxisMaximumFixedValue = double.NaN;
+    }
+    public ScatterPlotVisualProperties(string title)
+      : this() {
+      this.title = title;
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new ScatterPlotVisualProperties(this, cloner);
+    }
+
+    public event PropertyChangedEventHandler PropertyChanged;
+    protected virtual void OnPropertyChanged(string propertyName) {
+      PropertyChangedEventHandler handler = PropertyChanged;
+      if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
+    }
+  }
+}
Index: branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/HeuristicLab.Analysis-3.3.csproj
===================================================================
--- branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/HeuristicLab.Analysis-3.3.csproj	(revision 9280)
+++ branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/HeuristicLab.Analysis-3.3.csproj	(revision 9280)
@@ -0,0 +1,261 @@
+﻿<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProductVersion>9.0.30729</ProductVersion>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{887425B4-4348-49ED-A457-B7D2C26DDBF9}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>HeuristicLab.Analysis</RootNamespace>
+    <AssemblyName>HeuristicLab.Analysis-3.3</AssemblyName>
+    <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
+    <TargetFrameworkProfile>
+    </TargetFrameworkProfile>
+    <FileAlignment>512</FileAlignment>
+    <SignAssembly>true</SignAssembly>
+    <AssemblyOriginatorKeyFile>HeuristicLab.snk</AssemblyOriginatorKeyFile>
+    <FileUpgradeFlags>
+    </FileUpgradeFlags>
+    <OldToolsVersion>3.5</OldToolsVersion>
+    <UpgradeBackupLocation />
+    <PublishUrl>publish\</PublishUrl>
+    <Install>true</Install>
+    <InstallFrom>Disk</InstallFrom>
+    <UpdateEnabled>false</UpdateEnabled>
+    <UpdateMode>Foreground</UpdateMode>
+    <UpdateInterval>7</UpdateInterval>
+    <UpdateIntervalUnits>Days</UpdateIntervalUnits>
+    <UpdatePeriodically>false</UpdatePeriodically>
+    <UpdateRequired>false</UpdateRequired>
+    <MapFileExtensions>true</MapFileExtensions>
+    <ApplicationRevision>0</ApplicationRevision>
+    <ApplicationVersion>1.0.0.%2a</ApplicationVersion>
+    <IsWebBootstrapper>false</IsWebBootstrapper>
+    <UseApplicationTrust>false</UseApplicationTrust>
+    <BootstrapperEnabled>true</BootstrapperEnabled>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>$(SolutionDir)\bin\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>$(SolutionDir)\bin\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <DocumentationFile>
+    </DocumentationFile>
+    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
+    <DebugSymbols>true</DebugSymbols>
+    <OutputPath>$(SolutionDir)\bin\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <DebugType>full</DebugType>
+    <PlatformTarget>x86</PlatformTarget>
+    <ErrorReport>prompt</ErrorReport>
+    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
+    <OutputPath>$(SolutionDir)\bin\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <DocumentationFile>
+    </DocumentationFile>
+    <Optimize>true</Optimize>
+    <DebugType>pdbonly</DebugType>
+    <PlatformTarget>x86</PlatformTarget>
+    <ErrorReport>prompt</ErrorReport>
+    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x64' ">
+    <DebugSymbols>true</DebugSymbols>
+    <OutputPath>$(SolutionDir)\bin\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <DebugType>full</DebugType>
+    <PlatformTarget>x64</PlatformTarget>
+    <ErrorReport>prompt</ErrorReport>
+    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x64' ">
+    <OutputPath>$(SolutionDir)\bin\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <DocumentationFile>
+    </DocumentationFile>
+    <Optimize>true</Optimize>
+    <DebugType>pdbonly</DebugType>
+    <PlatformTarget>x64</PlatformTarget>
+    <ErrorReport>prompt</ErrorReport>
+    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="ALGLIB-3.6.0, Version=3.6.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <HintPath>..\..\bin\ALGLIB-3.6.0.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="System" />
+    <Reference Include="System.Core">
+      <RequiredTargetFramework>3.5</RequiredTargetFramework>
+    </Reference>
+    <Reference Include="System.Drawing" />
+    <Reference Include="System.Xml.Linq">
+      <RequiredTargetFramework>3.5</RequiredTargetFramework>
+    </Reference>
+    <Reference Include="System.Data.DataSetExtensions">
+      <RequiredTargetFramework>3.5</RequiredTargetFramework>
+    </Reference>
+    <Reference Include="System.Data" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="Plugin.cs.frame" />
+    <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="DataVisualization\ScatterPlotDataRowVisualProperties.cs" />
+    <Compile Include="DataVisualization\ScatterPlotDataRow.cs" />
+    <Compile Include="DataVisualization\ScatterPlotVisualProperties.cs" />
+    <Compile Include="DataVisualization\ScatterPlotHistory.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="DataVisualization\ScatterPlot.cs" />
+    <Compile Include="MultidimensionalScaling\MultidimensionalScaling.cs" />
+    <Compile Include="MultiObjective\RankBasedParetoFrontAnalyzer.cs" />
+    <Compile Include="MultiObjective\ParetoFrontAnalyzer.cs" />
+    <Compile Include="Plugin.cs" />
+    <Compile Include="PopulationDiversityAnalysis\PopulationDiversityAnalyzer.cs" />
+    <Compile Include="PopulationDiversityAnalysis\SingleObjectivePopulationDiversityAnalyzer.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="Properties\AssemblyInfo.cs" />
+    <Compile Include="QualityAnalysis\QualityDistributionAnalyzer.cs" />
+    <Compile Include="QualityAnalysis\ScaledQualityDifferenceAnalyzer.cs" />
+    <Compile Include="ValueAnalysis\SingleValueAnalyzer.cs" />
+    <Compile Include="ValueAnalysis\MinAverageMaxValueAnalyzer.cs" />
+    <Compile Include="ValueAnalysis\MinAverageMaxValueCalculator.cs" />
+    <Compile Include="ValueAnalysis\ValueAnalyzer.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="HeuristicLab.snk" />
+    <None Include="Properties\AssemblyInfo.cs.frame" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\..\HeuristicLab.Collections\3.3\HeuristicLab.Collections-3.3.csproj">
+      <Project>{958B43BC-CC5C-4FA2-8628-2B3B01D890B6}</Project>
+      <Name>HeuristicLab.Collections-3.3</Name>
+      <Private>False</Private>
+    </ProjectReference>
+    <ProjectReference Include="..\..\HeuristicLab.Common.Resources\3.3\HeuristicLab.Common.Resources-3.3.csproj">
+      <Project>{0E27A536-1C4A-4624-A65E-DC4F4F23E3E1}</Project>
+      <Name>HeuristicLab.Common.Resources-3.3</Name>
+      <Private>False</Private>
+    </ProjectReference>
+    <ProjectReference Include="..\..\HeuristicLab.Common\3.3\HeuristicLab.Common-3.3.csproj">
+      <Project>{A9AD58B9-3EF9-4CC1-97E5-8D909039FF5C}</Project>
+      <Name>HeuristicLab.Common-3.3</Name>
+      <Private>False</Private>
+    </ProjectReference>
+    <ProjectReference Include="..\..\HeuristicLab.Core\3.3\HeuristicLab.Core-3.3.csproj">
+      <Project>{C36BD924-A541-4A00-AFA8-41701378DDC5}</Project>
+      <Name>HeuristicLab.Core-3.3</Name>
+      <Private>False</Private>
+    </ProjectReference>
+    <ProjectReference Include="..\..\HeuristicLab.Data\3.3\HeuristicLab.Data-3.3.csproj">
+      <Project>{BBAB9DF5-5EF3-4BA8-ADE9-B36E82114937}</Project>
+      <Name>HeuristicLab.Data-3.3</Name>
+      <Private>False</Private>
+    </ProjectReference>
+    <ProjectReference Include="..\..\HeuristicLab.Operators\3.3\HeuristicLab.Operators-3.3.csproj">
+      <Project>{23DA7FF4-D5B8-41B6-AA96-F0561D24F3EE}</Project>
+      <Name>HeuristicLab.Operators-3.3</Name>
+      <Private>False</Private>
+    </ProjectReference>
+    <ProjectReference Include="..\..\HeuristicLab.Optimization.Operators\3.3\HeuristicLab.Optimization.Operators-3.3.csproj">
+      <Project>{25087811-F74C-4128-BC86-8324271DA13E}</Project>
+      <Name>HeuristicLab.Optimization.Operators-3.3</Name>
+      <Private>False</Private>
+    </ProjectReference>
+    <ProjectReference Include="..\..\HeuristicLab.Optimization\3.3\HeuristicLab.Optimization-3.3.csproj">
+      <Project>{14AB8D24-25BC-400C-A846-4627AA945192}</Project>
+      <Name>HeuristicLab.Optimization-3.3</Name>
+      <Private>False</Private>
+    </ProjectReference>
+    <ProjectReference Include="..\..\HeuristicLab.Parameters\3.3\HeuristicLab.Parameters-3.3.csproj">
+      <Project>{56F9106A-079F-4C61-92F6-86A84C2D84B7}</Project>
+      <Name>HeuristicLab.Parameters-3.3</Name>
+      <Private>False</Private>
+    </ProjectReference>
+    <ProjectReference Include="..\..\HeuristicLab.Persistence\3.3\HeuristicLab.Persistence-3.3.csproj">
+      <Project>{102BC7D3-0EF9-439C-8F6D-96FF0FDB8E1B}</Project>
+      <Name>HeuristicLab.Persistence-3.3</Name>
+      <Private>False</Private>
+    </ProjectReference>
+    <ProjectReference Include="..\..\HeuristicLab.PluginInfrastructure\3.3\HeuristicLab.PluginInfrastructure-3.3.csproj">
+      <Project>{94186A6A-5176-4402-AE83-886557B53CCA}</Project>
+      <Name>HeuristicLab.PluginInfrastructure-3.3</Name>
+      <Private>False</Private>
+    </ProjectReference>
+  </ItemGroup>
+  <ItemGroup>
+    <BootstrapperPackage Include="Microsoft.Net.Client.3.5">
+      <Visible>False</Visible>
+      <ProductName>.NET Framework 3.5 SP1 Client Profile</ProductName>
+      <Install>false</Install>
+    </BootstrapperPackage>
+    <BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
+      <Visible>False</Visible>
+      <ProductName>.NET Framework 3.5 SP1</ProductName>
+      <Install>true</Install>
+    </BootstrapperPackage>
+    <BootstrapperPackage Include="Microsoft.Windows.Installer.3.1">
+      <Visible>False</Visible>
+      <ProductName>Windows Installer 3.1</ProductName>
+      <Install>true</Install>
+    </BootstrapperPackage>
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+  <PropertyGroup>
+   <PreBuildEvent Condition=" '$(OS)' == 'Windows_NT' ">set Path=%25Path%25;$(ProjectDir);$(SolutionDir)
+set ProjectDir=$(ProjectDir)
+set SolutionDir=$(SolutionDir)
+set Outdir=$(Outdir)
+
+call PreBuildEvent.cmd
+</PreBuildEvent>
+<PreBuildEvent Condition=" '$(OS)' != 'Windows_NT' ">
+export ProjectDir=$(ProjectDir)
+export SolutionDir=$(SolutionDir)
+
+$SolutionDir/PreBuildEvent.sh
+</PreBuildEvent>
+  </PropertyGroup>
+</Project>
Index: branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/MultiAnalyzer.cs
===================================================================
--- branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/MultiAnalyzer.cs	(revision 9280)
+++ branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/MultiAnalyzer.cs	(revision 9280)
@@ -0,0 +1,93 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 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.Collections;
+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 analyzer which applies arbitrary many other analyzers.
+  /// </summary>
+  [Item("MultiAnalyzer", "An analyzer which applies arbitrary many other analyzers.")]
+  [StorableClass]
+  public class MultiAnalyzer : CheckedMultiOperator<IAnalyzer>, IMultiAnalyzer {
+    public override bool CanChangeName {
+      get { return false; }
+    }
+    public virtual bool EnabledByDefault {
+      get { return true; }
+    }
+
+    public ValueLookupParameter<IntValue> UpdateIntervalParameter {
+      get { return (ValueLookupParameter<IntValue>)Parameters["UpdateInterval"]; }
+    }
+    public LookupParameter<IntValue> UpdateCounterParameter {
+      get { return (LookupParameter<IntValue>)Parameters["UpdateCounter"]; }
+    }
+
+    public IntValue UpdateInterval {
+      get { return UpdateIntervalParameter.Value; }
+      set { UpdateIntervalParameter.Value = value; }
+    }
+
+    #region Storing & Cloning
+    [StorableConstructor]
+    protected MultiAnalyzer(bool deserializing) : base(deserializing) { }
+    protected MultiAnalyzer(MultiAnalyzer original, Cloner cloner) : base(original, cloner) { }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new MultiAnalyzer(this, cloner);
+    }
+    #endregion
+    public MultiAnalyzer()
+      : base() {
+      Parameters.Add(new ValueLookupParameter<IntValue>("UpdateInterval", "The interval in which the contained analyzers should be applied.", new IntValue(1)));
+      Parameters.Add(new LookupParameter<IntValue>("UpdateCounter", "The value which counts how many times the MultiAnalyzer was called since the last update.", "MultiAnalyzerUpdateCounter"));
+    }
+
+    public override IOperation Apply() {
+      IntValue interval = UpdateIntervalParameter.ActualValue;
+      if (interval == null) interval = new IntValue(1);
+
+      IntValue counter = UpdateCounterParameter.ActualValue;
+      if (counter == null) {
+        counter = new IntValue(interval.Value);
+        UpdateCounterParameter.ActualValue = counter;
+      } else counter.Value++;
+
+      if (counter.Value == interval.Value) {
+        counter.Value = 0;
+        OperationCollection next = new OperationCollection();
+        foreach (IndexedItem<IAnalyzer> item in Operators.CheckedItems)
+          next.Add(ExecutionContext.CreateOperation(item.Value));
+        next.Add(base.Apply());
+        return next;
+      } else {
+        return base.Apply();
+      }
+    }
+  }
+}
Index: branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/MultiObjective/ParetoFrontAnalyzer.cs
===================================================================
--- branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/MultiObjective/ParetoFrontAnalyzer.cs	(revision 9280)
+++ branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/MultiObjective/ParetoFrontAnalyzer.cs	(revision 9280)
@@ -0,0 +1,62 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 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.Optimization;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Analysis {
+  [Item("ParetoFrontAnalyzer", "Analyzer for multiobjective problems that collects and presents the current Pareto front as double matrix as well as the solution scopes that lie on the current front.")]
+  [StorableClass]
+  public abstract class ParetoFrontAnalyzer : SingleSuccessorOperator, IAnalyzer {
+    public virtual bool EnabledByDefault {
+      get { return true; }
+    }
+
+    public IScopeTreeLookupParameter<DoubleArray> QualitiesParameter {
+      get { return (IScopeTreeLookupParameter<DoubleArray>)Parameters["Qualities"]; }
+    }
+    public ILookupParameter<ResultCollection> ResultsParameter {
+      get { return (ILookupParameter<ResultCollection>)Parameters["Results"]; }
+    }
+
+    [StorableConstructor]
+    protected ParetoFrontAnalyzer(bool deserializing) : base(deserializing) { }
+    protected ParetoFrontAnalyzer(ParetoFrontAnalyzer original, Cloner cloner) : base(original, cloner) { }
+    public ParetoFrontAnalyzer() {
+      Parameters.Add(new ScopeTreeLookupParameter<DoubleArray>("Qualities", "The vector of qualities of each solution."));
+      Parameters.Add(new LookupParameter<ResultCollection>("Results", "The result collection to store the front to."));
+    }
+
+    public override IOperation Apply() {
+      ItemArray<DoubleArray> qualities = QualitiesParameter.ActualValue;
+      ResultCollection results = ResultsParameter.ActualValue;
+      Analyze(qualities, results);
+      return base.Apply();
+    }
+
+    protected abstract void Analyze(ItemArray<DoubleArray> qualities, ResultCollection results);
+  }
+}
Index: branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/MultiObjective/RankBasedParetoFrontAnalyzer.cs
===================================================================
--- branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/MultiObjective/RankBasedParetoFrontAnalyzer.cs	(revision 9280)
+++ branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/MultiObjective/RankBasedParetoFrontAnalyzer.cs	(revision 9280)
@@ -0,0 +1,97 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 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.Optimization;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Analysis {
+  [Item("RankBasedParetoFrontAnalyzer", "Uses the rank value that is computed by e.g. the NSGA2's fast non dominated sort operator to collect all solutions and their qualities of front 0 (the current Pareto front).")]
+  [StorableClass]
+  public class RankBasedParetoFrontAnalyzer : ParetoFrontAnalyzer {
+    public IScopeTreeLookupParameter<IntValue> RankParameter {
+      get { return (IScopeTreeLookupParameter<IntValue>)Parameters["Rank"]; }
+    }
+
+    [StorableConstructor]
+    protected RankBasedParetoFrontAnalyzer(bool deserializing) : base(deserializing) { }
+    protected RankBasedParetoFrontAnalyzer(RankBasedParetoFrontAnalyzer original, Cloner cloner) : base(original, cloner) { }
+    public RankBasedParetoFrontAnalyzer() {
+      Parameters.Add(new ScopeTreeLookupParameter<IntValue>("Rank", "The rank of solution [0..N] describes to which front it belongs."));
+    }
+
+    protected override void Analyze(ItemArray<DoubleArray> qualities, ResultCollection results) {
+      ItemArray<IntValue> ranks = RankParameter.ActualValue;
+
+      bool populationLevel = RankParameter.Depth == 1;
+
+      int objectives = qualities[0].Length;
+      int frontSize = ranks.Count(x => x.Value == 0);
+      ItemArray<IScope> paretoArchive = null;
+      if (populationLevel) paretoArchive = new ItemArray<IScope>(frontSize);
+
+      DoubleMatrix front = new DoubleMatrix(frontSize, objectives);
+      int counter = 0;
+      for (int i = 0; i < ranks.Length; i++) {
+        if (ranks[i].Value == 0) {
+          for (int k = 0; k < objectives; k++)
+            front[counter, k] = qualities[i][k];
+          if (populationLevel) {
+            paretoArchive[counter] = (IScope)ExecutionContext.Scope.SubScopes[i].Clone();
+          }
+          counter++;
+        }
+      }
+
+      front.RowNames = GetRowNames(front);
+      front.ColumnNames = GetColumnNames(front);
+
+      if (results.ContainsKey("Pareto Front"))
+        results["Pareto Front"].Value = front;
+      else results.Add(new Result("Pareto Front", front));
+
+      if (populationLevel) {
+        if (results.ContainsKey("Pareto Archive"))
+          results["Pareto Archive"].Value = paretoArchive;
+        else results.Add(new Result("Pareto Archive", paretoArchive));
+      }
+    }
+
+    private IEnumerable<string> GetRowNames(DoubleMatrix front) {
+      for (int i = 1; i <= front.Rows; i++)
+        yield return "Solution " + i.ToString();
+    }
+
+    private IEnumerable<string> GetColumnNames(DoubleMatrix front) {
+      for (int i = 1; i <= front.Columns; i++)
+        yield return "Objective " + i.ToString();
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new RankBasedParetoFrontAnalyzer(this, cloner);
+    }
+  }
+}
Index: branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/MultidimensionalScaling/MultidimensionalScaling.cs
===================================================================
--- branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/MultidimensionalScaling/MultidimensionalScaling.cs	(revision 9280)
+++ branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/MultidimensionalScaling/MultidimensionalScaling.cs	(revision 9280)
@@ -0,0 +1,182 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 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.Data;
+
+namespace HeuristicLab.Analysis {
+  public static class MultidimensionalScaling {
+
+    /// <summary>
+    /// Performs the Kruskal-Shepard algorithm and applies a gradient descent method
+    /// to fit the coordinates such that the difference between the fit distances
+    /// and the dissimilarities becomes minimal.
+    /// </summary>
+    /// <remarks>
+    /// It will initialize the coordinates in a deterministic fashion such that all initial points are equally spaced on a circle.
+    /// </remarks>
+    /// <param name="dissimilarities">A symmetric NxN matrix that specifies the dissimilarities between each element i and j. Diagonal elements are ignored.</param>
+    /// 
+    /// <returns>A Nx2 matrix where the first column represents the x- and the second column the y coordinates.</returns>
+    public static DoubleMatrix KruskalShepard(DoubleMatrix dissimilarities) {
+      if (dissimilarities == null) throw new ArgumentNullException("dissimilarities");
+      if (dissimilarities.Rows != dissimilarities.Columns) throw new ArgumentException("Dissimilarities must be a square matrix.", "dissimilarities");
+
+      int dimension = dissimilarities.Rows;
+      if (dimension == 1) return new DoubleMatrix(new double[,] { { 0, 0 } });
+      else if (dimension == 2) return new DoubleMatrix(new double[,] { { 0, 0 }, { 0, dissimilarities[0, 1] } });
+
+      DoubleMatrix coordinates = new DoubleMatrix(dimension, 2);
+      double rad = (2 * Math.PI) / coordinates.Rows;
+      for (int i = 0; i < dimension; i++) {
+        coordinates[i, 0] = 10 * Math.Cos(rad * i);
+        coordinates[i, 1] = 10 * Math.Sin(rad * i);
+      }
+
+      return KruskalShepard(dissimilarities, coordinates);
+    }
+
+    /// <summary>
+    /// Performs the Kruskal-Shepard algorithm and applies a gradient descent method
+    /// to fit the coordinates such that the difference between the fit distances
+    /// and the dissimilarities is minimal.
+    /// </summary>
+    /// <remarks>
+    /// It will use a pre-initialized x,y-coordinates matrix as a starting point of the gradient descent.
+    /// </remarks>
+    /// <param name="dissimilarities">A symmetric NxN matrix that specifies the dissimilarities between each element i and j. Diagonal elements are ignored.</param>
+    /// <param name="coordinates">The Nx2 matrix of initial coordinates.</param>
+    /// <param name="maximumIterations">The number of iterations for which the algorithm should run.
+    /// In every iteration it tries to find the best location for every item.</param>
+    /// <returns>A Nx2 matrix where the first column represents the x- and the second column the y coordinates.</returns>
+    public static DoubleMatrix KruskalShepard(DoubleMatrix dissimilarities, DoubleMatrix coordinates, int maximumIterations = 10) {
+      int dimension = dissimilarities.Rows;
+      if (dimension != dissimilarities.Columns || coordinates.Rows != dimension) throw new ArgumentException("The number of coordinates and the number of rows and columns in the dissimilarities matrix do not match.");
+
+      double epsg = 1e-7;
+      double epsf = 0;
+      double epsx = 0;
+      int maxits = 0;
+
+      alglib.minlmstate state;
+      alglib.minlmreport rep;
+      for (int iterations = 0; iterations < maximumIterations; iterations++) {
+        bool changed = false;
+        for (int i = 0; i < dimension; i++) {
+          double[] c = new double[] { coordinates[i, 0], coordinates[i, 1] };
+
+          try {
+            alglib.minlmcreatevj(dimension - 1, c, out state);
+            alglib.minlmsetcond(state, epsg, epsf, epsx, maxits);
+            alglib.minlmoptimize(state, StressFitness, StressJacobian, null, new Info(coordinates, dissimilarities, i));
+            alglib.minlmresults(state, out c, out rep);
+          } catch (alglib.alglibexception) { }
+          if (!double.IsNaN(c[0]) && !double.IsNaN(c[1])) {
+            changed = changed || (coordinates[i, 0] != c[0]) || (coordinates[i, 1] != c[1]);
+            coordinates[i, 0] = c[0];
+            coordinates[i, 1] = c[1];
+          }
+        }
+        if (!changed) break;
+      }
+      return coordinates;
+    }
+
+    private static void StressFitness(double[] x, double[] fi, object obj) {
+      Info info = (obj as Info);
+      int idx = 0;
+      for (int i = 0; i < info.Coordinates.Rows; i++) {
+        if (i == info.Row) continue;
+        if (!double.IsNaN(info.Dissimilarities[info.Row, i]))
+          fi[idx++] = Stress(x, info.Dissimilarities[info.Row, i], info.Coordinates[i, 0], info.Coordinates[i, 1]);
+        else fi[idx++] = 0.0;
+      }
+    }
+
+    private static void StressJacobian(double[] x, double[] fi, double[,] jac, object obj) {
+      Info info = (obj as Info);
+      int idx = 0;
+      for (int i = 0; i < info.Coordinates.Rows; i++) {
+        if (i == info.Row) continue;
+        double c = info.Dissimilarities[info.Row, i];
+        double a = info.Coordinates[i, 0];
+        double b = info.Coordinates[i, 1];
+        if (!double.IsNaN(c)) {
+          fi[idx] = Stress(x, c, a, b); ;
+          jac[idx, 0] = 2 * (x[0] - a) * (Math.Sqrt((a - x[0]) * (a - x[0]) + (b - x[1]) * (b - x[1])) - c) / Math.Sqrt((a - x[0]) * (a - x[0]) + (b - x[1]) * (b - x[1]));
+          jac[idx, 1] = 2 * (x[1] - b) * (Math.Sqrt((a - x[0]) * (a - x[0]) + (b - x[1]) * (b - x[1])) - c) / Math.Sqrt((a - x[0]) * (a - x[0]) + (b - x[1]) * (b - x[1]));
+        } else {
+          fi[idx] = jac[idx, 0] = jac[idx, 1] = 0;
+        }
+        idx++;
+      }
+    }
+
+    private static double Stress(double[] x, double distance, double xCoord, double yCoord) {
+      return Stress(x[0], x[1], distance, xCoord, yCoord);
+    }
+
+    private static double Stress(double x, double y, double distance, double otherX, double otherY) {
+      double d = Math.Sqrt((x - otherX) * (x - otherX)
+                         + (y - otherY) * (y - otherY));
+      return (d - distance) * (d - distance);
+    }
+
+    /// <summary>
+    /// This method computes the normalized raw-stress value according to Groenen and van de Velden 2004. "Multidimensional Scaling". Technical report EI 2004-15.
+    /// </summary>
+    /// <remarks>
+    /// Throws an ArgumentException when the <paramref name="dissimilarities"/> matrix is not symmetric.
+    /// </remarks>
+    /// 
+    /// <param name="dissimilarities">The matrix with the dissimilarities.</param>
+    /// <param name="coordinates">The actual location of the points.</param>
+    /// <returns>The normalized raw-stress value that describes the goodness-of-fit between the distances in the points and the size of the dissimilarities. If the value is &lt; 0.1 the fit is generally considered good. If between 0.1 and 0.2 it is considered acceptable, but the usefulness of the scaling with higher values is doubtful.</returns>
+    public static double CalculateNormalizedStress(DoubleMatrix dissimilarities, DoubleMatrix coordinates) {
+      int dimension = dissimilarities.Rows;
+      if (dimension != dissimilarities.Columns || dimension != coordinates.Rows) throw new ArgumentException("The number of coordinates and the number of rows and columns in the dissimilarities matrix do not match.");
+      double stress = 0, normalization = 0;
+      for (int i = 0; i < dimension - 1; i++) {
+        for (int j = i + 1; j < dimension; j++) {
+          if (dissimilarities[i, j] != dissimilarities[j, i] && !(double.IsNaN(dissimilarities[i, j]) && double.IsNaN(dissimilarities[j, i])))
+            throw new ArgumentException("Dissimilarities is not a symmetric matrix.", "dissimilarities");
+          if (!double.IsNaN(dissimilarities[i, j])) {
+            stress += Stress(coordinates[i, 0], coordinates[i, 1], dissimilarities[i, j], coordinates[j, 0], coordinates[j, 1]);
+            normalization += (dissimilarities[i, j] * dissimilarities[i, j]);
+          }
+        }
+      }
+      return stress / normalization;
+    }
+
+    private class Info {
+      public DoubleMatrix Coordinates { get; set; }
+      public DoubleMatrix Dissimilarities { get; set; }
+      public int Row { get; set; }
+
+      public Info(DoubleMatrix c, DoubleMatrix d, int r) {
+        Coordinates = c;
+        Dissimilarities = d;
+        Row = r;
+      }
+    }
+  }
+}
Index: branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/Plugin.cs.frame
===================================================================
--- branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/Plugin.cs.frame	(revision 9280)
+++ branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/Plugin.cs.frame	(revision 9280)
@@ -0,0 +1,43 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 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.PluginInfrastructure;
+
+namespace HeuristicLab.Analysis {
+  /// <summary>
+  /// Plugin class for HeuristicLab.Analysis plugin.
+  /// </summary>
+  [Plugin("HeuristicLab.Analysis", "3.3.7.$WCREV$")]
+  [PluginFile("HeuristicLab.Analysis-3.3.dll", PluginFileType.Assembly)]
+  [PluginDependency("HeuristicLab.ALGLIB", "3.6.0")]
+  [PluginDependency("HeuristicLab.Collections", "3.3")]
+  [PluginDependency("HeuristicLab.Common", "3.3")]
+  [PluginDependency("HeuristicLab.Common.Resources", "3.3")]
+  [PluginDependency("HeuristicLab.Core", "3.3")]
+  [PluginDependency("HeuristicLab.Data", "3.3")]
+  [PluginDependency("HeuristicLab.Operators", "3.3")]
+  [PluginDependency("HeuristicLab.Optimization", "3.3")]
+  [PluginDependency("HeuristicLab.Optimization.Operators", "3.3")]
+  [PluginDependency("HeuristicLab.Parameters", "3.3")]
+  [PluginDependency("HeuristicLab.Persistence", "3.3")]
+  public class HeuristicLabAnalysisPlugin : PluginBase {
+  }
+}
Index: branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/PopulationDiversityAnalysis/PopulationDiversityAnalyzer.cs
===================================================================
--- branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/PopulationDiversityAnalysis/PopulationDiversityAnalyzer.cs	(revision 9280)
+++ branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/PopulationDiversityAnalysis/PopulationDiversityAnalyzer.cs	(revision 9280)
@@ -0,0 +1,252 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 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 {
+  // use HeuristicLab.Analysis.SingleObjectivePopulationDiversityAnalyzer instead
+  // BackwardsCompatibility3.3
+  #region Backwards compatible code, remove with 3.4
+  /// <summary>
+  /// An operator for analyzing the solution diversity in a population.
+  /// </summary>
+  [Obsolete]
+  [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 virtual bool EnabledByDefault {
+      get { return false; }
+    }
+
+    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"));
+
+      MaximizationParameter.Hidden = true;
+      SolutionParameter.Hidden = true;
+      QualityParameter.Hidden = true;
+      ResultsParameter.Hidden = true;
+      UpdateCounterParameter.Hidden = true;
+    }
+
+    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(Name + " Results")) {
+            results = new ResultCollection();
+            ResultsParameter.ActualValue.Add(new Result(Name + " Results", results));
+          } else {
+            results = (ResultCollection)ResultsParameter.ActualValue[Name + " 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);
+  }
+  #endregion
+}
Index: branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/PopulationDiversityAnalysis/SingleObjectivePopulationDiversityAnalyzer.cs
===================================================================
--- branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/PopulationDiversityAnalysis/SingleObjectivePopulationDiversityAnalyzer.cs	(revision 9280)
+++ branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/PopulationDiversityAnalysis/SingleObjectivePopulationDiversityAnalyzer.cs	(revision 9280)
@@ -0,0 +1,256 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 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("SingleObjectivePopulationDiversityAnalyzer", "An operator for analyzing the solution diversity in a population.")]
+  [StorableClass]
+  public class SingleObjectivePopulationDiversityAnalyzer : SingleSuccessorOperator, IAnalyzer, ISimilarityBasedOperator {
+    #region ISimilarityBasedOperator Members
+    public ISolutionSimilarityCalculator SimilarityCalculator { get; set; }
+    #endregion
+
+    public virtual bool EnabledByDefault {
+      get { return false; }
+    }
+
+    public ScopeParameter CurrentScopeParameter {
+      get { return (ScopeParameter)Parameters["CurrentScope"]; }
+    }
+    public LookupParameter<BoolValue> MaximizationParameter {
+      get { return (LookupParameter<BoolValue>)Parameters["Maximization"]; }
+    }
+    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 SingleObjectivePopulationDiversityAnalyzer(bool deserializing) : base(deserializing) { }
+    protected SingleObjectivePopulationDiversityAnalyzer(SingleObjectivePopulationDiversityAnalyzer original, Cloner cloner) : base(original, cloner) { }
+    public SingleObjectivePopulationDiversityAnalyzer()
+      : base() {
+      Parameters.Add(new ScopeParameter("CurrentScope", "The current scope that contains the solutions which should be analyzed."));
+      Parameters.Add(new LookupParameter<BoolValue>("Maximization", "True if the problem is a maximization problem."));
+      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"));
+
+      MaximizationParameter.Hidden = true;
+      QualityParameter.Hidden = true;
+      ResultsParameter.Hidden = true;
+      UpdateCounterParameter.Hidden = true;
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new SingleObjectivePopulationDiversityAnalyzer(this, cloner);
+    }
+
+    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<DoubleValue> qualities = QualityParameter.ActualValue;
+        bool storeHistory = StoreHistoryParameter.Value.Value;
+        int count = CurrentScopeParameter.ActualValue.SubScopes.Count;
+
+        if (count > 1) {
+          // calculate solution similarities
+          var similarityMatrix = SimilarityCalculator.CalculateSolutionCrowdSimilarity(CurrentScopeParameter.ActualValue);
+
+          // sort similarities by quality
+          double[][] sortedSimilarityMatrix = null;
+          if (max)
+            sortedSimilarityMatrix = similarityMatrix
+              .Select((x, index) => new { Solutions = x, Quality = qualities[index] })
+              .OrderByDescending(x => x.Quality)
+              .Select(x => x.Solutions)
+              .ToArray();
+          else
+            sortedSimilarityMatrix = similarityMatrix
+              .Select((x, index) => new { Solutions = x, Quality = qualities[index] })
+              .OrderBy(x => x.Quality)
+              .Select(x => x.Solutions)
+              .ToArray();
+
+          double[,] similarities = new double[similarityMatrix.Length, similarityMatrix[0].Length];
+          for (int i = 0; i < similarityMatrix.Length; i++)
+            for (int j = 0; j < similarityMatrix[0].Length; j++)
+              similarities[i, j] = similarityMatrix[i][j];
+
+          // 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(Name + " Results")) {
+            results = new ResultCollection();
+            ResultsParameter.ActualValue.Add(new Result(Name + " Results", results));
+          } else {
+            results = (ResultCollection)ResultsParameter.ActualValue[Name + " 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();
+    }
+  }
+}
Index: branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/Properties/AssemblyInfo.cs.frame
===================================================================
--- branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/Properties/AssemblyInfo.cs.frame	(revision 9280)
+++ branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/Properties/AssemblyInfo.cs.frame	(revision 9280)
@@ -0,0 +1,56 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 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.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following 
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("HeuristicLab.Analysis")]
+[assembly: AssemblyDescription("HeuristicLab algorithm analysis classes")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("HeuristicLab")]
+[assembly: AssemblyCopyright("(c) 2002-2012 HEAL")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible 
+// to COM components.  If you need to access a type in this assembly from 
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("b987398b-693f-41e6-8a90-10374e9464ba")]
+
+// Version information for an assembly consists of the following four values:
+//
+//      Major Version
+//      Minor Version 
+//      Build Number
+//      Revision
+//
+// You can specify all the values or you can default the Revision and Build Numbers 
+// by using the '*' as shown below:
+[assembly: AssemblyVersion("3.3.0.0")]
+[assembly: AssemblyFileVersion("3.3.7.$WCREV$")]
Index: branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/QualityAnalysis/BestAverageWorstQualityAnalyzer.cs
===================================================================
--- branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/QualityAnalysis/BestAverageWorstQualityAnalyzer.cs	(revision 9280)
+++ branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/QualityAnalysis/BestAverageWorstQualityAnalyzer.cs	(revision 9280)
@@ -0,0 +1,197 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 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<ResultCollection> ResultsParameter {
+      get { return (ValueLookupParameter<ResultCollection>)Parameters["Results"]; }
+    }
+    #endregion
+
+    #region Properties
+    public bool EnabledByDefault {
+      get { return true; }
+    }
+    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<ResultCollection>("Results", "The results collection where the analysis values should be stored."));
+
+      BestQualityParameter.Hidden = true;
+      CurrentBestQualityParameter.Hidden = true;
+      CurrentAverageQualityParameter.Hidden = true;
+      CurrentWorstQualityParameter.Hidden = true;
+      QualitiesParameter.Hidden = true;
+      AbsoluteDifferenceBestKnownToBestParameter.Hidden = true;
+      RelativeDifferenceBestKnownToBestParameter.Hidden = true;
+      #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();
+      // BackwardsCompatibility3.3
+      #region Backwards compatible code, remove with 3.4
+      if (Parameters["Results"] is ValueLookupParameter<VariableCollection>) {
+        Parameters.Remove("Results");
+        Parameters.Add(new ValueLookupParameter<ResultCollection>("Results", "The results collection where the analysis values should be stored."));
+      }
+      #endregion
+    }
+
+    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: branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/QualityAnalysis/BestAverageWorstQualityCalculator.cs
===================================================================
--- branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/QualityAnalysis/BestAverageWorstQualityCalculator.cs	(revision 9280)
+++ branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/QualityAnalysis/BestAverageWorstQualityCalculator.cs	(revision 9280)
@@ -0,0 +1,104 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 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."));
+
+      BestQualityParameter.Hidden = true;
+      AverageQualityParameter.Hidden = true;
+      WorstQualityParameter.Hidden = true;
+    }
+
+
+    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: branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/QualityAnalysis/BestQualityMemorizer.cs
===================================================================
--- branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/QualityAnalysis/BestQualityMemorizer.cs	(revision 9280)
+++ branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/QualityAnalysis/BestQualityMemorizer.cs	(revision 9280)
@@ -0,0 +1,79 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 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: branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/QualityAnalysis/QualityAnalyzer.cs
===================================================================
--- branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/QualityAnalysis/QualityAnalyzer.cs	(revision 9280)
+++ branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/QualityAnalysis/QualityAnalyzer.cs	(revision 9280)
@@ -0,0 +1,174 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 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
+    public bool EnabledByDefault {
+      get { return true; }
+    }
+    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: branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/QualityAnalysis/QualityDifferenceCalculator.cs
===================================================================
--- branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/QualityAnalysis/QualityDifferenceCalculator.cs	(revision 9280)
+++ branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/QualityAnalysis/QualityDifferenceCalculator.cs	(revision 9280)
@@ -0,0 +1,81 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 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: branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/QualityAnalysis/QualityDistributionAnalyzer.cs
===================================================================
--- branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/QualityAnalysis/QualityDistributionAnalyzer.cs	(revision 9280)
+++ branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/QualityAnalysis/QualityDistributionAnalyzer.cs	(revision 9280)
@@ -0,0 +1,139 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 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.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.QualityAnalysis {
+  [Item("QualityDistributionAnalyzer", "Analyzes the distribution of the quality values in that it adds a Histogram of them into the result collection.")]
+  [StorableClass]
+  public class QualityDistributionAnalyzer : SingleSuccessorOperator, IAnalyzer, IIterationBasedOperator {
+
+    #region Parameter properties
+    public IScopeTreeLookupParameter<DoubleValue> QualityParameter {
+      get { return (IScopeTreeLookupParameter<DoubleValue>)Parameters["Quality"]; }
+    }
+    public IValueLookupParameter<ResultCollection> ResultsParameter {
+      get { return (IValueLookupParameter<ResultCollection>)Parameters["Results"]; }
+    }
+    private ValueParameter<StringValue> HistogramNameParameter {
+      get { return (ValueParameter<StringValue>)Parameters["HistogramName"]; }
+    }
+    private ValueParameter<BoolValue> StoreHistoryParameter {
+      get { return (ValueParameter<BoolValue>)Parameters["StoreHistory"]; }
+    }
+    public ILookupParameter<IntValue> IterationsParameter {
+      get { return (ILookupParameter<IntValue>)Parameters["Iterations"]; }
+    }
+    public IValueLookupParameter<IntValue> MaximumIterationsParameter {
+      get { return (IValueLookupParameter<IntValue>)Parameters["MaximumIterations"]; }
+    }
+    #endregion
+
+    public virtual bool EnabledByDefault {
+      get { return true; }
+    }
+
+    public string HistogramName {
+      get { return HistogramNameParameter.Value.Value; }
+      set { HistogramNameParameter.Value.Value = value; }
+    }
+
+    public bool StoreHistory {
+      get { return StoreHistoryParameter.Value.Value; }
+      set { StoreHistoryParameter.Value.Value = value; }
+    }
+
+    [StorableConstructor]
+    protected QualityDistributionAnalyzer(bool deserializing) : base(deserializing) { }
+    protected QualityDistributionAnalyzer(QualityDistributionAnalyzer original, Cloner cloner)
+      : base(original, cloner) {
+    }
+    public QualityDistributionAnalyzer()
+      : base() {
+      Parameters.Add(new ScopeTreeLookupParameter<DoubleValue>("Quality", "The value which represents the quality of a solution."));
+      Parameters.Add(new ValueLookupParameter<ResultCollection>("Results", "The results collection where the analysis values should be stored."));
+      Parameters.Add(new FixedValueParameter<StringValue>("HistogramName", "The name of the histogram that gets injected in to the results collection.", new StringValue("Quality Distribution")));
+      Parameters.Add(new FixedValueParameter<BoolValue>("StoreHistory", "True if the history should be stored in addition to the current distribution", new BoolValue(false)));
+      Parameters.Add(new LookupParameter<IntValue>("Iterations", "Optional: A value indicating the current iteration."));
+      Parameters.Add(new ValueLookupParameter<IntValue>("MaximumIterations", "Unused", new IntValue(-1)));
+
+      QualityParameter.Hidden = true;
+      ResultsParameter.Hidden = true;
+      IterationsParameter.Hidden = true;
+      MaximumIterationsParameter.Hidden = true;
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new QualityDistributionAnalyzer(this, cloner);
+    }
+
+    public override IOperation Apply() {
+      DataTable qualityDistribution = null;
+      ResultCollection results = ResultsParameter.ActualValue;
+      string description = "Shows the quality distributions in the current population.";
+      if (results.ContainsKey(HistogramName)) {
+        qualityDistribution = results[HistogramName].Value as DataTable;
+      } else {
+        qualityDistribution = new DataTable("Population Quality Distribution", description);
+        qualityDistribution.VisualProperties.XAxisTitle = QualityParameter.ActualName;
+        qualityDistribution.VisualProperties.YAxisTitle = "Frequency";
+        results.Add(new Result(HistogramName, description, qualityDistribution));
+      }
+      DataRow row;
+      if (!qualityDistribution.Rows.TryGetValue("QualityDistribution", out row)) {
+        row = new DataRow("QualityDistribution");
+        row.VisualProperties.ChartType = DataRowVisualProperties.DataRowChartType.Histogram;
+        qualityDistribution.Rows.Add(row);
+      }
+      var qualities = QualityParameter.ActualValue;
+      row.Values.Replace(qualities.Select(x => x.Value));
+
+      if (StoreHistory) {
+        string historyResultName = HistogramName + " History";
+        DataTableHistory qdHistory = null;
+        if (results.ContainsKey(historyResultName)) {
+          qdHistory = results[historyResultName].Value as DataTableHistory;
+        } else {
+          qdHistory = new DataTableHistory();
+          results.Add(new Result(historyResultName, qdHistory));
+        }
+        DataTable table = (DataTable)qualityDistribution.Clone();
+        IntValue iteration = IterationsParameter.ActualValue;
+        if (iteration != null) {
+          string iterationName = IterationsParameter.ActualName;
+          if (iterationName.EndsWith("s")) iterationName = iterationName.Remove(iterationName.Length - 1);
+          string appendix = " at " + iterationName + " " + iteration.Value.ToString();
+          table.Name += appendix;
+          table.Rows["QualityDistribution"].VisualProperties.DisplayName += appendix;
+        }
+        qdHistory.Add(table);
+      }
+      return base.Apply();
+    }
+  }
+}
Index: branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/QualityAnalysis/ScaledQualityDifferenceAnalyzer.cs
===================================================================
--- branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/QualityAnalysis/ScaledQualityDifferenceAnalyzer.cs	(revision 9280)
+++ branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/QualityAnalysis/ScaledQualityDifferenceAnalyzer.cs	(revision 9280)
@@ -0,0 +1,102 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 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.Optimization;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Analysis.QualityAnalysis {
+  [Item("ScaledQualityDifferenceAnalyzer", @"Calculates the quality value relative to a certain range given with a minimum and a maximum value.
+The difference lies in the interval [0;1] if the range [min;max] is as large as the observed quality values, otherwise the difference will become < 0 or > 1.
+A value towards 0 always means that it's closer to the better fitness value, while a value towards 1 means that it's closer to the worse fitness value.")]
+  [StorableClass]
+  public class ScaledQualityDifferenceAnalyzer : SingleSuccessorOperator, IAnalyzer {
+    public virtual bool EnabledByDefault {
+      get { return true; }
+    }
+
+    public ILookupParameter<DoubleValue> QualityParameter {
+      get { return (ILookupParameter<DoubleValue>)Parameters["Quality"]; }
+    }
+    public ILookupParameter<BoolValue> MaximizationParameter {
+      get { return (ILookupParameter<BoolValue>)Parameters["Maximization"]; }
+    }
+    public ILookupParameter<DoubleValue> ScaledDifferenceParameter {
+      get { return (ILookupParameter<DoubleValue>)Parameters["ScaledDifference"]; }
+    }
+    public ILookupParameter<ResultCollection> ResultsParameter {
+      get { return (ILookupParameter<ResultCollection>)Parameters["Results"]; }
+    }
+    public IValueLookupParameter<DoubleValue> MinimumQualityParameter {
+      get { return (IValueLookupParameter<DoubleValue>)Parameters["MinimumQuality"]; }
+    }
+    public IValueLookupParameter<DoubleValue> MaximumQualityParameter {
+      get { return (IValueLookupParameter<DoubleValue>)Parameters["MaximumQuality"]; }
+    }
+
+    [StorableConstructor]
+    protected ScaledQualityDifferenceAnalyzer(bool deserializing) : base(deserializing) { }
+    protected ScaledQualityDifferenceAnalyzer(ScaledQualityDifferenceAnalyzer original, Cloner cloner) : base(original, cloner) { }
+    public ScaledQualityDifferenceAnalyzer()
+      : base() {
+      Parameters.Add(new LookupParameter<DoubleValue>("Quality", "The quality value that should be compared."));
+      Parameters.Add(new LookupParameter<BoolValue>("Maximization", "True if the problem is a maximization problem, false otherwise."));
+      Parameters.Add(new LookupParameter<DoubleValue>("ScaledDifference", "The value that describes whether the quality value lies towards the better quality in the range (<=0.5) or more towards the worse quality (> 0.5)."));
+      Parameters.Add(new LookupParameter<ResultCollection>("Results", "The result collection where the difference will be stored (in addition to the scope)."));
+      Parameters.Add(new ValueLookupParameter<DoubleValue>("MinimumQuality", "The lower bound of the quality range to which the quality is compared."));
+      Parameters.Add(new ValueLookupParameter<DoubleValue>("MaximumQuality", "The upper bound of the quality range to which the quality is compared."));
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new ScaledQualityDifferenceAnalyzer(this, cloner);
+    }
+
+    public override IOperation Apply() {
+      bool maximization = MaximizationParameter.ActualValue.Value;
+      double quality = QualityParameter.ActualValue.Value, max = MaximumQualityParameter.ActualValue.Value, min = MinimumQualityParameter.ActualValue.Value;
+      double difference;
+
+      difference = ((quality - min) / (max - min));
+      if (maximization) difference = 1.0 - difference;
+
+      DoubleValue differenceValue = ScaledDifferenceParameter.ActualValue;
+      if (differenceValue == null) {
+        differenceValue = new DoubleValue(difference);
+        ScaledDifferenceParameter.ActualValue = differenceValue;
+      } else differenceValue.Value = difference;
+
+      ResultCollection results = ResultsParameter.ActualValue;
+      if (results != null) {
+        IResult r;
+        if (!results.TryGetValue(ScaledDifferenceParameter.TranslatedName, out r)) {
+          r = new Result(ScaledDifferenceParameter.TranslatedName, differenceValue);
+          results.Add(r);
+        }
+      }
+
+      return base.Apply();
+    }
+  }
+}
Index: branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/ValueAnalysis/MinAverageMaxValueAnalyzer.cs
===================================================================
--- branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/ValueAnalysis/MinAverageMaxValueAnalyzer.cs	(revision 9280)
+++ branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/ValueAnalysis/MinAverageMaxValueAnalyzer.cs	(revision 9280)
@@ -0,0 +1,228 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 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
+    public bool EnabledByDefault {
+      get { return true; }
+    }
+    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);
+      RegisterEventHandlers();
+    }
+    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
+
+      RegisterEventHandlers();
+    }
+
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() {
+      RegisterEventHandlers();
+    }
+
+    private void RegisterEventHandlers() {
+      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: branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/ValueAnalysis/MinAverageMaxValueCalculator.cs
===================================================================
--- branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/ValueAnalysis/MinAverageMaxValueCalculator.cs	(revision 9280)
+++ branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/ValueAnalysis/MinAverageMaxValueCalculator.cs	(revision 9280)
@@ -0,0 +1,89 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 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: branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/ValueAnalysis/SingleValueAnalyzer.cs
===================================================================
--- branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/ValueAnalysis/SingleValueAnalyzer.cs	(revision 9280)
+++ branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/ValueAnalysis/SingleValueAnalyzer.cs	(revision 9280)
@@ -0,0 +1,97 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 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.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 (current scope and parents).
+  /// </summary>
+  [Item("SingleValueAnalyzer", "An operator which analyzes a value in the scope tree (current scope and parents).")]
+  [StorableClass]
+  public sealed class SingleValueAnalyzer : AlgorithmOperator, IAnalyzer {
+    #region Parameter properties
+    public ILookupParameter<DoubleValue> ValueParameter {
+      get { return (ILookupParameter<DoubleValue>)Parameters["Value"]; }
+    }
+    public IValueLookupParameter<DataTable> ValuesParameter {
+      get { return (IValueLookupParameter<DataTable>)Parameters["Values"]; }
+    }
+    public IValueLookupParameter<VariableCollection> ResultsParameter {
+      get { return (IValueLookupParameter<VariableCollection>)Parameters["Results"]; }
+    }
+    #endregion
+
+    #region Properties
+    public bool EnabledByDefault {
+      get { return true; }
+    }
+    private DataTableValuesCollector DataTableValuesCollector {
+      get { return (DataTableValuesCollector)OperatorGraph.InitialOperator; }
+    }
+    private ResultsCollector ResultsCollector {
+      get { return (ResultsCollector)DataTableValuesCollector.Successor; }
+    }
+    #endregion
+
+    #region Storing & Cloning
+    [StorableConstructor]
+    private SingleValueAnalyzer(bool deserializing) : base(deserializing) { }
+    private SingleValueAnalyzer(SingleValueAnalyzer original, Cloner cloner) : base(original, cloner) { }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new SingleValueAnalyzer(this, cloner);
+    }
+    #endregion
+    public SingleValueAnalyzer()
+      : base() {
+      #region Create parameters
+      Parameters.Add(new LookupParameter<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 LookupParameter<DoubleValue>("Value", null, ValueParameter.Name));
+      dataTableValuesCollector.DataTableParameter.ActualName = ValuesParameter.Name;
+
+      resultsCollector.CollectedValues.Add(new LookupParameter<DoubleValue>("Value", null, ValueParameter.Name));
+      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
+    }
+  }
+}
Index: branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/ValueAnalysis/ValueAnalyzer.cs
===================================================================
--- branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/ValueAnalysis/ValueAnalyzer.cs	(revision 9280)
+++ branches/ImprovingStringConvertibleMatrix/HeuristicLab.Analysis/3.3/ValueAnalysis/ValueAnalyzer.cs	(revision 9280)
@@ -0,0 +1,119 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 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 (current scope and children).")]
+  [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
+    public bool EnabledByDefault {
+      get { return true; }
+    }
+    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;
+    }
+  }
+}
