Index: branches/GP-MoveOperators/HeuristicLab.Optimization.Operators/3.3/HeuristicLab.Optimization.Operators-3.3.csproj
===================================================================
--- branches/GP-MoveOperators/HeuristicLab.Optimization.Operators/3.3/HeuristicLab.Optimization.Operators-3.3.csproj	(revision 8286)
+++ branches/GP-MoveOperators/HeuristicLab.Optimization.Operators/3.3/HeuristicLab.Optimization.Operators-3.3.csproj	(revision 8660)
@@ -105,7 +105,11 @@
     </Reference>
     <Reference Include="System.Data" />
+    <Reference Include="System.Drawing" />
     <Reference Include="System.Xml" />
   </ItemGroup>
   <ItemGroup>
+    <Compile Include="NoSimilarityCalculator.cs" />
+    <Compile Include="QualitySimilarityCalculator.cs" />
+    <Compile Include="SingleObjectiveSolutionSimilarityCalculator.cs" />
     <Compile Include="GeneralizedExponentialDiscreteDoubleValueModifier.cs" />
     <Compile Include="MultiObjective\CrowdedComparisonSorter.cs" />
@@ -114,6 +118,9 @@
     <Compile Include="MultiObjective\FastNonDominatedSort.cs" />
     <Compile Include="MultiObjective\RankAndCrowdingSorter.cs" />
+    <Compile Include="SingleObjectivePathRelinker.cs" />
     <Compile Include="Plugin.cs" />
+    <Compile Include="ProgrammableAnalyzer.cs" />
     <Compile Include="ShakingOperator.cs" />
+    <Compile Include="SolutionSimilarityCalculator.cs" />
     <Compile Include="UserDefinedCrossover.cs" />
     <Compile Include="UserDefinedEvaluator.cs" />
@@ -163,4 +170,9 @@
       <Private>False</Private>
     </ProjectReference>
+    <ProjectReference Include="..\..\HeuristicLab.Operators.Programmable\3.3\HeuristicLab.Operators.Programmable-3.3.csproj">
+      <Project>{6A5F8C2D-B0C3-4B36-BC20-9B1A91EE6DB6}</Project>
+      <Name>HeuristicLab.Operators.Programmable-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>
@@ -220,5 +232,5 @@
   -->
   <PropertyGroup>
-    <PreBuildEvent>set Path=%25Path%25;$(ProjectDir);$(SolutionDir)
+   <PreBuildEvent Condition=" '$(OS)' == 'Windows_NT' ">set Path=%25Path%25;$(ProjectDir);$(SolutionDir)
 set ProjectDir=$(ProjectDir)
 set SolutionDir=$(SolutionDir)
@@ -227,4 +239,10 @@
 call PreBuildEvent.cmd
 </PreBuildEvent>
+<PreBuildEvent Condition=" '$(OS)' != 'Windows_NT' ">
+export ProjectDir=$(ProjectDir)
+export SolutionDir=$(SolutionDir)
+
+$SolutionDir/PreBuildEvent.sh
+</PreBuildEvent>
   </PropertyGroup>
 </Project>
Index: branches/GP-MoveOperators/HeuristicLab.Optimization.Operators/3.3/NoSimilarityCalculator.cs
===================================================================
--- branches/GP-MoveOperators/HeuristicLab.Optimization.Operators/3.3/NoSimilarityCalculator.cs	(revision 8660)
+++ branches/GP-MoveOperators/HeuristicLab.Optimization.Operators/3.3/NoSimilarityCalculator.cs	(revision 8660)
@@ -0,0 +1,50 @@
+﻿#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;
+
+namespace HeuristicLab.Optimization.Operators {
+  /// <summary>
+  /// An item that performs similarity calculation between two solutions.
+  /// </summary>
+  /// <remarks>
+  /// The item always considers two solutions to be distinct.
+  /// </remarks>
+  [Item("NoSimilarityCalculator", "An item that performs similarity calculation between two solutions. The item always considers two solutions to be distinct.")]
+  public sealed class NoSimilarityCalculator : SingleObjectiveSolutionSimilarityCalculator {
+    private NoSimilarityCalculator(bool deserializing) : base(deserializing) { }
+    private NoSimilarityCalculator(NoSimilarityCalculator original, Cloner cloner) : base(original, cloner) { }
+    public NoSimilarityCalculator() : base() { }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new NoSimilarityCalculator(this, cloner);
+    }
+
+    public static double CalculateSimilarity(IScope left, IScope right) {
+      return 0.0;
+    }
+
+    public override double CalculateSolutionSimilarity(IScope leftSolution, IScope rightSolution) {
+      return CalculateSimilarity(leftSolution, rightSolution);
+    }
+  }
+}
Index: branches/GP-MoveOperators/HeuristicLab.Optimization.Operators/3.3/Plugin.cs.frame
===================================================================
--- branches/GP-MoveOperators/HeuristicLab.Optimization.Operators/3.3/Plugin.cs.frame	(revision 8286)
+++ branches/GP-MoveOperators/HeuristicLab.Optimization.Operators/3.3/Plugin.cs.frame	(revision 8660)
@@ -26,5 +26,5 @@
   /// Plugin class for HeuristicLab.Optimization.Operators plugin.
   /// </summary>
-  [Plugin("HeuristicLab.Optimization.Operators", "3.3.6.$WCREV$")]
+  [Plugin("HeuristicLab.Optimization.Operators", "3.3.7.$WCREV$")]
   [PluginFile("HeuristicLab.Optimization.Operators-3.3.dll", PluginFileType.Assembly)]
   [PluginDependency("HeuristicLab.Collections", "3.3")]
@@ -33,4 +33,5 @@
   [PluginDependency("HeuristicLab.Data", "3.3")]
   [PluginDependency("HeuristicLab.Operators", "3.3")]
+  [PluginDependency("HeuristicLab.Operators.Programmable", "3.3")]
   [PluginDependency("HeuristicLab.Optimization","3.3")]
   [PluginDependency("HeuristicLab.Parameters", "3.3")]
Index: branches/GP-MoveOperators/HeuristicLab.Optimization.Operators/3.3/ProgrammableAnalyzer.cs
===================================================================
--- branches/GP-MoveOperators/HeuristicLab.Optimization.Operators/3.3/ProgrammableAnalyzer.cs	(revision 8660)
+++ branches/GP-MoveOperators/HeuristicLab.Optimization.Operators/3.3/ProgrammableAnalyzer.cs	(revision 8660)
@@ -0,0 +1,60 @@
+﻿#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.Programmable;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Optimization.Operators {
+
+  [Item("ProgrammableAnalyzer", "An analyzer that can be programmed for arbitrary needs.")]
+  [StorableClass]
+  public class ProgrammableAnalyzer : ProgrammableSingleSuccessorOperator, IAnalyzer {
+    public virtual bool EnabledByDefault {
+      get { return false; }
+    }
+
+    [StorableConstructor]
+    protected ProgrammableAnalyzer(bool deserializing) : base(deserializing) { }
+    protected ProgrammableAnalyzer(ProgrammableAnalyzer original, Cloner cloner)
+      : base(original, cloner) {
+    }
+    public ProgrammableAnalyzer()
+      : 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 ValueLookupParameter<ResultCollection>("Results", "The result collection where the solution should be stored."));
+      Parameters.ForEach(x => x.Hidden = false);
+
+      SelectNamespace("HeuristicLab.Optimization");
+      SelectNamespace("HeuristicLab.Optimization.Operators");
+      Assemblies[typeof(HeuristicLab.Optimization.ResultCollection).Assembly] = true;
+      Assemblies[typeof(HeuristicLab.Optimization.Operators.ProgrammableAnalyzer).Assembly] = true;
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new ProgrammableAnalyzer(this, cloner);
+    }
+  }
+}
Index: branches/GP-MoveOperators/HeuristicLab.Optimization.Operators/3.3/Properties/AssemblyInfo.cs.frame
===================================================================
--- branches/GP-MoveOperators/HeuristicLab.Optimization.Operators/3.3/Properties/AssemblyInfo.cs.frame	(revision 8286)
+++ branches/GP-MoveOperators/HeuristicLab.Optimization.Operators/3.3/Properties/AssemblyInfo.cs.frame	(revision 8660)
@@ -54,3 +54,3 @@
 // by using the '*' as shown below:
 [assembly: AssemblyVersion("3.3.0.0")]
-[assembly: AssemblyFileVersion("3.3.6.$WCREV$")]
+[assembly: AssemblyFileVersion("3.3.7.$WCREV$")]
Index: branches/GP-MoveOperators/HeuristicLab.Optimization.Operators/3.3/QualitySimilarityCalculator.cs
===================================================================
--- branches/GP-MoveOperators/HeuristicLab.Optimization.Operators/3.3/QualitySimilarityCalculator.cs	(revision 8660)
+++ branches/GP-MoveOperators/HeuristicLab.Optimization.Operators/3.3/QualitySimilarityCalculator.cs	(revision 8660)
@@ -0,0 +1,55 @@
+﻿#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;
+
+namespace HeuristicLab.Optimization.Operators {
+  /// <summary>
+  /// An item that performs similarity calculation between two solutions.
+  /// </summary>
+  /// <remarks>
+  /// The item always considers two solutions to be equal if they have the same quality.
+  /// </remarks>
+  [Item("QualitySimilarityCalculator", "An item that performs similarity calculation between two solutions. The item only considers the qualities of the two solutions.")]
+  public sealed class QualitySimilarityCalculator : SingleObjectiveSolutionSimilarityCalculator {
+    private QualitySimilarityCalculator(bool deserializing) : base(deserializing) { }
+    private QualitySimilarityCalculator(QualitySimilarityCalculator original, Cloner cloner) : base(original, cloner) { }
+    public QualitySimilarityCalculator() : base() { }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new QualitySimilarityCalculator(this, cloner);
+    }
+
+    public static double CalculateSimilarity(IScope left, IScope right, string qualityVariableName) {
+      double leftQuality = ((DoubleValue)left.Variables[qualityVariableName].Value).Value;
+      double rightQuality = ((DoubleValue)right.Variables[qualityVariableName].Value).Value;
+      double delta = leftQuality.IsAlmost(rightQuality) ? 0.0 : Math.Abs(leftQuality - rightQuality);
+      return 1.0 - delta / Math.Max(leftQuality, rightQuality);
+    }
+
+    public override double CalculateSolutionSimilarity(IScope leftSolution, IScope rightSolution) {
+      return CalculateSimilarity(leftSolution, rightSolution, QualityVariableName);
+    }
+  }
+}
Index: branches/GP-MoveOperators/HeuristicLab.Optimization.Operators/3.3/SingleObjectivePathRelinker.cs
===================================================================
--- branches/GP-MoveOperators/HeuristicLab.Optimization.Operators/3.3/SingleObjectivePathRelinker.cs	(revision 8660)
+++ branches/GP-MoveOperators/HeuristicLab.Optimization.Operators/3.3/SingleObjectivePathRelinker.cs	(revision 8660)
@@ -0,0 +1,86 @@
+﻿#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.Optimization.Operators {
+  /// <summary>
+  /// A base class for operators that perform path relinking between single objective solutions.
+  /// </summary>
+  [Item("SingleObjectivePathRelinker", "A base class for operators that perform path relinking between single objective solutions.")]
+  [StorableClass]
+  public abstract class SingleObjectivePathRelinker : SingleSuccessorOperator, ISingleObjectivePathRelinker {
+    #region Parameter properties
+    public ScopeParameter CurrentScopeParameter {
+      get { return (ScopeParameter)Parameters["CurrentScope"]; }
+    }
+    public ILookupParameter<ItemArray<IItem>> ParentsParameter {
+      get { return (IScopeTreeLookupParameter<IItem>)Parameters["Parents"]; }
+    }
+    public IValueParameter<PercentValue> RelinkingAccuracyParameter {
+      get { return (IValueParameter<PercentValue>)Parameters["RelinkingAccuracy"]; }
+    }
+    #endregion
+
+    #region Properties
+    private IScope CurrentScope {
+      get { return CurrentScopeParameter.ActualValue; }
+    }
+    private ItemArray<IItem> Parents {
+      get { return ParentsParameter.ActualValue; }
+    }
+    private PercentValue RelinkingAccuracy {
+      get { return RelinkingAccuracyParameter.Value; }
+    }
+    #endregion
+
+    [StorableConstructor]
+    protected SingleObjectivePathRelinker(bool deserializing) : base(deserializing) { }
+    protected SingleObjectivePathRelinker(SingleObjectivePathRelinker original, Cloner cloner) : base(original, cloner) { }
+    protected SingleObjectivePathRelinker()
+      : base() {
+      #region Create parameters
+      Parameters.Add(new ScopeParameter("CurrentScope", "The current scope that contains the parents."));
+      Parameters.Add(new ScopeTreeLookupParameter<IItem>("Parents", "The parents used for path relinking."));
+      Parameters.Add(new ValueParameter<PercentValue>("RelinkingAccuracy", "The percentage of relinked offspring that should be yielded.", new PercentValue(0.25)));
+      #endregion
+    }
+
+    public sealed override IOperation Apply() {
+      ItemArray<IItem> relinkedSolutions = Relink(Parents, RelinkingAccuracy);
+      var offspringScope = new Scope("Offspring");
+      foreach (var solution in relinkedSolutions) {
+        var scope = new Scope();
+        scope.Variables.Add(new Variable(ParentsParameter.ActualName, solution));
+        offspringScope.SubScopes.Add(scope);
+      }
+      CurrentScope.SubScopes.Add(offspringScope);
+      return base.Apply();
+    }
+
+    protected abstract ItemArray<IItem> Relink(ItemArray<IItem> parents, PercentValue n);
+  }
+}
Index: branches/GP-MoveOperators/HeuristicLab.Optimization.Operators/3.3/SingleObjectiveSolutionSimilarityCalculator.cs
===================================================================
--- branches/GP-MoveOperators/HeuristicLab.Optimization.Operators/3.3/SingleObjectiveSolutionSimilarityCalculator.cs	(revision 8660)
+++ branches/GP-MoveOperators/HeuristicLab.Optimization.Operators/3.3/SingleObjectiveSolutionSimilarityCalculator.cs	(revision 8660)
@@ -0,0 +1,54 @@
+﻿#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.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Optimization.Operators {
+  /// <summary>
+  /// A base class for items that perform similarity calculation between two single objective solutions.
+  /// </summary>
+  [Item("SimilarityCalculator", "A base class for items that perform similarity calculation between two solutions.")]
+  [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() { }
+
+    public override int GetHashCode(IScope scope) {
+      return ((DoubleValue)scope.Variables[QualityVariableName].Value).Value.GetHashCode();
+    }
+  }
+}
Index: branches/GP-MoveOperators/HeuristicLab.Optimization.Operators/3.3/SolutionSimilarityCalculator.cs
===================================================================
--- branches/GP-MoveOperators/HeuristicLab.Optimization.Operators/3.3/SolutionSimilarityCalculator.cs	(revision 8660)
+++ branches/GP-MoveOperators/HeuristicLab.Optimization.Operators/3.3/SolutionSimilarityCalculator.cs	(revision 8660)
@@ -0,0 +1,91 @@
+﻿#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.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Optimization.Operators {
+  /// <summary>
+  /// A base class for items that perform similarity calculation between two solutions.
+  /// </summary>
+  [Item("SimilarityCalculator", "A base class for items that perform similarity calculation between two solutions.")]
+  [StorableClass]
+  public abstract class SolutionSimilarityCalculator : Item, ISolutionSimilarityCalculator {
+    [StorableConstructor]
+    protected SolutionSimilarityCalculator(bool deserializing) : base(deserializing) { }
+    protected SolutionSimilarityCalculator(SolutionSimilarityCalculator original, Cloner cloner) : base(original, cloner) { }
+    protected SolutionSimilarityCalculator() : base() { }
+
+    public double[][] CalculateSolutionCrowdSimilarity(IScope leftSolutionCrowd, IScope rightSolutionCrowd) {
+      if (leftSolutionCrowd == null || rightSolutionCrowd == null)
+        throw new ArgumentException("Cannot calculate similarity because one of the provided crowds or both are null.");
+
+      var leftIndividuals = leftSolutionCrowd.SubScopes;
+      var rightIndividuals = rightSolutionCrowd.SubScopes;
+
+      if (!leftIndividuals.Any() || !rightIndividuals.Any())
+        throw new ArgumentException("Cannot calculate similarity because one of the provided crowds or both are empty.");
+
+      var similarityMatrix = new double[leftIndividuals.Count][];
+      for (int i = 0; i < leftIndividuals.Count; i++) {
+        similarityMatrix[i] = new double[rightIndividuals.Count];
+        for (int j = 0; j < rightIndividuals.Count; j++) {
+          similarityMatrix[i][j] = CalculateSolutionSimilarity(leftIndividuals[i], rightIndividuals[j]);
+        }
+      }
+
+      return similarityMatrix;
+    }
+
+    public double[][] CalculateSolutionCrowdSimilarity(IScope solutionCrowd) {
+      if (solutionCrowd == null)
+        throw new ArgumentException("Cannot calculate similarity because the provided crowd is null.");
+
+      var individuals = solutionCrowd.SubScopes;
+
+      if (!individuals.Any())
+        throw new ArgumentException("Cannot calculate similarity because the provided crowd is empty.");
+
+      var similarityMatrix = new double[individuals.Count][];
+      for (int i = 0; i < individuals.Count; i++) similarityMatrix[i] = new double[individuals.Count];
+
+      for (int i = 0; i < individuals.Count; i++) {
+        for (int j = i; j < individuals.Count; j++) {
+          similarityMatrix[i][j] = similarityMatrix[j][i] = CalculateSolutionSimilarity(individuals[i], individuals[j]);
+        }
+      }
+
+      return similarityMatrix;
+    }
+
+    public bool Equals(IScope x, IScope y) {
+      if (object.ReferenceEquals(x, y)) return true;
+      if (x == null || y == null) return false;
+      return CalculateSolutionSimilarity(x, y) == 1.0;
+    }
+
+    public abstract double CalculateSolutionSimilarity(IScope leftSolution, IScope rightSolution);
+    public abstract int GetHashCode(IScope obj);
+  }
+}
