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 15558)
+++ 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 15558)
+++ 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();
+    }
+  }
+}
