Index: /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Common/3.3/ExtensionMethods.cs
===================================================================
--- /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Common/3.3/ExtensionMethods.cs	(revision 7431)
+++ /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Common/3.3/ExtensionMethods.cs	(revision 7432)
@@ -28,73 +28,194 @@
   public static class ExtensionMethods {
 
-    /// <summary>
-    /// Selects an element from an enumerable randomly with equal probability for each element. If the sequence is empty, selected will be false and default(T) will be returned.
-    /// </summary>
-    /// <typeparam name="T">The type of the items that are to be selected.</typeparam>
-    /// <param name="source">The enumerable that contains the items.</param>
-    /// <param name="random">The random number generator, its NextDouble() method must return a value in the range [0;1).</param>
-    /// <param name="selected">True if an element was selected, false otherwise (only because of an empty sequence).</param>
-    /// <returns>The selected item.</returns>
-    public static T ChooseRandomOrDefault<T>(this IEnumerable<T> source, IRandom random, out bool selected) {
-      if (source == null) throw new ArgumentNullException("SelectRandomOrDefault: source is null");
-      uint counter = 1;
-      selected = false;
-      T selectedItem = default(T);
-      foreach (T item in source) {
-        if (counter * random.NextDouble() < 1.0) { // use multiplication instead of division
-          selectedItem = item;
-          selected = true;
-        }
-        counter++;
-      }
-      return selectedItem;
-    }
-
-    /// <summary>
-    /// Selects an element from an enumerable randomly with equal probability for each element.
-    /// </summary>
-    /// <typeparam name="T">The type of the items that are to be selected.</typeparam>
-    /// <param name="source">The enumerable that contains the items.</param>
-    /// <param name="random">The random number generator, its NextDouble() method must return a value in the range [0;1).</param>
-    /// <returns>The selected item.</returns>
-    public static T ChooseRandom<T>(this IEnumerable<T> source, IRandom random) {
-      if (source == null) throw new ArgumentNullException("SelectRandom: source is null");
-      if (!source.Any()) throw new ArgumentException("SelectRandom: sequence is empty.");
-      uint counter = 1;
-      T selectedItem = default(T);
-      foreach (T item in source) {
-        if (counter * random.NextDouble() < 1.0) // use multiplication instead of division
-          selectedItem = item;
-        counter++;
-      }
-      return selectedItem;
-    }
-
-    /// <summary>
-    /// Shuffles an enumerable and returns an new enumerable according to the Fisher-Yates shuffle.
-    /// </summary>
-    /// <remarks>
-    /// Source code taken from http://stackoverflow.com/questions/1287567/c-is-using-random-and-orderby-a-good-shuffle-algorithm.
-    /// Note that this is an online shuffle, but the source enumerable is transformed into an array.
-    /// </remarks>
-    /// <typeparam name="T">The type of the items that are to be shuffled.</typeparam>
-    /// <param name="source">The enumerable that contains the items.</param>
-    /// <param name="random">The random number generator, its Next(int) method must deliver uniformly distributed random numbers.</param>
-    /// <returns>An enumerable with the elements shuffled.</returns>
-    public static IEnumerable<T> Shuffle<T>(this IEnumerable<T> source, IRandom random) {
-      T[] elements = source.ToArray();
-      // Note i > 0 to avoid final pointless iteration
-      for (int i = elements.Length - 1; i > 0; i--) {
-        // Swap element "i" with a random earlier element it (or itself)
-        int swapIndex = random.Next(i + 1);
-        yield return elements[swapIndex];
-        elements[swapIndex] = elements[i];
-        // we don't actually perform the swap, we can forget about the
-        // swapped element because we already returned it.
-      }
-
-      // there is one item remaining that was not returned - we return it now
-      yield return elements[0];
-    }
+    #region Choosing from a sequence
+    /// <summary>
+    /// Chooses one elements from a sequence under equal chances for each element.
+    /// </summary>
+    /// <remarks>
+    /// Runtime complexity is O(1) for sequences that are <see cref="IList{T}"/> and
+    /// O(N) for all other.
+    /// </remarks>
+    /// <typeparam name="T">The type of the items to be selected.</typeparam>
+    /// <param name="source">The sequence of elements.</param>
+    /// <param name="random">The random number generator to use, its NextDouble() method must produce values in the range [0;1)</param>
+    /// <param name="count">The number of items to be selected.</param>
+    /// <returns>A sequence of elements that have been chosen randomly.</returns>
+    public static T ChooseUniformRandom<T>(this IEnumerable<T> source, IRandom random) {
+      return source.ChooseUniformRandom(random, 1).First();
+    }
+    /// <summary>
+    /// Chooses <paramref name="count"/> elements from a sequence with repetition under equal chances for each element.
+    /// </summary>
+    /// <remarks>
+    /// Runtime complexity is O(count) for sequences that are <see cref="IList{T}"/> and
+    /// O(N * count) for all other.
+    /// 
+    /// The method is online.
+    /// </remarks>
+    /// <typeparam name="T">The type of the items to be selected.</typeparam>
+    /// <param name="source">The sequence of elements.</param>
+    /// <param name="random">The random number generator to use, its NextDouble() method must produce values in the range [0;1)</param>
+    /// <param name="count">The number of items to be selected.</param>
+    /// <returns>A sequence of elements that have been chosen randomly.</returns>
+    public static IEnumerable<T> ChooseUniformRandom<T>(this IEnumerable<T> source, IRandom random, int count) {
+      if (source == null) throw new ArgumentNullException("source", "sequence is null");
+      if (!source.Any()) throw new ArgumentException("sequence is empty.", "source");
+
+      var listSource = source as IList<T>;
+      if (listSource != null)
+        while (count > 0) {
+          yield return listSource[random.Next(listSource.Count)];
+          count--;
+        }
+
+      while (count > 0) {
+        var enumerator = source.GetEnumerator();
+        enumerator.MoveNext();
+        T selectedItem = enumerator.Current;
+        int counter = 1;
+        while (enumerator.MoveNext()) {
+          counter++;
+          if (counter * random.NextDouble() < 1.0)
+            selectedItem = enumerator.Current;
+        }
+        yield return selectedItem;
+        count--;
+      }
+    }
+    /// <summary>
+    /// Chooses <paramref name="count"/> elements from a sequence without repetition under equal chances for each element.
+    /// </summary>
+    /// <remarks>
+    /// Runtime complexity is O(count) for sequences that are <see cref="IList{T}"/> and
+    /// O(N * count) for all other.
+    /// 
+    /// The method is online, but the source enumerable is transformed into an array.
+    /// </remarks>
+    /// <typeparam name="T">The type of the items to be selected.</typeparam>
+    /// <param name="source">The sequence of elements.</param>
+    /// <param name="random">The random number generator to use, its NextDouble() method must produce values in the range [0;1)</param>
+    /// <param name="count">The number of items to be selected.</param>
+    /// <returns>A sequence of elements that have been chosen randomly.</returns>
+    public static IEnumerable<T> ChooseUniformRandomWithoutRepetition<T>(this IEnumerable<T> source, IRandom random, int count) {
+      return source.Shuffle(random).Take(count);
+    }
+
+    /// <summary>
+    /// Chooses items out of a sequence with repetition. The chance that an item is selected is proportional or inverse-proportional
+    /// to the value obtained from <paramref name="valueSelector"/>.
+    /// </summary>
+    /// <remarks>
+    /// In case both <paramref name="maximization"/> and <paramref name="windowing"/> are false values must be &gt; 0,
+    /// otherwise an InvalidOperationException is thrown.
+    /// 
+    /// The method is online, but internally holds two arrays: One that is the sequence itself and another one for the values. The <paramref name="valueSelector"/>
+    /// is only applied once for each item.
+    /// </remarks>
+    /// <typeparam name="T">The type of the items to be selected.</typeparam>
+    /// <param name="source">The sequence of elements.</param>
+    /// <param name="random">The random number generator to use, its NextDouble() method must produce values in the range [0;1)</param>
+    /// <param name="count">The number of items to be selected.</param>
+    /// <param name="valueSelector">The function that calculates a proportional value for each item.</param>
+    /// <param name="windowing">Whether to scale the proportional values or not.</param>
+    /// <param name="maximization">Determines whether to choose proportionally (true) or inverse-proportionally (false).</param>
+    /// <returns>A sequence of selected items. The sequence might contain the same item more than once.</returns>
+    public static IEnumerable<T> ChooseProportionalRandom<T>(this IEnumerable<T> source, IRandom random, int count, Func<T, double> valueSelector, bool windowing, bool maximization) {
+      return source.ChooseProportionalRandom(random, valueSelector, windowing, maximization).Take(count);
+    }
+    /// <summary>
+    /// Same as <seealso cref="ChooseProportionalRandom<T>"/>, but selects each item exactly once.
+    /// </summary>
+    /// <remarks>
+    /// In case both <paramref name="maximization"/> and <paramref name="windowing"/> are false values must be &gt; 0,
+    /// otherwise an InvalidOperationException is thrown.
+    /// 
+    /// The method is online, but internally holds two arrays: One that is the sequence itself and another one for the values. The <paramref name="valueSelector"/>
+    /// is only applied once for each item.
+    /// </remarks>
+    /// <typeparam name="T">The type of the items to be selected.</typeparam>
+    /// <param name="source">The sequence of elements.</param>
+    /// <param name="random">The random number generator to use, its NextDouble() method must produce values in the range [0;1)</param>
+    /// <param name="count">The number of items to be selected.</param>
+    /// <param name="valueSelector">The function that calculates a proportional value for each item.</param>
+    /// <param name="windowing">Whether to scale the proportional values or not.</param>
+    /// <param name="maximization">Determines whether to choose proportionally (true) or inverse-proportionally (false).</param>
+    /// <returns>A sequence of selected items.</returns>
+    public static IEnumerable<T> ChooseProportionalRandomWithoutRepetition<T>(this IEnumerable<T> source, IRandom random, int count, Func<T, double> valueSelector, bool windowing, bool maximization) {
+      return source.ChooseProportionalRandomWithoutRepetition(random, valueSelector, windowing, maximization).Take(count);
+    }
+    #region Proportional Helpers
+    private static IEnumerable<T> ChooseProportionalRandom<T>(this IEnumerable<T> source, IRandom random, Func<T, double> valueSelector, bool windowing, bool maximization) {
+      if (source == null) throw new ArgumentNullException("source", "sequence is null");
+      if (!source.Any()) throw new ArgumentException("sequence is empty.", "source");
+
+      var sourceArray = source.ToArray();
+      var valueArray = PrepareProportional<T>(sourceArray, valueSelector, windowing, maximization);
+      double total = valueArray.Sum();
+
+      while (true) {
+        int index = 0;
+        double ball = valueArray[index], sum = random.NextDouble() * total;
+        while (ball < sum)
+          ball += valueArray[++index];
+        yield return sourceArray[index];
+      }
+    }
+    private static IEnumerable<T> ChooseProportionalRandomWithoutRepetition<T>(this IEnumerable<T> source, IRandom random, Func<T, double> valueSelector, bool windowing, bool maximization) {
+      if (source == null) throw new ArgumentNullException("source", "sequence is null");
+      if (!source.Any()) throw new ArgumentException("sequence is empty.", "source");
+
+      var sourceArray = source.ToArray();
+      var valueArray = PrepareProportional<T>(sourceArray, valueSelector, windowing, maximization);
+      double total = valueArray.Sum();
+
+      HashSet<int> chosenIndices = new HashSet<int>();
+      while (chosenIndices.Count < sourceArray.Length) {
+        int index = 0;
+        double ball = valueArray[index], sum = random.NextDouble() * total;
+        while (ball < sum) {
+          index++;
+          if (!chosenIndices.Contains(index))
+            ball += valueArray[++index];
+        }
+        yield return sourceArray[index];
+        chosenIndices.Add(index);
+        total -= valueArray[index];
+      }
+    }
+    private static double[] PrepareProportional<T>(IList<T> sourceArray, Func<T, double> valueSelector, bool windowing, bool maximization) {
+      double maxValue = double.MinValue, minValue = double.MaxValue;
+      double[] valueArray = new double[sourceArray.Count];
+
+      for (int i = 0; i < sourceArray.Count; i++) {
+        valueArray[i] = valueSelector(sourceArray[i]);
+        if (valueArray[i] > maxValue) maxValue = valueArray[i];
+        if (valueArray[i] < minValue) minValue = valueArray[i];
+      }
+      if (minValue == maxValue) {  // all values are equal
+        for (int i = 0; i < sourceArray.Count; i++) {
+          valueArray[i] = 1.0;
+        }
+      } else {
+        if (windowing) {
+          if (maximization) ProportionalScale(valueArray, minValue);
+          else InverseProportionalScale(valueArray, maxValue);
+        } else {
+          if (minValue < 0.0) throw new InvalidOperationException("Proportional selection without windowing does not work with values < 0.");
+          if (!maximization) InverseProportionalScale(valueArray, 2 * maxValue);
+        }
+      }
+      return valueArray;
+    }
+    private static void ProportionalScale(double[] values, double minValue) {
+      for (int i = 0; i < values.Length; i++) {
+        values[i] = values[i] - minValue;
+      }
+    }
+    private static void InverseProportionalScale(double[] values, double maxValue) {
+      for (int i = 0; i < values.Length; i++) {
+        values[i] = maxValue - values[i];
+      }
+    }
+    #endregion
 
     /// <summary>
@@ -109,7 +230,8 @@
     /// <param name="keySelector">The function that selects the key.</param>
     /// <returns>The element in the enumeration where the selected key is the maximum.</returns>
-    public static T SelectMax<T, TComparable>(this IEnumerable<T> source, Func<T, TComparable> keySelector) where TComparable : IComparable {
+    public static T ChooseMax<T, TComparable>(this IEnumerable<T> source, Func<T, TComparable> keySelector) where TComparable : IComparable {
+      if (source == null) throw new ArgumentNullException("source", "sequence is null");
       IEnumerator<T> enumerator = source.GetEnumerator();
-      if (!enumerator.MoveNext()) throw new InvalidOperationException("Sequence is empty!");
+      if (!enumerator.MoveNext()) throw new ArgumentException("sequence is empty", "source");
       T result = enumerator.Current;
       TComparable max = keySelector(result);
@@ -136,7 +258,8 @@
     /// <param name="keySelector">The function that selects the key.</param>
     /// <returns>The element in the enumeration where the selected key is the minimum.</returns>
-    public static T SelectMin<T, TComparable>(this IEnumerable<T> source, Func<T, TComparable> keySelector) where TComparable : IComparable {
+    public static T ChooseMin<T, TComparable>(this IEnumerable<T> source, Func<T, TComparable> keySelector) where TComparable : IComparable {
+      if (source == null) throw new ArgumentNullException("source", "sequence is null");
       IEnumerator<T> enumerator = source.GetEnumerator();
-      if (!enumerator.MoveNext()) throw new InvalidOperationException("Sequence is empty!");
+      if (!enumerator.MoveNext()) throw new ArgumentException("sequence is empty", "source");
       T result = enumerator.Current;
       TComparable min = keySelector(result);
@@ -151,5 +274,34 @@
       return result;
     }
-
+    #endregion
+
+    #region Shuffling
+    /// <summary>
+    /// Shuffles an enumerable and returns a new enumerable according to the Fisher-Yates shuffle.
+    /// </summary>
+    /// <remarks>
+    /// Note that this is an online shuffle, but the source enumerable is transformed into an array.
+    /// 
+    /// The implementation is described in http://stackoverflow.com/questions/1287567/c-is-using-random-and-orderby-a-good-shuffle-algorithm.
+    /// </remarks>
+    /// <typeparam name="T">The type of the items that are to be shuffled.</typeparam>
+    /// <param name="source">The enumerable that contains the items.</param>
+    /// <param name="random">The random number generator, its Next(n) method must deliver uniformly distributed random numbers in the range [0;n).</param>
+    /// <returns>An enumerable with the elements shuffled.</returns>
+    public static IEnumerable<T> Shuffle<T>(this IEnumerable<T> source, IRandom random) {
+      T[] elements = source.ToArray();
+      for (int i = elements.Length - 1; i > 0; i--) {
+        // Swap element "i" with a random earlier element it (or itself)
+        int swapIndex = random.Next(i + 1);
+        yield return elements[swapIndex];
+        elements[swapIndex] = elements[i];
+        // we don't actually perform the swap, we can forget about the
+        // swapped element because we already returned it.
+      }
+      yield return elements[0];
+    }
+    #endregion
+
+    #region Graph walk
     /// <summary>
     /// Walks an operator graph in that it jumps from one operator to all its operator parameters and yields each operator it touches.
@@ -178,5 +330,5 @@
       }
     }
-
+    #endregion
   }
 }
Index: /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Common/3.3/IntegerVectorEqualityComparer.cs
===================================================================
--- /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Common/3.3/IntegerVectorEqualityComparer.cs	(revision 7431)
+++ /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Common/3.3/IntegerVectorEqualityComparer.cs	(revision 7432)
@@ -38,4 +38,21 @@
       return obj.GetHashCode();
     }
+
+    public static double GetSimilarity(IntegerVector a, IntegerVector b) {
+      int similar = 0;
+      for (int i = 0; i < a.Length; i++) {
+        if (a[i] == b[i]) similar++;
+      }
+      return similar / (double)a.Length;
+    }
+
+    public static double GetDistance(IntegerVector a, IntegerVector b) {
+      return 1.0 - GetSimilarity(a, b);
+    }
+
+    public static IEnumerable<int> GetDifferingIndices(IntegerVector a, IntegerVector b) {
+      for (int i = 0; i < a.Length; i++)
+        if (a[i] != b[i]) yield return i;
+    }
   }
 }
Index: /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment/3.3/Analyzers/BestGQAPSolutionAnalyzer.cs
===================================================================
--- /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment/3.3/Analyzers/BestGQAPSolutionAnalyzer.cs	(revision 7431)
+++ /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment/3.3/Analyzers/BestGQAPSolutionAnalyzer.cs	(revision 7432)
@@ -155,6 +155,6 @@
       int bestIndex;
       var tmp = qualities.Select((x, index) => new { Index = index, Value = x.Value });
-      if (maximization) bestIndex = tmp.SelectMax(x => x.Value).Index;
-      else bestIndex = tmp.SelectMin(x => x.Value).Index;
+      if (maximization) bestIndex = tmp.ChooseMax(x => x.Value).Index;
+      else bestIndex = tmp.ChooseMin(x => x.Value).Index;
 
       if (bestKnownQuality == null || HasSolutionImproved(bestKnownQuality.Value, qualities[bestIndex].Value, maximization)) {
Index: /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment/3.3/GQAPAssignment.cs
===================================================================
--- /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment/3.3/GQAPAssignment.cs	(revision 7431)
+++ /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment/3.3/GQAPAssignment.cs	(revision 7432)
@@ -28,5 +28,5 @@
 
 namespace HeuristicLab.Problems.GeneralizedQuadraticAssignment {
-  [Item("Generalized QAP Assignment", "Represents a solution to the generalized QAP.")]
+  [Item("Generalized QAP Assignment", "Represents the solution as well as the problem parameters of a GQAP instance.")]
   [StorableClass]
   public sealed class GQAPAssignment : Item, INotifyPropertyChanged {
Index: /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment/3.3/GQAPAssignmentArchive.cs
===================================================================
--- /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment/3.3/GQAPAssignmentArchive.cs	(revision 7431)
+++ /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment/3.3/GQAPAssignmentArchive.cs	(revision 7432)
@@ -145,4 +145,5 @@
     private GQAPAssignmentArchive(GQAPAssignmentArchive original, Cloner cloner)
       : base(original, cloner) {
+      solutions = cloner.Clone(original.solutions);
       equipmentNames = cloner.Clone(original.equipmentNames);
       locationNames = cloner.Clone(original.locationNames);
Index: anches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment/3.3/GQAPIntegerVectorProximityCalculator.cs
===================================================================
--- /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment/3.3/GQAPIntegerVectorProximityCalculator.cs	(revision 7431)
+++ 	(revision )
@@ -1,44 +1,0 @@
-﻿#region License Information
-/* HeuristicLab
- * Copyright (C) 2002-2012 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
- *
- * This file is part of HeuristicLab.
- *
- * HeuristicLab is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * HeuristicLab is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
- */
-#endregion
-
-using System.Collections.Generic;
-using HeuristicLab.Encodings.IntegerVectorEncoding;
-
-namespace HeuristicLab.Problems.GeneralizedQuadraticAssignment {
-  public static class GQAPIntegerVectorProximityCalculator {
-    public static double CalculateGenotypeSimilarity(IntegerVector a, IntegerVector b) {
-      int similar = 0;
-      for (int i = 0; i < a.Length; i++) {
-        if (a[i] == b[i]) similar++;
-      }
-      return similar / (double)a.Length;
-    }
-
-    public static double CalculateGenotypeDistance(IntegerVector a, IntegerVector b) {
-      return 1.0 - CalculateGenotypeSimilarity(a, b);
-    }
-
-    public static IEnumerable<int> GetDifference(IntegerVector a, IntegerVector b) {
-      for (int i = 0; i < a.Length; i++)
-        if (a[i] != b[i]) yield return i;
-    }
-  }
-}
Index: anches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment/3.3/GQAPSolutionStructuralEqualityComparer.cs
===================================================================
--- /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment/3.3/GQAPSolutionStructuralEqualityComparer.cs	(revision 7431)
+++ 	(revision )
@@ -1,35 +1,0 @@
-﻿#region License Information
-/* HeuristicLab
- * Copyright (C) 2002-2012 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
- *
- * This file is part of HeuristicLab.
- *
- * HeuristicLab is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * HeuristicLab is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
- */
-#endregion
-
-using System.Collections.Generic;
-
-namespace HeuristicLab.Problems.GeneralizedQuadraticAssignment {
-  public class GQAPSolutionStructuralEqualityComparer : EqualityComparer<GQAPSolution> {
-
-    public override bool Equals(GQAPSolution x, GQAPSolution y) {
-      return GQAPIntegerVectorProximityCalculator.CalculateGenotypeSimilarity(x.Assignment, y.Assignment) >= 1.0;
-    }
-
-    public override int GetHashCode(GQAPSolution obj) {
-      return obj.GetHashCode();
-    }
-  }
-}
Index: /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment/3.3/GeneralizedQuadraticAssignmentProblem.cs
===================================================================
--- /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment/3.3/GeneralizedQuadraticAssignmentProblem.cs	(revision 7431)
+++ /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment/3.3/GeneralizedQuadraticAssignmentProblem.cs	(revision 7432)
@@ -142,5 +142,5 @@
     private GeneralizedQuadraticAssignmentProblem(GeneralizedQuadraticAssignmentProblem original, Cloner cloner)
       : base(original, cloner) {
-      AttachEventHandlers();
+      RegisterEventHandlers();
     }
     public GeneralizedQuadraticAssignmentProblem()
@@ -186,5 +186,5 @@
 
       InitializeOperators();
-      AttachEventHandlers();
+      RegisterEventHandlers();
     }
 
@@ -220,8 +220,8 @@
     [StorableHook(HookType.AfterDeserialization)]
     private void AfterDeserialization() {
-      AttachEventHandlers();
-    }
-
-    private void AttachEventHandlers() {
+      RegisterEventHandlers();
+    }
+
+    private void RegisterEventHandlers() {
       Evaluator.QualityParameter.ActualNameChanged += new System.EventHandler(Evaluator_QualityParameter_ActualNameChanged);
       SolutionCreator.AssignmentParameter.ActualNameChanged += new EventHandler(SolutionCreator_IntegerVectorParameter_ActualNameChanged);
Index: /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment/3.3/HeuristicLab.Problems.GeneralizedQuadraticAssignment-3.3.csproj
===================================================================
--- /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment/3.3/HeuristicLab.Problems.GeneralizedQuadraticAssignment-3.3.csproj	(revision 7431)
+++ /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment/3.3/HeuristicLab.Problems.GeneralizedQuadraticAssignment-3.3.csproj	(revision 7432)
@@ -97,5 +97,4 @@
     <Compile Include="GeneralizedQuadraticAssignmentProblem.cs" />
     <Compile Include="GQAPAssignmentArchive.cs" />
-    <Compile Include="GQAPIntegerVectorProximityCalculator.cs" />
     <Compile Include="GQAPSolution.cs" />
     <Compile Include="Interfaces\IQualitiesAwareGQAPOperator.cs" />
Index: /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment/3.3/Operators/DemandEquivalentSwapEquipmentManipluator.cs
===================================================================
--- /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment/3.3/Operators/DemandEquivalentSwapEquipmentManipluator.cs	(revision 7431)
+++ /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment/3.3/Operators/DemandEquivalentSwapEquipmentManipluator.cs	(revision 7432)
@@ -79,7 +79,6 @@
           assignment[equipment2] = location1;
           groupedLocations[location2].Remove(equipment2);
-          bool selected;
-          equipment2 = groupedLocations[location2].ChooseRandomOrDefault(random, out selected);
-          if (!selected) break;
+          if (!groupedLocations[location2].Any()) break;
+          equipment2 = groupedLocations[location2].ChooseUniformRandom(random);
         }
       }
Index: /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment/3.3/Operators/GQAPPathRelinking.cs
===================================================================
--- /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment/3.3/Operators/GQAPPathRelinking.cs	(revision 7431)
+++ /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment/3.3/Operators/GQAPPathRelinking.cs	(revision 7432)
@@ -73,4 +73,8 @@
     public IValueLookupParameter<DoubleValue> OverbookedCapacityPenaltyParameter {
       get { return (IValueLookupParameter<DoubleValue>)Parameters["OverbookedCapacityPenalty"]; }
+    }
+
+    public IValueParameter<PercentValue> CandidateSizeFactorParameter {
+      get { return (IValueParameter<PercentValue>)Parameters["CandidateSizeFactor"]; }
     }
 
@@ -92,4 +96,5 @@
       Parameters.Add(new ValueLookupParameter<DoubleValue>("TransportationCosts", GeneralizedQuadraticAssignmentProblem.TransportationCostsDescription));
       Parameters.Add(new ValueLookupParameter<DoubleValue>("OverbookedCapacityPenalty", GeneralizedQuadraticAssignmentProblem.OverbookedCapacityPenaltyDescription));
+      Parameters.Add(new ValueParameter<PercentValue>("CandidateSizeFactor", "(η) Determines the size of the set of feasible moves in each path-relinking step relative to the maximum size. A value of 50% means that only half of all possible moves are considered each step.", new PercentValue(0.5)));
     }
 
@@ -98,7 +103,8 @@
     }
 
-    public static IntegerVector Apply(IRandom random, ItemArray<IntegerVector> parents, ItemArray<DoubleValue> qualities, DoubleArray demands,
-      DoubleArray capacities, DoubleMatrix weights, DoubleMatrix distances, DoubleMatrix installationCosts, DoubleValue transportationCosts,
-      DoubleValue overbookedCapacityPenalty) {
+    public static IntegerVector Apply(IRandom random, ItemArray<IntegerVector> parents, BoolValue maximization, ItemArray<DoubleValue> qualities,
+      ItemArray<DoubleValue> flowDistanceQualities, ItemArray<DoubleValue> installationQualities, ItemArray<DoubleValue> overbookedCapacities,
+      DoubleArray demands, DoubleArray capacities, DoubleMatrix weights, DoubleMatrix distances, DoubleMatrix installationCosts,
+      DoubleValue transportationCosts, DoubleValue overbookedCapacityPenalty, DoubleValue candidateSizeFactor) {
       if (random == null) throw new ArgumentNullException("random", "No IRandom provider is given.");
       if (parents == null || !parents.Any()) throw new ArgumentException("No parents given for path relinking.", "parents");
@@ -110,59 +116,136 @@
       var source = parents[0];
       var target = parents[1];
-
-      var nu = 1.0;
+      IntegerVector result;
+      double resultQuality, resultFDQ, resultIQ, resultOC;
+
+      int betterParent = 1;
+      if ((maximization.Value && qualities[0].Value >= qualities[1].Value)
+        || (!maximization.Value && qualities[0].Value <= qualities[1].Value))
+        betterParent = 0;
+
+      result = (IntegerVector)parents[betterParent].Clone();
+      resultQuality = qualities[betterParent].Value;
+      resultFDQ = flowDistanceQualities[betterParent].Value;
+      resultIQ = installationQualities[betterParent].Value;
+      resultOC = overbookedCapacities[betterParent].Value;
+
       var pi_prime = (IntegerVector)source.Clone();
       var fix = new HashSet<int>();
       var nonFix = new HashSet<int>(Enumerable.Range(0, demands.Length));
-      var phi = new HashSet<int>(GQAPIntegerVectorProximityCalculator.GetDifference(pi_prime, target));
+      var phi = new HashSet<int>(IntegerVectorEqualityComparer.GetDifferingIndices(pi_prime, target));
 
       while (phi.Any()) {
-        var B = new HashSet<GQAPSolution>(new GQAPSolutionStructuralEqualityComparer());
+        var B = new List<GQAPSolution>();
         foreach (var v in phi) {
+          int oldLocation = pi_prime[v];
           pi_prime[v] = target[v];
-          var pi2 = makeFeasible(pi_prime, v);
-
-          double flowDistanceQuality, installationQuality, overbookedCapacity;
+          var pi2 = makeFeasible(random, pi_prime, v, nonFix, demands, capacities);
+          pi_prime[v] = oldLocation;
+
+          double currentFDQ, currentIQ, currentOC;
           GQAPEvaluator.Evaluate(pi2, weights, distances, installationCosts, demands, capacities,
-            out flowDistanceQuality, out installationQuality, out overbookedCapacity);
-
-          if (overbookedCapacity <= 0.0) {
-            var quality = GQAPEvaluator.GetCombinedQuality(flowDistanceQuality, installationQuality, overbookedCapacity,
+            out currentFDQ, out currentIQ, out currentOC);
+
+          if (currentOC <= 0.0) {
+            var quality = GQAPEvaluator.GetCombinedQuality(currentFDQ, currentIQ, currentOC,
                 transportationCosts.Value, overbookedCapacityPenalty.Value);
-            var solution = new GQAPSolution(pi2, new DoubleValue(quality), new DoubleValue(flowDistanceQuality), new DoubleValue(installationQuality), new DoubleValue(overbookedCapacity));
-            if (B.Count >= nu * phi.Count) {
-              if (!B.Contains(solution) && quality <= B.Select(x => x.Quality.Value).Max()) {
-                // TODO: replace most similar element in B with worse cost
+            var solution = new GQAPSolution(pi2, new DoubleValue(quality), new DoubleValue(currentFDQ),
+              new DoubleValue(currentIQ), new DoubleValue(currentOC));
+            if (B.Count >= candidateSizeFactor.Value * phi.Count) {
+              int mostSimilarIndex = -1;
+              double mostSimilarValue = 1.0;
+              for (int i = 0; i < B.Count; i++) {
+                if (IsBetter(maximization.Value, solution.Quality.Value, B[i].Quality.Value)) {
+                  var similarity = IntegerVectorEqualityComparer.GetSimilarity(solution.Assignment, B[i].Assignment);
+                  if (similarity == 1.0) {
+                    mostSimilarIndex = -1;
+                    break;
+                  } else if (similarity < mostSimilarValue) {
+                    mostSimilarValue = similarity;
+                    mostSimilarIndex = i;
+                  }
+                }
               }
-            } else if (!B.Contains(solution)) {
-              B.Add(solution);
+              if (mostSimilarIndex >= 0)
+                B[mostSimilarIndex] = solution;
+            } else {
+              bool contains = false;
+              foreach (var b in B) {
+                if (!IntegerVectorEqualityComparer.GetDifferingIndices(solution.Assignment, b.Assignment).Any()) {
+                  contains = true;
+                  break;
+                }
+              }
+              if (!contains) B.Add(solution);
             }
           }
         }
         if (B.Any()) {
-          var pi = B.ChooseRandom(random);
-          var diff = GQAPIntegerVectorProximityCalculator.GetDifference(pi.Assignment, target);
-          var I = phi.Except(phi.Intersect(diff));
-          var i = I.ChooseRandom(random);
+          GQAPSolution pi;
+          if (maximization.Value) pi = B.ChooseProportionalRandom(random, 1, x => x.Quality.Value, false, true).First();
+          else pi = B.ChooseProportionalRandom(random, 1, x => 1.0 / x.Quality.Value, false, true).First();
+          var diff = IntegerVectorEqualityComparer.GetDifferingIndices(pi.Assignment, target);
+          var I = phi.Except(diff);
+          var i = I.ChooseUniformRandom(random);
           fix.Add(i);
           nonFix.Remove(i);
           pi_prime = pi.Assignment;
-          // TODO
-        }
+          if (IsBetter(maximization.Value, pi.Quality.Value, resultQuality)) {
+            result = pi.Assignment;
+            resultQuality = pi.Quality.Value;
+            resultFDQ = pi.FlowDistanceQuality.Value;
+            resultIQ = pi.InstallationQuality.Value;
+            resultOC = pi.OverbookedCapacity.Value;
+          }
+        } else return result;
+        phi = new HashSet<int>(IntegerVectorEqualityComparer.GetDifferingIndices(pi_prime, target));
       }
 
-      return pi_prime;
+      return result;
     }
 
     protected override IntegerVector Cross(IRandom random, ItemArray<IntegerVector> parents) {
-      return Apply(random, parents, QualityParameter.ActualValue, DemandsParameter.ActualValue,
+      return Apply(random, parents, MaximizationParameter.ActualValue, QualityParameter.ActualValue, FlowDistanceQualityParameter.ActualValue,
+        InstallationQualityParameter.ActualValue, OverbookedCapacityParameter.ActualValue, DemandsParameter.ActualValue,
         CapacitiesParameter.ActualValue, WeightsParameter.ActualValue, DistancesParameter.ActualValue,
         InstallationCostsParameter.ActualValue, TransportationCostsParameter.ActualValue,
-        OverbookedCapacityPenaltyParameter.ActualValue);
-    }
-
-    private static IntegerVector makeFeasible(IntegerVector assignment, int equipment) {
-      // TODO: implement
-      return assignment;
+        OverbookedCapacityPenaltyParameter.ActualValue, CandidateSizeFactorParameter.Value);
+    }
+
+    private static IntegerVector makeFeasible(IRandom random, IntegerVector assignment, int equipment, HashSet<int> nonFix, DoubleArray demands, DoubleArray capacities, int maximumTries = 1000) {
+      int l = assignment[equipment];
+      var slack = ComputeSlack(assignment, demands, capacities);
+      if (slack[l] >= 0) return (IntegerVector)assignment.Clone();
+
+      IntegerVector result = null;
+      int k = 0;
+      while (k < maximumTries && slack[l] < 0) {
+        result = (IntegerVector)assignment.Clone();
+        do {
+          var maxSlack = slack.Max();
+          var T = nonFix.Where(x => x != equipment && assignment[x] == l && demands[x] <= maxSlack);
+          if (T.Any()) {
+            int i = T.ChooseProportionalRandom(random, 1, x => demands[x], false, true).First();
+            var j = Enumerable.Range(0, capacities.Length).Where(x => slack[x] >= demands[i]).ChooseUniformRandom(random);
+            result[i] = j;
+            slack[j] -= demands[i];
+            slack[l] += demands[i];
+          } else break;
+        } while (slack[l] < 0);
+        k++;
+      }
+      return result;
+    }
+
+    private static DoubleArray ComputeSlack(IntegerVector assignment, DoubleArray demands, DoubleArray capacities) {
+      var slack = (DoubleArray)capacities.Clone();
+      for (int i = 0; i < assignment.Length; i++) {
+        slack[assignment[i]] -= demands[i];
+      }
+      return slack;
+    }
+
+    private static bool IsBetter(bool maximization, double quality, double otherQuality) {
+      return maximization && quality > otherQuality || !maximization && quality < otherQuality;
     }
   }
Index: /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment/3.3/Operators/GreedyRandomizedSolutionCreator.cs
===================================================================
--- /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment/3.3/Operators/GreedyRandomizedSolutionCreator.cs	(revision 7431)
+++ /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment/3.3/Operators/GreedyRandomizedSolutionCreator.cs	(revision 7432)
@@ -70,5 +70,5 @@
         do {
           if (L.Any() && random.NextDouble() < threshold) {
-            int l = L.ChooseRandom(random);
+            int l = L.ChooseUniformRandom(random);
             L.Remove(l);
             CL.Add(l);
@@ -76,9 +76,9 @@
           }
           if (T.Any()) {
-            int f = T.ChooseRandom(random);
+            int f = T.ChooseUniformRandom(random);
             T.Remove(f);
             F.Remove(f);
             CF.Add(f);
-            int l = WithSlackGreaterOrEqual(CL, demands[f], slack).ChooseRandom(random);
+            int l = WithSlackGreaterOrEqual(CL, demands[f], slack).ChooseUniformRandom(random);
             assignment.Add(f, l);
             slack[l] -= demands[f];
Index: /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment/3.3/Operators/QualitySimilarityMerger.cs
===================================================================
--- /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment/3.3/Operators/QualitySimilarityMerger.cs	(revision 7431)
+++ /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment/3.3/Operators/QualitySimilarityMerger.cs	(revision 7432)
@@ -94,5 +94,5 @@
 
       foreach (var candidate in candidates) {
-        double[] similarities = population.Select(x => GQAPIntegerVectorProximityCalculator.CalculateGenotypeSimilarity(x.Solution, candidate.Solution)).ToArray();
+        double[] similarities = population.Select(x => IntegerVectorEqualityComparer.GetSimilarity(x.Solution, candidate.Solution)).ToArray();
         if (!similarities.Any()) {
           population.Add(candidate);
Index: /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment/3.3/Operators/RelocateEquipmentManipluator.cs
===================================================================
--- /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment/3.3/Operators/RelocateEquipmentManipluator.cs	(revision 7431)
+++ /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment/3.3/Operators/RelocateEquipmentManipluator.cs	(revision 7432)
@@ -72,19 +72,21 @@
       }
 
-      bool selected;
-      var overstuffedLocation = usedCapacities.Where(x => capacities[x.Key] < x.Value).ChooseRandomOrDefault(random, out selected);
-      if (selected) {
-        int equipment = groupedLocations[overstuffedLocation.Key].ChooseRandomOrDefault(random, out selected);
-        var freeLocations = usedCapacities.Where(x => capacities[x.Key] > x.Value).ToList();
-        var location = freeLocations.Where(x => capacities[x.Key] > x.Value + demands[equipment]).ChooseRandomOrDefault(random, out selected);
-        if (selected) {
-          assignment[equipment] = location.Key;
-        } else {
-          location = freeLocations.ChooseRandomOrDefault(random, out selected);
-          if (selected) assignment[equipment] = location.Key;
-          else assignment[equipment] = random.Next(locations);
-        }
-      } else {
+      var overbookedLocations = usedCapacities.Where(x => capacities[x.Key] < x.Value);
+      var freeLocations = usedCapacities.Where(x => capacities[x.Key] > x.Value);
+      if (!overbookedLocations.Any() || !freeLocations.Any()) { // perform a random relocation
         assignment[random.Next(assignment.Length)] = random.Next(locations);
+        return;
+      }
+
+      var sourceLocation = overbookedLocations.ChooseUniformRandom(random);
+      int equipmentToRelocate = groupedLocations[sourceLocation.Key].ChooseUniformRandom(random);
+      var bestFreeLocations = freeLocations.Where(x => capacities[x.Key] > x.Value + demands[equipmentToRelocate]);
+
+      if (bestFreeLocations.Any()) { // a feasible solution will still be feasible, an infeasible solution might become feasible
+        var selected = bestFreeLocations.ChooseUniformRandom(random);
+        assignment[equipmentToRelocate] = sourceLocation.Key;
+      } else { // the solution will become infeasible
+        sourceLocation = freeLocations.ChooseUniformRandom(random);
+        assignment[equipmentToRelocate] = sourceLocation.Key;
       }
     }
