Index: branches/2457_ExpertSystem/HeuristicLab.Analysis.FitnessLandscape/3.3/Analysis/InformationAnalysis.cs
===================================================================
--- branches/2457_ExpertSystem/HeuristicLab.Analysis.FitnessLandscape/3.3/Analysis/InformationAnalysis.cs	(revision 16137)
+++ branches/2457_ExpertSystem/HeuristicLab.Analysis.FitnessLandscape/3.3/Analysis/InformationAnalysis.cs	(revision 16955)
@@ -46,6 +46,6 @@
     public List<double> QualityDelta { get; private set; }
     public double InformationStability { get; private set; }
-    public int Regularity { get; private set; }
-    public int Diversity { get; private set; }
+    public double Regularity { get; private set; }
+    public double Diversity { get; private set; }
     public Peak PeakInformationContent { get; private set; }
     public Peak PeakSymmetricInformationContent { get; private set; }
@@ -71,6 +71,6 @@
       var differences = Differences(qualities).ToList();
       InformationStability = differences.Select(Math.Abs).Max();
-      Regularity = new HashSet<double>(differences).Count;
-      Diversity = new HashSet<double>(qualities).Count;
+      Regularity = new HashSet<double>(differences).Count / (double)differences.Count;
+      Diversity = new HashSet<double>(qualities).Count / (double)qualities.Count;
       var absDifferences = differences.Select(Math.Abs).OrderBy(d => d).ToList();
       nQuantiles = Math.Min(nQuantiles, absDifferences.Count);
@@ -118,4 +118,23 @@
       PeakTotalEntropy = GetPeak(QualityDelta, TotalEntropy);
       PeakSymmetricTotalEntropy = GetPeak(QualityDelta, SymmetricTotalEntropy);
+    }
+
+    public IEnumerable<Tuple<string, object>> GetFeatures() {
+      yield return Tuple.Create("InformationContent", (object)InformationContent[0]);
+      yield return Tuple.Create("DensityBasinInformation", (object)DensityBasinInformation[0]);
+      yield return Tuple.Create("PartialInformationContent", (object)PartialInformationContent[0]);
+      yield return Tuple.Create("TotalEntropy", (object)TotalEntropy[0]);
+      yield return Tuple.Create("InformationStability", (object)InformationStability);
+      yield return Tuple.Create("Regularity", (object)Regularity);
+      yield return Tuple.Create("Diversity", (object)Diversity);
+      yield return Tuple.Create("SymmetricInformationContent", (object)SymmetricInformationContent[0]);
+      yield return Tuple.Create("SymmetricDensityBasinInformation", (object)SymmetricDensityBasinInformation[0]);
+      yield return Tuple.Create("SymmetricTotalEntropy", (object)SymmetricTotalEntropy[0]);
+      yield return Tuple.Create("PeakInformationContent", (object)PeakInformationContent.Value);
+      yield return Tuple.Create("PeakDensityBasinInformation", (object)PeakDensityBasinInformation.Value);
+      yield return Tuple.Create("PeakTotalEntropy", (object)PeakTotalEntropy.Value);
+      yield return Tuple.Create("PeakSymmetricInformationContent", (object)PeakSymmetricInformationContent.Value);
+      yield return Tuple.Create("PeakSymmetricDensityBasinInformation", (object)PeakSymmetricDensityBasinInformation.Value);
+      yield return Tuple.Create("PeakSymmetricTotalEntropy", (object)PeakSymmetricTotalEntropy.Value);
     }
 
Index: branches/2457_ExpertSystem/HeuristicLab.Analysis.FitnessLandscape/3.3/Analysis/InformationAnalyzer.cs
===================================================================
--- branches/2457_ExpertSystem/HeuristicLab.Analysis.FitnessLandscape/3.3/Analysis/InformationAnalyzer.cs	(revision 16137)
+++ branches/2457_ExpertSystem/HeuristicLab.Analysis.FitnessLandscape/3.3/Analysis/InformationAnalyzer.cs	(revision 16955)
@@ -132,8 +132,8 @@
       InformationStabilityParameter.ActualValue = @is;
       results.AddOrUpdateResult(InformationStabilityParameter.Name, @is);
-      var regularity = new DoubleValue(1.0 * analysis.Regularity / qualities.Count);
+      var regularity = new DoubleValue(analysis.Regularity);
       RegularityParameter.ActualValue = regularity;
       results.AddOrUpdateResult(RegularityParameter.Name, regularity);
-      var diversity = new DoubleValue(1.0 * analysis.Diversity / qualities.Count);
+      var diversity = new DoubleValue(analysis.Diversity);
       DiversityParameter.ActualValue = diversity;
       results.AddOrUpdateResult(DiversityParameter.Name, diversity);
Index: branches/2457_ExpertSystem/HeuristicLab.Analysis.FitnessLandscape/3.3/Utilities/CurveAnalysis.cs
===================================================================
--- branches/2457_ExpertSystem/HeuristicLab.Analysis.FitnessLandscape/3.3/Utilities/CurveAnalysis.cs	(revision 16137)
+++ branches/2457_ExpertSystem/HeuristicLab.Analysis.FitnessLandscape/3.3/Utilities/CurveAnalysis.cs	(revision 16955)
@@ -26,10 +26,10 @@
 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();
-      if (trajectories.Count == 0) return new CurveAnalysisResult(0, 0, 0, new[] { 0.0, 0.0, 0.0 }, new[] { 0.0, 0.0, 0.0 }, new[] { 0.0, 0.0, 0.0 });
+    public static CurveAnalysisResult GetCharacteristics(IEnumerable<List<Tuple<T, double>>> trajectories, Func<T, T, double> distFunc) {
+      var traj = trajectories.Where(x => x.Count > 5).ToList();
+      if (traj.Count == 0) return new CurveAnalysisResult(0, 0, 0, new[] { 0.0, 0.0, 0.0 }, new[] { 0.0, 0.0, 0.0 }, new[] { 0.0, 0.0, 0.0 });
 
-      var symbols = GetSymbols(trajectories);
-      var f1 = trajectories.Select(path => ApproximateDerivative(path, distFunc).ToList()).ToList();
+      var symbols = GetSymbols(traj);
+      var f1 = traj.Select(path => ApproximateDerivative(path, distFunc).ToList()).ToList();
       var f2 = f1.Select(d1 => ApproximateDerivative(d1, distFunc).ToList()).ToList();
 
Index: branches/2457_ExpertSystem/PerformanceComparison.sln
===================================================================
--- branches/2457_ExpertSystem/PerformanceComparison.sln	(revision 16137)
+++ branches/2457_ExpertSystem/PerformanceComparison.sln	(revision 16955)
@@ -31,4 +31,6 @@
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnitTests", "UnitTests\UnitTests.csproj", "{76241AF2-B428-4127-805D-667F79983F0F}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WalkExporter", "WalkExporter\WalkExporter.csproj", "{EE6BD7D3-8012-4A5D-ABAE-356B3D1E4573}"
 EndProject
 Global
@@ -210,4 +212,16 @@
 		{76241AF2-B428-4127-805D-667F79983F0F}.Release|x86.ActiveCfg = Release|Any CPU
 		{76241AF2-B428-4127-805D-667F79983F0F}.Release|x86.Build.0 = Release|Any CPU
+		{EE6BD7D3-8012-4A5D-ABAE-356B3D1E4573}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{EE6BD7D3-8012-4A5D-ABAE-356B3D1E4573}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{EE6BD7D3-8012-4A5D-ABAE-356B3D1E4573}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{EE6BD7D3-8012-4A5D-ABAE-356B3D1E4573}.Debug|x64.Build.0 = Debug|Any CPU
+		{EE6BD7D3-8012-4A5D-ABAE-356B3D1E4573}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{EE6BD7D3-8012-4A5D-ABAE-356B3D1E4573}.Debug|x86.Build.0 = Debug|Any CPU
+		{EE6BD7D3-8012-4A5D-ABAE-356B3D1E4573}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{EE6BD7D3-8012-4A5D-ABAE-356B3D1E4573}.Release|Any CPU.Build.0 = Release|Any CPU
+		{EE6BD7D3-8012-4A5D-ABAE-356B3D1E4573}.Release|x64.ActiveCfg = Release|Any CPU
+		{EE6BD7D3-8012-4A5D-ABAE-356B3D1E4573}.Release|x64.Build.0 = Release|Any CPU
+		{EE6BD7D3-8012-4A5D-ABAE-356B3D1E4573}.Release|x86.ActiveCfg = Release|Any CPU
+		{EE6BD7D3-8012-4A5D-ABAE-356B3D1E4573}.Release|x86.Build.0 = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
Index: branches/2457_ExpertSystem/ProblemInstanceIdentifier/Program.cs
===================================================================
--- branches/2457_ExpertSystem/ProblemInstanceIdentifier/Program.cs	(revision 16137)
+++ branches/2457_ExpertSystem/ProblemInstanceIdentifier/Program.cs	(revision 16955)
@@ -48,5 +48,5 @@
         writer.WriteLine(header);
         Console.WriteLine(header);
-        foreach (var dim in new[] { 20, 30, 40, 50, 100 }) {
+        foreach (var dim in new[] { 20, 30, 40 }) {
           foreach (var feat in dwFeatureSets) {
             foreach (var type in dwTypes) {
Index: branches/2457_ExpertSystem/UnitTests/InformationAnalysisTest.cs
===================================================================
--- branches/2457_ExpertSystem/UnitTests/InformationAnalysisTest.cs	(revision 16137)
+++ branches/2457_ExpertSystem/UnitTests/InformationAnalysisTest.cs	(revision 16955)
@@ -15,6 +15,6 @@
       Assert.AreEqual(0.9008, ia.TotalEntropy[0], 1e-04);
       Assert.AreEqual(2, ia.InformationStability);
-      Assert.AreEqual(4, ia.Diversity);
-      Assert.AreEqual(5, ia.Regularity);
+      Assert.AreEqual(4.0 / qualities.Length, ia.Diversity, 1e-07);
+      Assert.AreEqual(5.0 / (qualities.Length - 1), ia.Regularity, 1e-07);
       Assert.AreEqual(0.4603, ia.PeakDensityBasinInformation.Value, 1e-04);
       Assert.AreEqual(0.8224, ia.PeakInformationContent.Value, 1e-04);
Index: branches/2457_ExpertSystem/WalkExporter/AdaptiveWalks.cs
===================================================================
--- branches/2457_ExpertSystem/WalkExporter/AdaptiveWalks.cs	(revision 16955)
+++ branches/2457_ExpertSystem/WalkExporter/AdaptiveWalks.cs	(revision 16955)
@@ -0,0 +1,96 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2018 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Collections.Generic;
+using HeuristicLab.Core;
+using HeuristicLab.Encodings.PermutationEncoding;
+using HeuristicLab.Problems.Instances;
+
+namespace WalkExporter {
+  static class AdaptiveWalks {
+    
+    public static IEnumerable<double> AdaptiveWalk(IRandom random, QAPData qap, int sampleSize) {
+      var sol = new Permutation(PermutationTypes.Absolute, qap.Dimension, random);
+      var fit = Util.Evaluate(sol, qap);
+      yield return fit;
+      while (true) {
+        var bestZ1 = -1;
+        var bestZ2 = -1;
+        var bestMove = double.MaxValue;
+        for (var s = 0; s < sampleSize; s++) {
+          var z1 = random.Next(qap.Dimension);
+          var z2 = (z1 + random.Next(1, qap.Dimension)) % qap.Dimension;
+          var move = Util.EvaluateSwap2Diff(sol, z1, z2, qap);
+          if (move < bestMove) {
+            bestZ1 = z1;
+            bestZ2 = z2;
+            bestMove = move;
+          }
+        }
+        fit += bestMove;
+        yield return fit;
+        sol.Swap(bestZ1, bestZ2);
+      }
+    }
+
+    public static IEnumerable<double> UpDownWalk(IRandom random, QAPData qap, int sampleSize) {
+      var sol = new Permutation(PermutationTypes.Absolute, qap.Dimension, random);
+      var fit = Util.Evaluate(sol, qap);
+      yield return fit;
+      var down = true;
+      while (true) {
+        int z1 = -1, z2 = -1, bestDownZ1 = -1, bestDownZ2 = -1, bestUpZ1 = -1, bestUpZ2 = -1;
+        double move = 0, bestDownMove = 0, bestUpMove = 0;
+        for (var s = 0; s < sampleSize; s++) {
+          z1 = random.Next(qap.Dimension);
+          z2 = (z1 + random.Next(1, qap.Dimension)) % qap.Dimension;
+          move = Util.EvaluateSwap2Diff(sol, z1, z2, qap);
+          if (move < bestDownMove) {
+            bestDownZ1 = z1;
+            bestDownZ2 = z2;
+            bestDownMove = move;
+          } else if (move > bestUpMove) {
+            bestUpZ1 = z1;
+            bestUpZ2 = z2;
+            bestUpMove = move;
+          }
+        }
+        // revert direction
+        if (down && bestDownZ1 < 0 || !down && bestUpZ1 < 0) down = !down;
+
+        if (down && bestDownZ1 >= 0) {
+          fit += bestDownMove;
+          yield return fit;
+          sol.Swap(bestDownZ1, bestDownZ2);
+        } else if (!down && bestUpZ1 >= 0) {
+          fit += bestUpMove;
+          yield return fit;
+          sol.Swap(bestUpZ1, bestUpZ2);
+        } else {
+          // all moves neutral, make a random move , i.e. last sampled one
+          fit += move;
+          yield return fit;
+          sol.Swap(z1, z2);
+        }
+      }
+    }
+  }
+}
Index: branches/2457_ExpertSystem/WalkExporter/App.config
===================================================================
--- branches/2457_ExpertSystem/WalkExporter/App.config	(revision 16955)
+++ branches/2457_ExpertSystem/WalkExporter/App.config	(revision 16955)
@@ -0,0 +1,6 @@
+﻿<?xml version="1.0" encoding="utf-8" ?>
+<configuration>
+    <startup> 
+        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
+    </startup>
+</configuration>
Index: branches/2457_ExpertSystem/WalkExporter/Data.cs
===================================================================
--- branches/2457_ExpertSystem/WalkExporter/Data.cs	(revision 16955)
+++ branches/2457_ExpertSystem/WalkExporter/Data.cs	(revision 16955)
@@ -0,0 +1,174 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2018 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.Linq;
+using System.Text;
+using ProtoBuf;
+
+namespace WalkExporter {
+  [ProtoContract]
+  public class KeyValue {
+    [ProtoMember(1, IsRequired = true)]
+    public string Key;
+    [ProtoMember(2)]
+    public double? ContinuousValue;
+    [ProtoMember(3)]
+    public long? DiscreteValue;
+    [ProtoMember(4)]
+    public string StringValue;
+    [ProtoMember(5, IsPacked = true)]
+    public List<double> ContinuousArrayValue;
+    [ProtoMember(6, IsPacked = true)]
+    public List<long> DiscreteArrayValue;
+    [ProtoMember(7)]
+    public List<string> StringArrayValue;
+    [ProtoMember(8)]
+    public byte[] RawValue;
+
+    public double GetNumericValue() {
+      return ContinuousValue.HasValue ? ContinuousValue.Value : DiscreteValue.Value;
+    }
+    public void SetNumericValue(long v) {
+      ContinuousValue = null;
+      DiscreteValue = v;
+    }
+    public void SetNumericValue(double v) {
+      ContinuousValue = v;
+      DiscreteValue = null;
+    }
+
+    public override string ToString() {
+      var sb = new StringBuilder();
+      sb.Append(Key);
+      sb.Append(": ");
+      sb.Append(string.Join(" / ", new string[] {
+        ContinuousValue?.ToString(), DiscreteValue?.ToString(),
+        StringValue?.Substring(0, 10),
+        ContinuousArrayValue != null ? string.Join(", ", ContinuousArrayValue.Take(10)) : null,
+        DiscreteArrayValue != null ? string.Join(", ", DiscreteArrayValue.Take(10)) : null,
+        StringArrayValue != null ? string.Join(", ", StringArrayValue.Take(10)) : null,
+        RawValue != null ? Convert.ToBase64String(RawValue).Substring(0, 10) : null
+      }.Where(x => !string.IsNullOrEmpty(x))));
+      return sb.ToString();
+    }
+  }
+
+  [ProtoContract]
+  public class Solution {
+    [ProtoMember(1)]
+    public string Type;
+    [ProtoMember(2)]
+    public List<KeyValue> Data;
+  }
+
+  [ProtoContract]
+  public class Walk {
+    [ProtoMember(1, IsRequired = true, IsPacked = true)]
+    public List<double> QualityTrail;
+    [ProtoMember(2)]
+    public List<Solution> Solutions;
+  }
+
+  [ProtoContract]
+  public class Exploration {
+    [ProtoMember(1, IsRequired = true)]
+    public string Problem;
+    [ProtoMember(2, IsRequired = true)]
+    public int Dimension;
+    [ProtoMember(3, IsRequired = true)]
+    public List<Walk> Walks;
+
+    public static Exploration Load(string file) => Serializer.Deserialize<Exploration>(File.OpenRead(file));
+  }
+
+  [ProtoContract]
+  public class Experiment {
+    [ProtoMember(1, IsRequired = true)]
+    public string Algorithm;
+    [ProtoMember(2, IsRequired = true)]
+    public List<Exploration> Trials;
+
+    public static Experiment Load(string file) => Serializer.Deserialize<Experiment>(File.OpenRead(file));
+
+    public void Print(TextWriter writer) {
+      writer.WriteLine("Experiment: " + Algorithm);
+      foreach (var t in Trials) {
+        writer.WriteLine("Trial: {0} ({1})", t.Problem, t.Dimension);
+        foreach (var w in t.Walks) {
+          writer.WriteLine("Walk: " + string.Join(";", w.QualityTrail.Take(10)));
+        }
+      }
+    }
+  }
+
+  [ProtoContract]
+  public class ProblemInstanceDescriptor {
+    [ProtoMember(1)]
+    public string Name;
+    [ProtoMember(2)]
+    public string Class;
+    [ProtoMember(3)]
+    public int Dimension;
+    [ProtoMember(4)]
+    public List<KeyValue> Features;
+    [ProtoMember(5)]
+    public double DescriptionEffort;
+    
+    public IEnumerable<double> GetNumericFeatures(IEnumerable<string> keys) {
+      var map = Features.ToDictionary(x => x.Key, x => x.GetNumericValue());
+      return keys.Select(x => map[x]);
+    }
+  }
+
+  [ProtoContract]
+  public class Knowledgebase {
+    [ProtoMember(1)]
+    public List<ProblemInstanceDescriptor> Problems;
+
+    public static Knowledgebase Load(string file) => Serializer.Deserialize<Knowledgebase>(File.OpenRead(file));
+
+    public void Print(TextWriter writer) {
+      writer.WriteLine("Knowledge base with {0} instances", Problems?.Count ?? 0);
+      if (Problems == null) return;
+      foreach (var p in Problems) {
+        writer.WriteLine("Problem: {2} / {0} ({1}), [{2}]", p.Name, p.Dimension, p.Class, p.DescriptionEffort);
+        writer.WriteLine("Features: {0}", p.Features?.Count ?? 0);
+        if (p.Features != null)
+          writer.WriteLine(" " + string.Join(Environment.NewLine + " ", p.Features.Select(f => f.ToString())));
+
+      }
+    }
+  }
+
+  /// <summary>
+  /// Just exists to have one type that includes all other types
+  /// </summary>
+  [ProtoContract]
+  internal class AllProtos {
+    [ProtoMember(1)]
+    public Experiment Experiment;
+    [ProtoMember(2)]
+    public Knowledgebase Knowledgebase;
+  }
+}
Index: branches/2457_ExpertSystem/WalkExporter/DirectedWalk.cs
===================================================================
--- branches/2457_ExpertSystem/WalkExporter/DirectedWalk.cs	(revision 16955)
+++ branches/2457_ExpertSystem/WalkExporter/DirectedWalk.cs	(revision 16955)
@@ -0,0 +1,233 @@
+﻿using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading;
+using HeuristicLab.Analysis.FitnessLandscape;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Encodings.PermutationEncoding;
+using HeuristicLab.Problems.Instances;
+using HeuristicLab.Problems.Instances.QAPLIB;
+using HeuristicLab.Problems.QuadraticAssignment;
+using HeuristicLab.Random;
+using static HeuristicLab.Analysis.FitnessLandscape.QAPDirectedWalk;
+
+namespace WalkExporter {
+  class DirectedWalk {
+    public int? Seed;
+    public QuadraticAssignmentProblem Problem;
+    public WalkType Type;
+    public int Paths;
+    public double EvaluatedSolutionEquiv;
+    public bool BestImprovement;
+
+
+    public static (Experiment experiment, Dictionary<int, Knowledgebase> training, Dictionary<int, Knowledgebase> test)
+        PerformExperiment(WalkType type, bool bestImprovement = true) {
+
+      string typeStr;
+      switch (type) {
+        case WalkType.RandomRandom: typeStr = "(rr)-dw"; break;
+        case WalkType.RandomLocal: typeStr = "(rl)-dw"; break;
+        case WalkType.LocalLocal: typeStr = "(ll)-dw"; break;
+        case WalkType.LocalInverse: typeStr = "(li)-dw"; break;
+        default: throw new ArgumentException(string.Format("unknown type {0}", type), "type");
+      }
+      var experiment = new Experiment() { Algorithm = typeStr, Trials = new List<Exploration>() };
+      var training = new[] { 1, 2, 5, 10, 20, 50, 100, 200, 500 }.ToDictionary(x => x, x => new Knowledgebase() { Problems = new List<ProblemInstanceDescriptor>() });
+      var test = new[] { 1, 2, 5, 10, 20, 50, 100, 200, 500 }.ToDictionary(x => x, x => new Knowledgebase() { Problems = new List<ProblemInstanceDescriptor>() });
+
+      foreach (var dimension in new[] { 20, 30, 40 }) {
+        var provider = new OneSizeInstanceProvider(dimension);
+        foreach (var desc in provider.GetDataDescriptors()) {
+          var qapData = provider.LoadData(desc);
+
+          var qap = new QuadraticAssignmentProblem();
+          qap.Load(qapData);
+          var calculator = new DirectedWalk() {
+            Problem = qap,
+            BestImprovement = bestImprovement,
+            Paths = 1000,
+            Seed = 42,
+            Type = type
+          };
+          var solutions = calculator.CalculateRelinkingPoints().ToList();
+          var walk = calculator.Run(solutions).ToList();
+
+          var exploration = new Exploration() { Problem = qapData.Name, Dimension = qapData.Dimension, Walks = new List<Walk>() };
+          foreach (var w in walk) {
+            exploration.Walks.Add(new Walk() {
+              QualityTrail = w.Select(x => x.Item2).ToList()
+            });
+          }
+          experiment.Trials.Add(exploration);
+          AddToKnowledgeBase(training, qapData, calculator, walk, 0);
+          AddToKnowledgeBase(test, qapData, calculator, walk, 500);
+        }
+      }
+      return (experiment, training, test);
+    }
+
+    private static void AddToKnowledgeBase(Dictionary<int, Knowledgebase> training, QAPData qapData, DirectedWalk calculator, List<List<Tuple<Permutation, double>>> walk, int start) {
+      foreach (var t in training.Keys) {
+        var kb = training[t];
+        var sbf = CurveAnalysis<Permutation>.GetCharacteristics(walk.Skip(start).Take(t), (left, right) => (1.0 - HammingSimilarityCalculator.CalculateSimilarity(left, right)) * left.Length);
+        var trail = walk.Skip(start).Take(t).SelectMany(x => x).Select(x => x.Item2).ToArray();
+        var ia = new InformationAnalysis(trail);
+        var clen = RuggednessCalculator.CalculateCorrelationLength(trail, out double[] acf);
+
+        var pid = new ProblemInstanceDescriptor() {
+          Name = qapData.Name,
+          Class = Util.GetGeneratorClass(qapData.Name),
+          Dimension = qapData.Dimension,
+          DescriptionEffort = calculator.EvaluatedSolutionEquiv / 1000 * t,
+          Features = new List<KeyValue>()
+        };
+        pid.Features.Add(new KeyValue { Key = "AC1", ContinuousValue = acf[1] });
+        pid.Features.Add(new KeyValue { Key = "CorrelationLength", DiscreteValue = clen });
+        foreach (var f in CurveAnalysisResult.AllFeatures.Zip(sbf.GetValues(), (a, b) => new { Feature = a, Value = b })) {
+          pid.Features.Add(new KeyValue { Key = f.Feature.ToString(), ContinuousValue = f.Value });
+        }
+        foreach (var f in ia.GetFeatures()) {
+          if (f.Item2 is double d) pid.Features.Add(new KeyValue { Key = f.Item1, ContinuousValue = d });
+          else if (f.Item2 is int i) pid.Features.Add(new KeyValue { Key = f.Item1, DiscreteValue = i });
+        }
+
+        kb.Problems.Add(pid);
+      }
+    }
+
+    public IEnumerable<Permutation> CalculateRelinkingPoints() {
+      IRandom random = Seed.HasValue ? new MersenneTwister((uint)Seed.Value) : new MersenneTwister();
+      var pathCount = Paths;
+
+      var perm = new Permutation(PermutationTypes.Absolute, Problem.Weights.Rows, random);
+      var startLocal = Type == WalkType.LocalGlobal || Type == WalkType.LocalLocal;
+      var targetLocal = Type == WalkType.LocalLocal || Type == WalkType.RandomLocal;
+      var targetGlobal = Type == WalkType.LocalGlobal || Type == WalkType.RandomGlobal;
+      var inverseWalk = Type == WalkType.LocalInverse;
+
+      if (Type == WalkType.LocalInverse) pathCount--; // inverse walks equal one walk per solution
+      for (var i = 0; i <= pathCount; i++) {
+        var start = i % 2 == 0;
+        var target = i % 2 == 1;
+        if (inverseWalk || start && startLocal) {
+          perm = new Permutation(PermutationTypes.Absolute, Problem.Weights.Rows, random);
+          var fit = new DoubleValue(QAPEvaluator.Apply(perm, Problem.Weights, Problem.Distances));
+          EvaluatedSolutionEquiv++;
+          var evalSol = new IntValue(0);
+          QAPExhaustiveSwap2LocalImprovement.ImproveFast(perm, Problem.Weights, Problem.Distances, fit, new IntValue(0), evalSol, Problem.Maximization.Value, int.MaxValue, CancellationToken.None);
+          EvaluatedSolutionEquiv += evalSol.Value;
+        } else if (target && (targetLocal || targetGlobal)) {
+          if (targetGlobal) {
+            perm = Problem.BestKnownSolutions.SampleRandom(random);
+          } else {
+            perm = new Permutation(PermutationTypes.Absolute, Problem.Weights.Rows, random);
+            var fit = new DoubleValue(QAPEvaluator.Apply(perm, Problem.Weights, Problem.Distances));
+            EvaluatedSolutionEquiv++;
+            var evalSol = new IntValue(0);
+            QAPExhaustiveSwap2LocalImprovement.ImproveFast(perm, Problem.Weights, Problem.Distances, fit, new IntValue(0), evalSol, Problem.Maximization.Value, int.MaxValue, CancellationToken.None);
+            EvaluatedSolutionEquiv += evalSol.Value;
+          }
+        } else { // random
+          BiasedShuffle(perm, random);
+        }
+        yield return (Permutation)perm.Clone();
+      }
+    }
+
+    public IEnumerable<List<Tuple<Permutation, double>>> Run(IEnumerable<Permutation> permutations) {
+      if (Type == WalkType.LocalInverse) return RunInverse(permutations);
+      return RunRegular(permutations);
+    }
+
+    private IEnumerable<List<Tuple<Permutation, double>>> RunInverse(IEnumerable<Permutation> permutations) {
+      var qap = (QuadraticAssignmentProblem)Problem;
+      var min = qap.LowerBound.Value;
+      var max = qap.AverageQuality.Value;
+      var bestImprovement = BestImprovement;
+
+      foreach (var start in permutations) {
+        var startFitness = QAPEvaluator.Apply(start, qap.Weights, qap.Distances);
+        EvaluatedSolutionEquiv++;
+
+        // inverse walks are applied to all solutions
+        Func<Tuple<Permutation, double>, IEnumerable<Tuple<Permutation, double>>> inverseNeighborFunc = (p) => RestrictedInverseNeighborhood(qap, p.Item1, p.Item2, start);
+        var walk = DirectedWalk<Permutation>.WalkRestricted(qap.Maximization.Value, inverseNeighborFunc, start, startFitness, !bestImprovement);
+        yield return walk.Select(x => Tuple.Create(x.Item1, (x.Item2 - min) / (max - min))).ToList();
+      } // end paths
+    }
+
+    private IEnumerable<List<Tuple<Permutation, double>>> RunRegular(IEnumerable<Permutation> permutations) {
+      var iter = permutations.GetEnumerator();
+      if (!iter.MoveNext()) yield break;
+      var bestImprovement = BestImprovement;
+
+      var qap = (QuadraticAssignmentProblem)Problem;
+      var min = qap.LowerBound.Value;
+      var max = qap.AverageQuality.Value;
+
+      var start = iter.Current;
+
+      while (iter.MoveNext()) {
+        var startFitness = QAPEvaluator.Apply(start, qap.Weights, qap.Distances);
+        EvaluatedSolutionEquiv++;
+        var end = iter.Current;
+
+        var invSol = new int[start.Length];
+        Func<Tuple<Permutation, double>, IEnumerable<Tuple<Permutation, double>>> regularNeighborFunc = (p) => RestrictedNeighborhood(qap, p.Item1, p.Item2, end, invSol);
+        var walk = DirectedWalk<Permutation>.WalkRestricted(qap.Maximization.Value, regularNeighborFunc, start, startFitness, !bestImprovement);
+
+        var trail = new List<Tuple<Permutation, double>>();
+        foreach (var step in walk) {
+          for (var i = 0; i < invSol.Length; i++)
+            invSol[step.Item1[i]] = i;
+          trail.Add(Tuple.Create(step.Item1, (step.Item2 - min) / (max - min)));
+        }
+        yield return trail;
+
+        start = end;
+      } // end paths
+    }
+
+    private IEnumerable<Tuple<Permutation, double>> RestrictedInverseNeighborhood(QuadraticAssignmentProblem qap, Permutation current, double currentFit, Permutation start) {
+      var evalSolPerMove = 4.0 / current.Length;
+      var N = current.Length;
+      for (var index = 0; index < N; index++) {
+        if (current[index] != start[index]) continue;
+        for (var k = 0; k < N; k++) {
+          if (k == index) continue;
+          var fit = QAPSwap2MoveEvaluator.Apply(current, new Swap2Move(index, k), qap.Weights, qap.Distances);
+          EvaluatedSolutionEquiv += evalSolPerMove;
+          current.Swap(index, k);
+          yield return Tuple.Create(current, currentFit + fit);
+          current.Swap(index, k); // reverse
+        }
+      }
+    }
+
+    private IEnumerable<Tuple<Permutation, double>> RestrictedNeighborhood(QuadraticAssignmentProblem qap, Permutation current, double currentFit, Permutation target, int[] inverse) {
+      var evalSolPerMove = 4.0 / current.Length;
+      for (var index = 0; index < current.Length; index++) {
+        if (current[index] == target[index]) continue;
+        var k = inverse[target[index]];
+        var fit = QAPSwap2MoveEvaluator.Apply(current, new Swap2Move(index, k), qap.Weights, qap.Distances);
+        EvaluatedSolutionEquiv += evalSolPerMove;
+        current.Swap(index, k);
+        yield return Tuple.Create(current, currentFit + fit);
+        current.Swap(index, k); // reverse
+      }
+    }
+
+    // permutation must be strictly different in every position
+    private static void BiasedShuffle(Permutation p, IRandom 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);
+        var h = p[swapIndex];
+        p[swapIndex] = p[i];
+        p[i] = h;
+      }
+    }
+  }
+}
Index: branches/2457_ExpertSystem/WalkExporter/Program.cs
===================================================================
--- branches/2457_ExpertSystem/WalkExporter/Program.cs	(revision 16955)
+++ branches/2457_ExpertSystem/WalkExporter/Program.cs	(revision 16955)
@@ -0,0 +1,302 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2018 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.Linq;
+using System.Text.RegularExpressions;
+using HeuristicLab.Random;
+using ProtoBuf;
+using static HeuristicLab.Analysis.FitnessLandscape.QAPDirectedWalk;
+
+namespace WalkExporter {
+  class Program {
+    public static readonly string[] SBF = new[] { "Sharpness", "Bumpiness", "Flatness" };
+    public static readonly string[] RUG = new[] {
+      "AC1", "CorrelationLength" };
+    public static readonly string[] IAL = new[] {
+      "InformationContent", "DensityBasinInformation", "PartialInformationContent",
+      "InformationStability", "Diversity", "Regularity", "TotalEntropy", "SymmetricInformationContent",
+      "SymmetricDensityBasinInformation", "SymmetricTotalEntropy", "PeakInformationContent", "PeakDensityBasinInformation",
+      "PeakTotalEntropy", "PeakSymmetricInformationContent", "PeakSymmetricDensityBasinInformation", "PeakSymmetricTotalEntropy" };
+    public static readonly string[] IALREG = new[] {
+      "InformationContent", "DensityBasinInformation", "PartialInformationContent",
+      "InformationStability", "Diversity", "Regularity", "TotalEntropy",
+      "PeakInformationContent", "PeakDensityBasinInformation", "PeakTotalEntropy"
+    };
+    public static readonly string[] IALSYM = new[] {
+      "PartialInformationContent", "InformationStability", "Diversity", "Regularity",
+      "SymmetricInformationContent", "SymmetricDensityBasinInformation", "SymmetricTotalEntropy",
+      "PeakSymmetricInformationContent", "PeakSymmetricDensityBasinInformation", "PeakSymmetricTotalEntropy"
+    };
+    
+
+    static void Main(string[] args) {
+      //AnalyzeRandomWalkIdentification();
+      //AnalyzeDirectedWalkIdentification();
+      var provider = new HeuristicLab.Problems.Instances.QAPLIB.QAPLIBInstanceProvider();
+      var tai30a = provider.LoadData(provider.GetDataDescriptors().Single(x => x.Name == "tai30a"));
+      RandomWalk.ConfinedRandomWalkAnalysis(tai30a);
+      var esc32f = provider.LoadData(provider.GetDataDescriptors().Single(x => x.Name == "esc32f"));
+      RandomWalk.ConfinedRandomWalkAnalysis(esc32f);
+    }
+
+    private static void AnalyzeRandomWalkIdentification() {
+      string[] RUG_IAL = RUG.Concat(IAL).ToArray();
+
+      var trainFiles = GetFiles(@"randwalk_kb_train_(?<eff>\d+)");
+      var testFiles = GetFiles(@"randwalk_kb_test_(?<eff>\d+)");
+
+      var filename = "randwalk_results.csv";
+
+      var features = new[] { (Name: "RUG", Set: RUG), (Name: "IAL", Set: IAL),
+        (Name: "IALREG", Set: IALREG), (Name: "IALSYM", Set: IALSYM), (Name: "RUG_IAL", Set: RUG_IAL) };
+
+      using (var writer = File.CreateText(filename)) {
+        CompareMatching(trainFiles, testFiles, features, "randwalk", writer);
+      }
+    }
+
+    private static void AnalyzeDirectedWalkIdentification() {
+      string[] RUG_IAL = RUG.Concat(IAL).ToArray();
+      string[] SBF_RUG = SBF.Concat(RUG).ToArray();
+      string[] SBF_IAL = SBF.Concat(IAL).ToArray();
+      string[] SBF_IALREG = SBF.Concat(IALREG).ToArray();
+      string[] SBF_IALSYM = SBF.Concat(IALSYM).ToArray();
+
+      var features = new[] { (Name: "RUG", Set: RUG), (Name: "IAL", Set: IAL),
+        (Name: "IALREG", Set: IALREG), (Name: "IALSYM", Set: IALSYM), (Name: "SBF", Set: SBF),
+        (Name: "RUG_IAL", Set: RUG_IAL), (Name: "SBF_RUG", Set: SBF_RUG), (Name: "SBF_IAL", Set: SBF_IAL),
+        (Name: "SBF_IALREG", Set: SBF_IALREG), (Name: "SBF_IALSYM", Set: SBF_IALSYM) };
+
+
+      var trainFiles = GetFiles(@"rrdw_best_kb_train_(?<eff>\d+)_qap");
+      var testFiles = GetFiles(@"rrdw_best_kb_test_(?<eff>\d+)_qap");
+
+      var filename = "rrdw_best_results.csv";
+
+      //using (var writer = File.CreateText(filename)) {
+      //  CompareMatching(trainFiles, testFiles, features, "(rr)-dw", writer);
+      //}
+      //trainFiles = GetFiles(@"rldw_best_kb_train_(?<eff>\d+)_qap");
+      //testFiles = GetFiles(@"rldw_best_kb_test_(?<eff>\d+)_qap");
+
+      //filename = "rldw_best_results.csv";
+
+      //using (var writer = File.CreateText(filename)) {
+      //  CompareMatching(trainFiles, testFiles, features, "(rl)-dw", writer);
+      //}
+
+      trainFiles = GetFiles(@"lldw_best_kb_train_(?<eff>\d+)_qap");
+      testFiles = GetFiles(@"lldw_best_kb_test_(?<eff>\d+)_qap");
+
+      filename = "lldw_best_results.csv";
+
+      using (var writer = File.CreateText(filename)) {
+        CompareMatching(trainFiles, testFiles, features, "(ll)-dw", writer);
+      }
+
+      trainFiles = GetFiles(@"lidw_best_kb_train_(?<eff>\d+)_qap");
+      testFiles = GetFiles(@"lidw_best_kb_test_(?<eff>\d+)_qap");
+
+      filename = "lidw_best_results.csv";
+
+      using (var writer = File.CreateText(filename)) {
+        CompareMatching(trainFiles, testFiles, features, "(li)-dw", writer);
+      }
+    }
+
+    private static List<(string Filename, int Effort)> GetFiles(string pattern) {
+      // randwalk_kb_(train|test)_{n}.buf
+      // {type}dw_best_kb_(train|test)_{n}_qap.buf
+
+      return Directory.EnumerateFiles(".").Where(x => x.EndsWith(".buf"))
+        .Select(x => {
+          var match = Regex.Match(Path.GetFileName(x), pattern);
+          if (match.Success) {
+            return (Filename: x, Effort: int.Parse(match.Groups["eff"].Value));
+          }
+          return (Filename: "", Effort: -1);
+        }).Where(x => !string.IsNullOrEmpty(x.Filename)).ToList();
+    }
+
+    private static void CompareMatching(List<(string Filename, int Effort)> trainFiles,
+        List<(string Filename, int Effort)> testFiles, (string Name, string[] Set)[] featuresets,
+        string type,
+        StreamWriter writer) {
+      var random = new MersenneTwister(42);
+      var header = string.Format("{0}\t{1}\t{2}\t{3}\t{4}\t{5}\t{6}\t{7}\t{8}\t{9}\t{10}\t{11}",
+          "Dimension", "FSet", "Type", "TrainEff", "TestEff", "ExCnt", "ExRnk", "ClsCnt", "ClsRnk", "TotCnt", "TrainEffSolEquiv", "TestEffSolEquiv");
+      writer.WriteLine(header);
+      Console.WriteLine(header);
+
+      foreach (var features in featuresets) {
+        foreach (var dim in new[] { 20, 30, 40 }) {
+          foreach (var a in trainFiles) {
+            Knowledgebase train = null;
+            using (var stream = File.OpenRead(a.Filename))
+              train = Serializer.Deserialize<Knowledgebase>(stream);
+
+            train.Problems.RemoveAll(x => x.Dimension != dim);
+            if (train.Problems.Count == 0) throw new InvalidOperationException("Dimension does not exist: " + dim);
+
+            var standardizer = InstancesStandardizer.CreateAndApply(train.Problems, features.Set);
+
+            foreach (var b in testFiles) {
+              Knowledgebase test = null;
+              using (var stream = File.OpenRead(b.Filename))
+                test = Serializer.Deserialize<Knowledgebase>(stream);
+
+              test.Problems.RemoveAll(x => x.Dimension != dim);
+              standardizer.Apply(test.Problems);
+              // MATCH
+
+              var match = EvaluateMatch(random, train, test, new HashSet<string>(features.Set));
+
+              //correlation analysis
+              //var corr = AnalyzeFeatureCorrelation(features.Set, train, test);
+
+              string output = string.Format("{0}\t{1}\t{2}\t{3}\t{4}\t{5}\t{6:F2}\t{7}\t{8:F2}\t{9}\t{10:F2}\t{11:F2}",
+                dim, features.Name, type, a.Effort, b.Effort, match.ExactCount,
+                match.ExactAverageRank, match.ClsCount, match.ClsAverageRank, match.TotalCount,
+                match.TrainingDescriptionEffort, match.TestDescriptionEffort);
+              writer.WriteLine(output);
+              Console.WriteLine(output);
+            }
+          }
+        }
+      }
+    }
+
+    private static MatchResult EvaluateMatch(MersenneTwister random, Knowledgebase train, Knowledgebase test, ISet<string> features) {
+      var result = new MatchResult();
+
+      foreach (var x in train.Problems) {
+
+        var ranked = test.Problems.Shuffle(random).Select(y => new {
+          Instance = y,
+          Distance = (from xx in x.Features.Where(f => features.Contains(f.Key))
+                      from yy in y.Features.Where(f => features.Contains(f.Key))
+                      where xx.Key == yy.Key
+                      let vxx = xx.GetNumericValue()
+                      let vyy = yy.GetNumericValue()
+                      select (vxx - vyy) * (vxx - vyy)).Sum(),
+        }).OrderBy(xx => xx.Distance).ToList();
+
+        var exactRank = -1;
+        var clsRank = -1;
+        var count = 1;
+        foreach (var r in ranked) {
+          result.TestDescriptionEffort += r.Instance.DescriptionEffort;
+          if (clsRank < 0 && r.Instance.Class == x.Class) {
+            clsRank = count;
+          }
+          if (r.Instance.Name == x.Name) {
+            exactRank = count;
+            break;
+          }
+          count++;
+        }
+        result.TestDescriptionEffort /= test.Problems.Count;
+        if (exactRank == 1) result.ExactCount++;
+        if (clsRank == 1) result.ClsCount++;
+        result.TotalCount++;
+
+        result.TrainingDescriptionEffort += x.DescriptionEffort;
+        result.ExactAverageRank += exactRank;
+        result.ClsAverageRank += clsRank;
+
+      }
+      result.TrainingDescriptionEffort /= train.Problems.Count;
+      result.ExactAverageRank /= train.Problems.Count;
+      result.ClsAverageRank /= train.Problems.Count;
+
+      return result;
+    }
+
+    private static double[,] AnalyzeFeatureCorrelation(string[] features, Knowledgebase train, Knowledgebase test) {
+      var trainMat = new double[train.Problems.Count, features.Length];
+      var testMat = new double[test.Problems.Count, features.Length];
+      int trainCount = 0, testCount = 0;
+
+      foreach (var x in train.Problems) {
+        var xFeatures = x.GetNumericFeatures(features);
+        foreach (var f in xFeatures.Select((v, i) => new { Index = i, Value = v })) {
+          trainMat[trainCount, f.Index] = f.Value;
+        }
+        trainCount++;
+      }
+      foreach (var y in test.Problems) {
+        var yFeatures = y.GetNumericFeatures(features);
+        foreach (var f in yFeatures.Select((v, i) => new { Index = i, Value = v })) {
+          testMat[testCount, f.Index] = f.Value;
+        }
+        testCount++;
+      }
+
+      double[,] corr;
+      alglib.pearsoncorrm2(trainMat, testMat, out corr);
+      return corr;
+    }
+
+    private static void DoRandomWalk() {
+      var experiment = RandomWalk.PerformExperiment();
+      Serializer.Serialize(File.Create("randwalk_trials_qap.buf"), experiment);
+      foreach (var exp in Enumerable.Range(7, 18 - 6)) {
+        var len = (int)Math.Pow(2, exp);
+        var (training, test) = RandomWalk.GetKnowledgeBases(experiment, len);
+        Serializer.Serialize(File.Create($"randwalk_kb_train_{exp}.buf"), training);
+        Serializer.Serialize(File.Create($"randwalk_kb_test_{exp}.buf"), test);
+      }
+    }
+
+    private static void DoDirectedWalk() {
+      var (exp, train, test) = DirectedWalk.PerformExperiment(WalkType.RandomRandom);
+      Save("rrdw_best", exp, train, test);
+      (exp, train, test) = DirectedWalk.PerformExperiment(WalkType.RandomLocal);
+      Save("rldw_best", exp, train, test);
+      (exp, train, test) = DirectedWalk.PerformExperiment(WalkType.LocalLocal);
+      Save("lldw_best", exp, train, test);
+      (exp, train, test) = DirectedWalk.PerformExperiment(WalkType.LocalInverse);
+      Save("lidw_best", exp, train, test);
+    }
+
+    private static void Save(string v, Experiment exp, Dictionary<int, Knowledgebase> train, Dictionary<int, Knowledgebase> test) {
+      Serializer.Serialize(File.Create(v + "_experiment_qap.buf"), exp);
+      foreach (var t in train.Keys) {
+        Serializer.Serialize(File.Create(v + $"_kb_train_{t}_qap.buf"), train[t]);
+        Serializer.Serialize(File.Create(v + $"_kb_test_{t}_qap.buf"), test[t]);
+      }
+    }
+  }
+
+  public 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; }
+
+    public double TrainingDescriptionEffort { get; set; }
+    public double TestDescriptionEffort { get; set; }
+  }
+}
Index: branches/2457_ExpertSystem/WalkExporter/Properties/AssemblyInfo.cs
===================================================================
--- branches/2457_ExpertSystem/WalkExporter/Properties/AssemblyInfo.cs	(revision 16955)
+++ branches/2457_ExpertSystem/WalkExporter/Properties/AssemblyInfo.cs	(revision 16955)
@@ -0,0 +1,36 @@
+﻿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("WalkExporter")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("WalkExporter")]
+[assembly: AssemblyCopyright("Copyright ©  2018")]
+[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("ee6bd7d3-8012-4a5d-abae-356b3d1e4573")]
+
+// 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("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
Index: branches/2457_ExpertSystem/WalkExporter/RandomWalk.cs
===================================================================
--- branches/2457_ExpertSystem/WalkExporter/RandomWalk.cs	(revision 16955)
+++ branches/2457_ExpertSystem/WalkExporter/RandomWalk.cs	(revision 16955)
@@ -0,0 +1,189 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2018 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.Linq;
+using HeuristicLab.Analysis.FitnessLandscape;
+using HeuristicLab.Core;
+using HeuristicLab.Encodings.PermutationEncoding;
+using HeuristicLab.Problems.Instances;
+using HeuristicLab.Problems.Instances.QAPLIB;
+using HeuristicLab.Random;
+using ProtoBuf;
+
+namespace WalkExporter {
+  class RandomWalk {
+    public static (Knowledgebase training, Knowledgebase test) GetKnowledgeBases(Experiment experiment, int length) {
+      var training = new Knowledgebase() { Problems = new List<ProblemInstanceDescriptor>() };
+      var test = new Knowledgebase() { Problems = new List<ProblemInstanceDescriptor>() };
+      foreach (var trial in experiment.Trials) {
+        foreach (var desc in AnalyzeEachWalk(trial, length)) {
+          if (training.Problems.Count == test.Problems.Count)
+            training.Problems.Add(desc);
+          else test.Problems.Add(desc);
+        }
+      }
+      return (training, test);
+    }
+
+    private static IEnumerable<ProblemInstanceDescriptor> AnalyzeEachWalk(Exploration trial, int length) {
+      var instance = trial.Problem;
+      var dim = trial.Dimension;
+      foreach (var walk in trial.Walks) {
+        var trail = walk.QualityTrail.Take(length).ToArray();
+        var clen = RuggednessCalculator.CalculateCorrelationLength(trail, out double[] acf);
+        var ia = new InformationAnalysis(trail);
+        var desc = new ProblemInstanceDescriptor() {
+          Name = instance,
+          Class = Util.GetGeneratorClass(instance),
+          Dimension = dim,
+          DescriptionEffort = length * 4.0 / dim,
+        };
+        desc.Features = new List<KeyValue>();
+        desc.Features.Add(new KeyValue { Key = "AC1", ContinuousValue = acf[1] });
+        desc.Features.Add(new KeyValue { Key = "CorrelationLength", DiscreteValue = clen });
+        foreach (var f in ia.GetFeatures()) {
+          if (f.Item2 is double d) desc.Features.Add(new KeyValue { Key = f.Item1, ContinuousValue = d });
+          else if (f.Item2 is int i) desc.Features.Add(new KeyValue { Key = f.Item1, DiscreteValue = i });
+        }
+        yield return desc;
+      }
+    }
+
+    public static Experiment PerformExperiment() {
+      var experiment = new Experiment() { Algorithm = "RandomWalk", Trials = new List<Exploration>() };
+      foreach (var dimension in new[] { 20, 30, 40 }) {
+        var provider = new OneSizeInstanceProvider(dimension);
+        foreach (var desc in provider.GetDataDescriptors()) {
+          var qapData = provider.LoadData(desc);
+          var exploration = new Exploration() { Problem = qapData.Name, Dimension = qapData.Dimension, Walks = new List<Walk>() };
+          for (var r = 0; r < 2; r++) {
+            var walk = RandomWalk.Run(new MersenneTwister((uint)(r + 13)), qapData).Take((int)Math.Pow(2, 18)).ToList();
+            exploration.Walks.Add(new Walk() { QualityTrail = walk });
+          }
+          experiment.Trials.Add(exploration);
+        }
+      }
+      return experiment;
+    }
+
+    public static IEnumerable<double> Run(IRandom random, QAPData qap) {
+      var sol = new Permutation(PermutationTypes.Absolute, qap.Dimension, random);
+      var fit = Util.Evaluate(sol, qap);
+      yield return fit;
+      while (true) {
+        var z1 = random.Next(qap.Dimension);
+        var z2 = (z1 + random.Next(1, qap.Dimension)) % qap.Dimension;
+        var move = Util.EvaluateSwap2Diff(sol, z1, z2, qap);
+        fit += move;
+        yield return fit;
+        sol.Swap(z1, z2);
+      }
+    }
+
+    ///////////////////////////////////////////////////////////////////////////////////
+    ///                             CONFINED RANDOM WALK                            ///
+    ///////////////////////////////////////////////////////////////////////////////////
+
+    
+    public static void ConfinedRandomWalkAnalysis(QAPData qapData) {
+      Exploration exploration = null;
+      if (File.Exists($"confinedrandwalk_{qapData.Name}.buf")) {
+        using (var file = File.OpenRead($"confinedrandwalk_{qapData.Name}.buf")) {
+          exploration = Serializer.Deserialize<Exploration>(file);
+        }
+      } else {
+        exploration = PerformCondinedRandomwWalkExploration(qapData, 100);
+        using (var file = File.Create($"confinedrandwalk_{qapData.Name}.buf")) {
+          Serializer.Serialize(file, exploration);
+        }
+      }
+
+      using (var writer = File.CreateText($"confinedrandwalk_{qapData.Name}.csv")) {
+        var headers = new[] { "Run", "Algorithm Name", "Problem Name", "Dimension", "Ld(Iterations)", "Iterations", "Effort",
+          "AC1", "CorrelationLength", "InformationContent", "DensityBasinInformation", "PartialInformationContent",
+          "InformationStability", "Diversity", "Regularity", "TotalEntropy", "SymmetricInformationContent",
+          "SymmetricDensityBasinInformation", "SymmetricTotalEntropy", "PeakInformationContent", "PeakDensityBasinInformation",
+          "PeakTotalEntropy", "PeakSymmetricInformationContent", "PeakSymmetricDensityBasinInformation", "PeakSymmetricTotalEntropy" };
+        var order = headers.Select((v, i) => new { Index = i, Header = v }).ToDictionary(x => x.Header, x => x.Index);
+        writer.WriteLine(string.Format(string.Join(";", Enumerable.Range(0, headers.Length).Select(x => "{" + x + "}")), headers));
+        foreach (var exp in Enumerable.Range(7, 18 - 6)) {
+          var length = (int)Math.Pow(2, exp);
+          var run = 0;
+          foreach (var desc in AnalyzeEachWalk(exploration, length)) {
+            var features = string.Join(";", desc.Features.OrderBy(x => order[x.Key]).Select(x => x.GetNumericValue().ToString()));
+            writer.WriteLine(string.Format("R{0};Confined Random Walk;{5};{6};{1};{2};{3};{4}", run, exp, length, length * 4.0 / qapData.Dimension, features, qapData.Name, qapData.Dimension));
+            run++;
+          }
+        }
+      }
+    }
+
+    private static Exploration PerformCondinedRandomwWalkExploration(QAPData qapData, int repetitions) {
+      var exploration = new Exploration() { Problem = qapData.Name, Dimension = qapData.Dimension, Walks = new List<Walk>() };
+      for (var r = 0; r < repetitions; r++) {
+        var walk = RunConfined(new MersenneTwister((uint)r), qapData, qapData.Dimension / 5).Take((int)Math.Pow(2, 18)).ToList();
+        exploration.Walks.Add(new Walk() { QualityTrail = walk });
+      }
+      return exploration;
+    }
+
+    public static IEnumerable<double> RunConfined(IRandom random, QAPData qap, int distance) {
+      var sol = new Permutation(PermutationTypes.Absolute, qap.Dimension, random);
+      var anchor = (Permutation)sol.Clone();
+      var fit = Util.Evaluate(sol, qap);
+      var dist = 0;
+      yield return fit;
+
+      while (true) {
+        var (j, k, deltaDist) = MoveConfined(random, sol, anchor, dist, distance);
+        dist += deltaDist;
+        var move = Util.EvaluateSwap2Diff(sol, j, k, qap);
+        fit += move;
+        yield return fit;
+        sol.Swap(j, k);
+      }
+    }
+
+    private static (int j, int k, int deltaDist) MoveConfined(IRandom random, Permutation current, Permutation anchor, int dist, int maxDist) {
+      var evalSolPerMove = 4.0 / current.Length;
+      var orderJ = Enumerable.Range(0, current.Length).Shuffle(random);
+      var orderK = Enumerable.Range(0, current.Length).Shuffle(random);
+      foreach (var j in orderJ) {
+        if (dist == maxDist && current[j] == anchor[j]) continue;
+        foreach (var k in orderK) {
+          if (j == k) continue;
+          var distChange = 0;
+          if (current[j] != anchor[j] && current[k] == anchor[j]) distChange--;
+          if (current[k] != anchor[k] && current[j] == anchor[k]) distChange--;
+          if (current[j] == anchor[j]) distChange++;
+          if (current[k] == anchor[k]) distChange++;
+          if (dist + distChange > maxDist) continue;
+
+          return (j, k, distChange);
+        }
+      }
+      return (-1, -1, 0);
+    }
+  }
+}
Index: branches/2457_ExpertSystem/WalkExporter/Standardizer.cs
===================================================================
--- branches/2457_ExpertSystem/WalkExporter/Standardizer.cs	(revision 16955)
+++ branches/2457_ExpertSystem/WalkExporter/Standardizer.cs	(revision 16955)
@@ -0,0 +1,47 @@
+﻿using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+
+namespace WalkExporter {
+  public class InstancesStandardizer {
+    private IDictionary<string, (double Avg, double Stdev)> normalization;
+
+    public IEnumerable<double> GetMeans() {
+      return normalization.Select(x => x.Value.Item1);
+    }
+    public IEnumerable<double> GetStdevs() {
+      return normalization.Select(x => x.Value.Item2);
+    }
+
+    private InstancesStandardizer(IList<ProblemInstanceDescriptor> instances, IEnumerable<string> features) {
+      normalization = instances
+        .SelectMany(x => x.Features)
+        .GroupBy(x => x.Key)
+        .ToDictionary(x => x.Key,
+                      x => {
+                        var values = x.Select(y => y.GetNumericValue());
+                        return (Avg: values.Average(), Stdev: values.StandardDeviation());
+                      });
+    }
+
+    public static InstancesStandardizer Create(IList<ProblemInstanceDescriptor> instances, IEnumerable<string> features) {
+      return new InstancesStandardizer(instances, features);
+      
+    }
+    public static InstancesStandardizer CreateAndApply(IList<ProblemInstanceDescriptor> instances, IEnumerable<string> features) {
+      var standardizer = Create(instances, features);
+      standardizer.Apply(instances);
+      return standardizer;
+    }
+
+    public void Apply(IList<ProblemInstanceDescriptor> instances) {
+      for (var i = 0; i < instances.Count; i++) {
+        var inst = instances[i];
+        for (var x = 0; x < inst.Features.Count; x++) {
+          var feat = inst.Features[x];
+          feat.SetNumericValue((inst.Features[x].GetNumericValue() - normalization[feat.Key].Avg) / normalization[feat.Key].Stdev);
+        }
+      }
+    }
+  }
+}
Index: branches/2457_ExpertSystem/WalkExporter/Util.cs
===================================================================
--- branches/2457_ExpertSystem/WalkExporter/Util.cs	(revision 16955)
+++ branches/2457_ExpertSystem/WalkExporter/Util.cs	(revision 16955)
@@ -0,0 +1,95 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2018 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.Linq;
+using System.Text.RegularExpressions;
+using HeuristicLab.Encodings.PermutationEncoding;
+using HeuristicLab.Problems.Instances;
+
+namespace WalkExporter {
+  static class Util {
+
+    public static double Evaluate(Permutation sol, QAPData qap) {
+      var weights = qap.Weights;
+      var distances = qap.Distances;
+      var q = 0.0;
+      for (var i = 0; i < sol.Length; i++)
+        for (var j = 0; j < sol.Length; j++)
+          q += weights[i, j] * distances[sol[i], sol[j]];
+      return q;
+    }
+
+    public static double EvaluateSwap2Diff(Permutation sol, int a, int b, QAPData qap) {
+      if (a == b) return 0;
+      double moveQuality = 0;
+      int fac1 = a, fac2 = b;
+      int loc1 = sol[fac1], loc2 = sol[fac2];
+      var weights = qap.Weights;
+      var distances = qap.Distances;
+
+      for (int j = 0; j < sol.Length; j++) {
+        if (j == fac1) {
+          moveQuality += weights[fac1, fac1] * (distances[loc2, loc2] - distances[loc1, loc1]);
+          moveQuality += weights[fac1, fac2] * (distances[loc2, loc1] - distances[loc1, loc2]);
+        } else if (j == fac2) {
+          moveQuality += weights[fac2, fac2] * (distances[loc1, loc1] - distances[loc2, loc2]);
+          moveQuality += weights[fac2, fac1] * (distances[loc1, loc2] - distances[loc2, loc1]);
+        } else {
+          int locJ = sol[j];
+          moveQuality += weights[fac1, j] * (distances[loc2, locJ] - distances[loc1, locJ]);
+          moveQuality += weights[j, fac1] * (distances[locJ, loc2] - distances[locJ, loc1]);
+          moveQuality += weights[fac2, j] * (distances[loc1, locJ] - distances[loc2, locJ]);
+          moveQuality += weights[j, fac2] * (distances[locJ, loc1] - distances[locJ, loc2]);
+        }
+      }
+      return moveQuality;
+    }
+
+    public static int Dist(Permutation a, Permutation b) {
+      var dist = 0;
+      for (var i = 0; i < a.Length; i++)
+        if (a[i] != b[i]) dist++;
+      return dist;
+    }
+
+    public static string GetGeneratorClass(string name) {
+      var match = Regex.Match(name, @"(?<n>.*)-\d+$");
+      if (match.Success) {
+        name = match.Groups["n"].Value;
+      }
+      var subCls = name.Last();
+      var cls = name.Substring(0, 3);
+      switch (cls) {
+        case "lip":
+          cls = name.Substring(0, 4) + "-" + subCls;
+          break;
+        case "RAN":
+          cls = name.Substring(0, 4) + "-" + name[name.Length - 2] + name[name.Length - 1];
+          break;
+        case "tai":
+          if (Regex.IsMatch(name, "tai\\d+e\\d+")) cls += "-e";
+          else if (char.IsLetter(subCls)) cls += "-" + subCls;
+          break;
+      }
+      return cls;
+    }
+  }
+}
Index: branches/2457_ExpertSystem/WalkExporter/WalkExporter.csproj
===================================================================
--- branches/2457_ExpertSystem/WalkExporter/WalkExporter.csproj	(revision 16955)
+++ branches/2457_ExpertSystem/WalkExporter/WalkExporter.csproj	(revision 16955)
@@ -0,0 +1,150 @@
+﻿<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProjectGuid>{EE6BD7D3-8012-4A5D-ABAE-356B3D1E4573}</ProjectGuid>
+    <OutputType>Exe</OutputType>
+    <RootNamespace>WalkExporter</RootNamespace>
+    <AssemblyName>WalkExporter</AssemblyName>
+    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <PlatformTarget>AnyCPU</PlatformTarget>
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <Prefer32Bit>false</Prefer32Bit>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <PlatformTarget>AnyCPU</PlatformTarget>
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="alglibnet2">
+      <HintPath>.\alglibnet2.dll</HintPath>
+    </Reference>
+    <Reference Include="HeuristicLab.Collections-3.3">
+      <HintPath>..\..\..\trunk\bin\HeuristicLab.Collections-3.3.dll</HintPath>
+      <Private>True</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.Common-3.3">
+      <HintPath>..\..\..\trunk\bin\HeuristicLab.Common-3.3.dll</HintPath>
+      <Private>True</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.Core-3.3">
+      <HintPath>..\..\..\trunk\bin\HeuristicLab.Core-3.3.dll</HintPath>
+      <Private>True</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.Data-3.3">
+      <HintPath>..\..\..\trunk\bin\HeuristicLab.Data-3.3.dll</HintPath>
+      <Private>True</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.Operators-3.3">
+      <HintPath>..\..\..\trunk\bin\HeuristicLab.Operators-3.3.dll</HintPath>
+      <Private>True</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.Optimization.Operators-3.3, Version=3.3.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\trunk\bin\HeuristicLab.Optimization.Operators-3.3.dll</HintPath>
+    </Reference>
+    <Reference Include="HeuristicLab.Persistence-3.3">
+      <HintPath>..\..\..\trunk\bin\HeuristicLab.Persistence-3.3.dll</HintPath>
+      <Private>True</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.PluginInfrastructure-3.3">
+      <HintPath>..\..\..\trunk\bin\HeuristicLab.PluginInfrastructure-3.3.dll</HintPath>
+      <Private>True</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.Problems.Instances-3.3">
+      <HintPath>..\..\..\trunk\bin\HeuristicLab.Problems.Instances-3.3.dll</HintPath>
+      <Private>True</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.Problems.QuadraticAssignment-3.3">
+      <HintPath>..\..\..\trunk\bin\HeuristicLab.Problems.QuadraticAssignment-3.3.dll</HintPath>
+      <Private>True</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.Random-3.3">
+      <HintPath>..\..\..\trunk\bin\HeuristicLab.Random-3.3.dll</HintPath>
+      <Private>True</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.Selection-3.3">
+      <HintPath>..\..\..\trunk\bin\HeuristicLab.Selection-3.3.dll</HintPath>
+      <Private>True</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.SequentialEngine-3.3">
+      <HintPath>..\..\..\trunk\bin\HeuristicLab.SequentialEngine-3.3.dll</HintPath>
+      <Private>True</Private>
+    </Reference>
+    <Reference Include="protobuf-net, Version=2.4.0.0, Culture=neutral, PublicKeyToken=257b51d87d2e4d67, processorArchitecture=MSIL">
+      <HintPath>..\packages\protobuf-net.2.4.0\lib\net40\protobuf-net.dll</HintPath>
+    </Reference>
+    <Reference Include="System" />
+    <Reference Include="System.Configuration" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Runtime.Serialization" />
+    <Reference Include="System.ServiceModel" />
+    <Reference Include="System.ValueTuple, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
+      <HintPath>..\packages\System.ValueTuple.4.5.0\lib\netstandard1.0\System.ValueTuple.dll</HintPath>
+    </Reference>
+    <Reference Include="System.Xml.Linq" />
+    <Reference Include="System.Data.DataSetExtensions" />
+    <Reference Include="Microsoft.CSharp" />
+    <Reference Include="System.Data" />
+    <Reference Include="System.Net.Http" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="AdaptiveWalks.cs" />
+    <Compile Include="Data.cs" />
+    <Compile Include="RandomWalk.cs" />
+    <Compile Include="DirectedWalk.cs" />
+    <Compile Include="Program.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="Standardizer.cs" />
+    <Compile Include="Util.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="App.config" />
+    <None Include="packages.config" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\HeuristicLab.Analysis.FitnessLandscape\3.3\HeuristicLab.Analysis.FitnessLandscape-3.3.csproj">
+      <Project>{5fbdcd4a-3c2a-4ec6-83ce-34b29f43621a}</Project>
+      <Name>HeuristicLab.Analysis.FitnessLandscape-3.3</Name>
+      <Private>True</Private>
+    </ProjectReference>
+    <ProjectReference Include="..\HeuristicLab.Analysis\3.3\HeuristicLab.Analysis-3.3.csproj">
+      <Project>{887425b4-4348-49ed-a457-b7d2c26ddbf9}</Project>
+      <Name>HeuristicLab.Analysis-3.3</Name>
+      <Private>True</Private>
+    </ProjectReference>
+    <ProjectReference Include="..\HeuristicLab.Encodings.PermutationEncoding\3.3\HeuristicLab.Encodings.PermutationEncoding-3.3.csproj">
+      <Project>{dbecb8b0-b166-4133-baf1-ed67c3fd7fca}</Project>
+      <Name>HeuristicLab.Encodings.PermutationEncoding-3.3</Name>
+      <Private>True</Private>
+    </ProjectReference>
+    <ProjectReference Include="..\HeuristicLab.Optimization\3.3\HeuristicLab.Optimization-3.3.csproj">
+      <Project>{14ab8d24-25bc-400c-a846-4627aa945192}</Project>
+      <Name>HeuristicLab.Optimization-3.3</Name>
+      <Private>True</Private>
+    </ProjectReference>
+    <ProjectReference Include="..\HeuristicLab.Problems.Instances.QAPLIB\3.3\HeuristicLab.Problems.Instances.QAPLIB-3.3.csproj">
+      <Project>{73f29d43-5714-4069-8fab-0d18feb5f175}</Project>
+      <Name>HeuristicLab.Problems.Instances.QAPLIB-3.3</Name>
+      <Private>True</Private>
+    </ProjectReference>
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+</Project>
Index: branches/2457_ExpertSystem/WalkExporter/packages.config
===================================================================
--- branches/2457_ExpertSystem/WalkExporter/packages.config	(revision 16955)
+++ branches/2457_ExpertSystem/WalkExporter/packages.config	(revision 16955)
@@ -0,0 +1,5 @@
+﻿<?xml version="1.0" encoding="utf-8"?>
+<packages>
+  <package id="protobuf-net" version="2.4.0" targetFramework="net45" />
+  <package id="System.ValueTuple" version="4.5.0" targetFramework="net45" />
+</packages>
