Index: trunk/sources/HeuristicLab.Optimization.Operators/3.3/SingleObjectiveSolutionSimilarityCalculator.cs
===================================================================
--- trunk/sources/HeuristicLab.Optimization.Operators/3.3/SingleObjectiveSolutionSimilarityCalculator.cs	(revision 12070)
+++ trunk/sources/HeuristicLab.Optimization.Operators/3.3/SingleObjectiveSolutionSimilarityCalculator.cs	(revision 12085)
@@ -32,17 +32,9 @@
   [StorableClass]
   public abstract class SingleObjectiveSolutionSimilarityCalculator : SolutionSimilarityCalculator, ISingleObjectiveSolutionSimilarityCalculator {
-    #region Properties
-    [Storable]
-    public string SolutionVariableName { get; set; }
-    [Storable]
-    public string QualityVariableName { get; set; }
-    #endregion
-
     [StorableConstructor]
     protected SingleObjectiveSolutionSimilarityCalculator(bool deserializing) : base(deserializing) { }
     protected SingleObjectiveSolutionSimilarityCalculator(SingleObjectiveSolutionSimilarityCalculator original, Cloner cloner)
       : base(original, cloner) {
-      this.SolutionVariableName = original.SolutionVariableName;
-      this.QualityVariableName = original.QualityVariableName;
+
     }
     protected SingleObjectiveSolutionSimilarityCalculator() : base() { }
Index: trunk/sources/HeuristicLab.Optimization.Operators/3.3/SolutionSimilarityCalculator.cs
===================================================================
--- trunk/sources/HeuristicLab.Optimization.Operators/3.3/SolutionSimilarityCalculator.cs	(revision 12070)
+++ trunk/sources/HeuristicLab.Optimization.Operators/3.3/SolutionSimilarityCalculator.cs	(revision 12085)
@@ -24,4 +24,5 @@
 using HeuristicLab.Common;
 using HeuristicLab.Core;
+using HeuristicLab.Data;
 using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
 
@@ -35,7 +36,19 @@
     protected abstract bool IsCommutative { get; }
 
+    #region Properties
+    [Storable]
+    public string SolutionVariableName { get; set; }
+    [Storable]
+    public string QualityVariableName { get; set; }
+    #endregion
+
     [StorableConstructor]
     protected SolutionSimilarityCalculator(bool deserializing) : base(deserializing) { }
-    protected SolutionSimilarityCalculator(SolutionSimilarityCalculator original, Cloner cloner) : base(original, cloner) { }
+
+    protected SolutionSimilarityCalculator(SolutionSimilarityCalculator original, Cloner cloner)
+      : base(original, cloner) {
+      this.SolutionVariableName = original.SolutionVariableName;
+      this.QualityVariableName = original.QualityVariableName;
+    }
     protected SolutionSimilarityCalculator() : base() { }
 
@@ -93,6 +106,49 @@
 
     public abstract double CalculateSolutionSimilarity(IScope leftSolution, IScope rightSolution);
-    public abstract bool Equals(IScope x, IScope y);
-    public abstract int GetHashCode(IScope obj);
+
+    public virtual bool Equals(IScope x, IScope y) {
+      if (ReferenceEquals(x, y)) return true;
+      if (x == null || y == null) return false;
+
+      var q1 = x.Variables[QualityVariableName];
+      var q2 = x.Variables[QualityVariableName];
+
+      return CheckQualityEquality(q1, q2) && CalculateSolutionSimilarity(x, y).IsAlmost(1.0);
+    }
+
+    public virtual int GetHashCode(IScope scope) {
+      var quality = scope.Variables[QualityVariableName].Value;
+      var dv = quality as DoubleValue;
+      if (dv != null)
+        return dv.Value.GetHashCode();
+
+      var da = quality as DoubleArray;
+      if (da != null) {
+        int hash = 17;
+        unchecked {
+          for (int i = 0; i < da.Length; ++i) {
+            hash += hash * 23 + da[i].GetHashCode();
+          }
+          return hash;
+        }
+      }
+      return 0; // throw exception?
+    }
+
+    private static bool CheckQualityEquality(IItem q1, IItem q2) {
+      var d1 = q1 as DoubleValue;
+      var d2 = q2 as DoubleValue;
+
+      if (d1 != null && d2 != null)
+        return d1.Value.IsAlmost(d2.Value);
+
+      var da1 = q1 as DoubleArray;
+      var da2 = q2 as DoubleArray;
+
+      if (da1 != null && da2 != null)
+        return da1.SequenceEqual(da2);
+
+      throw new ArgumentException("Could not determine quality equality.");
+    }
   }
 }
