Index: trunk/sources/HeuristicLab.Encodings.PermutationEncoding/3.3/HeuristicLab.Encodings.PermutationEncoding-3.3.csproj
===================================================================
--- trunk/sources/HeuristicLab.Encodings.PermutationEncoding/3.3/HeuristicLab.Encodings.PermutationEncoding-3.3.csproj	(revision 3199)
+++ trunk/sources/HeuristicLab.Encodings.PermutationEncoding/3.3/HeuristicLab.Encodings.PermutationEncoding-3.3.csproj	(revision 3200)
@@ -108,7 +108,7 @@
     <Compile Include="Manipulators\TranslocationManipulator.cs" />
     <Compile Include="Moves\ThreeIndexMove.cs" />
-    <Compile Include="Moves\ThreeOpt\StochasticThreeOptMoveGenerator.cs" />
-    <Compile Include="Moves\ThreeOpt\ThreeOptMove.cs" />
-    <Compile Include="Moves\ThreeOpt\ThreeOptMoveGenerator.cs" />
+    <Compile Include="Moves\ThreeOpt\ThreeOptMove.cs">
+      <SubType>Code</SubType>
+    </Compile>
     <Compile Include="Moves\TwoOpt\PreventReaddTwoOptTabuMoveEvaluator.cs" />
     <Compile Include="Moves\TwoOpt\StochasticTwoOptSingleMoveGenerator.cs" />
Index: trunk/sources/HeuristicLab.Encodings.PermutationEncoding/3.3/Manipulators/TranslocationManipulator.cs
===================================================================
--- trunk/sources/HeuristicLab.Encodings.PermutationEncoding/3.3/Manipulators/TranslocationManipulator.cs	(revision 3199)
+++ trunk/sources/HeuristicLab.Encodings.PermutationEncoding/3.3/Manipulators/TranslocationManipulator.cs	(revision 3200)
@@ -41,5 +41,4 @@
     /// <param name="permutation">The permutation array to manipulate.</param>
     public static void Apply(IRandom random, Permutation permutation) {
-      Permutation original = (Permutation)permutation.Clone();
       int breakPoint1, breakPoint2, insertPoint, insertPointLimit;
 
@@ -51,4 +50,10 @@
       else
         insertPoint = 0;
+
+      Apply(permutation, breakPoint1, breakPoint2, insertPoint);
+    }
+
+    public static void Apply(Permutation permutation, int breakPoint1, int breakPoint2, int insertPoint) {
+      Permutation original = (Permutation)permutation.Clone();
 
       int i = 0;  // index in new permutation
Index: trunk/sources/HeuristicLab.Encodings.PermutationEncoding/3.3/Moves/ThreeOpt/StochasticThreeOptMoveGenerator.cs
===================================================================
--- trunk/sources/HeuristicLab.Encodings.PermutationEncoding/3.3/Moves/ThreeOpt/StochasticThreeOptMoveGenerator.cs	(revision 3199)
+++ trunk/sources/HeuristicLab.Encodings.PermutationEncoding/3.3/Moves/ThreeOpt/StochasticThreeOptMoveGenerator.cs	(revision 3200)
@@ -30,10 +30,10 @@
   [Item("StochasticThreeOptMoveGenerator", "Randomly samples n from all possible 3-opt moves from a given permutation.")]
   [StorableClass]
-  public class StochasticThreeOptMoveGenerator : ThreeOptMoveGenerator, IStochasticOperator {
+  public class StochasticThreeOptMultiMoveGenerator : ThreeOptMoveGenerator, IStochasticOperator, IMultiMoveGenerator {
     public ILookupParameter<IRandom> RandomParameter {
       get { return (ILookupParameter<IRandom>)Parameters["Random"]; }
     }
-    private ValueLookupParameter<IntValue> SampleSizeParameter {
-      get { return (ValueLookupParameter<IntValue>)Parameters["SampleSize"]; }
+    public IValueLookupParameter<IntValue> SampleSizeParameter {
+      get { return (IValueLookupParameter<IntValue>)Parameters["SampleSize"]; }
     }
 
@@ -43,5 +43,5 @@
     }
 
-    public StochasticThreeOptMoveGenerator()
+    public StochasticThreeOptMultiMoveGenerator()
       : base() {
       Parameters.Add(new LookupParameter<IRandom>("Random", "The random number generator."));
@@ -51,18 +51,14 @@
     public static ThreeOptMove[] Apply(Permutation permutation, IRandom random, int sampleSize) {
       int length = permutation.Length;
-      /*int totalMoves = (length) * (length - 1) / 2 - 3;
-      // FIXME: Remove this comment if ExhaustiveThreeOptMoveGenerator exists, otherwise alter the exception message below.
-      if (sampleSize >= totalMoves) throw new InvalidOperationException("StochasticThreeOptMoveGenerator: Sample size (" + sampleSize + ") is larger than the set of all possible moves (" + totalMoves + "), use the ExhaustiveThreeOptMoveGenerator instead.");
-      */
       ThreeOptMove[] moves = new ThreeOptMove[sampleSize];
       for (int i = 0; i < sampleSize; i++) {
         int index1, index2, index3;
-        do {
-          index1 = random.Next(length - 1);
-          index2 = random.Next(index1 + 1, length);
-        } while (index2 - index1 == length - 1);
-        do {
-          index3 = random.Next(length);
-        } while (index1 <= index3 && index3 <= index2 + 1);
+        index1 = random.Next(length - 1);
+        index2 = random.Next(index1 + 1, length);
+        index3 = length - index2 + index1 - 1;  // get insertion point in remaining part
+        if (index3 > 0)
+          index3 = random.Next(index3);
+        else
+          index3 = 0;
         moves[i] = new ThreeOptMove(index1, index2, index3);
       }
Index: trunk/sources/HeuristicLab.Encodings.PermutationEncoding/3.3/Moves/ThreeOpt/ThreeOptMoveMaker.cs
===================================================================
--- trunk/sources/HeuristicLab.Encodings.PermutationEncoding/3.3/Moves/ThreeOpt/ThreeOptMoveMaker.cs	(revision 3200)
+++ trunk/sources/HeuristicLab.Encodings.PermutationEncoding/3.3/Moves/ThreeOpt/ThreeOptMoveMaker.cs	(revision 3200)
@@ -0,0 +1,71 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2010 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 HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Operators;
+using HeuristicLab.Optimization;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Encodings.PermutationEncoding {
+  [Item("ThreeOptMoveMaker", "Peforms a 3-opt move on a given permutation and updates the quality.")]
+  [StorableClass]
+  public class ThreeOptMoveMaker : SingleSuccessorOperator, IThreeOptPermutationMoveOperator, IMoveMaker {
+    public ILookupParameter<DoubleValue> QualityParameter {
+      get { return (ILookupParameter<DoubleValue>)Parameters["Quality"]; }
+    }
+    public ILookupParameter<DoubleValue> MoveQualityParameter {
+      get { return (ILookupParameter<DoubleValue>)Parameters["MoveQuality"]; }
+    }
+    public ILookupParameter<ThreeOptMove> ThreeOptMoveParameter {
+      get { return (ILookupParameter<ThreeOptMove>)Parameters["ThreeOptMove"]; }
+    }
+    public ILookupParameter<Permutation> PermutationParameter {
+      get { return (ILookupParameter<Permutation>)Parameters["Permutation"]; }
+    }
+
+    public ThreeOptMoveMaker()
+      : base() {
+      Parameters.Add(new LookupParameter<DoubleValue>("Quality", "The quality of the solution."));
+      Parameters.Add(new LookupParameter<ThreeOptMove>("ThreeOptMove", "The move to evaluate."));
+      Parameters.Add(new LookupParameter<DoubleValue>("MoveQuality", "The relative quality of the move."));
+      Parameters.Add(new LookupParameter<Permutation>("Permutation", "The solution as permutation."));
+    }
+
+    public override IOperation Apply() {
+      ThreeOptMove move = ThreeOptMoveParameter.ActualValue;
+      Permutation permutation = PermutationParameter.ActualValue;
+      DoubleValue moveQuality = MoveQualityParameter.ActualValue;
+      DoubleValue quality = QualityParameter.ActualValue;
+
+      TranslocationManipulator.Apply(permutation, move.Index1, move.Index2, move.Index3);
+      quality.Value = moveQuality.Value;
+
+      return base.Apply();
+    }
+
+    public override bool CanChangeName {
+      get { return false; }
+    }
+  }
+}
Index: trunk/sources/HeuristicLab.Problems.TravelingSalesman/3.3/HeuristicLab.Problems.TravelingSalesman-3.3.csproj
===================================================================
--- trunk/sources/HeuristicLab.Problems.TravelingSalesman/3.3/HeuristicLab.Problems.TravelingSalesman-3.3.csproj	(revision 3199)
+++ trunk/sources/HeuristicLab.Problems.TravelingSalesman/3.3/HeuristicLab.Problems.TravelingSalesman-3.3.csproj	(revision 3200)
@@ -87,4 +87,6 @@
     <Compile Include="Evaluators\TSPGeoPathEvaluator.cs" />
     <Compile Include="HeuristicLabProblemsTravelingSalesmanPlugin.cs" />
+    <Compile Include="MoveEvaluators\ThreeOptMoveTSPCoordinatesPathEvaluator.cs" />
+    <Compile Include="MoveEvaluators\ThreeOptMoveTSPRoundedEuclideanPathEvaluator.cs" />
     <Compile Include="TravelingSalesmanProblem.cs" />
     <Compile Include="TSPLIBTourParser.cs" />
Index: trunk/sources/HeuristicLab.Problems.TravelingSalesman/3.3/MoveEvaluators/ThreeOptMoveTSPCoordinatesPathEvaluator.cs
===================================================================
--- trunk/sources/HeuristicLab.Problems.TravelingSalesman/3.3/MoveEvaluators/ThreeOptMoveTSPCoordinatesPathEvaluator.cs	(revision 3200)
+++ trunk/sources/HeuristicLab.Problems.TravelingSalesman/3.3/MoveEvaluators/ThreeOptMoveTSPCoordinatesPathEvaluator.cs	(revision 3200)
@@ -0,0 +1,106 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2010 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;
+using HeuristicLab.Data;
+using HeuristicLab.Encodings.PermutationEncoding;
+using HeuristicLab.Operators;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using System;
+
+namespace HeuristicLab.Problems.TravelingSalesman {
+  /// <summary>
+  /// An operator to evaluate 3-opt moves.
+  /// </summary>
+  [Item("ThreeOptMoveTSPCoordinatesPathEvaluator", "Base class for evaluating 3-opt moves given the cities' coordinates.")]
+  [StorableClass]
+  public abstract class ThreeOptMoveTSPCoordinatesPathEvaluator : TSPPathMoveEvaluator, IThreeOptPermutationMoveOperator {
+    public ILookupParameter<ThreeOptMove> ThreeOptMoveParameter {
+      get { return (ILookupParameter<ThreeOptMove>)Parameters["ThreeOptMove"]; }
+    }
+
+    public ThreeOptMoveTSPCoordinatesPathEvaluator()
+      : base() {
+      Parameters.Add(new LookupParameter<ThreeOptMove>("ThreeOptMove", "The move to evaluate."));
+    }
+
+    public override IOperation Apply() {
+      Permutation permutation = PermutationParameter.ActualValue;
+      ThreeOptMove move = ThreeOptMoveParameter.ActualValue;
+      double moveQuality = QualityParameter.ActualValue.Value;
+      int edge1source = permutation.GetCircular(move.Index1 - 1);
+      int edge1target = permutation[move.Index1];
+      int edge2source = permutation[move.Index2];
+      int edge2target = permutation.GetCircular(move.Index2 + 1);
+      int edge3source = permutation.GetCircular(move.Index3 - 1);
+      int edge3target = permutation[move.Index3];
+
+      if (!(move.Index1 == 0 && move.Index2 == permutation.Length - 1)) { // a change like this would break the calculation (it doesn't actually change the quality anyway)
+        if (UseDistanceMatrixParameter.ActualValue.Value) {
+          DoubleMatrix distanceMatrix = DistanceMatrixParameter.ActualValue;
+          if (distanceMatrix == null) {
+            distanceMatrix = CalculateDistanceMatrix(CoordinatesParameter.ActualValue);
+            DistanceMatrixParameter.ActualValue = distanceMatrix;
+          }
+          // remove three edges
+          moveQuality -= distanceMatrix[edge1source, edge1target];
+          moveQuality -= distanceMatrix[edge2source, edge2target];
+          moveQuality -= distanceMatrix[edge3source, edge3target];
+          // add three edges
+          moveQuality += distanceMatrix[edge3source, edge1target];
+          moveQuality += distanceMatrix[edge2source, edge3target];
+          moveQuality += distanceMatrix[edge1source, edge2target];
+        } else {
+          DoubleMatrix coordinates = CoordinatesParameter.ActualValue;
+          // remove three edges
+          moveQuality -= CalculateDistance(coordinates[edge1source, 0], coordinates[edge1source, 1],
+            coordinates[edge1target, 0], coordinates[edge1target, 1]);
+          moveQuality -= CalculateDistance(coordinates[edge2source, 0], coordinates[edge2source, 1],
+            coordinates[edge2target, 0], coordinates[edge2target, 1]);
+          moveQuality -= CalculateDistance(coordinates[edge3source, 0], coordinates[edge3source, 1],
+            coordinates[edge3target, 0], coordinates[edge3target, 1]);
+          // add three edges
+          moveQuality += CalculateDistance(coordinates[edge3source, 0], coordinates[edge3source, 1],
+            coordinates[edge1target, 0], coordinates[edge1target, 1]);
+          moveQuality += CalculateDistance(coordinates[edge2source, 0], coordinates[edge2source, 1],
+            coordinates[edge3target, 0], coordinates[edge3target, 1]);
+          moveQuality += CalculateDistance(coordinates[edge1source, 0], coordinates[edge1source, 1],
+            coordinates[edge2target, 0], coordinates[edge2target, 1]);
+        }
+      }
+      if (MoveQualityParameter.ActualValue == null) MoveQualityParameter.ActualValue = new DoubleValue(moveQuality);
+      else MoveQualityParameter.ActualValue.Value = moveQuality;
+      return base.Apply();
+    }
+
+    protected abstract double CalculateDistance(double x1, double y1, double x2, double y2);
+
+    protected DoubleMatrix CalculateDistanceMatrix(DoubleMatrix c) {
+      DoubleMatrix distanceMatrix = new DoubleMatrix(c.Rows, c.Rows);
+      for (int i = 0; i < distanceMatrix.Rows; i++) {
+        for (int j = 0; j < distanceMatrix.Columns; j++)
+          distanceMatrix[i, j] = CalculateDistance(c[i, 0], c[i, 1], c[j, 0], c[j, 1]);
+      }
+      return distanceMatrix;
+    }
+  }
+}
Index: trunk/sources/HeuristicLab.Problems.TravelingSalesman/3.3/MoveEvaluators/ThreeOptMoveTSPRoundedEuclideanPathEvaluator.cs
===================================================================
--- trunk/sources/HeuristicLab.Problems.TravelingSalesman/3.3/MoveEvaluators/ThreeOptMoveTSPRoundedEuclideanPathEvaluator.cs	(revision 3200)
+++ trunk/sources/HeuristicLab.Problems.TravelingSalesman/3.3/MoveEvaluators/ThreeOptMoveTSPRoundedEuclideanPathEvaluator.cs	(revision 3200)
@@ -0,0 +1,41 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2010 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;
+using HeuristicLab.Data;
+using HeuristicLab.Encodings.PermutationEncoding;
+using HeuristicLab.Operators;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using System;
+
+namespace HeuristicLab.Problems.TravelingSalesman {
+  /// <summary>
+  /// An operator to evaluate 3-opt moves.
+  /// </summary>
+  [Item("ThreeOptMoveTSPRoundedEuclideanPathEvaluator", "Evaluates a 3-opt move (rounded euclidean distances) by summing up the length of all added edges and subtracting the length of all deleted edges.")]
+  [StorableClass]
+  public class ThreeOptMoveTSPRoundedEuclideanPathEvaluator : ThreeOptMoveTSPCoordinatesPathEvaluator {
+    protected override double CalculateDistance(double x1, double y1, double x2, double y2) {
+      return Math.Round(Math.Sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)));
+    }
+  }
+}
