Index: /branches/HeuristicLab.Analysis.AlgorithmBehavior/HeuristicLab.Analysis.AlgorithmBehavior/3.3/Analyzers/ConvergenceSpeedAnalyzer.cs
===================================================================
--- /branches/HeuristicLab.Analysis.AlgorithmBehavior/HeuristicLab.Analysis.AlgorithmBehavior/3.3/Analyzers/ConvergenceSpeedAnalyzer.cs	(revision 8269)
+++ /branches/HeuristicLab.Analysis.AlgorithmBehavior/HeuristicLab.Analysis.AlgorithmBehavior/3.3/Analyzers/ConvergenceSpeedAnalyzer.cs	(revision 8269)
@@ -0,0 +1,141 @@
+﻿#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.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Algorithms.ScatterSearch.TravelingSalesman;
+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;
+using HeuristicLab.Problems.TravelingSalesman;
+
+namespace HeuristicLab.Analysis.AlgorithmBehavior {
+
+  /// <summary>
+  /// An operator that analyzes the quality of schemas.
+  /// </summary>
+  [Item("ConvergenceSpeedAnalyzer", "An operator that calculates the convergence speed.")]
+  [StorableClass]
+  public sealed class ConvergenceSpeedAnalyzer : SingleSuccessorOperator, IAnalyzer {
+    private const string ResultsParameterName = "Results";
+    private const string PopulationGraphResultParameterName = "PopulationGraph";
+    private const string SchemataParameterName = "Schemata";
+    private const string SchemaOccurenceInGenerationsMatrixParameterName = "ConvergenceSpeedAnalyzer";
+    private const string QualitiesParameterName = "Qualities";
+    private const string DistanceMatrixParameterName = "DistanceMatrix";
+    private const string GenerationsParameterName = "Generations";
+    private const string BestSolutionParameterName = "Best TSP Solution";
+
+    #region IAnalyzer Members
+    public bool EnabledByDefault {
+      get { return true; }
+    }
+    #endregion
+
+    #region Parameter properties
+    public ILookupParameter<ResultCollection> ResultsParameter {
+      get { return (ILookupParameter<ResultCollection>)Parameters[ResultsParameterName]; }
+    }
+    public ILookupParameter<DistanceMatrix> DistanceMatrixParameter {
+      get { return (ILookupParameter<DistanceMatrix>)Parameters[DistanceMatrixParameterName]; }
+    }
+    public ILookupParameter<IntValue> GenerationsParameter {
+      get { return (ILookupParameter<IntValue>)Parameters[GenerationsParameterName]; }
+    }
+    #endregion
+
+    #region Properties
+    public ResultCollection Results {
+      get { return ResultsParameter.ActualValue; }
+    }
+    public DistanceMatrix DistanceMatrix {
+      get { return DistanceMatrixParameter.ActualValue; }
+    }
+    public HeuristicLab.Analysis.DataTable Qualities {
+      get { return ((HeuristicLab.Analysis.DataTable)ResultsParameter.ActualValue[QualitiesParameterName].Value); }
+    }
+    public PathTSPTour BestSolution {
+      get { return ((PathTSPTour)ResultsParameter.ActualValue[BestSolutionParameterName].Value); }
+    }
+    #endregion
+
+    [StorableConstructor]
+    private ConvergenceSpeedAnalyzer(bool deserializing) : base(deserializing) { }
+    private ConvergenceSpeedAnalyzer(ConvergenceSpeedAnalyzer original, Cloner cloner) : base(original, cloner) { }
+    public ConvergenceSpeedAnalyzer()
+      : base() {
+      Parameters.Add(new LookupParameter<ResultCollection>(ResultsParameterName, "The results collection where the analysis values should be stored."));
+      Parameters.Add(new LookupParameter<DistanceMatrix>(DistanceMatrixParameterName, "The distance matrix of the TSP."));
+      Parameters.Add(new LookupParameter<IntValue>(GenerationsParameterName, "Nr of generations."));
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new ConvergenceSpeedAnalyzer(this, cloner);
+    }
+
+    public override IOperation Apply() {
+      var graph = (GenealogyGraph<Permutation>)Results[PopulationGraphResultParameterName].Value;
+      Dictionary<int, double> occurences = new Dictionary<int, double>();
+
+      for (int i = 0; i < GenerationsParameter.ActualValue.Value; i++) {
+        var individuals = graph.Values.Where(x => x.Rank.Contains(i) || x.Rank.Contains(i + 0.5));
+
+        double convInGeneration = 0.0;
+        foreach (var ind1 in individuals) {
+          double convForInd = 0.0;
+          foreach (var ind2 in individuals) {
+            convForInd += TravelingSalesmanSimilarityCalculator.CalculateDiversity((Permutation)ind1.Data, (Permutation)ind2.Data);
+          }
+          convForInd = convForInd / individuals.Count();
+          convInGeneration += convForInd;
+        }
+        convInGeneration = convInGeneration / individuals.Count();
+        occurences.Add(i, convInGeneration);
+      }
+
+      var schemataMatrix = new Dictionary<int, string>();
+      foreach (var ind in occurences.Keys) {
+        if (!schemataMatrix.ContainsKey(ind)) {
+          string result = occurences[ind].ToString();
+          schemataMatrix.Add(ind, result);
+        }
+      }
+
+      var stringMatrix = new StringMatrix(schemataMatrix.Keys.Count, 2);
+      for (int i = 0; i < schemataMatrix.Keys.Count; i++) {
+        var element = schemataMatrix.ElementAt(i);
+        stringMatrix[i, 0] = element.Key.ToString();
+        stringMatrix[i, 1] = element.Value;
+      }
+      stringMatrix.ColumnNames = new[] { "Generation", "Diversity" };
+
+      Results.Add(new Result(SchemaOccurenceInGenerationsMatrixParameterName, stringMatrix));
+
+      return base.Apply();
+    }
+  }
+}
+
Index: /branches/HeuristicLab.Analysis.AlgorithmBehavior/HeuristicLab.Analysis.AlgorithmBehavior/3.3/HeuristicLab.Analysis.AlgorithmBehavior-3.3.csproj
===================================================================
--- /branches/HeuristicLab.Analysis.AlgorithmBehavior/HeuristicLab.Analysis.AlgorithmBehavior/3.3/HeuristicLab.Analysis.AlgorithmBehavior-3.3.csproj	(revision 8268)
+++ /branches/HeuristicLab.Analysis.AlgorithmBehavior/HeuristicLab.Analysis.AlgorithmBehavior/3.3/HeuristicLab.Analysis.AlgorithmBehavior-3.3.csproj	(revision 8269)
@@ -101,4 +101,5 @@
     <Compile Include="Analyzers\BestIndividualWildcardAnalyzer.cs" />
     <Compile Include="Analyzers\AlleleOccurencesInGenerationsAnalyzer.cs" />
+    <Compile Include="Analyzers\ConvergenceSpeedAnalyzer.cs" />
     <Compile Include="Creators\BestIndividualSchemataCreator.cs" />
     <Compile Include="Analyzers\BestIndividualQualityAnalyzer.cs" />
@@ -114,4 +115,6 @@
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="SchemaEqualityComparer.cs" />
+    <Compile Include="SimilarityCalculator.cs" />
+    <Compile Include="TravelingSalesmanSimilarityCalculator.cs" />
   </ItemGroup>
   <ItemGroup />
Index: /branches/HeuristicLab.Analysis.AlgorithmBehavior/HeuristicLab.Analysis.AlgorithmBehavior/3.3/SimilarityCalculator.cs
===================================================================
--- /branches/HeuristicLab.Analysis.AlgorithmBehavior/HeuristicLab.Analysis.AlgorithmBehavior/3.3/SimilarityCalculator.cs	(revision 8269)
+++ /branches/HeuristicLab.Analysis.AlgorithmBehavior/HeuristicLab.Analysis.AlgorithmBehavior/3.3/SimilarityCalculator.cs	(revision 8269)
@@ -0,0 +1,54 @@
+﻿#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.Operators;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Algorithms.ScatterSearch {
+  /// <summary>
+  /// A base class for operators that perform diversity calculation between two solutions.
+  /// </summary>
+  [Item("DiversityCalculator", "A base class for operators that perform diversity calculation between two solutions.")]
+  [StorableClass]
+  public abstract class SimilarityCalculator : SingleSuccessorOperator {
+    [StorableConstructor]
+    protected SimilarityCalculator(bool deserializing) : base(deserializing) { }
+    protected SimilarityCalculator(SimilarityCalculator original, Cloner cloner) : base(original, cloner) { }
+    protected SimilarityCalculator() : base() { }
+
+    public sealed override IOperation Apply() { // TODO: check if sealed fits here?
+      return base.Apply();
+    }
+
+    public double ExecuteCalculation(IScope left, IScope right) {
+      if (left == null || right == null)
+        throw new ArgumentException("Cannot calculate diversity because one or both of the provided scopes is null.");
+
+      if (left == right) return 0;
+      else return CalculateDiversity(left, right);
+    }
+
+    protected abstract double CalculateDiversity(IScope left, IScope right);
+  }
+}
Index: /branches/HeuristicLab.Analysis.AlgorithmBehavior/HeuristicLab.Analysis.AlgorithmBehavior/3.3/TravelingSalesmanSimilarityCalculator.cs
===================================================================
--- /branches/HeuristicLab.Analysis.AlgorithmBehavior/HeuristicLab.Analysis.AlgorithmBehavior/3.3/TravelingSalesmanSimilarityCalculator.cs	(revision 8269)
+++ /branches/HeuristicLab.Analysis.AlgorithmBehavior/HeuristicLab.Analysis.AlgorithmBehavior/3.3/TravelingSalesmanSimilarityCalculator.cs	(revision 8269)
@@ -0,0 +1,67 @@
+﻿#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 HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Encodings.PermutationEncoding;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Algorithms.ScatterSearch.TravelingSalesman {
+  /// <summary>
+  /// An operator that performs similarity calculation between two traveling salesman solutions.
+  /// </summary>
+  [Item("TravelingSalesmanSimilarityCalculator", "An operator that performs similarity calculation between two traveling salesman solutions.")]
+  [StorableClass]
+  public sealed class TravelingSalesmanSimilarityCalculator : SimilarityCalculator {
+    [StorableConstructor]
+    private TravelingSalesmanSimilarityCalculator(bool deserializing) : base(deserializing) { }
+    private TravelingSalesmanSimilarityCalculator(TravelingSalesmanSimilarityCalculator original, Cloner cloner) : base(original, cloner) { }
+    public TravelingSalesmanSimilarityCalculator() : base() { }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new TravelingSalesmanSimilarityCalculator(this, cloner);
+    }
+
+    protected override double CalculateDiversity(IScope left, IScope right) {
+      Permutation v1 = left.Variables["TSPTour"].Value as Permutation;
+      Permutation v2 = right.Variables["TSPTour"].Value as Permutation;
+
+      return CalculateDiversity(v1, v2);
+    }
+
+    public static double CalculateDiversity(Permutation v1, Permutation v2) {
+      int[,] edges = new int[v2.Length, 2];
+      for (int i = 0; i < v2.Length; i++) {
+        edges[v2[i], 0] = v2[(i + 1) % v2.Length];
+        edges[v2[i], 1] = v2[(i - 1 + v2.Length) % v2.Length];
+      }
+
+      double similarity = 0.0;
+      for (int i = 0; i < v1.Length; i++) {
+        int targetCity = v1[(i + 1) % v1.Length];
+        if (targetCity == edges[v1[i], 0] || targetCity == edges[v1[i], 1])
+          similarity++;
+      }
+
+      return similarity / v1.Length;
+    }
+  }
+}
