Index: trunk/sources/HeuristicLab.Encodings.PermutationEncoding/3.3/Moves/ThreeOpt/ExhaustiveInsertionMoveGenerator.cs
===================================================================
--- trunk/sources/HeuristicLab.Encodings.PermutationEncoding/3.3/Moves/ThreeOpt/ExhaustiveInsertionMoveGenerator.cs	(revision 8335)
+++ trunk/sources/HeuristicLab.Encodings.PermutationEncoding/3.3/Moves/ThreeOpt/ExhaustiveInsertionMoveGenerator.cs	(revision 8338)
@@ -21,4 +21,6 @@
 
 using System;
+using System.Collections.Generic;
+using System.Linq;
 using HeuristicLab.Common;
 using HeuristicLab.Core;
@@ -39,33 +41,31 @@
     }
 
-    public static TranslocationMove[] Apply(Permutation permutation) {
+    public static IEnumerable<TranslocationMove> Generate(Permutation permutation) {
       int length = permutation.Length;
       if (length == 1) throw new ArgumentException("ExhaustiveInsertionMoveGenerator: There cannot be an insertion move given a permutation of length 1.", "permutation");
-      TranslocationMove[] moves = null;
-      int count = 0;
+
       if (permutation.PermutationType == PermutationTypes.Absolute) {
-        moves = new TranslocationMove[length * (length - 1)];
         for (int i = 0; i < length; i++) {
           for (int j = 1; j <= length - 1; j++) {
-            moves[count++] = new TranslocationMove(i, i, (i + j) % length);
+            yield return new TranslocationMove(i, i, (i + j) % length);
           }
         }
       } else {
         if (length > 2) {
-          moves = new TranslocationMove[length * (length - 1) - 2];
           for (int i = 0; i < length; i++) {
             for (int j = 1; j <= length - 1; j++) {
               if (i == 0 && j == length - 1
                 || i == length - 1 && j == 1) continue;
-              moves[count++] = new TranslocationMove(i, i, (i + j) % length);
+              yield return new TranslocationMove(i, i, (i + j) % length);
             }
           }
         } else { // doesn't make sense, but just create a dummy move to not crash the algorithms
-          moves = new TranslocationMove[1];
-          moves[0] = new TranslocationMove(0, 0, 1);
+          yield return new TranslocationMove(0, 0, 1);
         }
       }
-      System.Diagnostics.Debug.Assert(count == moves.Length);
-      return moves;
+    }
+
+    public static TranslocationMove[] Apply(Permutation permutation) {
+      return Generate(permutation).ToArray();
     }
 
Index: trunk/sources/HeuristicLab.Encodings.PermutationEncoding/3.3/Moves/TwoOpt/ExhaustiveInversionMoveGenerator.cs
===================================================================
--- trunk/sources/HeuristicLab.Encodings.PermutationEncoding/3.3/Moves/TwoOpt/ExhaustiveInversionMoveGenerator.cs	(revision 8335)
+++ trunk/sources/HeuristicLab.Encodings.PermutationEncoding/3.3/Moves/TwoOpt/ExhaustiveInversionMoveGenerator.cs	(revision 8338)
@@ -21,4 +21,6 @@
 
 using System;
+using System.Collections.Generic;
+using System.Linq;
 using HeuristicLab.Common;
 using HeuristicLab.Core;
@@ -40,32 +42,30 @@
 
     public static InversionMove[] Apply(Permutation permutation) {
+      return Generate(permutation).ToArray();
+    }
+
+    public static IEnumerable<InversionMove> Generate(Permutation permutation) {
       int length = permutation.Length;
       if (length == 1) throw new ArgumentException("ExhaustiveInversionMoveGenerator: There cannot be an inversion move given a permutation of length 1.", "permutation");
       int totalMoves = (length) * (length - 1) / 2;
-      InversionMove[] moves = null;
-      int count = 0;
 
       if (permutation.PermutationType == PermutationTypes.RelativeUndirected) {
         if (totalMoves - 3 > 0) {
-          moves = new InversionMove[totalMoves - 3];
           for (int i = 0; i < length - 1; i++) {
             for (int j = i + 1; j < length; j++) {
               // doesn't make sense to inverse the whole permutation or the whole but one in case of relative undirected permutations
               if (j - i >= length - 2) continue;
-              moves[count++] = new InversionMove(i, j);
+              yield return new InversionMove(i, j);
             }
           }
         } else { // when length is 3 or less, there's actually no difference, but for the sake of not crashing the algorithm create a dummy move
-          moves = new InversionMove[1];
-          moves[0] = new InversionMove(0, 1);
+          yield return new InversionMove(0, 1);
         }
       } else {
-        moves = new InversionMove[totalMoves];
         for (int i = 0; i < length - 1; i++)
           for (int j = i + 1; j < length; j++) {
-            moves[count++] = new InversionMove(i, j);
+            yield return new InversionMove(i, j);
           }
       }
-      return moves;
     }
 
Index: trunk/sources/HeuristicLab.Problems.QuadraticAssignment/3.3/HeuristicLab.Problems.QuadraticAssignment-3.3.csproj
===================================================================
--- trunk/sources/HeuristicLab.Problems.QuadraticAssignment/3.3/HeuristicLab.Problems.QuadraticAssignment-3.3.csproj	(revision 8335)
+++ trunk/sources/HeuristicLab.Problems.QuadraticAssignment/3.3/HeuristicLab.Problems.QuadraticAssignment-3.3.csproj	(revision 8338)
@@ -125,5 +125,8 @@
     <Compile Include="Interfaces\IQAPEvaluator.cs" />
     <Compile Include="Interfaces\IQAPMoveEvaluator.cs" />
+    <Compile Include="LocalImprovement\QAPExhaustiveInsertionLocalImprovement.cs" />
+    <Compile Include="LocalImprovement\QAPStochasticScrambleLocalImprovement.cs" />
     <Compile Include="LocalImprovement\QAPExhaustiveSwap2LocalImprovement.cs" />
+    <Compile Include="LocalImprovement\QAPExhaustiveInversionLocalImprovement.cs" />
     <Compile Include="QAPAssignment.cs" />
     <Compile Include="QAPPermutationProximityCalculator.cs" />
Index: trunk/sources/HeuristicLab.Problems.QuadraticAssignment/3.3/LocalImprovement/QAPExhaustiveInsertionLocalImprovement.cs
===================================================================
--- trunk/sources/HeuristicLab.Problems.QuadraticAssignment/3.3/LocalImprovement/QAPExhaustiveInsertionLocalImprovement.cs	(revision 8338)
+++ trunk/sources/HeuristicLab.Problems.QuadraticAssignment/3.3/LocalImprovement/QAPExhaustiveInsertionLocalImprovement.cs	(revision 8338)
@@ -0,0 +1,152 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Threading;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Encodings.PermutationEncoding;
+using HeuristicLab.Operators;
+using HeuristicLab.Optimization;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.QuadraticAssignment {
+  [Item("QAPExhaustiveInsertionLocalImprovement", "Takes a solution and finds the local optimum with respect to the insertion neighborhood by decending along the steepest gradient.")]
+  [StorableClass]
+  public class QAPExhaustiveInsertionLocalImprovement : SingleSuccessorOperator, ILocalImprovementOperator {
+
+    public Type ProblemType {
+      get { return typeof(QuadraticAssignmentProblem); }
+    }
+
+    [Storable]
+    private QuadraticAssignmentProblem problem;
+    public IProblem Problem {
+      get { return problem; }
+      set { problem = (QuadraticAssignmentProblem)value; }
+    }
+
+    public ILookupParameter<IntValue> LocalIterationsParameter {
+      get { return (ILookupParameter<IntValue>)Parameters["LocalIterations"]; }
+    }
+
+    public IValueLookupParameter<IntValue> MaximumIterationsParameter {
+      get { return (IValueLookupParameter<IntValue>)Parameters["MaximumIterations"]; }
+    }
+
+    public ILookupParameter<IntValue> EvaluatedSolutionsParameter {
+      get { return (ILookupParameter<IntValue>)Parameters["EvaluatedSolutions"]; }
+    }
+
+    public ILookupParameter<ResultCollection> ResultsParameter {
+      get { return (ILookupParameter<ResultCollection>)Parameters["Results"]; }
+    }
+
+    public ILookupParameter<Permutation> AssignmentParameter {
+      get { return (ILookupParameter<Permutation>)Parameters["Assignment"]; }
+    }
+
+    public ILookupParameter<DoubleValue> QualityParameter {
+      get { return (ILookupParameter<DoubleValue>)Parameters["Quality"]; }
+    }
+
+    public ILookupParameter<BoolValue> MaximizationParameter {
+      get { return (ILookupParameter<BoolValue>)Parameters["Maximization"]; }
+    }
+
+    public ILookupParameter<DoubleMatrix> WeightsParameter {
+      get { return (ILookupParameter<DoubleMatrix>)Parameters["Weights"]; }
+    }
+
+    public ILookupParameter<DoubleMatrix> DistancesParameter {
+      get { return (ILookupParameter<DoubleMatrix>)Parameters["Distances"]; }
+    }
+
+    [StorableConstructor]
+    protected QAPExhaustiveInsertionLocalImprovement(bool deserializing) : base(deserializing) { }
+    protected QAPExhaustiveInsertionLocalImprovement(QAPExhaustiveInsertionLocalImprovement original, Cloner cloner)
+      : base(original, cloner) {
+      this.problem = cloner.Clone(original.problem);
+    }
+    public QAPExhaustiveInsertionLocalImprovement()
+      : base() {
+      Parameters.Add(new LookupParameter<IntValue>("LocalIterations", "The number of iterations that have already been performed."));
+      Parameters.Add(new ValueLookupParameter<IntValue>("MaximumIterations", "The maximum amount of iterations that should be performed (note that this operator will abort earlier when a local optimum is reached).", new IntValue(10000)));
+      Parameters.Add(new LookupParameter<IntValue>("EvaluatedSolutions", "The amount of evaluated solutions (here a move is counted only as 4/n evaluated solutions with n being the length of the permutation)."));
+      Parameters.Add(new LookupParameter<ResultCollection>("Results", "The collection where to store results."));
+      Parameters.Add(new LookupParameter<Permutation>("Assignment", "The permutation that is to be locally optimized."));
+      Parameters.Add(new LookupParameter<DoubleValue>("Quality", "The quality value of the assignment."));
+      Parameters.Add(new LookupParameter<BoolValue>("Maximization", "True if the problem should be maximized or minimized."));
+      Parameters.Add(new LookupParameter<DoubleMatrix>("Weights", "The weights matrix."));
+      Parameters.Add(new LookupParameter<DoubleMatrix>("Distances", "The distances matrix."));
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new QAPExhaustiveInsertionLocalImprovement(this, cloner);
+    }
+
+    public static void Improve(Permutation assignment, DoubleMatrix weights, DoubleMatrix distances, DoubleValue quality, IntValue localIterations, IntValue evaluatedSolutions, bool maximization, int maxIterations, CancellationToken cancellation) {
+      for (int i = localIterations.Value; i < maxIterations; i++) {
+        TranslocationMove bestMove = null;
+        double bestQuality = 0; // we have to make an improvement, so 0 is the baseline
+        double evaluations = 0.0;
+        foreach (var move in ExhaustiveInsertionMoveGenerator.Generate(assignment)) {
+          double moveQuality = QAPTranslocationMoveEvaluator.Apply(assignment, move, weights, distances);
+          int min = Math.Min(move.Index1, move.Index3);
+          int max = Math.Max(move.Index2, move.Index3 + (move.Index2 - move.Index1));
+          evaluations += 2.0 * (max - min + 1) / assignment.Length
+            + 4.0 * (assignment.Length - (max - min + 1)) / assignment.Length;
+          if (maximization && moveQuality > bestQuality
+            || !maximization && moveQuality < bestQuality) {
+            bestQuality = moveQuality;
+            bestMove = move;
+          }
+        }
+        evaluatedSolutions.Value += (int)Math.Ceiling(evaluations);
+        if (bestMove == null) break;
+        TranslocationManipulator.Apply(assignment, bestMove.Index1, bestMove.Index2, bestMove.Index3);
+        quality.Value += bestQuality;
+        localIterations.Value++;
+        cancellation.ThrowIfCancellationRequested();
+      }
+    }
+
+    public override IOperation Apply() {
+      var maxIterations = MaximumIterationsParameter.ActualValue.Value;
+      var assignment = AssignmentParameter.ActualValue;
+      var maximization = MaximizationParameter.ActualValue.Value;
+      var weights = WeightsParameter.ActualValue;
+      var distances = DistancesParameter.ActualValue;
+      var quality = QualityParameter.ActualValue;
+      var localIterations = LocalIterationsParameter.ActualValue;
+      var evaluations = EvaluatedSolutionsParameter.ActualValue;
+      if (localIterations == null) {
+        localIterations = new IntValue(0);
+        LocalIterationsParameter.ActualValue = localIterations;
+      }
+
+      Improve(assignment, weights, distances, quality, localIterations, evaluations, maximization, maxIterations, CancellationToken);
+      return base.Apply();
+    }
+  }
+}
Index: trunk/sources/HeuristicLab.Problems.QuadraticAssignment/3.3/LocalImprovement/QAPExhaustiveInversionLocalImprovement.cs
===================================================================
--- trunk/sources/HeuristicLab.Problems.QuadraticAssignment/3.3/LocalImprovement/QAPExhaustiveInversionLocalImprovement.cs	(revision 8338)
+++ trunk/sources/HeuristicLab.Problems.QuadraticAssignment/3.3/LocalImprovement/QAPExhaustiveInversionLocalImprovement.cs	(revision 8338)
@@ -0,0 +1,149 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Threading;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Encodings.PermutationEncoding;
+using HeuristicLab.Operators;
+using HeuristicLab.Optimization;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.QuadraticAssignment {
+  [Item("QAPExhaustiveInversionLocalImprovement", "Takes a solution and finds the local optimum with respect to the inversion neighborhood by decending along the steepest gradient.")]
+  [StorableClass]
+  public class QAPExhaustiveInversionLocalImprovement : SingleSuccessorOperator, ILocalImprovementOperator {
+
+    public Type ProblemType {
+      get { return typeof(QuadraticAssignmentProblem); }
+    }
+
+    [Storable]
+    private QuadraticAssignmentProblem problem;
+    public IProblem Problem {
+      get { return problem; }
+      set { problem = (QuadraticAssignmentProblem)value; }
+    }
+
+    public ILookupParameter<IntValue> LocalIterationsParameter {
+      get { return (ILookupParameter<IntValue>)Parameters["LocalIterations"]; }
+    }
+
+    public IValueLookupParameter<IntValue> MaximumIterationsParameter {
+      get { return (IValueLookupParameter<IntValue>)Parameters["MaximumIterations"]; }
+    }
+
+    public ILookupParameter<IntValue> EvaluatedSolutionsParameter {
+      get { return (ILookupParameter<IntValue>)Parameters["EvaluatedSolutions"]; }
+    }
+
+    public ILookupParameter<ResultCollection> ResultsParameter {
+      get { return (ILookupParameter<ResultCollection>)Parameters["Results"]; }
+    }
+
+    public ILookupParameter<Permutation> AssignmentParameter {
+      get { return (ILookupParameter<Permutation>)Parameters["Assignment"]; }
+    }
+
+    public ILookupParameter<DoubleValue> QualityParameter {
+      get { return (ILookupParameter<DoubleValue>)Parameters["Quality"]; }
+    }
+
+    public ILookupParameter<BoolValue> MaximizationParameter {
+      get { return (ILookupParameter<BoolValue>)Parameters["Maximization"]; }
+    }
+
+    public ILookupParameter<DoubleMatrix> WeightsParameter {
+      get { return (ILookupParameter<DoubleMatrix>)Parameters["Weights"]; }
+    }
+
+    public ILookupParameter<DoubleMatrix> DistancesParameter {
+      get { return (ILookupParameter<DoubleMatrix>)Parameters["Distances"]; }
+    }
+
+    [StorableConstructor]
+    protected QAPExhaustiveInversionLocalImprovement(bool deserializing) : base(deserializing) { }
+    protected QAPExhaustiveInversionLocalImprovement(QAPExhaustiveInversionLocalImprovement original, Cloner cloner)
+      : base(original, cloner) {
+      this.problem = cloner.Clone(original.problem);
+    }
+    public QAPExhaustiveInversionLocalImprovement()
+      : base() {
+      Parameters.Add(new LookupParameter<IntValue>("LocalIterations", "The number of iterations that have already been performed."));
+      Parameters.Add(new ValueLookupParameter<IntValue>("MaximumIterations", "The maximum amount of iterations that should be performed (note that this operator will abort earlier when a local optimum is reached).", new IntValue(10000)));
+      Parameters.Add(new LookupParameter<IntValue>("EvaluatedSolutions", "The amount of evaluated solutions (here a move is counted only as 4/n evaluated solutions with n being the length of the permutation)."));
+      Parameters.Add(new LookupParameter<ResultCollection>("Results", "The collection where to store results."));
+      Parameters.Add(new LookupParameter<Permutation>("Assignment", "The permutation that is to be locally optimized."));
+      Parameters.Add(new LookupParameter<DoubleValue>("Quality", "The quality value of the assignment."));
+      Parameters.Add(new LookupParameter<BoolValue>("Maximization", "True if the problem should be maximized or minimized."));
+      Parameters.Add(new LookupParameter<DoubleMatrix>("Weights", "The weights matrix."));
+      Parameters.Add(new LookupParameter<DoubleMatrix>("Distances", "The distances matrix."));
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new QAPExhaustiveInversionLocalImprovement(this, cloner);
+    }
+
+    public static void Improve(Permutation assignment, DoubleMatrix weights, DoubleMatrix distances, DoubleValue quality, IntValue localIterations, IntValue evaluatedSolutions, bool maximization, int maxIterations, CancellationToken cancellation) {
+      for (int i = localIterations.Value; i < maxIterations; i++) {
+        InversionMove bestMove = null;
+        double bestQuality = 0; // we have to make an improvement, so 0 is the baseline
+        double evaluations = 0.0;
+        foreach (var move in ExhaustiveInversionMoveGenerator.Generate(assignment)) {
+          double moveQuality = QAPInversionMoveEvaluator.Apply(assignment, move, weights, distances);
+          evaluations += 2 * (move.Index2 - move.Index1 + 1) / (double)assignment.Length;
+          if (maximization && moveQuality > bestQuality
+            || !maximization && moveQuality < bestQuality) {
+            bestQuality = moveQuality;
+            bestMove = move;
+          }
+        }
+        evaluatedSolutions.Value = (int)Math.Ceiling(evaluations);
+        if (bestMove == null) break;
+        InversionManipulator.Apply(assignment, bestMove.Index1, bestMove.Index2);
+        quality.Value += bestQuality;
+        localIterations.Value++;
+        cancellation.ThrowIfCancellationRequested();
+      }
+    }
+
+    public override IOperation Apply() {
+      var maxIterations = MaximumIterationsParameter.ActualValue.Value;
+      var assignment = AssignmentParameter.ActualValue;
+      var maximization = MaximizationParameter.ActualValue.Value;
+      var weights = WeightsParameter.ActualValue;
+      var distances = DistancesParameter.ActualValue;
+      var quality = QualityParameter.ActualValue;
+      var locationIterations = LocalIterationsParameter.ActualValue;
+      var evaluations = EvaluatedSolutionsParameter.ActualValue;
+      if (locationIterations == null) {
+        locationIterations = new IntValue(0);
+        LocalIterationsParameter.ActualValue = locationIterations;
+      }
+
+      Improve(assignment, weights, distances, quality, locationIterations, evaluations, maximization, maxIterations, CancellationToken);
+      return base.Apply();
+    }
+  }
+}
Index: trunk/sources/HeuristicLab.Problems.QuadraticAssignment/3.3/LocalImprovement/QAPExhaustiveSwap2LocalImprovement.cs
===================================================================
--- trunk/sources/HeuristicLab.Problems.QuadraticAssignment/3.3/LocalImprovement/QAPExhaustiveSwap2LocalImprovement.cs	(revision 8335)
+++ trunk/sources/HeuristicLab.Problems.QuadraticAssignment/3.3/LocalImprovement/QAPExhaustiveSwap2LocalImprovement.cs	(revision 8338)
@@ -21,4 +21,5 @@
 
 using System;
+using System.Threading;
 using HeuristicLab.Common;
 using HeuristicLab.Core;
@@ -44,4 +45,8 @@
       get { return problem; }
       set { problem = (QuadraticAssignmentProblem)value; }
+    }
+
+    public ILookupParameter<IntValue> LocalIterationsParameter {
+      get { return (ILookupParameter<IntValue>)Parameters["LocalIterations"]; }
     }
 
@@ -86,5 +91,6 @@
     public QAPExhaustiveSwap2LocalImprovement()
       : base() {
-      Parameters.Add(new ValueLookupParameter<IntValue>("MaximumIterations", "The maximum amount of iterations that should be performed (note that this operator will abort earlier when a local optimum is reached.", new IntValue(10000)));
+      Parameters.Add(new LookupParameter<IntValue>("LocalIterations", "The number of iterations that have already been performed."));
+      Parameters.Add(new ValueLookupParameter<IntValue>("MaximumIterations", "The maximum amount of iterations that should be performed (note that this operator will abort earlier when a local optimum is reached).", new IntValue(10000)));
       Parameters.Add(new LookupParameter<IntValue>("EvaluatedSolutions", "The amount of evaluated solutions (here a move is counted only as 4/n evaluated solutions with n being the length of the permutation)."));
       Parameters.Add(new LookupParameter<ResultCollection>("Results", "The collection where to store results."));
@@ -100,14 +106,23 @@
     }
 
-    public static double Improve(Permutation assignment, double quality, DoubleMatrix weights, DoubleMatrix distances, bool maximization, int maxIterations, out double evaluatedSolutions) {
-      evaluatedSolutions = 0.0;
+    // BackwardsCompatibility3.3
+    #region Backwards compatible code, remove with 3.4
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() {
+      if (!Parameters.ContainsKey("LocalIterations"))
+        Parameters.Add(new LookupParameter<IntValue>("LocalIterations", "The number of iterations that have already been performed."));
+    }
+    #endregion
+
+    public static void Improve(Permutation assignment, DoubleMatrix weights, DoubleMatrix distances, DoubleValue quality, IntValue localIterations, IntValue evaluatedSolutions, bool maximization, int maxIterations, CancellationToken cancellation) {
       double evalSolPerMove = 4.0 / assignment.Length;
 
-      for (int i = 0; i < maxIterations; i++) {
+      for (int i = localIterations.Value; i < maxIterations; i++) {
         Swap2Move bestMove = null;
         double bestQuality = 0; // we have to make an improvement, so 0 is the baseline
+        double evaluations = 0.0;
         foreach (Swap2Move move in ExhaustiveSwap2MoveGenerator.Generate(assignment)) {
           double moveQuality = QAPSwap2MoveEvaluator.Apply(assignment, move, weights, distances);
-          evaluatedSolutions += evalSolPerMove;
+          evaluations += evalSolPerMove;
           if (maximization && moveQuality > bestQuality
             || !maximization && moveQuality < bestQuality) {
@@ -116,22 +131,28 @@
           }
         }
+        evaluatedSolutions.Value += (int)Math.Ceiling(evaluations);
         if (bestMove == null) break;
         Swap2Manipulator.Apply(assignment, bestMove.Index1, bestMove.Index2);
-        quality += bestQuality;
+        quality.Value += bestQuality;
+        localIterations.Value++;
+        cancellation.ThrowIfCancellationRequested();
       }
-      return quality;
     }
 
     public override IOperation Apply() {
-      int maxIterations = MaximumIterationsParameter.ActualValue.Value;
-      Permutation assignment = AssignmentParameter.ActualValue;
-      bool maximization = MaximizationParameter.ActualValue.Value;
-      DoubleMatrix weights = WeightsParameter.ActualValue;
-      DoubleMatrix distances = DistancesParameter.ActualValue;
-      double quality = QualityParameter.ActualValue.Value;
+      var maxIterations = MaximumIterationsParameter.ActualValue.Value;
+      var assignment = AssignmentParameter.ActualValue;
+      var maximization = MaximizationParameter.ActualValue.Value;
+      var weights = WeightsParameter.ActualValue;
+      var distances = DistancesParameter.ActualValue;
+      var quality = QualityParameter.ActualValue;
+      var localIterations = LocalIterationsParameter.ActualValue;
+      var evaluations = EvaluatedSolutionsParameter.ActualValue;
+      if (localIterations == null) {
+        localIterations = new IntValue(0);
+        LocalIterationsParameter.ActualValue = localIterations;
+      }
 
-      double evaluations;
-      QualityParameter.ActualValue.Value = Improve(assignment, quality, weights, distances, maximization, maxIterations, out evaluations);
-      EvaluatedSolutionsParameter.ActualValue.Value += (int)Math.Ceiling(evaluations);
+      Improve(assignment, weights, distances, quality, localIterations, evaluations, maximization, maxIterations, CancellationToken);
       return base.Apply();
     }
Index: trunk/sources/HeuristicLab.Problems.QuadraticAssignment/3.3/LocalImprovement/QAPStochasticScrambleLocalImprovement.cs
===================================================================
--- trunk/sources/HeuristicLab.Problems.QuadraticAssignment/3.3/LocalImprovement/QAPStochasticScrambleLocalImprovement.cs	(revision 8338)
+++ trunk/sources/HeuristicLab.Problems.QuadraticAssignment/3.3/LocalImprovement/QAPStochasticScrambleLocalImprovement.cs	(revision 8338)
@@ -0,0 +1,162 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Threading;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Encodings.PermutationEncoding;
+using HeuristicLab.Operators;
+using HeuristicLab.Optimization;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.QuadraticAssignment {
+  [Item("QAPStochasticScrambleLocalImprovement", "Takes a solution and finds the local optimum with respect to the scramble neighborhood by decending along the steepest gradient.")]
+  [StorableClass]
+  public class QAPStochasticScrambleLocalImprovement : SingleSuccessorOperator, ILocalImprovementOperator, IStochasticOperator {
+
+    public Type ProblemType {
+      get { return typeof(QuadraticAssignmentProblem); }
+    }
+
+    [Storable]
+    private QuadraticAssignmentProblem problem;
+    public IProblem Problem {
+      get { return problem; }
+      set { problem = (QuadraticAssignmentProblem)value; }
+    }
+
+    public ILookupParameter<IntValue> LocalIterationsParameter {
+      get { return (ILookupParameter<IntValue>)Parameters["LocalIterations"]; }
+    }
+
+    public ILookupParameter<IRandom> RandomParameter {
+      get { return (ILookupParameter<IRandom>)Parameters["Random"]; }
+    }
+
+    public IValueLookupParameter<IntValue> MaximumIterationsParameter {
+      get { return (IValueLookupParameter<IntValue>)Parameters["MaximumIterations"]; }
+    }
+
+    public ILookupParameter<IntValue> EvaluatedSolutionsParameter {
+      get { return (ILookupParameter<IntValue>)Parameters["EvaluatedSolutions"]; }
+    }
+
+    public ILookupParameter<ResultCollection> ResultsParameter {
+      get { return (ILookupParameter<ResultCollection>)Parameters["Results"]; }
+    }
+
+    public ILookupParameter<Permutation> AssignmentParameter {
+      get { return (ILookupParameter<Permutation>)Parameters["Assignment"]; }
+    }
+
+    public ILookupParameter<DoubleValue> QualityParameter {
+      get { return (ILookupParameter<DoubleValue>)Parameters["Quality"]; }
+    }
+
+    public ILookupParameter<BoolValue> MaximizationParameter {
+      get { return (ILookupParameter<BoolValue>)Parameters["Maximization"]; }
+    }
+
+    public ILookupParameter<DoubleMatrix> WeightsParameter {
+      get { return (ILookupParameter<DoubleMatrix>)Parameters["Weights"]; }
+    }
+
+    public ILookupParameter<DoubleMatrix> DistancesParameter {
+      get { return (ILookupParameter<DoubleMatrix>)Parameters["Distances"]; }
+    }
+
+    public IValueLookupParameter<IntValue> NeighborhoodSizeParameter {
+      get { return (IValueLookupParameter<IntValue>)Parameters["NeighborhoodSize"]; }
+    }
+
+    [StorableConstructor]
+    protected QAPStochasticScrambleLocalImprovement(bool deserializing) : base(deserializing) { }
+    protected QAPStochasticScrambleLocalImprovement(QAPStochasticScrambleLocalImprovement original, Cloner cloner)
+      : base(original, cloner) {
+      this.problem = cloner.Clone(original.problem);
+    }
+    public QAPStochasticScrambleLocalImprovement()
+      : base() {
+      Parameters.Add(new LookupParameter<IntValue>("LocalIterations", "The number of iterations that have already been performed."));
+      Parameters.Add(new LookupParameter<IRandom>("Random", "The random number generator to use."));
+      Parameters.Add(new ValueLookupParameter<IntValue>("MaximumIterations", "The maximum amount of iterations that should be performed (note that this operator will abort earlier when a local optimum is reached).", new IntValue(10000)));
+      Parameters.Add(new LookupParameter<IntValue>("EvaluatedSolutions", "The amount of evaluated solutions (here a move is counted only as 4/n evaluated solutions with n being the length of the permutation)."));
+      Parameters.Add(new LookupParameter<ResultCollection>("Results", "The collection where to store results."));
+      Parameters.Add(new LookupParameter<Permutation>("Assignment", "The permutation that is to be locally optimized."));
+      Parameters.Add(new LookupParameter<DoubleValue>("Quality", "The quality value of the assignment."));
+      Parameters.Add(new LookupParameter<BoolValue>("Maximization", "True if the problem should be maximized or minimized."));
+      Parameters.Add(new LookupParameter<DoubleMatrix>("Weights", "The weights matrix."));
+      Parameters.Add(new LookupParameter<DoubleMatrix>("Distances", "The distances matrix."));
+      Parameters.Add(new ValueLookupParameter<IntValue>("NeighborhoodSize", "The number of moves to sample from the neighborhood.", new IntValue(100)));
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new QAPStochasticScrambleLocalImprovement(this, cloner);
+    }
+
+    public static void Improve(IRandom random, Permutation assignment, DoubleMatrix weights, DoubleMatrix distances, DoubleValue quality, IntValue localIterations, IntValue evaluatedSolutions, bool maximization, int maxIterations, int neighborhoodSize, CancellationToken cancellation) {
+      for (int i = localIterations.Value; i < maxIterations; i++) {
+        ScrambleMove bestMove = null;
+        double bestQuality = 0; // we have to make an improvement, so 0 is the baseline
+        double evaluations = 0.0;
+        for (int j = 0; j < neighborhoodSize; j++) {
+          var move = StochasticScrambleMultiMoveGenerator.GenerateRandomMove(assignment, random);
+          double moveQuality = QAPScrambleMoveEvaluator.Apply(assignment, move, weights, distances);
+          evaluations += 2.0 * move.ScrambledIndices.Length / assignment.Length;
+          if (maximization && moveQuality > bestQuality
+            || !maximization && moveQuality < bestQuality) {
+            bestQuality = moveQuality;
+            bestMove = move;
+          }
+        }
+        evaluatedSolutions.Value = (int)Math.Ceiling(evaluations);
+        if (bestMove == null) break;
+        ScrambleManipulator.Apply(assignment, bestMove.StartIndex, bestMove.ScrambledIndices);
+        quality.Value += bestQuality;
+        localIterations.Value++;
+        cancellation.ThrowIfCancellationRequested();
+      }
+    }
+
+    public override IOperation Apply() {
+      var random = RandomParameter.ActualValue;
+      var maxIterations = MaximumIterationsParameter.ActualValue.Value;
+      var neighborhoodSize = NeighborhoodSizeParameter.ActualValue.Value;
+      var assignment = AssignmentParameter.ActualValue;
+      var maximization = MaximizationParameter.ActualValue.Value;
+      var weights = WeightsParameter.ActualValue;
+      var distances = DistancesParameter.ActualValue;
+      var quality = QualityParameter.ActualValue;
+      var localIterations = LocalIterationsParameter.ActualValue;
+      var evaluations = EvaluatedSolutionsParameter.ActualValue;
+      if (localIterations == null) {
+        localIterations = new IntValue(0);
+        LocalIterationsParameter.ActualValue = localIterations;
+      }
+
+      Improve(random, assignment, weights, distances, quality, localIterations, evaluations, maximization, maxIterations, neighborhoodSize, CancellationToken);
+      return base.Apply();
+    }
+  }
+}
