Index: trunk/sources/HeuristicLab.Problems.Knapsack/3.3/HeuristicLab.Problems.Knapsack-3.3.csproj
===================================================================
--- trunk/sources/HeuristicLab.Problems.Knapsack/3.3/HeuristicLab.Problems.Knapsack-3.3.csproj	(revision 8246)
+++ trunk/sources/HeuristicLab.Problems.Knapsack/3.3/HeuristicLab.Problems.Knapsack-3.3.csproj	(revision 8334)
@@ -109,4 +109,5 @@
   <ItemGroup>
     <Compile Include="Evaluators\KnapsackEvaluator.cs" />
+    <Compile Include="Improvers\KnapsackImprovementOperator.cs" />
     <Compile Include="Interfaces\IKnapsackEvaluator.cs" />
     <Compile Include="Interfaces\IKnapsackMoveEvaluator.cs" />
@@ -115,7 +116,10 @@
     <Compile Include="MoveEvaluators\KnapsackMoveEvaluator.cs" />
     <Compile Include="MoveEvaluators\KnapsackOneBitflipMoveEvaluator.cs" />
+    <Compile Include="PathRelinkers\KnapsackPathRelinker.cs" />
+    <Compile Include="PathRelinkers\KnapsackSimultaneousPathRelinker.cs" />
     <Compile Include="Plugin.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="Analyzers\BestKnapsackSolutionAnalyzer.cs" />
+    <Compile Include="SimilarityCalculators\KnapsackSimilarityCalculator.cs" />
   </ItemGroup>
   <ItemGroup>
@@ -159,4 +163,8 @@
       <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>
     </ProjectReference>
     <ProjectReference Include="..\..\HeuristicLab.Optimization\3.3\HeuristicLab.Optimization-3.3.csproj">
@@ -198,4 +206,5 @@
     </BootstrapperPackage>
   </ItemGroup>
+  <ItemGroup />
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
   <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
Index: trunk/sources/HeuristicLab.Problems.Knapsack/3.3/Improvers/KnapsackImprovementOperator.cs
===================================================================
--- trunk/sources/HeuristicLab.Problems.Knapsack/3.3/Improvers/KnapsackImprovementOperator.cs	(revision 8334)
+++ trunk/sources/HeuristicLab.Problems.Knapsack/3.3/Improvers/KnapsackImprovementOperator.cs	(revision 8334)
@@ -0,0 +1,155 @@
+﻿#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.Encodings.BinaryVectorEncoding;
+using HeuristicLab.Operators;
+using HeuristicLab.Optimization;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.Knapsack {
+  /// <summary>
+  /// An operator that improves knapsack solutions.
+  /// </summary>
+  /// <remarks>
+  /// It is implemented as described in Laguna, M. and Martí, R. (2003). Scatter Search: Methodology and Implementations in C. Operations Research/Computer Science Interfaces Series, Vol. 24. Springer.<br />
+  /// The operator first orders the elements of the knapsack according to their value-to-weight ratio, then, if the solution is not feasible, removes the element with the lowest ratio until the solution is feasible and tries to add new elements with the best ratio that are not already included yet until the knapsack is full.
+  /// </remarks>
+  [Item("KnapsackImprovementOperator", "An operator that improves knapsack solutions. It is implemented as described in Laguna, M. and Martí, R. (2003). Scatter Search: Methodology and Implementations in C. Operations Research/Computer Science Interfaces Series, Vol. 24. Springer.")]
+  [StorableClass]
+  public sealed class KnapsackImprovementOperator : SingleSuccessorOperator, ISingleObjectiveImprovementOperator {
+    #region Parameter properties
+    public ScopeParameter CurrentScopeParameter {
+      get { return (ScopeParameter)Parameters["CurrentScope"]; }
+    }
+    public ILookupParameter<IntValue> KnapsackCapacityParameter {
+      get { return (ILookupParameter<IntValue>)Parameters["KnapsackCapacity"]; }
+    }
+    public ILookupParameter<DoubleValue> PenaltyParameter {
+      get { return (ILookupParameter<DoubleValue>)Parameters["Penalty"]; }
+    }
+    public IValueLookupParameter<IItem> SolutionParameter {
+      get { return (IValueLookupParameter<IItem>)Parameters["Solution"]; }
+    }
+    public ILookupParameter<IntArray> ValuesParameter {
+      get { return (ILookupParameter<IntArray>)Parameters["Values"]; }
+    }
+    public ILookupParameter<IntArray> WeightsParameter {
+      get { return (ILookupParameter<IntArray>)Parameters["Weights"]; }
+    }
+    #endregion
+
+    #region Properties
+    private IScope CurrentScope {
+      get { return CurrentScopeParameter.ActualValue; }
+    }
+    private IntValue KnapsackCapacity {
+      get { return KnapsackCapacityParameter.ActualValue; }
+      set { KnapsackCapacityParameter.ActualValue = value; }
+    }
+    private DoubleValue Penalty {
+      get { return PenaltyParameter.ActualValue; }
+      set { PenaltyParameter.ActualValue = value; }
+    }
+    private IntArray Values {
+      get { return ValuesParameter.ActualValue; }
+      set { ValuesParameter.ActualValue = value; }
+    }
+    private IntArray Weights {
+      get { return WeightsParameter.ActualValue; }
+      set { WeightsParameter.ActualValue = value; }
+    }
+    #endregion
+
+    [StorableConstructor]
+    private KnapsackImprovementOperator(bool deserializing) : base(deserializing) { }
+    private KnapsackImprovementOperator(KnapsackImprovementOperator original, Cloner cloner) : base(original, cloner) { }
+    public KnapsackImprovementOperator()
+      : base() {
+      #region Create parameters
+      Parameters.Add(new ScopeParameter("CurrentScope", "The current scope that contains the solution to be improved."));
+      Parameters.Add(new LookupParameter<IntValue>("KnapsackCapacity", "Capacity of the Knapsack."));
+      Parameters.Add(new LookupParameter<DoubleValue>("Penalty", "The penalty value for each unit of overweight."));
+      Parameters.Add(new ValueLookupParameter<IItem>("Solution", "The solution to be improved. This parameter is used for name translation only."));
+      Parameters.Add(new LookupParameter<IntArray>("Values", "The values of the items."));
+      Parameters.Add(new LookupParameter<IntArray>("Weights", "The weights of the items."));
+      #endregion
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new KnapsackImprovementOperator(this, cloner);
+    }
+
+    public override IOperation Apply() {
+      BinaryVector sol = CurrentScope.Variables[SolutionParameter.ActualName].Value as BinaryVector;
+      if (sol == null)
+        throw new ArgumentException("Cannot improve solution because it has the wrong type.");
+
+      // calculate value-to-weight ratio
+      double[] ratio = new double[Values.Length];
+      for (int i = 0; i < ratio.Length; i++)
+        ratio[i] = (double)Values[i] / (double)Weights[i];
+
+
+      // calculate order for ratio
+      int[] order = new int[ratio.Length];
+      foreach (var x in ratio.Select((x, index) => new { Value = x, ValueIndex = index })
+                             .OrderByDescending(x => x.Value)
+                             .Select((x, index) => new { ValueIndex = x.ValueIndex, ItemIndex = index })) {
+        order[x.ItemIndex] = x.ValueIndex;
+      }
+
+      int evaluatedSolutions = 0;
+      int j = sol.Length - 1;
+      while (KnapsackEvaluator.Apply(sol, KnapsackCapacity, Penalty, Weights, Values)
+                              .SumWeights.Value > KnapsackCapacity.Value && j >= 0) {
+        sol[order[j--]] = false;
+        evaluatedSolutions++;
+      }
+
+      // calculate weight
+      int weight = 0;
+      for (int i = 0; i < sol.Length; i++)
+        if (sol[i]) weight += Weights[i];
+
+      // improve solution
+      bool feasible = true; j = 0;
+      while (feasible && j < sol.Length) {
+        while (sol[order[j]]) j++;
+        if (weight + Weights[order[j]] <= KnapsackCapacity.Value) {
+          sol[order[j]] = true;
+          weight += Weights[order[j]];
+        } else feasible = false;
+        evaluatedSolutions++;
+      }
+
+      CurrentScope.Variables[SolutionParameter.ActualName].Value = sol;
+      CurrentScope.Variables.Add(new Variable("LocalEvaluatedSolutions", new IntValue(evaluatedSolutions)));
+
+      return base.Apply();
+    }
+  }
+}
Index: trunk/sources/HeuristicLab.Problems.Knapsack/3.3/KnapsackProblem.cs
===================================================================
--- trunk/sources/HeuristicLab.Problems.Knapsack/3.3/KnapsackProblem.cs	(revision 8246)
+++ trunk/sources/HeuristicLab.Problems.Knapsack/3.3/KnapsackProblem.cs	(revision 8334)
@@ -244,4 +244,9 @@
     }
     private void InitializeOperators() {
+      Operators.Add(new KnapsackImprovementOperator());
+      Operators.Add(new KnapsackPathRelinker());
+      Operators.Add(new KnapsackSimultaneousPathRelinker());
+      Operators.Add(new KnapsackSimilarityCalculator());
+
       Operators.Add(new BestKnapsackSolutionAnalyzer());
       ParameterizeAnalyzer();
@@ -286,7 +291,19 @@
         op.ValuesParameter.Hidden = true;
       }
-      foreach (var op in Operators.OfType<IBinaryVectorMultiNeighborhoodShakingOperator>()) {
+      foreach (IBinaryVectorMultiNeighborhoodShakingOperator op in Operators.OfType<IBinaryVectorMultiNeighborhoodShakingOperator>()) {
         op.BinaryVectorParameter.ActualName = SolutionCreator.BinaryVectorParameter.ActualName;
         op.BinaryVectorParameter.Hidden = true;
+      }
+      foreach (ISingleObjectiveImprovementOperator op in Operators.OfType<ISingleObjectiveImprovementOperator>()) {
+        op.SolutionParameter.ActualName = SolutionCreator.BinaryVectorParameter.ActualName;
+        op.SolutionParameter.Hidden = true;
+      }
+      foreach (ISingleObjectivePathRelinker op in Operators.OfType<ISingleObjectivePathRelinker>()) {
+        op.ParentsParameter.ActualName = SolutionCreator.BinaryVectorParameter.ActualName;
+        op.ParentsParameter.Hidden = true;
+      }
+      foreach (KnapsackSimilarityCalculator op in Operators.OfType<KnapsackSimilarityCalculator>()) {
+        op.SolutionVariableName = SolutionCreator.BinaryVectorParameter.ActualName;
+        op.QualityVariableName = Evaluator.QualityParameter.ActualName;
       }
     }
Index: trunk/sources/HeuristicLab.Problems.Knapsack/3.3/PathRelinkers/KnapsackPathRelinker.cs
===================================================================
--- trunk/sources/HeuristicLab.Problems.Knapsack/3.3/PathRelinkers/KnapsackPathRelinker.cs	(revision 8334)
+++ trunk/sources/HeuristicLab.Problems.Knapsack/3.3/PathRelinkers/KnapsackPathRelinker.cs	(revision 8334)
@@ -0,0 +1,88 @@
+﻿#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.Encodings.BinaryVectorEncoding;
+using HeuristicLab.Optimization.Operators;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.Knapsack {
+  /// <summary>
+  /// An operator that relinks paths between knapsack solutions.
+  /// </summary>
+  /// <remarks>
+  /// The operator incrementally assimilates the initiating solution into the guiding solution by adding and removing elements as needed.
+  /// </remarks>
+  [Item("KnapsackPathRelinker", "An operator that relinks paths between knapsack solutions. The operator incrementally assimilates the initiating solution into the guiding solution by adding and removing elements as needed.")]
+  [StorableClass]
+  public sealed class KnapsackPathRelinker : SingleObjectivePathRelinker {
+    [StorableConstructor]
+    private KnapsackPathRelinker(bool deserializing) : base(deserializing) { }
+    private KnapsackPathRelinker(KnapsackPathRelinker original, Cloner cloner) : base(original, cloner) { }
+    public KnapsackPathRelinker() : base() { }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new KnapsackPathRelinker(this, cloner);
+    }
+
+    public static ItemArray<IItem> Apply(IItem initiator, IItem guide, PercentValue n) {
+      if (!(initiator is BinaryVector) || !(guide is BinaryVector))
+        throw new ArgumentException("Cannot relink path because one of the provided solutions or both have the wrong type.");
+      if (n.Value <= 0.0)
+        throw new ArgumentException("RelinkingAccuracy must be greater than 0.");
+
+      BinaryVector v1 = initiator.Clone() as BinaryVector;
+      BinaryVector v2 = guide as BinaryVector;
+
+      if (v1.Length != v2.Length)
+        throw new ArgumentException("The solutions are of different length.");
+
+      IList<BinaryVector> solutions = new List<BinaryVector>();
+      for (int i = 0; i < v1.Length; i++)
+        if (v1[i] != v2[i]) {
+          v1[i] = v2[i];
+          solutions.Add(v1.Clone() as BinaryVector);
+        }
+
+      IList<IItem> selection = new List<IItem>();
+      if (solutions.Count > 0) {
+        int noSol = (int)(solutions.Count * n.Value);
+        if (noSol <= 0) noSol++;
+        double stepSize = (double)solutions.Count / (double)noSol;
+        for (int i = 0; i < noSol; i++)
+          selection.Add(solutions.ElementAt((int)((i + 1) * stepSize - stepSize * 0.5)));
+      }
+
+      return new ItemArray<IItem>(selection);
+    }
+
+    protected override ItemArray<IItem> Relink(ItemArray<IItem> parents, PercentValue n) {
+      if (parents.Length != 2)
+        throw new ArgumentException("The number of parents is not equal to 2.");
+      return Apply(parents[0], parents[1], n);
+    }
+  }
+}
Index: trunk/sources/HeuristicLab.Problems.Knapsack/3.3/PathRelinkers/KnapsackSimultaneousPathRelinker.cs
===================================================================
--- trunk/sources/HeuristicLab.Problems.Knapsack/3.3/PathRelinkers/KnapsackSimultaneousPathRelinker.cs	(revision 8334)
+++ trunk/sources/HeuristicLab.Problems.Knapsack/3.3/PathRelinkers/KnapsackSimultaneousPathRelinker.cs	(revision 8334)
@@ -0,0 +1,96 @@
+﻿#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.Encodings.BinaryVectorEncoding;
+using HeuristicLab.Optimization.Operators;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.Knapsack {
+  /// <summary>
+  /// An operator that relinks paths between knapsack solutions starting from both ends.
+  /// </summary>
+  /// <remarks>
+  /// The operator incrementally assimilates the initiating solution into the guiding solution and vice versa by adding and removing elements as needed.
+  /// </remarks>
+  [Item("KnapsackSimultaneousPathRelinker", "An operator that relinks paths between knapsack solutions starting from both ends. The operator incrementally assimilates the initiating solution into the guiding solution and vice versa by adding and removing elements as needed.")]
+  [StorableClass]
+  public sealed class KnapsackSimultaneousPathRelinker : SingleObjectivePathRelinker {
+    [StorableConstructor]
+    private KnapsackSimultaneousPathRelinker(bool deserializing) : base(deserializing) { }
+    private KnapsackSimultaneousPathRelinker(KnapsackSimultaneousPathRelinker original, Cloner cloner) : base(original, cloner) { }
+    public KnapsackSimultaneousPathRelinker() : base() { }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new KnapsackSimultaneousPathRelinker(this, cloner);
+    }
+
+    public static ItemArray<IItem> Apply(IItem initiator, IItem guide, PercentValue n) {
+      if (!(initiator is BinaryVector) || !(guide is BinaryVector))
+        throw new ArgumentException("Cannot relink path because one of the provided solutions or both have the wrong type.");
+      if (n.Value <= 0.0)
+        throw new ArgumentException("RelinkingAccuracy must be greater than 0.");
+
+      BinaryVector firstInitiator = initiator.Clone() as BinaryVector;
+      BinaryVector firstGuide = guide.Clone() as BinaryVector;
+      BinaryVector secondInitiator = firstGuide.Clone() as BinaryVector;
+      BinaryVector secondGuide = firstInitiator.Clone() as BinaryVector;
+
+      if (firstInitiator.Length != firstGuide.Length)
+        throw new ArgumentException("The solutions are of different length.");
+
+      IList<BinaryVector> solutions = new List<BinaryVector>();
+      for (int i = 0; i < firstInitiator.Length / 2; i++) {
+        if (firstInitiator[i] != firstGuide[i]) {
+          firstInitiator[i] = firstGuide[i];
+          solutions.Add(firstInitiator.Clone() as BinaryVector);
+        }
+        int j = secondInitiator.Length - 1 - i;
+        if (secondInitiator[j] != secondGuide[j]) {
+          secondInitiator[j] = secondGuide[j];
+          solutions.Add(secondInitiator.Clone() as BinaryVector);
+        }
+      }
+
+      IList<IItem> selection = new List<IItem>();
+      if (solutions.Count > 0) {
+        int noSol = (int)(solutions.Count * n.Value);
+        if (noSol <= 0) noSol++;
+        double stepSize = (double)solutions.Count / (double)noSol;
+        for (int i = 0; i < noSol; i++)
+          selection.Add(solutions.ElementAt((int)((i + 1) * stepSize - stepSize * 0.5)));
+      }
+
+      return new ItemArray<IItem>(selection);
+    }
+
+    protected override ItemArray<IItem> Relink(ItemArray<IItem> parents, PercentValue n) {
+      if (parents.Length != 2)
+        throw new ArgumentException("The number of parents is not equal to 2.");
+      return Apply(parents[0], parents[1], n);
+    }
+  }
+}
Index: trunk/sources/HeuristicLab.Problems.Knapsack/3.3/Plugin.cs.frame
===================================================================
--- trunk/sources/HeuristicLab.Problems.Knapsack/3.3/Plugin.cs.frame	(revision 8246)
+++ trunk/sources/HeuristicLab.Problems.Knapsack/3.3/Plugin.cs.frame	(revision 8334)
@@ -36,4 +36,5 @@
   [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")]
Index: trunk/sources/HeuristicLab.Problems.Knapsack/3.3/SimilarityCalculators/KnapsackSimilarityCalculator.cs
===================================================================
--- trunk/sources/HeuristicLab.Problems.Knapsack/3.3/SimilarityCalculators/KnapsackSimilarityCalculator.cs	(revision 8334)
+++ trunk/sources/HeuristicLab.Problems.Knapsack/3.3/SimilarityCalculators/KnapsackSimilarityCalculator.cs	(revision 8334)
@@ -0,0 +1,65 @@
+﻿#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.Encodings.BinaryVectorEncoding;
+using HeuristicLab.Optimization.Operators;
+
+namespace HeuristicLab.Problems.Knapsack {
+  /// <summary>
+  /// An operator that performs similarity calculation between two knapsack solutions.
+  /// </summary>
+  /// <remarks>
+  /// The operator calculates the similarity based on the number of elements the two solutions have in common.
+  /// </remarks>
+  [Item("KnapsackSimilarityCalculator", "An operator that performs similarity calculation between two knapsack solutions. The operator calculates the similarity based on the number of elements the two solutions have in common.")]
+  public sealed class KnapsackSimilarityCalculator : SingleObjectiveSolutionSimilarityCalculator {
+    private KnapsackSimilarityCalculator(bool deserializing) : base(deserializing) { }
+    private KnapsackSimilarityCalculator(KnapsackSimilarityCalculator original, Cloner cloner) : base(original, cloner) { }
+    public KnapsackSimilarityCalculator() : base() { }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new KnapsackSimilarityCalculator(this, cloner);
+    }
+
+    public static double CalculateSimilarity(BinaryVector left, BinaryVector right) {
+      if (left == null || right == null)
+        throw new ArgumentException("Cannot calculate similarity because one or both of the provided scopes is null.");
+      if (left.Length != right.Length)
+        throw new ArgumentException("Cannot calculate similarity because the provided solutions have different lengths.");
+      if (left == right) return 1.0;
+
+      double similarity = 0.0;
+      for (int i = 0; i < left.Length; i++)
+        if (left[i] == right[i]) similarity++;
+      return similarity / left.Length;
+    }
+
+    public override double CalculateSolutionSimilarity(IScope leftSolution, IScope rightSolution) {
+      var sol1 = leftSolution.Variables[SolutionVariableName].Value as BinaryVector;
+      var sol2 = rightSolution.Variables[SolutionVariableName].Value as BinaryVector;
+
+      return CalculateSimilarity(sol1, sol2);
+    }
+  }
+}
