Index: branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms/3.3/GRASP.cs
===================================================================
--- branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms/3.3/GRASP.cs	(revision 15557)
+++ branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms/3.3/GRASP.cs	(revision 15558)
@@ -108,6 +108,6 @@
     }
     [Storable]
-    private FixedValueParameter<PercentValue> minimumDifferenceParameter;
-    public IFixedValueParameter<PercentValue> MinimumDifferenceParameter {
+    private FixedValueParameter<IntValue> minimumDifferenceParameter;
+    public IFixedValueParameter<IntValue> MinimumDifferenceParameter {
       get { return minimumDifferenceParameter; }
     }
@@ -121,11 +121,19 @@
       set { seedParameter.Value.Value = value; }
     }
+    public int EliteSetSize {
+      get { return eliteSetSizeParameter.Value.Value; }
+      set { eliteSetSizeParameter.Value.Value = value; }
+    }
     public int MinimumEliteSetSize {
       get { return minimiumEliteSetSizeParameter.Value.Value; }
       set { minimiumEliteSetSizeParameter.Value.Value = value; }
     }
-    public int EliteSetSize {
-      get { return eliteSetSizeParameter.Value.Value; }
-      set { eliteSetSizeParameter.Value.Value = value; }
+    public int MaximumIterations {
+      get { return maximumIterationsParameter.Value.Value; }
+      set { maximumIterationsParameter.Value.Value = value; }
+    }
+    public int MaximumLocalSearchIterations {
+      get { return maximumLocalSearchIterationsParameter.Value.Value; }
+      set { maximumLocalSearchIterationsParameter.Value.Value = value; }
     }
     public double CandidateSizeFactor {
@@ -141,5 +149,5 @@
       set { oneMoveProbabilityParameter.Value.Value = value; }
     }
-    public double MinimumDifference {
+    public int MinimumDifference {
       get { return minimumDifferenceParameter.Value.Value; }
       set { minimumDifferenceParameter.Value.Value = value; }
@@ -174,5 +182,5 @@
       Parameters.Add(maximumCandidateListSizeParameter = new FixedValueParameter<IntValue>("MaximumCandidateListSize", "The maximum number of candidates that should be found in each step.", new IntValue(10)));
       Parameters.Add(oneMoveProbabilityParameter = new FixedValueParameter<PercentValue>("OneMoveProbability", "The probability for performing a 1-move, which is the opposite of performing a 2-move.", new PercentValue(.5)));
-      Parameters.Add(minimumDifferenceParameter = new FixedValueParameter<PercentValue>("MinimumDifference", "The minimum amount of difference between two solutions so that they are both accepted in the elite set.", new PercentValue(1e-7)));
+      Parameters.Add(minimumDifferenceParameter = new FixedValueParameter<IntValue>("MinimumDifference", "The minimum amount of difference between two solutions so that they are both accepted in the elite set.", new IntValue(4)));
       Problem = new GQAP();
     }
@@ -252,5 +260,5 @@
             var fit = Problem.ProblemInstance.ToSingleObjective(pi_prime.Evaluation);
             double[] similarities = context.Population.Select(x => HammingSimilarityCalculator.CalculateSimilarity(x.Solution.Assignment, pi_prime.Assignment)).ToArray();
-            if (similarities.Max() <= 1.0 - MinimumDifference) { // cond. 2 of line 13 in Algorithm 1
+            if (similarities.Max() <= 1.0 - (MinimumDifference / (double)pi_prime.Assignment.Length)) { // cond. 2 of line 13 in Algorithm 1
               var replacement = context.Population.Select((v, i) => new { V = v, Index = i })
                                           .Where(x => x.V.Fitness >= fit).ToArray();
@@ -277,6 +285,4 @@
         }
 
-        context.Iterations++;
-
         IResult result;
         if (Results.TryGetValue("Iterations", out result))
@@ -294,4 +300,6 @@
 
         context.RunOperator(analyzerParameter.Value, context.Scope, cancellationToken);
+
+        context.Iterations++;
       }
     }
@@ -299,5 +307,5 @@
     private bool IsSufficientlyDifferent(IntegerVector vec) {
       return context.Population.All(x =>
-        HammingSimilarityCalculator.CalculateSimilarity(x.Solution.Assignment, vec) <= 1.0 - MinimumDifference
+        HammingSimilarityCalculator.CalculateSimilarity(vec, x.Solution.Assignment) <= 1.0 - (MinimumDifference / (double)vec.Length)
       );
     }
@@ -329,10 +337,10 @@
       var localSearchEvaluations = 0;
       ApproximateLocalSearch.Apply(context.Random, pi_prime, MaximumCandidateListSize,
-        OneMoveProbability, 1000, Problem.ProblemInstance, out localSearchEvaluations);
+        OneMoveProbability, MaximumLocalSearchIterations, Problem.ProblemInstance, out localSearchEvaluations);
       context.EvaluatedSolutions += localSearchEvaluations;
     }
 
     private bool StoppingCriterion() {
-      return context.Iterations > MaximumIterationsParameter.Value.Value;
+      return context.Iterations > MaximumIterations;
     }
   }
Index: branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms/3.3/GRASPContext.cs
===================================================================
--- branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms/3.3/GRASPContext.cs	(revision 15557)
+++ branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms/3.3/GRASPContext.cs	(revision 15558)
@@ -174,24 +174,4 @@
       scope.Variables.Add(new Variable("Evaluation", code.Evaluation));
       return scope;
-    }
-
-    public double Evaluate(GQAPSolution solution, CancellationToken token) {
-      var solScope = ToScope(solution);
-      Evaluate(solScope, token);
-      return solScope.Fitness;
-    }
-
-    public void Evaluate(ISingleObjectiveSolutionScope<GQAPSolution> solScope, CancellationToken token) {
-      var pdef = Problem as ISingleObjectiveProblemDefinition;
-      if (pdef != null) {
-        var ind = new SingleEncodingIndividual(pdef.Encoding, solScope);
-        solScope.Fitness = pdef.Evaluate(ind, Random);
-      } else {
-        RunOperator(Problem.Evaluator, solScope, token);
-      }
-    }
-
-    public GRASPSolutionContext CreateSingleSolutionContext(ISingleObjectiveSolutionScope<GQAPSolution> solution) {
-      return new GRASPSolutionContext(this, solution);
     }
 
@@ -274,109 +254,3 @@
     #endregion
   }
-
-  [Item("GRASP+PR (GQAP) SolutionContext", "SolutionContext for GRASP+PR (GQAP).")]
-  [StorableClass]
-  public sealed class GRASPSolutionContext : ParameterizedNamedItem, IExecutionContext {
-
-    private GRASPContext parent;
-    public IExecutionContext Parent {
-      get { return parent; }
-      set { throw new InvalidOperationException("Cannot set the parent of a single-solution context."); }
-    }
-
-    [Storable]
-    private ISingleObjectiveSolutionScope<GQAPSolution> scope;
-    public IScope Scope {
-      get { return scope; }
-    }
-
-    IKeyedItemCollection<string, IParameter> IExecutionContext.Parameters {
-      get { return Parameters; }
-    }
-
-    public GQAP Problem {
-      get { return parent.Problem; }
-    }
-    public bool Maximization {
-      get { return parent.Maximization; }
-    }
-
-    public double BestQuality {
-      get { return parent.BestQuality; }
-      set { parent.BestQuality = value; }
-    }
-
-    public GQAPSolution BestSolution {
-      get { return parent.BestSolution; }
-      set { parent.BestSolution = value; }
-    }
-
-    public IRandom Random {
-      get { return parent.Random; }
-    }
-
-    [Storable]
-    private IValueParameter<IntValue> evaluatedSolutions;
-    public int EvaluatedSolutions {
-      get { return evaluatedSolutions.Value.Value; }
-      set { evaluatedSolutions.Value.Value = value; }
-    }
-
-    [Storable]
-    private IValueParameter<IntValue> iterations;
-    public int Iterations {
-      get { return iterations.Value.Value; }
-      set { iterations.Value.Value = value; }
-    }
-
-    [StorableConstructor]
-    private GRASPSolutionContext(bool deserializing) : base(deserializing) { }
-    private GRASPSolutionContext(GRASPSolutionContext original, Cloner cloner)
-      : base(original, cloner) {
-      scope = cloner.Clone(original.scope);
-      evaluatedSolutions = cloner.Clone(original.evaluatedSolutions);
-      iterations = cloner.Clone(original.iterations);
-    }
-    public GRASPSolutionContext(GRASPContext baseContext, ISingleObjectiveSolutionScope<GQAPSolution> solution) {
-      parent = baseContext;
-      scope = solution;
-
-      Parameters.Add(evaluatedSolutions = new ValueParameter<IntValue>("EvaluatedSolutions", new IntValue(0)));
-      Parameters.Add(iterations = new ValueParameter<IntValue>("Iterations", new IntValue(0)));
-    }
-
-    public override IDeepCloneable Clone(Cloner cloner) {
-      return new GRASPSolutionContext(this, cloner);
-    }
-
-    public void IncrementEvaluatedSolutions(int byEvaluations) {
-      if (byEvaluations < 0) throw new ArgumentException("Can only increment and not decrement evaluated solutions.");
-      EvaluatedSolutions += byEvaluations;
-    }
-    public double Evaluate(GQAPSolution solution, CancellationToken token) {
-      return parent.Evaluate(solution, token);
-    }
-
-    public void Evaluate(ISingleObjectiveSolutionScope<GQAPSolution> solScope, CancellationToken token) {
-      parent.Evaluate(solScope, token);
-    }
-
-    #region IExecutionContext members
-    public IAtomicOperation CreateOperation(IOperator op) {
-      return new Core.ExecutionContext(this, op, Scope);
-    }
-
-    public IAtomicOperation CreateOperation(IOperator op, IScope s) {
-      return new Core.ExecutionContext(this, op, s);
-    }
-
-    public IAtomicOperation CreateChildOperation(IOperator op) {
-      return new Core.ExecutionContext(this, op, Scope);
-    }
-
-    public IAtomicOperation CreateChildOperation(IOperator op, IScope s) {
-      return new Core.ExecutionContext(this, op, s);
-    }
-    #endregion
-  }
 }
Index: branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment/3.3/Operators/Crossovers/GQAPPathRelinking.cs
===================================================================
--- branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment/3.3/Operators/Crossovers/GQAPPathRelinking.cs	(revision 15557)
+++ branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment/3.3/Operators/Crossovers/GQAPPathRelinking.cs	(revision 15558)
@@ -45,7 +45,9 @@
       get { return (IScopeTreeLookupParameter<Evaluation>)Parameters["Evaluation"]; }
     }
-
     public IValueParameter<PercentValue> CandidateSizeFactorParameter {
       get { return (IValueParameter<PercentValue>)Parameters["CandidateSizeFactor"]; }
+    }
+    public IValueLookupParameter<BoolValue> GreedyParameter {
+      get { return (IValueLookupParameter<BoolValue>)Parameters["Greedy"]; }
     }
 
@@ -58,4 +60,5 @@
       Parameters.Add(new ScopeTreeLookupParameter<Evaluation>("Evaluation", GQAP.EvaluationDescription));
       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)));
+      Parameters.Add(new ValueLookupParameter<BoolValue>("Greedy", "Whether to use a greedy selection strategy or a probabilistic one.", new BoolValue(true)));
     }
 
@@ -68,11 +71,10 @@
       IntegerVector target, Evaluation targetEval,
       GQAPInstance problemInstance, double candidateSizeFactor,
-      out int evaluatedSolutions) {
+      out int evaluatedSolutions, bool greedy = true) {
       evaluatedSolutions = 0;
       var demands = problemInstance.Demands;
       var capacities = problemInstance.Capacities;
       var cmp = new IntegerVectorEqualityComparer();
-
-      var greedy = true; // greedy performed better according to the paper
+      
       var sFit = problemInstance.ToSingleObjective(sourceEval);
       var tFit = problemInstance.ToSingleObjective(targetEval);
@@ -83,9 +85,11 @@
       //var fix = new bool[demands.Length]; // line 3 of Algorithm 4, note that according to the description it is not necessary to track the fixed equipments
       var nonFix = Enumerable.Range(0, demands.Length).ToList(); // line 3 of Algorithm 4
-      var phi = new HashSet<int>(IntegerVectorEqualityComparer.GetDifferingIndices(pi_prime, target)); // line 4 of Algorithm 4
-
+      var phi = new List<int>(IntegerVectorEqualityComparer.GetDifferingIndices(pi_prime, target)); // line 4 of Algorithm 4
+
+      var B = new List<GQAPSolution>((int)Math.Ceiling(phi.Count * candidateSizeFactor));
+      var B_fit = new List<double>(B.Capacity);
       while (phi.Count > 0) { // line 5 of Algorithm 4
-        var B = new List<GQAPSolution>((int)Math.Ceiling(phi.Count * candidateSizeFactor)); // line 6 of Algorithm 4
-        var B_fit = new List<double>(B.Capacity); // line 6 of Algorithm 4 (B is split into two synchronized lists)
+        B.Clear(); // line 6 of Algorithm 4
+        B_fit.Clear(); // line 6 of Algorithm 4 (B is split into two synchronized lists)
         foreach (var v in phi) { // line 7 of Algorithm 4
           int oldLocation = pi_prime[v];
@@ -93,9 +97,10 @@
           var pi_dash = MakeFeasible(random, pi_prime, v, nonFix, demands, capacities); // line 9 of Algorithm 4
           pi_prime[v] = oldLocation; // not mentioned in Algorithm 4, but seems reasonable
-          var pi_dash_eval = problemInstance.Evaluate(pi_dash);
-          evaluatedSolutions++;
-          var pi_dash_fit = problemInstance.ToSingleObjective(pi_dash_eval);
 
           if (problemInstance.IsFeasible(pi_dash)) { // line 10 of Algorithm 4
+            var pi_dash_eval = problemInstance.Evaluate(pi_dash);
+            evaluatedSolutions++;
+            var pi_dash_fit = problemInstance.ToSingleObjective(pi_dash_eval);
+
             if (B.Any(x => cmp.Equals(x.Assignment, pi_dash))) continue; // cond. 2 of line 12 and cond. 1 of line 16 in Algorithm 4
 
@@ -103,8 +108,8 @@
               var replacement = B_fit.Select((val, idx) => new { Index = idx, Fitness = val })
                                             .Where(x => x.Fitness >= pi_dash_fit) // cond. 1 in line 12 of Algorithm 4
-                                            .Select(x => new { Index = x.Index, Fitness = x.Fitness, Similarity = HammingSimilarityCalculator.CalculateSimilarity(B[x.Index].Assignment, pi_dash) })
+                                            .Select(x => new { x.Index, x.Fitness, Similarity = HammingSimilarityCalculator.CalculateSimilarity(B[x.Index].Assignment, pi_dash) })
                                             .ToArray();
               if (replacement.Length > 0) {
-                var mostSimilar = replacement.MaxItems(x => x.Similarity).First().Index;
+                var mostSimilar = replacement.MaxItems(x => x.Similarity).SampleRandom(random).Index;
                 B[mostSimilar].Assignment = pi_dash; // line 13 of Algorithm 4
                 B[mostSimilar].Evaluation = pi_dash_eval; // line 13 of Algorithm 4
@@ -121,5 +126,5 @@
           // 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;
+            pi = B.Select((val, idx) => new { Index = idx, Value = val }).MinItems(x => B_fit[x.Index]).SampleRandom(random).Value;
           } else {
             pi = B.SampleProportional(random, 1, B_fit.Select(x => 1.0 / x), false).First();
@@ -137,5 +142,5 @@
           }
         } else return pi_star;
-        phi = new HashSet<int>(IntegerVectorEqualityComparer.GetDifferingIndices(pi_prime, target));
+        phi = new List<int>(IntegerVectorEqualityComparer.GetDifferingIndices(pi_prime, target));
       }
 
@@ -156,31 +161,75 @@
       return Apply(random, source, evaluations[betterParent],
         target, evaluations[worseParent], problemInstance,
-        CandidateSizeFactorParameter.Value.Value, out evaluatedSolution).Assignment;
-    }
-
+        CandidateSizeFactorParameter.Value.Value, out evaluatedSolution,
+        GreedyParameter.ActualValue.Value).Assignment;
+    }
+
+    /// <summary>
+    /// Relocates equipments in the same location as <paramref name="equipment"/> to other locations in case the location
+    /// is overutilized.
+    /// </summary>
+    /// <remarks>
+    /// This method is performance critical, called very often and should run as fast as possible.
+    /// </remarks>
+    /// <param name="random">The random number generator.</param>
+    /// <param name="pi">The current solution.</param>
+    /// <param name="equipment">The equipment that was just assigned to a new location.</param>
+    /// <param name="nonFix">The equipments that have not yet been fixed.</param>
+    /// <param name="demands">The demands for all equipments.</param>
+    /// <param name="capacities">The capacities of all locations.</param>
+    /// <param name="maximumTries">The number of tries that should be done in relocating the equipments.</param>
+    /// <returns>A feasible or infeasible solution</returns>
     private static IntegerVector MakeFeasible(IRandom random, IntegerVector pi, int equipment, List<int> nonFix, DoubleArray demands, DoubleArray capacities, int maximumTries = 1000) {
       int l = pi[equipment];
       var slack = ComputeSlack(pi, demands, capacities);
       if (slack[l] >= 0) // line 1 of Algorithm 5
-        return new IntegerVector(pi); // line 2 of Algorithm 5
+        return (IntegerVector)pi.Clone(); // line 2 of Algorithm 5
 
       IntegerVector pi_prime = null;
       int k = 0; // line 4 of Algorithm 5
-      while (k < maximumTries && slack[l] < 0) {  // line 5 of Algorithm 5
-        pi_prime = new IntegerVector(pi); // line 6 of Algorithm 5
+      var maxSlack = slack.Max(); // line 8-9 of Algorithm 5
+      var slack_prime = (double[])slack.Clone();
+      var maxSlack_prime = maxSlack;
+      // note that FTL can be computed only once for all tries as all tries restart with the same solution
+      var FTL = nonFix.Where(x => x != equipment && pi[x] == l && demands[x] <= maxSlack).ToList(); // line 8-9 of Algorithm 5
+      var FTLweight = FTL.Select(x => demands[x]).ToList();
+      while (k < maximumTries && slack_prime[l] < 0) {  // line 5 of Algorithm 5
+        pi_prime = (IntegerVector)pi.Clone(); // line 6 of Algorithm 5
+        // set T can only shrink and not grow, thus it is created outside the loop and only updated inside
+        var T = new List<int>(FTL); // line 8-9 of Algorithm 5
+        var weightT = new List<double>(FTLweight);
         do {  // line 7 of Algorithm 5
-          var maxSlack = slack.Max(); // line 8-9 of Algorithm 5
-          var T = nonFix.Where(x => pi[x] == l && demands[x] <= maxSlack).ToList(); // line 8-9 of Algorithm 5
           if (T.Count > 0) { // line 10 of Algorithm 5
-            int i = T.SampleProportional(random, 1, T.Select(x => demands[x]), false).First(); // line 11 of Algorithm 5
+            var idx = Enumerable.Range(0, T.Count).SampleProportional(random, 1, weightT, false, false).First(); // line 11 of Algorithm 5
+            int i = T[idx]; // line 11 of Algorithm 5
             var j = Enumerable.Range(0, capacities.Length)
-              .Where(x => slack[x] >= demands[i]) // line 12 of Algorithm 5
+              .Where(x => slack_prime[x] >= demands[i]) // line 12 of Algorithm 5
               .SampleRandom(random);  // line 13 of Algorithm 5
             pi_prime[i] = j; // line 14 of Algorithm 5
-            slack[j] -= demands[i]; // line 14 of Algorithm 5
-            slack[l] += demands[i]; // line 14 of Algorithm 5
+            T.RemoveAt(idx);
+            weightT.RemoveAt(idx);
+            var recomputeMaxSlack = slack_prime[j] == maxSlack_prime; // efficiency improvement: recompute max slack only if we assign to a location whose slack equals maxSlack
+            slack_prime[j] -= demands[i]; // line 14 of Algorithm 5
+            slack_prime[l] += demands[i]; // line 14 of Algorithm 5
+            if (recomputeMaxSlack) {
+              maxSlack_prime = slack_prime.Max();
+              // T needs to be removed of equipments whose demand is higher than maxSlack only if maxSlack changes
+              for (var h = 0; h < T.Count; h++) {
+                var f = T[h];
+                if (demands[f] > maxSlack_prime) {
+                  T.RemoveAt(h);
+                  weightT.RemoveAt(h);
+                  h--;
+                }
+              }
+            }
           } else break; // cond. 1 in line 16 of Algorithm 5
-        } while (slack[l] < 0); // cond. 2 in line 16 of Algorithm 5
+        } while (slack_prime[l] < 0); // cond. 2 in line 16 of Algorithm 5
         k++; // line 17 of Algorithm 5
+        if (slack_prime[l] < 0) {
+          // reset
+          Array.Copy(slack, slack_prime, slack.Length);
+          maxSlack_prime = maxSlack;
+        }
       }
       return pi_prime; // line 19-23 of Algorithm 5
@@ -188,5 +237,5 @@
 
     private static double[] ComputeSlack(IntegerVector assignment, DoubleArray demands, DoubleArray capacities) {
-      var slack = new double[capacities.Length];
+      var slack = capacities.ToArray();
       for (int i = 0; i < assignment.Length; i++) {
         slack[assignment[i]] -= demands[i];
Index: branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment/3.3/Operators/LocalImprovers/ApproximateLocalSearch.cs
===================================================================
--- branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment/3.3/Operators/LocalImprovers/ApproximateLocalSearch.cs	(revision 15557)
+++ branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment/3.3/Operators/LocalImprovers/ApproximateLocalSearch.cs	(revision 15558)
@@ -76,4 +76,7 @@
       get { return (ILookupParameter<ResultCollection>)Parameters["Results"]; }
     }
+    public IValueLookupParameter<BoolValue> GreedyParameter {
+      get { return (IValueLookupParameter<BoolValue>)Parameters["Greedy"]; }
+    }
 
     [StorableConstructor]
@@ -92,4 +95,5 @@
       Parameters.Add(new ValueLookupParameter<PercentValue>("OneMoveProbability", "The probability for performing a 1-move, which is the opposite of performing a 2-move.", new PercentValue(.5)));
       Parameters.Add(new LookupParameter<ResultCollection>("Results", "The result collection that stores the results."));
+      Parameters.Add(new ValueLookupParameter<BoolValue>("Greedy", "Whether to use a greedy selection strategy or a probabilistic one.", new BoolValue(true)));
     }
 
@@ -100,27 +104,28 @@
     public static void Apply(IRandom random, GQAPSolution sol, int maxCLS,
       double oneMoveProbability, int maximumIterations,
-      GQAPInstance problemInstance, out int evaluatedSolutions) {
+      GQAPInstance problemInstance, out int evaluatedSolutions, bool greedy = true) {
       var fit = problemInstance.ToSingleObjective(sol.Evaluation);
       var eval = sol.Evaluation;
       Apply(random, sol.Assignment, ref fit, ref eval, maxCLS, oneMoveProbability, maximumIterations, problemInstance,
-        out evaluatedSolutions);
+        out evaluatedSolutions, greedy);
       sol.Evaluation = eval;
     }
 
-      /// <summary>
-      /// </summary>
-      /// <param name="random">The random number generator to use.</param>
-      /// <param name="assignment">The equipment-location assignment vector.</param>
-      /// <param name="quality">The solution quality.</param>
-      /// <param name="evaluation">The evaluation result of the solution.</param>
-      /// <param name="maxCLS">The maximum number of candidates that should be found in each step.</param>
-      /// <param name="oneMoveProbability">The probability for performing a 1-move, which is the opposite of performing a 2-move.</param>
-      /// <param name="maximumIterations">The maximum number of iterations that should be performed each time the candidate list is generated.</param>
-      /// <param name="problemInstance">The problem instance that contains the data.</param>
-      /// <param name="evaluatedSolutions">The number of evaluated solutions.</param>
-      public static void Apply(IRandom random, IntegerVector assignment,
+    /// <summary>
+    /// </summary>
+    /// <param name="random">The random number generator to use.</param>
+    /// <param name="assignment">The equipment-location assignment vector.</param>
+    /// <param name="quality">The solution quality.</param>
+    /// <param name="evaluation">The evaluation result of the solution.</param>
+    /// <param name="maxCLS">The maximum number of candidates that should be found in each step.</param>
+    /// <param name="oneMoveProbability">The probability for performing a 1-move, which is the opposite of performing a 2-move.</param>
+    /// <param name="maximumIterations">The maximum number of iterations that should be performed each time the candidate list is generated.</param>
+    /// <param name="problemInstance">The problem instance that contains the data.</param>
+    /// <param name="evaluatedSolutions">The number of evaluated solutions.</param>
+    /// <param name="greedy">Greedy selection performed better in 5 of 8 instances according to the paper</param>
+    public static void Apply(IRandom random, IntegerVector assignment,
       ref double quality, ref Evaluation evaluation, int maxCLS,
       double oneMoveProbability, int maximumIterations,
-      GQAPInstance problemInstance, out int evaluatedSolutions) {
+      GQAPInstance problemInstance, out int evaluatedSolutions, bool greedy = true) {
       evaluatedSolutions = 0;
       var capacities = problemInstance.Capacities;
@@ -128,5 +133,4 @@
       var evaluations = 0.0;
       var deltaEvaluationFactor = 1.0 / assignment.Length;
-      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
@@ -183,5 +187,6 @@
         MaximumIterationsParameter.ActualValue.Value,
         ProblemInstanceParameter.ActualValue,
-        out evaluatedSolutions);
+        out evaluatedSolutions,
+        GreedyParameter.ActualValue.Value);
 
       EvaluationParameter.ActualValue = evaluation;
Index: branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment/3.3/SolutionCreators/GreedyRandomizedSolutionCreator.cs
===================================================================
--- branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment/3.3/SolutionCreators/GreedyRandomizedSolutionCreator.cs	(revision 15557)
+++ branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment/3.3/SolutionCreators/GreedyRandomizedSolutionCreator.cs	(revision 15558)
@@ -65,4 +65,5 @@
       var weights = problemInstance.Weights;
       var distances = problemInstance.Distances;
+      var installCosts = problemInstance.InstallationCosts;
       var demands = problemInstance.Demands;
       var capacities = problemInstance.Capacities.ToArray();
@@ -71,7 +72,7 @@
       var locations = capacities.Length;
       int tries = 0;
-      var assignment = new int[equipments];
       var slack = new double[locations];
       double minViolation = double.MaxValue;
+      int[] assignment = null;
       int[] bestAssignment = null;
       var F = new List<int>(equipments); // set of (initially) all facilities / equipments
@@ -84,7 +85,17 @@
       var W = new double[equipments]; // proportions for choosing facilities in stage 2
       var Z = new double[locations]; // proportions for choosing locations in stage 2
+      
+      for (var k = 0; k < equipments; k++) {
+        for (var h = 0; h < equipments; h++) {
+          if (k == h) continue;
+          W[k] += weights[k, h];
+        }
+        W[k] *= demands[k];
+      }
 
       while (maximumTries <= 0 || tries < maximumTries) {
         cancelToken.ThrowIfCancellationRequested();
+
+        assignment = new int[equipments];
 
         Array.Copy(capacities, slack, locations); // line 2 of Algorihm 2
@@ -96,4 +107,6 @@
         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
+
+        Array.Clear(H, 0, H.Length);
 
         double threshold = 1.0; // line 3 of Algorithm 2
@@ -104,29 +117,19 @@
             // 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);
+            var HH = L.Select(x => H[x]);
             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];
+            // incrementally updating location weights
+            foreach (var k in L)
+              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
+            var WW = T.Select(x => W[x]);
+            var f = T.SampleProportional(random, 1, WW, false, false) // line 11 of Algorithm 2
               .Single();
             T.Remove(f); // line 12 of Algorithm 2
@@ -135,21 +138,24 @@
             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];
+            var l = R[0];
+            if (R.Count > 1) { // optimization, calculate probabilistic weights only in case |R| > 1
+              Array.Clear(Z, 0, R.Count);
+              var zk = 0;
+              foreach (var k in R) {
+                // d is an increase in fitness if f would be assigned to location k
+                var d = installCosts[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++;
               }
-              foreach (var h in CL_list) {
-                if (k == h) continue;
-                Z[zk] += slack[k] * capacities[h] / (d * distances[k, h]);
-              }
-              zk++;
+              l = R.SampleProportional(random, 1, Z.Take(R.Count), false, false).Single(); // line 14 of Algorithm 2
             }
-            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];
@@ -183,5 +189,4 @@
             minViolation = violation;
           }
-          assignment = new int[equipments];
         }
       }
Index: branches/GeneralizedQAP/UnitTests/ApproximateLocalSearchTest.cs
===================================================================
--- branches/GeneralizedQAP/UnitTests/ApproximateLocalSearchTest.cs	(revision 15557)
+++ branches/GeneralizedQAP/UnitTests/ApproximateLocalSearchTest.cs	(revision 15558)
@@ -13,13 +13,13 @@
     [TestMethod]
     public void ApproximateLocalSearchApplyTest() {
-      CollectionAssert.AreEqual(new [] { 3, 2, 2, 0, 0, 0, 2, 3, 0, 2 }, assignment.ToArray());
+      CollectionAssert.AreEqual(new [] { 3, 2, 1, 1, 3, 0, 1, 0, 3, 0 }, assignment.ToArray());
 
       var evaluation = instance.Evaluate(assignment);
-      Assert.AreEqual(3764492, evaluation.FlowCosts);
-      Assert.AreEqual(46, evaluation.InstallationCosts);
+      Assert.AreEqual(4091776, evaluation.FlowCosts);
+      Assert.AreEqual(42, evaluation.InstallationCosts);
       Assert.AreEqual(0, evaluation.ExcessDemand);
 
       var quality = instance.ToSingleObjective(evaluation);
-      Assert.AreEqual(14631771.476177376, quality, 1e-9);
+      Assert.AreEqual(15903846.056964701, quality, 1e-9);
 
       var evaluatedSolutions = 0;
@@ -27,7 +27,7 @@
         ref evaluation, 10, 0.5, 1000, instance,
         out evaluatedSolutions);
-      Assert.AreEqual(300, evaluatedSolutions);
-      CollectionAssert.AreEqual(new[] { 3, 2, 2, 0, 0, 2, 2, 3, 0, 0 }, assignment.ToArray());
-      Assert.AreEqual(14271146.913257681, quality, 1e-9);
+      Assert.AreEqual(680, evaluatedSolutions);
+      CollectionAssert.AreEqual(new[] { 3, 1, 0, 3, 0, 0, 1, 2, 3, 0 }, assignment.ToArray());
+      Assert.AreEqual(12440163.936988469, quality, 1e-9);
     }
 
