Index: branches/GP-MoveOperators/HeuristicLab.Problems.TravelingSalesman/3.3/Evaluators/TSPDistanceMatrixEvaluator.cs
===================================================================
--- branches/GP-MoveOperators/HeuristicLab.Problems.TravelingSalesman/3.3/Evaluators/TSPDistanceMatrixEvaluator.cs	(revision 8085)
+++ branches/GP-MoveOperators/HeuristicLab.Problems.TravelingSalesman/3.3/Evaluators/TSPDistanceMatrixEvaluator.cs	(revision 8660)
@@ -59,6 +59,6 @@
       if (distances == null || distances.Rows == 0 || distances.Columns == 0
         || distances.Rows != distances.Columns)
-        throw new InvalidOperationException("The distance matrix is empty or not square");
-      if (tour == null) throw new ArgumentNullException("tour", "No tour is given.");
+        throw new InvalidOperationException("TSPDistanceMatrixEvaluator: The distance matrix is empty or not square");
+      if (tour == null) throw new ArgumentNullException("tour", "TSPDistanceMatrixEvaluator: No tour is given.");
       Permutation p = tour;
       double length = 0;
Index: branches/GP-MoveOperators/HeuristicLab.Problems.TravelingSalesman/3.3/HeuristicLab.Problems.TravelingSalesman-3.3.csproj
===================================================================
--- branches/GP-MoveOperators/HeuristicLab.Problems.TravelingSalesman/3.3/HeuristicLab.Problems.TravelingSalesman-3.3.csproj	(revision 8085)
+++ branches/GP-MoveOperators/HeuristicLab.Problems.TravelingSalesman/3.3/HeuristicLab.Problems.TravelingSalesman-3.3.csproj	(revision 8660)
@@ -108,4 +108,5 @@
     <Reference Include="System.Data" />
     <Reference Include="System.Drawing" />
+    <Reference Include="System.Windows.Forms" />
     <Reference Include="System.Xml" />
   </ItemGroup>
@@ -118,4 +119,5 @@
     <Compile Include="Evaluators\TSPEuclideanPathEvaluator.cs" />
     <Compile Include="Evaluators\TSPGeoPathEvaluator.cs" />
+    <Compile Include="Improvers\TSPImprovementOperator.cs" />
     <Compile Include="Interfaces\ITSPDistanceMatrixEvaluator.cs" />
     <Compile Include="MoveEvaluators\ThreeOpt\TSPTranslocationMoveEuclideanPathEvaluator.cs" />
@@ -127,5 +129,9 @@
     <Compile Include="MoveEvaluators\TwoOpt\TSPInversionMovePathEvaluator.cs" />
     <Compile Include="MoveEvaluators\TwoOpt\TSPInversionMoveRoundedEuclideanPathEvaluator.cs" />
+    <Compile Include="PathRelinkers\TSPMultipleGuidesPathRelinker.cs" />
+    <Compile Include="PathRelinkers\TSPPathRelinker.cs" />
+    <Compile Include="PathRelinkers\TSPSimultaneousPathRelinker.cs" />
     <Compile Include="Plugin.cs" />
+    <Compile Include="SimilarityCalculators\TSPSimilarityCalculator.cs" />
     <Compile Include="TravelingSalesmanProblem.cs" />
     <Compile Include="PathTSPTour.cs" />
@@ -182,4 +188,8 @@
       <Name>HeuristicLab.Operators-3.3</Name>
       <Private>False</Private>
+    </ProjectReference>
+    <ProjectReference Include="..\..\HeuristicLab.Optimization.Operators\3.3\HeuristicLab.Optimization.Operators-3.3.csproj">
+      <Project>{25087811-F74C-4128-BC86-8324271DA13E}</Project>
+      <Name>HeuristicLab.Optimization.Operators-3.3</Name>
     </ProjectReference>
     <ProjectReference Include="..\..\HeuristicLab.Optimization\3.3\HeuristicLab.Optimization-3.3.csproj">
@@ -240,5 +250,5 @@
   -->
   <PropertyGroup>
-    <PreBuildEvent>set Path=%25Path%25;$(ProjectDir);$(SolutionDir)
+   <PreBuildEvent Condition=" '$(OS)' == 'Windows_NT' ">set Path=%25Path%25;$(ProjectDir);$(SolutionDir)
 set ProjectDir=$(ProjectDir)
 set SolutionDir=$(SolutionDir)
@@ -247,4 +257,10 @@
 call PreBuildEvent.cmd
 </PreBuildEvent>
+<PreBuildEvent Condition=" '$(OS)' != 'Windows_NT' ">
+export ProjectDir=$(ProjectDir)
+export SolutionDir=$(SolutionDir)
+
+$SolutionDir/PreBuildEvent.sh
+</PreBuildEvent>
   </PropertyGroup>
 </Project>
Index: branches/GP-MoveOperators/HeuristicLab.Problems.TravelingSalesman/3.3/Improvers/TSPImprovementOperator.cs
===================================================================
--- branches/GP-MoveOperators/HeuristicLab.Problems.TravelingSalesman/3.3/Improvers/TSPImprovementOperator.cs	(revision 8660)
+++ branches/GP-MoveOperators/HeuristicLab.Problems.TravelingSalesman/3.3/Improvers/TSPImprovementOperator.cs	(revision 8660)
@@ -0,0 +1,130 @@
+﻿#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 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.TravelingSalesman {
+  /// <summary>
+  /// An operator that improves traveling salesman solutions.
+  /// </summary>
+  /// <remarks>
+  /// The operator tries to improve the traveling salesman solution by swapping two randomly chosen edges for a certain number of times.
+  /// </remarks>
+  [Item("TSPImprovementOperator", "An operator that improves traveling salesman solutions. The operator tries to improve the traveling salesman solution by swapping two randomly chosen edges for a certain number of times.")]
+  [StorableClass]
+  public sealed class TSPImprovementOperator : SingleSuccessorOperator, ISingleObjectiveImprovementOperator {
+    #region Parameter properties
+    public ScopeParameter CurrentScopeParameter {
+      get { return (ScopeParameter)Parameters["CurrentScope"]; }
+    }
+    public ILookupParameter<DistanceMatrix> DistanceMatrixParameter {
+      get { return (ILookupParameter<DistanceMatrix>)Parameters["DistanceMatrix"]; }
+    }
+    public IValueParameter<IntValue> ImprovementAttemptsParameter {
+      get { return (IValueParameter<IntValue>)Parameters["ImprovementAttempts"]; }
+    }
+    public ILookupParameter<IRandom> RandomParameter {
+      get { return (ILookupParameter<IRandom>)Parameters["Random"]; }
+    }
+    public IValueLookupParameter<IItem> SolutionParameter {
+      get { return (IValueLookupParameter<IItem>)Parameters["Solution"]; }
+    }
+    #endregion
+
+    #region Properties
+    public IScope CurrentScope {
+      get { return CurrentScopeParameter.ActualValue; }
+    }
+    public DistanceMatrix DistanceMatrix {
+      get { return DistanceMatrixParameter.ActualValue; }
+      set { DistanceMatrixParameter.ActualValue = value; }
+    }
+    public IntValue ImprovementAttempts {
+      get { return ImprovementAttemptsParameter.Value; }
+      set { ImprovementAttemptsParameter.Value = value; }
+    }
+    public IRandom Random {
+      get { return RandomParameter.ActualValue; }
+      set { RandomParameter.ActualValue = value; }
+    }
+    #endregion
+
+    [StorableConstructor]
+    private TSPImprovementOperator(bool deserializing) : base(deserializing) { }
+    private TSPImprovementOperator(TSPImprovementOperator original, Cloner cloner) : base(original, cloner) { }
+    public TSPImprovementOperator()
+      : base() {
+      #region Create parameters
+      Parameters.Add(new ScopeParameter("CurrentScope", "The current scope that contains the solution to be improved."));
+      Parameters.Add(new LookupParameter<DistanceMatrix>("DistanceMatrix", "The matrix which contains the distances between the cities."));
+      Parameters.Add(new ValueParameter<IntValue>("ImprovementAttempts", "The number of improvement attempts the operator should perform.", new IntValue(100)));
+      Parameters.Add(new LookupParameter<IRandom>("Random", "A pseudo random number generator."));
+      Parameters.Add(new ValueLookupParameter<IItem>("Solution", "The solution to be improved. This parameter is used for name translation only."));
+      #endregion
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new TSPImprovementOperator(this, cloner);
+    }
+
+    public override IOperation Apply() {
+      Permutation currSol = CurrentScope.Variables[SolutionParameter.ActualName].Value as Permutation;
+      if (currSol == null)
+        throw new ArgumentException("Cannot improve solution because it has the wrong type.");
+      if (currSol.PermutationType != PermutationTypes.RelativeUndirected)
+        throw new ArgumentException("Cannot improve solution because the permutation type is not supported.");
+
+      for (int i = 0; i < ImprovementAttempts.Value; i++) {
+        int a = Random.Next(currSol.Length);
+        int b = Random.Next(currSol.Length);
+        double oldFirstEdgeLength = DistanceMatrix[currSol[a], currSol[(a - 1 + currSol.Length) % currSol.Length]];
+        double oldSecondEdgeLength = DistanceMatrix[currSol[b], currSol[(b + 1) % currSol.Length]];
+        double newFirstEdgeLength = DistanceMatrix[currSol[b], currSol[(a - 1 + currSol.Length) % currSol.Length]];
+        double newSecondEdgeLength = DistanceMatrix[currSol[a], currSol[(b + 1 + currSol.Length) % currSol.Length]];
+        if (newFirstEdgeLength + newSecondEdgeLength < oldFirstEdgeLength + oldSecondEdgeLength)
+          Invert(currSol, a, b);
+      }
+
+      CurrentScope.Variables.Add(new Variable("LocalEvaluatedSolutions", ImprovementAttempts));
+
+      return base.Apply();
+    }
+
+    private void Invert(Permutation sol, int i, int j) {
+      if (i != j)
+        for (int a = 0; a < Math.Abs(i - j) / 2; a++)
+          if (sol[(i + a) % sol.Length] != sol[(j - a + sol.Length) % sol.Length]) {
+            // XOR swap
+            sol[(i + a) % sol.Length] ^= sol[(j - a + sol.Length) % sol.Length];
+            sol[(j - a + sol.Length) % sol.Length] ^= sol[(i + a) % sol.Length];
+            sol[(i + a) % sol.Length] ^= sol[(j - a + sol.Length) % sol.Length];
+          }
+    }
+  }
+}
Index: branches/GP-MoveOperators/HeuristicLab.Problems.TravelingSalesman/3.3/PathRelinkers/TSPMultipleGuidesPathRelinker.cs
===================================================================
--- branches/GP-MoveOperators/HeuristicLab.Problems.TravelingSalesman/3.3/PathRelinkers/TSPMultipleGuidesPathRelinker.cs	(revision 8660)
+++ branches/GP-MoveOperators/HeuristicLab.Problems.TravelingSalesman/3.3/PathRelinkers/TSPMultipleGuidesPathRelinker.cs	(revision 8660)
@@ -0,0 +1,134 @@
+﻿#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.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Encodings.PermutationEncoding;
+using HeuristicLab.Optimization.Operators;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.TravelingSalesman {
+  /// <summary>
+  /// An operator that relinks paths between traveling salesman solutions using a multiple guiding strategy.
+  /// </summary>
+  /// <remarks>
+  /// The operator incrementally changes the initiating solution towards the guiding solution by correcting edges as needed. For each city it choses the best edge from all guiding solutions.
+  /// </remarks>
+  [Item("TSPMultipleGuidesPathRelinker", "An operator that relinks paths between traveling salesman solutions using a multiple guiding strategy. The operator incrementally changes the initiating solution towards the guiding solution by correcting edges as needed. For each city it choses the best edge from all guiding solutions.")]
+  [StorableClass]
+  public sealed class TSPMultipleGuidesPathRelinker : SingleObjectivePathRelinker {
+    #region Parameter properties
+    public ILookupParameter<DistanceMatrix> DistanceMatrixParameter {
+      get { return (ILookupParameter<DistanceMatrix>)Parameters["DistanceMatrix"]; }
+    }
+    #endregion
+
+    #region Properties
+    public DistanceMatrix DistanceMatrix {
+      get { return DistanceMatrixParameter.ActualValue; }
+    }
+    #endregion
+
+    [StorableConstructor]
+    private TSPMultipleGuidesPathRelinker(bool deserializing) : base(deserializing) { }
+    private TSPMultipleGuidesPathRelinker(TSPMultipleGuidesPathRelinker original, Cloner cloner) : base(original, cloner) { }
+    public TSPMultipleGuidesPathRelinker()
+      : base() {
+      #region Create parameters
+      Parameters.Add(new LookupParameter<DistanceMatrix>("DistanceMatrix", "The matrix which contains the distances between the cities."));
+      #endregion
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new TSPMultipleGuidesPathRelinker(this, cloner);
+    }
+
+    public static ItemArray<IItem> Apply(IItem initiator, IItem[] guides, DistanceMatrix distances, PercentValue n) {
+      if (!(initiator is Permutation) || guides.Any(x => !(x is Permutation)))
+        throw new ArgumentException("Cannot relink path because some of the provided solutions have the wrong type.");
+      if (n.Value <= 0.0)
+        throw new ArgumentException("RelinkingAccuracy must be greater than 0.");
+
+      Permutation v1 = initiator.Clone() as Permutation;
+      Permutation[] targets = new Permutation[guides.Length];
+      Array.Copy(guides, targets, guides.Length);
+
+      if (targets.Any(x => x.Length != v1.Length))
+        throw new ArgumentException("At least one solution is of different length.");
+
+      IList<Permutation> solutions = new List<Permutation>();
+      for (int i = 0; i < v1.Length; i++) {
+        int currCityIndex = i;
+        int bestCityIndex = (i + 1) % v1.Length;
+        double currDistance = distances[v1[currCityIndex], v1[bestCityIndex]];
+        // check each guiding solution
+        targets.ToList().ForEach(solution => {
+          // locate current city
+          var node = solution.Select((x, index) => new { Id = x, Index = index }).Single(x => x.Id == v1[currCityIndex]);
+          int pred = solution[(node.Index - 1 + solution.Length) % solution.Length];
+          int succ = solution[(node.Index + 1) % solution.Length];
+          // get distances to neighbors
+          var results = new[] { pred, succ }.Select(x => new { Id = x, Distance = distances[x, node.Id] });
+          var bestCity = results.Where(x => x.Distance < currDistance).OrderBy(x => x.Distance).FirstOrDefault();
+          if (bestCity != null) {
+            bestCityIndex = v1.Select((x, index) => new { Id = x, Index = index }).Single(x => x.Id == bestCity.Id).Index;
+            currDistance = bestCity.Distance;
+          }
+        });
+        Invert(v1, currCityIndex + 1, bestCityIndex);
+        solutions.Add(v1.Clone() as Permutation);
+      }
+
+      IList<IItem> selection = new List<IItem>();
+      if (solutions.Count > 0) {
+        int noSol = (int)(solutions.Count * n.Value);
+        if (noSol <= 0) noSol++;
+        double stepSize = (double)solutions.Count / (double)noSol;
+        for (int i = 0; i < noSol; i++)
+          selection.Add(solutions.ElementAt((int)((i + 1) * stepSize - stepSize * 0.5)));
+      }
+
+      return new ItemArray<IItem>(selection);
+    }
+
+    private static void Invert(Permutation sol, int i, int j) {
+      if (i != j)
+        for (int a = 0; a < Math.Abs(i - j) / 2; a++)
+          if (sol[(i + a) % sol.Length] != sol[(j - a + sol.Length) % sol.Length]) {
+            // XOR swap
+            sol[(i + a) % sol.Length] ^= sol[(j - a + sol.Length) % sol.Length];
+            sol[(j - a + sol.Length) % sol.Length] ^= sol[(i + a) % sol.Length];
+            sol[(i + a) % sol.Length] ^= sol[(j - a + sol.Length) % sol.Length];
+          }
+    }
+
+    protected override ItemArray<IItem> Relink(ItemArray<IItem> parents, PercentValue n) {
+      if (parents.Length < 2)
+        throw new ArgumentException("The number of parents is smaller than 2.");
+      return Apply(parents[0], parents.Skip(1).ToArray(), DistanceMatrix, n);
+    }
+  }
+}
Index: branches/GP-MoveOperators/HeuristicLab.Problems.TravelingSalesman/3.3/PathRelinkers/TSPPathRelinker.cs
===================================================================
--- branches/GP-MoveOperators/HeuristicLab.Problems.TravelingSalesman/3.3/PathRelinkers/TSPPathRelinker.cs	(revision 8660)
+++ branches/GP-MoveOperators/HeuristicLab.Problems.TravelingSalesman/3.3/PathRelinkers/TSPPathRelinker.cs	(revision 8660)
@@ -0,0 +1,94 @@
+﻿#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.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Encodings.PermutationEncoding;
+using HeuristicLab.Optimization.Operators;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.TravelingSalesman {
+  /// <summary>
+  /// An operator that relinks paths between traveling salesman solutions.
+  /// </summary>
+  /// <remarks>
+  /// The operator incrementally assimilates the initiating solution into the guiding solution by correcting edges as needed.
+  /// </remarks>
+  [Item("TSPPathRelinker", "An operator that relinks paths between traveling salesman solutions. The operator incrementally assimilates the initiating solution into the guiding solution by correcting edges as needed.")]
+  [StorableClass]
+  public sealed class TSPPathRelinker : SingleObjectivePathRelinker {
+    [StorableConstructor]
+    private TSPPathRelinker(bool deserializing) : base(deserializing) { }
+    private TSPPathRelinker(TSPPathRelinker original, Cloner cloner) : base(original, cloner) { }
+    public TSPPathRelinker() : base() { }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new TSPPathRelinker(this, cloner);
+    }
+
+    public static ItemArray<IItem> Apply(IItem initiator, IItem guide, PercentValue n) {
+      if (!(initiator is Permutation) || !(guide is Permutation))
+        throw new ArgumentException("Cannot relink path because one of the provided solutions or both have the wrong type.");
+      if (n.Value <= 0.0)
+        throw new ArgumentException("RelinkingAccuracy must be greater than 0.");
+
+      Permutation v1 = initiator.Clone() as Permutation;
+      Permutation v2 = guide as Permutation;
+
+      if (v1.Length != v2.Length)
+        throw new ArgumentException("The solutions are of different length.");
+
+      IList<Permutation> solutions = new List<Permutation>();
+      for (int i = 0; i < v1.Length; i++)
+        if (v1[i] != v2[i]) {
+          var target = v1.Select((x, index) => new { Value = x, ValueIndex = index }).First(x => x.Value == v2[i]);
+          if (v1[i] != v1[target.ValueIndex]) {
+            // XOR swap
+            v1[i] ^= v1[target.ValueIndex];
+            v1[target.ValueIndex] ^= v1[i];
+            v1[i] ^= v1[target.ValueIndex];
+            solutions.Add(v1.Clone() as Permutation);
+          }
+        }
+
+      IList<IItem> selection = new List<IItem>();
+      if (solutions.Count > 0) {
+        int noSol = (int)(solutions.Count * n.Value);
+        if (noSol <= 0) noSol++;
+        double stepSize = (double)solutions.Count / (double)noSol;
+        for (int i = 0; i < noSol; i++)
+          selection.Add(solutions.ElementAt((int)((i + 1) * stepSize - stepSize * 0.5)));
+      }
+
+      return new ItemArray<IItem>(selection);
+    }
+
+    protected override ItemArray<IItem> Relink(ItemArray<IItem> parents, PercentValue n) {
+      if (parents.Length != 2)
+        throw new ArgumentException("The number of parents is not equal to 2.");
+      return Apply(parents[0], parents[1], n);
+    }
+  }
+}
Index: branches/GP-MoveOperators/HeuristicLab.Problems.TravelingSalesman/3.3/PathRelinkers/TSPSimultaneousPathRelinker.cs
===================================================================
--- branches/GP-MoveOperators/HeuristicLab.Problems.TravelingSalesman/3.3/PathRelinkers/TSPSimultaneousPathRelinker.cs	(revision 8660)
+++ branches/GP-MoveOperators/HeuristicLab.Problems.TravelingSalesman/3.3/PathRelinkers/TSPSimultaneousPathRelinker.cs	(revision 8660)
@@ -0,0 +1,104 @@
+﻿#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.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Encodings.PermutationEncoding;
+using HeuristicLab.Optimization.Operators;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.TravelingSalesman {
+  /// <summary>
+  /// An operator that relinks paths between traveling salesman solutions starting from both ends.
+  /// </summary>
+  /// <remarks>
+  /// The operator incrementally assimilates the initiating solution into the guiding solution and vice versa by correcting edges as needed.
+  /// </remarks>
+  [Item("TSPSimultaneousPathRelinker", "An operator that relinks paths between traveling salesman solutions starting from both ends. The operator incrementally assimilates the initiating solution into the guiding solution and vice versa by correcting edges as needed.")]
+  [StorableClass]
+  public sealed class TSPSimultaneousPathRelinker : SingleObjectivePathRelinker {
+    [StorableConstructor]
+    private TSPSimultaneousPathRelinker(bool deserializing) : base(deserializing) { }
+    private TSPSimultaneousPathRelinker(TSPSimultaneousPathRelinker original, Cloner cloner) : base(original, cloner) { }
+    public TSPSimultaneousPathRelinker() : base() { }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new TSPSimultaneousPathRelinker(this, cloner);
+    }
+
+    public static ItemArray<IItem> Apply(IItem initiator, IItem guide, PercentValue n) {
+      if (!(initiator is Permutation) || !(guide is Permutation))
+        throw new ArgumentException("Cannot relink path because one of the provided solutions or both have the wrong type.");
+      if (n.Value <= 0.0)
+        throw new ArgumentException("RelinkingAccuracy must be greater than 0.");
+
+      Permutation firstInitiator = initiator.Clone() as Permutation;
+      Permutation firstGuide = guide.Clone() as Permutation;
+      Permutation secondInitiator = firstGuide.Clone() as Permutation;
+      Permutation secondGuide = firstInitiator.Clone() as Permutation;
+
+      if (firstInitiator.Length != firstGuide.Length)
+        throw new ArgumentException("The solutions are of different length.");
+
+      IList<Permutation> solutions = new List<Permutation>();
+      for (int i = 0; i < firstInitiator.Length / 2; i++) {
+        if (firstInitiator[i] != firstGuide[i]) {
+          var target = firstInitiator.Select((x, index) => new { Value = x, ValueIndex = index }).First(x => x.Value == firstGuide[i]);
+          // XOR swap
+          firstInitiator[i] ^= firstInitiator[target.ValueIndex];
+          firstInitiator[target.ValueIndex] ^= firstInitiator[i];
+          firstInitiator[i] ^= firstInitiator[target.ValueIndex];
+          solutions.Add(firstInitiator.Clone() as Permutation);
+        }
+        int j = secondInitiator.Length - 1 - i;
+        if (secondInitiator[j] != secondGuide[j]) {
+          var target = secondInitiator.Select((x, index) => new { Value = x, ValueIndex = index }).First(x => x.Value == secondGuide[j]);
+          // XOR swap
+          secondInitiator[j] ^= secondInitiator[target.ValueIndex];
+          secondInitiator[target.ValueIndex] ^= secondInitiator[j];
+          secondInitiator[j] ^= secondInitiator[target.ValueIndex];
+          solutions.Add(secondInitiator.Clone() as Permutation);
+        }
+      }
+
+      IList<IItem> selection = new List<IItem>();
+      if (solutions.Count > 0) {
+        int noSol = (int)(solutions.Count * n.Value);
+        if (noSol <= 0) noSol++;
+        double stepSize = (double)solutions.Count / (double)noSol;
+        for (int i = 0; i < noSol; i++)
+          selection.Add(solutions.ElementAt((int)((i + 1) * stepSize - stepSize * 0.5)));
+      }
+
+      return new ItemArray<IItem>(selection);
+    }
+
+    protected override ItemArray<IItem> Relink(ItemArray<IItem> parents, PercentValue n) {
+      if (parents.Length != 2)
+        throw new ArgumentException("The number of parents is not equal to 2.");
+      return Apply(parents[0], parents[1], n);
+    }
+  }
+}
Index: branches/GP-MoveOperators/HeuristicLab.Problems.TravelingSalesman/3.3/Plugin.cs.frame
===================================================================
--- branches/GP-MoveOperators/HeuristicLab.Problems.TravelingSalesman/3.3/Plugin.cs.frame	(revision 8085)
+++ branches/GP-MoveOperators/HeuristicLab.Problems.TravelingSalesman/3.3/Plugin.cs.frame	(revision 8660)
@@ -26,5 +26,5 @@
   /// Plugin class for HeuristicLab.Problems.TravelingSalesman plugin
   /// </summary>
-  [Plugin("HeuristicLab.Problems.TravelingSalesman", "3.3.6.$WCREV$")]
+  [Plugin("HeuristicLab.Problems.TravelingSalesman", "3.3.7.$WCREV$")]
   [PluginFile("HeuristicLab.Problems.TravelingSalesman-3.3.dll", PluginFileType.Assembly)]
   [PluginDependency("HeuristicLab.Analysis", "3.3")]
@@ -37,4 +37,5 @@
   [PluginDependency("HeuristicLab.Operators", "3.3")]
   [PluginDependency("HeuristicLab.Optimization", "3.3")]
+  [PluginDependency("HeuristicLab.Optimization.Operators", "3.3")]
   [PluginDependency("HeuristicLab.Parameters", "3.3")]
   [PluginDependency("HeuristicLab.Persistence", "3.3")]
Index: branches/GP-MoveOperators/HeuristicLab.Problems.TravelingSalesman/3.3/Properties/AssemblyInfo.cs.frame
===================================================================
--- branches/GP-MoveOperators/HeuristicLab.Problems.TravelingSalesman/3.3/Properties/AssemblyInfo.cs.frame	(revision 8085)
+++ branches/GP-MoveOperators/HeuristicLab.Problems.TravelingSalesman/3.3/Properties/AssemblyInfo.cs.frame	(revision 8660)
@@ -53,3 +53,3 @@
 // by using the '*' as shown below:
 [assembly: AssemblyVersion("3.3.0.0")]
-[assembly: AssemblyFileVersion("3.3.6.$WCREV$")]
+[assembly: AssemblyFileVersion("3.3.7.$WCREV$")]
Index: branches/GP-MoveOperators/HeuristicLab.Problems.TravelingSalesman/3.3/SimilarityCalculators/TSPSimilarityCalculator.cs
===================================================================
--- branches/GP-MoveOperators/HeuristicLab.Problems.TravelingSalesman/3.3/SimilarityCalculators/TSPSimilarityCalculator.cs	(revision 8660)
+++ branches/GP-MoveOperators/HeuristicLab.Problems.TravelingSalesman/3.3/SimilarityCalculators/TSPSimilarityCalculator.cs	(revision 8660)
@@ -0,0 +1,111 @@
+﻿#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 HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Encodings.PermutationEncoding;
+using HeuristicLab.Optimization.Operators;
+
+namespace HeuristicLab.Problems.TravelingSalesman {
+  /// <summary>
+  /// An operator that performs similarity calculation between two traveling salesman solutions.
+  /// </summary>
+  /// <remarks>
+  /// The operator calculates the similarity based on the number of edges the two solutions have in common.
+  /// </remarks>
+  [Item("TSPSimilarityCalculator", "An operator that performs similarity calculation between two traveling salesman solutions. The operator calculates the similarity based on the number of edges the two solutions have in common.")]
+  public sealed class TSPSimilarityCalculator : SingleObjectiveSolutionSimilarityCalculator {
+    private TSPSimilarityCalculator(bool deserializing) : base(deserializing) { }
+    private TSPSimilarityCalculator(TSPSimilarityCalculator original, Cloner cloner) : base(original, cloner) { }
+    public TSPSimilarityCalculator() : base() { }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new TSPSimilarityCalculator(this, cloner);
+    }
+
+    public static double CalculateSimilarity(Permutation left, Permutation right) {
+      if (left == null || right == null)
+        throw new ArgumentException("Cannot calculate similarity because one of the provided solutions or both are null.");
+      if (left.PermutationType != right.PermutationType)
+        throw new ArgumentException("Cannot calculate similarity because the provided solutions have different types.");
+      if (left.Length != right.Length)
+        throw new ArgumentException("Cannot calculate similarity because the provided solutions have different lengths.");
+      var comparer = new PermutationEqualityComparer();
+      if (object.ReferenceEquals(left, right) || comparer.Equals(left, right)) return 1.0;
+
+      switch (left.PermutationType) {
+        case PermutationTypes.Absolute:
+          return CalculateAbsolute(left, right);
+        case PermutationTypes.RelativeDirected:
+          return CalculateRelativeDirected(left, right);
+        case PermutationTypes.RelativeUndirected:
+          return CalculateRelativeUndirected(left, right);
+        default:
+          throw new InvalidOperationException("unknown permutation type");
+      }
+    }
+
+    private static double CalculateAbsolute(Permutation left, Permutation right) {
+      double similarity = 0.0;
+      for (int i = 0; i < left.Length; i++)
+        if (left[i] == right[i]) similarity++;
+
+      return similarity / left.Length;
+    }
+
+    private static double CalculateRelativeDirected(Permutation left, Permutation right) {
+      int[] edges = new int[right.Length];
+      for (int i = 0; i < right.Length; i++)
+        edges[right[i]] = right[(i + 1) % right.Length];
+
+      double similarity = 0.0;
+      for (int i = 0; i < left.Length; i++)
+        if (left[(i + 1) % left.Length] == edges[left[i]]) similarity++;
+
+      return similarity / left.Length;
+    }
+
+    private static double CalculateRelativeUndirected(Permutation left, Permutation right) {
+      int[,] edges = new int[right.Length, 2];
+      for (int i = 0; i < right.Length; i++) {
+        edges[right[i], 0] = right[(i + 1) % right.Length];
+        edges[right[i], 1] = right[(i - 1 + right.Length) % right.Length];
+      }
+
+      double similarity = 0.0;
+      for (int i = 0; i < left.Length; i++) {
+        int targetCity = left[(i + 1) % left.Length];
+        if (targetCity == edges[left[i], 0] || targetCity == edges[left[i], 1])
+          similarity++;
+      }
+
+      return similarity / left.Length;
+    }
+
+    public override double CalculateSolutionSimilarity(IScope leftSolution, IScope rightSolution) {
+      var sol1 = leftSolution.Variables[SolutionVariableName].Value as Permutation;
+      var sol2 = rightSolution.Variables[SolutionVariableName].Value as Permutation;
+
+      return CalculateSimilarity(sol1, sol2);
+    }
+  }
+}
Index: branches/GP-MoveOperators/HeuristicLab.Problems.TravelingSalesman/3.3/TravelingSalesmanProblem.cs
===================================================================
--- branches/GP-MoveOperators/HeuristicLab.Problems.TravelingSalesman/3.3/TravelingSalesmanProblem.cs	(revision 8085)
+++ branches/GP-MoveOperators/HeuristicLab.Problems.TravelingSalesman/3.3/TravelingSalesmanProblem.cs	(revision 8660)
@@ -24,4 +24,5 @@
 using System.IO;
 using System.Linq;
+using HeuristicLab.Analysis;
 using HeuristicLab.Common;
 using HeuristicLab.Core;
@@ -84,4 +85,7 @@
       get { return Operators.OfType<TSPPopulationDiversityAnalyzer>().FirstOrDefault(); }
     }
+    private SingleObjectivePopulationDiversityAnalyzer SingleObjectivePopulationDiversityAnalyzer {
+      get { return Operators.OfType<SingleObjectivePopulationDiversityAnalyzer>().FirstOrDefault(); }
+    }
     #endregion
 
@@ -112,9 +116,10 @@
       Parameters.Add(new OptionalValueParameter<DoubleMatrix>("Coordinates", "The x- and y-Coordinates of the cities."));
       Parameters.Add(new OptionalValueParameter<DistanceMatrix>("DistanceMatrix", "The matrix which contains the distances between the cities."));
-      Parameters.Add(new ValueParameter<BoolValue>("UseDistanceMatrix", "True if a distance matrix should be calculated and used for evaluation, otherwise false.", new BoolValue(true)));
+      Parameters.Add(new ValueParameter<BoolValue>("UseDistanceMatrix", "True if the coordinates based evaluators should calculate the distance matrix from the coordinates and use it for evaluation similar to the distance matrix evaluator, otherwise false.", new BoolValue(true)));
       Parameters.Add(new OptionalValueParameter<Permutation>("BestKnownSolution", "The best known solution of this TSP instance."));
 
       Maximization.Value = false;
       MaximizationParameter.Hidden = true;
+      UseDistanceMatrixParameter.Hidden = true;
       DistanceMatrixParameter.ReactOnValueToStringChangedAndValueItemImageChanged = false;
 
@@ -151,5 +156,6 @@
       UpdateMoveEvaluators();
       ParameterizeAnalyzers();
-      ClearDistanceMatrix();
+      if (Evaluator is ITSPCoordinatesPathEvaluator && Coordinates != null)
+        ClearDistanceMatrix();
     }
     private void CoordinatesParameter_ValueChanged(object sender, EventArgs e) {
@@ -158,13 +164,19 @@
         Coordinates.Reset += new EventHandler(Coordinates_Reset);
       }
-      ParameterizeSolutionCreator();
-      ClearDistanceMatrix();
+      if (Evaluator is ITSPCoordinatesPathEvaluator) {
+        ParameterizeSolutionCreator();
+        ClearDistanceMatrix();
+      }
     }
     private void Coordinates_ItemChanged(object sender, EventArgs<int, int> e) {
-      ClearDistanceMatrix();
+      if (Evaluator is ITSPCoordinatesPathEvaluator) {
+        ClearDistanceMatrix();
+      }
     }
     private void Coordinates_Reset(object sender, EventArgs e) {
-      ParameterizeSolutionCreator();
-      ClearDistanceMatrix();
+      if (Evaluator is ITSPCoordinatesPathEvaluator) {
+        ParameterizeSolutionCreator();
+        ClearDistanceMatrix();
+      }
     }
     private void SolutionCreator_PermutationParameter_ActualNameChanged(object sender, EventArgs e) {
@@ -222,7 +234,13 @@
 
     private void InitializeOperators() {
+      Operators.Add(new TSPImprovementOperator());
+      Operators.Add(new TSPMultipleGuidesPathRelinker());
+      Operators.Add(new TSPPathRelinker());
+      Operators.Add(new TSPSimultaneousPathRelinker());
+      Operators.Add(new TSPSimilarityCalculator());
+
       Operators.Add(new BestTSPSolutionAnalyzer());
       Operators.Add(new TSPAlleleFrequencyAnalyzer());
-      Operators.Add(new TSPPopulationDiversityAnalyzer());
+      Operators.Add(new SingleObjectivePopulationDiversityAnalyzer());
       ParameterizeAnalyzers();
       var operators = new HashSet<IPermutationOperator>(new IPermutationOperator[] {
@@ -251,5 +269,12 @@
       else if (Evaluator is ITSPCoordinatesPathEvaluator && Coordinates != null)
         SolutionCreator.LengthParameter.Value = new IntValue(Coordinates.Rows);
-      else SolutionCreator.LengthParameter.Value = null;
+      else {
+        SolutionCreator.LengthParameter.Value = null;
+        string error = "The given problem does not support the selected evaluator.";
+        if (Evaluator is ITSPDistanceMatrixEvaluator)
+          error += Environment.NewLine + "Please review that the " + DistanceMatrixParameter.Name + " parameter is defined or choose another evaluator.";
+        else error += Environment.NewLine + "Please review that the " + CoordinatesParameter.Name + " parameter is defined or choose another evaluator.";
+        PluginInfrastructure.ErrorHandling.ShowErrorDialog(error, null);
+      }
       SolutionCreator.LengthParameter.Hidden = SolutionCreator.LengthParameter.Value != null;
       SolutionCreator.PermutationTypeParameter.Value = new PermutationType(PermutationTypes.RelativeUndirected);
@@ -303,4 +328,11 @@
         TSPPopulationDiversityAnalyzer.QualityParameter.ActualName = Evaluator.QualityParameter.ActualName;
         TSPPopulationDiversityAnalyzer.ResultsParameter.ActualName = "Results";
+      }
+
+      if (SingleObjectivePopulationDiversityAnalyzer != null) {
+        SingleObjectivePopulationDiversityAnalyzer.MaximizationParameter.ActualName = MaximizationParameter.Name;
+        SingleObjectivePopulationDiversityAnalyzer.QualityParameter.ActualName = Evaluator.QualityParameter.ActualName;
+        SingleObjectivePopulationDiversityAnalyzer.ResultsParameter.ActualName = "Results";
+        SingleObjectivePopulationDiversityAnalyzer.SimilarityCalculator = Operators.OfType<TSPSimilarityCalculator>().SingleOrDefault();
       }
     }
@@ -336,9 +368,20 @@
         op.PermutationParameter.Hidden = true;
       }
+      foreach (ISingleObjectiveImprovementOperator op in Operators.OfType<ISingleObjectiveImprovementOperator>()) {
+        op.SolutionParameter.ActualName = SolutionCreator.PermutationParameter.ActualName;
+        op.SolutionParameter.Hidden = true;
+      }
+      foreach (ISingleObjectivePathRelinker op in Operators.OfType<ISingleObjectivePathRelinker>()) {
+        op.ParentsParameter.ActualName = SolutionCreator.PermutationParameter.ActualName;
+        op.ParentsParameter.Hidden = true;
+      }
+      foreach (TSPSimilarityCalculator op in Operators.OfType<TSPSimilarityCalculator>()) {
+        op.SolutionVariableName = SolutionCreator.PermutationParameter.ActualName;
+        op.QualityVariableName = Evaluator.QualityParameter.ActualName;
+      }
     }
 
     private void ClearDistanceMatrix() {
-      if (!(Evaluator is ITSPDistanceMatrixEvaluator))
-        DistanceMatrixParameter.Value = null;
+      DistanceMatrixParameter.Value = null;
     }
     #endregion
@@ -358,7 +401,8 @@
       Description = data.Description;
 
+      bool clearCoordinates = false, clearDistanceMatrix = false;
       if (data.Coordinates != null && data.Coordinates.GetLength(0) > 0)
         Coordinates = new DoubleMatrix(data.Coordinates);
-      else Coordinates = null;
+      else clearCoordinates = true;
 
       TSPEvaluator evaluator;
@@ -375,5 +419,5 @@
         DistanceMatrix = new DistanceMatrix(data.Distances);
       } else {
-        DistanceMatrix = null;
+        clearDistanceMatrix = true;
         UseDistanceMatrix = new BoolValue(data.Dimension <= DistanceMatrixSizeLimit);
         switch (data.DistanceMeasure) {
@@ -394,4 +438,8 @@
       Evaluator = evaluator;
 
+      // reset them after assigning the evaluator
+      if (clearCoordinates) Coordinates = null;
+      if (clearDistanceMatrix) DistanceMatrix = null;
+
       BestKnownSolution = null;
       BestKnownQuality = null;
@@ -400,6 +448,5 @@
         try {
           EvaluateAndLoadTour(data.BestKnownTour);
-        }
-        catch (InvalidOperationException) {
+        } catch (InvalidOperationException) {
           if (data.BestKnownQuality.HasValue)
             BestKnownQuality = new DoubleValue(data.BestKnownQuality.Value);
