Index: /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms/3.3/Evolutionary/ESContext.cs
===================================================================
--- /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms/3.3/Evolutionary/ESContext.cs	(revision 15562)
+++ /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms/3.3/Evolutionary/ESContext.cs	(revision 15562)
@@ -0,0 +1,79 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2017 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.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms.Evolutionary {
+  [Item("Evolution Strategy (GQAP) Context", "Context for Evolution Strategies (GQAP).")]
+  [StorableClass]
+  public sealed class ESContext : SingleObjectivePopulationContext<ISingleObjectiveSolutionScope<ESGQAPSolution>> {
+    
+    [Storable]
+    private IValueParameter<GQAP> problem;
+    public GQAP Problem {
+      get { return problem.Value; }
+      set { problem.Value = value; }
+    }
+
+    [Storable]
+    private IValueParameter<ESGQAPSolution> bestSolution;
+    public ESGQAPSolution BestSolution {
+      get { return bestSolution.Value; }
+      set { bestSolution.Value = value; }
+    }
+
+    public void ReplacePopulation(IEnumerable<ISingleObjectiveSolutionScope<ESGQAPSolution>> replacement) {
+      Scope.SubScopes.Replace(replacement);
+    }
+    
+    [StorableConstructor]
+    private ESContext(bool deserializing) : base(deserializing) { }
+    private ESContext(ESContext original, Cloner cloner)
+      : base(original, cloner) {
+      problem = cloner.Clone(original.problem);
+      bestSolution = cloner.Clone(original.bestSolution);
+    }
+    public ESContext() : this("Evolution Strategy (GQAP) Context") { }
+    public ESContext(string name) : base(name) {
+      Parameters.Add(problem = new ValueParameter<GQAP>("Problem"));
+      Parameters.Add(bestSolution = new ValueParameter<ESGQAPSolution>("BestFoundSolution"));
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new ESContext(this, cloner);
+    }
+
+    public ISingleObjectiveSolutionScope<ESGQAPSolution> ToScope(ESGQAPSolution code, double fitness = double.NaN) {
+      var name = Problem.Encoding.Name;
+      var scope = new SingleObjectiveSolutionScope<ESGQAPSolution>(code,
+        name + "Solution", fitness, Problem.Evaluator.QualityParameter.ActualName) {
+        Parent = Scope
+      };
+      scope.Variables.Add(new Variable(name, code.Assignment));
+      scope.Variables.Add(new Variable("Evaluation", code.Evaluation));
+      return scope;
+    }
+  }
+}
Index: /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms/3.3/Evolutionary/ESGQAPSolution.cs
===================================================================
--- /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms/3.3/Evolutionary/ESGQAPSolution.cs	(revision 15562)
+++ /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms/3.3/Evolutionary/ESGQAPSolution.cs	(revision 15562)
@@ -0,0 +1,55 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2017 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using HeuristicLab.Common;
+using HeuristicLab.Encodings.IntegerVectorEncoding;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms.Evolutionary {
+  public class ESGQAPSolution : GQAPSolution {
+
+    [Storable]
+    private double sParam;
+    public double SParam {
+      get { return sParam; }
+      set {
+        if (sParam == value) return;
+        sParam = value;
+        OnPropertyChanged(nameof(SParam));
+      }
+    }
+
+    [StorableConstructor]
+    protected ESGQAPSolution(bool deserializing) : base(deserializing) { }
+    protected ESGQAPSolution(ESGQAPSolution original, Cloner cloner)
+    : base(original, cloner) {
+      sParam = original.sParam;
+    }
+    public ESGQAPSolution(IntegerVector assignment, Evaluation eval, double sParam)
+      : base(assignment, eval) {
+      this.sParam = sParam;
+    }
+    
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new ESGQAPSolution(this, cloner);
+    }
+  }
+}
Index: /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms/3.3/Evolutionary/EvolutionStrategy.cs
===================================================================
--- /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms/3.3/Evolutionary/EvolutionStrategy.cs	(revision 15562)
+++ /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms/3.3/Evolutionary/EvolutionStrategy.cs	(revision 15562)
@@ -0,0 +1,219 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2017 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Encodings.IntegerVectorEncoding;
+using HeuristicLab.Optimization;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Random;
+
+namespace HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms.Evolutionary {
+  public enum ESSelection { Plus = 0, Comma = 1 }
+
+  [Item("Evolution Strategy (GQAP)", "The algorithm implements a simple evolution strategy (ES).")]
+  [Creatable(CreatableAttribute.Categories.PopulationBasedAlgorithms)]
+  [StorableClass]
+  public sealed class EvolutionStrategy : StochasticAlgorithm<ESContext> {
+
+    public override bool SupportsPause {
+      get { return true; }
+    }
+
+    public override Type ProblemType {
+      get { return typeof(GQAP); }
+    }
+
+    public new GQAP Problem {
+      get { return (GQAP)base.Problem; }
+      set { base.Problem = value; }
+    }
+
+    [Storable]
+    private FixedValueParameter<IntValue> lambdaParameter;
+    private IFixedValueParameter<IntValue> LambdaParameter {
+      get { return lambdaParameter; }
+    }
+    [Storable]
+    private FixedValueParameter<IntValue> muParameter;
+    public IFixedValueParameter<IntValue> MuParameter {
+      get { return muParameter; }
+    }
+    [Storable]
+    private FixedValueParameter<EnumValue<ESSelection>> selectionParameter;
+    public IFixedValueParameter<EnumValue<ESSelection>> SelectionParameter {
+      get { return selectionParameter; }
+    }
+
+    public int Lambda {
+      get { return lambdaParameter.Value.Value; }
+      set { lambdaParameter.Value.Value = value; }
+    }
+    public int Mu {
+      get { return muParameter.Value.Value; }
+      set { muParameter.Value.Value = value; }
+    }
+    public ESSelection Selection {
+      get { return selectionParameter.Value.Value; }
+      set { selectionParameter.Value.Value = value; }
+    }
+
+    [StorableConstructor]
+    private EvolutionStrategy(bool deserializing) : base(deserializing) { }
+    private EvolutionStrategy(EvolutionStrategy original, Cloner cloner)
+      : base(original, cloner) {
+      lambdaParameter = cloner.Clone(original.lambdaParameter);
+      muParameter = cloner.Clone(original.muParameter);
+      selectionParameter = cloner.Clone(original.selectionParameter);
+    }
+    public EvolutionStrategy() {
+      Parameters.Add(lambdaParameter = new FixedValueParameter<IntValue>("Lambda", "(λ) The amount of offspring that are created each generation.", new IntValue(10)));
+      Parameters.Add(muParameter = new FixedValueParameter<IntValue>("Mu", "(μ) The population size.", new IntValue(1)));
+      Parameters.Add(selectionParameter= new FixedValueParameter<EnumValue<ESSelection>>("Selection", "The selection strategy: elitist (plus) or generational (comma).", new EnumValue<ESSelection>(ESSelection.Plus)));
+      
+      Problem = new GQAP();
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new EvolutionStrategy(this, cloner);
+    }
+
+    protected override void Initialize(CancellationToken cancellationToken) {
+      base.Initialize(cancellationToken);
+
+      Context.Problem = Problem;      
+      Context.BestQuality = double.NaN;
+      Context.BestSolution = null;
+
+      for (var m = 0; m < Mu; m++) {
+        var assign = new IntegerVector(Problem.ProblemInstance.Demands.Length, Context.Random, 0, Problem.ProblemInstance.Capacities.Length);
+        var eval = Problem.ProblemInstance.Evaluate(assign);
+        Context.EvaluatedSolutions++;
+
+        var ind = new ESGQAPSolution(assign, eval, 1.0 / assign.Length);
+        var fit = Problem.ProblemInstance.ToSingleObjective(eval);
+        Context.AddToPopulation(Context.ToScope(ind, fit));
+        if (double.IsNaN(Context.BestQuality) || fit < Context.BestQuality) {
+          Context.BestQuality = fit;
+          Context.BestSolution = (ESGQAPSolution)ind.Clone();
+        }
+      }
+
+      Results.Add(new Result("Iterations", new IntValue(Context.Iterations)));
+      Results.Add(new Result("EvaluatedSolutions", new IntValue(Context.EvaluatedSolutions)));
+      Results.Add(new Result("BestQuality", new DoubleValue(Context.BestQuality)));
+      Results.Add(new Result("BestSolution", Context.BestSolution));
+
+      Context.RunOperator(Analyzer, Context.Scope, cancellationToken);
+    }
+
+    protected override void Run(CancellationToken cancellationToken) {
+      while (!StoppingCriterion()) {
+        var nextGen = new List<ISingleObjectiveSolutionScope<ESGQAPSolution>>(Lambda);
+
+        for (var l = 0; l < Lambda; l++) {
+          var m = Context.AtRandomPopulation();
+
+          var offspring = (ESGQAPSolution)m.Solution.Clone();
+          var count = Mutate(m, offspring);
+          offspring.SParam += ((1.0 / count) - offspring.SParam) / 10.0;
+
+          offspring.Evaluation = Problem.ProblemInstance.Evaluate(offspring.Assignment);
+          Context.EvaluatedSolutions++;
+          var fit = Problem.ProblemInstance.ToSingleObjective(offspring.Evaluation);
+          nextGen.Add(Context.ToScope(offspring, fit));
+
+          if (fit < Context.BestQuality) {
+            Context.BestQuality = fit;
+            Context.BestSolution = (ESGQAPSolution)offspring.Clone();
+          }
+        }
+
+        if (Selection == ESSelection.Comma) {
+          Context.ReplacePopulation(nextGen.OrderBy(x => x.Fitness).Take(Mu));
+        } else if (Selection == ESSelection.Plus) {
+          var best = nextGen.Concat(Context.Population).OrderBy(x => x.Fitness).Take(Mu).ToList();
+          Context.ReplacePopulation(best);
+        } else throw new InvalidOperationException("Unknown Selection strategy: " + Selection);
+
+        IResult result;
+        if (Results.TryGetValue("Iterations", out result))
+          ((IntValue)result.Value).Value = Context.Iterations;
+        else Results.Add(new Result("Iterations", new IntValue(Context.Iterations)));
+        if (Results.TryGetValue("EvaluatedSolutions", out result))
+          ((IntValue)result.Value).Value = Context.EvaluatedSolutions;
+        else Results.Add(new Result("EvaluatedSolutions", new IntValue(Context.EvaluatedSolutions)));
+        if (Results.TryGetValue("BestQuality", out result))
+          ((DoubleValue)result.Value).Value = Context.BestQuality;
+        else Results.Add(new Result("BestQuality", new DoubleValue(Context.BestQuality)));
+        if (Results.TryGetValue("BestSolution", out result))
+          result.Value = Context.BestSolution;
+        else Results.Add(new Result("BestSolution", Context.BestSolution));
+
+        Context.RunOperator(Analyzer, Context.Scope, cancellationToken);
+
+        Context.Iterations++;
+        if (cancellationToken.IsCancellationRequested) break;
+      }
+    }
+
+    private int Mutate(ISingleObjectiveSolutionScope<ESGQAPSolution> m, ESGQAPSolution offspring) {
+      var offspringFeasible = offspring.Evaluation.IsFeasible;
+      double[] slack = null;
+      if (offspringFeasible) slack = offspring.Evaluation.Slack.ToArray();
+      var count = 1;
+      foreach (var equip in Enumerable.Range(0, Problem.ProblemInstance.Demands.Length).Shuffle(Context.Random)) {
+        var currentLoc = offspring.Assignment[equip];
+        if (offspringFeasible) {
+          var demand = Problem.ProblemInstance.Demands[equip];
+          var feasibleLoc = slack.Select((v, i) => new { Index = i, Value = v })
+            .Where(x => x.Index != currentLoc
+            && x.Value >= demand).ToList();
+          int newLoc = -1;
+          if (feasibleLoc.Count == 0) {
+            newLoc = Context.Random.Next(Problem.ProblemInstance.Capacities.Length - 1);
+            if (newLoc >= currentLoc) newLoc++; // don't reassign to current loc
+            offspringFeasible = false;
+          } else {
+            newLoc = feasibleLoc.SampleRandom(Context.Random).Index;
+          }
+          offspring.Assignment[equip] = newLoc;
+          slack[currentLoc] += demand;
+          slack[newLoc] -= demand;
+        } else {
+          var newLoc = Context.Random.Next(Problem.ProblemInstance.Capacities.Length - 1);
+          if (newLoc >= currentLoc) newLoc++; // don't reassign to current loc
+          offspring.Assignment[equip] = newLoc;
+        }
+        if (Context.Random.NextDouble() < m.Solution.SParam) break;
+        count++;
+      }
+
+      return count;
+    }
+  }
+}
Index: anches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms/3.3/GRASP.cs
===================================================================
--- /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms/3.3/GRASP.cs	(revision 15561)
+++ 	(revision )
@@ -1,347 +1,0 @@
-﻿#region License Information
-/* HeuristicLab
- * Copyright (C) 2002-2017 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
- *
- * This file is part of HeuristicLab.
- *
- * HeuristicLab is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * HeuristicLab is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
- */
-#endregion
-
-using System;
-using System.Linq;
-using System.Threading;
-using HeuristicLab.Analysis;
-using HeuristicLab.Common;
-using HeuristicLab.Core;
-using HeuristicLab.Data;
-using HeuristicLab.Encodings.IntegerVectorEncoding;
-using HeuristicLab.Optimization;
-using HeuristicLab.Parameters;
-using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
-using HeuristicLab.Random;
-
-namespace HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms.GRASP {
-
-  /// <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("GRASP+PR (GQAP)", "The algorithm implements the Greedy Randomized Adaptive Search Procedure (GRASP) with Path Relinking as 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.")]
-  [Creatable(CreatableAttribute.Categories.PopulationBasedAlgorithms)]
-  [StorableClass]
-  public class GRASP : BasicAlgorithm {
-
-    public override bool SupportsPause {
-      get { return true; }
-    }
-
-    public override Type ProblemType {
-      get { return typeof(GQAP); }
-    }
-
-    public new GQAP Problem {
-      get { return (GQAP)base.Problem; }
-      set { base.Problem = value; }
-    }
-
-    [Storable]
-    private ValueParameter<IAnalyzer> analyzerParameter;
-    public IValueParameter<IAnalyzer> AnalyzerParameter {
-      get { return analyzerParameter; }
-    }
-
-    [Storable]
-    private FixedValueParameter<BoolValue> setSeedRandomlyParameter;
-    private IFixedValueParameter<BoolValue> SetSeedRandomlyParameter {
-      get { return setSeedRandomlyParameter; }
-    }
-    [Storable]
-    private FixedValueParameter<IntValue> seedParameter;
-    private IFixedValueParameter<IntValue> SeedParameter {
-      get { return seedParameter; }
-    }
-    [Storable]
-    private FixedValueParameter<IntValue> eliteSetSizeParameter;
-    private IFixedValueParameter<IntValue> EliteSetSizeParameter {
-      get { return eliteSetSizeParameter; }
-    }
-    [Storable]
-    private FixedValueParameter<IntValue> minimiumEliteSetSizeParameter;
-    public IFixedValueParameter<IntValue> MinimumEliteSetSizeParameter {
-      get { return minimiumEliteSetSizeParameter; }
-    }
-    [Storable]
-    private FixedValueParameter<IntValue> maximumIterationsParameter;
-    public IFixedValueParameter<IntValue> MaximumIterationsParameter {
-      get { return maximumIterationsParameter; }
-    }
-    [Storable]
-    private FixedValueParameter<IntValue> maximumLocalSearchIterationsParameter;
-    public IFixedValueParameter<IntValue> MaximumLocalSearchIterationsParameter {
-      get { return maximumIterationsParameter; }
-    }
-    [Storable]
-    private FixedValueParameter<PercentValue> candidateSizeFactorParameter;
-    public IFixedValueParameter<PercentValue> CandidateSizeFactorParameter {
-      get { return candidateSizeFactorParameter; }
-    }
-    [Storable]
-    private FixedValueParameter<IntValue> maximumCandidateListSizeParameter;
-    public IFixedValueParameter<IntValue> MaximumCandidateListSizeParameter {
-      get { return maximumCandidateListSizeParameter; }
-    }
-    [Storable]
-    private FixedValueParameter<PercentValue> oneMoveProbabilityParameter;
-    public IFixedValueParameter<PercentValue> OneMoveProbabilityParameter {
-      get { return oneMoveProbabilityParameter; }
-    }
-    [Storable]
-    private FixedValueParameter<IntValue> minimumDifferenceParameter;
-    public IFixedValueParameter<IntValue> MinimumDifferenceParameter {
-      get { return minimumDifferenceParameter; }
-    }
-    
-    public bool SetSeedRandomly {
-      get { return setSeedRandomlyParameter.Value.Value; }
-      set { setSeedRandomlyParameter.Value.Value = value; }
-    }
-    public int Seed {
-      get { return seedParameter.Value.Value; }
-      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 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 {
-      get { return candidateSizeFactorParameter.Value.Value; }
-      set { candidateSizeFactorParameter.Value.Value = value; }
-    }
-    public int MaximumCandidateListSize {
-      get { return maximumCandidateListSizeParameter.Value.Value; }
-      set { maximumCandidateListSizeParameter.Value.Value = value; }
-    }
-    public double OneMoveProbability {
-      get { return oneMoveProbabilityParameter.Value.Value; }
-      set { oneMoveProbabilityParameter.Value.Value = value; }
-    }
-    public int MinimumDifference {
-      get { return minimumDifferenceParameter.Value.Value; }
-      set { minimumDifferenceParameter.Value.Value = value; }
-    }
-
-    [StorableConstructor]
-    protected GRASP(bool deserializing) : base(deserializing) { }
-    protected GRASP(GRASP original, Cloner cloner)
-      : base(original, cloner) {
-      setSeedRandomlyParameter = cloner.Clone(original.setSeedRandomlyParameter);
-      seedParameter = cloner.Clone(original.seedParameter);
-      analyzerParameter = cloner.Clone(original.analyzerParameter);
-      eliteSetSizeParameter = cloner.Clone(original.eliteSetSizeParameter);
-      minimiumEliteSetSizeParameter = cloner.Clone(original.minimiumEliteSetSizeParameter);
-      maximumIterationsParameter = cloner.Clone(original.maximumIterationsParameter);
-      maximumLocalSearchIterationsParameter = cloner.Clone(original.maximumLocalSearchIterationsParameter);
-      candidateSizeFactorParameter = cloner.Clone(original.candidateSizeFactorParameter);
-      maximumCandidateListSizeParameter = cloner.Clone(original.maximumCandidateListSizeParameter);
-      oneMoveProbabilityParameter = cloner.Clone(original.oneMoveProbabilityParameter);
-      minimumDifferenceParameter = cloner.Clone(original.minimumDifferenceParameter);
-      context = cloner.Clone(original.context);
-    }
-    public GRASP() {
-      Parameters.Add(setSeedRandomlyParameter = new FixedValueParameter<BoolValue>("SetSeedRandomly", "Whether to overwrite the seed with a random value each time the algorithm is run.", new BoolValue(true)));
-      Parameters.Add(seedParameter = new FixedValueParameter<IntValue>("Seed", "The random seed that is used in the stochastic algorithm", new IntValue(0)));
-      Parameters.Add(analyzerParameter = new ValueParameter<IAnalyzer>("Analyzer", "The analyzers that are used to perform an analysis of the solutions.", new MultiAnalyzer()));
-      Parameters.Add(eliteSetSizeParameter = new FixedValueParameter<IntValue>("EliteSetSize", "The (maximum) size of the elite set.", new IntValue(10)));
-      Parameters.Add(minimiumEliteSetSizeParameter = new FixedValueParameter<IntValue>("MinimumEliteSetSize", "(ρ) The minimal size of the elite set, before local search and path relinking are applied.", new IntValue(2)));
-      Parameters.Add(maximumIterationsParameter = new FixedValueParameter<IntValue>("MaximumIterations", "The number of iterations that the algorithm should run.", new IntValue(1000)));
-      Parameters.Add(maximumLocalSearchIterationsParameter = new FixedValueParameter<IntValue>("MaximumLocalSearchIteration", "The maximum number of iterations that the approximate local search should run", new IntValue(100)));
-      Parameters.Add(candidateSizeFactorParameter = new FixedValueParameter<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(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<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();
-    }
-
-    public override IDeepCloneable Clone(Cloner cloner) {
-      return new GRASP(this, cloner);
-    }
-
-    public override void Prepare() {
-      base.Prepare();
-      Results.Clear();
-      context = null;
-    }
-
-    [Storable]
-    private GRASPContext context;
-
-    protected override void Initialize(CancellationToken cancellationToken) {
-      base.Initialize(cancellationToken);
-      context = new GRASPContext();
-      context.Problem = Problem;
-      context.Scope.Variables.Add(new Variable("Results", Results));
-
-      IExecutionContext ctxt = null;
-      foreach (var item in Problem.ExecutionContextItems)
-        ctxt = new Core.ExecutionContext(ctxt, item, context.Scope);
-      ctxt = new Core.ExecutionContext(ctxt, this, context.Scope);
-      context.Parent = ctxt;
-
-      if (SetSeedRandomly) {
-        var rnd = new System.Random();
-        Seed = rnd.Next();
-      }
-      context.Random = new MersenneTwister((uint)Seed);
-      context.Iterations = 0;
-      context.EvaluatedSolutions = 0;
-      context.BestQuality = double.NaN;
-      context.BestSolution = null;
-
-      context.Initialized = true;
-
-      Results.Add(new Result("Iterations", new IntValue(context.Iterations)));
-      Results.Add(new Result("EvaluatedSolutions", new IntValue(context.EvaluatedSolutions)));
-      Results.Add(new Result("BestQuality", new DoubleValue(context.BestQuality)));
-      Results.Add(new Result("BestSolution", typeof(GQAPSolution)));
-
-      context.RunOperator(analyzerParameter.Value, context.Scope, cancellationToken);
-    }
-
-    protected override void Run(CancellationToken cancellationToken) {
-      var eq = new IntegerVectorEqualityComparer();
-      while (!StoppingCriterion()) { // line 2 in Algorithm 1
-        // next: line 3 in Algorithm 1
-        var pi_prime_vec = GreedyRandomizedSolutionCreator.CreateSolution(context.Random, Problem.ProblemInstance, 1000, false, cancellationToken);
-        if (context.PopulationCount >= MinimumEliteSetSize) { // line 4 in Algorithm 1
-          GQAPSolution pi_prime;
-          if (!Problem.ProblemInstance.IsFeasible(pi_prime_vec)) // line 5 in Algorithm 1
-            pi_prime = context.AtPopulation(context.Random.Next(context.PopulationCount)).Solution; // line 6 in Algorithm 1
-          else {
-            // This is necessary, because pi_prime has not been evaluated yet and such details are not covered in Algorithm 1
-            pi_prime = Problem.ProblemInstance.ToEvaluatedSolution(pi_prime_vec);
-            context.EvaluatedSolutions++;
-          }
-
-          ApproxLocalSearch(pi_prime); // line 8 in Algorithm 1
-          var pi_plus = context.AtPopulation(context.Random.Next(context.PopulationCount)); // line 9 in Algorithm 1
-          pi_prime = PathRelinking(pi_prime, pi_plus.Solution); // line 10 in Algorithm 1
-          ApproxLocalSearch(pi_prime); // line 11 in Algorithm 1
-          var fitness = Problem.ProblemInstance.ToSingleObjective(pi_prime.Evaluation);
-          // Book-keeping
-          if (context.BestQuality > fitness) {
-            context.BestQuality = fitness;
-            context.BestSolution = (GQAPSolution)pi_prime.Clone();
-          }
-
-          if (context.PopulationCount == EliteSetSize) { // line 12 in Algorithm 1
-            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 / (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();
-              if (replacement.Length > 0) { // cond. 1 of line 13 in Algorithm 1
-                // next two lines: line 14 in Algorithm 1
-                replacement = replacement.OrderBy(x => similarities[x.Index]).ToArray();
-                context.ReplaceAtPopulation(replacement.Last().Index, context.ToScope(pi_prime, fit));
-              }
-            }
-          } else if (IsSufficientlyDifferent(pi_prime.Assignment)) { // line 17 in Algorithm 1
-            context.AddToPopulation(context.ToScope(pi_prime, Problem.ProblemInstance.ToSingleObjective(pi_prime.Evaluation))); // line 18 in Algorithm 1
-          }
-        } else if (Problem.ProblemInstance.IsFeasible(pi_prime_vec) /* cond. 1 of line 21 in Algorithm 1 */
-          && IsSufficientlyDifferent(pi_prime_vec))  /* cond. 2 of line 21 in Algorithm 1 */ {
-          var pi_prime = Problem.ProblemInstance.ToEvaluatedSolution(pi_prime_vec);
-          context.EvaluatedSolutions++;
-          var fitness = Problem.ProblemInstance.ToSingleObjective(pi_prime.Evaluation);
-          context.AddToPopulation(context.ToScope(pi_prime, fitness)); /* line 22 in Algorithm 1 */
-          // Book-keeping
-          if (context.PopulationCount == 1 || context.BestQuality > fitness) {
-            context.BestQuality = fitness;
-            context.BestSolution = (GQAPSolution)pi_prime.Clone();
-          }
-        }
-
-        IResult result;
-        if (Results.TryGetValue("Iterations", out result))
-          ((IntValue)result.Value).Value = context.Iterations;
-        else Results.Add(new Result("Iterations", new IntValue(context.Iterations)));
-        if (Results.TryGetValue("EvaluatedSolutions", out result))
-          ((IntValue)result.Value).Value = context.EvaluatedSolutions;
-        else Results.Add(new Result("EvaluatedSolutions", new IntValue(context.EvaluatedSolutions)));
-        if (Results.TryGetValue("BestQuality", out result))
-          ((DoubleValue)result.Value).Value = context.BestQuality;
-        else Results.Add(new Result("BestQuality", new DoubleValue(context.BestQuality)));
-        if (Results.TryGetValue("BestSolution", out result))
-          result.Value = context.BestSolution;
-        else Results.Add(new Result("BestSolution", context.BestSolution));
-
-        context.RunOperator(analyzerParameter.Value, context.Scope, cancellationToken);
-
-        context.Iterations++;
-      }
-    }
-
-    private bool IsSufficientlyDifferent(IntegerVector vec) {
-      return context.Population.All(x =>
-        HammingSimilarityCalculator.CalculateSimilarity(vec, x.Solution.Assignment) <= 1.0 - (MinimumDifference / (double)vec.Length)
-      );
-    }
-
-    private GQAPSolution PathRelinking(GQAPSolution pi_prime, GQAPSolution pi_plus) {
-      // Following code represents line 1 of Algorithm 4
-      IntegerVector source = pi_prime.Assignment, target = pi_plus.Assignment;
-      Evaluation sourceEval = pi_prime.Evaluation, targetEval = pi_plus.Evaluation;
-      var sourceFit = Problem.ProblemInstance.ToSingleObjective(sourceEval);
-      var targetFit = Problem.ProblemInstance.ToSingleObjective(targetEval);
-      if (targetFit < sourceFit) {
-        var h = source;
-        source = target;
-        target = h;
-        var hh = sourceEval;
-        sourceEval = targetEval;
-        targetEval = hh;
-      }
-      int evaluatedSolutions;
-      // lines 2-36 of Algorithm 4 are implemented in the following call
-      var pi_star = GQAPPathRelinking.Apply(context.Random, source, sourceEval,
-        target, targetEval, Problem.ProblemInstance, CandidateSizeFactor,
-        out evaluatedSolutions);
-      context.EvaluatedSolutions += evaluatedSolutions;
-      return pi_star;
-    }
-
-    private void ApproxLocalSearch(GQAPSolution pi_prime) {
-      var localSearchEvaluations = 0;
-      ApproximateLocalSearch.Apply(context.Random, pi_prime, MaximumCandidateListSize,
-        OneMoveProbability, MaximumLocalSearchIterations, Problem.ProblemInstance, out localSearchEvaluations);
-      context.EvaluatedSolutions += localSearchEvaluations;
-    }
-
-    private bool StoppingCriterion() {
-      return context.Iterations > MaximumIterations;
-    }
-  }
-}
Index: /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms/3.3/GRASP/GRASP.cs
===================================================================
--- /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms/3.3/GRASP/GRASP.cs	(revision 15562)
+++ /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms/3.3/GRASP/GRASP.cs	(revision 15562)
@@ -0,0 +1,275 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2017 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Linq;
+using System.Threading;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Encodings.IntegerVectorEncoding;
+using HeuristicLab.Optimization;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms.GRASP {
+
+  /// <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("GRASP+PR (GQAP)", "The algorithm implements the Greedy Randomized Adaptive Search Procedure (GRASP) with Path Relinking as 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.")]
+  [Creatable(CreatableAttribute.Categories.PopulationBasedAlgorithms)]
+  [StorableClass]
+  public sealed class GRASP : StochasticAlgorithm<GRASPContext> {
+
+    public override bool SupportsPause {
+      get { return true; }
+    }
+
+    public override Type ProblemType {
+      get { return typeof(GQAP); }
+    }
+
+    public new GQAP Problem {
+      get { return (GQAP)base.Problem; }
+      set { base.Problem = value; }
+    }
+
+    [Storable]
+    private FixedValueParameter<IntValue> eliteSetSizeParameter;
+    private IFixedValueParameter<IntValue> EliteSetSizeParameter {
+      get { return eliteSetSizeParameter; }
+    }
+    [Storable]
+    private FixedValueParameter<IntValue> minimiumEliteSetSizeParameter;
+    public IFixedValueParameter<IntValue> MinimumEliteSetSizeParameter {
+      get { return minimiumEliteSetSizeParameter; }
+    }
+    [Storable]
+    private FixedValueParameter<IntValue> maximumLocalSearchIterationsParameter;
+    public IFixedValueParameter<IntValue> MaximumLocalSearchIterationsParameter {
+      get { return maximumLocalSearchIterationsParameter; }
+    }
+    [Storable]
+    private FixedValueParameter<PercentValue> candidateSizeFactorParameter;
+    public IFixedValueParameter<PercentValue> CandidateSizeFactorParameter {
+      get { return candidateSizeFactorParameter; }
+    }
+    [Storable]
+    private FixedValueParameter<IntValue> maximumCandidateListSizeParameter;
+    public IFixedValueParameter<IntValue> MaximumCandidateListSizeParameter {
+      get { return maximumCandidateListSizeParameter; }
+    }
+    [Storable]
+    private FixedValueParameter<PercentValue> oneMoveProbabilityParameter;
+    public IFixedValueParameter<PercentValue> OneMoveProbabilityParameter {
+      get { return oneMoveProbabilityParameter; }
+    }
+    [Storable]
+    private FixedValueParameter<IntValue> minimumDifferenceParameter;
+    public IFixedValueParameter<IntValue> MinimumDifferenceParameter {
+      get { return minimumDifferenceParameter; }
+    }
+    
+    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 MaximumLocalSearchIterations {
+      get { return maximumLocalSearchIterationsParameter.Value.Value; }
+      set { maximumLocalSearchIterationsParameter.Value.Value = value; }
+    }
+    public double CandidateSizeFactor {
+      get { return candidateSizeFactorParameter.Value.Value; }
+      set { candidateSizeFactorParameter.Value.Value = value; }
+    }
+    public int MaximumCandidateListSize {
+      get { return maximumCandidateListSizeParameter.Value.Value; }
+      set { maximumCandidateListSizeParameter.Value.Value = value; }
+    }
+    public double OneMoveProbability {
+      get { return oneMoveProbabilityParameter.Value.Value; }
+      set { oneMoveProbabilityParameter.Value.Value = value; }
+    }
+    public int MinimumDifference {
+      get { return minimumDifferenceParameter.Value.Value; }
+      set { minimumDifferenceParameter.Value.Value = value; }
+    }
+
+    [StorableConstructor]
+    private GRASP(bool deserializing) : base(deserializing) { }
+    private GRASP(GRASP original, Cloner cloner)
+      : base(original, cloner) {
+      eliteSetSizeParameter = cloner.Clone(original.eliteSetSizeParameter);
+      minimiumEliteSetSizeParameter = cloner.Clone(original.minimiumEliteSetSizeParameter);
+      maximumLocalSearchIterationsParameter = cloner.Clone(original.maximumLocalSearchIterationsParameter);
+      candidateSizeFactorParameter = cloner.Clone(original.candidateSizeFactorParameter);
+      maximumCandidateListSizeParameter = cloner.Clone(original.maximumCandidateListSizeParameter);
+      oneMoveProbabilityParameter = cloner.Clone(original.oneMoveProbabilityParameter);
+      minimumDifferenceParameter = cloner.Clone(original.minimumDifferenceParameter);
+    }
+    public GRASP() {
+      Parameters.Add(eliteSetSizeParameter = new FixedValueParameter<IntValue>("EliteSetSize", "The (maximum) size of the elite set.", new IntValue(10)));
+      Parameters.Add(minimiumEliteSetSizeParameter = new FixedValueParameter<IntValue>("MinimumEliteSetSize", "(ρ) The minimal size of the elite set, before local search and path relinking are applied.", new IntValue(2)));
+      Parameters.Add(maximumLocalSearchIterationsParameter = new FixedValueParameter<IntValue>("MaximumLocalSearchIteration", "The maximum number of iterations that the approximate local search should run", new IntValue(100)));
+      Parameters.Add(candidateSizeFactorParameter = new FixedValueParameter<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(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<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();
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new GRASP(this, cloner);
+    }
+
+    protected override void Initialize(CancellationToken cancellationToken) {
+      base.Initialize(cancellationToken);
+
+      Context.Problem = Problem;      
+      Context.BestQuality = double.NaN;
+      Context.BestSolution = null;
+
+      Results.Add(new Result("Iterations", new IntValue(Context.Iterations)));
+      Results.Add(new Result("EvaluatedSolutions", new IntValue(Context.EvaluatedSolutions)));
+      Results.Add(new Result("BestQuality", new DoubleValue(Context.BestQuality)));
+      Results.Add(new Result("BestSolution", typeof(GQAPSolution)));
+
+      Context.RunOperator(Analyzer, Context.Scope, cancellationToken);
+    }
+
+    protected override void Run(CancellationToken cancellationToken) {
+      var eq = new IntegerVectorEqualityComparer();
+      while (!StoppingCriterion()) { // line 2 in Algorithm 1
+        // next: line 3 in Algorithm 1
+        var pi_prime_vec = GreedyRandomizedSolutionCreator.CreateSolution(Context.Random, Problem.ProblemInstance, 1000, false, cancellationToken);
+        if (Context.PopulationCount >= MinimumEliteSetSize) { // line 4 in Algorithm 1
+          GQAPSolution pi_prime;
+          if (!Problem.ProblemInstance.IsFeasible(pi_prime_vec)) // line 5 in Algorithm 1
+            pi_prime = Context.AtPopulation(Context.Random.Next(Context.PopulationCount)).Solution; // line 6 in Algorithm 1
+          else {
+            // This is necessary, because pi_prime has not been evaluated yet and such details are not covered in Algorithm 1
+            pi_prime = Problem.ProblemInstance.ToEvaluatedSolution(pi_prime_vec);
+            Context.EvaluatedSolutions++;
+          }
+
+          ApproxLocalSearch(pi_prime); // line 8 in Algorithm 1
+          var pi_plus = Context.AtPopulation(Context.Random.Next(Context.PopulationCount)); // line 9 in Algorithm 1
+          pi_prime = PathRelinking(pi_prime, pi_plus.Solution); // line 10 in Algorithm 1
+          ApproxLocalSearch(pi_prime); // line 11 in Algorithm 1
+          var fitness = Problem.ProblemInstance.ToSingleObjective(pi_prime.Evaluation);
+          // Book-keeping
+          if (Context.BestQuality > fitness) {
+            Context.BestQuality = fitness;
+            Context.BestSolution = (GQAPSolution)pi_prime.Clone();
+          }
+
+          if (Context.PopulationCount == EliteSetSize) { // line 12 in Algorithm 1
+            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 / (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();
+              if (replacement.Length > 0) { // cond. 1 of line 13 in Algorithm 1
+                // next two lines: line 14 in Algorithm 1
+                replacement = replacement.OrderBy(x => similarities[x.Index]).ToArray();
+                Context.ReplaceAtPopulation(replacement.Last().Index, Context.ToScope(pi_prime, fit));
+              }
+            }
+          } else if (IsSufficientlyDifferent(pi_prime.Assignment)) { // line 17 in Algorithm 1
+            Context.AddToPopulation(Context.ToScope(pi_prime, Problem.ProblemInstance.ToSingleObjective(pi_prime.Evaluation))); // line 18 in Algorithm 1
+          }
+        } else if (Problem.ProblemInstance.IsFeasible(pi_prime_vec) /* cond. 1 of line 21 in Algorithm 1 */
+          && IsSufficientlyDifferent(pi_prime_vec))  /* cond. 2 of line 21 in Algorithm 1 */ {
+          var pi_prime = Problem.ProblemInstance.ToEvaluatedSolution(pi_prime_vec);
+          Context.EvaluatedSolutions++;
+          var fitness = Problem.ProblemInstance.ToSingleObjective(pi_prime.Evaluation);
+          Context.AddToPopulation(Context.ToScope(pi_prime, fitness)); /* line 22 in Algorithm 1 */
+          // Book-keeping
+          if (Context.PopulationCount == 1 || Context.BestQuality > fitness) {
+            Context.BestQuality = fitness;
+            Context.BestSolution = (GQAPSolution)pi_prime.Clone();
+          }
+        }
+
+        IResult result;
+        if (Results.TryGetValue("Iterations", out result))
+          ((IntValue)result.Value).Value = Context.Iterations;
+        else Results.Add(new Result("Iterations", new IntValue(Context.Iterations)));
+        if (Results.TryGetValue("EvaluatedSolutions", out result))
+          ((IntValue)result.Value).Value = Context.EvaluatedSolutions;
+        else Results.Add(new Result("EvaluatedSolutions", new IntValue(Context.EvaluatedSolutions)));
+        if (Results.TryGetValue("BestQuality", out result))
+          ((DoubleValue)result.Value).Value = Context.BestQuality;
+        else Results.Add(new Result("BestQuality", new DoubleValue(Context.BestQuality)));
+        if (Results.TryGetValue("BestSolution", out result))
+          result.Value = Context.BestSolution;
+        else Results.Add(new Result("BestSolution", Context.BestSolution));
+
+        Context.RunOperator(Analyzer, Context.Scope, cancellationToken);
+
+        Context.Iterations++;
+        if (cancellationToken.IsCancellationRequested) break;
+      }
+    }
+
+    private bool IsSufficientlyDifferent(IntegerVector vec) {
+      return Context.Population.All(x =>
+        HammingSimilarityCalculator.CalculateSimilarity(vec, x.Solution.Assignment) <= 1.0 - (MinimumDifference / (double)vec.Length)
+      );
+    }
+
+    private GQAPSolution PathRelinking(GQAPSolution pi_prime, GQAPSolution pi_plus) {
+      // Following code represents line 1 of Algorithm 4
+      IntegerVector source = pi_prime.Assignment, target = pi_plus.Assignment;
+      Evaluation sourceEval = pi_prime.Evaluation, targetEval = pi_plus.Evaluation;
+      var sourceFit = Problem.ProblemInstance.ToSingleObjective(sourceEval);
+      var targetFit = Problem.ProblemInstance.ToSingleObjective(targetEval);
+      if (targetFit < sourceFit) {
+        var h = source;
+        source = target;
+        target = h;
+        var hh = sourceEval;
+        sourceEval = targetEval;
+        targetEval = hh;
+      }
+      int evaluatedSolutions;
+      // lines 2-36 of Algorithm 4 are implemented in the following call
+      var pi_star = GQAPPathRelinking.Apply(Context.Random, source, sourceEval,
+        target, targetEval, Problem.ProblemInstance, CandidateSizeFactor,
+        out evaluatedSolutions);
+      Context.EvaluatedSolutions += evaluatedSolutions;
+      return pi_star;
+    }
+
+    private void ApproxLocalSearch(GQAPSolution pi_prime) {
+      var localSearchEvaluations = 0;
+      ApproximateLocalSearch.Apply(Context.Random, pi_prime, MaximumCandidateListSize,
+        OneMoveProbability, MaximumLocalSearchIterations, Problem.ProblemInstance, out localSearchEvaluations);
+      Context.EvaluatedSolutions += localSearchEvaluations;
+    }
+  }
+}
Index: /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms/3.3/GRASP/GRASPContext.cs
===================================================================
--- /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms/3.3/GRASP/GRASPContext.cs	(revision 15562)
+++ /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms/3.3/GRASP/GRASPContext.cs	(revision 15562)
@@ -0,0 +1,79 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2017 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.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms.GRASP {
+  [Item("GRASP+PR (GQAP) Context", "Context for GRASP+PR (GQAP).")]
+  [StorableClass]
+  public sealed class GRASPContext : SingleObjectivePopulationContext<ISingleObjectiveSolutionScope<GQAPSolution>> {
+    
+    [Storable]
+    private IValueParameter<GQAP> problem;
+    public GQAP Problem {
+      get { return problem.Value; }
+      set { problem.Value = value; }
+    }
+
+    [Storable]
+    private IValueParameter<GQAPSolution> bestSolution;
+    public GQAPSolution BestSolution {
+      get { return bestSolution.Value; }
+      set { bestSolution.Value = value; }
+    }
+    
+    public void SortPopulation() {
+      Scope.SubScopes.Replace(Scope.SubScopes.OfType<ISingleObjectiveSolutionScope<GQAPSolution>>().OrderBy(x => Problem.Maximization ? -x.Fitness : x.Fitness).ToList());
+    }
+    
+    [StorableConstructor]
+    private GRASPContext(bool deserializing) : base(deserializing) { }
+    private GRASPContext(GRASPContext original, Cloner cloner)
+      : base(original, cloner) {
+      problem = cloner.Clone(original.problem);
+      bestSolution = cloner.Clone(original.bestSolution);
+    }
+    public GRASPContext() : this("GRASP+PR (GQAP) Context") { }
+    public GRASPContext(string name) : base(name) {
+      Parameters.Add(problem = new ValueParameter<GQAP>("Problem"));
+      Parameters.Add(bestSolution = new ValueParameter<GQAPSolution>("BestFoundSolution"));
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new GRASPContext(this, cloner);
+    }
+
+    public ISingleObjectiveSolutionScope<GQAPSolution> ToScope(GQAPSolution code, double fitness = double.NaN) {
+      var name = Problem.Encoding.Name;
+      var scope = new SingleObjectiveSolutionScope<GQAPSolution>(code,
+        name + "Solution", fitness, Problem.Evaluator.QualityParameter.ActualName) {
+        Parent = Scope
+      };
+      scope.Variables.Add(new Variable(name, code.Assignment));
+      scope.Variables.Add(new Variable("Evaluation", code.Evaluation));
+      return scope;
+    }
+  }
+}
Index: anches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms/3.3/GRASPContext.cs
===================================================================
--- /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms/3.3/GRASPContext.cs	(revision 15561)
+++ 	(revision )
@@ -1,256 +1,0 @@
-﻿#region License Information
-/* HeuristicLab
- * Copyright (C) 2002-2017 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
- *
- * This file is part of HeuristicLab.
- *
- * HeuristicLab is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * HeuristicLab is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
- */
-#endregion
-
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Runtime.CompilerServices;
-using System.Threading;
-using HeuristicLab.Common;
-using HeuristicLab.Core;
-using HeuristicLab.Data;
-using HeuristicLab.Optimization;
-using HeuristicLab.Parameters;
-using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
-using HeuristicLab.Random;
-
-namespace HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms.GRASP {
-  [Item("GRASP+PR (GQAP) Context", "Context for GRASP+PR (GQAP).")]
-  [StorableClass]
-  public sealed class GRASPContext : ParameterizedNamedItem, IExecutionContext {
-    
-    private IExecutionContext parent;
-    public IExecutionContext Parent {
-      get { return parent; }
-      set { parent = value; }
-    }
-
-    [Storable]
-    private IScope scope;
-    public IScope Scope {
-      get { return scope; }
-      private set { scope = value; }
-    }
-
-    IKeyedItemCollection<string, IParameter> IExecutionContext.Parameters {
-      get { return Parameters; }
-    }
-
-    [Storable]
-    private IValueParameter<GQAP> problem;
-    public GQAP Problem {
-      get { return problem.Value; }
-      set { problem.Value = value; }
-    }
-    public bool Maximization {
-      get { return Problem.Maximization; }
-    }
-
-    [Storable]
-    private IValueParameter<BoolValue> initialized;
-    public bool Initialized {
-      get { return initialized.Value.Value; }
-      set { initialized.Value.Value = value; }
-    }
-
-    [Storable]
-    private IValueParameter<IntValue> iterations;
-    public int Iterations {
-      get { return iterations.Value.Value; }
-      set { iterations.Value.Value = value; }
-    }
-
-    [Storable]
-    private IValueParameter<IntValue> evaluatedSolutions;
-    public int EvaluatedSolutions {
-      get { return evaluatedSolutions.Value.Value; }
-      set { evaluatedSolutions.Value.Value = value; }
-    }
-
-    [Storable]
-    private IValueParameter<DoubleValue> bestQuality;
-    public double BestQuality {
-      get { return bestQuality.Value.Value; }
-      set { bestQuality.Value.Value = value; }
-    }
-
-    [Storable]
-    private IValueParameter<GQAPSolution> bestSolution;
-    public GQAPSolution BestSolution {
-      get { return bestSolution.Value; }
-      set { bestSolution.Value = value; }
-    }
-
-    [Storable]
-    private IValueParameter<IntValue> localSearchEvaluations;
-    public int LocalSearchEvaluations {
-      get { return localSearchEvaluations.Value.Value; }
-      set { localSearchEvaluations.Value.Value = value; }
-    }
-    
-    [Storable]
-    private IValueParameter<IRandom> random;
-    public IRandom Random {
-      get { return random.Value; }
-      set { random.Value = value; }
-    }
-
-    public IEnumerable<ISingleObjectiveSolutionScope<GQAPSolution>> Population {
-      get { return scope.SubScopes.OfType<ISingleObjectiveSolutionScope<GQAPSolution>>(); }
-    }
-    public void AddToPopulation(ISingleObjectiveSolutionScope<GQAPSolution> solScope) {
-      scope.SubScopes.Add(solScope);
-    }
-    public void ReplaceAtPopulation(int index, ISingleObjectiveSolutionScope<GQAPSolution> solScope) {
-      scope.SubScopes[index] = solScope;
-    }
-    public ISingleObjectiveSolutionScope<GQAPSolution> AtPopulation(int index) {
-      return scope.SubScopes[index] as ISingleObjectiveSolutionScope<GQAPSolution>;
-    }
-    public void SortPopulation() {
-      scope.SubScopes.Replace(scope.SubScopes.OfType<ISingleObjectiveSolutionScope<GQAPSolution>>().OrderBy(x => Maximization ? -x.Fitness : x.Fitness).ToList());
-    }
-    public int PopulationCount {
-      get { return scope.SubScopes.Count; }
-    }
-    
-    [StorableConstructor]
-    private GRASPContext(bool deserializing) : base(deserializing) { }
-    private GRASPContext(GRASPContext original, Cloner cloner)
-      : base(original, cloner) {
-      scope = cloner.Clone(original.scope);
-      problem = cloner.Clone(original.problem);
-      initialized = cloner.Clone(original.initialized);
-      iterations = cloner.Clone(original.iterations);
-      evaluatedSolutions = cloner.Clone(original.evaluatedSolutions);
-      bestQuality = cloner.Clone(original.bestQuality);
-      bestSolution = cloner.Clone(original.bestSolution);
-      localSearchEvaluations = cloner.Clone(original.localSearchEvaluations);
-      random = cloner.Clone(original.random);
-    }
-    public GRASPContext() : this("GRASP+PR (GQAP) Context") { }
-    public GRASPContext(string name) : base(name) {
-      scope = new Scope("Global");
-
-      Parameters.Add(problem = new ValueParameter<GQAP>("Problem"));
-      Parameters.Add(initialized = new ValueParameter<BoolValue>("Initialized", new BoolValue(false)));
-      Parameters.Add(iterations = new ValueParameter<IntValue>("Iterations", new IntValue(0)));
-      Parameters.Add(evaluatedSolutions = new ValueParameter<IntValue>("EvaluatedSolutions", new IntValue(0)));
-      Parameters.Add(bestQuality = new ValueParameter<DoubleValue>("BestQuality", new DoubleValue(double.NaN)));
-      Parameters.Add(bestSolution = new ValueParameter<GQAPSolution>("BestFoundSolution"));
-      Parameters.Add(localSearchEvaluations = new ValueParameter<IntValue>("LocalSearchEvaluations", new IntValue(0)));
-      Parameters.Add(random = new ValueParameter<IRandom>("Random", new MersenneTwister()));
-    }
-
-    public override IDeepCloneable Clone(Cloner cloner) {
-      return new GRASPContext(this, cloner);
-    }
-
-    public ISingleObjectiveSolutionScope<GQAPSolution> ToScope(GQAPSolution code, double fitness = double.NaN) {
-      var name = Problem.Encoding.Name;
-      var scope = new SingleObjectiveSolutionScope<GQAPSolution>(code,
-        name + "Solution", fitness, Problem.Evaluator.QualityParameter.ActualName) {
-        Parent = Scope
-      };
-      scope.Variables.Add(new Variable(name, code.Assignment));
-      scope.Variables.Add(new Variable("Evaluation", code.Evaluation));
-      return scope;
-    }
-
-    public void IncrementEvaluatedSolutions(int byEvaluations) {
-      if (byEvaluations < 0) throw new ArgumentException("Can only increment and not decrement evaluated solutions.");
-      EvaluatedSolutions += byEvaluations;
-    }
-    
-    private static void ExecuteAlgorithm(IAlgorithm algorithm) {
-      using (var evt = new AutoResetEvent(false)) {
-        EventHandler exeStateChanged = (o, args) => {
-          if (algorithm.ExecutionState != ExecutionState.Started)
-            evt.Set();
-        };
-        algorithm.ExecutionStateChanged += exeStateChanged;
-        if (algorithm.ExecutionState != ExecutionState.Prepared) {
-          algorithm.Prepare(true);
-          evt.WaitOne();
-        }
-        algorithm.Start();
-        evt.WaitOne();
-        algorithm.ExecutionStateChanged -= exeStateChanged;
-      }
-    }
-    [MethodImpl(MethodImplOptions.AggressiveInlining)]
-    public bool IsBetter(ISingleObjectiveSolutionScope<GQAPSolution> a, ISingleObjectiveSolutionScope<GQAPSolution> b) {
-      return IsBetter(a.Fitness, b.Fitness);
-    }
-    [MethodImpl(MethodImplOptions.AggressiveInlining)]
-    public bool IsBetter(double a, double b) {
-      return double.IsNaN(b) && !double.IsNaN(a)
-        || Maximization && a > b
-        || !Maximization && a < b;
-    }
-
-    #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
-
-    #region Engine Helper
-    public void RunOperator(IOperator op, IScope scope, CancellationToken cancellationToken) {
-      var stack = new Stack<IOperation>();
-      stack.Push(CreateChildOperation(op, scope));
-
-      while (stack.Count > 0) {
-        cancellationToken.ThrowIfCancellationRequested();
-
-        var next = stack.Pop();
-        if (next is OperationCollection) {
-          var coll = (OperationCollection)next;
-          for (int i = coll.Count - 1; i >= 0; i--)
-            if (coll[i] != null) stack.Push(coll[i]);
-        } else if (next is IAtomicOperation) {
-          var operation = (IAtomicOperation)next;
-          try {
-            next = operation.Operator.Execute((IExecutionContext)operation, cancellationToken);
-          } catch (Exception ex) {
-            stack.Push(operation);
-            if (ex is OperationCanceledException) throw ex;
-            else throw new OperatorExecutionException(operation.Operator, ex);
-          }
-          if (next != null) stack.Push(next);
-        }
-      }
-    }
-    #endregion
-  }
-}
Index: /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms/3.3/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms-3.3.csproj
===================================================================
--- /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms/3.3/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms-3.3.csproj	(revision 15561)
+++ /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms/3.3/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms-3.3.csproj	(revision 15562)
@@ -99,10 +99,24 @@
   </ItemGroup>
   <ItemGroup>
-    <Compile Include="GRASPContext.cs" />
-    <Compile Include="GRASP.cs" />
-    <Compile Include="Interfaces.cs" />
+    <Compile Include="Evolutionary\ESContext.cs" />
+    <Compile Include="Evolutionary\ESGQAPSolution.cs" />
+    <Compile Include="Evolutionary\EvolutionStrategy.cs" />
+    <Compile Include="Infrastructure\Algorithms\StochasticAlgorithm.cs" />
+    <Compile Include="Infrastructure\Contexts\SingleObjectiveSingleSolutionContext.cs" />
+    <Compile Include="Infrastructure\Contexts\SingleObjectivePopulationContext.cs" />
+    <Compile Include="Infrastructure\Contexts\StochasticContext.cs" />
+    <Compile Include="Infrastructure\Contexts\BasicContext.cs" />
+    <Compile Include="Infrastructure\Algorithms\ContextAlgorithm.cs" />
+    <Compile Include="GRASP\GRASPContext.cs" />
+    <Compile Include="GRASP\GRASP.cs" />
+    <Compile Include="LocalSearch\LocalSearchContext.cs" />
+    <Compile Include="Infrastructure\Interfaces.cs" />
+    <Compile Include="LocalSearch\IteratedLS.cs" />
+    <Compile Include="LocalSearch\MultistartLS.cs" />
     <Compile Include="Plugin.cs" />
+    <Compile Include="Infrastructure\Contexts\SingleSolutionContext.cs" />
+    <Compile Include="Infrastructure\Contexts\PopulationContext.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
-    <Compile Include="SingleObjectiveSolutionScope.cs" />
+    <Compile Include="Infrastructure\SingleObjectiveSolutionScope.cs" />
   </ItemGroup>
   <ItemGroup>
Index: /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms/3.3/Infrastructure/Algorithms/ContextAlgorithm.cs
===================================================================
--- /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms/3.3/Infrastructure/Algorithms/ContextAlgorithm.cs	(revision 15562)
+++ /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms/3.3/Infrastructure/Algorithms/ContextAlgorithm.cs	(revision 15562)
@@ -0,0 +1,126 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2017 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Threading;
+using HeuristicLab.Analysis;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Optimization;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms {
+  [Item("Context-based Algorithm", "Algorithms that make use of contexts to facilitate applying operators.")]
+  [StorableClass]
+  public abstract class ContextAlgorithm<TContext> : BasicAlgorithm
+    where TContext : class, IContext, new() {
+
+    [Storable]
+    private TContext context;
+    protected TContext Context {
+      get { return context; }
+    }
+
+    [Storable]
+    private ValueParameter<IAnalyzer> analyzerParameter;
+    public IValueParameter<IAnalyzer> AnalyzerParameter {
+      get { return analyzerParameter; }
+    }
+    [Storable]
+    private FixedValueParameter<IntValue> maximumIterationsParameter;
+    public IFixedValueParameter<IntValue> MaximumIterationsParameter {
+      get { return maximumIterationsParameter; }
+    }
+    [Storable]
+    private FixedValueParameter<IntValue> maximumEvaluationsParameter;
+    public IFixedValueParameter<IntValue> MaximumEvaluationsParameter {
+      get { return maximumEvaluationsParameter; }
+    }
+    [Storable]
+    private FixedValueParameter<TimeSpanValue> maximumRuntimeParameter;
+    public IFixedValueParameter<TimeSpanValue> MaximumRuntimeParameter {
+      get { return maximumRuntimeParameter; }
+    }
+
+    public IAnalyzer Analyzer {
+      get { return analyzerParameter.Value; }
+      set { analyzerParameter.Value = value; }
+    }
+    public int MaximumIterations {
+      get { return maximumIterationsParameter.Value.Value; }
+      set { maximumIterationsParameter.Value.Value = value; }
+    }
+    public int MaximumEvaluations {
+      get { return maximumEvaluationsParameter.Value.Value; }
+      set { maximumEvaluationsParameter.Value.Value = value; }
+    }
+    public TimeSpan MaximumRuntime {
+      get { return maximumRuntimeParameter.Value.Value; }
+      set { maximumRuntimeParameter.Value.Value = value; }
+    }
+
+    [StorableConstructor]
+    protected ContextAlgorithm(bool deserializing) : base(deserializing) { }
+    protected ContextAlgorithm(ContextAlgorithm<TContext> original, Cloner cloner)
+      : base(original, cloner) {
+      context = cloner.Clone(original.context);
+      analyzerParameter = cloner.Clone(original.analyzerParameter);
+      maximumIterationsParameter = cloner.Clone(original.maximumIterationsParameter);
+      maximumEvaluationsParameter = cloner.Clone(original.maximumEvaluationsParameter);
+      maximumRuntimeParameter = cloner.Clone(original.maximumRuntimeParameter);
+    }
+    protected ContextAlgorithm()
+      : base() {
+      Parameters.Add(analyzerParameter = new ValueParameter<IAnalyzer>("Analyzer", "The analyzers that are used to perform an analysis of the solutions.", new MultiAnalyzer()));
+      Parameters.Add(maximumIterationsParameter = new FixedValueParameter<IntValue>("MaximumIterations", "The number of iterations that the algorithm should run or < 1 to ignore.", new IntValue(0)));
+      Parameters.Add(maximumEvaluationsParameter = new FixedValueParameter<IntValue>("MaximumEvaluations", "The number of evaluated solutions that the algorithm should perform or < 1 to ignore.", new IntValue(0)));
+      Parameters.Add(maximumRuntimeParameter = new FixedValueParameter<TimeSpanValue>("MaximumRuntime", "The timespan that the algorithm is allowed to run.", new TimeSpanValue(TimeSpan.FromMinutes(1))));
+    }
+
+    protected override void Initialize(CancellationToken cancellationToken) {
+      base.Initialize(cancellationToken);
+      context = new TContext();
+      context.Scope.Variables.Add(new Variable("Results", Results));
+
+      IExecutionContext ctxt = null;
+      foreach (var item in Problem.ExecutionContextItems)
+        ctxt = new Core.ExecutionContext(ctxt, item, Context.Scope);
+      ctxt = new Core.ExecutionContext(ctxt, this, Context.Scope);
+      context.Parent = ctxt;
+
+      context.Iterations = 0;
+      context.EvaluatedSolutions = 0;
+    }
+
+    public override void Prepare() {
+      context = null;
+      base.Prepare();
+    }
+
+    protected virtual bool StoppingCriterion() {
+      return MaximumIterations > 0 && Context.Iterations > MaximumIterations
+        || MaximumEvaluations > 0 && Context.EvaluatedSolutions > MaximumEvaluations
+        || MaximumRuntime > TimeSpan.Zero && ExecutionTime > MaximumRuntime;
+    }
+  }
+}
Index: /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms/3.3/Infrastructure/Algorithms/StochasticAlgorithm.cs
===================================================================
--- /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms/3.3/Infrastructure/Algorithms/StochasticAlgorithm.cs	(revision 15562)
+++ /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms/3.3/Infrastructure/Algorithms/StochasticAlgorithm.cs	(revision 15562)
@@ -0,0 +1,80 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2017 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.Threading;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Random;
+
+namespace HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms {
+  [Item("Stochastic Algorithm", "Stochastic context-based algorithms to facilitate applying operators.")]
+  [StorableClass]
+  public abstract class StochasticAlgorithm<TContext> : ContextAlgorithm<TContext>
+    where TContext : class, IStochasticContext, new() {
+    
+    [Storable]
+    private FixedValueParameter<BoolValue> setSeedRandomlyParameter;
+    private IFixedValueParameter<BoolValue> SetSeedRandomlyParameter {
+      get { return setSeedRandomlyParameter; }
+    }
+    [Storable]
+    private FixedValueParameter<IntValue> seedParameter;
+    private IFixedValueParameter<IntValue> SeedParameter {
+      get { return seedParameter; }
+    }
+    
+    public bool SetSeedRandomly {
+      get { return setSeedRandomlyParameter.Value.Value; }
+      set { setSeedRandomlyParameter.Value.Value = value; }
+    }
+    public int Seed {
+      get { return seedParameter.Value.Value; }
+      set { seedParameter.Value.Value = value; }
+    }
+
+    [StorableConstructor]
+    protected StochasticAlgorithm(bool deserializing) : base(deserializing) { }
+    protected StochasticAlgorithm(StochasticAlgorithm<TContext> original, Cloner cloner)
+      : base(original, cloner) {
+      setSeedRandomlyParameter = cloner.Clone(original.setSeedRandomlyParameter);
+      seedParameter = cloner.Clone(original.seedParameter);
+    }
+    protected StochasticAlgorithm()
+      : base() {
+      Parameters.Add(setSeedRandomlyParameter = new FixedValueParameter<BoolValue>("SetSeedRandomly", "Whether to overwrite the seed with a random value each time the algorithm is run.", new BoolValue(true)));
+      Parameters.Add(seedParameter = new FixedValueParameter<IntValue>("Seed", "The random seed that is used in the stochastic algorithm", new IntValue(0)));
+    }
+
+    protected override void Initialize(CancellationToken cancellationToken) {
+      base.Initialize(cancellationToken);
+
+      if (SetSeedRandomly) {
+        var rnd = new System.Random();
+        Seed = rnd.Next();
+      }
+
+      Context.Random = new MersenneTwister((uint)Seed);
+    }
+  }
+}
Index: /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms/3.3/Infrastructure/Contexts/BasicContext.cs
===================================================================
--- /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms/3.3/Infrastructure/Contexts/BasicContext.cs	(revision 15562)
+++ /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms/3.3/Infrastructure/Contexts/BasicContext.cs	(revision 15562)
@@ -0,0 +1,144 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2017 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Threading;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms {
+  public class BasicContext : ParameterizedNamedItem, IContext {
+
+    private IExecutionContext parent;
+    public IExecutionContext Parent {
+      get { return parent; }
+      set { parent = value; }
+    }
+
+    [Storable]
+    private IScope scope;
+    public IScope Scope {
+      get { return scope; }
+      private set { scope = value; }
+    }
+
+    IKeyedItemCollection<string, IParameter> IExecutionContext.Parameters {
+      get { return Parameters; }
+    }
+
+    [Storable]
+    private IFixedValueParameter<IntValue> iterations;
+    public int Iterations {
+      get { return iterations.Value.Value; }
+      set { iterations.Value.Value = value; }
+    }
+
+    [Storable]
+    private IFixedValueParameter<IntValue> evaluatedSolutions;
+    public int EvaluatedSolutions {
+      get { return evaluatedSolutions.Value.Value; }
+      set { evaluatedSolutions.Value.Value = value; }
+    }
+
+    [StorableConstructor]
+    protected BasicContext(bool deserializing) : base(deserializing) { }
+    protected BasicContext(BasicContext original, Cloner cloner)
+    : base(original, cloner) {
+      scope = cloner.Clone(original.scope);
+      iterations = cloner.Clone(original.iterations);
+      evaluatedSolutions = cloner.Clone(original.evaluatedSolutions);
+    }
+    protected BasicContext() : base() {
+      scope = new Scope("Global");
+      Parameters.Add(iterations = new FixedValueParameter<IntValue>("Iterations", new IntValue(0)));
+      Parameters.Add(evaluatedSolutions = new FixedValueParameter<IntValue>("EvaluatedSolutions", new IntValue(0)));
+    }
+    protected BasicContext(string name) : base(name) {
+      scope = new Scope("Global");
+      Parameters.Add(iterations = new FixedValueParameter<IntValue>("Iterations", new IntValue(0)));
+      Parameters.Add(evaluatedSolutions = new FixedValueParameter<IntValue>("EvaluatedSolutions", new IntValue(0)));
+    }
+    protected BasicContext(string name, ParameterCollection parameters) : base(name, parameters) {
+      scope = new Scope("Global");
+      Parameters.Add(iterations = new FixedValueParameter<IntValue>("Iterations", new IntValue(0)));
+      Parameters.Add(evaluatedSolutions = new FixedValueParameter<IntValue>("EvaluatedSolutions", new IntValue(0)));
+    }
+    protected BasicContext(string name, string description) : base(name, description) {
+      scope = new Scope("Global");
+      Parameters.Add(iterations = new FixedValueParameter<IntValue>("Iterations", new IntValue(0)));
+      Parameters.Add(evaluatedSolutions = new FixedValueParameter<IntValue>("EvaluatedSolutions", new IntValue(0)));
+    }
+    protected BasicContext(string name, string description, ParameterCollection parameters) : base(name, description, parameters) {
+      scope = new Scope("Global");
+      Parameters.Add(iterations = new FixedValueParameter<IntValue>("Iterations", new IntValue(0)));
+      Parameters.Add(evaluatedSolutions = new FixedValueParameter<IntValue>("EvaluatedSolutions", new IntValue(0)));
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new BasicContext(this, cloner);
+    }
+
+    public void RunOperator(IOperator op, IScope scope, CancellationToken cancellationToken) {
+      var stack = new Stack<IOperation>();
+      stack.Push(((IExecutionContext)this).CreateChildOperation(op, scope));
+
+      while (stack.Count > 0) {
+        cancellationToken.ThrowIfCancellationRequested();
+
+        var next = stack.Pop();
+        if (next is OperationCollection) {
+          var coll = (OperationCollection)next;
+          for (int i = coll.Count - 1; i >= 0; i--)
+            if (coll[i] != null) stack.Push(coll[i]);
+        } else if (next is IAtomicOperation) {
+          var operation = (IAtomicOperation)next;
+          try {
+            next = operation.Operator.Execute((IExecutionContext)operation, cancellationToken);
+          } catch (Exception ex) {
+            stack.Push(operation);
+            if (ex is OperationCanceledException) throw ex;
+            else throw new OperatorExecutionException(operation.Operator, ex);
+          }
+          if (next != null) stack.Push(next);
+        }
+      }
+    }
+
+    #region IExecutionContext members
+    IAtomicOperation IExecutionContext.CreateOperation(IOperator op) {
+      return new Core.ExecutionContext(this, op, Scope);
+    }
+    IAtomicOperation IExecutionContext.CreateOperation(IOperator op, IScope s) {
+      return new Core.ExecutionContext(this, op, s);
+    }
+    IAtomicOperation IExecutionContext.CreateChildOperation(IOperator op) {
+      return new Core.ExecutionContext(this, op, Scope);
+    }
+    IAtomicOperation IExecutionContext.CreateChildOperation(IOperator op, IScope s) {
+      return new Core.ExecutionContext(this, op, s);
+    }
+    #endregion
+  }
+}
Index: /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms/3.3/Infrastructure/Contexts/PopulationContext.cs
===================================================================
--- /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms/3.3/Infrastructure/Contexts/PopulationContext.cs	(revision 15562)
+++ /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms/3.3/Infrastructure/Contexts/PopulationContext.cs	(revision 15562)
@@ -0,0 +1,64 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2017 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 System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms {
+  [Item("Population Context", "A context for population-based algorithms.")]
+  public abstract class PopulationContext<TSolutionScope> : StochasticContext
+    where TSolutionScope: class, IScope {
+
+    public IEnumerable<TSolutionScope> Population {
+      get { return Scope.SubScopes.OfType<TSolutionScope>(); }
+    }
+    public void AddToPopulation(TSolutionScope solScope) {
+      Scope.SubScopes.Add(solScope);
+    }
+    public void ReplaceAtPopulation(int index, TSolutionScope solScope) {
+      Scope.SubScopes[index] = solScope;
+    }
+    public TSolutionScope AtPopulation(int index) {
+      return Scope.SubScopes[index] as TSolutionScope;
+    }
+    public TSolutionScope AtRandomPopulation() {
+      return Scope.SubScopes[Random.Next(PopulationCount)] as TSolutionScope;
+    }
+    public int PopulationCount {
+      get { return Scope.SubScopes.Count; }
+    }
+
+
+    [StorableConstructor]
+    protected PopulationContext(bool deserializing) : base(deserializing) { }
+    protected PopulationContext(PopulationContext<TSolutionScope> original, Cloner cloner)
+      : base(original, cloner) {
+    }
+    protected PopulationContext() : base() { }
+    protected PopulationContext(string name) : base(name) { }
+    protected PopulationContext(string name, ParameterCollection parameters) : base(name, parameters) { }
+    protected PopulationContext(string name, string description) : base(name, description) { }
+    protected PopulationContext(string name, string description, ParameterCollection parameters) : base(name, description, parameters) { }
+  }
+}
Index: /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms/3.3/Infrastructure/Contexts/SingleObjectivePopulationContext.cs
===================================================================
--- /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms/3.3/Infrastructure/Contexts/SingleObjectivePopulationContext.cs	(revision 15562)
+++ /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms/3.3/Infrastructure/Contexts/SingleObjectivePopulationContext.cs	(revision 15562)
@@ -0,0 +1,66 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2017 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms {
+  [Item("Single-objective Population Context", "A context for single-objective population-based algorithms.")]
+  public abstract class SingleObjectivePopulationContext<TSolutionScope> : PopulationContext<TSolutionScope>
+    where TSolutionScope: class, IScope {
+
+    [Storable]
+    private IValueParameter<DoubleValue> bestQuality;
+    public double BestQuality {
+      get { return bestQuality.Value.Value; }
+      set { bestQuality.Value.Value = value; }
+    }
+
+    [StorableConstructor]
+    protected SingleObjectivePopulationContext(bool deserializing) : base(deserializing) { }
+    protected SingleObjectivePopulationContext(SingleObjectivePopulationContext<TSolutionScope> original, Cloner cloner)
+      : base(original, cloner) {
+      bestQuality = cloner.Clone(original.bestQuality);
+    }
+    protected SingleObjectivePopulationContext()
+      : base() {
+      Parameters.Add(bestQuality = new ValueParameter<DoubleValue>("BestQuality", new DoubleValue(double.NaN)));
+    }
+    protected SingleObjectivePopulationContext(string name) : base(name) {
+      Parameters.Add(bestQuality = new ValueParameter<DoubleValue>("BestQuality", new DoubleValue(double.NaN)));
+    }
+    protected SingleObjectivePopulationContext(string name, ParameterCollection parameters)
+      : base(name, parameters) {
+      Parameters.Add(bestQuality = new ValueParameter<DoubleValue>("BestQuality", new DoubleValue(double.NaN)));
+    }
+    protected SingleObjectivePopulationContext(string name, string description)
+      : base(name, description) {
+      Parameters.Add(bestQuality = new ValueParameter<DoubleValue>("BestQuality", new DoubleValue(double.NaN)));
+    }
+    protected SingleObjectivePopulationContext(string name, string description, ParameterCollection parameters)
+      : base(name, description, parameters) {
+      Parameters.Add(bestQuality = new ValueParameter<DoubleValue>("BestQuality", new DoubleValue(double.NaN)));
+    }
+  }
+}
Index: /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms/3.3/Infrastructure/Contexts/SingleObjectiveSingleSolutionContext.cs
===================================================================
--- /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms/3.3/Infrastructure/Contexts/SingleObjectiveSingleSolutionContext.cs	(revision 15562)
+++ /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms/3.3/Infrastructure/Contexts/SingleObjectiveSingleSolutionContext.cs	(revision 15562)
@@ -0,0 +1,66 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2017 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms {
+  [Item("Single-objective Single Solution Context", "A context for single-objective single solution algorithms.")]
+  public abstract class SingleObjectiveSingleSolutionContext<TSolutionScope> : SingleSolutionContext<TSolutionScope>
+    where TSolutionScope: class, IScope {
+
+    [Storable]
+    private IValueParameter<DoubleValue> bestQuality;
+    public double BestQuality {
+      get { return bestQuality.Value.Value; }
+      set { bestQuality.Value.Value = value; }
+    }
+
+    [StorableConstructor]
+    protected SingleObjectiveSingleSolutionContext(bool deserializing) : base(deserializing) { }
+    protected SingleObjectiveSingleSolutionContext(SingleObjectiveSingleSolutionContext<TSolutionScope> original, Cloner cloner)
+      : base(original, cloner) {
+      bestQuality = cloner.Clone(original.bestQuality);
+    }
+    protected SingleObjectiveSingleSolutionContext()
+      : base() {
+      Parameters.Add(bestQuality = new ValueParameter<DoubleValue>("BestQuality", new DoubleValue(double.NaN)));
+    }
+    protected SingleObjectiveSingleSolutionContext(string name) : base(name) {
+      Parameters.Add(bestQuality = new ValueParameter<DoubleValue>("BestQuality", new DoubleValue(double.NaN)));
+    }
+    protected SingleObjectiveSingleSolutionContext(string name, ParameterCollection parameters)
+      : base(name, parameters) {
+      Parameters.Add(bestQuality = new ValueParameter<DoubleValue>("BestQuality", new DoubleValue(double.NaN)));
+    }
+    protected SingleObjectiveSingleSolutionContext(string name, string description)
+      : base(name, description) {
+      Parameters.Add(bestQuality = new ValueParameter<DoubleValue>("BestQuality", new DoubleValue(double.NaN)));
+    }
+    protected SingleObjectiveSingleSolutionContext(string name, string description, ParameterCollection parameters)
+      : base(name, description, parameters) {
+      Parameters.Add(bestQuality = new ValueParameter<DoubleValue>("BestQuality", new DoubleValue(double.NaN)));
+    }
+  }
+}
Index: /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms/3.3/Infrastructure/Contexts/SingleSolutionContext.cs
===================================================================
--- /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms/3.3/Infrastructure/Contexts/SingleSolutionContext.cs	(revision 15562)
+++ /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms/3.3/Infrastructure/Contexts/SingleSolutionContext.cs	(revision 15562)
@@ -0,0 +1,56 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2017 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms {
+  [Item("Single Solution Context", "A context for single solution algorithms.")]
+  public abstract class SingleSolutionContext<TSolutionScope> : StochasticContext
+    where TSolutionScope: class, IScope {
+    
+    [Storable]
+    private TSolutionScope incumbent;
+    public TSolutionScope Incumbent {
+      get { return incumbent; }
+    }
+
+    public void ReplaceIncumbent(TSolutionScope solScope) {
+      if (incumbent != null) Scope.SubScopes.Remove(incumbent);
+      this.incumbent = solScope;
+      if (incumbent != null) Scope.SubScopes.Add(incumbent);
+    }
+
+
+    [StorableConstructor]
+    protected SingleSolutionContext(bool deserializing) : base(deserializing) { }
+    protected SingleSolutionContext(SingleSolutionContext<TSolutionScope> original, Cloner cloner)
+      : base(original, cloner) {
+      incumbent = cloner.Clone(original.incumbent);
+    }
+    protected SingleSolutionContext() : base() { }
+    protected SingleSolutionContext(string name) : base(name) { }
+    protected SingleSolutionContext(string name, ParameterCollection parameters) : base(name, parameters) { }
+    protected SingleSolutionContext(string name, string description) : base(name, description) { }
+    protected SingleSolutionContext(string name, string description, ParameterCollection parameters) : base(name, description, parameters) { }
+  }
+}
Index: /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms/3.3/Infrastructure/Contexts/StochasticContext.cs
===================================================================
--- /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms/3.3/Infrastructure/Contexts/StochasticContext.cs	(revision 15562)
+++ /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms/3.3/Infrastructure/Contexts/StochasticContext.cs	(revision 15562)
@@ -0,0 +1,64 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2017 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Random;
+
+namespace HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms {
+  public class StochasticContext : BasicContext, IStochasticContext {
+    
+    [Storable]
+    private IValueParameter<IRandom> random;
+    public IRandom Random {
+      get { return random.Value; }
+      set { random.Value = value; }
+    }
+
+    [StorableConstructor]
+    protected StochasticContext(bool deserializing) : base(deserializing) { }
+    protected StochasticContext(StochasticContext original, Cloner cloner)
+    : base(original, cloner) {
+      random = cloner.Clone(original.random);
+    }
+    protected StochasticContext() : base() {
+      Parameters.Add(random = new ValueParameter<IRandom>("Random", new MersenneTwister()));
+    }
+    protected StochasticContext(string name) : base(name) {
+      Parameters.Add(random = new ValueParameter<IRandom>("Random", new MersenneTwister()));
+    }
+    protected StochasticContext(string name, ParameterCollection parameters) : base(name, parameters) {
+      Parameters.Add(random = new ValueParameter<IRandom>("Random", new MersenneTwister()));
+    }
+    protected StochasticContext(string name, string description) : base(name, description) {
+      Parameters.Add(random = new ValueParameter<IRandom>("Random", new MersenneTwister()));
+    }
+    protected StochasticContext(string name, string description, ParameterCollection parameters) : base(name, description, parameters) {
+      Parameters.Add(random = new ValueParameter<IRandom>("Random", new MersenneTwister()));
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new StochasticContext(this, cloner);
+    }
+  }
+}
Index: /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms/3.3/Infrastructure/Interfaces.cs
===================================================================
--- /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms/3.3/Infrastructure/Interfaces.cs	(revision 15562)
+++ /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms/3.3/Infrastructure/Interfaces.cs	(revision 15562)
@@ -0,0 +1,41 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2017 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using HeuristicLab.Core;
+
+namespace HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms {
+  public interface ISingleObjectiveSolutionScope<TSolution> : IScope {
+    TSolution Solution { get; set; }
+    double Fitness { get; set; }
+
+    void Adopt(ISingleObjectiveSolutionScope<TSolution> orphan);
+  }
+
+  public interface IContext : IExecutionContext {
+    new IExecutionContext Parent { get; set; }
+    int Iterations { get; set; }
+    int EvaluatedSolutions { get; set; }
+  }
+
+  public interface IStochasticContext : IContext {
+    IRandom Random { get; set; }
+  }
+}
Index: /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms/3.3/Infrastructure/SingleObjectiveSolutionScope.cs
===================================================================
--- /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms/3.3/Infrastructure/SingleObjectiveSolutionScope.cs	(revision 15562)
+++ /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms/3.3/Infrastructure/SingleObjectiveSolutionScope.cs	(revision 15562)
@@ -0,0 +1,142 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2017 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.Drawing;
+using HeuristicLab.Collections;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms {
+  [Item("Solution Scope", "Scope for an individual/solution of a single-objective single-encoded problem.")]
+  [StorableClass]
+  public sealed class SingleObjectiveSolutionScope<T> : NamedItem, ISingleObjectiveSolutionScope<T> where T : class, IItem {
+    public new static Image StaticItemImage {
+      get { return HeuristicLab.Common.Resources.VSImageLibrary.OrgChart; }
+    }
+
+    [Storable]
+    private IScope parent;
+    public IScope Parent {
+      get { return parent; }
+      set {
+        if (parent != value) {
+          parent = value;
+        }
+      }
+    }
+
+    [Storable]
+    private VariableCollection variables;
+    public VariableCollection Variables {
+      get { return variables; }
+    }
+
+    [Storable]
+    private ScopeList subScopes;
+    public ScopeList SubScopes {
+      get { return subScopes; }
+    }
+
+    [Storable]
+    private Variable solution;
+    public T Solution {
+      get { return (T)solution.Value; }
+      set { solution.Value = value; }
+    }
+
+    [Storable]
+    private Variable fitness;
+    public double Fitness {
+      get { return ((DoubleValue)fitness.Value).Value; }
+      set { ((DoubleValue)fitness.Value).Value = value; }
+    }
+
+    [StorableConstructor]
+    private SingleObjectiveSolutionScope(bool deserializing) : base(deserializing) { }
+    private SingleObjectiveSolutionScope(SingleObjectiveSolutionScope<T> original, Cloner cloner)
+      : base(original, cloner) {
+      // the parent will not be deep-cloned
+      parent = original.parent;
+      variables = cloner.Clone(original.variables);
+      subScopes = cloner.Clone(original.subScopes);
+      foreach (var child in SubScopes)
+        child.Parent = this;
+      solution = cloner.Clone(original.solution);
+      fitness = cloner.Clone(original.fitness);
+
+      RegisterSubScopesEvents();
+    }
+    public SingleObjectiveSolutionScope(T code, string codeName, double fitness, string fitnessName) {
+      this.solution = new Variable(codeName, code);
+      this.fitness = new Variable(fitnessName, new DoubleValue(fitness));
+      variables = new VariableCollection(2) { this.solution, this.fitness };
+      subScopes = new ScopeList(2);
+
+      RegisterSubScopesEvents();
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new SingleObjectiveSolutionScope<T>(this, cloner);
+    }
+
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() {
+      RegisterSubScopesEvents();
+    }
+
+    public void Clear() {
+      variables.Clear();
+      subScopes.Clear();
+    }
+
+    #region SubScopes Events
+    private void RegisterSubScopesEvents() {
+      if (subScopes != null) {
+        subScopes.ItemsAdded += SubScopes_ItemsAdded;
+        subScopes.ItemsRemoved += SubScopes_ItemsRemoved;
+        subScopes.ItemsReplaced += SubScopes_ItemsReplaced;
+        subScopes.CollectionReset += SubScopes_CollectionReset;
+      }
+    }
+    private void SubScopes_ItemsAdded(object sender, CollectionItemsChangedEventArgs<IndexedItem<IScope>> e) {
+      foreach (var item in e.Items) item.Value.Parent = this;
+    }
+    private void SubScopes_ItemsRemoved(object sender, CollectionItemsChangedEventArgs<IndexedItem<IScope>> e) {
+      foreach (var item in e.Items) item.Value.Parent = null;
+    }
+    private void SubScopes_ItemsReplaced(object sender, CollectionItemsChangedEventArgs<IndexedItem<IScope>> e) {
+      foreach (var oldItem in e.OldItems) oldItem.Value.Parent = null;
+      foreach (var item in e.Items) item.Value.Parent = this;
+    }
+    private void SubScopes_CollectionReset(object sender, CollectionItemsChangedEventArgs<IndexedItem<IScope>> e) {
+      foreach (var oldItem in e.OldItems) oldItem.Value.Parent = null;
+      foreach (var item in e.Items) item.Value.Parent = this;
+    }
+    #endregion
+
+    public void Adopt(ISingleObjectiveSolutionScope<T> orphan) {
+      Solution = orphan.Solution;
+      Fitness = orphan.Fitness;
+    }
+  }
+}
Index: anches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms/3.3/Interfaces.cs
===================================================================
--- /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms/3.3/Interfaces.cs	(revision 15561)
+++ 	(revision )
@@ -1,31 +1,0 @@
-﻿#region License Information
-/* HeuristicLab
- * Copyright (C) 2002-2017 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
- *
- * This file is part of HeuristicLab.
- *
- * HeuristicLab is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * HeuristicLab is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
- */
-#endregion
-
-using HeuristicLab.Core;
-
-namespace HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms {
-  public interface ISingleObjectiveSolutionScope<TSolution> : IScope {
-    TSolution Solution { get; set; }
-    double Fitness { get; set; }
-
-    void Adopt(ISingleObjectiveSolutionScope<TSolution> orphan);
-  }
-}
Index: /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms/3.3/LocalSearch/IteratedLS.cs
===================================================================
--- /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms/3.3/LocalSearch/IteratedLS.cs	(revision 15562)
+++ /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms/3.3/LocalSearch/IteratedLS.cs	(revision 15562)
@@ -0,0 +1,139 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2017 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Threading;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Encodings.IntegerVectorEncoding;
+using HeuristicLab.Optimization;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms.LocalSearch {
+  [Item("Iterated Local Search (GQAP)", "Iterated local search for the GQAP.")]
+  [Creatable(CreatableAttribute.Categories.SingleSolutionAlgorithms)]
+  [StorableClass]
+  public sealed class IteratedLS : ContextAlgorithm<LocalSearchContext> {
+
+    public override bool SupportsPause {
+      get { return true; }
+    }
+
+    public override Type ProblemType {
+      get { return typeof(GQAP); }
+    }
+
+    public new GQAP Problem {
+      get { return (GQAP)base.Problem; }
+      set { base.Problem = value; }
+    }
+
+    [StorableConstructor]
+    private IteratedLS(bool deserializing) : base(deserializing) { }
+    private IteratedLS(IteratedLS original, Cloner cloner)
+      : base(original, cloner) {
+    }
+    public IteratedLS() {
+
+      Problem = new GQAP();
+    }
+    
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new IteratedLS(this, cloner);
+    }
+
+    protected override void Initialize(CancellationToken token) {
+      base.Initialize(token);
+
+      Context.Problem = Problem;
+      Context.BestQuality = double.NaN;
+      Context.BestSolution = null;
+
+      var assign = GreedyRandomizedSolutionCreator.CreateSolution(Context.Random, Problem.ProblemInstance, 10, true, token);
+      var eval = Problem.ProblemInstance.Evaluate(assign);
+      var fit = Problem.ProblemInstance.ToSingleObjective(eval);
+      Context.EvaluatedSolutions++;
+
+      var candidate = new GQAPSolution(assign, eval);
+      var lsevaluations = 0;
+      OneOptLocalSearch.Apply(Context.Random, candidate, Problem.ProblemInstance, out lsevaluations);
+      Context.EvaluatedSolutions += lsevaluations;
+
+      Context.ReplaceIncumbent(Context.ToScope(candidate, fit));
+      Context.BestQuality = fit;
+      Context.BestSolution = (GQAPSolution)candidate.Clone();
+
+      Results.Add(new Result("Iterations", new IntValue(Context.Iterations)));
+      Results.Add(new Result("EvaluatedSolutions", new IntValue(Context.EvaluatedSolutions)));
+      Results.Add(new Result("BestQuality", new DoubleValue(Context.BestQuality)));
+      Results.Add(new Result("BestSolution", Context.BestSolution));
+
+      Context.RunOperator(Analyzer, Context.Scope, token);
+    }
+
+    protected override void Run(CancellationToken cancellationToken) {
+      while (!StoppingCriterion()) {
+        var lsevaluations = 0;
+        var candidate = (GQAPSolution)Context.Incumbent.Solution.Clone();
+        RandomWalk(Context.Random, candidate.Assignment, Problem.ProblemInstance.Capacities.Length, candidate.Assignment.Length);
+        candidate.Evaluation = Problem.ProblemInstance.Evaluate(candidate.Assignment);
+        Context.EvaluatedSolutions++;
+        OneOptLocalSearch.Apply(Context.Random, candidate, Problem.ProblemInstance, out lsevaluations);
+        Context.EvaluatedSolutions += lsevaluations;
+
+        var candidateFit = Problem.ProblemInstance.ToSingleObjective(candidate.Evaluation);
+        if (candidateFit < Context.Incumbent.Fitness) {
+          Context.ReplaceIncumbent(Context.ToScope(candidate, candidateFit));
+          Context.BestQuality = candidateFit;
+          Context.BestSolution = (GQAPSolution)candidate.Clone();
+        }
+
+        IResult result;
+        if (Results.TryGetValue("Iterations", out result))
+          ((IntValue)result.Value).Value = Context.Iterations;
+        else Results.Add(new Result("Iterations", new IntValue(Context.Iterations)));
+        if (Results.TryGetValue("EvaluatedSolutions", out result))
+          ((IntValue)result.Value).Value = Context.EvaluatedSolutions;
+        else Results.Add(new Result("EvaluatedSolutions", new IntValue(Context.EvaluatedSolutions)));
+        if (Results.TryGetValue("BestQuality", out result))
+          ((DoubleValue)result.Value).Value = Context.BestQuality;
+        else Results.Add(new Result("BestQuality", new DoubleValue(Context.BestQuality)));
+        if (Results.TryGetValue("BestSolution", out result))
+          result.Value = Context.BestSolution;
+        else Results.Add(new Result("BestSolution", Context.BestSolution));
+
+        Context.RunOperator(Analyzer, Context.Scope, cancellationToken);
+
+        Context.Iterations++;
+        if (cancellationToken.IsCancellationRequested) break;
+      }
+    }
+
+    private static void RandomWalk(IRandom random, IntegerVector assignment, int locations, int walkLength) {
+      for (int i = 0; i < walkLength; i++) {
+        var equipment = random.Next(assignment.Length);
+        assignment[equipment] = random.Next(locations);
+        if (random.NextDouble() < 1.0 / walkLength) break;
+      }
+    }
+  }
+}
Index: /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms/3.3/LocalSearch/LocalSearchContext.cs
===================================================================
--- /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms/3.3/LocalSearch/LocalSearchContext.cs	(revision 15562)
+++ /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms/3.3/LocalSearch/LocalSearchContext.cs	(revision 15562)
@@ -0,0 +1,70 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2017 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms.LocalSearch {
+  public sealed class LocalSearchContext : SingleObjectiveSingleSolutionContext<ISingleObjectiveSolutionScope<GQAPSolution>> {
+    [Storable]
+    private IValueParameter<GQAP> problem;
+    public GQAP Problem {
+      get { return problem.Value; }
+      set { problem.Value = value; }
+    }
+
+    [Storable]
+    private IValueParameter<GQAPSolution> bestSolution;
+    public GQAPSolution BestSolution {
+      get { return bestSolution.Value; }
+      set { bestSolution.Value = value; }
+    }
+    
+    [StorableConstructor]
+    private LocalSearchContext(bool deserializing) : base(deserializing) { }
+    private LocalSearchContext(LocalSearchContext original, Cloner cloner)
+    : base(original, cloner) {
+      problem = cloner.Clone(original.problem);
+      bestSolution = cloner.Clone(original.bestSolution);
+    }
+    public LocalSearchContext() {
+      Parameters.Add(problem = new ValueParameter<GQAP>("Problem"));
+      Parameters.Add(bestSolution = new ValueParameter<GQAPSolution>("BestFoundSolution"));
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new LocalSearchContext(this, cloner);
+    }
+
+    public ISingleObjectiveSolutionScope<GQAPSolution> ToScope(GQAPSolution code, double fitness = double.NaN) {
+      var name = Problem.Encoding.Name;
+      var scope = new SingleObjectiveSolutionScope<GQAPSolution>(code,
+        name + "Solution", fitness, Problem.Evaluator.QualityParameter.ActualName) {
+        Parent = Scope
+      };
+      scope.Variables.Add(new Variable(name, code.Assignment));
+      scope.Variables.Add(new Variable("Evaluation", code.Evaluation));
+      return scope;
+    }
+  }
+}
Index: /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms/3.3/LocalSearch/MultistartLS.cs
===================================================================
--- /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms/3.3/LocalSearch/MultistartLS.cs	(revision 15562)
+++ /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms/3.3/LocalSearch/MultistartLS.cs	(revision 15562)
@@ -0,0 +1,111 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2017 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Threading;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Encodings.IntegerVectorEncoding;
+using HeuristicLab.Optimization;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms.LocalSearch {
+  [Item("Multi-start Local Search (GQAP)", "Multi-start local search for the GQAP.")]
+  [Creatable(CreatableAttribute.Categories.SingleSolutionAlgorithms)]
+  [StorableClass]
+  public sealed class MultistartLS : ContextAlgorithm<LocalSearchContext> {
+
+    public override bool SupportsPause {
+      get { return true; }
+    }
+
+    public override Type ProblemType {
+      get { return typeof(GQAP); }
+    }
+
+    public new GQAP Problem {
+      get { return (GQAP)base.Problem; }
+      set { base.Problem = value; }
+    }
+
+    [StorableConstructor]
+    private MultistartLS(bool deserializing) : base(deserializing) { }
+    private MultistartLS(MultistartLS original, Cloner cloner)
+      : base(original, cloner) {
+    }
+    public MultistartLS() {
+
+      Problem = new GQAP();
+    }
+    
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new MultistartLS(this, cloner);
+    }
+
+    protected override void Initialize(CancellationToken token) {
+      base.Initialize(token);
+
+      Context.Problem = Problem;
+      Context.BestQuality = double.NaN;
+      Context.BestSolution = null;
+    }
+
+    protected override void Run(CancellationToken cancellationToken) {
+      while (!StoppingCriterion()) {
+        var lsevaluations = 0;
+        var assign = new IntegerVector(Problem.ProblemInstance.Demands.Length, Context.Random, 0, Problem.ProblemInstance.Capacities.Length);
+        var eval = Problem.ProblemInstance.Evaluate(assign);
+        Context.EvaluatedSolutions++;
+
+        var candidate = new GQAPSolution(assign, eval);
+        OneOptLocalSearch.Apply(Context.Random, candidate, Problem.ProblemInstance, out lsevaluations);
+        Context.EvaluatedSolutions += lsevaluations;
+
+        var candidateFit = Problem.ProblemInstance.ToSingleObjective(candidate.Evaluation);
+        if (Context.Incumbent == null || candidateFit < Context.Incumbent.Fitness) {
+          Context.ReplaceIncumbent(Context.ToScope(candidate, candidateFit));
+          Context.BestQuality = candidateFit;
+          Context.BestSolution = (GQAPSolution)candidate.Clone();
+        }
+
+        IResult result;
+        if (Results.TryGetValue("Iterations", out result))
+          ((IntValue)result.Value).Value = Context.Iterations;
+        else Results.Add(new Result("Iterations", new IntValue(Context.Iterations)));
+        if (Results.TryGetValue("EvaluatedSolutions", out result))
+          ((IntValue)result.Value).Value = Context.EvaluatedSolutions;
+        else Results.Add(new Result("EvaluatedSolutions", new IntValue(Context.EvaluatedSolutions)));
+        if (Results.TryGetValue("BestQuality", out result))
+          ((DoubleValue)result.Value).Value = Context.BestQuality;
+        else Results.Add(new Result("BestQuality", new DoubleValue(Context.BestQuality)));
+        if (Results.TryGetValue("BestSolution", out result))
+          result.Value = Context.BestSolution;
+        else Results.Add(new Result("BestSolution", Context.BestSolution));
+
+        Context.RunOperator(Analyzer, Context.Scope, cancellationToken);
+
+        Context.Iterations++;
+        if (cancellationToken.IsCancellationRequested) break;
+      }
+    }
+  }
+}
Index: anches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms/3.3/SingleObjectiveSolutionScope.cs
===================================================================
--- /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms/3.3/SingleObjectiveSolutionScope.cs	(revision 15561)
+++ 	(revision )
@@ -1,142 +1,0 @@
-﻿#region License Information
-/* HeuristicLab
- * Copyright (C) 2002-2017 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.Drawing;
-using HeuristicLab.Collections;
-using HeuristicLab.Common;
-using HeuristicLab.Core;
-using HeuristicLab.Data;
-using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
-
-namespace HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms {
-  [Item("Solution Scope", "Scope for an individual/solution of a single-objective single-encoded problem.")]
-  [StorableClass]
-  public sealed class SingleObjectiveSolutionScope<T> : NamedItem, ISingleObjectiveSolutionScope<T> where T : class, IItem {
-    public new static Image StaticItemImage {
-      get { return HeuristicLab.Common.Resources.VSImageLibrary.OrgChart; }
-    }
-
-    [Storable]
-    private IScope parent;
-    public IScope Parent {
-      get { return parent; }
-      set {
-        if (parent != value) {
-          parent = value;
-        }
-      }
-    }
-
-    [Storable]
-    private VariableCollection variables;
-    public VariableCollection Variables {
-      get { return variables; }
-    }
-
-    [Storable]
-    private ScopeList subScopes;
-    public ScopeList SubScopes {
-      get { return subScopes; }
-    }
-
-    [Storable]
-    private Variable solution;
-    public T Solution {
-      get { return (T)solution.Value; }
-      set { solution.Value = value; }
-    }
-
-    [Storable]
-    private Variable fitness;
-    public double Fitness {
-      get { return ((DoubleValue)fitness.Value).Value; }
-      set { ((DoubleValue)fitness.Value).Value = value; }
-    }
-
-    [StorableConstructor]
-    private SingleObjectiveSolutionScope(bool deserializing) : base(deserializing) { }
-    private SingleObjectiveSolutionScope(SingleObjectiveSolutionScope<T> original, Cloner cloner)
-      : base(original, cloner) {
-      // the parent will not be deep-cloned
-      parent = original.parent;
-      variables = cloner.Clone(original.variables);
-      subScopes = cloner.Clone(original.subScopes);
-      foreach (var child in SubScopes)
-        child.Parent = this;
-      solution = cloner.Clone(original.solution);
-      fitness = cloner.Clone(original.fitness);
-
-      RegisterSubScopesEvents();
-    }
-    public SingleObjectiveSolutionScope(T code, string codeName, double fitness, string fitnessName) {
-      this.solution = new Variable(codeName, code);
-      this.fitness = new Variable(fitnessName, new DoubleValue(fitness));
-      variables = new VariableCollection(2) { this.solution, this.fitness };
-      subScopes = new ScopeList(2);
-
-      RegisterSubScopesEvents();
-    }
-
-    public override IDeepCloneable Clone(Cloner cloner) {
-      return new SingleObjectiveSolutionScope<T>(this, cloner);
-    }
-
-    [StorableHook(HookType.AfterDeserialization)]
-    private void AfterDeserialization() {
-      RegisterSubScopesEvents();
-    }
-
-    public void Clear() {
-      variables.Clear();
-      subScopes.Clear();
-    }
-
-    #region SubScopes Events
-    private void RegisterSubScopesEvents() {
-      if (subScopes != null) {
-        subScopes.ItemsAdded += SubScopes_ItemsAdded;
-        subScopes.ItemsRemoved += SubScopes_ItemsRemoved;
-        subScopes.ItemsReplaced += SubScopes_ItemsReplaced;
-        subScopes.CollectionReset += SubScopes_CollectionReset;
-      }
-    }
-    private void SubScopes_ItemsAdded(object sender, CollectionItemsChangedEventArgs<IndexedItem<IScope>> e) {
-      foreach (var item in e.Items) item.Value.Parent = this;
-    }
-    private void SubScopes_ItemsRemoved(object sender, CollectionItemsChangedEventArgs<IndexedItem<IScope>> e) {
-      foreach (var item in e.Items) item.Value.Parent = null;
-    }
-    private void SubScopes_ItemsReplaced(object sender, CollectionItemsChangedEventArgs<IndexedItem<IScope>> e) {
-      foreach (var oldItem in e.OldItems) oldItem.Value.Parent = null;
-      foreach (var item in e.Items) item.Value.Parent = this;
-    }
-    private void SubScopes_CollectionReset(object sender, CollectionItemsChangedEventArgs<IndexedItem<IScope>> e) {
-      foreach (var oldItem in e.OldItems) oldItem.Value.Parent = null;
-      foreach (var item in e.Items) item.Value.Parent = this;
-    }
-    #endregion
-
-    public void Adopt(ISingleObjectiveSolutionScope<T> orphan) {
-      Solution = orphan.Solution;
-      Fitness = orphan.Fitness;
-    }
-  }
-}
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 15561)
+++ /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment/3.3/HeuristicLab.Problems.GeneralizedQuadraticAssignment-3.3.csproj	(revision 15562)
@@ -104,5 +104,7 @@
     <Compile Include="GQAPInstance.cs" />
     <Compile Include="Interfaces\Parameter\IAssignmentAwareGQAPOperator.cs" />
+    <Compile Include="Moves\ExhaustiveOneMoveGenerator.cs" />
     <Compile Include="Operators\Crossovers\CordeauCrossover.cs" />
+    <Compile Include="Operators\LocalImprovers\OneOptLocalSearch.cs" />
     <Compile Include="SolutionCreators\SlackMinimizationSolutionCreator.cs" />
     <Compile Include="SolutionCreators\RandomButFeasibleSolutionCreator.cs" />
Index: /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment/3.3/Interfaces/Operator/IGQAPLocalImprovementOperator.cs
===================================================================
--- /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment/3.3/Interfaces/Operator/IGQAPLocalImprovementOperator.cs	(revision 15561)
+++ /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment/3.3/Interfaces/Operator/IGQAPLocalImprovementOperator.cs	(revision 15562)
@@ -21,5 +21,4 @@
 
 using HeuristicLab.Core;
-using HeuristicLab.Data;
 using HeuristicLab.Encodings.IntegerVectorEncoding;
 using HeuristicLab.Optimization;
@@ -27,5 +26,4 @@
 namespace HeuristicLab.Problems.GeneralizedQuadraticAssignment {
   public interface IGQAPLocalImprovementOperator : ILocalImprovementAlgorithmOperator {
-    IValueLookupParameter<IntValue> MaximumCandidateListSizeParameter { get; }
     ILookupParameter<IntegerVector> AssignmentParameter { get; }
   }
Index: /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment/3.3/Moves/ExhaustiveOneMoveGenerator.cs
===================================================================
--- /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment/3.3/Moves/ExhaustiveOneMoveGenerator.cs	(revision 15562)
+++ /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment/3.3/Moves/ExhaustiveOneMoveGenerator.cs	(revision 15562)
@@ -0,0 +1,90 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2017 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Encodings.IntegerVectorEncoding;
+using HeuristicLab.Optimization;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Random;
+
+namespace HeuristicLab.Problems.GeneralizedQuadraticAssignment {
+  [Item("Exhaustive 1-Move MoveGenerator", "Exhaustively generates all possible 1-moves.")]
+  [StorableClass]
+  public class ExhaustiveOneMoveGenerator : GQAPNMoveGenerator, IStochasticOperator, IExhaustiveMoveGenerator {
+    
+    public ILookupParameter<IRandom> RandomParameter {
+      get { return (ILookupParameter<IRandom>)Parameters["Random"]; }
+    }
+
+    [StorableConstructor]
+    protected ExhaustiveOneMoveGenerator(bool deserializing) : base(deserializing) { }
+    protected ExhaustiveOneMoveGenerator(ExhaustiveOneMoveGenerator original, Cloner cloner) : base(original, cloner) { }
+    public ExhaustiveOneMoveGenerator()
+      : base() {
+      Parameters.Add(new LookupParameter<IRandom>("Random", "The random number generator that should be used."));
+      NParameter.Value.Value = 1;
+      NParameter.Hidden = true;
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new ExhaustiveOneMoveGenerator(this, cloner);
+    }
+
+    public static IEnumerable<NMove> Generate(IntegerVector assignment, GQAPInstance problemInstance) {
+      var equipments = problemInstance.Demands.Length;
+      var locations = problemInstance.Capacities.Length;
+      var tmp = new int[equipments];
+      for (var e = 0; e < equipments; e++) {
+        var indices = new List<int> { e };
+        for (var l = 0; l < locations; l++) {
+          if (assignment[e] == l) continue;
+          var reassign = (int[])tmp.Clone();
+          reassign[e] = l + 1;
+          yield return new NMove(reassign, indices);
+        }
+      }
+    }
+
+    public static IEnumerable<NMove> GenerateAllNxM(GQAPInstance problemInstance) {
+      var equipments = problemInstance.Demands.Length;
+      var locations = problemInstance.Capacities.Length;
+      var tmp = new int[equipments];
+      for (var e = 0; e < equipments; e++) {
+        var indices = new List<int> { e };
+        for (var l = 0; l < locations; l++) {
+          var reassign = (int[])tmp.Clone();
+          reassign[e] = l + 1;
+          yield return new NMove(reassign, indices);
+        }
+      }
+    }
+
+    public override IEnumerable<NMove> GenerateMoves(IntegerVector assignment, int n, GQAPInstance problemInstance) {
+      if (n != 1) throw new ArgumentException("N must be equal to 1 for the exhaustive 1-move generator.");
+      var random = RandomParameter.ActualValue;
+      return Generate(assignment, problemInstance).Shuffle(random);
+    }
+  }
+}
Index: /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment/3.3/Operators/LocalImprovers/OneOptLocalSearch.cs
===================================================================
--- /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment/3.3/Operators/LocalImprovers/OneOptLocalSearch.cs	(revision 15562)
+++ /branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment/3.3/Operators/LocalImprovers/OneOptLocalSearch.cs	(revision 15562)
@@ -0,0 +1,173 @@
+﻿
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2017 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Encodings.IntegerVectorEncoding;
+using HeuristicLab.Operators;
+using HeuristicLab.Optimization;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Random;
+
+namespace HeuristicLab.Problems.GeneralizedQuadraticAssignment {
+  [Item("1-opt LocalSearch", "A simple exhaustive 1-change local search.")]
+  [StorableClass]
+  public class OneOptLocalSearch : SingleSuccessorOperator, IProblemInstanceAwareGQAPOperator,
+    IQualityAwareGQAPOperator, IGQAPLocalImprovementOperator, IAssignmentAwareGQAPOperator, IStochasticOperator {
+    public IProblem Problem { get; set; }
+    public Type ProblemType {
+      get { return typeof(GQAP); }
+    }
+
+    public ILookupParameter<GQAPInstance> ProblemInstanceParameter {
+      get { return (ILookupParameter<GQAPInstance>)Parameters["ProblemInstance"]; }
+    }
+    public ILookupParameter<IntegerVector> AssignmentParameter {
+      get { return (ILookupParameter<IntegerVector>)Parameters["Assignment"]; }
+    }
+    public ILookupParameter<DoubleValue> QualityParameter {
+      get { return (ILookupParameter<DoubleValue>)Parameters["Quality"]; }
+    }
+    public ILookupParameter<Evaluation> EvaluationParameter {
+      get { return (ILookupParameter<Evaluation>)Parameters["Evaluation"]; }
+    }
+    public IValueLookupParameter<IntValue> MaximumIterationsParameter {
+      get { return (IValueLookupParameter<IntValue>)Parameters["MaximumIterations"]; }
+    }
+    public ILookupParameter<IntValue> EvaluatedSolutionsParameter {
+      get { return (ILookupParameter<IntValue>)Parameters["EvaluatedSolutions"]; }
+    }
+    public ILookupParameter<IRandom> RandomParameter {
+      get { return (ILookupParameter<IRandom>)Parameters["Random"]; }
+    }
+    public ILookupParameter<ResultCollection> ResultsParameter {
+      get { return (ILookupParameter<ResultCollection>)Parameters["Results"]; }
+    }
+
+    [StorableConstructor]
+    protected OneOptLocalSearch(bool deserializing) : base(deserializing) { }
+    protected OneOptLocalSearch(OneOptLocalSearch original, Cloner cloner) : base(original, cloner) { }
+    public OneOptLocalSearch()
+      : base() {
+      Parameters.Add(new LookupParameter<GQAPInstance>("ProblemInstance", GQAP.ProblemInstanceDescription));
+      Parameters.Add(new LookupParameter<IntegerVector>("Assignment", GQAPSolutionCreator.AssignmentDescription));
+      Parameters.Add(new LookupParameter<DoubleValue>("Quality", ""));
+      Parameters.Add(new LookupParameter<Evaluation>("Evaluation", GQAP.EvaluationDescription));
+      Parameters.Add(new ValueLookupParameter<IntValue>("MaximumIterations", "This parameter is ignored by the operator.") { Hidden = true });
+      Parameters.Add(new LookupParameter<IntValue>("EvaluatedSolutions", "The number of evaluated solution equivalents."));
+      Parameters.Add(new LookupParameter<IRandom>("Random", "The random number generator to use."));
+      Parameters.Add(new LookupParameter<ResultCollection>("Results", "The result collection that stores the results."));
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new OneOptLocalSearch(this, cloner);
+    }
+
+    public static void Apply(IRandom random, GQAPSolution sol,
+      GQAPInstance problemInstance, out int evaluatedSolutions) {
+      var fit = problemInstance.ToSingleObjective(sol.Evaluation);
+      var eval = sol.Evaluation;
+      Apply(random, sol.Assignment, ref fit, ref eval, problemInstance, out evaluatedSolutions);
+      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>
+    /// <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,
+      GQAPInstance problemInstance, out int evaluatedSolutions) {
+      evaluatedSolutions = 0;
+      var capacities = problemInstance.Capacities;
+      var demands = problemInstance.Demands;
+      var evaluations = 0.0;
+      var deltaEvaluationFactor = 1.0 / assignment.Length;
+      var change = true;
+      var moves = ExhaustiveOneMoveGenerator.GenerateAllNxM(problemInstance).ToList();
+      var slack = evaluation.Slack.ToList();
+      while (change) {
+        change = false;
+        var feasible = evaluation.IsFeasible;
+        foreach (var move in moves
+            .Where(x => {
+              var equip = x.Indices[0];
+              var assignTo = x.Reassignments[equip] - 1;
+              if (assignTo == assignment[equip]) return false;
+              var dem = problemInstance.Demands[equip];
+              if (feasible) return slack[assignTo] >= dem;
+              return slack[assignTo] - dem > slack[assignment[equip]];
+            })
+            .Shuffle(random)) {
+          var moveEval = GQAPNMoveEvaluator.Evaluate(move, assignment, evaluation, problemInstance);
+          evaluations += deltaEvaluationFactor;
+          var moveQuality = problemInstance.ToSingleObjective(moveEval);
+          if (moveQuality < quality) {
+            NMoveMaker.Apply(assignment, move);
+            quality = moveQuality;
+            evaluation = moveEval;
+            change = true;
+            break;
+          }
+        }
+      }
+      evaluatedSolutions += (int)Math.Ceiling(evaluations);
+    }
+
+    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);
+    }
+
+    public override IOperation Apply() {
+      var evaluation = EvaluationParameter.ActualValue;
+      var quality = QualityParameter.ActualValue;
+      var fit = quality.Value;
+      var evaluatedSolutions = 0;
+
+      Apply(RandomParameter.ActualValue,
+        AssignmentParameter.ActualValue,
+        ref fit,
+        ref evaluation,
+        ProblemInstanceParameter.ActualValue,
+        out evaluatedSolutions);
+
+      EvaluationParameter.ActualValue = evaluation;
+      quality.Value = fit;
+      EvaluatedSolutionsParameter.ActualValue.Value += evaluatedSolutions;
+      return base.Apply();
+    }
+  }
+}
Index: /branches/GeneralizedQAP/UnitTests/ApproximateLocalSearchTest.cs
===================================================================
--- /branches/GeneralizedQAP/UnitTests/ApproximateLocalSearchTest.cs	(revision 15561)
+++ /branches/GeneralizedQAP/UnitTests/ApproximateLocalSearchTest.cs	(revision 15562)
@@ -13,21 +13,21 @@
     [TestMethod]
     public void ApproximateLocalSearchApplyTest() {
-      CollectionAssert.AreEqual(new [] { 3, 2, 1, 1, 3, 0, 1, 0, 3, 0 }, assignment.ToArray());
+      CollectionAssert.AreEqual(new [] { 2, 0, 1, 1, 2, 3, 0, 3, 0, 0 }, assignment.ToArray());
 
       var evaluation = instance.Evaluate(assignment);
-      Assert.AreEqual(4091776, evaluation.FlowCosts);
-      Assert.AreEqual(42, evaluation.InstallationCosts);
+      Assert.AreEqual(3985258, evaluation.FlowCosts);
+      Assert.AreEqual(30, evaluation.InstallationCosts);
       Assert.AreEqual(0, evaluation.ExcessDemand);
 
       var quality = instance.ToSingleObjective(evaluation);
-      Assert.AreEqual(15903846.056964701, quality, 1e-9);
+      Assert.AreEqual(15489822.781533258, quality, 1e-9);
 
       var evaluatedSolutions = 0;
       ApproximateLocalSearch.Apply(random, assignment, ref quality,
-        ref evaluation, 10, 0.5, 1000, instance,
+        ref evaluation, 10, 0.5, 100, instance,
         out evaluatedSolutions);
-      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);
+      Assert.AreEqual(61, evaluatedSolutions);
+      CollectionAssert.AreEqual(new[] { 2, 0, 0, 0, 2, 1, 0, 3, 0, 0 }, assignment.ToArray());
+      Assert.AreEqual(10167912.633734789, quality, 1e-9);
     }
 
Index: /branches/GeneralizedQAP/UnitTests/GRASPTest.cs
===================================================================
--- /branches/GeneralizedQAP/UnitTests/GRASPTest.cs	(revision 15562)
+++ /branches/GeneralizedQAP/UnitTests/GRASPTest.cs	(revision 15562)
@@ -0,0 +1,64 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2017 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 System.Linq;
+using HeuristicLab.Data;
+using HeuristicLab.Problems.GeneralizedQuadraticAssignment;
+using HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms.GRASP;
+using HeuristicLab.Problems.Instances.CordeauGQAP;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+namespace UnitTests {
+  [TestClass]
+  public class GRASPTest {
+    [TestMethod]
+    public void TestGraspSolveInstance() {
+      var provider = new CordeauGQAPInstanceProvider();
+      var instance = provider.LoadData(provider.GetDataDescriptors().Single(x => x.Name == "20-15-35"));
+      var gqap = new GQAP();
+      gqap.Load(instance);
+
+      var bestQuality = new List<double>();
+      for (var i = 0; i < 5; i++) {
+        var grasp = new GRASP() {
+          Problem = gqap,
+          CandidateSizeFactor = 0.5,
+          EliteSetSize = 10,
+          MaximumCandidateListSize = 10,
+          MaximumIterations = 200,
+          MaximumLocalSearchIterations = 100,
+          MinimumDifference = 4,
+          MinimumEliteSetSize = 2,
+          OneMoveProbability = 0.5,
+          SetSeedRandomly = false,
+          Seed = i
+        };
+        grasp.Start();
+        Assert.IsTrue(grasp.ExecutionTime.TotalSeconds < 6);
+        bestQuality.Add(((DoubleValue)grasp.Results["BestQuality"].Value).Value);
+      }
+      // at least one in 10 runs should find the global optimum
+      Assert.IsTrue(bestQuality.Count(x => x == gqap.BestKnownQuality) > 0, string.Join("; ", bestQuality));
+      CollectionAssert.AreEqual(new double[] { 1471896, 1506076, 1509356, 1511402, 1471896 }, bestQuality);
+    }
+  }
+}
Index: /branches/GeneralizedQAP/UnitTests/UnitTests.csproj
===================================================================
--- /branches/GeneralizedQAP/UnitTests/UnitTests.csproj	(revision 15561)
+++ /branches/GeneralizedQAP/UnitTests/UnitTests.csproj	(revision 15562)
@@ -110,4 +110,5 @@
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="ApproximateLocalSearchTest.cs" />
+    <Compile Include="GRASPTest.cs" />
   </ItemGroup>
   <ItemGroup>
@@ -115,4 +116,8 @@
       <Project>{14ab8d24-25bc-400c-a846-4627aa945192}</Project>
       <Name>HeuristicLab.Optimization-3.3</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms\3.3\HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms-3.3.csproj">
+      <Project>{577239EC-7D7F-4505-A0A4-572E34010DBA}</Project>
+      <Name>HeuristicLab.Problems.GeneralizedQuadraticAssignment.Algorithms-3.3</Name>
     </ProjectReference>
     <ProjectReference Include="..\HeuristicLab.Problems.GeneralizedQuadraticAssignment\3.3\HeuristicLab.Problems.GeneralizedQuadraticAssignment-3.3.csproj">
