Index: /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment/3.3/Operators/Crossovers/GQAPPathRelinking.cs
===================================================================
--- /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment/3.3/Operators/Crossovers/GQAPPathRelinking.cs	(revision 15554)
+++ /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment/3.3/Operators/Crossovers/GQAPPathRelinking.cs	(revision 15555)
@@ -32,4 +32,7 @@
 
 namespace HeuristicLab.Problems.GeneralizedQuadraticAssignment {
+  /// <summary>
+  /// This is an implementation of the algorithm described in Mateus, G.R., Resende, M.G.C. & Silva, R.M.A. J Heuristics (2011) 17: 527. https://doi.org/10.1007/s10732-010-9144-0
+  /// </summary>
   [Item("GQAPPathRelinking", "Operator that performs path relinking between two solutions. It is described in Mateus, G., Resende, M., and Silva, R. 2011. GRASP with path-relinking for the generalized quadratic assignment problem. Journal of Heuristics 17, Springer Netherlands, pp. 527-565.")]
   [StorableClass]
@@ -71,4 +74,5 @@
       var cmp = new IntegerVectorEqualityComparer();
 
+      var greedy = true; // greedy performed better according to the paper
       var sFit = problemInstance.ToSingleObjective(sourceEval);
       var tFit = problemInstance.ToSingleObjective(targetEval);
@@ -114,5 +118,11 @@
         }
         if (B.Count > 0) { // line 21 of Algorithm 4
-          var pi = B.SampleProportional(random, 1, B_fit.Select(x => 1.0 / x), false).First(); // line 22 of Algorithm 4
+          GQAPSolution pi;
+          // line 22 of Algorithm 4
+          if (greedy) {
+            pi = B.Select((val, idx) => new { Index = idx, Value = val }).MinItems(x => B_fit[x.Index]).Shuffle(random).First().Value;
+          } else {
+            pi = B.SampleProportional(random, 1, B_fit.Select(x => 1.0 / x), false).First();
+          }
           var diff = IntegerVectorEqualityComparer.GetDifferingIndices(pi.Assignment, target); // line 23 of Algorithm 4
           var I = phi.Except(diff); // line 24 of Algorithm 4
@@ -126,9 +136,9 @@
             pi_star = pi; // line 30 of Algorithm 4
           }
-        } else return pi_star ?? new GQAPSolution((IntegerVector)source.Clone(), (Evaluation)sourceEval.Clone());
+        } else return pi_star;
         phi = new HashSet<int>(IntegerVectorEqualityComparer.GetDifferingIndices(pi_prime, target));
       }
 
-      return pi_star ?? new GQAPSolution((IntegerVector)source.Clone(), (Evaluation)sourceEval.Clone());
+      return pi_star;
     }
 
Index: /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment/3.3/Operators/LocalImprovers/ApproximateLocalSearch.cs
===================================================================
--- /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment/3.3/Operators/LocalImprovers/ApproximateLocalSearch.cs	(revision 15554)
+++ /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment/3.3/Operators/LocalImprovers/ApproximateLocalSearch.cs	(revision 15555)
@@ -31,6 +31,10 @@
 using HeuristicLab.Parameters;
 using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Random;
 
 namespace HeuristicLab.Problems.GeneralizedQuadraticAssignment {
+  /// <summary>
+  /// This is an implementation of the algorithm described in Mateus, G.R., Resende, M.G.C. & Silva, R.M.A. J Heuristics (2011) 17: 527. https://doi.org/10.1007/s10732-010-9144-0
+  /// </summary>
   [Item("ApproximateLocalSearch", "The approximate local search is described in Mateus, G., Resende, M., and Silva, R. 2011. GRASP with path-relinking for the generalized quadratic assignment problem. Journal of Heuristics 17, Springer Netherlands, pp. 527-565.")]
   [StorableClass]
@@ -105,7 +109,4 @@
 
       /// <summary>
-      /// The implementation differs slightly from Mateus et al. in that the maximumIterations parameter defines a cap
-      /// on the number of steps that the local search can perform. While the maxSampleSize parameter corresponds to
-      /// the maxItr parameter defined by Mateus et al.
       /// </summary>
       /// <param name="random">The random number generator to use.</param>
@@ -127,37 +128,31 @@
       var evaluations = 0.0;
       var deltaEvaluationFactor = 1.0 / assignment.Length;
-      while (true) {
-        int count = 0;
-        var CLS = new List<Tuple<NMove, double, Evaluation>>();
-        double sum = 0.0;
+      var greedy = true; // greedy selection performed better in 5 of 8 instances according to the paper
+      while (true) { // line 1 of Algorithm 3
+        var count = 0; // line 2 of Algorithm 3
+        var CLS = new List<Tuple<NMove, double, Evaluation>>(); // line 3 of Algorithm 3
         do {
-          NMove move;
-          if (random.NextDouble() < oneMoveProbability)
-            move = StochasticNMoveSingleMoveGenerator.GenerateOneMove(random, assignment, capacities);
-          else move = StochasticNMoveSingleMoveGenerator.GenerateTwoMove(random, assignment, capacities);
-          
+          var move = Move(random, assignment, oneMoveProbability, capacities); // line 4 of Algorithm 3
+
           var moveEval = GQAPNMoveEvaluator.Evaluate(move, assignment, evaluation, problemInstance);
           evaluations += move.Indices.Count * deltaEvaluationFactor;
           double moveQuality = problemInstance.ToSingleObjective(moveEval);
 
-          if (moveEval.ExcessDemand <= 0.0 && moveQuality < quality) {
-            CLS.Add(Tuple.Create(move, moveQuality, moveEval));
-            sum += 1.0 / moveQuality;
+          if (moveEval.ExcessDemand <= 0.0 && moveQuality < quality) { // line 5 of Algorithm 3
+            CLS.Add(Tuple.Create(move, moveQuality, moveEval)); // line 6 of Algorithm 3
           }
-          count++;
-        } while (CLS.Count < maxCLS && count < maximumIterations);
+          count++; // line 8 of Algorithm 3
+        } while (CLS.Count < maxCLS && count < maximumIterations); // line 9 of Algorithm 3
 
-        if (CLS.Count == 0) {
+        if (CLS.Count == 0) { // line 10 of Algorithm 3
           evaluatedSolutions += (int)Math.Ceiling(evaluations);
           return; // END
         } else {
-          var ball = random.NextDouble() * sum;
-          var selected = CLS.Last();
-          foreach (var candidate in CLS) {
-            ball -= 1.0 / candidate.Item2;
-            if (ball <= 0.0) {
-              selected = candidate;
-              break;
-            }
+          // line 11 of Algorithm 3
+          Tuple<NMove, double, Evaluation> selected;
+          if (greedy) {
+            selected = CLS.MinItems(x => x.Item2).Shuffle(random).First();
+          } else {
+            selected = CLS.SampleProportional(random, 1, CLS.Select(x => 1.0 / x.Item2), false, false).Single();
           }
           NMoveMaker.Apply(assignment, selected.Item1);
@@ -166,4 +161,10 @@
         }
       }
+    }
+
+    private static NMove Move(IRandom random, IntegerVector assignment, double oneMoveProbability, DoubleArray capacities) {
+      if (random.NextDouble() < oneMoveProbability)
+        return StochasticNMoveSingleMoveGenerator.GenerateOneMove(random, assignment, capacities);
+      return StochasticNMoveSingleMoveGenerator.GenerateTwoMove(random, assignment, capacities);
     }
 
Index: /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment/3.3/SolutionCreators/GreedyRandomizedSolutionCreator.cs
===================================================================
--- /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment/3.3/SolutionCreators/GreedyRandomizedSolutionCreator.cs	(revision 15554)
+++ /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment/3.3/SolutionCreators/GreedyRandomizedSolutionCreator.cs	(revision 15555)
@@ -33,4 +33,7 @@
 
 namespace HeuristicLab.Problems.GeneralizedQuadraticAssignment {
+  /// <summary>
+  /// This is an implementation of the algorithm described in Mateus, G.R., Resende, M.G.C. & Silva, R.M.A. J Heuristics (2011) 17: 527. https://doi.org/10.1007/s10732-010-9144-0
+  /// </summary>
   [Item("GreedyRandomizedSolutionCreator", "Creates a solution according to the procedure described in Mateus, G., Resende, M., and Silva, R. 2011. GRASP with path-relinking for the generalized quadratic assignment problem. Journal of Heuristics 17, Springer Netherlands, pp. 527-565.")]
   [StorableClass]
@@ -60,6 +63,9 @@
     public static IntegerVector CreateSolution(IRandom random, GQAPInstance problemInstance,
       int maximumTries, bool createMostFeasibleSolution, CancellationToken cancelToken) {
+      var weights = problemInstance.Weights;
+      var distances = problemInstance.Distances;
       var demands = problemInstance.Demands;
       var capacities = problemInstance.Capacities.ToArray();
+      var transportCosts = problemInstance.TransportationCosts;
       var equipments = demands.Length;
       var locations = capacities.Length;
@@ -69,48 +75,92 @@
       double minViolation = double.MaxValue;
       int[] bestAssignment = null;
-      var CF = new bool[equipments]; // set of chosen facilities / equipments
-      var T = new List<int>(equipments); // set of facilities / equpiments that can be assigned to the set of chosen locations (CL)
+      var F = new List<int>(equipments); // set of (initially) all facilities / equipments
+      var CF = new List<int>(equipments); // set of chosen facilities / equipments
+      var L = new List<int>(locations); // set of (initially) all locations
       var CL_list = new List<int>(locations); // list of chosen locations
       var CL_selected = new bool[locations]; // bool decision if location is chosen
-      var F = new List<int>(equipments); // set of (initially) all facilities / equipments
-      var L = new List<int>(locations); // set of (initially) all locations
-      
+      var T = new List<int>(equipments); // set of facilities / equpiments that can be assigned to the set of chosen locations (CL)
+      var H = new double[locations]; // proportions for choosing locations in stage 1
+      var W = new double[equipments]; // proportions for choosing facilities in stage 2
+      var Z = new double[locations]; // proportions for choosing locations in stage 2
+
       while (maximumTries <= 0 || tries < maximumTries) {
         cancelToken.ThrowIfCancellationRequested();
 
-        Array.Copy(capacities, slack, locations);
-        Array.Clear(CF, 0, equipments);
-        Array.Clear(CL_selected, 0, locations);
-        CL_list.Clear();
-        T.Clear();
-
-        F.Clear(); F.AddRange(Enumerable.Range(0, equipments));
-        L.Clear(); L.AddRange(Enumerable.Range(0, locations));
-
-        double threshold = 1.0;
-        do {
-          if (L.Count > 0 && random.NextDouble() < threshold) {
-            int l = L.SampleRandom(random);
-            L.Remove(l);
-            CL_list.Add(l);
-            CL_selected[l] = true;
-            T = new List<int>(WhereDemandEqualOrLess(F, GetMaximumSlack(slack, CL_selected), demands));
-          }
-          if (T.Count > 0) {
-            var fidx = Enumerable.Range(0, T.Count).SampleRandom(random);
-            var f = T[fidx];
-            T.RemoveAt(fidx);
-            F.Remove(f); // TODO: slow
-            CF[f] = true;
-            int l = WhereSlackGreaterOrEqual(CL_list, demands[f], slack).SampleRandom(random);
-            assignment[f] = l + 1;
+        Array.Copy(capacities, slack, locations); // line 2 of Algorihm 2
+        CF.Clear(); // line 2 of Algorihm 2
+        Array.Clear(CL_selected, 0, locations); // line 2 of Algorihm 2
+        CL_list.Clear(); // line 2 of Algorihm 2
+        T.Clear(); // line 2 of Algorihm 2
+
+        F.Clear(); F.AddRange(Enumerable.Range(0, equipments)); // line 2 of Algorihm 2
+        L.Clear(); L.AddRange(Enumerable.Range(0, locations)); // line 2 of Algorihm 2
+
+        double threshold = 1.0; // line 3 of Algorithm 2
+        do { // line 4 of Algorithm 2
+          if (L.Count > 0 && random.NextDouble() < threshold) { // line 5 of Algorithm 2
+            // H is the proportion that a location is chosen
+            // The paper doesn't mention what happens if the candidate list CL
+            // does not contain an element in which case according to the formula
+            // all H_k elements would be 0 which would be equal to random selection
+            var HH = H.Select((v, i) => new { Index = i, Value = v })
+              .Where(x => !CL_selected[x.Index])
+              .Select(x => x.Value);
+            int l = L.SampleProportional(random, 1, HH, false, false).Single(); // line 6 of Algorithm 2
+            L.Remove(l); // line 7 of Algorithm 2
+            CL_list.Add(l); // line 7 of Algorithm 2
+            CL_selected[l] = true; // line 7 of Algorithm 2
+            for (var k = 0; k < locations; k++)
+              if (!CL_selected[k])
+                H[k] += capacities[k] * capacities[l] / distances[k, l];
+            T = new List<int>(WhereDemandEqualOrLess(F, GetMaximumSlack(slack, CL_selected), demands)); // line 8 of Algorithm 2
+          }
+          if (T.Count > 0) { // line 10 of Algorithm 2
+            // W is the proportion that an equipment is chosen
+            Array.Clear(W, 0, W.Length);
+            var wk = 0;
+            foreach (var k in T) {
+              for (var h = 0; h < equipments; h++) {
+                if (k == h) continue;
+                W[wk] += weights[k, h];
+              }
+              W[wk] *= demands[k];
+              wk++;
+            }
+            var f = T.SampleProportional(random, 1, W.Take(T.Count), false, false) // line 11 of Algorithm 2
+              .Single();
+            T.Remove(f); // line 12 of Algorithm 2
+            F.Remove(f); // line 12 of Algorithm 2
+            CF.Add(f); // line 12 of Algorithm 2
+            var R = WhereSlackGreaterOrEqual(CL_list, demands[f], slack).ToList(); // line 13 of Algorithm 2
+            // Z is the proportion that a location is chosen in stage 2
+            Array.Clear(Z, 0, Z.Length);
+            var zk = 0;
+            foreach (var k in R) {
+              // d is an increase in fitness if f would be assigned to location k
+              var d = problemInstance.InstallationCosts[f, k];
+              foreach (var i in CF) {
+                if (assignment[i] == 0) continue; // i is unassigned
+                var j = assignment[i] - 1;
+                d += transportCosts * weights[f, i] * distances[k, j];
+              }
+              foreach (var h in CL_list) {
+                if (k == h) continue;
+                Z[zk] += slack[k] * capacities[h] / (d * distances[k, h]);
+              }
+              zk++;
+            }
+            int l = R.SampleProportional(random, 1, Z.Take(R.Count), false, false).Single(); // line 14 of Algorithm 2
+            assignment[f] = l + 1; // line 15 of Algorithm 2
             slack[l] -= demands[f];
-            T = new List<int>(WhereDemandEqualOrLess(F, GetMaximumSlack(slack, CL_selected), demands));
-            threshold = 1.0 - (double)T.Count / Math.Max(F.Count, 1.0);
-          }
-        } while (T.Count > 0 || L.Count > 0);
+            T = new List<int>(WhereDemandEqualOrLess(F, GetMaximumSlack(slack, CL_selected), demands)); // line 16 of Algorithm 2
+            threshold = 1.0 - (double)T.Count / Math.Max(F.Count, 1.0); // line 17 of Algorithm 2
+          }
+        } while (T.Count > 0 || L.Count > 0); // line 19 of Algorithm 2
+
         if (maximumTries > 0) tries++;
+
         if (F.Count == 0) {
-          bestAssignment = assignment;
+          bestAssignment = assignment.Select(x => x - 1).ToArray();
           break;
         } else if (createMostFeasibleSolution) {
@@ -130,15 +180,15 @@
           double violation = slack.Select(x => x < 0 ? -x : 0).Sum();
           if (violation < minViolation) {
-            bestAssignment = assignment;
-            assignment = new int[equipments];
+            bestAssignment = assignment.Select(x => x - 1).ToArray();
             minViolation = violation;
           }
+          assignment = new int[equipments];
         }
       }
 
-      if (bestAssignment == null || bestAssignment.Any(x => x == 0))
+      if (bestAssignment == null)
         throw new InvalidOperationException(String.Format("No solution could be found in {0} tries.", maximumTries));
 
-      return new IntegerVector(bestAssignment.Select(x => x - 1).ToArray());
+      return new IntegerVector(bestAssignment);
     }
 
Index: /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment/3.3/SolutionCreators/RandomButFeasibleSolutionCreator.cs
===================================================================
--- /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment/3.3/SolutionCreators/RandomButFeasibleSolutionCreator.cs	(revision 15554)
+++ /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment/3.3/SolutionCreators/RandomButFeasibleSolutionCreator.cs	(revision 15555)
@@ -65,6 +65,6 @@
       int counter = 0;
       double minViolation = double.MaxValue;
-      var slack = new DoubleArray(capacities.Length);
-      var assignment = new IntegerVector(demands.Length);
+      var slack = new double[capacities.Length];
+      var assignment = new int[demands.Length];
 
       while (!isFeasible) {
@@ -86,5 +86,5 @@
         isFeasible = violation == 0;
         if (isFeasible || violation < minViolation) {
-          result = (IntegerVector)assignment.Clone();
+          result = new IntegerVector(assignment);
           minViolation = violation;
         }
@@ -100,5 +100,5 @@
     }
 
-    private static IEnumerable<int> GetFreeLocations(int equipment, DoubleArray demands, DoubleArray freeCapacities) {
+    private static IEnumerable<int> GetFreeLocations(int equipment, DoubleArray demands, double[] freeCapacities) {
       var freeLocations = freeCapacities
         .Select((v, idx) => new KeyValuePair<int, double>(idx, v))
Index: /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment/3.3/SolutionCreators/SlackMinimizationSolutionCreator.cs
===================================================================
--- /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment/3.3/SolutionCreators/SlackMinimizationSolutionCreator.cs	(revision 15554)
+++ /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment/3.3/SolutionCreators/SlackMinimizationSolutionCreator.cs	(revision 15555)
@@ -74,5 +74,5 @@
       int counter = 0;
       double minViolation = double.MaxValue;
-      var slack = new DoubleArray(capacities.Length);
+      var slack = new double[capacities.Length];
       var assignment = new Dictionary<int, int>(demands.Length);
 
@@ -150,5 +150,5 @@
     }
 
-    private static void RandomFeasibleWalk(IRandom random, Dictionary<int, int> assignment, DoubleArray demands, DoubleArray slack, int walkLength) {
+    private static void RandomFeasibleWalk(IRandom random, Dictionary<int, int> assignment, DoubleArray demands, double[] slack, int walkLength) {
       for (int i = 0; i < walkLength; i++) {
         var equipments = Enumerable.Range(0, demands.Length).Shuffle(random);
