Index: /branches/1614_GeneralizedQAP/GeneralizedQAP.sln
===================================================================
--- /branches/1614_GeneralizedQAP/GeneralizedQAP.sln	(revision 15701)
+++ /branches/1614_GeneralizedQAP/GeneralizedQAP.sln	(revision 15702)
@@ -26,5 +26,10 @@
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HeuristicLab.Optimization.Views-3.3", "HeuristicLab.Optimization.Views\3.3\HeuristicLab.Optimization.Views-3.3.csproj", "{662B4B15-8F4D-4AE5-B3EB-D91C215F5AF2}"
 EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HeuristicLab.Analysis.FitnessLandscape-3.3", "HeuristicLab.Analysis.FitnessLandscape\3.3\HeuristicLab.Analysis.FitnessLandscape-3.3.csproj", "{5FBDCD4A-3C2A-4EC6-83CE-34B29F43621A}"
+EndProject
 Global
+	GlobalSection(Performance) = preSolution
+		HasPerformanceSessions = true
+	EndGlobalSection
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Any CPU = Debug|Any CPU
@@ -156,4 +161,16 @@
 		{662B4B15-8F4D-4AE5-B3EB-D91C215F5AF2}.Release|x86.ActiveCfg = Release|x86
 		{662B4B15-8F4D-4AE5-B3EB-D91C215F5AF2}.Release|x86.Build.0 = Release|x86
+		{5FBDCD4A-3C2A-4EC6-83CE-34B29F43621A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{5FBDCD4A-3C2A-4EC6-83CE-34B29F43621A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{5FBDCD4A-3C2A-4EC6-83CE-34B29F43621A}.Debug|x64.ActiveCfg = Debug|x64
+		{5FBDCD4A-3C2A-4EC6-83CE-34B29F43621A}.Debug|x64.Build.0 = Debug|x64
+		{5FBDCD4A-3C2A-4EC6-83CE-34B29F43621A}.Debug|x86.ActiveCfg = Debug|x86
+		{5FBDCD4A-3C2A-4EC6-83CE-34B29F43621A}.Debug|x86.Build.0 = Debug|x86
+		{5FBDCD4A-3C2A-4EC6-83CE-34B29F43621A}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{5FBDCD4A-3C2A-4EC6-83CE-34B29F43621A}.Release|Any CPU.Build.0 = Release|Any CPU
+		{5FBDCD4A-3C2A-4EC6-83CE-34B29F43621A}.Release|x64.ActiveCfg = Release|x64
+		{5FBDCD4A-3C2A-4EC6-83CE-34B29F43621A}.Release|x64.Build.0 = Release|x64
+		{5FBDCD4A-3C2A-4EC6-83CE-34B29F43621A}.Release|x86.ActiveCfg = Release|x86
+		{5FBDCD4A-3C2A-4EC6-83CE-34B29F43621A}.Release|x86.Build.0 = Release|x86
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
Index: /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/Algorithms/AdaptiveWalk.cs
===================================================================
--- /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/Algorithms/AdaptiveWalk.cs	(revision 15702)
+++ /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/Algorithms/AdaptiveWalk.cs	(revision 15702)
@@ -0,0 +1,56 @@
+﻿#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.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Selection;
+using System.Linq;
+
+namespace HeuristicLab.Analysis.FitnessLandscape {
+  [Item("Adaptive Walk", "An adaptive walk applies a certain manipulation operation always taking the best of the sample.")]
+  [StorableClass]
+  [Creatable(CreatableAttribute.Categories.TestingAndAnalysis + CreatableAttribute.Categories.SplitToken + "1" + CreatableAttribute.Categories.OrderToken + "FLA", Priority = 303)]
+  public sealed class AdaptiveWalk : LocalAnalysis<BestSelector> {
+
+    public IFixedValueParameter<IntValue> SampleSizeParameter {
+      get { return (IFixedValueParameter<IntValue>)Parameters["SampleSize"]; }
+    }
+
+    [StorableConstructor]
+    private AdaptiveWalk(bool deserializing) : base(deserializing) { }
+    private AdaptiveWalk(AdaptiveWalk original, Cloner cloner) : base(original, cloner) { }
+    public AdaptiveWalk()
+      : base(new BestSelector()) {
+      SelectorParameter.Value.NumberOfSelectedSubScopesParameter.Hidden = true;
+      Parameters.Add(new FixedValueParameter<IntValue>("SampleSize", "Number of sampled moves from which the adaptive walk chooses the best.", new IntValue(10)));
+      var trailAnalyzer = AnalyzerParameter.Value.Operators.OfType<QualityTrailMultiAnalyzer>().Single();
+      var upDown = trailAnalyzer.Operators.OfType<UpDownWalkAnalyzer>().Single();
+      trailAnalyzer.Operators.SetItemCheckedState(upDown, false);
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new AdaptiveWalk(this, cloner);
+    }
+  }
+}
Index: /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/Algorithms/FLACharacterizer.cs
===================================================================
--- /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/Algorithms/FLACharacterizer.cs	(revision 15702)
+++ /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/Algorithms/FLACharacterizer.cs	(revision 15702)
@@ -0,0 +1,87 @@
+﻿#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.Threading;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Optimization;
+using HeuristicLab.Parameters;
+
+namespace HeuristicLab.Analysis.FitnessLandscape {
+  [Item("FLA Characterizer", "An algorithm that executes a characteristic calculator.")]
+  [StorableClass]
+  [Creatable(CreatableAttribute.Categories.TestingAndAnalysis + CreatableAttribute.Categories.SplitToken + "1" + CreatableAttribute.Categories.OrderToken + "FLA", Priority = 300)]
+  public sealed class FLACharacterizer : BasicAlgorithm {
+    public override bool SupportsPause { get { return false; } }
+    
+    public IValueParameter<ICharacteristicCalculator> CalculatorParameter {
+      get { return (IValueParameter<ICharacteristicCalculator>)Parameters["Calculator"]; }
+    }
+
+    public ICharacteristicCalculator Calculator {
+      get { return CalculatorParameter.Value; }
+    }
+
+    [StorableConstructor]
+    private FLACharacterizer(bool deserializing) : base(deserializing) { }
+    private FLACharacterizer(FLACharacterizer original, Cloner cloner)
+      : base(original, cloner) {
+      RegisterEventHandlers();
+    }
+    public FLACharacterizer() : base() {
+      Parameters.Add(new ValueParameter<ICharacteristicCalculator>("Calculator", "The FLA characteristic calculator.", new RandomWalkCalculator()));
+      RegisterEventHandlers();
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new FLACharacterizer(this, cloner);
+    }
+    
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() {
+      RegisterEventHandlers();
+    }
+
+    private void RegisterEventHandlers() {
+      CalculatorParameter.ValueChanged += CalculatorParameterOnValueChanged;
+    }
+
+    private void CalculatorParameterOnValueChanged(object sender, EventArgs e) {
+      Calculator.Problem = Problem;
+    }
+
+    protected override void OnProblemChanged() {
+      base.OnProblemChanged();
+      Calculator.Problem = Problem;
+    }
+
+    protected override void Run(CancellationToken cancellationToken) {
+      var calculator = Calculator;
+      if (calculator.CanCalculate()) {
+        foreach (var result in calculator.Calculate()) {
+          Results.Add(result);
+        }
+      } else throw new InvalidOperationException("Calculator cannot be applied.");
+    }
+  }
+}
Index: /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/Algorithms/LocalAnalysis.cs
===================================================================
--- /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/Algorithms/LocalAnalysis.cs	(revision 15702)
+++ /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/Algorithms/LocalAnalysis.cs	(revision 15702)
@@ -0,0 +1,296 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2010 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Operators;
+using HeuristicLab.Optimization;
+using HeuristicLab.Optimization.Operators;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Random;
+using System;
+using System.Linq;
+
+namespace HeuristicLab.Analysis.FitnessLandscape {
+  [Item("Local Analysis", "A local analysis algorithm.")]
+  [StorableClass]
+  public abstract class LocalAnalysis<T> : HeuristicOptimizationEngineAlgorithm, IStorableContent where T : class, IOperator, new() {
+    public string Filename { get; set; }
+
+    #region Problem Properties
+    public override Type ProblemType {
+      get { return typeof(ISingleObjectiveHeuristicOptimizationProblem); }
+    }
+    public new ISingleObjectiveHeuristicOptimizationProblem Problem {
+      get { return (ISingleObjectiveHeuristicOptimizationProblem)base.Problem; }
+      set { base.Problem = value; }
+    }
+    #endregion
+
+    #region Parameter Properties
+    public IFixedValueParameter<IntValue> SeedParameter {
+      get { return (IFixedValueParameter<IntValue>)Parameters["Seed"]; }
+    }
+    public IFixedValueParameter<BoolValue> SetSeedRandomlyParameter {
+      get { return (IFixedValueParameter<BoolValue>)Parameters["SetSeedRandomly"]; }
+    }
+    public IConstrainedValueParameter<IManipulator> MutatorParameter {
+      get { return (IConstrainedValueParameter<IManipulator>)Parameters["Mutator"]; }
+    }
+    public IFixedValueParameter<IntValue> MaximumIterationsParameter {
+      get { return (IFixedValueParameter<IntValue>)Parameters["MaximumIterations"]; }
+    }
+    public IFixedValueParameter<IntValue> RepetitionsParameter {
+      get { return (IFixedValueParameter<IntValue>)Parameters["Repetitions"]; }
+    }
+    public IValueParameter<MultiAnalyzer> AnalyzerParameter {
+      get { return (IValueParameter<MultiAnalyzer>)Parameters["Analyzer"]; }
+    }
+    public IFixedValueParameter<T> SelectorParameter {
+      get { return (IFixedValueParameter<T>)Parameters["Selector"]; }
+    }
+    #endregion
+
+    #region Properties
+    protected RandomCreator GlobalRandomCreator {
+      get { return (RandomCreator)OperatorGraph.InitialOperator; }
+    }
+    protected UniformSubScopesProcessor FirstUniformSubScopesProcessor {
+      get { return (UniformSubScopesProcessor)((SubScopesCreator)GlobalRandomCreator.Successor).Successor; }
+    }
+    protected LocalRandomCreator IteratedRandomCreator {
+      get { return (LocalRandomCreator)FirstUniformSubScopesProcessor.Operator; }
+    }
+    protected VariableCreator VariableCreator {
+      get { return (VariableCreator)IteratedRandomCreator.Successor; }
+    }
+    protected UniformSubScopesProcessor SecondUniformSubScopesProcessor {
+      get { return (UniformSubScopesProcessor)FirstUniformSubScopesProcessor.Successor; }
+    }
+    protected SolutionsCreator SolutionsCreator {
+      get { return (SolutionsCreator)SecondUniformSubScopesProcessor.Operator; }
+    }
+    protected LocalAnalysisMainLoop MainLoop {
+      get { return (LocalAnalysisMainLoop)SolutionsCreator.Successor; }
+    }
+
+    [Storable]
+    private QualityTrailMultiAnalyzer qualityTrailAnalyzer;
+    #endregion
+
+    [StorableConstructor]
+    protected LocalAnalysis(bool deserializing) : base(deserializing) { }
+    protected LocalAnalysis(LocalAnalysis<T> original, Cloner cloner)
+      : base(original, cloner) {
+      qualityTrailAnalyzer = cloner.Clone(original.qualityTrailAnalyzer);
+      RegisterEventHandlers();
+    }
+    protected LocalAnalysis(T selector)
+      : base() {
+      Parameters.Add(new FixedValueParameter<IntValue>("Seed", "The random seed used to initialize the new pseudo random number generator.", new IntValue(0)));
+      Parameters.Add(new FixedValueParameter<BoolValue>("SetSeedRandomly", "True if the random seed should be set to a random value, otherwise false.", new BoolValue(true)));
+      Parameters.Add(new ConstrainedValueParameter<IManipulator>("Mutator", "Mutation operator."));
+      Parameters.Add(new FixedValueParameter<IntValue>("MaximumIterations", "The maximum number of generations which should be processed.", new IntValue(100)));
+      Parameters.Add(new FixedValueParameter<IntValue>("Repetitions", "The number of repetitions that should be performed.", new IntValue(10)));
+      Parameters.Add(new ValueParameter<MultiAnalyzer>("Analyzer", "The operator used to analyze the solution and moves.", new MultiAnalyzer()));
+      Parameters.Add(new FixedValueParameter<T>("Selector", "Selection operator.", selector));
+
+      RandomCreator randomCreator = new RandomCreator();
+      SubScopesCreator ssc = new SubScopesCreator();
+      UniformSubScopesProcessor ussp1 = new UniformSubScopesProcessor();
+      UniformSubScopesProcessor ussp2 = new UniformSubScopesProcessor();
+      LocalRandomCreator lrc = new LocalRandomCreator();
+      VariableCreator variableCreator = new VariableCreator();
+      SolutionsCreator solutionsCreator = new SolutionsCreator();
+      LocalAnalysisMainLoop laMainLoop = new LocalAnalysisMainLoop();
+      ResultsCollector collector = new ResultsCollector();
+
+      OperatorGraph.InitialOperator = randomCreator;
+
+      randomCreator.RandomParameter.ActualName = "Random";
+      randomCreator.SeedParameter.ActualName = SeedParameter.Name;
+      randomCreator.SeedParameter.Value = null;
+      randomCreator.SetSeedRandomlyParameter.ActualName = SetSeedRandomlyParameter.Name;
+      randomCreator.SetSeedRandomlyParameter.Value = null;
+      randomCreator.Successor = ssc;
+
+      ssc.NumberOfSubScopesParameter.Value = null;
+      ssc.NumberOfSubScopesParameter.ActualName = RepetitionsParameter.Name;
+      ssc.Successor = ussp1;
+
+      ussp1.Depth = new IntValue(1);
+      ussp1.Parallel = new BoolValue(false);
+      ussp1.Operator = lrc;
+      ussp1.Successor = ussp2;
+
+      lrc.GlobalRandomParameter.ActualName = randomCreator.RandomParameter.ActualName;
+      lrc.LocalRandomParameter.ActualName = "IteratedRandom";
+      lrc.Successor = variableCreator;
+
+      var iterResults = new ValueParameter<ResultCollection>("IteratedResults", new ResultCollection());
+      variableCreator.CollectedValues.Add(iterResults);
+      variableCreator.Successor = null;
+
+      ussp2.Depth = new IntValue(1);
+      ussp2.Parallel = new BoolValue(true);
+      ussp2.Operator = solutionsCreator;
+      ussp2.Successor = collector;
+
+      solutionsCreator.NumberOfSolutions = new IntValue(1);
+      solutionsCreator.Successor = laMainLoop;
+
+      laMainLoop.MutatorParameter.ActualName = MutatorParameter.Name;
+      laMainLoop.SelectorParameter.ActualName = SelectorParameter.Name;
+      laMainLoop.MaximumIterationsParameter.ActualName = MaximumIterationsParameter.Name;
+      laMainLoop.RandomParameter.ActualName = lrc.LocalRandomParameter.ActualName;
+      laMainLoop.ResultsParameter.ActualName = iterResults.Name;
+      laMainLoop.AnalyzerParameter.ActualName = AnalyzerParameter.Name;
+
+      qualityTrailAnalyzer = new QualityTrailMultiAnalyzer();
+      qualityTrailAnalyzer.UpdateIntervalParameter.Value = null;
+      qualityTrailAnalyzer.UpdateIntervalParameter.ActualName = MaximumIterationsParameter.Name;
+      AnalyzerParameter.Value.Operators.Add(qualityTrailAnalyzer, true);
+
+      collector.CollectedValues.Add(new ScopeTreeLookupParameter<ResultCollection>("IteratedResults", 1));
+      collector.ResultsParameter.ActualName = "Results";
+      collector.CopyValue = new BoolValue(false);
+      collector.Successor = null;
+
+      RegisterEventHandlers();
+    }
+
+    public override void Prepare() {
+      if (Problem != null) base.Prepare();
+    }
+
+    protected override void OnStopped() {
+      var iteratedResults = Results.SingleOrDefault(x => x.Name == "IteratedResults");
+      if (iteratedResults != null) {
+        var rc = iteratedResults.Value as ItemArray<ResultCollection>;
+        if (rc != null) {
+          var results = rc.FirstOrDefault();
+          if (results != null) {
+            var toAvg = results.Select(x => x.Name).ToDictionary(x => x, x => 0.0);
+            foreach (var r in rc) {
+              foreach (var v in r) {
+                if (!toAvg.ContainsKey(v.Name)) continue;
+                var value = v.Value as IntValue;
+                if (value != null) toAvg[v.Name] += value.Value;
+                else {
+                  var doubleValue = v.Value as DoubleValue;
+                  if (doubleValue != null) toAvg[v.Name] += doubleValue.Value;
+                }
+              }
+            }
+
+            foreach (var r in toAvg.Keys.OrderBy(x => x)) {
+              Results.Add(new Result(r, new DoubleValue(toAvg[r] / RepetitionsParameter.Value.Value)));
+            }
+          }
+        }
+      }
+      base.OnStopped();
+    }
+
+    #region Events
+    protected override void OnProblemChanged() {
+      base.OnProblemChanged();
+      UpdateMutators();
+      Parameterize();
+      Problem.Evaluator.QualityParameter.ActualNameChanged += Evaluator_QualityParameter_ActualNameChanged;
+    }
+    protected override void Problem_SolutionCreatorChanged(object sender, EventArgs e) {
+      base.Problem_SolutionCreatorChanged(sender, e);
+      Parameterize();
+    }
+    protected override void Problem_EvaluatorChanged(object sender, EventArgs e) {
+      base.Problem_EvaluatorChanged(sender, e);
+      Parameterize();
+      Problem.Evaluator.QualityParameter.ActualNameChanged += Evaluator_QualityParameter_ActualNameChanged;
+    }
+    protected override void Problem_OperatorsChanged(object sender, EventArgs e) {
+      UpdateMutators();
+      Parameterize();
+      base.Problem_OperatorsChanged(sender, e);
+    }
+    private void Evaluator_QualityParameter_ActualNameChanged(object sender, EventArgs e) {
+      Parameterize();
+    }
+    #endregion
+
+    #region Helpers
+    private void RegisterEventHandlers() {
+      if (Problem != null) {
+        Problem.Evaluator.QualityParameter.ActualNameChanged += Evaluator_QualityParameter_ActualNameChanged;
+      }
+    }
+
+    private void UpdateMutators() {
+      var selected = MutatorParameter.Value;
+      MutatorParameter.ValidValues.Clear();
+      foreach (var m in Problem.Operators.OfType<IManipulator>()) {
+        MutatorParameter.ValidValues.Add(m);
+        if (selected != null && selected.GetType() == m.GetType()) MutatorParameter.Value = m;
+      }
+    }
+
+    protected virtual void Parameterize() {
+      if (Problem == null) return;
+
+      MainLoop.BestKnownQualityParameter.ActualName = Problem.BestKnownQualityParameter.Name;
+      MainLoop.MaximizationParameter.ActualName = Problem.MaximizationParameter.Name;
+      MainLoop.QualityParameter.ActualName = Problem.Evaluator.QualityParameter.ActualName;
+      foreach (var sOp in Problem.Operators.OfType<IStochasticOperator>()) {
+        sOp.RandomParameter.ActualName = IteratedRandomCreator.LocalRandomParameter.ActualName;
+      }
+      foreach (var iOp in Problem.Operators.OfType<IIterationBasedOperator>()) {
+        iOp.IterationsParameter.ActualName = "Iterations";
+        iOp.MaximumIterationsParameter.ActualName = MaximumIterationsParameter.Name;
+      }
+      var sEval = Problem.Evaluator as IStochasticOperator;
+      if (sEval != null) sEval.RandomParameter.ActualName = IteratedRandomCreator.LocalRandomParameter.ActualName;
+      var sCrea = Problem.SolutionCreator as IStochasticOperator;
+      if (sCrea != null) sCrea.RandomParameter.ActualName = IteratedRandomCreator.LocalRandomParameter.ActualName;
+      var sSel = SelectorParameter.Value as IStochasticOperator;
+      if (sSel != null) sSel.RandomParameter.ActualName = IteratedRandomCreator.LocalRandomParameter.ActualName;
+      var sel = SelectorParameter.Value as ISelector;
+      if (sel != null) {
+        sel.NumberOfSelectedSubScopesParameter.Value = new IntValue(1);
+        sel.CopySelected = new BoolValue(false);
+        var sos = sel as ISingleObjectiveSelector;
+        if (sos != null) {
+          sos.MaximizationParameter.ActualName = Problem.MaximizationParameter.Name;
+          sos.QualityParameter.ActualName = Problem.Evaluator.QualityParameter.ActualName;
+        }
+      }
+
+      foreach (var op in Problem.Operators.OfType<IParameterizedItem>()) {
+        var resultsParam = op.Parameters.SingleOrDefault(x => x.Name == "Results");
+        var lookupParam = resultsParam as ILookupParameter<ResultCollection>;
+        if (lookupParam == null) continue;
+        lookupParam.ActualName = "IteratedResults";
+      }
+    }
+    #endregion
+  }
+}
Index: /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/Algorithms/LocalAnalysisMainLoop.cs
===================================================================
--- /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/Algorithms/LocalAnalysisMainLoop.cs	(revision 15702)
+++ /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/Algorithms/LocalAnalysisMainLoop.cs	(revision 15702)
@@ -0,0 +1,197 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2010 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Operators;
+using HeuristicLab.Optimization;
+using HeuristicLab.Optimization.Operators;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Selection;
+
+namespace HeuristicLab.Analysis.FitnessLandscape {
+  /// <summary>
+  /// An operator which represents a local search.
+  /// </summary>
+  [Item("LocalAnalysisMainLoop", "An operator which represents the main loop of a best improvement local search (if only a single move is generated in each iteration it is a first improvement local search).")]
+  [StorableClass]
+  public class LocalAnalysisMainLoop : AlgorithmOperator {
+
+    #region Parameter properties
+    public ValueLookupParameter<IRandom> RandomParameter {
+      get { return (ValueLookupParameter<IRandom>)Parameters["Random"]; }
+    }
+    public ValueLookupParameter<BoolValue> MaximizationParameter {
+      get { return (ValueLookupParameter<BoolValue>)Parameters["Maximization"]; }
+    }
+    public ValueLookupParameter<DoubleValue> BestKnownQualityParameter {
+      get { return (ValueLookupParameter<DoubleValue>)Parameters["BestKnownQuality"]; }
+    }
+    public LookupParameter<DoubleValue> QualityParameter {
+      get { return (LookupParameter<DoubleValue>)Parameters["Quality"]; }
+    }
+    public ValueLookupParameter<IntValue> MaximumIterationsParameter {
+      get { return (ValueLookupParameter<IntValue>)Parameters["MaximumIterations"]; }
+    }
+    public ValueLookupParameter<ResultCollection> ResultsParameter {
+      get { return (ValueLookupParameter<ResultCollection>)Parameters["Results"]; }
+    }
+    public ValueLookupParameter<IOperator> MutatorParameter {
+      get { return (ValueLookupParameter<IOperator>)Parameters["Mutator"]; }
+    }
+    public ValueLookupParameter<IOperator> SelectorParameter {
+      get { return (ValueLookupParameter<IOperator>)Parameters["Selector"]; }
+    }
+    public ValueLookupParameter<IntValue> SampleSizeParameter {
+      get { return (ValueLookupParameter<IntValue>)Parameters["SampleSize"]; }
+    }
+    public ValueLookupParameter<IOperator> AnalyzerParameter {
+      get { return (ValueLookupParameter<IOperator>)Parameters["Analyzer"]; }
+    }
+    #endregion
+
+    [StorableConstructor]
+    protected LocalAnalysisMainLoop(bool deserializing) : base(deserializing) { }
+    protected LocalAnalysisMainLoop(LocalAnalysisMainLoop original, Cloner cloner) : base(original, cloner) { }
+    public LocalAnalysisMainLoop()
+      : base() {
+      Initialize();
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new LocalAnalysisMainLoop(this, cloner);
+    }
+
+    private void Initialize() {
+      #region Create parameters
+      Parameters.Add(new ValueLookupParameter<IRandom>("Random", "A pseudo random number generator."));
+      Parameters.Add(new ValueLookupParameter<BoolValue>("Maximization", "True if the problem is a maximization problem, otherwise false."));
+      Parameters.Add(new LookupParameter<DoubleValue>("Quality", "The value which represents the quality of a solution."));
+      Parameters.Add(new ValueLookupParameter<DoubleValue>("BestKnownQuality", "The best known quality value found so far."));
+      Parameters.Add(new ValueLookupParameter<IntValue>("MaximumIterations", "The maximum number of generations which should be processed."));
+      Parameters.Add(new ValueLookupParameter<ResultCollection>("Results", "The variable collection where results should be stored."));
+
+      Parameters.Add(new ValueLookupParameter<IOperator>("Mutator", "Mutation Operator."));
+      Parameters.Add(new ValueLookupParameter<IOperator>("Selector", "The operator that selects how to continue."));
+      Parameters.Add(new ValueLookupParameter<IntValue>("SampleSize", "Number of mutation samples."));
+
+      Parameters.Add(new ValueLookupParameter<IOperator>("Analyzer", "The operator used to analyze the solution and moves."));
+      #endregion
+
+      #region Create operators
+      VariableCreator variableCreator = new VariableCreator();
+      Placeholder analyzer1 = new Placeholder();
+      SubScopesCounter evaluatedSolutionsCounter1 = new SubScopesCounter();
+      LeftSelector leftSelector = new LeftSelector();
+      SubScopesProcessor mainProcessor = new SubScopesProcessor();
+      UniformSubScopesProcessor mutationProcessor = new UniformSubScopesProcessor();
+      Placeholder mutator = new Placeholder();
+      Placeholder evaluator = new Placeholder();
+      SubScopesCounter evaluatedSolutionsCounter2 = new SubScopesCounter();
+      Placeholder selector = new Placeholder();
+      RightReducer rightReducer1 = new RightReducer();
+      RightReducer rightReducer2 = new RightReducer();
+      Placeholder analyzer2 = new Placeholder();
+      IntCounter iterationsCounter = new IntCounter();
+      Comparator iterationsComparator = new Comparator();
+      ResultsCollector resultsCollector2 = new ResultsCollector();
+      ConditionalBranch iterationsTermination = new ConditionalBranch();
+
+      variableCreator.CollectedValues.Add(new ValueParameter<IntValue>("Iterations", new IntValue(0)));
+      variableCreator.CollectedValues.Add(new ValueParameter<IntValue>("EvaluatedSolutions", new IntValue(0)));
+
+      analyzer1.Name = "Analyzer (placeholder)";
+      analyzer1.OperatorParameter.ActualName = AnalyzerParameter.Name;
+
+      evaluatedSolutionsCounter1.Name = "EvaluatedSolutions++";
+      evaluatedSolutionsCounter1.AccumulateParameter.Value = new BoolValue(true);
+      evaluatedSolutionsCounter1.ValueParameter.ActualName = "EvaluatedSolutions";
+
+      leftSelector.CopySelected = new BoolValue(true);
+      leftSelector.NumberOfSelectedSubScopesParameter.ActualName = SampleSizeParameter.Name;
+
+      mainProcessor.Name = "Main Processsor";
+
+      mutationProcessor.Parallel = new BoolValue(false);
+
+      mutator.Name = "(Mutator)";
+      mutator.OperatorParameter.ActualName = MutatorParameter.Name;
+
+      evaluator.Name = "(Evaluator)";
+      evaluator.OperatorParameter.ActualName = "Evaluator";
+
+      evaluatedSolutionsCounter2.Name = "EvaluatedSolutions++";
+      evaluatedSolutionsCounter2.AccumulateParameter.Value = new BoolValue(true);
+      evaluatedSolutionsCounter2.ValueParameter.ActualName = "EvaluatedSolutions";
+
+      selector.Name = "(Selector)";
+      selector.OperatorParameter.ActualName = SelectorParameter.Name;
+
+      analyzer2.Name = "(Analyzer)";
+      analyzer2.OperatorParameter.ActualName = AnalyzerParameter.Name;
+
+      iterationsCounter.Name = "Iterations Counter";
+      iterationsCounter.Increment = new IntValue(1);
+      iterationsCounter.ValueParameter.ActualName = "Iterations";
+
+      iterationsComparator.Name = "Iterations >= MaximumIterations";
+      iterationsComparator.Comparison = new Comparison(ComparisonType.GreaterOrEqual);
+      iterationsComparator.LeftSideParameter.ActualName = "Iterations";
+      iterationsComparator.RightSideParameter.ActualName = MaximumIterationsParameter.Name;
+      iterationsComparator.ResultParameter.ActualName = "Terminate";
+
+      resultsCollector2.CopyValue = new BoolValue(true);
+      resultsCollector2.CollectedValues.Add(new LookupParameter<IntValue>("Iterations"));
+      resultsCollector2.CollectedValues.Add(new LookupParameter<IntValue>("EvaluatedSolutions"));
+      resultsCollector2.ResultsParameter.ActualName = ResultsParameter.Name;
+
+      iterationsTermination.Name = "Iterations Termination Condition";
+      iterationsTermination.ConditionParameter.ActualName = "Terminate";
+      #endregion
+
+      #region Create operator graph
+      OperatorGraph.InitialOperator = variableCreator;
+      variableCreator.Successor = evaluatedSolutionsCounter1;
+      evaluatedSolutionsCounter1.Successor = analyzer1;
+      analyzer1.Successor = leftSelector;
+      leftSelector.Successor = mainProcessor;
+      mainProcessor.Operators.Add(new EmptyOperator());
+      mainProcessor.Operators.Add(mutationProcessor);
+      mainProcessor.Successor = rightReducer2;
+      mutationProcessor.Operator = mutator;
+      mutationProcessor.Successor = evaluatedSolutionsCounter2;
+      mutator.Successor = evaluator;
+      evaluator.Successor = null;
+      evaluatedSolutionsCounter2.Successor = selector;
+      selector.Successor = rightReducer1;
+      rightReducer1.Successor = null;
+      rightReducer2.Successor = iterationsCounter;
+      iterationsCounter.Successor = analyzer2;
+      analyzer2.Successor = iterationsComparator;
+      iterationsComparator.Successor = iterationsTermination;
+      iterationsTermination.TrueBranch = resultsCollector2;
+      iterationsTermination.FalseBranch = leftSelector;
+      #endregion
+    }
+  }
+}
Index: /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/Algorithms/RandomWalk.cs
===================================================================
--- /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/Algorithms/RandomWalk.cs	(revision 15702)
+++ /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/Algorithms/RandomWalk.cs	(revision 15702)
@@ -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 HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Selection;
+using System.Linq;
+
+namespace HeuristicLab.Analysis.FitnessLandscape {
+  [Item("Random Walk", "A random walk applies a certain manipulation operation over and over.")]
+  [StorableClass]
+  [Creatable(CreatableAttribute.Categories.TestingAndAnalysis + CreatableAttribute.Categories.SplitToken + "1" + CreatableAttribute.Categories.OrderToken + "FLA", Priority = 301)]
+  public sealed class RandomWalk : LocalAnalysis<RandomSelector> {
+
+    [StorableConstructor]
+    private RandomWalk(bool deserializing) : base(deserializing) { }
+    private RandomWalk(RandomWalk original, Cloner cloner) : base(original, cloner) { }
+    public RandomWalk()
+      : base(new RandomSelector()) {
+      SelectorParameter.Value.NumberOfSelectedSubScopesParameter.Hidden = true;
+      MainLoop.SampleSizeParameter.Value = new IntValue(1);
+      var trailAnalyzer = AnalyzerParameter.Value.Operators.OfType<QualityTrailMultiAnalyzer>().Single();
+      var upDown = trailAnalyzer.Operators.OfType<UpDownWalkAnalyzer>().Single();
+      trailAnalyzer.Operators.SetItemCheckedState(upDown, false);
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new RandomWalk(this, cloner);
+    }
+  }
+}
Index: /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/Algorithms/UpDownWalk.cs
===================================================================
--- /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/Algorithms/UpDownWalk.cs	(revision 15702)
+++ /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/Algorithms/UpDownWalk.cs	(revision 15702)
@@ -0,0 +1,62 @@
+﻿#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.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Analysis.FitnessLandscape {
+  [Item("Up/Down Walk", "An up/down walk attempts to take the best of the sample until no better can be found and then switch to take the worse until no worse can be found.")]
+  [StorableClass]
+  [Creatable(CreatableAttribute.Categories.TestingAndAnalysis + CreatableAttribute.Categories.SplitToken + "1" + CreatableAttribute.Categories.OrderToken + "FLA", Priority = 302)]
+  public sealed class UpDownWalk : LocalAnalysis<UpDownSelector> {
+
+    public IFixedValueParameter<IntValue> SampleSizeParameter {
+      get { return (IFixedValueParameter<IntValue>)Parameters["SampleSize"]; }
+    }
+
+    [StorableConstructor]
+    private UpDownWalk(bool deserializing) : base(deserializing) { }
+    private UpDownWalk(UpDownWalk original, Cloner cloner) : base(original, cloner) { }
+    public UpDownWalk()
+      : base(new UpDownSelector()) {
+      Parameters.Add(new FixedValueParameter<IntValue>("SampleSize", "Number of moves that MultiMoveGenerators should create. This is ignored for Exhaustive- and SingleMoveGenerators.", new IntValue(10)));
+
+      VariableCreator.CollectedValues.Add(new ValueParameter<BoolValue>("MoveTowardsOptimum", new BoolValue(true)));
+      VariableCreator.CollectedValues.Add(new ValueParameter<DoubleValue>("BaseQuality", new DoubleValue(double.NaN)));
+
+      SelectorParameter.Value.BaseQualityParameter.ActualName = "BaseQuality";
+      SelectorParameter.Value.MoveTowardsOptimumParameter.ActualName = "MoveTowardsOptimum";
+    }
+
+    protected override void Parameterize() {
+      base.Parameterize();
+      if (Problem == null) return;
+      SelectorParameter.Value.QualityParameter.ActualName = Problem.Evaluator.QualityParameter.ActualName;
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new UpDownWalk(this, cloner);
+    }
+  }
+}
Index: /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/Analysis/EnumerableExtensions.cs
===================================================================
--- /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/Analysis/EnumerableExtensions.cs	(revision 15702)
+++ /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/Analysis/EnumerableExtensions.cs	(revision 15702)
@@ -0,0 +1,63 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2010 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+
+namespace HeuristicLab.Analysis.FitnessLandscape {
+
+  public static class Utils {
+
+    public static IEnumerable<TResult> Delta<T, TResult>(this IEnumerable<T> values, Func<T, T, TResult> f) {
+      var it = values.GetEnumerator();
+      T last = default(T);
+      if (it.MoveNext())
+        last = it.Current;
+      while (it.MoveNext()) {
+        yield return f(last, it.Current);
+        last = it.Current;
+      }
+    }
+
+    public static IEnumerable<IEnumerable<TSource>> GroupConsecutive<TSource, TKey>(
+        this IEnumerable<TSource> source, Func<TSource, TKey> keySelector) {
+      if (source == null) throw new ArgumentNullException("source");
+      if (keySelector == null) throw new ArgumentNullException("keySelector");
+
+      var comparer = EqualityComparer<TKey>.Default;
+      var grouped = new List<TSource>();
+      using (var iter = source.GetEnumerator()) {
+        if (!iter.MoveNext()) yield break;
+        grouped.Add(iter.Current);
+        var last = iter.Current;
+        while (iter.MoveNext()) {
+          if (!comparer.Equals(keySelector(iter.Current), keySelector(last))) {
+            yield return grouped.AsReadOnly();
+            grouped = new List<TSource>();
+          }
+          grouped.Add(iter.Current);
+          last = iter.Current;
+        }
+        yield return grouped.AsReadOnly();
+      }
+    }
+  }
+}
Index: /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/Analysis/FitnessCloudAnalyzer.cs
===================================================================
--- /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/Analysis/FitnessCloudAnalyzer.cs	(revision 15702)
+++ /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/Analysis/FitnessCloudAnalyzer.cs	(revision 15702)
@@ -0,0 +1,91 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2010 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Drawing;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Operators;
+using HeuristicLab.Optimization.Operators;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Analysis.FitnessLandscape {
+
+  [StorableClass]
+  public class FitnessCloudAnalyzer : AlgorithmOperator, IQualityTrailAnalyzer {
+    public bool EnabledByDefault {
+      get { return false; }
+    }
+
+    #region Parameters
+    public LookupParameter<DataTable> QualityTrailParameter {
+      get { return (LookupParameter<DataTable>)Parameters["Quality Trail"]; }
+    }
+    public LookupParameter<ScatterPlot> FitnessCloudParameter {
+      get { return (LookupParameter<ScatterPlot>)Parameters["Fitness Cloud"]; }
+    }
+    public LookupParameter<VariableCollection> ResultsParameter {
+      get { return (LookupParameter<VariableCollection>)Parameters["Results"]; }
+    }
+    #endregion
+
+    [StorableConstructor]
+    protected FitnessCloudAnalyzer(bool deserializing) : base(deserializing) { }
+    protected FitnessCloudAnalyzer(FitnessCloudAnalyzer original, Cloner cloner) : base(original, cloner) { }
+
+    public FitnessCloudAnalyzer() {
+      Parameters.Add(new LookupParameter<DataTable>("Quality Trail", "The qualities of the solutions"));
+      Parameters.Add(new LookupParameter<ScatterPlot>("Fitness Cloud", "Information stability development over time"));
+      Parameters.Add(new LookupParameter<VariableCollection>("Results", "The collection of all results of this algorithm"));
+
+      var resultsCollector = new ResultsCollector();
+      resultsCollector.CollectedValues.Add(new LookupParameter<ScatterPlot>(FitnessCloudParameter.Name));
+
+      OperatorGraph.InitialOperator = resultsCollector;
+      resultsCollector.Successor = null;
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new FitnessCloudAnalyzer(this, cloner);
+    }
+
+    public override IOperation Apply() {
+      ScatterPlot fitnessCloud = FitnessCloudParameter.ActualValue;
+      if (fitnessCloud == null) {
+        fitnessCloud = new ScatterPlot();
+        FitnessCloudParameter.ActualValue = fitnessCloud;
+        fitnessCloud.Name = "Fitness Cloud";
+        fitnessCloud.XAxisName = "Fitness";
+        fitnessCloud.YAxisName = "Neighboring Fitness";
+      }
+
+      DataTable qualityTrail = QualityTrailParameter.ActualValue;
+      if (qualityTrail != null && qualityTrail.Rows.Count > 0) {
+        var qualities = qualityTrail.Rows.First().Values.ToList();
+        if (qualities.Count > 2) {
+          fitnessCloud.Add(Utils.Delta(qualities, (a, b) => new PointF((float)a, (float)b)));
+        }
+      }
+      return base.Apply();
+    }
+  }
+}
Index: /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/Analysis/IQualityTrailAnalyzer.cs
===================================================================
--- /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/Analysis/IQualityTrailAnalyzer.cs	(revision 15702)
+++ /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/Analysis/IQualityTrailAnalyzer.cs	(revision 15702)
@@ -0,0 +1,26 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2010 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using HeuristicLab.Optimization;
+
+namespace HeuristicLab.Analysis.FitnessLandscape {
+  public interface IQualityTrailAnalyzer : IAnalyzer { }
+}
Index: /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/Analysis/InformationAnalysis.cs
===================================================================
--- /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/Analysis/InformationAnalysis.cs	(revision 15702)
+++ /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/Analysis/InformationAnalysis.cs	(revision 15702)
@@ -0,0 +1,270 @@
+﻿#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.Linq;
+
+namespace HeuristicLab.Analysis.FitnessLandscape {
+
+  public class InformationAnalysis {
+
+    public class Peak {
+      public double QualityDelta { get; private set; }
+      public double Value { get; private set; }
+      public Peak(double qualityDelta, double value) {
+        QualityDelta = qualityDelta;
+        Value = value;
+      }
+    }
+
+    public List<double> InformationContent { get; private set; }
+    public List<double> PartialInformationContent { get; private set; }
+    public List<double> DensityBasinInformation { get; private set; }
+    public List<double> TotalEntropy { get; private set; }
+    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 Peak PeakInformationContent { get; private set; }
+    public Peak PeakPartialInformationContent { get; private set; }
+    public Peak PeakDensityBasinInformation { get; private set; }
+    public Peak PeakTotalEntropy { get; private set; }
+
+    public InformationAnalysis(IList<double> qualities, int nQuantiles, int shapeSize) {
+      InformationContent = new List<double>();
+      PartialInformationContent = new List<double>();
+      DensityBasinInformation = new List<double>();
+      TotalEntropy = new List<double>();
+      QualityDelta = new List<double>();
+      if (shapeSize < 1)
+        throw new ArgumentException("Shape size must be at least 1 (better 2)");
+      if (qualities.Count > 1)
+        PerformAnalysis(qualities, nQuantiles, shapeSize);
+    }
+
+    private void PerformAnalysis(IList<double> qualities, int nQuantiles, int shapeSize) {
+      var differences = Differences(qualities).ToList();
+      InformationStability = differences.Select(Math.Abs).Max();
+      Regularity = new HashSet<double>(differences).Count;
+      Diversity = new HashSet<double>(qualities).Count;
+      var absDifferences = differences.Select(Math.Abs).OrderBy(d => d).ToList();
+      nQuantiles = Math.Min(nQuantiles, absDifferences.Count);
+      var thresholds = (nQuantiles == 0
+                         ? absDifferences
+                         : UniqueThresholdCalculator.DetermineThresholds(differences, nQuantiles)).ToList();
+      foreach (var eps in thresholds) {
+        if (QualityDelta.Count > 0 && QualityDelta.Last() == eps) {
+          QualityDelta.DuplicateLast();
+          InformationContent.DuplicateLast();
+          DensityBasinInformation.DuplicateLast();
+          TotalEntropy.DuplicateLast();
+          PartialInformationContent.DuplicateLast();
+        } else {
+          var slopes = Slopes(eps, differences).ToList();
+          var shapes = Shapes(shapeSize, slopes).ToList();
+          var shapeCounts = CountShapes(shapes);
+          QualityDelta.Add(eps);
+          InformationContent.Add(CalculateEntropy(Shape.GetAll(shapeSize, Shape.Form.NonUni), shapeCounts, shapes.Count));
+          DensityBasinInformation.Add(CalculateEntropy(Shape.GetAll(shapeSize, Shape.Form.Uni), shapeCounts, shapes.Count));
+          TotalEntropy.Add(CalculateEntropy(Shape.GetAll(shapeSize, Shape.Form.Any), shapeCounts, shapes.Count));
+          PartialInformationContent.Add(CalculatePartialInformationContent(eps, differences));
+        }
+      }
+      PeakInformationContent = GetPeak(QualityDelta, InformationContent);
+      PeakDensityBasinInformation = GetPeak(QualityDelta, DensityBasinInformation);
+      PeakPartialInformationContent = GetPeak(QualityDelta, PartialInformationContent);
+      PeakTotalEntropy = GetPeak(QualityDelta, TotalEntropy);
+    }
+
+    public static Peak GetPeak(IEnumerable<double> indexes, IEnumerable<double> values) {
+      var max = indexes.Zip(values, (i, v) => new { i, v }).OrderByDescending(p => p.v).First();
+      return new Peak(max.i, max.v);
+    }
+
+    public enum Slope {
+      Up = 1,
+      Flat = 0,
+      Down = -1
+    }
+
+    public class Shape : IEnumerable<Slope>, IComparable<Shape> {
+
+      #region types, fields and properties
+      public enum Form { Uni, NonUni, Any }
+
+      private readonly Slope[] slopes;
+
+      private static readonly Dictionary<Tuple<Form, int>, IList<Shape>> SHAPES =
+        new Dictionary<Tuple<Form, int>, IList<Shape>>();
+      #endregion
+
+      public Shape(IEnumerable<Slope> slopes) {
+        this.slopes = slopes.ToArray();
+      }
+
+      #region static methods
+
+      public static Shape Get(params Slope[] slopes) {
+        return new Shape(slopes);
+      }
+
+      public static IList<Shape> GetAll(int size, Form type) {
+        var key = Tuple.Create(type, size);
+        IList<Shape> allShapes;
+        if (!SHAPES.TryGetValue(key, out allShapes)) {
+          allShapes = CreateAll(size, type).ToList();
+          SHAPES[key] = allShapes;
+        }
+        return allShapes;
+      }
+
+      private static IEnumerable<Shape> CreateAll(int size, Form type) {
+        if (size == 0) {
+          yield return Get();
+        } else {
+          foreach (var s in CreateAll(size - 1, type)) {
+            foreach (var s2 in s.ExtendAll(type))
+              yield return s2;
+          }
+        }
+      }
+      #endregion
+
+      private Shape Extend(Slope s) {
+        return new Shape(slopes.Concat(new[] { s }));
+      }
+
+      private IEnumerable<Shape> ExtendAll(Form t) {
+        if (Length == 0 || t == Form.Any) {
+          yield return Extend(Slope.Up);
+          yield return Extend(Slope.Flat);
+          yield return Extend(Slope.Down);
+        } else if (t == Form.Uni) {
+          yield return Extend(slopes[0]);
+        } else if (t == Form.NonUni) {
+          if (slopes.Last() != Slope.Up) yield return Extend(Slope.Up);
+          if (slopes.Last() != Slope.Flat) yield return Extend(Slope.Flat);
+          if (slopes.Last() != Slope.Down) yield return Extend(Slope.Down);
+        }
+      }
+
+      public int Length {
+        get { return slopes.Length; }
+      }
+
+      public Slope this[int i] {
+        get { return slopes[i]; }
+      }
+
+      #region IEnumerable Members
+      public IEnumerator<Slope> GetEnumerator() {
+        return (IEnumerator<Slope>)slopes.GetEnumerator();
+      }
+      System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() {
+        return GetEnumerator();
+      }
+      #endregion
+
+      #region IComparable Members
+
+      public int CompareTo(Shape other) {
+        if (other.Length < Length)
+          return -1;
+        if (other.Length > Length)
+          return 1;
+        for (var i = 0; i < Length; i++) {
+          var d = slopes[i].CompareTo(other.slopes[i]);
+          if (d != 0)
+            return d;
+        }
+        return 0;
+      }
+      public override bool Equals(object obj) {
+        var s = obj as Shape;
+        if (s == null) return false;
+        return CompareTo(s) == 0;
+      }
+      public override int GetHashCode() {
+        return slopes.Aggregate(0, (a, s) => a * 3 + ((int)s + 1)).GetHashCode();
+      }
+
+      #endregion
+
+      private string asString;
+      public override string ToString() {
+        return asString ?? (asString = string.Join("", slopes.Select(s => (s == Slope.Down ? "\\" : (s == Slope.Up ? "/" : "-")))));
+      }
+    }
+
+    private static IEnumerable<Slope> Slopes(double eps, IEnumerable<double> differences) {
+      return differences.Select(d => (d > eps ? Slope.Up : (d < -eps ? Slope.Down : Slope.Flat)));
+    }
+
+    private static IEnumerable<Shape> Shapes(int size, IEnumerable<Slope> slopes) {
+      var q = new Queue<Slope>();
+      foreach (var s in slopes) {
+        q.Enqueue(s);
+        if (q.Count < size) continue;
+        yield return new Shape(q);
+        q.Dequeue();
+      }
+    }
+
+    private static double CalculateEntropy(IList<Shape> shapes, Dictionary<Shape, int> shapeCounts, int totalNShapes) {
+      return shapes.Aggregate(0.0, (current, s) => current - Entropy(shapeCounts.GetValueOrDefault(s, 0), totalNShapes, shapes.Count));
+    }
+
+    private static double CalculatePartialInformationContent(double eps, ICollection<double> differences) {
+      int slope = 0;
+      int nPeaks = 0;
+      foreach (var d in differences) {
+        if (d > eps) {
+          if (slope < 0) nPeaks++;
+          slope = +1;
+        } else if (d < -eps) {
+          if (slope > 0) nPeaks++;
+          slope = -1;
+        }
+      }
+      return 1.0 * nPeaks / differences.Count;
+    }
+
+    private static Dictionary<Shape, int> CountShapes(IEnumerable<Shape> shapes) {
+      var shapeCounts = new Dictionary<Shape, int>();
+      foreach (var group in shapes.GroupBy(s => s))
+        shapeCounts[group.Key] = group.Count();
+      return shapeCounts;
+    }
+
+    private static double Entropy(int count, int total, int nCases) {
+      if (count == 0)
+        return 0;
+      double freq = 1.0 * count / total;
+      return freq * Math.Log(freq, nCases);
+    }
+
+    private static IEnumerable<double> Differences(IEnumerable<double> values) {
+      return values.Delta((x, y) => y - x);
+    }
+
+  }
+}
Index: /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/Analysis/InformationAnalyzer.cs
===================================================================
--- /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/Analysis/InformationAnalyzer.cs	(revision 15702)
+++ /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/Analysis/InformationAnalyzer.cs	(revision 15702)
@@ -0,0 +1,186 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2010 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Operators;
+using HeuristicLab.Optimization;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using System.Linq;
+using System;
+
+namespace HeuristicLab.Analysis.FitnessLandscape {
+
+  [StorableClass]
+  public class InformationAnalyzer : SingleSuccessorOperator, IQualityTrailAnalyzer {
+    public bool EnabledByDefault {
+      get { return false; }
+    }
+
+    #region Parameters
+    public LookupParameter<DataTable> QualityTrailParameter {
+      get { return (LookupParameter<DataTable>)Parameters["Quality Trail"]; }
+    }
+    public LookupParameter<ResultCollection> ResultsParameter {
+      get { return (LookupParameter<ResultCollection>)Parameters["Results"]; }
+    }
+    public ValueLookupParameter<IntValue> NQuantilesParameter {
+      get { return (ValueLookupParameter<IntValue>)Parameters["NQuantiles"]; }
+    }
+    public ValueLookupParameter<IntValue> ShapeSizeParameter {
+      get { return (ValueLookupParameter<IntValue>)Parameters["ShapeSize"]; }
+    }
+    public LookupParameter<DoubleValue> InformationContentParameter {
+      get { return (LookupParameter<DoubleValue>)Parameters["InformationContent"]; }
+    }
+    public LookupParameter<DoubleValue> PartialInformationContentParameter {
+      get { return (LookupParameter<DoubleValue>)Parameters["PartialInformationContent"]; }
+    }
+    public LookupParameter<DoubleValue> DensityBasinInformationParameter {
+      get { return (LookupParameter<DoubleValue>)Parameters["DensityBasinInformation"]; }
+    }
+    public LookupParameter<DoubleValue> TotalEntropyParameter {
+      get { return (LookupParameter<DoubleValue>)Parameters["TotalEntropy"]; }
+    }
+    public LookupParameter<DoubleValue> InformationStabilityParameter {
+      get { return (LookupParameter<DoubleValue>)Parameters["InformationStability"]; }
+    }
+    public LookupParameter<DoubleValue> RegularityParameter {
+      get { return (LookupParameter<DoubleValue>)Parameters["Regularity"]; }
+    }
+    public LookupParameter<DoubleValue> DiversityParameter {
+      get { return (LookupParameter<DoubleValue>)Parameters["Diversity"]; }
+    }
+    public LookupParameter<DoubleValue> PeakInformationContentParameter {
+      get { return (LookupParameter<DoubleValue>)Parameters["PeakInformationContent"]; }
+    }
+    public LookupParameter<DoubleValue> PeakDensityBasinInformationParameter {
+      get { return (LookupParameter<DoubleValue>)Parameters["PeakDensityBasinInformation"]; }
+    }
+    public ILookupParameter<DataTable> InformationAnalysisParameter {
+      get { return (ILookupParameter<DataTable>)Parameters["InformationAnalysis"]; }
+    }
+    #endregion
+
+    [StorableConstructor]
+    protected InformationAnalyzer(bool deserializing) : base(deserializing) { }
+    protected InformationAnalyzer(InformationAnalyzer original, Cloner cloner) : base(original, cloner) { }
+
+    public InformationAnalyzer() {
+      Parameters.Add(new LookupParameter<DataTable>("Quality Trail", "The qualities of the solutions"));
+      Parameters.Add(new LookupParameter<ResultCollection>("Results", "The collection of all results of this algorithm"));
+
+      Parameters.Add(new ValueLookupParameter<IntValue>("NQuantiles", "The number of delta quantiles to display", new IntValue(20)));
+      Parameters.Add(new ValueLookupParameter<IntValue>("ShapeSize", "The number of slopes to consider as shapes.", new IntValue(2)));
+
+      Parameters.Add(new LookupParameter<DoubleValue>("InformationContent", "The information content H(0) at eps = 0"));
+      Parameters.Add(new LookupParameter<DoubleValue>("PartialInformationContent", "Partial information content M(0) at eps = 0"));
+      Parameters.Add(new LookupParameter<DoubleValue>("DensityBasinInformation", "Density Basin Information h(0) at eps = 0"));
+      Parameters.Add(new LookupParameter<DoubleValue>("TotalEntropy", "The overall disorder in the trajectory"));
+      Parameters.Add(new LookupParameter<DoubleValue>("InformationStability", "Information Stability Value"));
+      Parameters.Add(new LookupParameter<DoubleValue>("Regularity", "The number of different quality differences"));
+      Parameters.Add(new LookupParameter<DoubleValue>("Diversity", "The number of different quality values"));
+      Parameters.Add(new LookupParameter<DoubleValue>("PeakInformationContent", "Maximum information content at any quality delta."));
+      Parameters.Add(new LookupParameter<DoubleValue>("PeakDensityBasinInformation", "Maximum density basin information at any quality delta."));
+
+      Parameters.Add(new LookupParameter<DataTable>("InformationAnalysis", "Graphical analysis of information theoretic features."));
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new InformationAnalyzer(this, cloner);
+    }
+
+    public override IOperation Apply() {
+      var qualityTrail = QualityTrailParameter.ActualValue;
+      if (qualityTrail == null || qualityTrail.Rows.Count == 0) return base.Apply();
+
+      var qualities = QualityTrailParameter.ActualValue.Rows.First().Values.ToList();
+      if (qualities.Count <= 2) return base.Apply();
+
+      var nQuantiles = NQuantilesParameter.ActualValue.Value;
+      var shapeSize = ShapeSizeParameter.ActualValue.Value;
+      var results = ResultsParameter.ActualValue;
+
+      var analysis = new InformationAnalysis(qualities, nQuantiles, shapeSize);
+      var ic = new DoubleValue(analysis.InformationContent.FirstOrDefault());
+      InformationContentParameter.ActualValue = ic;
+      AddOrUpdateResult(results, InformationContentParameter.Name, ic);
+      var pic = new DoubleValue(analysis.PartialInformationContent.FirstOrDefault());
+      PartialInformationContentParameter.ActualValue = pic;
+      AddOrUpdateResult(results, PartialInformationContentParameter.Name, pic);
+      var dbi = new DoubleValue(analysis.DensityBasinInformation.FirstOrDefault());
+      DensityBasinInformationParameter.ActualValue = dbi;
+      AddOrUpdateResult(results, DensityBasinInformationParameter.Name, dbi);
+      var @is = new DoubleValue(analysis.InformationStability);
+      InformationStabilityParameter.ActualValue = @is;
+      AddOrUpdateResult(results, InformationStabilityParameter.Name, @is);
+      var regularity = new DoubleValue(1.0 * analysis.Regularity / qualities.Count);
+      RegularityParameter.ActualValue = regularity;
+      AddOrUpdateResult(results, RegularityParameter.Name, regularity);
+      var diversity = new DoubleValue(1.0 * analysis.Diversity / qualities.Count);
+      DiversityParameter.ActualValue = diversity;
+      AddOrUpdateResult(results, DiversityParameter.Name, diversity);
+      var totalEntropy = new DoubleValue(analysis.TotalEntropy.FirstOrDefault());
+      TotalEntropyParameter.ActualValue = totalEntropy;
+      AddOrUpdateResult(results, TotalEntropyParameter.Name, totalEntropy);
+      var peakIc = new DoubleValue(analysis.PeakInformationContent.Value);
+      PeakInformationContentParameter.ActualValue = peakIc;
+      AddOrUpdateResult(results, PeakInformationContentParameter.Name, peakIc);
+      var peakDbi = new DoubleValue(analysis.PeakDensityBasinInformation.Value);
+      PeakDensityBasinInformationParameter.ActualValue = peakDbi;
+      AddOrUpdateResult(results, PeakDensityBasinInformationParameter.Name, peakDbi);
+
+      var itable = GetInformationTable(analysis);
+      AddOrUpdateResult(results, InformationAnalysisParameter.Name, itable);
+      return base.Apply();
+    }
+
+    private static DataTable GetInformationTable(InformationAnalysis analysis) {
+      var dt = new DataTable("Information Analysis");
+      var ic = new DataRow("Information Content");
+      var pic = new DataRow("Partial Information Content");
+      var dbi = new DataRow("Density Basin Information");
+      var te = new DataRow("Total Entropy");
+      var e = new DataRow("Epsilon");
+      e.VisualProperties.SecondYAxis = true;
+      ic.Values.AddRange(analysis.InformationContent);
+      pic.Values.AddRange(analysis.PartialInformationContent);
+      dbi.Values.AddRange(analysis.DensityBasinInformation);
+      te.Values.AddRange(analysis.TotalEntropy);
+      e.Values.AddRange(analysis.QualityDelta);
+      dt.Rows.Add(ic);
+      dt.Rows.Add(pic);
+      dt.Rows.Add(dbi);
+      dt.Rows.Add(te);
+      dt.Rows.Add(e);
+      return dt;
+    }
+
+    private static void AddOrUpdateResult(ResultCollection results, string name, IItem item, bool clone = false) {
+      IResult r;
+      if (!results.TryGetValue(name, out r)) {
+        results.Add(new Result(name, clone ? (IItem)item.Clone() : item));
+      } else r.Value = clone ? (IItem)item.Clone() : item;
+    }
+  }
+}
Index: /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/Analysis/QualityTrailMultiAnalyzer.cs
===================================================================
--- /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/Analysis/QualityTrailMultiAnalyzer.cs	(revision 15702)
+++ /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/Analysis/QualityTrailMultiAnalyzer.cs	(revision 15702)
@@ -0,0 +1,117 @@
+﻿#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.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Operators;
+using HeuristicLab.Optimization;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.PluginInfrastructure;
+using System.Linq;
+
+namespace HeuristicLab.Analysis.FitnessLandscape {
+  [Item("QualityTrailAnalyzer", "An analyzer that creates a quality trail which can be further analyzed by several analyzers.")]
+  [StorableClass]
+  public class QualityTrailMultiAnalyzer : CheckedMultiOperator<IQualityTrailAnalyzer>, IAnalyzer {
+    public bool EnabledByDefault {
+      get { return false; }
+    }
+
+    public override bool CanChangeName {
+      get { return false; }
+    }
+
+    public IValueLookupParameter<IntValue> UpdateIntervalParameter {
+      get { return (IValueLookupParameter<IntValue>)Parameters["QualityTrailUpdateInterval"]; }
+    }
+    public ILookupParameter<IntValue> UpdateCounterParameter {
+      get { return (ILookupParameter<IntValue>)Parameters["QualityTrailUpdateCounter"]; }
+    }
+    public ILookupParameter<DataTable> QualityTrailParameter {
+      get { return (ILookupParameter<DataTable>)Parameters["Quality Trail"]; }
+    }
+    public ILookupParameter<ResultCollection> ResultsParameter {
+      get { return (ILookupParameter<ResultCollection>)Parameters["Results"]; }
+    }
+    public IScopeTreeLookupParameter<DoubleValue> QualityParameter {
+      get { return (IScopeTreeLookupParameter<DoubleValue>)Parameters["Quality"]; }
+    }
+    public ILookupParameter<BoolValue> MaximizationParameter {
+      get { return (ILookupParameter<BoolValue>)Parameters["Maximization"]; }
+    }
+
+    public IntValue UpdateInterval {
+      get { return UpdateIntervalParameter.Value; }
+      set { UpdateIntervalParameter.Value = value; }
+    }
+
+    [StorableConstructor]
+    protected QualityTrailMultiAnalyzer(bool deserializing) : base(deserializing) { }
+    protected QualityTrailMultiAnalyzer(QualityTrailMultiAnalyzer original, Cloner cloner) : base(original, cloner) { }
+    public QualityTrailMultiAnalyzer()
+      : base() {
+      Parameters.Add(new ValueLookupParameter<IntValue>("QualityTrailUpdateInterval", "The interval at which the contained analyzers should be applied.", new IntValue(1)));
+      Parameters.Add(new LookupParameter<IntValue>("QualityTrailUpdateCounter", "The number of times the Analyzer was called since the last update."));
+      Parameters.Add(new LookupParameter<DataTable>("Quality Trail", "All historical quality values throughout the algorithm run"));
+      Parameters.Add(new ScopeTreeLookupParameter<DoubleValue>("Quality", "Quality values of the whole population", 1));
+      Parameters.Add(new LookupParameter<ResultCollection>("Results", "The collected results"));
+      Parameters.Add(new LookupParameter<BoolValue>("Maximization", "Whether the problem is a maximization problem"));
+
+      foreach (var analyzer in ApplicationManager.Manager.GetInstances<IQualityTrailAnalyzer>()) {
+        Operators.Add(analyzer, !(analyzer is FitnessCloudAnalyzer));
+      }
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new QualityTrailMultiAnalyzer(this, cloner);
+    }
+
+    public override IOperation InstrumentedApply() {
+      var maximization = MaximizationParameter.ActualValue.Value;
+      var qualityTrail = QualityTrailParameter.ActualValue;
+      if (qualityTrail == null) {
+        qualityTrail = new DataTable("Quality Trail");
+        qualityTrail.Rows.Add(new DataRow("Qualities"));
+        QualityTrailParameter.ActualValue = qualityTrail;
+      }
+      var qualities = QualityParameter.ActualValue.Select(x => x.Value);
+      qualityTrail.Rows["Qualities"].Values.Add(maximization ? qualities.Max() : qualities.Min());
+
+      var interval = UpdateIntervalParameter.ActualValue.Value;
+      var counter = UpdateCounterParameter.ActualValue;
+      if (counter == null) {
+        counter = new IntValue(0);
+        UpdateCounterParameter.ActualValue = counter;
+      }
+      counter.Value++;
+
+      var next = new OperationCollection();
+      if (counter.Value % interval == 0) {
+        counter.Value = 0;
+        foreach (var item in Operators.CheckedItems) next.Add(ExecutionContext.CreateOperation(item.Value));
+      }
+      next.Add(base.InstrumentedApply());
+      return next;
+    }
+  }
+}
Index: /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/Analysis/RuggednessAnalyzer.cs
===================================================================
--- /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/Analysis/RuggednessAnalyzer.cs	(revision 15702)
+++ /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/Analysis/RuggednessAnalyzer.cs	(revision 15702)
@@ -0,0 +1,90 @@
+﻿#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.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Operators;
+using HeuristicLab.Optimization;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using System.Linq;
+
+namespace HeuristicLab.Analysis.FitnessLandscape {
+  [Item("Ruggedness Analyzer", "Analyzes autocorrelation for one mutation step and correlation length.")]
+  [StorableClass]
+  public class RuggednessAnalyzer : SingleSuccessorOperator, IQualityTrailAnalyzer {
+    public bool EnabledByDefault {
+      get { return false; }
+    }
+
+    #region Parameters
+    public LookupParameter<DataTable> QualityTrailParameter {
+      get { return (LookupParameter<DataTable>)Parameters["Quality Trail"]; }
+    }
+    public LookupParameter<ResultCollection> ResultsParameter {
+      get { return (LookupParameter<ResultCollection>)Parameters["Results"]; }
+    }
+    public LookupParameter<DoubleValue> AutoCorrelation1Parameter {
+      get { return (LookupParameter<DoubleValue>)Parameters["AutoCorrelation1"]; }
+    }
+    public LookupParameter<IntValue> CorrelationLengthParameter {
+      get { return (LookupParameter<IntValue>)Parameters["CorrelationLength"]; }
+    }
+    #endregion
+
+    [StorableConstructor]
+    protected RuggednessAnalyzer(bool deserializing) : base(deserializing) { }
+    protected RuggednessAnalyzer(RuggednessAnalyzer original, Cloner cloner) : base(original, cloner) { }
+    public RuggednessAnalyzer() {
+      Parameters.Add(new LookupParameter<DataTable>("Quality Trail", "The quality of the solution"));
+      Parameters.Add(new LookupParameter<ResultCollection>("Results", "The collection of all results of this algorithm"));
+      Parameters.Add(new LookupParameter<DoubleValue>("AutoCorrelation1", "Autocorrelation for one mutation step."));
+      Parameters.Add(new LookupParameter<IntValue>("CorrelationLength", "The correlation length."));
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new RuggednessAnalyzer(this, cloner);
+    }
+
+    public override IOperation Apply() {
+      var qualityTrail = QualityTrailParameter.ActualValue;
+      if (qualityTrail == null || qualityTrail.Rows.Count <= 0) return base.Apply();
+      var results = ResultsParameter.ActualValue;
+      double[] autocorrelationValues;
+      var correlationLength = RuggednessCalculator.CalculateCorrelationLength(qualityTrail.Rows.First().Values.ToArray(), out autocorrelationValues);
+      var cl = new IntValue(correlationLength);
+      CorrelationLengthParameter.ActualValue = cl;
+      AddOrUpdateResult(results, CorrelationLengthParameter.Name, cl);
+      var ac1 = new DoubleValue(autocorrelationValues.Length > 1 ? autocorrelationValues[1] : 0.0);
+      AutoCorrelation1Parameter.ActualValue = ac1;
+      AddOrUpdateResult(results, AutoCorrelation1Parameter.Name, ac1);
+      return base.Apply();
+    }
+
+    private static void AddOrUpdateResult(ResultCollection results, string name, IItem item, bool clone = false) {
+      IResult r;
+      if (!results.TryGetValue(name, out r)) {
+        results.Add(new Result(name, clone ? (IItem)item.Clone() : item));
+      } else r.Value = clone ? (IItem)item.Clone() : item;
+    }
+  }
+}
Index: /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/Analysis/RuggednessCalculator.cs
===================================================================
--- /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/Analysis/RuggednessCalculator.cs	(revision 15702)
+++ /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/Analysis/RuggednessCalculator.cs	(revision 15702)
@@ -0,0 +1,98 @@
+﻿#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.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Operators;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace HeuristicLab.Analysis.FitnessLandscape {
+  [Item("Ruggedness Calculator", "Calculates ruggedness descriptors froma given quality trail.")]
+  [StorableClass]
+  public class RuggednessCalculator : SingleSuccessorOperator {
+
+    #region Parameters
+    public LookupParameter<DataTable> QualityTrailParameter {
+      get { return (LookupParameter<DataTable>)Parameters["QualityTrail"]; }
+    }
+    public LookupParameter<IntValue> CorrelationLengthParameter {
+      get { return (LookupParameter<IntValue>)Parameters["CorrelationLength"]; }
+    }
+    public LookupParameter<DoubleArray> AutoCorrelationParameter {
+      get { return (LookupParameter<DoubleArray>)Parameters["AutoCorrelation"]; }
+    }
+    #endregion
+
+    #region Constructors & Cloning
+    [StorableConstructor]
+    protected RuggednessCalculator(bool deserializing) : base(deserializing) { }
+    protected RuggednessCalculator(RuggednessCalculator original, Cloner cloner) : base(original, cloner) { }
+    public RuggednessCalculator() {
+      Parameters.Add(new LookupParameter<DataTable>("QualityTrail", "Historical values of walk qualities"));
+      Parameters.Add(new LookupParameter<IntValue>("CorrelationLength", "Average maximum distances between correlated quality values."));
+      Parameters.Add(new LookupParameter<DoubleArray>("AutoCorrelation", "AutoCorrelation"));
+    }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new RuggednessCalculator(this, cloner);
+    }
+    #endregion
+
+    public override IOperation Apply() {
+      double[] qualities = QualityTrailParameter.ActualValue.Rows.First().Values.ToArray();
+      double[] autocorrelation;
+      CorrelationLengthParameter.ActualValue = new IntValue(CalculateCorrelationLength(qualities, out autocorrelation));
+      AutoCorrelationParameter.ActualValue = new DoubleArray(autocorrelation);
+      return base.Apply();
+    }
+
+    public static int CalculateCorrelationLength(double[] qualities, out double[] acf) {
+      double[] correlations = new double[qualities.Length];
+      alglib.corr.corrr1dcircular(qualities, qualities.Length, qualities, qualities.Length, ref correlations);
+      double mean = 0;
+      double variance = 0;
+      double skewness = 0;
+      double kurtosis = 0;
+      alglib.basestat.samplemoments(qualities, qualities.Length, ref mean, ref variance, ref skewness, ref kurtosis);
+      List<double> autocorrelation = new List<double>() { 1.0 };
+      int correlationLength = -1, counter = 1;
+      for (; counter < qualities.Length / 2; counter++) {
+        double value = correlations[counter] / qualities.Length - mean * mean;
+        if (variance > 0)
+          value = Math.Max(Math.Min(value / variance, 1.0), -1.0);
+        else
+          value = 1;
+        autocorrelation.Add(value);
+        if (value < 0 && correlationLength < 0) correlationLength = counter;
+      }
+      acf = autocorrelation.ToArray();
+      return correlationLength - 1;
+    }
+
+    public static bool AnyGreaterOne(double[] values) {
+      return values.Any(d => d > 1);
+    }
+  }
+}
Index: /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/Analysis/UniqueThresholdCalculator.cs
===================================================================
--- /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/Analysis/UniqueThresholdCalculator.cs	(revision 15702)
+++ /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/Analysis/UniqueThresholdCalculator.cs	(revision 15702)
@@ -0,0 +1,179 @@
+﻿#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.Diagnostics;
+using System.Linq;
+
+namespace HeuristicLab.Analysis.FitnessLandscape {
+
+  public static class UniqueThresholdCalculator {
+
+    private sealed class IndexRange {
+
+      public int Start, End, N;
+      public readonly bool Merge;
+      private readonly List<IndexRange> receivers, distributors;
+
+      public IndexRange(int start, int end, int n, bool merge) {
+        Start = start;
+        End = end;
+        N = n;
+        Merge = merge;
+        receivers = new List<IndexRange>();
+        distributors = new List<IndexRange>();
+      }
+
+      public void AddReceiver(IndexRange receiver) {
+        if (receiver != null) {
+          receivers.Add(receiver);
+          receiver.distributors.Add(this);
+        }
+      }
+
+      public void Distribute() {
+        int n = N - 1;
+        Debug.Assert(n >= 0);
+        switch (receivers.Count) {
+          case 0: break; // No receivers indexes are lost :-(
+          case 1: receivers[0].N += n; N = 1; break;
+          case 2: receivers[0].N += n / 2; receivers[1].N += n - n / 2; N = 1; break;
+          default: throw new InvalidOperationException("More than two receivers registered");
+        }
+        var followers = distributors.Where(d => d.Start > End).ToList();
+        if (followers.Count > 0)
+          End = followers.Min(g => g.Start);
+        var predecessors = distributors.Where(d => d.End < Start).ToList();
+        if (predecessors.Count > 0)
+          Start = predecessors.Max(g => g.End);
+      }
+
+      public override string ToString() {
+        return string.Format("[{0}-{1}, n={2}, {3}]", Start, End, N, Merge ? "Merge" : "Spread");
+      }
+    }
+
+    public static IEnumerable<double> DetermineThresholds(IEnumerable<double> differences, int n) {
+      var thresholds = differences.Select(d => Math.Abs(d)).ToList();
+      thresholds.Sort();
+      if (thresholds.Count <= n) {
+        foreach (var t in thresholds)
+          yield return t;
+      } else {
+        double min = thresholds[0];
+        double max = thresholds[thresholds.Count - 1];
+        if (min == max) {
+          yield return min;
+        } else {
+          yield return min;
+          foreach (var t in DetermineInnerThresholds(thresholds, n - 2))
+            yield return t;
+          yield return max;
+        }
+      }
+    }
+
+    private static IEnumerable<double> DetermineInnerThresholds(List<double> thresholds, int n) {
+      n = Math.Min(thresholds.Count - 2, n);
+      var indexes = Enumerable.Range(0, n + 2).Select(i => (int)Math.Round(1.0 * i * (thresholds.Count - 1) / (n + 1))).ToList();
+      var ranges = CreateRanges(thresholds, indexes);
+      RedistributeIndexes(ranges);
+      TrimBoundaryRanges(ranges);
+      if (ranges.Count == 1 && ranges[0].Start == 0 && ranges[0].End == thresholds.Count - 1 && ranges[0].N == n) {
+        if (ranges[0].Merge)
+          yield return thresholds[ranges[0].Start];
+        else
+          foreach (var i in indexes.Where(i => ranges[0].Start < i && i < ranges[0].End))
+            yield return thresholds[i];
+      } else {
+        foreach (var range in ranges) {
+          if (range.Merge)
+            yield return thresholds[range.Start];
+          else
+            foreach (var t in DetermineInnerThresholds(thresholds.GetRange(range.Start, range.End - range.Start + 1), range.N))
+              yield return t;
+        }
+      }
+    }
+
+    private static void TrimBoundaryRanges(List<IndexRange> ranges) {
+      if (ranges.Count > 0)
+        if (ranges[0].Merge)
+          ranges.RemoveAt(0);
+        else
+          ranges[0].N--;
+      if (ranges.Count > 0)
+        if (ranges[ranges.Count - 1].Merge)
+          ranges.RemoveAt(ranges.Count - 1);
+        else
+          ranges[ranges.Count - 1].N--;
+    }
+
+    private static void RedistributeIndexes(List<IndexRange> ranges) {
+      IndexRange lastReceiver = null;
+      List<IndexRange> lastDistributors = new List<IndexRange>();
+      foreach (var range in ranges) {
+        if (range.Merge) {
+          range.AddReceiver(lastReceiver);
+          lastDistributors.Add(range);
+        } else {
+          foreach (var d in lastDistributors)
+            d.AddReceiver(range);
+          lastDistributors = new List<IndexRange>();
+          lastReceiver = range;
+        }
+      }
+      foreach (var range in ranges) {
+        range.Distribute();
+      }
+    }
+
+    private static List<IndexRange> CreateRanges(List<double> thresholds, List<int> indexes) {
+      var values = indexes.Select(i => new { i, v = thresholds[i] }).ToList();
+      var mergedRanges = values.GroupBy(iv => iv.v)
+        .Select(g => g.Count() == 1 ?
+          new IndexRange(g.First().i, g.First().i, 1, false) :
+          new IndexRange(g.Min(iv => iv.i), g.Max(iv => iv.i), g.Count(), true)).ToList();
+      IndexRange lastSpreadRange = null;
+      var ranges = new List<IndexRange>();
+      foreach (var group in mergedRanges) {
+        if (group.Merge) {
+          if (lastSpreadRange != null) {
+            ranges.Add(lastSpreadRange);
+            lastSpreadRange = null;
+          }
+          ranges.Add(group);
+        } else {
+          if (lastSpreadRange != null) {
+            lastSpreadRange.End = group.End;
+            lastSpreadRange.N++;
+          } else {
+            lastSpreadRange = group;
+          }
+        }
+      }
+      if (lastSpreadRange != null)
+        ranges.Add(lastSpreadRange);
+      return ranges;
+    }
+  }
+}
Index: /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/Analysis/UpDownWalkAnalyzer.cs
===================================================================
--- /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/Analysis/UpDownWalkAnalyzer.cs	(revision 15702)
+++ /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/Analysis/UpDownWalkAnalyzer.cs	(revision 15702)
@@ -0,0 +1,159 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2010 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Operators;
+using HeuristicLab.Optimization;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using System.Linq;
+
+namespace HeuristicLab.Analysis.FitnessLandscape {
+  [Item("Up/Down Walk Analyzer", "Analyzes the quality trail produced from an up/down walk.")]
+  [StorableClass]
+  public class UpDownWalkAnalyzer : SingleSuccessorOperator, IQualityTrailAnalyzer {
+    public bool EnabledByDefault {
+      get { return false; }
+    }
+
+    #region Parameters
+    public LookupParameter<DataTable> QualityTrailParameter {
+      get { return (LookupParameter<DataTable>)Parameters["Quality Trail"]; }
+    }
+    public LookupParameter<ResultCollection> ResultsParameter {
+      get { return (LookupParameter<ResultCollection>)Parameters["Results"]; }
+    }
+    public LookupParameter<DoubleValue> UpWalkLengthParameter {
+      get { return (LookupParameter<DoubleValue>)Parameters["UpWalkLength"]; }
+    }
+    public LookupParameter<DoubleValue> DownWalkLengthParameter {
+      get { return (LookupParameter<DoubleValue>)Parameters["DownWalkLength"]; }
+    }
+    public LookupParameter<DoubleValue> UpWalkLenVarParameter {
+      get { return (LookupParameter<DoubleValue>)Parameters["UpWalkLenVar"]; }
+    }
+    public LookupParameter<DoubleValue> DownWalkLenVarParameter {
+      get { return (LookupParameter<DoubleValue>)Parameters["DownWalkLenVar"]; }
+    }
+    public LookupParameter<DoubleValue> UpperVarianceParameter {
+      get { return (LookupParameter<DoubleValue>)Parameters["UpperVariance"]; }
+    }
+    public LookupParameter<DoubleValue> LowerVarianceParameter {
+      get { return (LookupParameter<DoubleValue>)Parameters["LowerVariance"]; }
+    }
+    #endregion
+
+    [StorableConstructor]
+    protected UpDownWalkAnalyzer(bool deserializing) : base(deserializing) { }
+    protected UpDownWalkAnalyzer(UpDownWalkAnalyzer original, Cloner cloner) : base(original, cloner) { }
+    public UpDownWalkAnalyzer() {
+      Parameters.Add(new LookupParameter<DataTable>("Quality Trail", "The qualities of the solutions"));
+      Parameters.Add(new LookupParameter<ResultCollection>("Results", "The collection of all results of this algorithm"));
+      Parameters.Add(new LookupParameter<DoubleValue>("DownWalkLength", "Average downward walk length."));
+      Parameters.Add(new LookupParameter<DoubleValue>("UpWalkLength", "Average updward walk length."));
+      Parameters.Add(new LookupParameter<DoubleValue>("UpWalkLenVar", "Upward walk length variance."));
+      Parameters.Add(new LookupParameter<DoubleValue>("DownWalkLenVar", "Downward walk length variance."));
+      Parameters.Add(new LookupParameter<DoubleValue>("LowerVariance", "Lower level variance."));
+      Parameters.Add(new LookupParameter<DoubleValue>("UpperVariance", "Upper level variance."));
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new UpDownWalkAnalyzer(this, cloner);
+    }
+
+    public override IOperation Apply() {
+      var qualityTrail = QualityTrailParameter.ActualValue;
+      if (qualityTrail != null && qualityTrail.Rows.Count > 0) {
+        var qualities = qualityTrail.Rows.First().Values.ToList();
+        if (qualities.Count > 2) {
+          var results = ResultsParameter.ActualValue;
+          var extremes = qualities
+            .Delta((a, b) => new { a, b, diff = b - a })
+            .Select((p, i) => new { p.a, p.b, p.diff, i = i + 1 })
+            .Delta((s1, s2) => new {
+              s1.i,
+              value = s2.a,
+              top = s1.diff >= 0 && s2.diff < 0,
+              bottom = s1.diff <= 0 && s2.diff > 0
+            })
+            .Where(x => x.top || x.bottom)
+            .GroupConsecutive(x => x.bottom)
+            .Select(g => g.Count() == 1
+                           ? g.First()
+                           : (g.First().bottom
+                                ? g.OrderBy(x => x.value).First()
+                                : g.OrderByDescending(x => x.value).First())).ToList();
+          var maxima = extremes.Where(x => x.top).ToList();
+          var minima = extremes.Where(x => x.bottom).ToList();
+          var tops = Enumerable.Repeat(new { length = 0, value = 0.0 }, 0).ToList();
+          var bottoms = tops;
+          if (maxima.Count > 0 && minima.Count > 0) {
+            if (maxima.First().i < minima.First().i) {
+              bottoms = maxima.Zip(minima, (t, b) => new { length = b.i - t.i, b.value }).ToList();
+              minima.Insert(0, new { i = -1, value = 0.0, top = false, bottom = false });
+              tops = maxima.Zip(minima, (t, b) => new { length = t.i - b.i, t.value }).ToList();
+            } else {
+              tops = maxima.Zip(minima, (t, b) => new { length = t.i - b.i, t.value }).ToList();
+              maxima.Insert(0, new { i = -1, value = 0.0, top = false, bottom = false });
+              bottoms = maxima.Zip(minima, (t, b) => new { length = b.i - t.i, b.value }).ToList();
+            }
+            if (tops.Count > 0) {
+              var topLengths = tops.Select(t => (double)t.length).ToList();
+              var topVals = tops.Select(t => t.value).ToList();
+              var uv = new DoubleValue(topVals.Variance());
+              UpperVarianceParameter.ActualValue = uv;
+              AddOrUpdateResult(results, UpperVarianceParameter.Name, uv);
+              var ul = new DoubleValue(topLengths.Average());
+              UpWalkLengthParameter.ActualValue = ul;
+              AddOrUpdateResult(results, UpWalkLengthParameter.Name, ul);
+              var ulv = new DoubleValue(topLengths.Variance());
+              UpWalkLenVarParameter.ActualValue = ulv;
+              AddOrUpdateResult(results, UpWalkLenVarParameter.Name, ulv);
+            }
+            if (bottoms.Count > 0) {
+              var bottomLengths = bottoms.Select(b => (double)b.length).ToList();
+              var bottomVals = bottoms.Select(b => b.value).ToList();
+              var lv = new DoubleValue(bottomVals.Variance());
+              LowerVarianceParameter.ActualValue = lv;
+              AddOrUpdateResult(results, LowerVarianceParameter.Name, lv);
+              var dl = new DoubleValue(bottomLengths.Average());
+              DownWalkLengthParameter.ActualValue = dl;
+              AddOrUpdateResult(results, DownWalkLengthParameter.Name, dl);
+              var dlv = new DoubleValue(bottomLengths.Variance());
+              DownWalkLenVarParameter.ActualValue = dlv;
+              AddOrUpdateResult(results, DownWalkLenVarParameter.Name, dlv);
+            }
+          }
+        }
+      }
+      return base.Apply();
+    }
+
+    private static void AddOrUpdateResult(ResultCollection results, string name, IItem item, bool clone = false) {
+      IResult r;
+      if (!results.TryGetValue(name, out r)) {
+        results.Add(new Result(name, clone ? (IItem)item.Clone() : item));
+      } else r.Value = clone ? (IItem)item.Clone() : item;
+    }
+  }
+}
Index: /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/CharacteristicCalculator/AdaptiveWalkCalculator.cs
===================================================================
--- /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/CharacteristicCalculator/AdaptiveWalkCalculator.cs	(revision 15702)
+++ /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/CharacteristicCalculator/AdaptiveWalkCalculator.cs	(revision 15702)
@@ -0,0 +1,112 @@
+﻿#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.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Optimization;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading;
+
+namespace HeuristicLab.Analysis.FitnessLandscape {
+  [Item("Adaptive Walk Calculator", "Calculates characteristics from an adaptive walk.")]
+  [StorableClass]
+  public class AdaptiveWalkCalculator : NamedItem, ICharacteristicCalculator {
+
+    [Storable]
+    private IProblem problem;
+    public IProblem Problem {
+      get { return problem; }
+      set {
+        if (problem == value) return;
+        problem = value;
+        var soProblem = problem as ISingleObjectiveHeuristicOptimizationProblem;
+        walker.Problem = soProblem;
+      }
+    }
+
+    [Storable]
+    private AdaptiveWalk walker;
+
+    [StorableConstructor]
+    private AdaptiveWalkCalculator(bool deserializing) : base(deserializing) { }
+    private AdaptiveWalkCalculator(AdaptiveWalkCalculator original, Cloner cloner)
+      : base(original, cloner) {
+      problem = cloner.Clone(original.problem);
+      walker = cloner.Clone(original.walker);
+      characteristics = cloner.Clone(original.characteristics);
+    }
+    public AdaptiveWalkCalculator() : this(new AdaptiveWalk()) { }
+    public AdaptiveWalkCalculator(AdaptiveWalk walker) {
+      Name = ItemName;
+      Description = ItemDescription;
+      this.walker = walker;
+      characteristics = new CheckedItemList<StringValue>(
+        new[] { "AutoCorrelation1", "CorrelationLength", "InformationContent",
+        "PartialInformationContent", "DensityBasinInformation", "InformationStability",
+        "Diversity", "Regularity", "TotalEntropy", "PeakInformationContent",
+        "PeakDensityBasinInformation" }.Select(x => new StringValue(x)));
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new AdaptiveWalkCalculator(this, cloner);
+    }
+
+    private CheckedItemList<StringValue> characteristics;
+    public ReadOnlyCheckedItemList<StringValue> Characteristics {
+      get { return characteristics.AsReadOnly(); }
+    }
+
+    public bool CanCalculate() {
+      return Problem is ISingleObjectiveHeuristicOptimizationProblem
+        && Problem.Operators.Any(x => x is IManipulator);
+    }
+
+    public IEnumerable<IResult> Calculate() {
+      walker.Prepare(true);
+      using (var waitHandle = new AutoResetEvent(false)) {
+        EventHandler evHandle = (sender, e) => {
+          if (walker.ExecutionState == ExecutionState.Paused
+          || walker.ExecutionState == ExecutionState.Stopped) waitHandle.Set();
+        };
+        walker.ExecutionStateChanged += evHandle;
+        walker.Start();
+        waitHandle.WaitOne();
+        walker.ExecutionStateChanged -= evHandle;
+      }
+      foreach (var p in characteristics.CheckedItems) {
+        yield return new Result("AdaptiveWalk." + walker.MutatorParameter.Value.Name + "." + p.Value.Value, walker.Results[p.Value.Value].Value);
+      }
+      walker.Prepare(true);
+    }
+
+    public void CollectParameterValues(IDictionary<string, IItem> values) {
+      walker.CollectParameterValues(values);
+    }
+
+    public IKeyedItemCollection<string, IParameter> Parameters {
+      get { return ((IParameterizedItem)walker).Parameters; }
+    }
+  }
+}
Index: /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/CharacteristicCalculator/RandomWalkCalculator.cs
===================================================================
--- /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/CharacteristicCalculator/RandomWalkCalculator.cs	(revision 15702)
+++ /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/CharacteristicCalculator/RandomWalkCalculator.cs	(revision 15702)
@@ -0,0 +1,117 @@
+﻿#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.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Optimization;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading;
+
+namespace HeuristicLab.Analysis.FitnessLandscape {
+  [Item("Random Walk Calculator", "Calculates characteristics from a random walk.")]
+  [StorableClass]
+  public class RandomWalkCalculator : NamedItem, ICharacteristicCalculator {
+
+    [Storable]
+    private IProblem problem;
+    public IProblem Problem {
+      get { return problem; }
+      set {
+        if (problem == value) return;
+        problem = value;
+        var soProblem = problem as ISingleObjectiveHeuristicOptimizationProblem;
+        walker.Problem = soProblem;
+      }
+    }
+
+    [Storable]
+    private RandomWalk walker;
+
+    [StorableConstructor]
+    private RandomWalkCalculator(bool deserializing) : base(deserializing) { }
+    private RandomWalkCalculator(RandomWalkCalculator original, Cloner cloner)
+      : base(original, cloner) {
+      problem = cloner.Clone(original.problem);
+      walker = cloner.Clone(original.walker);
+      characteristics = cloner.Clone(original.characteristics);
+    }
+    public RandomWalkCalculator() : this(new RandomWalk()) { }
+    public RandomWalkCalculator(RandomWalk walker) {
+      Name = ItemName;
+      Description = ItemDescription;
+      this.walker = walker;
+      characteristics = new CheckedItemList<StringValue>(
+        new[] { "AutoCorrelation1", "CorrelationLength", "InformationContent",
+        "PartialInformationContent", "DensityBasinInformation", "InformationStability",
+        "Diversity", "Regularity", "TotalEntropy", "PeakInformationContent",
+        "PeakDensityBasinInformation" }.Select(x => new StringValue(x)));
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new RandomWalkCalculator(this, cloner);
+    }
+
+    private CheckedItemList<StringValue> characteristics;
+    public ReadOnlyCheckedItemList<StringValue> Characteristics {
+      get { return characteristics.AsReadOnly(); }
+    }
+
+    public bool CanCalculate() {
+      return Problem is ISingleObjectiveHeuristicOptimizationProblem
+        && Problem.Operators.Any(x => x is IManipulator);
+    }
+
+    public IEnumerable<IResult> Calculate() {
+      walker.Prepare(true);
+      using (var waitHandle = new AutoResetEvent(false)) {
+        EventHandler evHandle = (sender, e) => {
+          if (walker.ExecutionState == ExecutionState.Paused
+          || walker.ExecutionState == ExecutionState.Stopped) waitHandle.Set();
+        };
+        walker.ExecutionStateChanged += evHandle;
+        try {
+          walker.Start();
+          waitHandle.WaitOne();
+        } finally { walker.ExecutionStateChanged -= evHandle; }
+      }
+      foreach (var p in characteristics.CheckedItems) {
+        var resultName = "RandomWalk." + walker.MutatorParameter.Value.Name + "." + p.Value.Value;
+        IResult result;
+        if (walker.Results.TryGetValue(p.Value.Value, out result)) {
+          yield return new Result(resultName, result.Value);
+        } else yield return new Result(resultName, new DoubleValue(0));
+      }
+      walker.Prepare(true);
+    }
+
+    public void CollectParameterValues(IDictionary<string, IItem> values) {
+      walker.CollectParameterValues(values);
+    }
+
+    public IKeyedItemCollection<string, IParameter> Parameters {
+      get { return ((IParameterizedItem)walker).Parameters; }
+    }
+  }
+}
Index: /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/CharacteristicCalculator/UpDownWalkCalculator.cs
===================================================================
--- /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/CharacteristicCalculator/UpDownWalkCalculator.cs	(revision 15702)
+++ /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/CharacteristicCalculator/UpDownWalkCalculator.cs	(revision 15702)
@@ -0,0 +1,113 @@
+﻿#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.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Optimization;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading;
+
+namespace HeuristicLab.Analysis.FitnessLandscape {
+  [Item("Up/Down Walk Calculator", "Calculates characteristics from an up/down walk.")]
+  [StorableClass]
+  public class UpDownWalkCalculator : NamedItem, ICharacteristicCalculator {
+
+    [Storable]
+    private IProblem problem;
+    public IProblem Problem {
+      get { return problem; }
+      set {
+        if (problem == value) return;
+        problem = value;
+        var soProblem = problem as ISingleObjectiveHeuristicOptimizationProblem;
+        walker.Problem = soProblem;
+      }
+    }
+
+    [Storable]
+    private UpDownWalk walker;
+
+    [StorableConstructor]
+    private UpDownWalkCalculator(bool deserializing) : base(deserializing) { }
+    private UpDownWalkCalculator(UpDownWalkCalculator original, Cloner cloner)
+      : base(original, cloner) {
+      problem = cloner.Clone(original.problem);
+      walker = cloner.Clone(original.walker);
+      characteristics = cloner.Clone(original.characteristics);
+    }
+    public UpDownWalkCalculator() : this(new UpDownWalk()) { }
+    public UpDownWalkCalculator(UpDownWalk walker) {
+      Name = ItemName;
+      Description = ItemDescription;
+      this.walker = walker;
+      characteristics = new CheckedItemList<StringValue>(
+        new[] { "AutoCorrelation1", "CorrelationLength", "InformationContent",
+        "PartialInformationContent", "DensityBasinInformation", "InformationStability", 
+        "Diversity", "Regularity", "TotalEntropy", "PeakInformationContent",
+        "PeakDensityBasinInformation", "DownWalkLength", "UpWalkLength", "UpWalkLenVar",
+        "DownWalkLenVar", "LowerVariance", "UpperVariance" }.Select(x => new StringValue(x)));
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new UpDownWalkCalculator(this, cloner);
+    }
+
+    private CheckedItemList<StringValue> characteristics;
+    public ReadOnlyCheckedItemList<StringValue> Characteristics {
+      get { return characteristics.AsReadOnly(); }
+    }
+
+    public bool CanCalculate() {
+      return Problem is ISingleObjectiveHeuristicOptimizationProblem
+        && Problem.Operators.Any(x => x is IManipulator);
+    }
+
+    public IEnumerable<IResult> Calculate() {
+      walker.Prepare(true);
+      using (var waitHandle = new AutoResetEvent(false)) {
+        EventHandler evHandle = (sender, e) => {
+          if (walker.ExecutionState == ExecutionState.Paused
+          || walker.ExecutionState == ExecutionState.Stopped) waitHandle.Set();
+        };
+        walker.ExecutionStateChanged += evHandle;
+        walker.Start();
+        waitHandle.WaitOne();
+        walker.ExecutionStateChanged -= evHandle;
+      }
+      foreach (var p in characteristics.CheckedItems) {
+        yield return new Result("UpDownWalk." + walker.MutatorParameter.Value.Name + "." + p.Value.Value, walker.Results[p.Value.Value].Value);
+      }
+      walker.Prepare(true);
+    }
+
+    public void CollectParameterValues(IDictionary<string, IItem> values) {
+      walker.CollectParameterValues(values);
+    }
+
+    public IKeyedItemCollection<string, IParameter> Parameters {
+      get { return ((IParameterizedItem)walker).Parameters; }
+    }
+  }
+}
Index: /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/Extensions.cs
===================================================================
--- /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/Extensions.cs	(revision 15702)
+++ /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/Extensions.cs	(revision 15702)
@@ -0,0 +1,55 @@
+﻿#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.Core;
+using System;
+using System.Collections.Generic;
+
+namespace HeuristicLab.Analysis.FitnessLandscape {
+  public static class IListExtensions {
+    public static void DuplicateLast<T>(this IList<T> l) {
+      l.Add(l[l.Count - 1]);
+    }
+
+    public static void Shuffle<T>(this IList<T> list, IRandom random) {
+      int n = list.Count - 1;
+      while (n > 0) {
+        int k = random.Next(n + 1);
+        T value = list[k];
+        list[k] = list[n];
+        list[n] = value;
+        n--;
+      }
+    }
+  }
+
+  public static class IDictionaryExtensions {
+    public static TValue GetValueOrDefault<TKey, TValue>(this IDictionary<TKey, TValue> d, TKey key, Func<TValue> @default) {
+      TValue value;
+      return d.TryGetValue(key, out value) ? value : @default();
+    }
+
+    public static TValue GetValueOrDefault<TKey, TValue>(this IDictionary<TKey, TValue> d, TKey key, TValue @default = default(TValue)) {
+      TValue value;
+      return d.TryGetValue(key, out value) ? value : @default;
+    }
+  }
+}
Index: /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/FDC/BinaryVectorFitnessDistanceCorrelationAnalyzer.cs
===================================================================
--- /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/FDC/BinaryVectorFitnessDistanceCorrelationAnalyzer.cs	(revision 15702)
+++ /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/FDC/BinaryVectorFitnessDistanceCorrelationAnalyzer.cs	(revision 15702)
@@ -0,0 +1,80 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2010 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Encodings.BinaryVectorEncoding;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Analysis.FitnessLandscape {
+
+  [Item("BinaryVectorFitnessDistanceCorrelationAnalyzer", "An operator that analyzes the correlation between fitness and distance to the best know solution for binary vector encoding")]
+  [StorableClass]
+  public class BinaryVectorFitnessDistanceCorrelationAnalyzer : FitnessDistanceCorrelationAnalyzer, IBinaryVectorOperator {
+
+    #region Parameters
+    public ScopeTreeLookupParameter<BinaryVector> BinaryVectorParameter {
+      get { return (ScopeTreeLookupParameter<BinaryVector>)Parameters["BinaryVector"]; }
+    }
+    public LookupParameter<BinaryVector> BestKnownSolution {
+      get { return (LookupParameter<BinaryVector>)Parameters["BestKnownSolution"]; }
+    }
+    #endregion
+
+    [StorableConstructor]
+    protected BinaryVectorFitnessDistanceCorrelationAnalyzer(bool deserializing) : base(deserializing) { }
+    protected BinaryVectorFitnessDistanceCorrelationAnalyzer(BinaryVectorFitnessDistanceCorrelationAnalyzer original, Cloner cloner) : base(original, cloner) { }
+
+    public BinaryVectorFitnessDistanceCorrelationAnalyzer() {
+      Parameters.Add(new ScopeTreeLookupParameter<BinaryVector>("BinaryVector", "The real encoded solution"));
+      Parameters.Add(new LookupParameter<BinaryVector>("BestKnownSolution", "The best known solution"));
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new BinaryVectorFitnessDistanceCorrelationAnalyzer(this, cloner);
+    }
+
+    public static double Distance(BinaryVector a, BinaryVector b) {
+      if (a.Length != b.Length)
+        throw new InvalidOperationException("Cannot compare vectors of different lengths");
+      double nEqualBits = 0;
+      for (int i = 0; i < a.Length; i++) {
+        if (a[i] == b[i])
+          nEqualBits++;
+      }
+      return Math.Max(a.Length, b.Length) - nEqualBits;
+    }
+
+
+    protected override IEnumerable<double> GetDistancesToBestKnownSolution() {
+      if (BinaryVectorParameter.ActualValue == null)
+        return new double[0];
+      BinaryVector bestKnownValue = BestKnownSolution.ActualValue;
+      if (bestKnownValue == null)
+        return BinaryVectorParameter.ActualValue.Select(v => 0d);
+      return BinaryVectorParameter.ActualValue.Select(v => Distance(v, bestKnownValue));
+    }
+  }
+}
Index: /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/FDC/FitnessDistanceCorrelationAnalyzer.cs
===================================================================
--- /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/FDC/FitnessDistanceCorrelationAnalyzer.cs	(revision 15702)
+++ /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/FDC/FitnessDistanceCorrelationAnalyzer.cs	(revision 15702)
@@ -0,0 +1,98 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2010 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Collections.Generic;
+using System.Drawing;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Operators;
+using HeuristicLab.Optimization;
+using HeuristicLab.Optimization.Operators;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Analysis.FitnessLandscape {
+
+  [StorableClass]
+  public abstract class FitnessDistanceCorrelationAnalyzer : AlgorithmOperator, IAnalyzer {
+    public bool EnabledByDefault {
+      get { return false; }
+    }
+
+    #region Parameters
+    public ScopeTreeLookupParameter<DoubleValue> QualityParameter {
+      get { return (ScopeTreeLookupParameter<DoubleValue>)Parameters["Quality"]; }
+    }
+    public ValueLookupParameter<ScatterPlot> FDCParameter {
+      get { return (ValueLookupParameter<ScatterPlot>)Parameters["FDC"]; }
+    }
+    public ValueLookupParameter<VariableCollection> ResultsParameter {
+      get { return (ValueLookupParameter<VariableCollection>)Parameters["Results"]; }
+    }
+    #endregion
+
+    [StorableConstructor]
+    protected FitnessDistanceCorrelationAnalyzer(bool deserializing) : base(deserializing) { }
+    protected FitnessDistanceCorrelationAnalyzer(FitnessDistanceCorrelationAnalyzer original, Cloner cloner)
+      : base(original, cloner) { }
+
+    public FitnessDistanceCorrelationAnalyzer() {
+      Parameters.Add(new ScopeTreeLookupParameter<DoubleValue>("Quality", "The quality of the solution"));
+      Parameters.Add(new ValueLookupParameter<ScatterPlot>("FDC", "The data table the stores all observed fitness/distance values"));
+      Parameters.Add(new ValueLookupParameter<VariableCollection>("Results", "The collection of all results of this algorithm"));
+
+      var resultsCollector = new ResultsCollector();
+      resultsCollector.CollectedValues.Add(new LookupParameter<ScatterPlot>(FDCParameter.Name));
+
+      OperatorGraph.InitialOperator = resultsCollector;
+      resultsCollector.Successor = null;
+    }
+
+    protected abstract IEnumerable<double> GetDistancesToBestKnownSolution();
+
+    public override IOperation Apply() {
+      ScatterPlot plot = FDCParameter.ActualValue;
+      if (plot == null) {
+        plot = new ScatterPlot();
+        plot.Name = "Fitness Distance Correlation";
+        plot.XAxisName = "Quality";
+        plot.YAxisName = "Distance";
+        FDCParameter.ActualValue = plot;
+      }
+      plot.Add(EnumerateFDC().ToList());
+      return base.Apply();
+    }
+
+    private IEnumerable<PointF> EnumerateFDC() {
+      var qualities = QualityParameter.ActualValue.Select(d => d.Value).ToList();
+      var distances = GetDistancesToBestKnownSolution().ToList();
+      if (qualities.Count == distances.Count) {
+        var qIt = qualities.GetEnumerator();
+        var dIt = distances.GetEnumerator();
+        while (qIt.MoveNext() && dIt.MoveNext()) {
+          yield return new PointF((float)qIt.Current, (float)dIt.Current);
+        }
+      }
+    }
+  }
+}
Index: /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/FDC/PermutationFitnessDistanceCorrelationAnalyzer.cs
===================================================================
--- /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/FDC/PermutationFitnessDistanceCorrelationAnalyzer.cs	(revision 15702)
+++ /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/FDC/PermutationFitnessDistanceCorrelationAnalyzer.cs	(revision 15702)
@@ -0,0 +1,107 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2010 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Encodings.PermutationEncoding;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Analysis.FitnessLandscape {
+
+  [Item("PermutationFitnessDistanceCorrelationAnalyzer", "An operator that analyzes the correlation between fitness and distance to the best know solution for permutation encoding")]
+  [StorableClass]
+  public class PermutationFitnessDistanceCorrelationAnalyzer : FitnessDistanceCorrelationAnalyzer, IPermutationOperator {
+
+    #region Parameters
+    public ScopeTreeLookupParameter<Permutation> PermutationParameter {
+      get { return (ScopeTreeLookupParameter<Permutation>)Parameters["Permutation"]; }
+    }
+    public LookupParameter<Permutation> BestKnownSolution {
+      get { return (LookupParameter<Permutation>)Parameters["BestKnownSolution"]; }
+    }
+    #endregion
+
+    [StorableConstructor]
+    protected PermutationFitnessDistanceCorrelationAnalyzer(bool deserializing) : base(deserializing) { }
+    protected PermutationFitnessDistanceCorrelationAnalyzer(PermutationFitnessDistanceCorrelationAnalyzer original, Cloner cloner) : base(original, cloner) { }
+
+    public PermutationFitnessDistanceCorrelationAnalyzer() {
+      Parameters.Add(new ScopeTreeLookupParameter<Permutation>("Permutation", "The permutation encoded solution"));
+      Parameters.Add(new LookupParameter<Permutation>("BestKnownSolution", "The best known solution"));
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new PermutationFitnessDistanceCorrelationAnalyzer(this, cloner);
+    }
+
+    private static Point GetEdge(Permutation a, int index) {
+      switch (a.PermutationType) {
+        case PermutationTypes.RelativeDirected:
+          return new Point(a[index], a[(index + 1) % a.Length]);
+        case PermutationTypes.RelativeUndirected:
+          return new Point(
+            Math.Min(a[index], a[(index + 1) % a.Length]),
+            Math.Max(a[index], a[(index + 1) % a.Length]));
+        default:
+          throw new ArgumentException("cannot derive edge from non-relative permutation type");
+      }
+    }
+
+    public static double Distance(Permutation a, Permutation b) {
+      if (a.PermutationType != b.PermutationType)
+        throw new ArgumentException(
+          "Cannot calculate distance between different permuatation types: " +
+          a.PermutationType + " and " + b.PermutationType);
+      if (a.PermutationType == PermutationTypes.Absolute) {
+        int nEqual = 0;
+        for (int i = 0; i < Math.Min(a.Length, b.Length); i++) {
+          if (a[i] == b[i])
+            nEqual++;
+        }
+        return Math.Max(a.Length, b.Length) - nEqual;
+      } else {
+        HashSet<Point> edges = new HashSet<Point>();
+        for (int i = 0; i < a.Length; i++)
+          edges.Add(GetEdge(a, i));
+        int nCommonEdges = 0;
+        for (int i = 0; i < b.Length; i++) {
+          if (edges.Contains(GetEdge(b, i)))
+            nCommonEdges++;
+        }
+        return Math.Max(a.Length, b.Length) - nCommonEdges;
+      }
+    }
+
+    protected override IEnumerable<double> GetDistancesToBestKnownSolution() {
+      if (PermutationParameter.ActualName == null)
+        return new double[0];
+      Permutation bestKnownValue = BestKnownSolution.ActualValue;
+      if (bestKnownValue == null)
+        return PermutationParameter.ActualValue.Select(v => 0d);
+      return PermutationParameter.ActualValue.Select(v => Distance(v, bestKnownValue));
+    }
+  }
+}
Index: /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/FDC/QAPPermutationFitnessDistanceCorrelationAnalyzer.cs
===================================================================
--- /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/FDC/QAPPermutationFitnessDistanceCorrelationAnalyzer.cs	(revision 15702)
+++ /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/FDC/QAPPermutationFitnessDistanceCorrelationAnalyzer.cs	(revision 15702)
@@ -0,0 +1,101 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2010 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Encodings.PermutationEncoding;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Analysis.FitnessLandscape {
+
+  [Item("QAPPermutationFitnessDistanceCorrelationAnalyzer", "An operator that analyzes the correlation between fitness and distance to the best know solution for permutation encoding")]
+  [StorableClass]
+  public class QAPPermutationFitnessDistanceCorrelationAnalyzer : FitnessDistanceCorrelationAnalyzer, IPermutationOperator {
+
+    #region Parameters
+    public ScopeTreeLookupParameter<Permutation> PermutationParameter {
+      get { return (ScopeTreeLookupParameter<Permutation>)Parameters["Permutation"]; }
+    }
+    public LookupParameter<Permutation> BestKnownSolution {
+      get { return (LookupParameter<Permutation>)Parameters["BestKnownSolution"]; }
+    }
+    public ILookupParameter<DoubleMatrix> WeightsParameter {
+      get { return (ILookupParameter<DoubleMatrix>)Parameters["Weights"]; }
+    }
+    public ILookupParameter<DoubleMatrix> DistancesParameter {
+      get { return (ILookupParameter<DoubleMatrix>)Parameters["Distances"]; }
+    }
+    #endregion
+
+    [StorableConstructor]
+    protected QAPPermutationFitnessDistanceCorrelationAnalyzer(bool deserializing) : base(deserializing) { }
+    protected QAPPermutationFitnessDistanceCorrelationAnalyzer(QAPPermutationFitnessDistanceCorrelationAnalyzer original, Cloner cloner) : base(original, cloner) { }
+
+    public QAPPermutationFitnessDistanceCorrelationAnalyzer() {
+      Parameters.Add(new ScopeTreeLookupParameter<Permutation>("Permutation", "The permutation encoded solution"));
+      Parameters.Add(new LookupParameter<Permutation>("BestKnownSolution", "The best known solution"));
+      Parameters.Add(new LookupParameter<DoubleMatrix>("Weights", "The weights matrix."));
+      Parameters.Add(new LookupParameter<DoubleMatrix>("Distances", "The distances matrix."));
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new QAPPermutationFitnessDistanceCorrelationAnalyzer(this, cloner);
+    }
+
+    public static double Distance(Permutation a, Permutation b, DoubleMatrix weights, DoubleMatrix distances) {
+      Dictionary<string, int> alleles = new Dictionary<string, int>(a.Length * a.Length);
+      int distance = 0;
+      for (int x = 0; x < a.Length; x++) {
+        for (int y = 0; y < a.Length; y++) {
+          string alleleA = weights[x, y].ToString() + ">" + distances[a[x], a[y]].ToString();
+          string alleleB = weights[x, y].ToString() + ">" + distances[b[x], b[y]].ToString();
+          if (alleleA == alleleB) continue;
+
+          int countA = 1, countB = -1;
+          if (alleles.ContainsKey(alleleA)) countA += alleles[alleleA];
+          if (alleles.ContainsKey(alleleB)) countB += alleles[alleleB];
+
+          if (countA <= 0) distance--; // we've found in A an allele that was present in B
+          else distance++; // we've found in A a new allele
+          alleles[alleleA] = countA;
+
+          if (countB >= 0) distance--; // we've found in B an allele that was present in A
+          else distance++; // we've found in B a new allele
+          alleles[alleleB] = countB;
+        }
+      }
+      return distance;
+    }
+
+    protected override IEnumerable<double> GetDistancesToBestKnownSolution() {
+      if (PermutationParameter.ActualName == null)
+        return new double[0];
+      Permutation bestKnownValue = BestKnownSolution.ActualValue;
+      if (bestKnownValue == null)
+        return PermutationParameter.ActualValue.Select(v => 0d);
+      return PermutationParameter.ActualValue.Select(v => Distance(v, bestKnownValue, WeightsParameter.ActualValue, DistancesParameter.ActualValue));
+    }
+  }
+}
Index: /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/FDC/RealVectorFitnessDistanceCorrelationAnalyzer.cs
===================================================================
--- /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/FDC/RealVectorFitnessDistanceCorrelationAnalyzer.cs	(revision 15702)
+++ /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/FDC/RealVectorFitnessDistanceCorrelationAnalyzer.cs	(revision 15702)
@@ -0,0 +1,79 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2010 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Encodings.RealVectorEncoding;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Analysis.FitnessLandscape {
+
+  [Item("RealVectorFitnessDistanceCorrelationAnalyzer", "An operator that analyzes the correlation between fitness and distance to the best know solution for real vector encoding")]
+  [StorableClass]
+  public class RealVectorFitnessDistanceCorrelationAnalyzer : FitnessDistanceCorrelationAnalyzer, IRealVectorOperator {
+
+    #region Parameters
+    public ScopeTreeLookupParameter<RealVector> RealVectorParameter {
+      get { return (ScopeTreeLookupParameter<RealVector>)Parameters["RealVector"]; }
+    }
+    public LookupParameter<RealVector> BestKnownSolution {
+      get { return (LookupParameter<RealVector>)Parameters["BestKnownSolution"]; }
+    }
+    #endregion
+
+    [StorableConstructor]
+    protected RealVectorFitnessDistanceCorrelationAnalyzer(bool deserializing) : base(deserializing) { }
+    protected RealVectorFitnessDistanceCorrelationAnalyzer(RealVectorFitnessDistanceCorrelationAnalyzer original, Cloner cloner) : base(original, cloner) { }
+
+    public RealVectorFitnessDistanceCorrelationAnalyzer() {
+      Parameters.Add(new ScopeTreeLookupParameter<RealVector>("RealVector", "The real encoded solution"));
+      Parameters.Add(new LookupParameter<RealVector>("BestKnownSolution", "The best known solution"));
+      RealVectorParameter.ActualName = "Point";
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new RealVectorFitnessDistanceCorrelationAnalyzer(this, cloner);
+    }
+
+    public static double Distance(RealVector a, RealVector b) {
+      if (a.Length != b.Length)
+        throw new InvalidOperationException("Cannot compare vectors of different lengths");
+      double sum = 0;
+      for (int i = 0; i < a.Length; i++) {
+        sum += (a[i] - b[i]) * (a[i] - b[i]);
+      }
+      return Math.Sqrt(sum);
+    }
+
+    protected override IEnumerable<double> GetDistancesToBestKnownSolution() {
+      if (this.RealVectorParameter.ActualValue == null)
+        return new double[0];
+      RealVector bestKnownValue = BestKnownSolution.ActualValue;
+      if (bestKnownValue == null)
+        return RealVectorParameter.ActualValue.Select(v => 0d);
+      return RealVectorParameter.ActualValue.Select(v => Distance(v, bestKnownValue));
+    }
+  }
+}
Index: /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/FDC/ScatterPlot.cs
===================================================================
--- /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/FDC/ScatterPlot.cs	(revision 15702)
+++ /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/FDC/ScatterPlot.cs	(revision 15702)
@@ -0,0 +1,150 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2010 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Common.Resources;
+
+namespace HeuristicLab.Analysis.FitnessLandscape {
+
+  public class PointsEventArgs : EventArgs {
+    public IEnumerable<PointF> NewPoints { get; private set; }
+    public PointsEventArgs(IEnumerable<PointF> points) {
+      NewPoints = points.ToList();
+    }
+  }
+
+  [Item("ScatterPlot", "A scatter plot of 2D data")]
+  [StorableClass]
+  public class ScatterPlot : NamedItem {
+
+    public static new Image StaticItemImage { get { return VSImageLibrary.Image; } }
+
+    public event EventHandler<PointsEventArgs> PixelsChanged;
+    public event EventHandler AxisNameChanged;
+
+    protected virtual void OnPixelsChanged(IEnumerable<PointF> p) {
+      EventHandler<PointsEventArgs> handler = PixelsChanged;
+      if (handler != null)
+        handler(this, new PointsEventArgs(p));
+    }
+
+    protected virtual void OnAxesNameChanged() {
+      EventHandler handler = AxisNameChanged;
+      if (handler != null)
+        handler(this, EventArgs.Empty);
+    }
+
+    private IEnumerable<float> GetPointCoordinates() {
+      foreach (var p in points) {
+        yield return p.X;
+        yield return p.Y;
+      }
+    }
+
+    [Storable]
+    private List<float> PointCoordinateList {
+      get {
+        return new List<float>(GetPointCoordinates());
+      }
+      set {
+        points = new HashSet<PointF>();
+        var iter = value.GetEnumerator();
+        while (iter.MoveNext()) {
+          float x = iter.Current;
+          iter.MoveNext();
+          float y = iter.Current;
+          points.Add(new PointF(x, y));
+        }
+      }
+    }
+
+    private HashSet<PointF> points;
+    public IEnumerable<PointF> Points {
+      get { return points; }
+    }
+
+    [Storable]
+    private string xAxisName;
+    public string XAxisName {
+      get { return xAxisName; }
+      set {
+        if (value == xAxisName) return;
+        xAxisName = value;
+        OnAxesNameChanged();
+      }
+    }
+
+    [Storable]
+    private string yAxisName;
+    public string YAxisName {
+      get { return yAxisName; }
+      set {
+        if (value == yAxisName) return;
+        yAxisName = value;
+        OnAxesNameChanged();
+      }
+    }
+
+    public void Add(IEnumerable<PointF> points) {
+      List<PointF> newPoints = new List<PointF>();
+      foreach (var p in points) {
+        if (this.points.Add(p))
+          newPoints.Add(p);
+      }
+      if (newPoints.Count > 0)
+        OnPixelsChanged(newPoints);
+    }
+
+    [StorableConstructor]
+    protected ScatterPlot(bool deserializing) : base(deserializing) { }
+    protected ScatterPlot(ScatterPlot original, Cloner cloner)
+      : base(original, cloner) {
+      points = new HashSet<PointF>(original.points.Select(p => new PointF(p.X, p.Y)));
+      xAxisName = original.xAxisName;
+      yAxisName = original.yAxisName;
+    }
+
+
+    public ScatterPlot() {
+      points = new HashSet<PointF>();
+      Name = "Scatter Plot";
+      xAxisName = "Fitness";
+      yAxisName = "Distance";
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new ScatterPlot(this, cloner);
+    }
+
+
+    internal void Clear() {
+      var oldPoints = points;
+      points = new HashSet<PointF>();
+      OnPixelsChanged(oldPoints);
+    }
+  }
+}
Index: /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/HeuristicLab.Analysis.FitnessLandscape-3.3.csproj
===================================================================
--- /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/HeuristicLab.Analysis.FitnessLandscape-3.3.csproj	(revision 15702)
+++ /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/HeuristicLab.Analysis.FitnessLandscape-3.3.csproj	(revision 15702)
@@ -0,0 +1,282 @@
+﻿<?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>9.0.30729</ProductVersion>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{5FBDCD4A-3C2A-4EC6-83CE-34B29F43621A}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>HeuristicLab.Analysis.FitnessLandscape</RootNamespace>
+    <AssemblyName>HeuristicLab.Analysis.FitnessLandscape-3.3</AssemblyName>
+    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+    <SignAssembly>true</SignAssembly>
+    <AssemblyOriginatorKeyFile>HeuristicLab.snk</AssemblyOriginatorKeyFile>
+    <FileUpgradeFlags>
+    </FileUpgradeFlags>
+    <OldToolsVersion>3.5</OldToolsVersion>
+    <UpgradeBackupLocation />
+    <PublishUrl>publish\</PublishUrl>
+    <Install>true</Install>
+    <InstallFrom>Disk</InstallFrom>
+    <UpdateEnabled>false</UpdateEnabled>
+    <UpdateMode>Foreground</UpdateMode>
+    <UpdateInterval>7</UpdateInterval>
+    <UpdateIntervalUnits>Days</UpdateIntervalUnits>
+    <UpdatePeriodically>false</UpdatePeriodically>
+    <UpdateRequired>false</UpdateRequired>
+    <MapFileExtensions>true</MapFileExtensions>
+    <ApplicationRevision>0</ApplicationRevision>
+    <ApplicationVersion>1.0.0.%2a</ApplicationVersion>
+    <IsWebBootstrapper>false</IsWebBootstrapper>
+    <UseApplicationTrust>false</UseApplicationTrust>
+    <BootstrapperEnabled>true</BootstrapperEnabled>
+    <TargetFrameworkProfile />
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>..\..\..\..\trunk\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\bin\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <Prefer32Bit>false</Prefer32Bit>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
+    <DebugSymbols>true</DebugSymbols>
+    <OutputPath>..\..\..\..\trunk\bin\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <DebugType>full</DebugType>
+    <PlatformTarget>x86</PlatformTarget>
+    <ErrorReport>prompt</ErrorReport>
+    <Prefer32Bit>false</Prefer32Bit>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
+    <OutputPath>..\..\..\..\trunk\bin\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <Optimize>true</Optimize>
+    <DebugType>pdbonly</DebugType>
+    <PlatformTarget>x86</PlatformTarget>
+    <ErrorReport>prompt</ErrorReport>
+    <Prefer32Bit>false</Prefer32Bit>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x64' ">
+    <DebugSymbols>true</DebugSymbols>
+    <OutputPath>..\..\..\..\trunk\bin\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <DebugType>full</DebugType>
+    <PlatformTarget>x64</PlatformTarget>
+    <ErrorReport>prompt</ErrorReport>
+    <Prefer32Bit>false</Prefer32Bit>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x64' ">
+    <OutputPath>..\..\..\..\trunk\bin\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <Optimize>true</Optimize>
+    <DebugType>pdbonly</DebugType>
+    <PlatformTarget>x64</PlatformTarget>
+    <ErrorReport>prompt</ErrorReport>
+    <Prefer32Bit>false</Prefer32Bit>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="ALGLIB-3.7.0">
+      <HintPath>..\..\..\..\trunk\bin\ALGLIB-3.7.0.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.Analysis-3.3">
+      <HintPath>..\..\..\..\trunk\bin\HeuristicLab.Analysis-3.3.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.Collections-3.3">
+      <HintPath>..\..\..\..\trunk\bin\HeuristicLab.Collections-3.3.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.Common-3.3">
+      <HintPath>..\..\..\..\trunk\bin\HeuristicLab.Common-3.3.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.Common.Resources-3.3">
+      <HintPath>..\..\..\..\trunk\bin\HeuristicLab.Common.Resources-3.3.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.Core-3.3">
+      <HintPath>..\..\..\..\trunk\bin\HeuristicLab.Core-3.3.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.Data-3.3">
+      <HintPath>..\..\..\..\trunk\bin\HeuristicLab.Data-3.3.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.Encodings.BinaryVectorEncoding-3.3">
+      <HintPath>..\..\..\..\trunk\bin\HeuristicLab.Encodings.BinaryVectorEncoding-3.3.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.Encodings.IntegerVectorEncoding-3.3">
+      <HintPath>..\..\..\..\trunk\bin\HeuristicLab.Encodings.IntegerVectorEncoding-3.3.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.Encodings.PermutationEncoding-3.3">
+      <HintPath>..\..\..\..\trunk\bin\HeuristicLab.Encodings.PermutationEncoding-3.3.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.Encodings.RealVectorEncoding-3.3">
+      <HintPath>..\..\..\..\trunk\bin\HeuristicLab.Encodings.RealVectorEncoding-3.3.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.Operators-3.3">
+      <HintPath>..\..\..\..\trunk\bin\HeuristicLab.Operators-3.3.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.Optimization.Operators-3.3">
+      <HintPath>..\..\..\..\trunk\bin\HeuristicLab.Optimization.Operators-3.3.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.Parameters-3.3">
+      <HintPath>..\..\..\..\trunk\bin\HeuristicLab.Parameters-3.3.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.Persistence-3.3">
+      <HintPath>..\..\..\..\trunk\bin\HeuristicLab.Persistence-3.3.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.PluginInfrastructure-3.3">
+      <HintPath>..\..\..\..\trunk\bin\HeuristicLab.PluginInfrastructure-3.3.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.Problems.Instances-3.3">
+      <HintPath>..\..\..\..\trunk\bin\HeuristicLab.Problems.Instances-3.3.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.Problems.QuadraticAssignment-3.3">
+      <HintPath>..\..\..\..\trunk\bin\HeuristicLab.Problems.QuadraticAssignment-3.3.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.Random-3.3">
+      <HintPath>..\..\..\..\trunk\bin\HeuristicLab.Random-3.3.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.Selection-3.3">
+      <HintPath>..\..\..\..\trunk\bin\HeuristicLab.Selection-3.3.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="System" />
+    <Reference Include="System.Core">
+      <RequiredTargetFramework>3.5</RequiredTargetFramework>
+    </Reference>
+    <Reference Include="System.Drawing" />
+    <Reference Include="System.IO.Compression" />
+    <Reference Include="System.Windows.Forms" />
+    <Reference Include="System.Windows.Forms.DataVisualization" />
+    <Reference Include="System.Xml.Linq">
+      <RequiredTargetFramework>3.5</RequiredTargetFramework>
+    </Reference>
+    <Reference Include="System.Data.DataSetExtensions">
+      <RequiredTargetFramework>3.5</RequiredTargetFramework>
+    </Reference>
+    <Reference Include="System.Data" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="Algorithms\AdaptiveWalk.cs" />
+    <Compile Include="Algorithms\FLACharacterizer.cs" />
+    <Compile Include="Algorithms\UpDownWalk.cs" />
+    <Compile Include="Algorithms\RandomWalk.cs" />
+    <Compile Include="Analysis\RuggednessCalculator.cs" />
+    <Compile Include="Analysis\UpDownWalkAnalyzer.cs" />
+    <Compile Include="Analysis\EnumerableExtensions.cs" />
+    <Compile Include="Analysis\FitnessCloudAnalyzer.cs" />
+    <Compile Include="Analysis\InformationAnalysis.cs" />
+    <Compile Include="Analysis\QualityTrailMultiAnalyzer.cs" />
+    <Compile Include="Analysis\RuggednessAnalyzer.cs" />
+    <Compile Include="Analysis\IQualityTrailAnalyzer.cs" />
+    <Compile Include="Algorithms\LocalAnalysis.cs" />
+    <Compile Include="Algorithms\LocalAnalysisMainLoop.cs" />
+    <Compile Include="Analysis\InformationAnalyzer.cs" />
+    <Compile Include="Analysis\UniqueThresholdCalculator.cs" />
+    <Compile Include="CharacteristicCalculator\AdaptiveWalkCalculator.cs" />
+    <Compile Include="CharacteristicCalculator\UpDownWalkCalculator.cs" />
+    <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" />
+    <Compile Include="ProblemInstanceAnalysis\DirectedPath.cs" />
+    <Compile Include="ProblemInstanceAnalysis\ProblemInstanceAnalyzer.cs" />
+    <Compile Include="ProblemInstanceAnalysis\PRProblemInstanceAnalyzer.cs" />
+    <Compile Include="ProblemInstanceAnalysis\QAPPRProblemInstanceAnalyzer.cs" />
+    <Compile Include="UpDownSelector.cs" />
+    <Compile Include="Extensions.cs" />
+    <Compile Include="FDC\QAPPermutationFitnessDistanceCorrelationAnalyzer.cs" />
+    <Compile Include="FDC\BinaryVectorFitnessDistanceCorrelationAnalyzer.cs" />
+    <Compile Include="Plugin.cs" />
+    <Compile Include="FDC\PermutationFitnessDistanceCorrelationAnalyzer.cs" />
+    <None Include="Properties\AssemblyInfo.cs.frame" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="FDC\RealVectorFitnessDistanceCorrelationAnalyzer.cs" />
+    <Compile Include="FDC\FitnessDistanceCorrelationAnalyzer.cs" />
+    <None Include="Plugin.cs.frame" />
+    <Compile Include="FDC\ScatterPlot.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="HeuristicLab.snk" />
+  </ItemGroup>
+  <ItemGroup>
+    <BootstrapperPackage Include="Microsoft.Net.Client.3.5">
+      <Visible>False</Visible>
+      <ProductName>.NET Framework 3.5 SP1 Client Profile</ProductName>
+      <Install>false</Install>
+    </BootstrapperPackage>
+    <BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
+      <Visible>False</Visible>
+      <ProductName>.NET Framework 3.5 SP1</ProductName>
+      <Install>true</Install>
+    </BootstrapperPackage>
+    <BootstrapperPackage Include="Microsoft.Windows.Installer.3.1">
+      <Visible>False</Visible>
+      <ProductName>Windows Installer 3.1</ProductName>
+      <Install>true</Install>
+    </BootstrapperPackage>
+  </ItemGroup>
+  <ItemGroup>
+    <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>False</Private>
+    </ProjectReference>
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <!-- 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>
+  -->
+  <PropertyGroup>
+    <PostBuildEvent>
+    </PostBuildEvent>
+  </PropertyGroup>
+  <PropertyGroup>
+    <PreBuildEvent>set Path=%25Path%25;$(ProjectDir);$(SolutionDir)
+set ProjectDir=$(ProjectDir)
+set SolutionDir=$(SolutionDir)
+set Outdir=$(Outdir)
+
+call PreBuildEvent.cmd
+</PreBuildEvent>
+  </PropertyGroup>
+</Project>
Index: /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/Plugin.cs.frame
===================================================================
--- /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/Plugin.cs.frame	(revision 15702)
+++ /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/Plugin.cs.frame	(revision 15702)
@@ -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 HeuristicLab.PluginInfrastructure;
+
+namespace HeuristicLab.Analysis.FitnessLandscape {
+
+  [Plugin("HeuristicLab.Analysis.FitnessLandscape", "3.3.14.$WCREV$")]
+  [PluginFile("HeuristicLab.Analysis.FitnessLandscape-3.3.dll", PluginFileType.Assembly)]
+  [PluginDependency("HeuristicLab.ALGLIB", "3.7")]
+  [PluginDependency("HeuristicLab.Analysis", "3.3")]
+  [PluginDependency("HeuristicLab.Collections", "3.3")]
+  [PluginDependency("HeuristicLab.Common", "3.3")]
+  [PluginDependency("HeuristicLab.Common.Resources", "3.3")]
+  [PluginDependency("HeuristicLab.Core", "3.3")]
+  [PluginDependency("HeuristicLab.Data", "3.3")]
+  [PluginDependency("HeuristicLab.Encodings.BinaryVectorEncoding", "3.3")]
+  [PluginDependency("HeuristicLab.Encodings.PermutationEncoding", "3.3")]
+  [PluginDependency("HeuristicLab.Encodings.RealVectorEncoding", "3.3")]
+  [PluginDependency("HeuristicLab.Operators", "3.3")]
+  [PluginDependency("HeuristicLab.Optimization", "3.3")]
+  [PluginDependency("HeuristicLab.Optimization.Operators", "3.3")]
+  [PluginDependency("HeuristicLab.Parameters", "3.3")]
+  [PluginDependency("HeuristicLab.Persistence", "3.3")]  
+  [PluginDependency("HeuristicLab.Problems.TestFunctions", "3.3")]  
+  [PluginDependency("HeuristicLab.Random", "3.3")]
+  [PluginDependency("HeuristicLab.Selection", "3.3")]
+  public class HeuristicLabAnalysisFitnessLandscapePlugin : PluginBase { }
+}
Index: /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/ProblemCharacteristicAnalysis/CharacteristicCalculator.cs
===================================================================
--- /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/ProblemCharacteristicAnalysis/CharacteristicCalculator.cs	(revision 15702)
+++ /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/ProblemCharacteristicAnalysis/CharacteristicCalculator.cs	(revision 15702)
@@ -0,0 +1,59 @@
+﻿#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.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Optimization;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using System.Collections.Generic;
+
+namespace HeuristicLab.Analysis.FitnessLandscape {
+  [Item("Characteristic Calculator", "")]
+  [StorableClass]
+  public abstract class CharacteristicCalculator : ParameterizedNamedItem, ICharacteristicCalculator {
+
+    [Storable]
+    public IProblem Problem { get; set; }
+
+    [Storable]
+    protected CheckedItemList<StringValue> characteristics;
+    public ReadOnlyCheckedItemList<StringValue> Characteristics { get { return characteristics.AsReadOnly(); } }
+
+    [StorableConstructor]
+    protected CharacteristicCalculator(bool deserializing) : base(deserializing) { }
+    protected CharacteristicCalculator(CharacteristicCalculator original, Cloner cloner)
+      : base(original, cloner) {
+      characteristics = cloner.Clone(original.characteristics);
+      Problem = cloner.Clone(original.Problem);
+    }
+    protected CharacteristicCalculator()
+      : base() {
+      name = ItemName;
+      description = ItemDescription;
+      characteristics = new CheckedItemList<StringValue>();
+    }
+
+    public abstract bool CanCalculate();
+
+    public abstract IEnumerable<IResult> Calculate();
+  }
+}
Index: /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/ProblemCharacteristicAnalysis/CurveAnalysis.cs
===================================================================
--- /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/ProblemCharacteristicAnalysis/CurveAnalysis.cs	(revision 15702)
+++ /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/ProblemCharacteristicAnalysis/CurveAnalysis.cs	(revision 15702)
@@ -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/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/ProblemCharacteristicAnalysis/DoubleMatrixCharacteristicCalculator.cs
===================================================================
--- /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/ProblemCharacteristicAnalysis/DoubleMatrixCharacteristicCalculator.cs	(revision 15702)
+++ /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/ProblemCharacteristicAnalysis/DoubleMatrixCharacteristicCalculator.cs	(revision 15702)
@@ -0,0 +1,75 @@
+﻿#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.Common;
+using HeuristicLab.Data;
+using System;
+using System.Linq;
+
+namespace HeuristicLab.Analysis.FitnessLandscape {
+  public static class DoubleMatrixCharacteristicCalculator {
+    public static double CoeffVariation(DoubleMatrix m) {
+      var avg = m.Average();
+      var stdDev = m.StandardDeviation();
+      return stdDev / avg;
+    }
+
+    public static double Sparsity(DoubleMatrix m) {
+      return m.Count(x => x == 0) / (double)(m.Rows * m.Columns);
+    }
+
+    public static double Disparity(DoubleMatrix m) {
+      if (m.Rows != m.Columns) throw new ArgumentException("not a quadratic matrix", "m");
+      var n = m.Rows;
+      var avg = m.Sum() / n;
+      var disparity = 0.0;
+      for (var i = 0; i < n; i++) {
+        var tmp = 0.0;
+        for (var j = 0; j < n; j++) {
+          tmp += m[i, j];
+        }
+        disparity += (tmp - avg) * (tmp - avg);
+      }
+      return Math.Sqrt(disparity / n) / avg;
+    }
+
+    public static double Skewness(DoubleMatrix m) {
+      double mean = 0, variance = 0, skewness = 0, kurtosis = 0;
+      alglib.basestat.samplemoments(m.ToArray(), m.Rows * m.Columns, ref mean, ref variance, ref skewness, ref kurtosis);
+      return skewness;
+    }
+
+    public static double Asymmetry(DoubleMatrix m) {
+      if (m.Rows != m.Columns) throw new ArgumentException("not a quadratic matrix", "m");
+      var n = m.Rows;
+      var count = 0;
+      for (var i = 0; i < n; i++) {
+        for (var j = 0; j < i; j++) {
+          var v = Math.Abs(m[i, j] - m[j, i]);
+          if (v > 0) {
+            count++;
+          }
+        }
+      }
+      return count / (n * (n - 1) / 2.0);
+    }
+  }
+}
Index: /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/ProblemCharacteristicAnalysis/PermutationPathAnalysis.cs
===================================================================
--- /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/ProblemCharacteristicAnalysis/PermutationPathAnalysis.cs	(revision 15702)
+++ /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/ProblemCharacteristicAnalysis/PermutationPathAnalysis.cs	(revision 15702)
@@ -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/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/ProblemCharacteristicAnalysis/QAP/QAPCharacteristicCalculator.cs
===================================================================
--- /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/ProblemCharacteristicAnalysis/QAP/QAPCharacteristicCalculator.cs	(revision 15702)
+++ /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/ProblemCharacteristicAnalysis/QAP/QAPCharacteristicCalculator.cs	(revision 15702)
@@ -0,0 +1,86 @@
+﻿#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.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Optimization;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Problems.QuadraticAssignment;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace HeuristicLab.Analysis.FitnessLandscape {
+  [Item("QAP Characteristic Calculator", "")]
+  [StorableClass]
+  public sealed class QAPCharacteristicCalculator : CharacteristicCalculator {
+
+    [StorableConstructor]
+    private QAPCharacteristicCalculator(bool deserializing) : base(deserializing) { }
+    private QAPCharacteristicCalculator(QAPCharacteristicCalculator original, Cloner cloner) : base(original, cloner) { }
+    public QAPCharacteristicCalculator() {
+      characteristics.AddRange(new[] { "Dimension",
+        "FlowDominance", "DistanceDominance",
+        "FlowAsymmetry", "DistanceAsymmetry",
+        "FlowSparsity", "DistanceSparsity",
+        "FlowSkewness", "DistanceSkewness",
+        "FlowDisparity", "DistanceDisparity" }.Select(x => new StringValue(x)).ToList());
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new QAPCharacteristicCalculator(this, cloner);
+    }
+
+    public override bool CanCalculate() {
+      return Problem is QuadraticAssignmentProblem;
+    }
+
+    public override IEnumerable<IResult> Calculate() {
+      var qap = Problem as QuadraticAssignmentProblem;
+      if (qap == null) throw new ArgumentException("Instance is not of type QuadraticAssignmentProblem");
+      foreach (var chara in characteristics.CheckedItems.Select(x => x.Value.Value)) {
+        if (chara == "Dimension")
+          yield return new Result(chara, new IntValue(qap.Weights.Rows));
+        if (chara == "FlowDominance")
+          yield return new Result(chara, new DoubleValue(DoubleMatrixCharacteristicCalculator.CoeffVariation(qap.Weights)));
+        if (chara == "DistanceDominance")
+          yield return new Result(chara, new DoubleValue(DoubleMatrixCharacteristicCalculator.CoeffVariation(qap.Distances)));
+        if (chara == "FlowAsymmetry")
+          yield return new Result(chara, new DoubleValue(DoubleMatrixCharacteristicCalculator.Asymmetry(qap.Weights)));
+        if (chara == "DistanceAsymmetry")
+          yield return new Result(chara, new DoubleValue(DoubleMatrixCharacteristicCalculator.Asymmetry(qap.Distances)));
+        if (chara == "FlowSparsity")
+          yield return new Result(chara, new DoubleValue(DoubleMatrixCharacteristicCalculator.Sparsity(qap.Weights)));
+        if (chara == "DistanceSparsity")
+          yield return new Result(chara, new DoubleValue(DoubleMatrixCharacteristicCalculator.Sparsity(qap.Distances)));
+        if (chara == "FlowSkewness")
+          yield return new Result(chara, new DoubleValue(DoubleMatrixCharacteristicCalculator.Skewness(qap.Weights)));
+        if (chara == "DistanceSkewness")
+          yield return new Result(chara, new DoubleValue(DoubleMatrixCharacteristicCalculator.Skewness(qap.Distances)));
+        if (chara == "FlowDisparity")
+          yield return new Result(chara, new DoubleValue(DoubleMatrixCharacteristicCalculator.Disparity(qap.Weights)));
+        if (chara == "DistanceDisparity")
+          yield return new Result(chara, new DoubleValue(DoubleMatrixCharacteristicCalculator.Disparity(qap.Distances)));
+      }
+    }
+  }
+}
Index: /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/ProblemCharacteristicAnalysis/QAP/QAPDirectedWalk.cs
===================================================================
--- /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/ProblemCharacteristicAnalysis/QAP/QAPDirectedWalk.cs	(revision 15702)
+++ /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/ProblemCharacteristicAnalysis/QAP/QAPDirectedWalk.cs	(revision 15702)
@@ -0,0 +1,235 @@
+﻿#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.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Encodings.PermutationEncoding;
+using HeuristicLab.Optimization;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Problems.QuadraticAssignment;
+using HeuristicLab.Random;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading;
+
+namespace HeuristicLab.Analysis.FitnessLandscape {
+  [Item("Directed Walk (QAP-specific)", "")]
+  [StorableClass]
+  public class QAPDirectedWalk : CharacteristicCalculator {
+    
+    public IFixedValueParameter<IntValue> PathsParameter {
+      get { return (IFixedValueParameter<IntValue>)Parameters["Paths"]; }
+    }
+
+    public IFixedValueParameter<BoolValue> BestImprovementParameter {
+      get { return (IFixedValueParameter<BoolValue>)Parameters["BestImprovement"]; }
+    }
+
+    public IValueParameter<IntValue> SeedParameter {
+      get { return (IValueParameter<IntValue>)Parameters["Seed"]; }
+    }
+
+    public IFixedValueParameter<BoolValue> LocalOptimaParameter {
+      get { return (IFixedValueParameter<BoolValue>)Parameters["LocalOptima"]; }
+    }
+
+    public int Paths {
+      get { return PathsParameter.Value.Value; }
+      set { PathsParameter.Value.Value = value; }
+    }
+
+    public bool BestImprovement {
+      get { return BestImprovementParameter.Value.Value; }
+      set { BestImprovementParameter.Value.Value = value; }
+    }
+
+    public int? Seed {
+      get { return SeedParameter.Value != null ? SeedParameter.Value.Value : (int?)null; }
+      set { SeedParameter.Value = value.HasValue ? new IntValue(value.Value) : null; }
+    }
+
+    public bool LocalOptima {
+      get { return LocalOptimaParameter.Value.Value; }
+      set { LocalOptimaParameter.Value.Value = value; }
+    }
+
+    [StorableConstructor]
+    private QAPDirectedWalk(bool deserializing) : base(deserializing) { }
+    private QAPDirectedWalk(QAPDirectedWalk original, Cloner cloner) : base(original, cloner) { }
+    public QAPDirectedWalk() {
+      characteristics.AddRange(new[] { "Swap2.Sharpness", "Swap2.Bumpiness", "Swap2.Flatness" }
+        .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)));
+      Parameters.Add(new FixedValueParameter<BoolValue>("BestImprovement", "Whether the best of all alternatives should be chosen for each step in the path or just the first improving (least degrading) move should be made.", new BoolValue(true)));
+      Parameters.Add(new OptionalValueParameter<IntValue>("Seed", "The seed for the random number generator."));
+      Parameters.Add(new FixedValueParameter<BoolValue>("LocalOptima", "Whether to perform walks between local optima.", new BoolValue(false)));
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new QAPDirectedWalk(this, cloner);
+    }
+
+    public override bool CanCalculate() {
+      return Problem is QuadraticAssignmentProblem;
+    }
+
+    public override IEnumerable<IResult> Calculate() {
+      IRandom random = Seed.HasValue ? new MersenneTwister((uint)Seed.Value) : new MersenneTwister();
+      var qap = (QuadraticAssignmentProblem)Problem;
+      List<Permutation> permutations = CalculateRelinkingPoints(random, qap, Paths, LocalOptima);
+
+      var trajectories = Run(random, (QuadraticAssignmentProblem)Problem, permutations, BestImprovement).ToList();
+      var result = PermutationPathAnalysis.GetCharacteristics(trajectories);
+
+      foreach (var chara in characteristics.CheckedItems.Select(x => x.Value.Value)) {
+        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));
+      }
+    }
+
+    public static List<Permutation> CalculateRelinkingPoints(IRandom random, QuadraticAssignmentProblem qap, int pathCount, bool localOptima) {
+      var perm = new Permutation(PermutationTypes.Absolute, qap.Weights.Rows, random);
+      if (localOptima) {
+        var fit = new DoubleValue(QAPEvaluator.Apply(perm, qap.Weights, qap.Distances));
+        QAPExhaustiveSwap2LocalImprovement.ImproveFast(perm, qap.Weights, qap.Distances, fit, new IntValue(0), new IntValue(0), qap.Maximization.Value, int.MaxValue, CancellationToken.None);
+      }
+      var permutations = new List<Permutation> { perm };
+      while (permutations.Count < pathCount + 1) {
+        perm = (Permutation)permutations.Last().Clone();
+        BiasedShuffle(perm, random);
+        if (localOptima) {
+          var fit = new DoubleValue(QAPEvaluator.Apply(perm, qap.Weights, qap.Distances));
+          QAPExhaustiveSwap2LocalImprovement.ImproveFast(perm, qap.Weights, qap.Distances, fit, new IntValue(0), new IntValue(0), qap.Maximization.Value, int.MaxValue, CancellationToken.None);
+        }
+        if (HammingSimilarityCalculator.CalculateSimilarity(permutations.Last(), perm) < 0.75)
+          permutations.Add(perm);
+      }
+
+      return permutations;
+    }
+
+    public static IEnumerable<List<Tuple<Permutation, double>>> Run(IRandom random, QuadraticAssignmentProblem qap, IEnumerable<Permutation> permutations, bool bestImprovement = true) {
+      var iter = permutations.GetEnumerator();
+      if (!iter.MoveNext()) yield break;
+
+      var min = qap.LowerBound.Value;
+      var max = qap.AverageQuality.Value;
+
+      var start = iter.Current;
+      while (iter.MoveNext()) {
+        var end = iter.Current;
+
+        var walk = (bestImprovement ? BestDirectedWalk(qap, start, end) : FirstDirectedWalk(random, qap, start, end)).ToList();
+        yield return walk.Select(x => Tuple.Create(x.Item1, (x.Item2 - min) / (max - min))).ToList();
+        start = end;
+      } // end paths
+    }
+
+    private static IEnumerable<Tuple<Permutation, double>> BestDirectedWalk(QuadraticAssignmentProblem qap, Permutation start, Permutation end) {
+      var N = qap.Weights.Rows;
+      var sol = start;
+      var fitness = QAPEvaluator.Apply(sol, qap.Weights, qap.Distances);
+      yield return Tuple.Create(sol, fitness);
+
+      var invSol = GetInverse(sol);
+      // we require at most N-1 steps to move from one permutation to another
+      for (var step = 0; step < N - 1; step++) {
+        var bestFitness = double.MaxValue;
+        var bestIndex = -1;
+        sol = (Permutation)sol.Clone();
+        for (var index = 0; index < N; index++) {
+          if (sol[index] == end[index]) continue;
+          var fit = QAPSwap2MoveEvaluator.Apply(sol, new Swap2Move(index, invSol[end[index]]), qap.Weights, qap.Distances);
+          if (fit < bestFitness) { // QAP is minimization
+            bestFitness = fit;
+            bestIndex = index;
+          }
+        }
+        if (bestIndex >= 0) {
+          var prev = sol[bestIndex];
+          Swap2Manipulator.Apply(sol, bestIndex, invSol[end[bestIndex]]);
+          fitness += bestFitness;
+          yield return Tuple.Create(sol, fitness);
+          invSol[prev] = invSol[end[bestIndex]];
+          invSol[sol[bestIndex]] = bestIndex;
+        } else break;
+      }
+    }
+
+    private static IEnumerable<Tuple<Permutation, double>> FirstDirectedWalk(IRandom random, QuadraticAssignmentProblem qap, Permutation start, Permutation end) {
+      var N = qap.Weights.Rows;
+      var sol = start;
+      var fitness = QAPEvaluator.Apply(sol, qap.Weights, qap.Distances);
+      yield return Tuple.Create(sol, fitness);
+
+      var invSol = GetInverse(sol);
+      // randomize the order in which improvements are tried
+      var order = Enumerable.Range(0, N).Shuffle(random).ToArray();
+      // we require at most N-1 steps to move from one permutation to another
+      for (var step = 0; step < N - 1; step++) {
+        var bestFitness = double.MaxValue;
+        var bestIndex = -1;
+        sol = (Permutation)sol.Clone();
+        for (var i = 0; i < N; i++) {
+          var index = order[i];
+          if (sol[index] == end[index]) continue;
+          var fit = QAPSwap2MoveEvaluator.Apply(sol, new Swap2Move(index, invSol[end[index]]), qap.Weights, qap.Distances);
+          if (fit < bestFitness) { // QAP is minimization
+            bestFitness = fit;
+            bestIndex = index;
+            if (bestFitness < 0) break;
+          }
+        }
+        if (bestIndex >= 0) {
+          var prev = sol[bestIndex];
+          Swap2Manipulator.Apply(sol, bestIndex, invSol[end[bestIndex]]);
+          fitness += bestFitness;
+          yield return Tuple.Create(sol, fitness);
+          invSol[prev] = invSol[end[bestIndex]];
+          invSol[sol[bestIndex]] = bestIndex;
+        } else break;
+      }
+    }
+
+    private static int[] GetInverse(Permutation p) {
+      var inv = new int[p.Length];
+      for (var i = 0; i < p.Length; i++) {
+        inv[p[i]] = i;
+      }
+      return inv;
+    }
+
+    // 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/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/ProblemInstanceAnalysis/DirectedPath.cs
===================================================================
--- /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/ProblemInstanceAnalysis/DirectedPath.cs	(revision 15702)
+++ /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/ProblemInstanceAnalysis/DirectedPath.cs	(revision 15702)
@@ -0,0 +1,61 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2017 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Analysis.FitnessLandscape {
+  [Item("Directed Path", "")]
+  [StorableClass]
+  public class DirectedPath<T> : Item where T : class, IDeepCloneable {
+    [Storable]
+    private List<List<Tuple<T, double>>> paths;
+    public IEnumerable<List<Tuple<T, double>>> Paths {
+      get { return paths ?? new List<List<Tuple<T, double>>>(); }
+    }
+
+    [StorableConstructor]
+    protected DirectedPath(bool deserializing) : base(deserializing) { }
+    protected DirectedPath(DirectedPath<T> original, Cloner cloner)
+      : base(original, cloner) {
+      if (original.paths != null)
+        paths = original.paths.Select(x => x.Select(y => Tuple.Create(cloner.Clone(y.Item1), y.Item2)).ToList()).ToList();
+    }
+    public DirectedPath() { }
+
+    public bool IsEmpty {
+      get { return paths == null || paths.Count == 0; }
+    }
+
+    public void AddPath(IEnumerable<Tuple<T, double>> path) {
+      if (paths == null) paths = new List<List<Tuple<T, double>>>();
+      paths.Add(path.ToList());
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new DirectedPath<T>(this, cloner);
+    }
+  }
+}
Index: /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/ProblemInstanceAnalysis/PRProblemInstanceAnalyzer.cs
===================================================================
--- /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/ProblemInstanceAnalysis/PRProblemInstanceAnalyzer.cs	(revision 15702)
+++ /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/ProblemInstanceAnalysis/PRProblemInstanceAnalyzer.cs	(revision 15702)
@@ -0,0 +1,49 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2017 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Analysis.FitnessLandscape {
+  [Item("Path-Relinking Problem Instance Analyzer", "Tries to identify the current problem instance being solved by analyzing the output of path-relinking heuristics.")]
+  [StorableClass]
+  public abstract class PrProblemInstanceAnalyzer<T> : ProblemInstanceAnalyzer where T : class, IDeepCloneable {
+
+    [Storable]
+    private ILookupParameter<DirectedPath<T>> pathsParameter;
+    public ILookupParameter<DirectedPath<T>> PathsParameter {
+      get { return pathsParameter; }
+    }
+
+    [StorableConstructor]
+    protected PrProblemInstanceAnalyzer(bool deserializing) : base(deserializing) { }
+    protected PrProblemInstanceAnalyzer(PrProblemInstanceAnalyzer<T> original, Cloner cloner)
+      : base(original, cloner) {
+      pathsParameter = cloner.Clone(original.pathsParameter);
+    }
+    public PrProblemInstanceAnalyzer() {
+      Parameters.Add(pathsParameter = new LookupParameter<DirectedPath<T>>("RelinkedPaths", ""));
+    }
+  }
+}
Index: /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/ProblemInstanceAnalysis/ProblemInstanceAnalyzer.cs
===================================================================
--- /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/ProblemInstanceAnalysis/ProblemInstanceAnalyzer.cs	(revision 15702)
+++ /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/ProblemInstanceAnalysis/ProblemInstanceAnalyzer.cs	(revision 15702)
@@ -0,0 +1,110 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2017 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.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Operators;
+using HeuristicLab.Optimization;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Analysis.FitnessLandscape {
+  [Item("Problem Instance Similarity Analyzer", "Base class for analyzing whether certain obtained characteristics match the characteristics of already known problem instances.")]
+  [StorableClass]
+  public abstract class ProblemInstanceAnalyzer : SingleSuccessorOperator, IAnalyzer {
+
+    public bool EnabledByDefault {
+      get { return false; }
+    }
+
+    [Storable]
+    private IResultParameter<StringMatrix> similarInstParam;
+    public IResultParameter<StringMatrix> SimilarInstancesParameter {
+      get { return similarInstParam; }
+    }
+
+    [Storable]
+    private IValueParameter<DoubleMatrix> characteristicsParam;
+    public IValueParameter<DoubleMatrix> CharacteristicsParameter {
+      get { return characteristicsParam; }
+    }
+
+    public DoubleMatrix Characteristics {
+      get { return CharacteristicsParameter.Value; }
+      set { CharacteristicsParameter.Value = value; }
+    }
+
+    [StorableConstructor]
+    protected ProblemInstanceAnalyzer(bool deserializing) : base(deserializing) { }
+
+    protected ProblemInstanceAnalyzer(ProblemInstanceAnalyzer original, Cloner cloner)
+      : base(original, cloner) {
+      similarInstParam = cloner.Clone(original.similarInstParam);
+      characteristicsParam = cloner.Clone(original.characteristicsParam);
+    }
+
+    public ProblemInstanceAnalyzer() {
+      Parameters.Add(similarInstParam = new ResultParameter<StringMatrix>("Similar Instances", "Ordered enumeration of similar problem instances to the one currently observed.", "Results", new StringMatrix(new [,] { { "undefined", double.NaN.ToString(CultureInfo.CurrentCulture.NumberFormat) } })));
+      Parameters.Add(characteristicsParam = new ValueParameter<DoubleMatrix>("Characteristics", "The matrix that contains the characteristics data and corresponding problem instance as row name."));
+    }
+
+    public override IOperation Apply() {
+      var kbCharacteristics = Characteristics;
+      if (kbCharacteristics == null) throw new InvalidOperationException("No characteristics are given.");
+
+      var currentCharacteristics = GetCharacteristics();
+      if (currentCharacteristics == null) return base.Apply();
+
+      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 - 2)
+        instances.Add(instances.Count.ToString(CultureInfo.CurrentCulture.NumberFormat));
+
+      var result = new StringMatrix(instances.Count, 2);
+      var idx = 0;
+      foreach (var o in order) {
+        result[idx, 0] = instances[o.Row];
+        result[idx, 1] = o.MSE.ToString(CultureInfo.CurrentCulture.NumberFormat);
+        idx++;
+      }
+
+      similarInstParam.ActualValue = result;
+
+      return base.Apply();
+    }
+
+    protected abstract DoubleArray GetCharacteristics();
+  }
+}
Index: /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/ProblemInstanceAnalysis/QAPPRProblemInstanceAnalyzer.cs
===================================================================
--- /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/ProblemInstanceAnalysis/QAPPRProblemInstanceAnalyzer.cs	(revision 15702)
+++ /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/ProblemInstanceAnalysis/QAPPRProblemInstanceAnalyzer.cs	(revision 15702)
@@ -0,0 +1,54 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2017 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 HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Encodings.PermutationEncoding;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Analysis.FitnessLandscape {
+  [Item("QAP Path-Relinking Problem Instance Analyzer", "")]
+  [StorableClass]
+  public sealed class QAPPRProblemInstanceAnalyzer : PrProblemInstanceAnalyzer<Permutation> {
+
+    [StorableConstructor]
+    private QAPPRProblemInstanceAnalyzer(bool deserializing) : base(deserializing) { }
+    private QAPPRProblemInstanceAnalyzer(QAPPRProblemInstanceAnalyzer original, Cloner cloner) : base(original, cloner) { }
+    public QAPPRProblemInstanceAnalyzer() { }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new QAPPRProblemInstanceAnalyzer(this, cloner);
+    }
+
+    protected override DoubleArray GetCharacteristics() {
+      var paths = PathsParameter.ActualValue;
+      if (paths == null || paths.IsEmpty) return null;
+      var trajectories = paths.Paths.ToList();
+      var length = trajectories[0].First().Item1.Length;
+      trajectories = paths.Paths.Where(x => x.Count > 0.75 * length).ToList();
+      if (trajectories.Count == 0) return null;
+
+      return new DoubleArray(PermutationPathAnalysis.GetCharacteristics(trajectories).GetValues().ToArray());
+    }
+  }
+}
Index: /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/Properties/AssemblyInfo.cs.frame
===================================================================
--- /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/Properties/AssemblyInfo.cs.frame	(revision 15702)
+++ /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/Properties/AssemblyInfo.cs.frame	(revision 15702)
@@ -0,0 +1,58 @@
+﻿#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.Analysis.FitnessLandscape")]
+[assembly: AssemblyDescription("HeuristicLab algorithm analysis for fitness landscape properties")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("HeuristicLab")]
+[assembly: AssemblyCopyright("(c) 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("34e1ec7e-0124-4f76-b8f8-42b9244d2b09")]
+
+// 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/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/UpDownSelector.cs
===================================================================
--- /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/UpDownSelector.cs	(revision 15702)
+++ /branches/1614_GeneralizedQAP/HeuristicLab.Analysis.FitnessLandscape/3.3/UpDownSelector.cs	(revision 15702)
@@ -0,0 +1,115 @@
+﻿#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.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Operators;
+using HeuristicLab.Optimization;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace HeuristicLab.Analysis.FitnessLandscape {
+  [Item("Up/DownSelector", "A selection operator that moves towards the next local optimum, when found reverses direction and so on.")]
+  [StorableClass]
+  public class UpDownSelector : InstrumentedOperator, IStochasticOperator {
+
+    #region Parameters
+    public ILookupParameter<BoolValue> MaximizationParameter {
+      get { return (ILookupParameter<BoolValue>)Parameters["Maximization"]; }
+    }
+    public ILookupParameter<BoolValue> MoveTowardsOptimumParameter {
+      get { return (ILookupParameter<BoolValue>)Parameters["MoveTowardsOptimum"]; }
+    }
+    public ILookupParameter<DoubleValue> BaseQualityParameter {
+      get { return (ILookupParameter<DoubleValue>)Parameters["BaseQuality"]; }
+    }
+    public IScopeTreeLookupParameter<DoubleValue> QualityParameter {
+      get { return (IScopeTreeLookupParameter<DoubleValue>)Parameters["Quality"]; }
+    }
+    public ILookupParameter<IRandom> RandomParameter {
+      get { return (ILookupParameter<IRandom>)Parameters["Random"]; }
+    }
+    #endregion
+
+    #region Construction & Cloning
+
+    [StorableConstructor]
+    protected UpDownSelector(bool deserializing) : base(deserializing) { }
+    protected UpDownSelector(UpDownSelector original, Cloner cloner) : base(original, cloner) { }
+    public UpDownSelector() {
+      Parameters.Add(new LookupParameter<BoolValue>("Maximization", "Whether the problem is a maximization or minimization problem."));
+      Parameters.Add(new LookupParameter<BoolValue>("MoveTowardsOptimum", "Specifies whether the selector should optimize towards or away from the optimum."));
+      Parameters.Add(new LookupParameter<DoubleValue>("BaseQuality", "The base quality value to compare to. This is required to determine wheter a local optimum has been found and the direction should be reversed."));
+      Parameters.Add(new ScopeTreeLookupParameter<DoubleValue>("Quality", "The qualities of the solutions."));
+      Parameters.Add(new LookupParameter<IRandom>("Random", "Random number generator"));
+      BaseQualityParameter.ActualName = "Quality";
+    }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new UpDownSelector(this, cloner);
+    }
+    #endregion
+
+    public override IOperation InstrumentedApply() {
+      var scopes = ExecutionContext.Scope.SubScopes.ToList();
+      var selected = Select(scopes);
+      scopes.Remove(selected);
+      ExecutionContext.Scope.SubScopes.Clear();
+      ExecutionContext.Scope.SubScopes.Add(new Scope("Remaining"));
+      ExecutionContext.Scope.SubScopes[0].SubScopes.AddRange(scopes);
+      ExecutionContext.Scope.SubScopes.Add(new Scope("Selected"));
+      ExecutionContext.Scope.SubScopes[1].SubScopes.Add(selected);
+      return base.InstrumentedApply();
+    }
+
+    private IScope Select(List<IScope> scopes) {
+      var maximization = MaximizationParameter.ActualValue.Value;
+      bool optimize = true;
+      if (MoveTowardsOptimumParameter.ActualValue == null) {
+        MoveTowardsOptimumParameter.ActualValue = new BoolValue(true);
+      } else {
+        optimize = MoveTowardsOptimumParameter.ActualValue.Value;
+      }
+      var qualities = QualityParameter.ActualValue;
+      var list = qualities.Select((x, i) => new { Index = i, Quality = x.Value }).ToList();
+      var baseQuality = BaseQualityParameter.ActualValue.Value;
+      if (double.IsNaN(baseQuality)) {
+        baseQuality = maximization ? list.Max(x => x.Quality) : list.Min(x => x.Quality);
+      }
+      var random = RandomParameter.ActualValue;
+
+      if (random != null)
+        list.Shuffle(random);
+      if (maximization && optimize || !maximization && !optimize) {
+        list = list.OrderByDescending(x => x.Quality).ToList();
+        if (list.Count > 0 && list[0].Quality <= baseQuality)
+          MoveTowardsOptimumParameter.ActualValue = new BoolValue(!optimize);
+      } else {
+        list = list.OrderBy(x => x.Quality).ToList();
+        if (list.Count > 0 && list[0].Quality >= baseQuality)
+          MoveTowardsOptimumParameter.ActualValue = new BoolValue(!optimize);
+      }
+      return scopes[list[0].Index];
+    }
+  }
+}
