Index: /trunk/sources/HeuristicLab.Algorithms.LocalSearch/3.3/LocalSearchImprovementOperator.cs
===================================================================
--- /trunk/sources/HeuristicLab.Algorithms.LocalSearch/3.3/LocalSearchImprovementOperator.cs	(revision 12068)
+++ /trunk/sources/HeuristicLab.Algorithms.LocalSearch/3.3/LocalSearchImprovementOperator.cs	(revision 12069)
@@ -251,5 +251,5 @@
         foreach (IAnalyzer analyzer in problem.Operators.OfType<IAnalyzer>()) {
           if (!IsSubclassOfGeneric(typeof(AlleleFrequencyAnalyzer<>), analyzer.GetType()) &&
-              !(analyzer is SingleObjectivePopulationDiversityAnalyzer)) {
+              !(analyzer is PopulationSimilarityAnalyzer)) {
             IAnalyzer clone = analyzer.Clone() as IAnalyzer;
             foreach (IScopeTreeLookupParameter param in clone.Parameters.OfType<IScopeTreeLookupParameter>())
Index: /trunk/sources/HeuristicLab.Algorithms.RAPGA/3.3/DuplicatesSelector.cs
===================================================================
--- /trunk/sources/HeuristicLab.Algorithms.RAPGA/3.3/DuplicatesSelector.cs	(revision 12068)
+++ /trunk/sources/HeuristicLab.Algorithms.RAPGA/3.3/DuplicatesSelector.cs	(revision 12069)
@@ -25,4 +25,5 @@
 using HeuristicLab.Core;
 using HeuristicLab.Optimization;
+using HeuristicLab.Parameters;
 using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
 using HeuristicLab.Selection;
@@ -37,20 +38,28 @@
   [Item("DuplicatesSelector", "A selection operator which considers a single solution representation and selects duplicates. The remaining scope then contains unique solutions and the selected scope their duplicates.")]
   [StorableClass]
-  public sealed class DuplicatesSelector : SingleObjectiveSelector, ISimilarityBasedOperator {
-    #region ISimilarityBasedOperator Members
-    [Storable]
-    public ISolutionSimilarityCalculator SimilarityCalculator { get; set; }
-    #endregion
+  public sealed class DuplicatesSelector : SingleObjectiveSelector {
+    public IValueLookupParameter<ISolutionSimilarityCalculator> SimilarityCalculatorParameter {
+      get { return (IValueLookupParameter<ISolutionSimilarityCalculator>)Parameters["SimilarityCalculator"]; }
+    }
 
     [StorableConstructor]
     private DuplicatesSelector(bool deserializing) : base(deserializing) { }
-    private DuplicatesSelector(DuplicatesSelector original, Cloner cloner)
-      : base(original, cloner) {
-      this.SimilarityCalculator = cloner.Clone(original.SimilarityCalculator);
+    private DuplicatesSelector(DuplicatesSelector original, Cloner cloner) : base(original, cloner) { }
+    public DuplicatesSelector()
+      : base() {
+      Parameters.Add(new ValueLookupParameter<ISolutionSimilarityCalculator>("SimilarityCalculator", "The similarity calculator that should be used to calculate solution similarity."));
     }
-    public DuplicatesSelector() : base() { }
 
     public override IDeepCloneable Clone(Cloner cloner) {
       return new DuplicatesSelector(this, cloner);
+    }
+
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() {
+      // BackwardsCompatibility3.3
+      #region Backwards compatible code, remove with 3.4
+      if (!Parameters.ContainsKey("SimilarityCalculator"))
+        Parameters.Add(new ValueLookupParameter<ISolutionSimilarityCalculator>("SimilarityCalculator", "The similarity calculator that should be used to calculate solution similarity."));
+      #endregion
     }
 
@@ -61,5 +70,5 @@
       for (int i = 0; i < scopes.Count; i++)
         for (int j = i + 1; j < scopes.Count; j++)
-          marks[j] = SimilarityCalculator.Equals(scopes[i], scopes[j]);
+          marks[j] = SimilarityCalculatorParameter.ActualValue.Equals(scopes[i], scopes[j]);
 
 
Index: /trunk/sources/HeuristicLab.Algorithms.RAPGA/3.3/ProgressiveOffspringPreserver.cs
===================================================================
--- /trunk/sources/HeuristicLab.Algorithms.RAPGA/3.3/ProgressiveOffspringPreserver.cs	(revision 12068)
+++ /trunk/sources/HeuristicLab.Algorithms.RAPGA/3.3/ProgressiveOffspringPreserver.cs	(revision 12069)
@@ -38,10 +38,5 @@
   [Item("ProgressiveOffspringPreserver", "An operator that progressively selects offspring by adding it to a scope list. The operator also performs duplication control.")]
   [StorableClass]
-  public sealed class ProgressiveOffspringPreserver : SingleSuccessorOperator, ISimilarityBasedOperator {
-    #region ISimilarityBasedOperator Members
-    [Storable]
-    public ISolutionSimilarityCalculator SimilarityCalculator { get; set; }
-    #endregion
-
+  public sealed class ProgressiveOffspringPreserver : SingleSuccessorOperator {
     #region Parameter Properties
     public ScopeParameter CurrentScopeParameter {
@@ -56,4 +51,7 @@
     public ILookupParameter<IntValue> MaximumPopulationSizeParameter {
       get { return (ILookupParameter<IntValue>)Parameters["MaximumPopulationSize"]; }
+    }
+    public IValueLookupParameter<ISolutionSimilarityCalculator> SimilarityCalculatorParameter {
+      get { return (IValueLookupParameter<ISolutionSimilarityCalculator>)Parameters["SimilarityCalculator"]; }
     }
     #endregion
@@ -76,18 +74,27 @@
     [StorableConstructor]
     private ProgressiveOffspringPreserver(bool deserializing) : base(deserializing) { }
-    private ProgressiveOffspringPreserver(ProgressiveOffspringPreserver original, Cloner cloner)
-      : base(original, cloner) {
-      this.SimilarityCalculator = cloner.Clone(original.SimilarityCalculator);
-    }
+    private ProgressiveOffspringPreserver(ProgressiveOffspringPreserver original, Cloner cloner) : base(original, cloner) { }
     public ProgressiveOffspringPreserver()
       : base() {
+      #region Create parameters
       Parameters.Add(new ScopeParameter("CurrentScope", "The current scope that contains the offspring."));
       Parameters.Add(new LookupParameter<ScopeList>("OffspringList", "The list that contains the offspring."));
       Parameters.Add(new LookupParameter<IntValue>("Elites", "The numer of elite solutions which are kept in each generation."));
       Parameters.Add(new LookupParameter<IntValue>("MaximumPopulationSize", "The maximum size of the population of solutions."));
+      Parameters.Add(new ValueLookupParameter<ISolutionSimilarityCalculator>("SimilarityCalculator", "The similarity calculator that should be used to calculate solution similarity."));
+      #endregion
     }
 
     public override IDeepCloneable Clone(Cloner cloner) {
       return new ProgressiveOffspringPreserver(this, cloner);
+    }
+
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() {
+      // BackwardsCompatibility3.3
+      #region Backwards compatible code, remove with 3.4
+      if (!Parameters.ContainsKey("SimilarityCalculator"))
+        Parameters.Add(new ValueLookupParameter<ISolutionSimilarityCalculator>("SimilarityCalculator", "The similarity calculator that should be used to calculate solution similarity."));
+      #endregion
     }
 
@@ -98,5 +105,5 @@
           var storedOffspringScope = new Scope();
           storedOffspringScope.SubScopes.AddRange(OffspringList);
-          var similarityMatrix = SimilarityCalculator.CalculateSolutionCrowdSimilarity(CurrentScope, storedOffspringScope);
+          var similarityMatrix = SimilarityCalculatorParameter.ActualValue.CalculateSolutionCrowdSimilarity(CurrentScope, storedOffspringScope);
 
           var createdOffspring = CurrentScope.SubScopes.ToArray();
Index: /trunk/sources/HeuristicLab.Algorithms.RAPGA/3.3/RAPGA.cs
===================================================================
--- /trunk/sources/HeuristicLab.Algorithms.RAPGA/3.3/RAPGA.cs	(revision 12068)
+++ /trunk/sources/HeuristicLab.Algorithms.RAPGA/3.3/RAPGA.cs	(revision 12069)
@@ -394,6 +394,4 @@
       RAPGAMainLoop.MaximizationParameter.ActualName = Problem.MaximizationParameter.Name;
       RAPGAMainLoop.QualityParameter.ActualName = Problem.Evaluator.QualityParameter.ActualName;
-      foreach (ISimilarityBasedOperator op in RAPGAMainLoop.OperatorGraph.Operators.OfType<ISimilarityBasedOperator>())
-        op.SimilarityCalculator = SimilarityCalculator;
     }
     private void ParameterizeStochasticOperator(IOperator op) {
Index: /trunk/sources/HeuristicLab.Algorithms.ScatterSearch/3.3/ReferenceSetUpdateMethod.cs
===================================================================
--- /trunk/sources/HeuristicLab.Algorithms.ScatterSearch/3.3/ReferenceSetUpdateMethod.cs	(revision 12068)
+++ /trunk/sources/HeuristicLab.Algorithms.ScatterSearch/3.3/ReferenceSetUpdateMethod.cs	(revision 12069)
@@ -36,10 +36,5 @@
   [Item("ReferenceSetUpdateMethod", "An operator that updates the reference set.")]
   [StorableClass]
-  public sealed class ReferenceSetUpdateMethod : SingleSuccessorOperator, ISimilarityBasedOperator {
-    #region ISimilarityBasedOperator Members
-    [Storable]
-    public ISolutionSimilarityCalculator SimilarityCalculator { get; set; }
-    #endregion
-
+  public sealed class ReferenceSetUpdateMethod : SingleSuccessorOperator {
     #region Parameter properties
     public ScopeParameter CurrentScopeParameter {
@@ -48,4 +43,7 @@
     public IValueLookupParameter<IntValue> ReferenceSetSizeParameter {
       get { return (IValueLookupParameter<IntValue>)Parameters["ReferenceSetSize"]; }
+    }
+    public IValueLookupParameter<ISolutionSimilarityCalculator> SimilarityCalculatorParameter {
+      get { return (IValueLookupParameter<ISolutionSimilarityCalculator>)Parameters["SimilarityCalculator"]; }
     }
     #endregion
@@ -62,8 +60,5 @@
     [StorableConstructor]
     private ReferenceSetUpdateMethod(bool deserializing) : base(deserializing) { }
-    private ReferenceSetUpdateMethod(ReferenceSetUpdateMethod original, Cloner cloner)
-      : base(original, cloner) {
-      this.SimilarityCalculator = cloner.Clone(original.SimilarityCalculator);
-    }
+    private ReferenceSetUpdateMethod(ReferenceSetUpdateMethod original, Cloner cloner) : base(original, cloner) { }
     public ReferenceSetUpdateMethod()
       : base() {
@@ -71,4 +66,5 @@
       Parameters.Add(new ScopeParameter("CurrentScope", "The current scope that contains the population and the reference set."));
       Parameters.Add(new ValueLookupParameter<IntValue>("ReferenceSetSize", "The size of the reference set."));
+      Parameters.Add(new ValueLookupParameter<ISolutionSimilarityCalculator>("SimilarityCalculator", "The similarity calculator that should be used to calculate solution similarity."));
       #endregion
     }
@@ -78,9 +74,18 @@
     }
 
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() {
+      // BackwardsCompatibility3.3
+      #region Backwards compatible code, remove with 3.4
+      if (!Parameters.ContainsKey("SimilarityCalculator"))
+        Parameters.Add(new ValueLookupParameter<ISolutionSimilarityCalculator>("SimilarityCalculator", "The similarity calculator that should be used to calculate solution similarity."));
+      #endregion
+    }
+
     public override IOperation Apply() {
       var populationSimilarity = new Dictionary<IScope, double>();
       var populationScope = CurrentScope.SubScopes[0];
       var refSetScope = CurrentScope.SubScopes[1];
-      var similarityMatrix = SimilarityCalculator.CalculateSolutionCrowdSimilarity(populationScope, refSetScope);
+      var similarityMatrix = SimilarityCalculatorParameter.ActualValue.CalculateSolutionCrowdSimilarity(populationScope, refSetScope);
       for (int i = 0; i < populationScope.SubScopes.Count; i++) {
         populationSimilarity[populationScope.SubScopes[i]] = similarityMatrix[i].Sum();
Index: /trunk/sources/HeuristicLab.Algorithms.ScatterSearch/3.3/ScatterSearch.cs
===================================================================
--- /trunk/sources/HeuristicLab.Algorithms.ScatterSearch/3.3/ScatterSearch.cs	(revision 12068)
+++ /trunk/sources/HeuristicLab.Algorithms.ScatterSearch/3.3/ScatterSearch.cs	(revision 12069)
@@ -423,6 +423,4 @@
         MainLoop.OperatorGraph.Operators.OfType<PopulationRebuildMethod>().Single().QualityParameter.ActualName = Problem.Evaluator.QualityParameter.ActualName;
         MainLoop.OperatorGraph.Operators.OfType<SolutionPoolUpdateMethod>().Single().QualityParameter.ActualName = Problem.Evaluator.QualityParameter.ActualName;
-        foreach (ISimilarityBasedOperator op in MainLoop.OperatorGraph.Operators.OfType<ISimilarityBasedOperator>())
-          op.SimilarityCalculator = SimilarityCalculator;
       }
     }
Index: /trunk/sources/HeuristicLab.Algorithms.ScatterSearch/3.3/SolutionPoolUpdateMethod.cs
===================================================================
--- /trunk/sources/HeuristicLab.Algorithms.ScatterSearch/3.3/SolutionPoolUpdateMethod.cs	(revision 12068)
+++ /trunk/sources/HeuristicLab.Algorithms.ScatterSearch/3.3/SolutionPoolUpdateMethod.cs	(revision 12069)
@@ -36,10 +36,5 @@
   [Item("SolutionPoolUpdateMethod", "An operator that updates the solution pool.")]
   [StorableClass]
-  public sealed class SolutionPoolUpdateMethod : SingleSuccessorOperator, ISimilarityBasedOperator, ISingleObjectiveOperator {
-    #region ISimilarityBasedOperator Members
-    [Storable]
-    public ISolutionSimilarityCalculator SimilarityCalculator { get; set; }
-    #endregion
-
+  public sealed class SolutionPoolUpdateMethod : SingleSuccessorOperator, ISingleObjectiveOperator {
     #region Parameter properties
     public ScopeParameter CurrentScopeParameter {
@@ -57,4 +52,7 @@
     public IValueLookupParameter<IntValue> ReferenceSetSizeParameter {
       get { return (IValueLookupParameter<IntValue>)Parameters["ReferenceSetSize"]; }
+    }
+    public IValueLookupParameter<ISolutionSimilarityCalculator> SimilarityCalculatorParameter {
+      get { return (IValueLookupParameter<ISolutionSimilarityCalculator>)Parameters["SimilarityCalculator"]; }
     }
     #endregion
@@ -82,15 +80,7 @@
     [StorableConstructor]
     private SolutionPoolUpdateMethod(bool deserializing) : base(deserializing) { }
-    private SolutionPoolUpdateMethod(SolutionPoolUpdateMethod original, Cloner cloner)
-      : base(original, cloner) {
-      this.SimilarityCalculator = cloner.Clone(original.SimilarityCalculator);
-    }
-    public SolutionPoolUpdateMethod() : base() { Initialize(); }
-
-    public override IDeepCloneable Clone(Cloner cloner) {
-      return new SolutionPoolUpdateMethod(this, cloner);
-    }
-
-    private void Initialize() {
+    private SolutionPoolUpdateMethod(SolutionPoolUpdateMethod original, Cloner cloner) : base(original, cloner) { }
+    public SolutionPoolUpdateMethod()
+      : base() {
       #region Create parameters
       Parameters.Add(new ScopeParameter("CurrentScope", "The current scope that is the reference set."));
@@ -99,4 +89,18 @@
       Parameters.Add(new ValueLookupParameter<IItem>("Quality", "This parameter is used for name translation only."));
       Parameters.Add(new ValueLookupParameter<IntValue>("ReferenceSetSize", "The size of the reference set."));
+      Parameters.Add(new ValueLookupParameter<ISolutionSimilarityCalculator>("SimilarityCalculator", "The similarity calculator that should be used to calculate solution similarity."));
+      #endregion
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new SolutionPoolUpdateMethod(this, cloner);
+    }
+
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() {
+      // BackwardsCompatibility3.3
+      #region Backwards compatible code, remove with 3.4
+      if (!Parameters.ContainsKey("SimilarityCalculator"))
+        Parameters.Add(new ValueLookupParameter<ISolutionSimilarityCalculator>("SimilarityCalculator", "The similarity calculator that should be used to calculate solution similarity."));
       #endregion
     }
@@ -132,5 +136,5 @@
       if (orderedOffspring.Any(hasBetterQuality)) {
         // produce the set union
-        var union = orderedParents.Union(orderedOffspring.Where(hasBetterQuality), SimilarityCalculator);
+        var union = orderedParents.Union(orderedOffspring.Where(hasBetterQuality), SimilarityCalculatorParameter.ActualValue);
         if (union.Count() > orderedParents.Count()) {
           var orderedUnion = Maximization.Value ? union.OrderByDescending(x => x.Variables[QualityParameter.ActualName].Value) :
Index: /trunk/sources/HeuristicLab.Algorithms.SimulatedAnnealing/3.3/SimulatedAnnealingImprovementOperator.cs
===================================================================
--- /trunk/sources/HeuristicLab.Algorithms.SimulatedAnnealing/3.3/SimulatedAnnealingImprovementOperator.cs	(revision 12068)
+++ /trunk/sources/HeuristicLab.Algorithms.SimulatedAnnealing/3.3/SimulatedAnnealingImprovementOperator.cs	(revision 12069)
@@ -279,5 +279,5 @@
         foreach (IAnalyzer analyzer in problem.Operators.OfType<IAnalyzer>()) {
           if (!IsSubclassOfGeneric(typeof(AlleleFrequencyAnalyzer<>), analyzer.GetType()) &&
-              !(analyzer is SingleObjectivePopulationDiversityAnalyzer)) {
+              !(analyzer is PopulationSimilarityAnalyzer)) {
             IAnalyzer clone = analyzer.Clone() as IAnalyzer;
             foreach (IScopeTreeLookupParameter param in clone.Parameters.OfType<IScopeTreeLookupParameter>())
Index: /trunk/sources/HeuristicLab.Analysis/3.3/HeuristicLab.Analysis-3.3.csproj
===================================================================
--- /trunk/sources/HeuristicLab.Analysis/3.3/HeuristicLab.Analysis-3.3.csproj	(revision 12068)
+++ /trunk/sources/HeuristicLab.Analysis/3.3/HeuristicLab.Analysis-3.3.csproj	(revision 12069)
@@ -148,6 +148,7 @@
     <Compile Include="MultiObjective\ParetoFrontAnalyzer.cs" />
     <Compile Include="Plugin.cs" />
-    <Compile Include="PopulationDiversityAnalysis\PopulationDiversityAnalyzer.cs" />
-    <Compile Include="PopulationDiversityAnalysis\SingleObjectivePopulationDiversityAnalyzer.cs" />
+    <Compile Include="PopulationSimilarityAnalysis\PopulationDiversityAnalyzer.cs" />
+    <Compile Include="PopulationSimilarityAnalysis\PopulationSimilarityAnalyzer.cs" />
+    <Compile Include="PopulationSimilarityAnalysis\SingleObjectivePopulationDiversityAnalyzer.cs" />
     <Compile Include="QualityAnalysis\BestAverageWorstQualityAnalyzer.cs" />
     <Compile Include="QualityAnalysis\BestAverageWorstQualityCalculator.cs" />
Index: /trunk/sources/HeuristicLab.Analysis/3.3/PopulationSimilarityAnalysis/PopulationDiversityAnalyzer.cs
===================================================================
--- /trunk/sources/HeuristicLab.Analysis/3.3/PopulationSimilarityAnalysis/PopulationDiversityAnalyzer.cs	(revision 12069)
+++ /trunk/sources/HeuristicLab.Analysis/3.3/PopulationSimilarityAnalysis/PopulationDiversityAnalyzer.cs	(revision 12069)
@@ -0,0 +1,252 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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, ISingleObjectiveOperator 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: /trunk/sources/HeuristicLab.Analysis/3.3/PopulationSimilarityAnalysis/PopulationSimilarityAnalyzer.cs
===================================================================
--- /trunk/sources/HeuristicLab.Analysis/3.3/PopulationSimilarityAnalysis/PopulationSimilarityAnalyzer.cs	(revision 12069)
+++ /trunk/sources/HeuristicLab.Analysis/3.3/PopulationSimilarityAnalysis/PopulationSimilarityAnalyzer.cs	(revision 12069)
@@ -0,0 +1,266 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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 solution similarity in a population.
+  /// </summary>
+  [Item("PopulationSimilarityAnalyzer", "An operator for analyzing the solution similarity in a population.")]
+  [StorableClass]
+  public class PopulationSimilarityAnalyzer : SingleSuccessorOperator, IAnalyzer, ISimilarityBasedOperator {
+    private const string DiversityResultNameParameterName = "DiversityResultsName";
+
+    #region Backwards compatible code, remove with 3.4
+    private ISolutionSimilarityCalculator oldSimilarityCalculator;
+    [Storable(AllowOneWay = true, Name = "SimilarityCalculator")]
+    [Obsolete]
+    private ISolutionSimilarityCalculator SimilarityCalculator { set { oldSimilarityCalculator = value; } }
+    #endregion
+
+    public virtual bool EnabledByDefault {
+      get { return false; }
+    }
+    public ScopeParameter CurrentScopeParameter {
+      get { return (ScopeParameter)Parameters["CurrentScope"]; }
+    }
+    public IValueLookupParameter<ResultCollection> ResultsParameter {
+      get { return (IValueLookupParameter<ResultCollection>)Parameters["Results"]; }
+    }
+    public IConstrainedValueParameter<ISolutionSimilarityCalculator> SimilarityCalculatorParameter {
+      get { return (IConstrainedValueParameter<ISolutionSimilarityCalculator>)Parameters["SimilarityCalculator"]; }
+    }
+    public IValueParameter<BoolValue> StoreHistoryParameter {
+      get { return (IValueParameter<BoolValue>)Parameters["StoreHistory"]; }
+    }
+    public IValueParameter<IntValue> UpdateIntervalParameter {
+      get { return (IValueParameter<IntValue>)Parameters["UpdateInterval"]; }
+    }
+    public ILookupParameter<IntValue> UpdateCounterParameter {
+      get { return (ILookupParameter<IntValue>)Parameters["UpdateCounter"]; }
+    }
+    public IFixedValueParameter<StringValue> DiversityResultNameParameter {
+      get { return (FixedValueParameter<StringValue>)Parameters[DiversityResultNameParameterName]; }
+    }
+
+    public string DiversityResultName {
+      get { return DiversityResultNameParameter.Value.Value; }
+      set { DiversityResultNameParameter.Value.Value = value; }
+    }
+
+    [StorableConstructor]
+    protected PopulationSimilarityAnalyzer(bool deserializing) : base(deserializing) { }
+    protected PopulationSimilarityAnalyzer(PopulationSimilarityAnalyzer original, Cloner cloner) : base(original, cloner) { }
+    public PopulationSimilarityAnalyzer(IEnumerable<ISolutionSimilarityCalculator> validSimilarityCalculators)
+      : base() {
+      Parameters.Add(new ScopeParameter("CurrentScope", "The current scope that contains 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 ConstrainedValueParameter<ISolutionSimilarityCalculator>("SimilarityCalculator", "The similarity calculator that should be used to calculate population similarity."));
+      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"));
+      Parameters.Add(new FixedValueParameter<StringValue>(DiversityResultNameParameterName, "Specifies how the diversity results should be named.", new StringValue("PopulationDiversity")));
+
+      var similarityCalculators = SimilarityCalculatorParameter.ValidValues;
+      foreach (var sc in validSimilarityCalculators)
+        similarityCalculators.Add(sc);
+
+
+      ResultsParameter.Hidden = true;
+      UpdateCounterParameter.Hidden = true;
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new PopulationSimilarityAnalyzer(this, cloner);
+    }
+
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() {
+      // BackwardsCompatibility3.3
+      #region Backwards compatible code, remove with 3.4
+      if (!Parameters.ContainsKey(DiversityResultNameParameterName))
+        Parameters.Add(new FixedValueParameter<StringValue>(DiversityResultNameParameterName, "Specifies how the diversity results should be named.", new StringValue("PopulationDiversity")));
+
+      if (!Parameters.ContainsKey("SimilarityCalculator"))
+        Parameters.Add(new ConstrainedValueParameter<ISolutionSimilarityCalculator>("SimilarityCalculator", "The similarity calculator that should be used to calculate solution similarity."));
+
+      SimilarityCalculatorParameter.ValidValues.Add(oldSimilarityCalculator);
+      #endregion
+    }
+
+    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 storeHistory = StoreHistoryParameter.Value.Value;
+        int count = CurrentScopeParameter.ActualValue.SubScopes.Count;
+
+        if (count > 1) {
+          var similarityCalculator = SimilarityCalculatorParameter.Value;
+          // calculate solution similarities
+          var similarityMatrix = similarityCalculator.CalculateSolutionCrowdSimilarity(CurrentScopeParameter.ActualValue);
+          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(DiversityResultName)) {
+            results = new ResultCollection();
+            ResultsParameter.ActualValue.Add(new Result(DiversityResultName, results));
+          } else {
+            results = (ResultCollection)ResultsParameter.ActualValue[DiversityResultName].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: /trunk/sources/HeuristicLab.Analysis/3.3/PopulationSimilarityAnalysis/SingleObjectivePopulationDiversityAnalyzer.cs
===================================================================
--- /trunk/sources/HeuristicLab.Analysis/3.3/PopulationSimilarityAnalysis/SingleObjectivePopulationDiversityAnalyzer.cs	(revision 12069)
+++ /trunk/sources/HeuristicLab.Analysis/3.3/PopulationSimilarityAnalysis/SingleObjectivePopulationDiversityAnalyzer.cs	(revision 12069)
@@ -0,0 +1,49 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.PluginInfrastructure;
+
+namespace HeuristicLab.Analysis {
+  // use HeuristicLab.Analysis.PopulationSimilarityAnalyzer instead
+  // BackwardsCompatibility3.3
+  #region Backwards compatible code, remove with 3.4
+  /// <summary>
+  /// An operator for analyzing the solution diversity in a population.
+  /// </summary>
+  [Obsolete]
+  [NonDiscoverableType]
+  [Item("SingleObjectivePopulationDiversityAnalyzer", "An operator for analyzing the solution diversity in a population.")]
+  [StorableClass]
+  public class SingleObjectivePopulationDiversityAnalyzer : PopulationSimilarityAnalyzer {
+    [StorableConstructor]
+    protected SingleObjectivePopulationDiversityAnalyzer(bool deserializing) : base(deserializing) { }
+    protected SingleObjectivePopulationDiversityAnalyzer(SingleObjectivePopulationDiversityAnalyzer original, Cloner cloner) : base(original, cloner) { }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new SingleObjectivePopulationDiversityAnalyzer(this, cloner);
+    }
+  }
+  #endregion
+}
Index: /trunk/sources/HeuristicLab.Optimization/3.3/Interfaces/ISimilarityBasedOperator.cs
===================================================================
--- /trunk/sources/HeuristicLab.Optimization/3.3/Interfaces/ISimilarityBasedOperator.cs	(revision 12068)
+++ /trunk/sources/HeuristicLab.Optimization/3.3/Interfaces/ISimilarityBasedOperator.cs	(revision 12069)
@@ -24,5 +24,5 @@
 namespace HeuristicLab.Optimization {
   public interface ISimilarityBasedOperator : IOperator {
-    ISolutionSimilarityCalculator SimilarityCalculator { get; set; }
+    IConstrainedValueParameter<ISolutionSimilarityCalculator> SimilarityCalculatorParameter { get; }
   }
 }
Index: /trunk/sources/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/SymbolicDataAnalysisProblem.cs
===================================================================
--- /trunk/sources/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/SymbolicDataAnalysisProblem.cs	(revision 12068)
+++ /trunk/sources/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/SymbolicDataAnalysisProblem.cs	(revision 12069)
@@ -233,5 +233,5 @@
       Operators.Add(new MinAverageMaxSymbolicExpressionTreeLengthAnalyzer());
       Operators.Add(new SymbolicExpressionTreeLengthAnalyzer());
-      Operators.Add(new SingleObjectivePopulationDiversityAnalyzer());
+      Operators.Add(new PopulationSimilarityAnalyzer(new[] { new SymbolicExpressionTreeBottomUpSimilarityCalculator() }));
       ParameterizeOperators();
     }
@@ -357,7 +357,4 @@
         op.SolutionVariableName = SolutionCreator.SymbolicExpressionTreeParameter.ActualName;
       }
-      foreach (var op in operators.OfType<SingleObjectivePopulationDiversityAnalyzer>()) {
-        op.SimilarityCalculator = new SymbolicExpressionTreeBottomUpSimilarityCalculator();
-      }
     }
 
Index: /trunk/sources/HeuristicLab.Problems.Knapsack/3.3/KnapsackProblem.cs
===================================================================
--- /trunk/sources/HeuristicLab.Problems.Knapsack/3.3/KnapsackProblem.cs	(revision 12068)
+++ /trunk/sources/HeuristicLab.Problems.Knapsack/3.3/KnapsackProblem.cs	(revision 12069)
@@ -82,6 +82,6 @@
       get { return Operators.OfType<BestKnapsackSolutionAnalyzer>().FirstOrDefault(); }
     }
-    private SingleObjectivePopulationDiversityAnalyzer SingleObjectivePopulationDiversityAnalyzer {
-      get { return Operators.OfType<SingleObjectivePopulationDiversityAnalyzer>().FirstOrDefault(); }
+    private PopulationSimilarityAnalyzer PopulationSimilarityAnalyzer {
+      get { return Operators.OfType<PopulationSimilarityAnalyzer>().FirstOrDefault(); }
     }
     #endregion
@@ -248,11 +248,4 @@
         BestKnapsackSolutionAnalyzer.ValuesParameter.Hidden = true;
       }
-
-      if (SingleObjectivePopulationDiversityAnalyzer != null) {
-        SingleObjectivePopulationDiversityAnalyzer.MaximizationParameter.ActualName = MaximizationParameter.Name;
-        SingleObjectivePopulationDiversityAnalyzer.QualityParameter.ActualName = Evaluator.QualityParameter.ActualName;
-        SingleObjectivePopulationDiversityAnalyzer.ResultsParameter.ActualName = "Results";
-        SingleObjectivePopulationDiversityAnalyzer.SimilarityCalculator = Operators.OfType<KnapsackSimilarityCalculator>().SingleOrDefault();
-      }
     }
     private void InitializeOperators() {
@@ -263,5 +256,5 @@
 
       Operators.Add(new BestKnapsackSolutionAnalyzer());
-      Operators.Add(new SingleObjectivePopulationDiversityAnalyzer());
+      Operators.Add(new PopulationSimilarityAnalyzer(Operators.OfType<ISolutionSimilarityCalculator>()));
       ParameterizeAnalyzer();
       foreach (IBinaryVectorOperator op in ApplicationManager.Manager.GetInstances<IBinaryVectorOperator>()) {
Index: /trunk/sources/HeuristicLab.Problems.TestFunctions/3.3/SingleObjectiveTestFunctionProblem.cs
===================================================================
--- /trunk/sources/HeuristicLab.Problems.TestFunctions/3.3/SingleObjectiveTestFunctionProblem.cs	(revision 12068)
+++ /trunk/sources/HeuristicLab.Problems.TestFunctions/3.3/SingleObjectiveTestFunctionProblem.cs	(revision 12069)
@@ -72,6 +72,6 @@
       get { return Operators.OfType<BestSingleObjectiveTestFunctionSolutionAnalyzer>().FirstOrDefault(); }
     }
-    private SingleObjectivePopulationDiversityAnalyzer SingleObjectivePopulationDiversityAnalyzer {
-      get { return Operators.OfType<SingleObjectivePopulationDiversityAnalyzer>().FirstOrDefault(); }
+    private PopulationSimilarityAnalyzer PopulationSimilarityAnalyzer {
+      get { return Operators.OfType<PopulationSimilarityAnalyzer>().FirstOrDefault(); }
     }
     #endregion
@@ -258,11 +258,4 @@
         BestSingleObjectiveTestFunctionSolutionAnalyzer.BoundsParameter.ActualName = BoundsParameter.Name;
       }
-
-      if (SingleObjectivePopulationDiversityAnalyzer != null) {
-        SingleObjectivePopulationDiversityAnalyzer.MaximizationParameter.ActualName = MaximizationParameter.Name;
-        SingleObjectivePopulationDiversityAnalyzer.QualityParameter.ActualName = Evaluator.QualityParameter.ActualName;
-        SingleObjectivePopulationDiversityAnalyzer.ResultsParameter.ActualName = "Results";
-        SingleObjectivePopulationDiversityAnalyzer.SimilarityCalculator = Operators.OfType<SingleObjectiveTestFunctionSimilarityCalculator>().SingleOrDefault();
-      }
     }
     private void InitializeOperators() {
@@ -272,5 +265,5 @@
 
       Operators.Add(new BestSingleObjectiveTestFunctionSolutionAnalyzer());
-      Operators.Add(new SingleObjectivePopulationDiversityAnalyzer());
+      Operators.Add(new PopulationSimilarityAnalyzer(Operators.OfType<ISolutionSimilarityCalculator>()));
       ParameterizeAnalyzers();
       Operators.AddRange(ApplicationManager.Manager.GetInstances<IRealVectorOperator>().Cast<IOperator>());
Index: /trunk/sources/HeuristicLab.Problems.TravelingSalesman/3.3/TravelingSalesmanProblem.cs
===================================================================
--- /trunk/sources/HeuristicLab.Problems.TravelingSalesman/3.3/TravelingSalesmanProblem.cs	(revision 12068)
+++ /trunk/sources/HeuristicLab.Problems.TravelingSalesman/3.3/TravelingSalesmanProblem.cs	(revision 12069)
@@ -82,6 +82,6 @@
       get { return Operators.OfType<TSPAlleleFrequencyAnalyzer>().FirstOrDefault(); }
     }
-    private SingleObjectivePopulationDiversityAnalyzer SingleObjectivePopulationDiversityAnalyzer {
-      get { return Operators.OfType<SingleObjectivePopulationDiversityAnalyzer>().FirstOrDefault(); }
+    private PopulationSimilarityAnalyzer PopulationSimilarityAnalyzer {
+      get { return Operators.OfType<PopulationSimilarityAnalyzer>().FirstOrDefault(); }
     }
     #endregion
@@ -239,5 +239,5 @@
       Operators.Add(new BestTSPSolutionAnalyzer());
       Operators.Add(new TSPAlleleFrequencyAnalyzer());
-      Operators.Add(new SingleObjectivePopulationDiversityAnalyzer());
+      Operators.Add(new PopulationSimilarityAnalyzer(Operators.OfType<ISolutionSimilarityCalculator>()));
       ParameterizeAnalyzers();
       var operators = new HashSet<IPermutationOperator>(new IPermutationOperator[] {
@@ -318,11 +318,4 @@
         TSPAlleleFrequencyAnalyzer.BestKnownSolutionParameter.ActualName = BestKnownSolutionParameter.Name;
         TSPAlleleFrequencyAnalyzer.ResultsParameter.ActualName = "Results";
-      }
-
-      if (SingleObjectivePopulationDiversityAnalyzer != null) {
-        SingleObjectivePopulationDiversityAnalyzer.MaximizationParameter.ActualName = MaximizationParameter.Name;
-        SingleObjectivePopulationDiversityAnalyzer.QualityParameter.ActualName = Evaluator.QualityParameter.ActualName;
-        SingleObjectivePopulationDiversityAnalyzer.ResultsParameter.ActualName = "Results";
-        SingleObjectivePopulationDiversityAnalyzer.SimilarityCalculator = Operators.OfType<TSPSimilarityCalculator>().SingleOrDefault();
       }
     }
Index: /trunk/sources/HeuristicLab.Problems.VehicleRouting/3.4/VehicleRoutingProblem.cs
===================================================================
--- /trunk/sources/HeuristicLab.Problems.VehicleRouting/3.4/VehicleRoutingProblem.cs	(revision 12068)
+++ /trunk/sources/HeuristicLab.Problems.VehicleRouting/3.4/VehicleRoutingProblem.cs	(revision 12069)
@@ -114,6 +114,6 @@
       set { SolutionCreatorParameter.Value = value; }
     }
-    private SingleObjectivePopulationDiversityAnalyzer SingleObjectivePopulationDiversityAnalyzer {
-      get { return Operators.OfType<SingleObjectivePopulationDiversityAnalyzer>().FirstOrDefault(); }
+    private PopulationSimilarityAnalyzer PopulationSimilarityAnalyzer {
+      get { return Operators.OfType<PopulationSimilarityAnalyzer>().FirstOrDefault(); }
     }
     #endregion
@@ -256,5 +256,5 @@
           ApplicationManager.Manager.GetInstances<IGeneralVRPOperator>().Cast<IOperator>()).OrderBy(op => op.Name));
         Operators.Add(new VRPSimilarityCalculator());
-        Operators.Add(new SingleObjectivePopulationDiversityAnalyzer());
+        Operators.Add(new PopulationSimilarityAnalyzer(Operators.OfType<ISolutionSimilarityCalculator>()));
 
         IVRPCreator defaultCreator = null;
@@ -291,10 +291,4 @@
           op.QualityVariableName = ProblemInstance.SolutionEvaluator.QualityParameter.ActualName;
           op.ProblemInstance = ProblemInstance;
-        }
-        if (SingleObjectivePopulationDiversityAnalyzer != null) {
-          SingleObjectivePopulationDiversityAnalyzer.MaximizationParameter.ActualName = MaximizationParameter.Name;
-          SingleObjectivePopulationDiversityAnalyzer.QualityParameter.ActualName = ProblemInstance.SolutionEvaluator.QualityParameter.ActualName;
-          SingleObjectivePopulationDiversityAnalyzer.ResultsParameter.ActualName = "Results";
-          SingleObjectivePopulationDiversityAnalyzer.SimilarityCalculator = Operators.OfType<VRPSimilarityCalculator>().SingleOrDefault();
         }
       }
