Index: /branches/PerformanceComparison/HeuristicLab.Algorithms.MemPR/3.3/HeuristicLab.Algorithms.MemPR-3.3.csproj
===================================================================
--- /branches/PerformanceComparison/HeuristicLab.Algorithms.MemPR/3.3/HeuristicLab.Algorithms.MemPR-3.3.csproj	(revision 14690)
+++ /branches/PerformanceComparison/HeuristicLab.Algorithms.MemPR/3.3/HeuristicLab.Algorithms.MemPR-3.3.csproj	(revision 14691)
@@ -132,4 +132,14 @@
     <Reference Include="HeuristicLab.Problems.DataAnalysis-3.4">
       <HintPath>..\..\..\..\trunk\sources\bin\HeuristicLab.Problems.DataAnalysis-3.4.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.Problems.Instances-3.3, Version=3.3.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\..\trunk\sources\bin\HeuristicLab.Problems.Instances-3.3.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.Problems.QuadraticAssignment-3.3, Version=3.3.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\..\trunk\sources\bin\HeuristicLab.Problems.QuadraticAssignment-3.3.dll</HintPath>
       <Private>False</Private>
     </Reference>
Index: /branches/PerformanceComparison/HeuristicLab.Algorithms.MemPR/3.3/MemPRContext.cs
===================================================================
--- /branches/PerformanceComparison/HeuristicLab.Algorithms.MemPR/3.3/MemPRContext.cs	(revision 14690)
+++ /branches/PerformanceComparison/HeuristicLab.Algorithms.MemPR/3.3/MemPRContext.cs	(revision 14691)
@@ -469,4 +469,7 @@
 
     private TContext parent;
+    protected TContext BaseContext {
+      get { return parent;}
+    }
     public IExecutionContext Parent {
       get { return parent; }
Index: /branches/PerformanceComparison/HeuristicLab.Algorithms.MemPR/3.3/Permutation/LocalSearch/ExhaustiveHillClimb.cs
===================================================================
--- /branches/PerformanceComparison/HeuristicLab.Algorithms.MemPR/3.3/Permutation/LocalSearch/ExhaustiveHillClimb.cs	(revision 14690)
+++ /branches/PerformanceComparison/HeuristicLab.Algorithms.MemPR/3.3/Permutation/LocalSearch/ExhaustiveHillClimb.cs	(revision 14691)
@@ -28,4 +28,5 @@
 using HeuristicLab.Optimization;
 using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Problems.QuadraticAssignment;
 
 namespace HeuristicLab.Algorithms.MemPR.Permutation.LocalSearch {
@@ -54,17 +55,26 @@
       var quality = context.Solution.Fitness;
       try {
+
+        var min = 0.0;
+        var max = 1.0;
+        var qap = context.Problem as QuadraticAssignmentProblem;
+        if (qap != null) {
+          min = qap.LowerBound.Value;
+          max = qap.AverageQuality.Value;
+        }
+
         var path = new List<Tuple<Encodings.PermutationEncoding.Permutation, double>>();
-        path.Add(Tuple.Create((Encodings.PermutationEncoding.Permutation)context.Solution.Solution.Clone(), quality));
+        path.Add(Tuple.Create((Encodings.PermutationEncoding.Permutation)context.Solution.Solution.Clone(), (quality - min) / (max - min)));
 
         var result = Exhaustive.HillClimb(context.Random, context.Solution.Solution, quality,
           context.Maximization, context.Evaluate, CancellationToken.None);
-
-        Tuple<Encodings.PermutationEncoding.Permutation, double, int> last = null;
+        
+        var evaluations = 0;
         foreach (var step in result) {
-          path.Add(Tuple.Create((Encodings.PermutationEncoding.Permutation)step.Item1.Clone(), step.Item2));
-          last = step;
+          path.Add(Tuple.Create((Encodings.PermutationEncoding.Permutation)step.Item1.Clone(), (step.Item2 - min) / (max - min)));
+          evaluations = step.Item3; // last one will be actual evaluations
         }
         context.LocalSearchPaths.AddPath(path);
-        context.IncrementEvaluatedSolutions(last.Item3);
+        context.IncrementEvaluatedSolutions(evaluations);
         context.Iterations = path.Count - 2;
       } finally {
Index: /branches/PerformanceComparison/HeuristicLab.Algorithms.MemPR/3.3/Permutation/LocalSearch/ExhaustiveHillClimbSubspace.cs
===================================================================
--- /branches/PerformanceComparison/HeuristicLab.Algorithms.MemPR/3.3/Permutation/LocalSearch/ExhaustiveHillClimbSubspace.cs	(revision 14690)
+++ /branches/PerformanceComparison/HeuristicLab.Algorithms.MemPR/3.3/Permutation/LocalSearch/ExhaustiveHillClimbSubspace.cs	(revision 14691)
@@ -28,4 +28,5 @@
 using HeuristicLab.Optimization;
 using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Problems.QuadraticAssignment;
 
 namespace HeuristicLab.Algorithms.MemPR.Permutation.LocalSearch {
@@ -54,17 +55,25 @@
       var quality = context.Solution.Fitness;
       try {
+        var min = 0.0;
+        var max = 1.0;
+        var qap = context.Problem as QuadraticAssignmentProblem;
+        if (qap != null) {
+          min = qap.LowerBound.Value;
+          max = qap.AverageQuality.Value;
+        }
+
         var path = new List<Tuple<Encodings.PermutationEncoding.Permutation, double>>();
-        path.Add(Tuple.Create((Encodings.PermutationEncoding.Permutation)context.Solution.Solution.Clone(), quality));
+        path.Add(Tuple.Create((Encodings.PermutationEncoding.Permutation)context.Solution.Solution.Clone(), (quality - min) / (max - min)));
 
         var result = Exhaustive.HillClimb(context.Random, context.Solution.Solution, quality,
           context.Maximization, context.Evaluate, CancellationToken.None, context.Subspace.Subspace);
 
-        Tuple<Encodings.PermutationEncoding.Permutation, double, int> last = null;
+        var evaluations = 0;
         foreach (var step in result) {
-          path.Add(Tuple.Create((Encodings.PermutationEncoding.Permutation)step.Item1.Clone(), step.Item2));
-          last = step;
+          path.Add(Tuple.Create((Encodings.PermutationEncoding.Permutation)step.Item1.Clone(), (step.Item2 - min) / (max - min)));
+          evaluations = step.Item3; // last one will be actual evaluations
         }
         context.LocalSearchPaths.AddPath(path);
-        context.IncrementEvaluatedSolutions(last.Item3);
+        context.IncrementEvaluatedSolutions(evaluations);
         context.Iterations = path.Count - 2;
       } finally {
Index: /branches/PerformanceComparison/HeuristicLab.Algorithms.MemPR/3.3/Permutation/PermutationMemPRContext.cs
===================================================================
--- /branches/PerformanceComparison/HeuristicLab.Algorithms.MemPR/3.3/Permutation/PermutationMemPRContext.cs	(revision 14690)
+++ /branches/PerformanceComparison/HeuristicLab.Algorithms.MemPR/3.3/Permutation/PermutationMemPRContext.cs	(revision 14691)
@@ -23,4 +23,5 @@
 using System.Runtime.Remoting.Contexts;
 using HeuristicLab.Algorithms.MemPR.Interfaces;
+using HeuristicLab.Analysis.FitnessLandscape;
 using HeuristicLab.Common;
 using HeuristicLab.Core;
@@ -61,5 +62,6 @@
   [Item("MemPR Solution Context (permutation)", "MemPR solution context for permutation encoded problems.")]
   [StorableClass]
-  public sealed class PermutationMemPRSolutionContext : MemPRSolutionContext<ISingleObjectiveHeuristicOptimizationProblem, Encodings.PermutationEncoding.Permutation, PermutationMemPRPopulationContext, PermutationMemPRSolutionContext>, IPermutationSubspaceContext {
+  public sealed class PermutationMemPRSolutionContext : MemPRSolutionContext<ISingleObjectiveHeuristicOptimizationProblem, Encodings.PermutationEncoding.Permutation, PermutationMemPRPopulationContext, PermutationMemPRSolutionContext>, IPermutationSubspaceContext,
+    ILocalSearchPathContext<Encodings.PermutationEncoding.Permutation> {
 
     [Storable]
@@ -87,4 +89,8 @@
       return new PermutationMemPRSolutionContext(this, cloner);
     }
+
+    public DirectedPath<Encodings.PermutationEncoding.Permutation> LocalSearchPaths {
+      get { return BaseContext.LocalSearchPaths; }
+    }
   }
 }
Index: /branches/PerformanceComparison/HeuristicLab.Analysis.FitnessLandscape/3.3/HeuristicLab.Analysis.FitnessLandscape-3.3.csproj
===================================================================
--- /branches/PerformanceComparison/HeuristicLab.Analysis.FitnessLandscape/3.3/HeuristicLab.Analysis.FitnessLandscape-3.3.csproj	(revision 14690)
+++ /branches/PerformanceComparison/HeuristicLab.Analysis.FitnessLandscape/3.3/HeuristicLab.Analysis.FitnessLandscape-3.3.csproj	(revision 14691)
@@ -207,5 +207,7 @@
     <Compile Include="CharacteristicCalculator\RandomWalkCalculator.cs" />
     <Compile Include="ProblemCharacteristicAnalysis\CharacteristicCalculator.cs" />
+    <Compile Include="ProblemCharacteristicAnalysis\CurveAnalysis.cs" />
     <Compile Include="ProblemCharacteristicAnalysis\DoubleMatrixCharacteristicCalculator.cs" />
+    <Compile Include="ProblemCharacteristicAnalysis\PermutationPathAnalysis.cs" />
     <Compile Include="ProblemCharacteristicAnalysis\QAP\QAPCharacteristicCalculator.cs" />
     <Compile Include="ProblemCharacteristicAnalysis\QAP\QAPDirectedWalk.cs" />
Index: /branches/PerformanceComparison/HeuristicLab.Analysis.FitnessLandscape/3.3/ProblemCharacteristicAnalysis/CurveAnalysis.cs
===================================================================
--- /branches/PerformanceComparison/HeuristicLab.Analysis.FitnessLandscape/3.3/ProblemCharacteristicAnalysis/CurveAnalysis.cs	(revision 14691)
+++ /branches/PerformanceComparison/HeuristicLab.Analysis.FitnessLandscape/3.3/ProblemCharacteristicAnalysis/CurveAnalysis.cs	(revision 14691)
@@ -0,0 +1,101 @@
+﻿using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace HeuristicLab.Analysis.FitnessLandscape {
+  public static class CurveAnalysis<T> {
+    public static CurveAnalysisResult GetCharacteristics(List<List<Tuple<T, double>>> trajectories, Func<T, T, double> distFunc) {
+      trajectories = trajectories.Where(x => x.Count > 5).ToList();
+      var f1 = trajectories.Select(path => ApproximateDerivative(path, distFunc).ToList()).ToList();
+      var f2 = f1.Select(d1 => ApproximateDerivative(d1, distFunc).ToList()).ToList();
+
+      var sharpness = f1.Average(x => x.Average(y => Math.Abs(y.Item2)));//f2.Average(x => Area(x, distFunc));
+      var bumpiness = 0.0;
+      var flatness = 0.0;
+
+      for (var p = 0; p < f2.Count; p++) {
+        if (f2[p].Count <= 2) continue;
+        var bump = 0;
+        var flat = 0;
+        for (var i = 0; i < f2[p].Count - 1; i++) {
+          if ((f2[p][i].Item2 > 0 && f2[p][i + 1].Item2 < 0) || (f2[p][i].Item2 < 0 && f2[p][i + 1].Item2 > 0)) {
+            bump++;
+          } else if (f2[p][i].Item2 == 0) {
+            flat++;
+          }
+        }
+        bumpiness += bump / (f2[p].Count - 1.0);
+        flatness += flat / (f2[p].Count - 1.0);
+      }
+      bumpiness /= f2.Count;
+      flatness /= f2.Count;
+      return new CurveAnalysisResult(sharpness, bumpiness, flatness);
+    }
+
+    private static double Area(IEnumerable<Tuple<T, double>> path, Func<T, T, double> distFunc) {
+      var iter = path.GetEnumerator();
+      if (!iter.MoveNext()) return 0.0;
+      var area = 0.0;
+      var prev = iter.Current;
+      while (iter.MoveNext()) {
+        area += TrapezoidArea(prev, iter.Current, distFunc);
+        prev = iter.Current;
+      }
+      return area;
+    }
+
+    private static double TrapezoidArea(Tuple<T, double> a, Tuple<T, double> b, Func<T, T, double> distFunc) {
+      var area = 0.0;
+      var dist = distFunc(a.Item1, b.Item1);
+      if ((a.Item2 <= 0 && b.Item2 <= 0) || (a.Item2 >= 0 && b.Item2 >= 0))
+        area += dist * (Math.Abs(a.Item2) + Math.Abs(b.Item2)) / 2.0;
+      else {
+        var k = (b.Item2 - a.Item2) / dist;
+        var d = a.Item2;
+        var x = -d / k;
+        area += Math.Abs(x * a.Item2 / 2.0);
+        area += Math.Abs((dist - x) * b.Item2 / 2.0);
+      }
+      return area;
+    }
+
+    private static IEnumerable<Tuple<T, double>> ApproximateDerivative(IEnumerable<Tuple<T, double>> data, Func<T, T, double> distFunc) {
+      Tuple<T, double> prev = null, prev2 = null;
+      foreach (var d in data) {
+        if (prev == null) {
+          prev = d;
+          continue;
+        }
+        if (prev2 == null) {
+          prev2 = prev;
+          prev = d;
+          continue;
+        }
+        var dist = distFunc(prev2.Item1, d.Item1);
+        yield return Tuple.Create(prev.Item1, (d.Item2 - prev2.Item2) / dist);
+        prev2 = prev;
+        prev = d;
+      }
+    }
+  }
+
+  public class CurveAnalysisResult {
+    public double Sharpness { get; private set; }
+    public double Bumpiness { get; private set; }
+    public double Flatness { get; private set; }
+
+    public string[] GetNames() {
+      return new[] { "Sharpness", "Bumpiness", "Flatness" };
+    }
+
+    public double[] GetValues() {
+      return new[] { Sharpness, Bumpiness, Flatness };
+    }
+
+    public CurveAnalysisResult(double sharpness, double bumpiness, double flatness) {
+      Sharpness = sharpness;
+      Bumpiness = bumpiness;
+      Flatness = flatness;
+    }
+  }
+}
Index: /branches/PerformanceComparison/HeuristicLab.Analysis.FitnessLandscape/3.3/ProblemCharacteristicAnalysis/PermutationPathAnalysis.cs
===================================================================
--- /branches/PerformanceComparison/HeuristicLab.Analysis.FitnessLandscape/3.3/ProblemCharacteristicAnalysis/PermutationPathAnalysis.cs	(revision 14691)
+++ /branches/PerformanceComparison/HeuristicLab.Analysis.FitnessLandscape/3.3/ProblemCharacteristicAnalysis/PermutationPathAnalysis.cs	(revision 14691)
@@ -0,0 +1,18 @@
+﻿using System;
+using System.Collections.Generic;
+using HeuristicLab.Encodings.PermutationEncoding;
+
+namespace HeuristicLab.Analysis.FitnessLandscape {
+  public static class PermutationPathAnalysis {
+    public static CurveAnalysisResult GetCharacteristics(List<List<Tuple<Permutation, double>>> trajectories) {
+      return CurveAnalysis<Permutation>.GetCharacteristics(trajectories, Dist);
+    }
+
+    private static double Dist(Permutation a, Permutation b) {
+      var dist = 0;
+      for (var i = 0; i < a.Length; i++)
+        if (a[i] != b[i]) dist++;
+      return dist;
+    }
+  }
+}
Index: /branches/PerformanceComparison/HeuristicLab.Analysis.FitnessLandscape/3.3/ProblemCharacteristicAnalysis/QAP/QAPDirectedWalk.cs
===================================================================
--- /branches/PerformanceComparison/HeuristicLab.Analysis.FitnessLandscape/3.3/ProblemCharacteristicAnalysis/QAP/QAPDirectedWalk.cs	(revision 14690)
+++ /branches/PerformanceComparison/HeuristicLab.Analysis.FitnessLandscape/3.3/ProblemCharacteristicAnalysis/QAP/QAPDirectedWalk.cs	(revision 14691)
@@ -79,5 +79,5 @@
     private QAPDirectedWalk(QAPDirectedWalk original, Cloner cloner) : base(original, cloner) { }
     public QAPDirectedWalk() {
-      characteristics.AddRange(new[] { "Swap2.Sharpness", "Swap2.Bumpiness", "Swap2.Flatness", "Swap2.Steadiness" }
+      characteristics.AddRange(new[] { "Swap2.Sharpness", "Swap2.Bumpiness", "Swap2.Flatness", /*"Swap2.Steadiness"*/ }
         .Select(x => new StringValue(x)).ToList());
       Parameters.Add(new FixedValueParameter<IntValue>("Paths", "The number of paths to explore (a path is a set of solutions that connect two randomly chosen solutions).", new IntValue(50)));
@@ -118,25 +118,11 @@
 
       var trajectories = Run(random, (QuadraticAssignmentProblem)Problem, permutations, BestImprovement).ToList();
-      var firstDerivatives = trajectories.Select(path => ApproximateDerivative(path).ToList()).ToList();
-      var secondDerivatives = firstDerivatives.Select(d1 => ApproximateDerivative(d1).ToList()).ToList();
+      var result = PermutationPathAnalysis.GetCharacteristics(trajectories);
       
-      var props = GetCharacteristics(trajectories, firstDerivatives, secondDerivatives).ToDictionary(x => x.Item1, x => x.Item2);
       foreach (var chara in characteristics.CheckedItems.Select(x => x.Value.Value)) {
-        if (chara == "Swap2.Sharpness") yield return new Result("Swap2.Sharpness", new DoubleValue(props["Sharpness"]));
-        if (chara == "Swap2.Bumpiness") yield return new Result("Swap2.Bumpiness", new DoubleValue(props["Bumpiness"]));
-        if (chara == "Swap2.Flatness") yield return new Result("Swap2.Flatness", new DoubleValue(props["Flatness"]));
-        if (chara == "Swap2.Steadiness") yield return new Result("Swap2.Steadiness", new DoubleValue(props["Steadiness"]));
-      }
-    }
-
-    public static IEnumerable<IResult> Calculate(List<List<Tuple<Permutation, double>>> trajectories) {
-      var firstDerivatives = trajectories.Select(path => ApproximateDerivative(path).ToList()).ToList();
-      var secondDerivatives = firstDerivatives.Select(d1 => ApproximateDerivative(d1).ToList()).ToList();
-
-      var props = GetCharacteristics(trajectories, firstDerivatives, secondDerivatives).ToDictionary(x => x.Item1, x => x.Item2);
-      yield return new Result("Swap2.Sharpness", new DoubleValue(props["Sharpness"]));
-      yield return new Result("Swap2.Bumpiness", new DoubleValue(props["Bumpiness"]));
-      yield return new Result("Swap2.Flatness", new DoubleValue(props["Flatness"]));
-      yield return new Result("Swap2.Steadiness", new DoubleValue(props["Steadiness"]));
+        if (chara == "Swap2.Sharpness") yield return new Result("Swap2.Sharpness", new DoubleValue(result.Sharpness));
+        if (chara == "Swap2.Bumpiness") yield return new Result("Swap2.Bumpiness", new DoubleValue(result.Bumpiness));
+        if (chara == "Swap2.Flatness") yield return new Result("Swap2.Flatness", new DoubleValue(result.Flatness));
+      }
     }
 
@@ -158,41 +144,5 @@
     }
 
-    private static IEnumerable<Tuple<string, double>> GetCharacteristics(List<List<Tuple<Permutation, double>>> f, List<List<Tuple<Permutation, double>>> f1, List<List<Tuple<Permutation, double>>> f2) {
-      var sharpness = f2.Average(x => Area(x));
-      var bumpiness = 0.0;
-      var flatness = 0.0;
-      var downPointing = f1.Where(x => x.Min(y => y.Item2) < 0).ToList();
-
-      var steadiness = 0.0;
-      foreach (var path in downPointing) {
-        steadiness += ComBelowZero(path);
-      }
-      if (downPointing.Count > 0) steadiness /= downPointing.Count;
-
-      for (var p = 0; p < f2.Count; p++) {
-        if (f2[p].Count <= 2) continue;
-        var bump = 0;
-        var flat = 0;
-        for (var i = 0; i < f2[p].Count - 1; i++) {
-          if ((f2[p][i].Item2 > 0 && f2[p][i + 1].Item2 < 0) || (f2[p][i].Item2 < 0 && f2[p][i + 1].Item2 > 0)) {
-            bump++;
-          } else if (f2[p][i].Item2 == 0) {
-            flat++;
-          }
-        }
-        bumpiness += bump / (f2[p].Count - 1.0);
-        flatness += flat / (f2[p].Count - 1.0);
-      }
-      bumpiness /= f2.Count;
-      flatness /= f2.Count;
-      return new[] {
-      Tuple.Create("Sharpness", sharpness),
-      Tuple.Create("Bumpiness", bumpiness),
-      Tuple.Create("Flatness", flatness),
-      Tuple.Create("Steadiness", steadiness)
-    };
-    }
-
-    public static IEnumerable<Tuple<Permutation, double>> BestDirectedWalk(QuadraticAssignmentProblem qap, Permutation start, Permutation end) {
+    private static IEnumerable<Tuple<Permutation, double>> BestDirectedWalk(QuadraticAssignmentProblem qap, Permutation start, Permutation end) {
       var N = qap.Weights.Rows;
       var sol = start;
@@ -225,5 +175,5 @@
     }
 
-    public static IEnumerable<Tuple<Permutation, double>> FirstDirectedWalk(IRandom random, QuadraticAssignmentProblem qap, Permutation start, Permutation end) {
+    private static IEnumerable<Tuple<Permutation, double>> FirstDirectedWalk(IRandom random, QuadraticAssignmentProblem qap, Permutation start, Permutation end) {
       var N = qap.Weights.Rows;
       var sol = start;
@@ -260,80 +210,4 @@
     }
 
-    private static double Area(IEnumerable<Tuple<Permutation, double>> path) {
-      var iter = path.GetEnumerator();
-      if (!iter.MoveNext()) return 0.0;
-      var area = 0.0;
-      var prev = iter.Current;
-      while (iter.MoveNext()) {
-        area += TrapezoidArea(prev, iter.Current);
-        prev = iter.Current;
-      }
-      return area;
-    }
-
-    private static double TrapezoidArea(Tuple<Permutation, double> a, Tuple<Permutation, double> b) {
-      var area = 0.0;
-      var dist = Dist(a.Item1, b.Item1);
-      if ((a.Item2 <= 0 && b.Item2 <= 0) || (a.Item2 >= 0 && b.Item2 >= 0))
-        area += dist * (Math.Abs(a.Item2) + Math.Abs(b.Item2)) / 2.0;
-      else {
-        var k = (b.Item2 - a.Item2) / dist;
-        var d = a.Item2;
-        var x = -d / k;
-        area += Math.Abs(x * a.Item2 / 2.0);
-        area += Math.Abs((dist - x) * b.Item2 / 2.0);
-      }
-      return area;
-    }
-
-    // Center-of-Mass
-    private static double ComBelowZero(IEnumerable<Tuple<Permutation, double>> path) {
-      var area = 0.0;
-      var com = 0.0;
-      var nwalkDist = 0.0;
-      Tuple<Permutation, double> prev = null;
-      var iter = path.GetEnumerator();
-      while (iter.MoveNext()) {
-        var c = iter.Current;
-        if (prev != null) {
-          var ndist = Dist(prev.Item1, c.Item1) / (double)c.Item1.Length;
-          nwalkDist += ndist;
-          if (prev.Item2 < 0 || c.Item2 < 0) {
-            var a = TrapezoidArea(prev, c) / (double)c.Item1.Length;
-            area += a;
-            com += (nwalkDist - (ndist / 2.0)) * a;
-          }
-        }
-        prev = c;
-      }
-      return com / area;
-    }
-
-    private static IEnumerable<Tuple<Permutation, double>> ApproximateDerivative(IEnumerable<Tuple<Permutation, double>> data) {
-      Tuple<Permutation, double> prev = null, prev2 = null;
-      foreach (var d in data) {
-        if (prev == null) {
-          prev = d;
-          continue;
-        }
-        if (prev2 == null) {
-          prev2 = prev;
-          prev = d;
-          continue;
-        }
-        var dist = Dist(prev2.Item1, d.Item1);
-        yield return Tuple.Create(prev.Item1, (d.Item2 - prev2.Item2) / (double)dist);
-        prev2 = prev;
-        prev = d;
-      }
-    }
-
-    private static double Dist(Permutation a, Permutation b) {
-      var dist = 0;
-      for (var i = 0; i < a.Length; i++)
-        if (a[i] != b[i]) dist++;
-      return dist;
-    }
-
     private static int[] GetInverse(Permutation p) {
       var inv = new int[p.Length];
Index: /branches/PerformanceComparison/HeuristicLab.Analysis.FitnessLandscape/3.3/ProblemInstanceAnalysis/ProblemInstanceAnalyzer.cs
===================================================================
--- /branches/PerformanceComparison/HeuristicLab.Analysis.FitnessLandscape/3.3/ProblemInstanceAnalysis/ProblemInstanceAnalyzer.cs	(revision 14690)
+++ /branches/PerformanceComparison/HeuristicLab.Analysis.FitnessLandscape/3.3/ProblemInstanceAnalysis/ProblemInstanceAnalyzer.cs	(revision 14691)
@@ -78,10 +78,17 @@
       if (currentCharacteristics == null) return base.Apply();
 
-      var order = Enumerable.Range(0, kbCharacteristics.Rows)
+      var means = kbCharacteristics.GetRow(kbCharacteristics.Rows - 2).ToArray();
+      var stdevs = kbCharacteristics.GetRow(kbCharacteristics.Rows - 1).ToArray();
+
+      for (var i = 0; i < means.Length; i++) {
+        currentCharacteristics[i] = (currentCharacteristics[i] - means[i]) / stdevs[i];
+      }
+
+      var order = Enumerable.Range(0, kbCharacteristics.Rows - 2)
         .Select(row => new { Row = row, MSE = kbCharacteristics.GetRow(row).Zip(currentCharacteristics, (a, b) => (a - b) * (a - b)).Average() })
         .OrderBy(x => x.MSE);
 
       var instances = kbCharacteristics.RowNames.ToList();
-      while (instances.Count < kbCharacteristics.Rows)
+      while (instances.Count < kbCharacteristics.Rows - 2)
         instances.Add(instances.Count.ToString(CultureInfo.CurrentCulture.NumberFormat));
 
Index: /branches/PerformanceComparison/HeuristicLab.Analysis.FitnessLandscape/3.3/ProblemInstanceAnalysis/QAPPRProblemInstanceAnalyzer.cs
===================================================================
--- /branches/PerformanceComparison/HeuristicLab.Analysis.FitnessLandscape/3.3/ProblemInstanceAnalysis/QAPPRProblemInstanceAnalyzer.cs	(revision 14690)
+++ /branches/PerformanceComparison/HeuristicLab.Analysis.FitnessLandscape/3.3/ProblemInstanceAnalysis/QAPPRProblemInstanceAnalyzer.cs	(revision 14691)
@@ -49,15 +49,5 @@
       if (trajectories.Count == 0) return null;
 
-      var characteristics = QAPDirectedWalk.Calculate(trajectories).Select(x => x.Value).ToList();
-      var result = new DoubleArray(characteristics.Count);
-      for (var i = 0; i < characteristics.Count; i++) {
-        var dv = characteristics[i] as DoubleValue;
-        if (dv != null) result[i] = dv.Value;
-        else {
-          var iv = characteristics[i] as IntValue;
-          if (iv != null) result[i] = iv.Value;
-        }
-      }
-      return result;
+      return new DoubleArray(PermutationPathAnalysis.GetCharacteristics(trajectories).GetValues().ToArray());
     }
   }
Index: /branches/PerformanceComparison/HeuristicLab.Problems.Instances.QAPLIB/3.3/DreznerQAPInstanceProvider.cs
===================================================================
--- /branches/PerformanceComparison/HeuristicLab.Problems.Instances.QAPLIB/3.3/DreznerQAPInstanceProvider.cs	(revision 14691)
+++ /branches/PerformanceComparison/HeuristicLab.Problems.Instances.QAPLIB/3.3/DreznerQAPInstanceProvider.cs	(revision 14691)
@@ -0,0 +1,49 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2016 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;
+
+namespace HeuristicLab.Problems.Instances.QAPLIB {
+  public class DreznerQAPInstanceProvider : QAPLIBInstanceProvider {
+    
+    public override string Name {
+      get { return "Drezner's QAP instances"; }
+    }
+
+    public override string Description {
+      get { return "QAP instances from Zvi Drezner"; }
+    }
+
+    public override Uri WebLink {
+      get { return new Uri("http://cbeweb-1.fullerton.edu/isds/zdrezner/programs.htm"); }
+    }
+
+    public override string ReferencePublication {
+      get {
+        return @"Z. Drezner, P.M. Hahn, E.D. Taillard. 2005.
+Recent Advances for the Quadratic Assignment Problem with Special Emphasis on Instances that are Difficult for Meta-heuristic Methods.
+Annals of Operations Research, 139, pp. 65–94.";
+      }
+    }
+
+    protected override string FileName { get { return "drezner"; } }
+  }
+}
Index: /branches/PerformanceComparison/HeuristicLab.Problems.Instances.QAPLIB/3.3/HeuristicLab.Problems.Instances.QAPLIB-3.3.csproj
===================================================================
--- /branches/PerformanceComparison/HeuristicLab.Problems.Instances.QAPLIB/3.3/HeuristicLab.Problems.Instances.QAPLIB-3.3.csproj	(revision 14691)
+++ /branches/PerformanceComparison/HeuristicLab.Problems.Instances.QAPLIB/3.3/HeuristicLab.Problems.Instances.QAPLIB-3.3.csproj	(revision 14691)
@@ -0,0 +1,183 @@
+﻿<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProductVersion>8.0.30703</ProductVersion>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{73F29D43-5714-4069-8FAB-0D18FEB5F175}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>HeuristicLab.Problems.Instances.QAPLIB</RootNamespace>
+    <AssemblyName>HeuristicLab.Problems.Instances.QAPLIB-3.3</AssemblyName>
+    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+    <TargetFrameworkProfile />
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>..\..\..\..\trunk\sources\bin\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <Prefer32Bit>false</Prefer32Bit>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>..\..\..\..\trunk\sources\bin\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <Prefer32Bit>false</Prefer32Bit>
+  </PropertyGroup>
+  <PropertyGroup>
+    <SignAssembly>true</SignAssembly>
+  </PropertyGroup>
+  <PropertyGroup>
+    <AssemblyOriginatorKeyFile>HeuristicLab.snk</AssemblyOriginatorKeyFile>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
+    <DebugSymbols>true</DebugSymbols>
+    <OutputPath>..\..\..\..\trunk\sources\bin\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <DebugType>full</DebugType>
+    <PlatformTarget>x64</PlatformTarget>
+    <CodeAnalysisLogFile>..\..\bin\HeuristicLab.Problems.Instances.QAPLIB-3.3.dll.CodeAnalysisLog.xml</CodeAnalysisLogFile>
+    <CodeAnalysisUseTypeNameInSuppression>true</CodeAnalysisUseTypeNameInSuppression>
+    <CodeAnalysisModuleSuppressionsFile>GlobalSuppressions.cs</CodeAnalysisModuleSuppressionsFile>
+    <ErrorReport>prompt</ErrorReport>
+    <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
+    <CodeAnalysisRuleSetDirectories>;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets</CodeAnalysisRuleSetDirectories>
+    <CodeAnalysisIgnoreBuiltInRuleSets>false</CodeAnalysisIgnoreBuiltInRuleSets>
+    <CodeAnalysisRuleDirectories>;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules</CodeAnalysisRuleDirectories>
+    <CodeAnalysisIgnoreBuiltInRules>false</CodeAnalysisIgnoreBuiltInRules>
+    <Prefer32Bit>false</Prefer32Bit>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
+    <OutputPath>..\..\..\..\trunk\sources\bin\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <Optimize>true</Optimize>
+    <DebugType>pdbonly</DebugType>
+    <PlatformTarget>x64</PlatformTarget>
+    <CodeAnalysisLogFile>..\..\bin\HeuristicLab.Problems.Instances.QAPLIB-3.3.dll.CodeAnalysisLog.xml</CodeAnalysisLogFile>
+    <CodeAnalysisUseTypeNameInSuppression>true</CodeAnalysisUseTypeNameInSuppression>
+    <CodeAnalysisModuleSuppressionsFile>GlobalSuppressions.cs</CodeAnalysisModuleSuppressionsFile>
+    <ErrorReport>prompt</ErrorReport>
+    <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
+    <CodeAnalysisRuleSetDirectories>;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets</CodeAnalysisRuleSetDirectories>
+    <CodeAnalysisIgnoreBuiltInRuleSets>false</CodeAnalysisIgnoreBuiltInRuleSets>
+    <CodeAnalysisRuleDirectories>;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules</CodeAnalysisRuleDirectories>
+    <CodeAnalysisIgnoreBuiltInRules>false</CodeAnalysisIgnoreBuiltInRules>
+    <Prefer32Bit>false</Prefer32Bit>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
+    <DebugSymbols>true</DebugSymbols>
+    <OutputPath>..\..\..\..\trunk\sources\bin\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <DebugType>full</DebugType>
+    <PlatformTarget>x86</PlatformTarget>
+    <CodeAnalysisLogFile>..\..\bin\HeuristicLab.Problems.Instances.QAPLIB-3.3.dll.CodeAnalysisLog.xml</CodeAnalysisLogFile>
+    <CodeAnalysisUseTypeNameInSuppression>true</CodeAnalysisUseTypeNameInSuppression>
+    <CodeAnalysisModuleSuppressionsFile>GlobalSuppressions.cs</CodeAnalysisModuleSuppressionsFile>
+    <ErrorReport>prompt</ErrorReport>
+    <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
+    <CodeAnalysisRuleSetDirectories>;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets</CodeAnalysisRuleSetDirectories>
+    <CodeAnalysisIgnoreBuiltInRuleSets>false</CodeAnalysisIgnoreBuiltInRuleSets>
+    <CodeAnalysisRuleDirectories>;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules</CodeAnalysisRuleDirectories>
+    <CodeAnalysisIgnoreBuiltInRules>false</CodeAnalysisIgnoreBuiltInRules>
+    <Prefer32Bit>false</Prefer32Bit>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
+    <OutputPath>..\..\..\..\trunk\sources\bin\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <Optimize>true</Optimize>
+    <DebugType>pdbonly</DebugType>
+    <PlatformTarget>x86</PlatformTarget>
+    <CodeAnalysisLogFile>..\..\bin\HeuristicLab.Problems.Instances.QAPLIB-3.3.dll.CodeAnalysisLog.xml</CodeAnalysisLogFile>
+    <CodeAnalysisUseTypeNameInSuppression>true</CodeAnalysisUseTypeNameInSuppression>
+    <CodeAnalysisModuleSuppressionsFile>GlobalSuppressions.cs</CodeAnalysisModuleSuppressionsFile>
+    <ErrorReport>prompt</ErrorReport>
+    <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
+    <CodeAnalysisRuleSetDirectories>;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets</CodeAnalysisRuleSetDirectories>
+    <CodeAnalysisIgnoreBuiltInRuleSets>false</CodeAnalysisIgnoreBuiltInRuleSets>
+    <CodeAnalysisRuleDirectories>;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules</CodeAnalysisRuleDirectories>
+    <CodeAnalysisIgnoreBuiltInRules>false</CodeAnalysisIgnoreBuiltInRules>
+    <Prefer32Bit>false</Prefer32Bit>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="HeuristicLab.Common-3.3, Version=3.3.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\..\trunk\sources\bin\HeuristicLab.Common-3.3.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.PluginInfrastructure-3.3, Version=3.3.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\..\trunk\sources\bin\HeuristicLab.PluginInfrastructure-3.3.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.Problems.Instances-3.3, Version=3.3.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\..\trunk\sources\bin\HeuristicLab.Problems.Instances-3.3.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="System" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Data" />
+    <Reference Include="System.IO.Compression" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="OneSizeDataDescriptor.cs" />
+    <Compile Include="OneSizeInstanceProvider.cs" />
+    <Compile Include="TaillardQAPInstanceProvider.cs" />
+    <Compile Include="DreznerQAPInstanceProvider.cs" />
+    <Compile Include="MicroarrayQAPInstanceProvider.cs" />
+    <Compile Include="QAPLIBParser.cs" />
+    <Compile Include="QAPLIBDataDescriptor.cs" />
+    <Compile Include="QAPLIBSolutionParser.cs" />
+    <Compile Include="QAPLIBInstanceProvider.cs" />
+    <EmbeddedResource Include="Data\qap.dat.zip" />
+    <EmbeddedResource Include="Data\qap.sln.zip" />
+    <EmbeddedResource Include="Data\microarray.dat.zip" />
+    <EmbeddedResource Include="Data\microarray.sln.zip" />
+    <EmbeddedResource Include="Data\drezner.dat.zip" />
+    <EmbeddedResource Include="Data\drezner.sln.zip" />
+    <EmbeddedResource Include="Data\taillard.dat.zip" />
+    <EmbeddedResource Include="Data\taillard.sln.zip" />
+    <None Include="Plugin.cs.frame" />
+    <Compile Include="Plugin.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <None Include="Properties\AssemblyInfo.cs.frame" />
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="HeuristicLab.snk" />
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <PropertyGroup>
+    <PreBuildEvent Condition=" '$(OS)' == 'Windows_NT' ">set Path=%25Path%25;$(ProjectDir);$(SolutionDir)
+set ProjectDir=$(ProjectDir)
+set SolutionDir=$(SolutionDir)
+set Outdir=$(Outdir)
+
+call PreBuildEvent.cmd</PreBuildEvent>
+    <PreBuildEvent Condition=" '$(OS)' != 'Windows_NT' ">
+export ProjectDir=$(ProjectDir)
+export SolutionDir=$(SolutionDir)
+
+$SolutionDir/PreBuildEvent.sh
+</PreBuildEvent>
+  </PropertyGroup>
+  <PropertyGroup>
+    <PostBuildEvent>
+    </PostBuildEvent>
+  </PropertyGroup>
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+</Project>
Index: /branches/PerformanceComparison/HeuristicLab.Problems.Instances.QAPLIB/3.3/MicroarrayQAPInstanceProvider.cs
===================================================================
--- /branches/PerformanceComparison/HeuristicLab.Problems.Instances.QAPLIB/3.3/MicroarrayQAPInstanceProvider.cs	(revision 14691)
+++ /branches/PerformanceComparison/HeuristicLab.Problems.Instances.QAPLIB/3.3/MicroarrayQAPInstanceProvider.cs	(revision 14691)
@@ -0,0 +1,51 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2016 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;
+
+namespace HeuristicLab.Problems.Instances.QAPLIB {
+  public class MicroarrayQAPInstanceProvider : QAPLIBInstanceProvider {
+    
+    public override string Name {
+      get { return "Microarray QAP"; }
+    }
+
+    public override string Description {
+      get { return "Microarray placement problems (QAPLIB format)"; }
+    }
+
+    public override Uri WebLink {
+      get { return new Uri("http://www.rahmannlab.de/research/microarray-design"); }
+    }
+
+    public override string ReferencePublication {
+      get {
+        return @"S.A. de Carvalho Jr, S. Rahmann. 2006.
+Microarray layout as a quadratic assignment problem.
+D. Huson, O. Kohlbacher, A. Lupas, K. Nieselt, A. Zell (Eds.),
+Proceedings of the German Conference on Bioinformatics, vol. 83, pp. 11-20.
+Gesellschaft für Informatik Bonn, Germany.";
+      }
+    }
+
+    protected override string FileName { get { return "microarray"; } }
+  }
+}
Index: /branches/PerformanceComparison/HeuristicLab.Problems.Instances.QAPLIB/3.3/OneSizeDataDescriptor.cs
===================================================================
--- /branches/PerformanceComparison/HeuristicLab.Problems.Instances.QAPLIB/3.3/OneSizeDataDescriptor.cs	(revision 14691)
+++ /branches/PerformanceComparison/HeuristicLab.Problems.Instances.QAPLIB/3.3/OneSizeDataDescriptor.cs	(revision 14691)
@@ -0,0 +1,18 @@
+﻿
+namespace HeuristicLab.Problems.Instances.QAPLIB {
+  internal class OneSizeDataDescriptor : IDataDescriptor {
+    public string Name { get; internal set; }
+    public string Description { get; internal set; }
+
+    internal ProblemInstanceProvider<QAPData> ActualProvider { get; set; }
+    internal IDataDescriptor ActualDescriptor { get; set; }
+    
+    internal OneSizeDataDescriptor(string name, string description,
+      ProblemInstanceProvider<QAPData> actualProvider, IDataDescriptor actualDescriptor) {
+      this.Name = name;
+      this.Description = description;
+      this.ActualProvider = actualProvider;
+      this.ActualDescriptor = actualDescriptor;
+    }
+  }
+}
Index: /branches/PerformanceComparison/HeuristicLab.Problems.Instances.QAPLIB/3.3/OneSizeInstanceProvider.cs
===================================================================
--- /branches/PerformanceComparison/HeuristicLab.Problems.Instances.QAPLIB/3.3/OneSizeInstanceProvider.cs	(revision 14691)
+++ /branches/PerformanceComparison/HeuristicLab.Problems.Instances.QAPLIB/3.3/OneSizeInstanceProvider.cs	(revision 14691)
@@ -0,0 +1,82 @@
+﻿using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace HeuristicLab.Problems.Instances.QAPLIB {
+  public class OneSizeInstanceProvider : ProblemInstanceProvider<QAPData> {
+    public override IEnumerable<IDataDescriptor> GetDataDescriptors() {
+      var drezner = new DreznerQAPInstanceProvider();
+      foreach (var desc in drezner.GetDataDescriptors())
+        yield return new OneSizeDataDescriptor(desc.Name + "-25", desc.Description, drezner, desc);
+      var microarray = new MicroarrayQAPInstanceProvider();
+      foreach (var desc in microarray.GetDataDescriptors())
+        yield return new OneSizeDataDescriptor(desc.Name + "-25", desc.Description, microarray, desc);
+      var qaplib = new QAPLIBInstanceProvider();
+      foreach (var desc in qaplib.GetDataDescriptors())
+        yield return new OneSizeDataDescriptor(desc.Name + "-25", desc.Description, qaplib, desc);
+      var taillard = new TaillardQAPInstanceProvider();
+      foreach (var desc in taillard.GetDataDescriptors())
+        yield return new OneSizeDataDescriptor(desc.Name + "-25", desc.Description, taillard, desc);
+    }
+
+    public override QAPData LoadData(IDataDescriptor descriptor) {
+      var desc = (OneSizeDataDescriptor)descriptor;
+      var data = desc.ActualProvider.LoadData(desc.ActualDescriptor);
+      data.BestKnownAssignment = null;
+      data.BestKnownQuality = null;
+      if (data.Dimension <= 25) {
+        return data;
+      }
+      var rand = new Random(data.Dimension);
+
+      var tmp = Enumerable.Range(0, data.Dimension).ToArray();
+      Shuffle(tmp, rand);
+      var throwAway = new bool[data.Dimension];
+      foreach (var t in tmp.Take(data.Dimension - 25))
+        throwAway[t] = true;
+
+      var weights = new double[25, 25];
+      var distances = new double[25, 25];
+      var k = 0;
+      for (var i = 0; i < data.Dimension; i++) {
+        if (throwAway[i]) continue;
+        var h = 0;
+        for (var j = 0; j < data.Dimension; j++) {
+          if (throwAway[j]) continue;
+          weights[k, h] = data.Weights[i, j];
+          distances[k, h] = data.Distances[i, j];
+          h++;
+        }
+        k++;
+      }
+
+      data.Weights = weights;
+      data.Distances = distances;
+      data.BestKnownAssignment = null;
+      data.BestKnownQuality = null;
+      data.Dimension = 25;
+      data.Name += "-25";
+      data.Description += " (reduced or enlarged to 25 dimensions)";
+
+      return data;
+    }
+
+    public override string Name { get { return "One Size"; } }
+    public override string Description { get { return string.Empty; } }
+    public override Uri WebLink { get { return null; } }
+    public override string ReferencePublication { get { return string.Empty; } }
+
+    // permutation must be strictly different in every position
+    private static void Shuffle(int[] p, Random random) {
+      for (var i = p.Length - 1; i > 0; i--) {
+        // Swap element "i" with a random earlier element (excluding itself)
+        var swapIndex = random.Next(i + 1);
+        var h = p[swapIndex];
+        p[swapIndex] = p[i];
+        p[i] = h;
+      }
+    }
+  }
+}
Index: /branches/PerformanceComparison/HeuristicLab.Problems.Instances.QAPLIB/3.3/Plugin.cs.frame
===================================================================
--- /branches/PerformanceComparison/HeuristicLab.Problems.Instances.QAPLIB/3.3/Plugin.cs.frame	(revision 14691)
+++ /branches/PerformanceComparison/HeuristicLab.Problems.Instances.QAPLIB/3.3/Plugin.cs.frame	(revision 14691)
@@ -0,0 +1,30 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2016 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.PluginInfrastructure;
+
+namespace HeuristicLab.Problems.Instances {
+  [Plugin("HeuristicLab.Problems.Instances.QAPLIB", "3.3.14.$WCREV$")]
+  [PluginFile("HeuristicLab.Problems.Instances.QAPLIB-3.3.dll", PluginFileType.Assembly)]
+  [PluginDependency("HeuristicLab.Problems.Instances", "3.3")]
+  public class HeuristicLabProblemsInstancesQAPLIBPlugin : PluginBase {
+  }
+}
Index: /branches/PerformanceComparison/HeuristicLab.Problems.Instances.QAPLIB/3.3/Properties/AssemblyInfo.cs.frame
===================================================================
--- /branches/PerformanceComparison/HeuristicLab.Problems.Instances.QAPLIB/3.3/Properties/AssemblyInfo.cs.frame	(revision 14691)
+++ /branches/PerformanceComparison/HeuristicLab.Problems.Instances.QAPLIB/3.3/Properties/AssemblyInfo.cs.frame	(revision 14691)
@@ -0,0 +1,57 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2016 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.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following 
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("HeuristicLab.Problems.Instances.QAPLIB")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("HEAL")]
+[assembly: AssemblyProduct("HeuristicLab")]
+[assembly: AssemblyCopyright("(c) 2002-2016 HEAL")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible 
+// to COM components.  If you need to access a type in this assembly from 
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("7c14407e-6980-465b-ba3a-4a916d48989b")]
+
+// Version information for an assembly consists of the following four values:
+//
+//      Major Version
+//      Minor Version 
+//      Build Number
+//      Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers 
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("3.3.0.0")]
+[assembly: AssemblyFileVersion("3.3.14.$WCREV$")]
Index: /branches/PerformanceComparison/HeuristicLab.Problems.Instances.QAPLIB/3.3/QAPLIBDataDescriptor.cs
===================================================================
--- /branches/PerformanceComparison/HeuristicLab.Problems.Instances.QAPLIB/3.3/QAPLIBDataDescriptor.cs	(revision 14691)
+++ /branches/PerformanceComparison/HeuristicLab.Problems.Instances.QAPLIB/3.3/QAPLIBDataDescriptor.cs	(revision 14691)
@@ -0,0 +1,37 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2016 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
+
+namespace HeuristicLab.Problems.Instances.QAPLIB {
+  internal class QAPLIBDataDescriptor : IDataDescriptor {
+    public string Name { get; internal set; }
+    public string Description { get; internal set; }
+
+    internal string InstanceIdentifier { get; set; }
+    internal string SolutionIdentifier { get; set; }
+
+    internal QAPLIBDataDescriptor(string name, string description, string instanceIdentifier, string solutionIdentifier) {
+      this.Name = name;
+      this.Description = description;
+      this.InstanceIdentifier = instanceIdentifier;
+      this.SolutionIdentifier = solutionIdentifier;
+    }
+  }
+}
Index: /branches/PerformanceComparison/HeuristicLab.Problems.Instances.QAPLIB/3.3/QAPLIBInstanceProvider.cs
===================================================================
--- /branches/PerformanceComparison/HeuristicLab.Problems.Instances.QAPLIB/3.3/QAPLIBInstanceProvider.cs	(revision 14691)
+++ /branches/PerformanceComparison/HeuristicLab.Problems.Instances.QAPLIB/3.3/QAPLIBInstanceProvider.cs	(revision 14691)
@@ -0,0 +1,261 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2016 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.IO;
+using System.IO.Compression;
+using System.Linq;
+using System.Reflection;
+using System.Text.RegularExpressions;
+
+namespace HeuristicLab.Problems.Instances.QAPLIB {
+  public class QAPLIBInstanceProvider : ProblemInstanceProvider<QAPData> {
+    #region Reversed instances
+    // These instances specified their best known solution in the wrong order
+    protected virtual HashSet<string> ReversedSolutions {
+      get {
+        return new HashSet<string>(new string[] {
+              "bur26a",
+              "bur26b",
+              "bur26c",
+              "bur26d",
+              "bur26e",
+              "bur26f",
+              "bur26g",
+              "bur26h",
+              "chr12a",
+              "chr12b",
+              "chr12c",
+              "chr15a",
+              "chr15b",
+              "chr15c",
+              "chr18a",
+              "chr18b",
+              "chr20a",
+              "chr20b",
+              "chr20c",
+              "chr22a",
+              "chr22b",
+              "chr25a",
+              "esc16a",
+              "esc16b",
+              "esc16c",
+              "esc16d",
+              "esc16e",
+              "esc16g",
+              "esc16h",
+              "esc16i",
+              "esc16j",
+              "esc32a",
+              "esc32b",
+              "esc32c",
+              "esc32d",
+              "esc32e",
+              "esc32f",
+              "esc32g",
+              "esc32h",
+              "had12",
+              "had14",
+              "had16",
+              "had18",
+              "had20",
+              "kra32",
+              "lipa20a",
+              "lipa30a",
+              "lipa40a",
+              "lipa50a",
+              "lipa60a",
+              "lipa70a",
+              "lipa80a",
+              "lipa90a",
+              "nug12",
+              "nug14",
+              "nug15",
+              "nug16a",
+              "nug16b",
+              "nug17",
+              "nug18",
+              "nug20",
+              "nug21",
+              "nug22",
+              "nug24",
+              "nug25",
+              "nug27",
+              "nug28",
+              "rou12",
+              "rou15",
+              "rou20",
+              "scr12",
+              "scr15",
+              "scr20",
+              "sko100a",
+              "sko100b",
+              "sko100c",
+              "sko100d",
+              "sko100e",
+              "sko100f",
+              "sko49",
+              "sko81",
+              "sko90",
+              "ste36a",
+              "ste36b",
+              "tai100a",
+              "tai100b",
+              "tai12a",
+              "tai12b",
+              "tai150b",
+              "tai15a",
+              "tai15b",
+              "tai17a",
+              "tai20a",
+              "tai20b",
+              "tai256c",
+              "tai25a",
+              "tai25b",
+              "tai30a",
+              "tai30b",
+              "tai35a",
+              "tai35b",
+              "tai40a",
+              "tai40b",
+              "tai50a",
+              "tai50b",
+              "tai60a",
+              "tai60b",
+              "tai64c",
+              "tai80a",
+              "tai80b",
+              "wil100"
+        });
+      }
+    }
+    #endregion
+
+    public override string Name {
+      get { return "QAPLIB"; }
+    }
+
+    public override string Description {
+      get { return "Quadratic Assignment Problem Library"; }
+    }
+
+    public override Uri WebLink {
+      get { return new Uri("http://www.seas.upenn.edu/qaplib/"); }
+    }
+
+    public override string ReferencePublication {
+      get {
+        return @"R. E. Burkard, S. E. Karisch, and F. Rendl. 1997.
+QAPLIB - A Quadratic Assignment Problem Library.
+Journal of Global Optimization, 10, pp. 391-403.";
+      }
+    }
+
+    protected virtual string FileName { get { return "qap"; } }
+
+    public override IEnumerable<IDataDescriptor> GetDataDescriptors() {
+      Dictionary<string, string> solutions = new Dictionary<string, string>();
+      var solutionsArchiveName = GetResourceName(FileName + @"\.sln\.zip");
+      if (!String.IsNullOrEmpty(solutionsArchiveName)) {
+        using (var solutionsZipFile = new ZipArchive(GetType().Assembly.GetManifestResourceStream(solutionsArchiveName), ZipArchiveMode.Read)) {
+          foreach (var entry in solutionsZipFile.Entries)
+            solutions.Add(Path.GetFileNameWithoutExtension(entry.Name) + ".dat", entry.Name);
+        }
+      }
+      var instanceArchiveName = GetResourceName(FileName + @"\.dat\.zip");
+      if (String.IsNullOrEmpty(instanceArchiveName)) yield break;
+
+      using (var instanceStream = new ZipArchive(GetType().Assembly.GetManifestResourceStream(instanceArchiveName), ZipArchiveMode.Read)) {
+        foreach (var entry in instanceStream.Entries.Select(x => x.Name).OrderBy(x => x)) {
+          yield return new QAPLIBDataDescriptor(Path.GetFileNameWithoutExtension(entry), GetDescription(), entry, solutions.ContainsKey(entry) ? solutions[entry] : String.Empty);
+        }
+      }
+    }
+
+    public override QAPData LoadData(IDataDescriptor id) {
+      var descriptor = (QAPLIBDataDescriptor)id;
+      var instanceArchiveName = GetResourceName(FileName + @"\.dat\.zip");
+      using (var instancesZipFile = new ZipArchive(GetType().Assembly.GetManifestResourceStream(instanceArchiveName), ZipArchiveMode.Read)) {
+        var entry = instancesZipFile.GetEntry(descriptor.InstanceIdentifier);
+
+        using (var stream = entry.Open()) {
+          var parser = new QAPLIBParser();
+          parser.Parse(stream);
+          var instance = Load(parser);
+          instance.Name = id.Name;
+          instance.Description = id.Description;
+
+          if (!String.IsNullOrEmpty(descriptor.SolutionIdentifier)) {
+            var solutionsArchiveName = GetResourceName(FileName + @"\.sln\.zip");
+            using (var solutionsZipFile = new ZipArchive(GetType().Assembly.GetManifestResourceStream(solutionsArchiveName), ZipArchiveMode.Read)) {
+              entry = solutionsZipFile.GetEntry(descriptor.SolutionIdentifier);
+              using (var solStream = entry.Open()) {
+                var slnParser = new QAPLIBSolutionParser();
+                slnParser.Parse(solStream, true);
+                if (slnParser.Error != null) throw slnParser.Error;
+
+                int[] assignment = slnParser.Assignment;
+                if (assignment != null && ReversedSolutions.Contains(instance.Name)) {
+                  assignment = (int[])slnParser.Assignment.Clone();
+                  for (int i = 0; i < assignment.Length; i++)
+                    assignment[slnParser.Assignment[i]] = i;
+                }
+                instance.BestKnownAssignment = assignment;
+                instance.BestKnownQuality = slnParser.Quality;
+              }
+            }
+          }
+          return instance;
+        }
+      }
+    }
+
+    public override bool CanImportData {
+      get { return true; }
+    }
+    public override QAPData ImportData(string path) {
+      var parser = new QAPLIBParser();
+      parser.Parse(path);
+      var instance = Load(parser);
+      instance.Name = Path.GetFileName(path);
+      instance.Description = "Loaded from file \"" + path + "\" on " + DateTime.Now.ToString();
+      return instance;
+    }
+
+    private QAPData Load(QAPLIBParser parser) {
+      var instance = new QAPData();
+      instance.Dimension = parser.Size;
+      instance.Distances = parser.Distances;
+      instance.Weights = parser.Weights;
+      return instance;
+    }
+
+    private string GetDescription() {
+      return "Embedded instance of plugin version " + Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyFileVersionAttribute), true).Cast<AssemblyFileVersionAttribute>().First().Version + ".";
+    }
+
+    protected virtual string GetResourceName(string fileName) {
+      return Assembly.GetExecutingAssembly().GetManifestResourceNames()
+              .Where(x => Regex.Match(x, @".*\.Data\." + fileName).Success).SingleOrDefault();
+    }
+  }
+}
Index: /branches/PerformanceComparison/HeuristicLab.Problems.Instances.QAPLIB/3.3/QAPLIBParser.cs
===================================================================
--- /branches/PerformanceComparison/HeuristicLab.Problems.Instances.QAPLIB/3.3/QAPLIBParser.cs	(revision 14691)
+++ /branches/PerformanceComparison/HeuristicLab.Problems.Instances.QAPLIB/3.3/QAPLIBParser.cs	(revision 14691)
@@ -0,0 +1,85 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2016 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.IO;
+
+namespace HeuristicLab.Problems.Instances.QAPLIB {
+  public class QAPLIBParser {
+    public int Size { get; private set; }
+    public double[,] Distances { get; private set; }
+    public double[,] Weights { get; private set; }
+
+    public QAPLIBParser() {
+      Reset();
+    }
+
+    public void Reset() {
+      Size = 0;
+      Distances = null;
+      Weights = null;
+    }
+
+    public void Parse(string file) {
+      using (Stream stream = new FileStream(file, FileMode.Open, FileAccess.Read)) {
+        Parse(stream);
+      }
+    }
+
+    /// <summary>
+    /// Reads from the given stream data which is expected to be in the QAPLIB format.
+    /// </summary>
+    /// <remarks>
+    /// The stream is not closed or disposed. The caller has to take care of that.
+    /// </remarks>
+    /// <param name="stream">The stream to read data from.</param>
+    /// <returns>True if the file was successfully read or false otherwise.</returns>
+    public void Parse(Stream stream) {
+      var reader = new StreamReader(stream);
+      Size = int.Parse(reader.ReadLine());
+      Distances = new double[Size, Size];
+      Weights = new double[Size, Size];
+      char[] delim = new char[] { ' ', '\t' };
+
+      Weights = ParseMatrix(reader, delim);
+      Distances = ParseMatrix(reader, delim);
+    }
+
+    private double[,] ParseMatrix(StreamReader reader, char[] delim) {
+      int read = 0, k = 0;
+      double[,] result = new double[Size, Size];
+      while (k < Size) {
+        if (reader.EndOfStream) throw new InvalidDataException("Reached end of stream while reading second matrix.");
+        string valLine = reader.ReadLine();
+        while (String.IsNullOrWhiteSpace(valLine)) valLine = reader.ReadLine();
+        string[] vals = valLine.Split(delim, StringSplitOptions.RemoveEmptyEntries);
+        foreach (string val in vals) {
+          result[k, read++] = double.Parse(val);
+          if (read == Size) {
+            read = 0;
+            k++;
+          }
+        }
+      }
+      return result;
+    }
+  }
+}
Index: /branches/PerformanceComparison/HeuristicLab.Problems.Instances.QAPLIB/3.3/QAPLIBSolutionParser.cs
===================================================================
--- /branches/PerformanceComparison/HeuristicLab.Problems.Instances.QAPLIB/3.3/QAPLIBSolutionParser.cs	(revision 14691)
+++ /branches/PerformanceComparison/HeuristicLab.Problems.Instances.QAPLIB/3.3/QAPLIBSolutionParser.cs	(revision 14691)
@@ -0,0 +1,110 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2016 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.Globalization;
+using System.IO;
+using System.Linq;
+
+namespace HeuristicLab.Problems.Instances.QAPLIB {
+  public class QAPLIBSolutionParser {
+    public int Size { get; private set; }
+    public int[] Assignment { get; private set; }
+    public double Quality { get; private set; }
+    public Exception Error { get; private set; }
+
+    public QAPLIBSolutionParser() {
+      Reset();
+    }
+
+    public void Reset() {
+      Size = 0;
+      Assignment = null;
+      Quality = double.NaN;
+      Error = null;
+    }
+
+    /// <summary>
+    /// Reads from the given stream data which is expected to be in the QAPLIB solution format.
+    /// 
+    /// The QAPLIB solution file format (.sln) is as follows:
+    /// First line: Size of the permutation followed by a blank followed by the quality formatted using no thousands separator and if a fractional number with the "." as decimal symbol
+    /// Remaining lines: The values of the permutation separated by blanks. Values must lie in the range [1;size of the permutation].
+    /// </summary>
+    /// <param name="file">The file to read data from.</param>
+    /// <param name="valueAsLocation">The numbers can be interpreted either as facilities or locations.
+    /// HeuristicLab always encodes the permutation such that the index denotes the facility and the value the location.
+    /// If this parameter is true, then the permutation is expected to follow this encoding.
+    /// If this parameter is false, the meaning of value and index will be swapped when reading the permutation.</param>
+    /// <returns></returns>
+    public bool Parse(string file, bool valueAsLocation) {
+      using (Stream stream = new FileStream(file, FileMode.Open, FileAccess.Read)) {
+        return Parse(stream, valueAsLocation);
+      }
+    }
+
+    /// <summary>
+    /// Reads from the given stream data which is expected to be in the QAPLIB solution format.
+    /// 
+    /// The QAPLIB solution file format (.sln) is as follows:
+    /// First line: Size of the permutation followed by a blank followed by the quality formatted using no thousands separator and if a fractional number with the "." as decimal symbol
+    /// Remaining lines: The values of the permutation separated by blanks. Values must lie in the range [1;size of the permutation].
+    /// </summary>
+    /// <remarks>
+    /// The stream is not closed or disposed. The caller has to take care of that.
+    /// </remarks>
+    /// <param name="stream">The stream to read data from.</param>
+    /// <param name="valueAsLocation">The numbers can be interpreted either as facilities or locations.
+    /// HeuristicLab always encodes the permutation such that the index denotes the facility and the value the location.
+    /// If this parameter is true, then the permutation is expected to follow this encoding.
+    /// If this parameter is false, the meaning of value and index will be swapped when reading the permutation.</param>
+    /// <returns>True if the file was successfully read or false otherwise.</returns>
+    public bool Parse(Stream stream, bool valueAsLocation) {
+      Error = null;
+      try {
+        StreamReader reader = new StreamReader(stream);
+        char[] delim = new char[] { ' ', '\t', ',' }; // comma is added for nug30.sln which is the only file that separates the permutation with commas
+        string[] firstline = reader.ReadLine().Split(delim, StringSplitOptions.RemoveEmptyEntries);
+        Size = int.Parse(firstline[0]);
+        Quality = double.Parse(firstline[1], CultureInfo.InvariantCulture.NumberFormat);
+        Assignment = new int[Size];
+        int read = 0;
+        while (!reader.EndOfStream) {
+          string valLine = reader.ReadLine();
+          string[] vals = valLine.Split(delim, StringSplitOptions.RemoveEmptyEntries);
+          int start = 1;
+          if (vals.Any(x => x == "0")) start = 0;
+          if (vals.Length == 0) continue;
+          for (int j = 0; j < vals.Length; j++) {
+            if (valueAsLocation)
+              Assignment[int.Parse(vals[j]) - start] = read++;
+            else Assignment[read++] = int.Parse(vals[j]) - start;
+          }
+        }
+        if (read < Size) Assignment = null;
+        return true;
+      } catch (Exception e) {
+        Error = e;
+        return false;
+      }
+    }
+  }
+}
Index: /branches/PerformanceComparison/HeuristicLab.Problems.Instances.QAPLIB/3.3/TaillardQAPInstanceProvider.cs
===================================================================
--- /branches/PerformanceComparison/HeuristicLab.Problems.Instances.QAPLIB/3.3/TaillardQAPInstanceProvider.cs	(revision 14691)
+++ /branches/PerformanceComparison/HeuristicLab.Problems.Instances.QAPLIB/3.3/TaillardQAPInstanceProvider.cs	(revision 14691)
@@ -0,0 +1,47 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2016 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;
+
+namespace HeuristicLab.Problems.Instances.QAPLIB {
+  public class TaillardQAPInstanceProvider : QAPLIBInstanceProvider {
+    
+    public override string Name {
+      get { return "Taillard's QAP instances"; }
+    }
+
+    public override string Description {
+      get { return "Additional QAP instances from Eric Taillard"; }
+    }
+
+    public override Uri WebLink {
+      get { return new Uri("http://mistic.heig-vd.ch/taillard/problemes.dir/qap.dir/qap.html"); }
+    }
+
+    public override string ReferencePublication {
+      get {
+        return String.Empty;
+      }
+    }
+
+    protected override string FileName { get { return "taillard"; } }
+  }
+}
Index: /branches/PerformanceComparison/PerformanceComparison.sln
===================================================================
--- /branches/PerformanceComparison/PerformanceComparison.sln	(revision 14690)
+++ /branches/PerformanceComparison/PerformanceComparison.sln	(revision 14691)
@@ -25,4 +25,6 @@
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HeuristicLab.Algorithms.DataAnalysis-3.4", "HeuristicLab.Algorithms.DataAnalysis\3.4\HeuristicLab.Algorithms.DataAnalysis-3.4.csproj", "{2E782078-FA81-4B70-B56F-74CE38DAC6C8}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HeuristicLab.Problems.Instances.QAPLIB-3.3", "HeuristicLab.Problems.Instances.QAPLIB\3.3\HeuristicLab.Problems.Instances.QAPLIB-3.3.csproj", "{73F29D43-5714-4069-8FAB-0D18FEB5F175}"
 EndProject
 Global
@@ -168,4 +170,16 @@
 		{2E782078-FA81-4B70-B56F-74CE38DAC6C8}.Release|x86.ActiveCfg = Release|x86
 		{2E782078-FA81-4B70-B56F-74CE38DAC6C8}.Release|x86.Build.0 = Release|x86
+		{73F29D43-5714-4069-8FAB-0D18FEB5F175}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{73F29D43-5714-4069-8FAB-0D18FEB5F175}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{73F29D43-5714-4069-8FAB-0D18FEB5F175}.Debug|x64.ActiveCfg = Debug|x64
+		{73F29D43-5714-4069-8FAB-0D18FEB5F175}.Debug|x64.Build.0 = Debug|x64
+		{73F29D43-5714-4069-8FAB-0D18FEB5F175}.Debug|x86.ActiveCfg = Debug|x86
+		{73F29D43-5714-4069-8FAB-0D18FEB5F175}.Debug|x86.Build.0 = Debug|x86
+		{73F29D43-5714-4069-8FAB-0D18FEB5F175}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{73F29D43-5714-4069-8FAB-0D18FEB5F175}.Release|Any CPU.Build.0 = Release|Any CPU
+		{73F29D43-5714-4069-8FAB-0D18FEB5F175}.Release|x64.ActiveCfg = Release|x64
+		{73F29D43-5714-4069-8FAB-0D18FEB5F175}.Release|x64.Build.0 = Release|x64
+		{73F29D43-5714-4069-8FAB-0D18FEB5F175}.Release|x86.ActiveCfg = Release|x86
+		{73F29D43-5714-4069-8FAB-0D18FEB5F175}.Release|x86.Build.0 = Release|x86
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
Index: /branches/PerformanceComparison/ProblemInstanceIdentifier/InstanceDescriptor.cs
===================================================================
--- /branches/PerformanceComparison/ProblemInstanceIdentifier/InstanceDescriptor.cs	(revision 14690)
+++ /branches/PerformanceComparison/ProblemInstanceIdentifier/InstanceDescriptor.cs	(revision 14691)
@@ -46,12 +46,12 @@
 
     public static InstanceDescriptor FromPaths(QuadraticAssignmentProblem qap, List<List<Tuple<Permutation, double>>> trajectories) {
-      var features = QAPDirectedWalk.Calculate(trajectories).ToDictionary(x => x.Name, x => x.Value);
-      
+      var result = PermutationPathAnalysis.GetCharacteristics(trajectories);
+
       return new InstanceDescriptor() {
         Name = qap.Name,
         Cls = GetClass(qap.Name),
         Dimension = qap.Weights.Rows,
-        FeatureNames = features.Keys.ToArray(),
-        FeatureValues = features.Values.Select(x => ((DoubleValue)x).Value).ToArray()
+        FeatureNames = result.GetNames(),
+        FeatureValues = result.GetValues()
       };
     }
@@ -87,4 +87,11 @@
     private double[] featureStdevs;
 
+    public IEnumerable<double> GetMeans() {
+      return featureMeans;
+    }
+    public IEnumerable<double> GetStdevs() {
+      return featureStdevs;
+    }
+
     private InstancesStandardizer() { }
 
@@ -101,4 +108,9 @@
       return standardizer;
     }
+    public static InstancesStandardizer CreateAndApply(IList<InstanceDescriptor> instances) {
+      var standardizer = Create(instances);
+      standardizer.Apply(instances);
+      return standardizer;
+    }
 
     public void Apply(IList<InstanceDescriptor> instances) {
Index: /branches/PerformanceComparison/ProblemInstanceIdentifier/InstanceExplorer.cs
===================================================================
--- /branches/PerformanceComparison/ProblemInstanceIdentifier/InstanceExplorer.cs	(revision 14690)
+++ /branches/PerformanceComparison/ProblemInstanceIdentifier/InstanceExplorer.cs	(revision 14691)
@@ -1,4 +1,6 @@
-﻿using System.Linq;
+﻿using System;
+using System.Linq;
 using System.Threading;
+using HeuristicLab.Algorithms.MemPR.Permutation;
 using HeuristicLab.Analysis.FitnessLandscape;
 using HeuristicLab.Data;
@@ -57,5 +59,5 @@
       var walk = new RandomWalk() {
         SeedParameter = { Value = { Value = seed ?? 0 } },
-        SetSeedRandomlyParameter = { Value = { Value = seed.HasValue } },
+        SetSeedRandomlyParameter = { Value = { Value = !seed.HasValue } },
         MaximumIterationsParameter = { Value = { Value = Iterations } },
         RepetitionsParameter = { Value = { Value = 1 } }
@@ -71,3 +73,41 @@
     }
   }
+
+  public class MemPRExplorer : InstanceExplorer {
+    public int Seconds { get; set; }
+
+    public bool IncludeLocalSearch { get; set; }
+
+    public override string Name { get { return "MemPR Explorer"; } }
+    public override int Effort { get { return Seconds; } }
+
+    public MemPRExplorer() {
+
+    }
+
+    public override InstanceDescriptor Explore(QuadraticAssignmentProblem problem, int? seed = null) {
+      var memPr = new PermutationMemPR();
+      memPr.Problem = problem;
+      memPr.Prepare(true);
+      memPr.MaximumExecutionTime = TimeSpan.FromSeconds(Seconds);
+      memPr.SetSeedRandomly = !seed.HasValue;
+      memPr.Seed = seed ?? 0;
+      memPr.StartSync();
+      if (memPr.Context.RelinkedPaths.IsEmpty
+        || IncludeLocalSearch && memPr.Context.LocalSearchPaths.IsEmpty) {
+        Console.Write("{0} not all paths present!", problem.Name);
+        return null;
+      };
+
+      var features = PermutationPathAnalysis.GetCharacteristics(memPr.Context.RelinkedPaths.Paths.ToList());
+      var result = features.GetValues();
+      var resultNames = features.GetNames();
+      if (IncludeLocalSearch) {
+        features = PermutationPathAnalysis.GetCharacteristics(memPr.Context.LocalSearchPaths.Paths.ToList());
+        result = result.Concat(features.GetValues()).ToArray();
+        resultNames = resultNames.Concat(features.GetNames()).ToArray();
+      }
+      return new InstanceDescriptor(problem.Name, InstanceDescriptor.GetClass(problem.Name), problem.Weights.Rows, resultNames, result);
+    }
+  }
 }
Index: /branches/PerformanceComparison/ProblemInstanceIdentifier/Program.cs
===================================================================
--- /branches/PerformanceComparison/ProblemInstanceIdentifier/Program.cs	(revision 14690)
+++ /branches/PerformanceComparison/ProblemInstanceIdentifier/Program.cs	(revision 14691)
@@ -9,4 +9,5 @@
 using HeuristicLab.Problems.Instances.QAPLIB;
 using HeuristicLab.Problems.QuadraticAssignment;
+using HeuristicLab.Random;
 
 namespace ProblemInstanceIdentifier {
@@ -18,4 +19,54 @@
     };
     static void Main(string[] args) {
+      var instances = Get20DifferentClasses();
+      //var instances = GetSomeRandomInstances(50);
+
+      /*var classes = instances.Select(InstanceDescriptor.FromProblemOnly).GroupBy(x => x.Cls);
+      foreach (var cls in classes.OrderBy(x => x.Key)) {
+        Console.WriteLine("{0};{1}", cls.Key, cls.Count());
+      }*/
+
+      var prExplorer = new PathRelinkingExplorer() {
+        LocalOptima = false,
+        Paths = 200
+      };
+      var prLocalExplorer = new PathRelinkingExplorer() {
+        LocalOptima = true,
+        Paths = 200
+      };
+      var memPrExplorer = new MemPRExplorer() {
+        IncludeLocalSearch = false,
+        Seconds = 10
+      };
+
+      var training = GenerateData(instances, prExplorer, parallel:true);
+      var standardizer = InstancesStandardizer.CreateAndApply(training);
+      var test = GenerateData(instances, prExplorer, parallel: false);
+      standardizer.Apply(test);
+      PrintMatchResult(Compare(training, test));
+
+      ExploreMatching(instances, new [] { prLocalExplorer }, new [] { memPrExplorer });
+    }
+
+    private static List<QuadraticAssignmentProblem> GetSomeRandomInstances(int totalInstances) {
+      var sync = new object();
+      var provider = new OneSizeInstanceProvider();
+      var instances = new List<QuadraticAssignmentProblem>();
+      var random = new FastRandom(0);
+      Parallel.ForEach(provider.GetDataDescriptors().Shuffle(random), desc => {
+        var qapData = provider.LoadData(desc);
+        if (qapData.Dimension < 25) return;
+        if (instances.Count >= totalInstances) return;
+        var qap = new QuadraticAssignmentProblem();
+        qap.Load(qapData);
+        lock (sync) {
+          if (instances.Count >= totalInstances) return;
+          instances.Add(qap);
+        }
+      });
+      return instances;
+    }
+
+    private static List<QuadraticAssignmentProblem> Get20DifferentClasses() {
       var sync = new object();
 
@@ -36,52 +87,62 @@
         });
       }
-
-      /*var classes = instances.Select(InstanceDescriptor.FromProblemOnly).GroupBy(x => x.Cls);
-      foreach (var cls in classes.OrderBy(x => x.Key)) {
-        Console.WriteLine("{0};{1}", cls.Key, cls.Count());
-      }*/
-
-      //var kb = GenerateKnowledgeBase(instances, 200, localOptima: false);
-
-
-      //var paths = new[] { 1, 2, 3, 5, 10, 20, 30, 50, 100, 200 };
-      //var kbExplorers = paths.Select(x => new PathRelinkingExplorer() { Paths = x }).ToArray();
-      //var expExplorers = paths.Select(x => new PathRelinkingExplorer() { Paths = x }).ToArray();
-      //ExploreSelfIdentification(instances, kbExplorers, expExplorers);
-
-      var iterations = new[] { 100, 1000, 10000, 100000 };
-      var kbExplorers = iterations.Select(x => new RandomWalkExplorer() { Iterations = x }).ToArray();
-      var expExplorers = iterations.Select(x => new RandomWalkExplorer() { Iterations = x }).ToArray();
-      ExploreSelfIdentification(instances, kbExplorers, expExplorers);
-
-      //ExploreMemPrIdentification(instances);
-    }
-
-    private static List<InstanceDescriptor> GenerateKnowledgeBase(List<QuadraticAssignmentProblem> instances, InstanceExplorer explorer) {
-      var headerPrinted = false;
-      var sync = new object();
-      var kb = new List<InstanceDescriptor>();
-      Parallel.ForEach(instances.OrderBy(x => x.Weights.Rows), qap => {
+      return instances;
+    }
+
+    private static List<InstanceDescriptor> GenerateData(List<QuadraticAssignmentProblem> instances, InstanceExplorer explorer, bool parallel = false) {
+      var sync = new object();
+      var data = new List<InstanceDescriptor>();
+      Action<QuadraticAssignmentProblem> body = (qap) => {
         var instance = explorer.Explore(qap);
-        lock (sync) {
-          if (!headerPrinted) {
-            headerPrinted = true;
-            Console.WriteLine(string.Join(";",
-              new [] { "Name", "Cls", "Dimension" }
-              .Concat(instance.FeatureNames)));
-          }
-          PrintInstanceLine(instance);
-          kb.Add(instance);
-        }
-      });
-      var standardizer = InstancesStandardizer.Create(kb);
-      var normalizedKb = kb.Select(x => new InstanceDescriptor(x)).ToList();
-      standardizer.Apply(normalizedKb);
-      Console.WriteLine();
-      foreach (var instance in kb) {
-        PrintInstanceLine(instance);
-      }
-      //return normalizedKb;
-      return kb;
+        if (instance == null) return;
+        lock (sync) {
+          data.Add(instance);
+        }
+      };
+      if (parallel) {
+        Parallel.ForEach(instances, body);
+      } else {
+        foreach (var qap in instances) body(qap);
+      }
+      return data;
+    }
+
+    private static MatchResult Compare(List<InstanceDescriptor> training, List<InstanceDescriptor> test) {
+      int exactCount = 0, clsCount = 0, totalCount = 0;
+      int exactRank = 0, clsRank = 0;
+      foreach (var e in test) {
+        var ordered = training.OrderBy(x => x.CalculateSimilarity(e)).ToList();
+        var bestMatch = ordered.First();
+        if (bestMatch.Cls == e.Cls) clsCount++;
+        if (bestMatch.Name == e.Name) exactCount++;
+        totalCount++;
+        clsRank += ordered.FindIndex((id) => id.Cls == e.Cls) + 1;
+        exactRank += ordered.FindIndex((id) => id.Name == e.Name) + 1;
+      }
+
+      return new MatchResult() {
+        ExactCount = exactCount,
+        ClsCount = clsCount,
+        TotalCount = totalCount,
+        ExactAverageRank = exactRank / (double)totalCount,
+        ClsAverageRank = clsRank / (double)totalCount
+      };
+    }
+
+    private static void PrintMatchResult(MatchResult result) {
+      Console.WriteLine("{0}\t{1}\t{2}\t{3:F2}\t{4:F2}",
+        result.ExactCount, result.ClsCount, result.TotalCount,
+        result.ExactAverageRank, result.ClsAverageRank);
+    }
+
+    private static void PrintData(List<InstanceDescriptor> instances) {
+      using (var iter = instances.GetEnumerator()) {
+        if (!iter.MoveNext()) return;
+        Console.WriteLine(string.Join(";", new[] {"Name", "Cls", "Dimension"}
+          .Concat(iter.Current != null ? iter.Current.FeatureNames : new [] { "(null)" })));
+        do {
+          PrintInstanceLine(iter.Current);
+        } while (iter.MoveNext());
+      }
     }
 
@@ -92,101 +153,72 @@
     }
 
-    private static void ExploreSelfIdentification(List<QuadraticAssignmentProblem> instances, InstanceExplorer[] kbExplorer, InstanceExplorer[] expExporer) {
-      var sync = new object();
-      Console.WriteLine("{0}\t{1}\t{2}\t{3}\t{4}\t{5}", "Repetition", "KB-Effort", "Exp-Effort",
-        "Exact-Hits", "No-Hits", "Exact-Rank");
-      var kbSeeds = Enumerable.Range(0, 20).ToList();
-      var expSeeds = Enumerable.Range(20, 20).ToList();
-      for (var r = 0; r < 10; r++) {
-        var rlokal = r;
-        Parallel.ForEach(kbExplorer, kbPaths => {
-        //foreach (var kbPaths in kbExplorer) {
-          foreach (var expPaths in expExporer) {
-            //if (expPaths > kbPaths) continue;
-            var kb = new List<InstanceDescriptor>();
-            var exp = new List<InstanceDescriptor>();
-            foreach (var qap in instances) {
-              kb.Add(kbPaths.Explore(qap, kbSeeds[rlokal]));
-              exp.Add(expPaths.Explore(qap, expSeeds[rlokal]));
-            }
-            var standardizer = InstancesStandardizer.Create(kb);
-            standardizer.Apply(kb);
-            standardizer.Apply(exp);
-            int exactCount = 0, clsCount = 0, missedCount = 0;
-            int exactRank = 0, clsRank = 0;
-            foreach (var e in exp) {
-              var ordered = kb.OrderBy(x => x.CalculateSimilarity(e)).ToList();
-              var bestMatch = ordered.First();
-              if (bestMatch.Cls == e.Cls) {
-                clsCount++;
-                if (bestMatch.Name == e.Name) exactCount++;
-              }
-              else missedCount++;
-              clsRank += ordered.FindIndex((id) => id.Cls == e.Cls) + 1;
-              exactRank += ordered.FindIndex((id) => id.Name == e.Name) + 1;
-            }
-            lock (sync) {
-              Console.WriteLine("{0}\t{1}\t{2}\t{3}\t{4}\t{5:F2}", rlokal, kbPaths.Effort, expPaths.Effort, exactCount,
-                missedCount, exactRank / (double) exp.Count);
-            }
+    private static void ExploreMatching(List<QuadraticAssignmentProblem> instances, InstanceExplorer[] trainingExplorers, InstanceExplorer[] testExporers, bool parallel = false) {
+      var sync = new object();
+      var rand = new Random();
+      var first = rand.Next();
+      var second = rand.Next();
+      while (first == second) second = rand.Next();
+
+      var knowledgeBase = new Dictionary<InstanceExplorer, Tuple<InstancesStandardizer, List<InstanceDescriptor>>>();
+      Action<InstanceExplorer> trainingBody = (kbExplorer) => {
+        var trainingData = GenerateData(instances, kbExplorer, parallel);
+        var standardizer = InstancesStandardizer.Create(trainingData);
+        standardizer.Apply(trainingData);
+        lock (sync) {
+          knowledgeBase.Add(kbExplorer, Tuple.Create(standardizer, trainingData));
+        }
+      };
+      if (parallel) {
+        Parallel.ForEach(trainingExplorers, trainingBody);
+      } else {
+        foreach (var kbExplorer in trainingExplorers) trainingBody(kbExplorer);
+      }
+
+      var experimentBase = new Dictionary<InstanceExplorer, List<InstanceDescriptor>>();
+      Action<InstanceExplorer> testBody = (expExplorer) => {
+        var trainingData = GenerateData(instances, expExplorer, parallel);
+        lock (sync) {
+          experimentBase.Add(expExplorer, trainingData);
+        }
+      };
+      if (parallel) {
+        Parallel.ForEach(testExporers, testBody);
+      } else {
+        foreach (var expExplorer in testExporers) testBody(expExplorer);
+      }
+
+      var data = from kb in knowledgeBase
+        from exp in experimentBase
+        select new { Training = kb, Test = exp };
+
+      if (parallel) {
+        Parallel.ForEach(data, (point) => {
+          var normalizedTest = point.Test.Value.Select(x => new InstanceDescriptor(x)).ToList();
+          point.Training.Value.Item1.Apply(normalizedTest);
+          var result = Compare(point.Training.Value.Item2, normalizedTest);
+          lock (sync) {
+            Console.WriteLine("{0}\t{1}\t{2}\t{3:F2}\t{4}\t{5:F2}\t{6}",
+              point.Training.Key.Effort, point.Test.Key.Effort, result.ExactCount,
+              result.ExactAverageRank, result.ClsCount, result.ClsAverageRank, result.TotalCount);
           }
         });
-        //}
-      }
-    }
-    
-    private static void ExploreMemPrIdentification(List<QuadraticAssignmentProblem> instances) {
-      var sync = new object();
-      Console.WriteLine("{0}\t{1}\t{2}\t{3}\t{4}\t{5}", "Repetition", "KB-Runtime", "Exp-Runtime",
-        "Exact-Hits", "No-Hits", "Average-Rank");
-      var paths = new[] { 10 };
-      var repetitions = 10;
-      var kbSeeds = Enumerable.Range(0, repetitions).ToList();
-      var expSeeds = Enumerable.Range(repetitions, repetitions).ToList();
-      for (var r = 0; r < repetitions; r++) {
-        var rlokal = r;
-        Parallel.ForEach(paths, kbPaths => {
-          var memPr = new PermutationMemPR();
-          foreach (var expPaths in paths) {
-            //if (expPaths > kbPaths) continue;
-            var kb = new List<InstanceDescriptor>();
-            var exp = new List<InstanceDescriptor>();
-            foreach (var qap in instances.Select(x => (QuadraticAssignmentProblem)x.Clone())) {
-              memPr.Problem = qap;
-              memPr.Prepare(true);
-              memPr.Seed = kbSeeds[rlokal];
-              memPr.MaximumExecutionTime = TimeSpan.FromSeconds(kbPaths);
-              memPr.StartSync();
-              if (memPr.Context.RelinkedPaths.IsEmpty) continue;
-              kb.Add(InstanceDescriptor.FromPaths(qap, memPr.Context.RelinkedPaths.Paths.ToList()));
-              memPr.Prepare(true);
-              memPr.Seed = expSeeds[rlokal];
-              memPr.MaximumExecutionTime = TimeSpan.FromSeconds(expPaths);
-              memPr.StartSync();
-              if (memPr.Context.RelinkedPaths.IsEmpty) continue;
-              exp.Add(InstanceDescriptor.FromPaths(qap, memPr.Context.RelinkedPaths.Paths.ToList()));
-            }
-            var standardizer = InstancesStandardizer.Create(kb);
-            standardizer.Apply(kb);
-            standardizer.Apply(exp);
-            int exactCount = 0, clsCount = 0, missedCount = 0;
-            int exactRank = 0, clsRank = 0;
-            foreach (var e in exp) {
-              var ordered = kb.OrderBy(x => x.CalculateSimilarity(e)).ToList();
-              var bestMatch = ordered.First();
-              if (bestMatch.Cls == e.Cls) {
-                clsCount++;
-                if (bestMatch.Name == e.Name) exactCount++;
-              } else missedCount++;
-              clsRank += ordered.FindIndex((id) => id.Cls == e.Cls) + 1;
-              exactRank += ordered.FindIndex((id) => id.Name == e.Name) + 1;
-            }
-            lock (sync) {
-              Console.WriteLine("{0}\t{1}\t{2}\t{3}\t{4}\t{5:F2}", rlokal, kbPaths, expPaths, exactCount,
-                missedCount, exactRank / (double)exp.Count);
-            }
-          }
-        });
-      }
+      } else {
+        foreach (var point in data) {
+          var normalizedTest = point.Test.Value.Select(x => new InstanceDescriptor(x)).ToList();
+          point.Training.Value.Item1.Apply(normalizedTest);
+          var result = Compare(point.Training.Value.Item2, normalizedTest);
+          Console.WriteLine("{0}\t{1}\t{2}\t{3:F2}\t{4}\t{5:F2}\t{6}",
+            point.Training.Key.Effort, point.Test.Key.Effort, result.ExactCount,
+            result.ExactAverageRank, result.ClsCount, result.ClsAverageRank, result.TotalCount);
+        }
+      }
+    }
+
+    private class MatchResult {
+      public int ExactCount { get; set; }
+      public int ClsCount { get; set; }
+      public int TotalCount { get; set; }
+      public double ExactAverageRank { get; set; }
+      public double ClsAverageRank { get; set; }
     }
   }
