Index: branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/Binary/BinaryMemPR.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/Binary/BinaryMemPR.cs	(revision 14562)
+++ branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/Binary/BinaryMemPR.cs	(revision 14563)
@@ -45,5 +45,10 @@
       foreach (var trainer in ApplicationManager.Manager.GetInstances<ISolutionModelTrainer<BinaryMemPRPopulationContext>>())
         SolutionModelTrainerParameter.ValidValues.Add(trainer);
-      
+
+      if (SolutionModelTrainerParameter.ValidValues.Count > 0) {
+        var unbiased = SolutionModelTrainerParameter.ValidValues.FirstOrDefault(x => !x.Bias);
+        if (unbiased != null) SolutionModelTrainerParameter.Value = unbiased;
+      }
+
       foreach (var localSearch in ApplicationManager.Manager.GetInstances<ILocalSearch<BinaryMemPRSolutionContext>>()) {
         LocalSearchParameter.ValidValues.Add(localSearch);
@@ -156,9 +161,10 @@
       cache.Add(p2.Solution);
 
-      var cacheHits = 0;
+      var cacheHits = new Dictionary<int, int>() { { 0, 0 }, { 1, 0 }, { 2, 0 } };
       ISingleObjectiveSolutionScope<BinaryVector> offspring = null;
+      
       while (evaluations < N) {
         BinaryVector c = null;
-        var xochoice = Context.Random.Next(3);
+        var xochoice = cacheHits.SampleRandom(Context.Random).Key;
         switch (xochoice) {
           case 0: c = NPointCrossover.Apply(Context.Random, p1.Solution, p2.Solution, new IntValue(1)); break;
@@ -167,6 +173,9 @@
         }
         if (cache.Contains(c)) {
-          cacheHits++;
-          if (cacheHits > 50) break;
+          cacheHits[xochoice]++;
+          if (cacheHits[xochoice] > 10) {
+            cacheHits.Remove(xochoice);
+            if (cacheHits.Count == 0) break;
+          }
           continue;
         }
Index: branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/Binary/SolutionModel/Univariate/BiasedModelTrainer.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/Binary/SolutionModel/Univariate/BiasedModelTrainer.cs	(revision 14562)
+++ branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/Binary/SolutionModel/Univariate/BiasedModelTrainer.cs	(revision 14563)
@@ -36,4 +36,6 @@
     where TContext : IPopulationBasedHeuristicAlgorithmContext<ISingleObjectiveHeuristicOptimizationProblem, BinaryVector>, ISolutionModelContext<BinaryVector> {
     
+    public bool Bias { get { return true; } }
+
     [Storable]
     private IValueParameter<EnumValue<ModelBiasOptions>> modelBiasParameter;
Index: branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/Binary/SolutionModel/Univariate/UnbiasedModelTrainer.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/Binary/SolutionModel/Univariate/UnbiasedModelTrainer.cs	(revision 14562)
+++ branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/Binary/SolutionModel/Univariate/UnbiasedModelTrainer.cs	(revision 14563)
@@ -33,5 +33,7 @@
   public class UniasedModelTrainer<TContext> : NamedItem, ISolutionModelTrainer<TContext>
     where TContext : IPopulationBasedHeuristicAlgorithmContext<ISingleObjectiveHeuristicOptimizationProblem, BinaryVector>, ISolutionModelContext<BinaryVector> {
-    
+
+    public bool Bias { get { return false; } }
+
     [StorableConstructor]
     protected UniasedModelTrainer(bool deserializing) : base(deserializing) { }
Index: branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/Interfaces/Interfaces.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/Interfaces/Interfaces.cs	(revision 14562)
+++ branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/Interfaces/Interfaces.cs	(revision 14563)
@@ -50,4 +50,5 @@
    
   public interface ISolutionModelTrainer<TContext> : IItem {
+    bool Bias { get; }
     void TrainModel(TContext context);
   }
Index: branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/LinearLinkage/LinearLinkageMemPR.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/LinearLinkage/LinearLinkageMemPR.cs	(revision 14562)
+++ branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/LinearLinkage/LinearLinkageMemPR.cs	(revision 14563)
@@ -32,4 +32,5 @@
 using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
 using HeuristicLab.PluginInfrastructure;
+using HeuristicLab.Random;
 
 namespace HeuristicLab.Algorithms.MemPR.Grouping {
@@ -44,5 +45,10 @@
       foreach (var trainer in ApplicationManager.Manager.GetInstances<ISolutionModelTrainer<LinearLinkageMemPRPopulationContext>>())
         SolutionModelTrainerParameter.ValidValues.Add(trainer);
-      
+
+      if (SolutionModelTrainerParameter.ValidValues.Count > 0) {
+        var unbiased = SolutionModelTrainerParameter.ValidValues.FirstOrDefault(x => !x.Bias);
+        if (unbiased != null) SolutionModelTrainerParameter.Value = unbiased;
+      }
+
       foreach (var localSearch in ApplicationManager.Manager.GetInstances<ILocalSearch<LinearLinkageMemPRSolutionContext>>()) {
         LocalSearchParameter.ValidValues.Add(localSearch);
@@ -245,5 +251,5 @@
       cache.Add(p2.Solution);
 
-      var cachehits = 0;
+      var cacheHits = new Dictionary<int, int>() { { 0, 0 }, { 1, 0 } };
       var evaluations = 0;
       var probe = Context.ToScope((LinearLinkage)p1.Solution.Clone());
@@ -251,11 +257,15 @@
       while (evaluations < p1.Solution.Length) {
         LinearLinkage c = null;
-        if (Context.Random.NextDouble() < 0.8)
-          c = GroupCrossover.Apply(Context.Random, p1.Solution, p2.Solution);
-        else c = SinglePointCrossover.Apply(Context.Random, p1.Solution, p2.Solution);
-        
+        var xochoice = cacheHits.SampleRandom(Context.Random).Key;
+        switch (xochoice) {
+          case 0: c = GroupCrossover.Apply(Context.Random, p1.Solution, p2.Solution); break;
+          case 1: c = SinglePointCrossover.Apply(Context.Random, p1.Solution, p2.Solution); break;
+        }
         if (cache.Contains(c)) {
-          cachehits++;
-          if (cachehits > 10) break;
+          cacheHits[xochoice]++;
+          if (cacheHits[xochoice] > 10) {
+            cacheHits.Remove(xochoice);
+            if (cacheHits.Count == 0) break;
+          }
           continue;
         }
Index: branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/LinearLinkage/SolutionModel/Univariate/UnbiasedModelTrainer.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/LinearLinkage/SolutionModel/Univariate/UnbiasedModelTrainer.cs	(revision 14562)
+++ branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/LinearLinkage/SolutionModel/Univariate/UnbiasedModelTrainer.cs	(revision 14563)
@@ -33,5 +33,7 @@
   public class UniasedModelTrainer<TContext> : NamedItem, ISolutionModelTrainer<TContext>
     where TContext : IPopulationBasedHeuristicAlgorithmContext<ISingleObjectiveHeuristicOptimizationProblem, LinearLinkage>, ISolutionModelContext<LinearLinkage> {
-    
+
+    public bool Bias { get { return false; } }
+
     [StorableConstructor]
     protected UniasedModelTrainer(bool deserializing) : base(deserializing) { }
Index: branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/MemPRAlgorithm.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/MemPRAlgorithm.cs	(revision 14562)
+++ branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/MemPRAlgorithm.cs	(revision 14563)
@@ -138,4 +138,8 @@
     [Storable]
     private BestAverageWorstQualityAnalyzer qualityAnalyzer;
+    [Storable]
+    private QualityPerClockAnalyzer qualityPerClockAnalyzer;
+    [Storable]
+    private QualityPerEvaluationsAnalyzer qualityPerEvaluationsAnalyzer;
 
     [StorableConstructor]
@@ -144,4 +148,7 @@
       context = cloner.Clone(original.context);
       qualityAnalyzer = cloner.Clone(original.qualityAnalyzer);
+      qualityPerClockAnalyzer = cloner.Clone(original.qualityPerClockAnalyzer);
+      qualityPerEvaluationsAnalyzer = cloner.Clone(original.qualityPerEvaluationsAnalyzer);
+
       RegisterEventHandlers();
     }
@@ -150,5 +157,5 @@
       Parameters.Add(new FixedValueParameter<IntValue>("MaximumPopulationSize", "The maximum size of the population that is evolved.", new IntValue(20)));
       Parameters.Add(new OptionalValueParameter<IntValue>("MaximumEvaluations", "The maximum number of solution evaluations."));
-      Parameters.Add(new OptionalValueParameter<TimeSpanValue>("MaximumExecutionTime", "The maximum runtime.", new TimeSpanValue(TimeSpan.FromMinutes(1))));
+      Parameters.Add(new OptionalValueParameter<TimeSpanValue>("MaximumExecutionTime", "The maximum runtime.", new TimeSpanValue(TimeSpan.FromMinutes(10))));
       Parameters.Add(new OptionalValueParameter<DoubleValue>("TargetQuality", "The target quality at which the algorithm terminates."));
       Parameters.Add(new FixedValueParameter<BoolValue>("SetSeedRandomly", "Whether each run of the algorithm should be conducted with a new random seed.", new BoolValue(true)));
@@ -158,4 +165,7 @@
 
       qualityAnalyzer = new BestAverageWorstQualityAnalyzer();
+      qualityPerClockAnalyzer = new QualityPerClockAnalyzer();
+      qualityPerEvaluationsAnalyzer = new QualityPerEvaluationsAnalyzer();
+
       RegisterEventHandlers();
     }
@@ -193,8 +203,10 @@
             foreach (var param in analyzer.Parameters.OfType<IScopeTreeLookupParameter>())
               param.Depth = 1;
-            multiAnalyzer.Operators.Add(analyzer, analyzer.EnabledByDefault);
+            multiAnalyzer.Operators.Add(analyzer, analyzer.EnabledByDefault || analyzer is ISimilarityBasedOperator);
           }
         }
         multiAnalyzer.Operators.Add(qualityAnalyzer, qualityAnalyzer.EnabledByDefault);
+        multiAnalyzer.Operators.Add(qualityPerClockAnalyzer, true);
+        multiAnalyzer.Operators.Add(qualityPerEvaluationsAnalyzer, true);
       }
     }
@@ -300,9 +312,9 @@
 
       if (!replaced) {
-        offspring = (ISingleObjectiveSolutionScope<TSolution>)Context.Population.SampleRandom(Context.Random).Clone();
-        var before = offspring.Fitness;
+        var before = Context.Population.SampleRandom(Context.Random);
+        offspring = (ISingleObjectiveSolutionScope<TSolution>)before.Clone();
         AdaptiveWalk(offspring, Context.LocalSearchEvaluations * 2, token);
-        Context.AdaptivewalkingStat.Add(Tuple.Create(before, offspring.Fitness));
-        if (Context.AdaptivewalkingStat.Count % 10 == 0) Context.RelearnAdaptiveWalkPerformanceModel();
+        if (!Eq(before, offspring))
+          Context.AddAdaptivewalkingResult(before, offspring);
         if (Replace(offspring, token)) {
           Context.ByAdaptivewalking++;
@@ -345,6 +357,7 @@
 
       var sp = new ScatterPlot("Breeding Correlation", "");
-      sp.Rows.Add(new ScatterPlotDataRow("Parent1 vs Offspring", "", Context.BreedingStat.Select(x => new Point2D<double>(x.Item1, x.Item3))) { VisualProperties = { PointSize = 6 }});
-      sp.Rows.Add(new ScatterPlotDataRow("Parent2 vs Offspring", "", Context.BreedingStat.Select(x => new Point2D<double>(x.Item2, x.Item3))) { VisualProperties = { PointSize = 6 } });
+      sp.Rows.Add(new ScatterPlotDataRow("Parent1 vs Offspring", "", Context.BreedingStat.Select(x => new Point2D<double>(x.Item1, x.Item4))) { VisualProperties = { PointSize = 6 }});
+      sp.Rows.Add(new ScatterPlotDataRow("Parent2 vs Offspring", "", Context.BreedingStat.Select(x => new Point2D<double>(x.Item2, x.Item4))) { VisualProperties = { PointSize = 6 } });
+      sp.Rows.Add(new ScatterPlotDataRow("Parent Distance vs Offspring", "", Context.BreedingStat.Select(x => new Point2D<double>(x.Item3, x.Item4))) { VisualProperties = { PointSize = 6 } });
       if (!Results.TryGetValue("BreedingStat", out res)) {
         Results.Add(new Result("BreedingStat", sp));
@@ -352,6 +365,7 @@
 
       sp = new ScatterPlot("Relinking Correlation", "");
-      sp.Rows.Add(new ScatterPlotDataRow("A vs Relink", "", Context.RelinkingStat.Select(x => new Point2D<double>(x.Item1, x.Item3))) { VisualProperties = { PointSize = 6 } });
-      sp.Rows.Add(new ScatterPlotDataRow("B vs Relink", "", Context.RelinkingStat.Select(x => new Point2D<double>(x.Item2, x.Item3))) { VisualProperties = { PointSize = 6 } });
+      sp.Rows.Add(new ScatterPlotDataRow("A vs Relink", "", Context.RelinkingStat.Select(x => new Point2D<double>(x.Item1, x.Item4))) { VisualProperties = { PointSize = 6 } });
+      sp.Rows.Add(new ScatterPlotDataRow("B vs Relink", "", Context.RelinkingStat.Select(x => new Point2D<double>(x.Item2, x.Item4))) { VisualProperties = { PointSize = 6 } });
+      sp.Rows.Add(new ScatterPlotDataRow("d(A,B) vs Offspring", "", Context.RelinkingStat.Select(x => new Point2D<double>(x.Item3, x.Item4))) { VisualProperties = { PointSize = 6 } });
       if (!Results.TryGetValue("RelinkingStat", out res)) {
         Results.Add(new Result("RelinkingStat", sp));
@@ -359,6 +373,7 @@
 
       sp = new ScatterPlot("Delinking Correlation", "");
-      sp.Rows.Add(new ScatterPlotDataRow("A vs Delink", "", Context.DelinkingStat.Select(x => new Point2D<double>(x.Item1, x.Item3))) { VisualProperties = { PointSize = 6 } });
-      sp.Rows.Add(new ScatterPlotDataRow("B vs Delink", "", Context.DelinkingStat.Select(x => new Point2D<double>(x.Item2, x.Item3))) { VisualProperties = { PointSize = 6 } });
+      sp.Rows.Add(new ScatterPlotDataRow("A vs Delink", "", Context.DelinkingStat.Select(x => new Point2D<double>(x.Item1, x.Item4))) { VisualProperties = { PointSize = 6 } });
+      sp.Rows.Add(new ScatterPlotDataRow("B vs Delink", "", Context.DelinkingStat.Select(x => new Point2D<double>(x.Item2, x.Item4))) { VisualProperties = { PointSize = 6 } });
+      sp.Rows.Add(new ScatterPlotDataRow("d(A,B) vs Offspring", "", Context.DelinkingStat.Select(x => new Point2D<double>(x.Item3, x.Item4))) { VisualProperties = { PointSize = 6 } });
       if (!Results.TryGetValue("DelinkingStat", out res)) {
         Results.Add(new Result("DelinkingStat", sp));
@@ -372,5 +387,5 @@
 
       sp = new ScatterPlot("Hillclimbing Correlation", "");
-      sp.Rows.Add(new ScatterPlotDataRow("Start vs End", "", Context.HillclimbingStat.Select(x => new Point2D<double>(x.Item1, x.Item2))) { VisualProperties = { PointSize = 6 } });
+      sp.Rows.Add(new ScatterPlotDataRow("Start vs Improvement", "", Context.HillclimbingStat.Select(x => new Point2D<double>(x.Item1, x.Item2))) { VisualProperties = { PointSize = 6 } });
       if (!Results.TryGetValue("HillclimbingStat", out res)) {
         Results.Add(new Result("HillclimbingStat", sp));
@@ -535,10 +550,8 @@
         Context.IncrementEvaluatedSolutions(1);
       }
-      var before = scope.Fitness;
+      var before = (ISingleObjectiveSolutionScope<TSolution>)scope.Clone();
       var lscontext = Context.CreateSingleSolutionContext(scope);
       LocalSearchParameter.Value.Optimize(lscontext);
-      var after = scope.Fitness;
-      Context.HillclimbingStat.Add(Tuple.Create(before, after));
-      if (Context.HillclimbingStat.Count % 10 == 0) Context.RelearnHillclimbingPerformanceModel();
+      Context.AddHillclimbingResult(before, scope);
       Context.IncrementEvaluatedSolutions(lscontext.EvaluatedSolutions);
       return lscontext.EvaluatedSolutions;
@@ -550,11 +563,12 @@
         Context.IncrementEvaluatedSolutions(1);
       }
-      var before = scope.Fitness;
       var newScope = (ISingleObjectiveSolutionScope<TSolution>)scope.Clone();
       AdaptiveWalk(newScope, maxEvals, token, subspace);
-      Context.AdaptivewalkingStat.Add(Tuple.Create(before, newScope.Fitness));
-      if (Context.AdaptivewalkingStat.Count % 10 == 0) Context.RelearnAdaptiveWalkPerformanceModel();
-      if (Context.IsBetter(newScope, scope))
+      
+      if (Context.IsBetter(newScope, scope)) {
+        Context.AddAdaptivewalkingResult(scope, newScope);
         scope.Adopt(newScope);
+      } else if (!Eq(newScope, scope))
+        Context.AddAdaptivewalkingResult(scope, newScope);
     }
     protected abstract void AdaptiveWalk(ISingleObjectiveSolutionScope<TSolution> scope, int maxEvals, CancellationToken token, ISolutionSubspace<TSolution> subspace = null);
@@ -580,23 +594,22 @@
       }
 
-      if (Context.BreedingSuited(p1, p2)) {
-        var offspring = Breed(p1, p2, token);
-
-        if (double.IsNaN(offspring.Fitness)) {
-          Context.Evaluate(offspring, token);
-          Context.IncrementEvaluatedSolutions(1);
-        }
-
-        // new best solutions are improved using hill climbing in full solution space
-        if (Context.Population.All(p => Context.IsBetter(offspring, p)))
-          HillClimb(offspring, token);
-        else if (!Eq(offspring, p1) && !Eq(offspring, p2) && Context.HillclimbingSuited(offspring.Fitness))
-          HillClimb(offspring, token, CalculateSubspace(new[] { p1.Solution, p2.Solution }, inverse: false));
-
-        Context.AddBreedingResult(p1, p2, offspring);
-        if (Context.BreedingStat.Count % 10 == 0) Context.RelearnBreedingPerformanceModel();
-        return offspring;
-      }
-      return null;
+      if (!Context.BreedingSuited(p1, p2, Dist(p1, p2))) return null;
+
+      var offspring = Breed(p1, p2, token);
+
+      if (double.IsNaN(offspring.Fitness)) {
+        Context.Evaluate(offspring, token);
+        Context.IncrementEvaluatedSolutions(1);
+      }
+
+      Context.AddBreedingResult(p1, p2, Dist(p1, p2), offspring);
+
+      // new best solutions are improved using hill climbing in full solution space
+      if (Context.Population.All(p => Context.IsBetter(offspring, p)))
+        HillClimb(offspring, token);
+      else if (!Eq(offspring, p1) && !Eq(offspring, p2) && Context.HillclimbingSuited(offspring.Fitness))
+        HillClimb(offspring, token, CalculateSubspace(new[] { p1.Solution, p2.Solution }, inverse: false));
+
+      return offspring;
     }
 
@@ -613,11 +626,8 @@
       var p2 = Context.AtPopulation(i2);
 
-      if (!Context.RelinkSuited(p1, p2)) return null;
+      if (!Context.RelinkSuited(p1, p2, Dist(p1, p2))) return null;
 
       var link = PerformRelinking(p1, p2, token, delink: false);
-      if (double.IsNaN(link.Fitness)) {
-        Context.Evaluate(link, token);
-        Context.IncrementEvaluatedSolutions(1);
-      }
+
       // new best solutions are improved using hill climbing in full solution space
       if (Context.Population.All(p => Context.IsBetter(link, p)))
@@ -637,15 +647,12 @@
       var p2 = Context.AtPopulation(i2);
       
-      if (!Context.DelinkSuited(p1, p2)) return null;
+      if (!Context.DelinkSuited(p1, p2, Dist(p1, p2))) return null;
 
       var link = PerformRelinking(p1, p2, token, delink: true);
-      if (double.IsNaN(link.Fitness)) {
-        Context.Evaluate(link, token);
-        Context.IncrementEvaluatedSolutions(1);
-      }
+
       // new best solutions are improved using hill climbing in full solution space
       if (Context.Population.All(p => Context.IsBetter(link, p)))
         HillClimb(link, token);
-      // intentionally not making hill climbing after delinking in sub-space
+      // intentionally not making hill climbing otherwise after delinking in sub-space
       return link;
     }
@@ -659,15 +666,10 @@
       }
 
-      // new best solutions are improved using hill climbing
-      if (Context.Population.All(p => Context.IsBetter(relink, p)))
-        HillClimb(relink, token);
-
       if (delink) {
-        Context.AddDelinkingResult(a, b, relink);
-        if (Context.DelinkingStat.Count % 10 == 0) Context.RelearnDelinkingPerformanceModel();
+        Context.AddDelinkingResult(a, b, Dist(a, b), relink);
       } else {
-        Context.AddRelinkingResult(a, b, relink);
-        if (context.RelinkingStat.Count % 10 == 0) Context.RelearnRelinkingPerformanceModel();
-      }
+        Context.AddRelinkingResult(a, b, Dist(a, b), relink);
+      }
+
       return relink;
     }
@@ -682,4 +684,7 @@
         ISingleObjectiveSolutionScope<TSolution> bestSample = null;
         var tries = 1;
+        var avgDist = (from a in Context.Population.Shuffle(Context.Random)
+                       from b in Context.Population.Shuffle(Context.Random)
+                       select Dist(a, b)).Average();
         for (; tries < 100; tries++) {
           var sample = Context.ToScope(Context.Model.Sample());
@@ -689,9 +694,8 @@
             if (Context.Population.Any(x => !Context.IsBetter(x, bestSample))) break;
           }
-          if (!Context.SamplingSuited()) break;
+          if (!Context.SamplingSuited(avgDist)) break;
         }
         Context.IncrementEvaluatedSolutions(tries);
-        Context.AddSamplingResult(bestSample);
-        if (Context.SamplingStat.Count % 10 == 0) Context.RelearnSamplingPerformanceModel();
+        Context.AddSamplingResult(bestSample, avgDist);
         return bestSample;
       }
Index: branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/MemPRContext.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/MemPRContext.cs	(revision 14562)
+++ branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/MemPRContext.cs	(revision 14563)
@@ -197,6 +197,6 @@
     }
     [Storable]
-    private List<Tuple<double, double, double>> breedingStat;
-    public List<Tuple<double, double, double>> BreedingStat {
+    private List<Tuple<double, double, double, double>> breedingStat;
+    public IEnumerable<Tuple<double, double, double, double>> BreedingStat {
       get { return breedingStat; }
     }
@@ -207,6 +207,6 @@
     }
     [Storable]
-    private List<Tuple<double, double, double>> relinkingStat;
-    public List<Tuple<double, double, double>> RelinkingStat {
+    private List<Tuple<double, double, double, double>> relinkingStat;
+    public IEnumerable<Tuple<double, double, double, double>> RelinkingStat {
       get { return relinkingStat; }
     }
@@ -217,6 +217,6 @@
     }
     [Storable]
-    private List<Tuple<double, double, double>> delinkingStat;
-    public List<Tuple<double, double, double>> DelinkingStat {
+    private List<Tuple<double, double, double, double>> delinkingStat;
+    public IEnumerable<Tuple<double, double, double, double>> DelinkingStat {
       get { return delinkingStat; }
     }
@@ -228,5 +228,5 @@
     [Storable]
     private List<Tuple<double, double>> samplingStat;
-    public List<Tuple<double, double>> SamplingStat {
+    public IEnumerable<Tuple<double, double>> SamplingStat {
       get { return samplingStat; }
     }
@@ -238,5 +238,5 @@
     [Storable]
     private List<Tuple<double, double>> hillclimbingStat;
-    public List<Tuple<double, double>> HillclimbingStat {
+    public IEnumerable<Tuple<double, double>> HillclimbingStat {
       get { return hillclimbingStat; }
     }
@@ -248,5 +248,5 @@
     [Storable]
     private List<Tuple<double, double>> adaptivewalkingStat;
-    public List<Tuple<double, double>> AdaptivewalkingStat {
+    public IEnumerable<Tuple<double, double>> AdaptivewalkingStat {
       get { return adaptivewalkingStat; }
     }
@@ -276,9 +276,9 @@
       random = cloner.Clone(original.random);
       breedingPerformanceModel = cloner.Clone(original.breedingPerformanceModel);
-      breedingStat = original.breedingStat.Select(x => Tuple.Create(x.Item1, x.Item2, x.Item3)).ToList();
+      breedingStat = original.breedingStat.Select(x => Tuple.Create(x.Item1, x.Item2, x.Item3, x.Item4)).ToList();
       relinkingPerformanceModel = cloner.Clone(original.relinkingPerformanceModel);
-      relinkingStat = original.relinkingStat.Select(x => Tuple.Create(x.Item1, x.Item2, x.Item3)).ToList();
+      relinkingStat = original.relinkingStat.Select(x => Tuple.Create(x.Item1, x.Item2, x.Item3, x.Item4)).ToList();
       delinkingPerformanceModel = cloner.Clone(original.delinkingPerformanceModel);
-      delinkingStat = original.delinkingStat.Select(x => Tuple.Create(x.Item1, x.Item2, x.Item3)).ToList();
+      delinkingStat = original.delinkingStat.Select(x => Tuple.Create(x.Item1, x.Item2, x.Item3, x.Item4)).ToList();
       samplingPerformanceModel = cloner.Clone(original.samplingPerformanceModel);
       samplingStat = original.samplingStat.Select(x => Tuple.Create(x.Item1, x.Item2)).ToList();
@@ -310,7 +310,7 @@
       Parameters.Add(random = new ValueParameter<IRandom>("Random", new MersenneTwister()));
 
-      breedingStat = new List<Tuple<double, double, double>>();
-      relinkingStat = new List<Tuple<double, double, double>>();
-      delinkingStat = new List<Tuple<double, double, double>>();
+      breedingStat = new List<Tuple<double, double, double, double>>();
+      relinkingStat = new List<Tuple<double, double, double, double>>();
+      delinkingStat = new List<Tuple<double, double, double, double>>();
       samplingStat = new List<Tuple<double, double>>();
       hillclimbingStat = new List<Tuple<double, double>>();
@@ -344,7 +344,7 @@
 
     public void RelearnBreedingPerformanceModel() {
-      breedingPerformanceModel = RunRegression(PrepareRegression(BreedingStat), breedingPerformanceModel).Model;
-    }
-    public bool BreedingSuited(ISingleObjectiveSolutionScope<TSolution> p1, ISingleObjectiveSolutionScope<TSolution> p2) {
+      breedingPerformanceModel = RunRegression(PrepareRegression(ToListRow(breedingStat)), breedingPerformanceModel).Model;
+    }
+    public bool BreedingSuited(ISingleObjectiveSolutionScope<TSolution> p1, ISingleObjectiveSolutionScope<TSolution> p2, double dist) {
       if (breedingPerformanceModel == null) return true;
       double minI1 = double.MaxValue, minI2 = double.MaxValue, maxI1 = double.MinValue, maxI2 = double.MinValue;
@@ -355,18 +355,14 @@
         if (d.Item2 > maxI2) maxI2 = d.Item2;
       }
-      if (IsBetter(p1, p2)) {
-        if (p1.Fitness < minI1 || p1.Fitness > maxI1 || p2.Fitness < minI2 || p2.Fitness > maxI2)
-          return true;
-        return Random.NextDouble() < ProbabilityAccept3dModel(p1.Fitness, p2.Fitness, breedingPerformanceModel);
-      }
-      if (p1.Fitness < minI2 || p1.Fitness > maxI2 || p2.Fitness < minI1 || p2.Fitness > maxI1)
+      if (p1.Fitness < minI1 || p1.Fitness > maxI1 || p2.Fitness < minI2 || p2.Fitness > maxI2)
         return true;
-      return Random.NextDouble() < ProbabilityAccept3dModel(p2.Fitness, p1.Fitness, breedingPerformanceModel);
+      
+      return Random.NextDouble() < ProbabilityAcceptAbsolutePerformanceModel(new List<double> { p1.Fitness, p2.Fitness, dist }, breedingPerformanceModel);
     }
 
     public void RelearnRelinkingPerformanceModel() {
-      relinkingPerformanceModel = RunRegression(PrepareRegression(RelinkingStat), relinkingPerformanceModel).Model;
-    }
-    public bool RelinkSuited(ISingleObjectiveSolutionScope<TSolution> p1, ISingleObjectiveSolutionScope<TSolution> p2) {
+      relinkingPerformanceModel = RunRegression(PrepareRegression(ToListRow(relinkingStat)), relinkingPerformanceModel).Model;
+    }
+    public bool RelinkSuited(ISingleObjectiveSolutionScope<TSolution> p1, ISingleObjectiveSolutionScope<TSolution> p2, double dist) {
       if (relinkingPerformanceModel == null) return true;
       double minI1 = double.MaxValue, minI2 = double.MaxValue, maxI1 = double.MinValue, maxI2 = double.MinValue;
@@ -377,18 +373,17 @@
         if (d.Item2 > maxI2) maxI2 = d.Item2;
       }
+      if (p1.Fitness < minI1 || p1.Fitness > maxI1 || p2.Fitness < minI2 || p2.Fitness > maxI2)
+        return true;
+
       if (IsBetter(p1, p2)) {
-        if (p1.Fitness < minI1 || p1.Fitness > maxI1 || p2.Fitness < minI2 || p2.Fitness > maxI2)
-          return true;
-        return Random.NextDouble() < ProbabilityAccept3dModel(p1.Fitness, p2.Fitness, relinkingPerformanceModel);
-      }
-      if (p1.Fitness < minI2 || p1.Fitness > maxI2 || p2.Fitness < minI1 || p2.Fitness > maxI1)
-        return true;
-      return Random.NextDouble() < ProbabilityAccept3dModel(p2.Fitness, p1.Fitness, relinkingPerformanceModel);
+        return Random.NextDouble() < ProbabilityAcceptRelativePerformanceModel(p1.Fitness, new List<double> { p1.Fitness, p2.Fitness, dist }, relinkingPerformanceModel);
+      }
+      return Random.NextDouble() < ProbabilityAcceptRelativePerformanceModel(p2.Fitness, new List<double> { p1.Fitness, p2.Fitness, dist }, relinkingPerformanceModel);
     }
 
     public void RelearnDelinkingPerformanceModel() {
-      delinkingPerformanceModel = RunRegression(PrepareRegression(DelinkingStat), delinkingPerformanceModel).Model;
-    }
-    public bool DelinkSuited(ISingleObjectiveSolutionScope<TSolution> p1, ISingleObjectiveSolutionScope<TSolution> p2) {
+      delinkingPerformanceModel = RunRegression(PrepareRegression(ToListRow(delinkingStat)), delinkingPerformanceModel).Model;
+    }
+    public bool DelinkSuited(ISingleObjectiveSolutionScope<TSolution> p1, ISingleObjectiveSolutionScope<TSolution> p2, double dist) {
       if (delinkingPerformanceModel == null) return true;
       double minI1 = double.MaxValue, minI2 = double.MaxValue, maxI1 = double.MinValue, maxI2 = double.MinValue;
@@ -399,30 +394,26 @@
         if (d.Item2 > maxI2) maxI2 = d.Item2;
       }
+      if (p1.Fitness < minI1 || p1.Fitness > maxI1 || p2.Fitness < minI2 || p2.Fitness > maxI2)
+        return true;
       if (IsBetter(p1, p2)) {
-        if (p1.Fitness < minI1 || p1.Fitness > maxI1 || p2.Fitness < minI2 || p2.Fitness > maxI2)
-          return true;
-        return Random.NextDouble() < ProbabilityAccept3dModel(p1.Fitness, p2.Fitness, delinkingPerformanceModel);
-      }
-      if (p1.Fitness < minI2 || p1.Fitness > maxI2 || p2.Fitness < minI1 || p2.Fitness > maxI1)
-        return true;
-      return Random.NextDouble() < ProbabilityAccept3dModel(p2.Fitness, p1.Fitness, delinkingPerformanceModel);
+        return Random.NextDouble() < ProbabilityAcceptRelativePerformanceModel(p1.Fitness, new List<double> { p1.Fitness, p2.Fitness, dist }, delinkingPerformanceModel);
+      }
+      return Random.NextDouble() < ProbabilityAcceptRelativePerformanceModel(p2.Fitness, new List<double> { p1.Fitness, p2.Fitness, dist }, delinkingPerformanceModel);
     }
 
     public void RelearnSamplingPerformanceModel() {
-      samplingPerformanceModel = RunRegression(PrepareRegression(SamplingStat), samplingPerformanceModel).Model;
-    }
-    public bool SamplingSuited() {
+      samplingPerformanceModel = RunRegression(PrepareRegression(ToListRow(samplingStat)), samplingPerformanceModel).Model;
+    }
+    public bool SamplingSuited(double avgDist) {
       if (samplingPerformanceModel == null) return true;
-      return Random.NextDouble() < ProbabilityAccept2dModel(Population.Average(x => x.Fitness), samplingPerformanceModel);
+      if (avgDist < samplingStat.Min(x => x.Item1) || avgDist > samplingStat.Max(x => x.Item1)) return true;
+      return Random.NextDouble() < ProbabilityAcceptAbsolutePerformanceModel(new List<double> { avgDist }, samplingPerformanceModel);
     }
 
     public void RelearnHillclimbingPerformanceModel() {
-      hillclimbingPerformanceModel = RunRegression(PrepareRegression(HillclimbingStat), hillclimbingPerformanceModel).Model;
+      hillclimbingPerformanceModel = RunRegression(PrepareRegression(ToListRow(hillclimbingStat)), hillclimbingPerformanceModel).Model;
     }
     public bool HillclimbingSuited(ISingleObjectiveSolutionScope<TSolution> scope) {
-      if (hillclimbingPerformanceModel == null) return true;
-      if (scope.Fitness < HillclimbingStat.Min(x => x.Item1) || scope.Fitness > HillclimbingStat.Max(x => x.Item1))
-        return true;
-      return Random.NextDouble() < ProbabilityAccept2dModel(scope.Fitness, hillclimbingPerformanceModel);
+      return HillclimbingSuited(scope.Fitness);
     }
     public bool HillclimbingSuited(double startingFitness) {
@@ -430,15 +421,12 @@
       if (startingFitness < HillclimbingStat.Min(x => x.Item1) || startingFitness > HillclimbingStat.Max(x => x.Item1))
         return true;
-      return Random.NextDouble() < ProbabilityAccept2dModel(startingFitness, hillclimbingPerformanceModel);
+      return Random.NextDouble() < ProbabilityAcceptRelativePerformanceModel(startingFitness, new List<double> { startingFitness }, hillclimbingPerformanceModel);
     }
 
     public void RelearnAdaptiveWalkPerformanceModel() {
-      adaptiveWalkPerformanceModel = RunRegression(PrepareRegression(AdaptivewalkingStat), adaptiveWalkPerformanceModel).Model;
+      adaptiveWalkPerformanceModel = RunRegression(PrepareRegression(ToListRow(adaptivewalkingStat)), adaptiveWalkPerformanceModel).Model;
     }
     public bool AdaptivewalkingSuited(ISingleObjectiveSolutionScope<TSolution> scope) {
-      if (adaptiveWalkPerformanceModel == null) return true;
-      if (scope.Fitness < AdaptivewalkingStat.Min(x => x.Item1) || scope.Fitness > AdaptivewalkingStat.Max(x => x.Item1))
-        return true;
-      return Random.NextDouble() < ProbabilityAccept2dModel(scope.Fitness, adaptiveWalkPerformanceModel);
+      return AdaptivewalkingSuited(scope.Fitness);
     }
     public bool AdaptivewalkingSuited(double startingFitness) {
@@ -446,40 +434,26 @@
       if (startingFitness < AdaptivewalkingStat.Min(x => x.Item1) || startingFitness > AdaptivewalkingStat.Max(x => x.Item1))
         return true;
-      return Random.NextDouble() < ProbabilityAccept2dModel(startingFitness, adaptiveWalkPerformanceModel);
-    }
-
-    public IConfidenceRegressionSolution GetSolution(IConfidenceRegressionModel model, List<Tuple<double, double>> data) {
-      return new ConfidenceRegressionSolution(model, PrepareRegression(data));
-    }
-    public IConfidenceRegressionSolution GetSolution(IConfidenceRegressionModel model, List<Tuple<double, double, double>> data) {
-      return new ConfidenceRegressionSolution(model, PrepareRegression(data));
-    }
-
-    protected RegressionProblemData PrepareRegression(List<Tuple<double, double>> sample) {
-      var inCol = new List<double>();
-      var outCol = new List<double>();
+      return Random.NextDouble() < ProbabilityAcceptAbsolutePerformanceModel(new List<double> { startingFitness }, adaptiveWalkPerformanceModel);
+    }
+
+    public IConfidenceRegressionSolution GetSolution(IConfidenceRegressionModel model, IEnumerable<Tuple<double, double>> data) {
+      return new ConfidenceRegressionSolution(model, PrepareRegression(ToListRow(data.ToList())));
+    }
+    public IConfidenceRegressionSolution GetSolution(IConfidenceRegressionModel model, IEnumerable<Tuple<double, double, double>> data) {
+      return new ConfidenceRegressionSolution(model, PrepareRegression(ToListRow(data.ToList())));
+    }
+    public IConfidenceRegressionSolution GetSolution(IConfidenceRegressionModel model, IEnumerable<Tuple<double, double, double, double>> data) {
+      return new ConfidenceRegressionSolution(model, PrepareRegression(ToListRow(data.ToList())));
+    }
+
+    protected RegressionProblemData PrepareRegression(List<List<double>> sample) {
+      var columns = sample.First().Select(y => new List<double>()).ToList();
       foreach (var next in sample.Shuffle(Random)) {
-        inCol.Add(next.Item1);
-        outCol.Add(next.Item2);
-      }
-      var ds = new Dataset(new[] { "in", "out" }, new[] { inCol, outCol });
-      var regPrb = new RegressionProblemData(ds, new[] { "in" }, "out") {
-        TrainingPartition = { Start = 0, End = Math.Min(50, sample.Count) },
-        TestPartition = { Start = Math.Min(50, sample.Count), End = sample.Count }
-      };
-      return regPrb;
-    }
-
-    protected RegressionProblemData PrepareRegression(List<Tuple<double, double, double>> sample) {
-      var in1Col = new List<double>();
-      var in2Col = new List<double>();
-      var outCol = new List<double>();
-      foreach (var next in sample.Shuffle(Random)) {
-        in1Col.Add(next.Item1);
-        in2Col.Add(next.Item2);
-        outCol.Add(next.Item3);
-      }
-      var ds = new Dataset(new[] { "in1", "in2", "out" }, new[] { in1Col, in2Col, outCol });
-      var regPrb = new RegressionProblemData(ds, new[] { "in1", "in2" }, "out") {
+        for (var i = 0; i < next.Count; i++) {
+          columns[i].Add(next[i]);
+        }
+      }
+      var ds = new Dataset(columns.Select((v, i) => i < columns.Count - 1 ? "in" + i : "out").ToList(), columns);
+      var regPrb = new RegressionProblemData(ds, Enumerable.Range(0, columns.Count - 1).Select(x => "in" + x), "out") {
         TrainingPartition = { Start = 0, End = Math.Min(50, sample.Count) },
         TestPartition = { Start = Math.Min(50, sample.Count), End = sample.Count }
@@ -525,22 +499,39 @@
     }
 
-    private double ProbabilityAccept2dModel(double a, IConfidenceRegressionModel model) {
-      var ds = new Dataset(new[] { "in", "out" }, new[] { new List<double> { a }, new List<double> { double.NaN } });
+    private double ProbabilityAcceptAbsolutePerformanceModel(List<double> inputs, IConfidenceRegressionModel model) {
+      var inputVariables = inputs.Select((v, i) => "in" + i);
+      var ds = new Dataset(inputVariables.Concat( new [] { "out" }), inputs.Select(x => new List<double> { x }).Concat(new [] { new List<double> { double.NaN } }));
       var mean = model.GetEstimatedValues(ds, new[] { 0 }).Single();
       var sdev = Math.Sqrt(model.GetEstimatedVariances(ds, new[] { 0 }).Single());
 
+      // calculate the fitness goal
       var goal = Maximization ? Population.Min(x => x.Fitness) : Population.Max(x => x.Fitness);
       var z = (goal - mean) / sdev;
-      return Maximization ? 1.0 - Phi(z) /* P(X >= z) */ : Phi(z); // P(X <= z)
-    }
-
-    private double ProbabilityAccept3dModel(double a, double b, IConfidenceRegressionModel model) {
-      var ds = new Dataset(new[] { "in1", "in2", "out" }, new[] { new List<double> { a }, new List<double> { b }, new List<double> { double.NaN } });
+      // return the probability of achieving or surpassing that goal
+      var y = alglib.invnormaldistribution(z);
+      return Maximization ? 1.0 - y /* P(X >= z) */ : y; // P(X <= z)
+    }
+
+    private double ProbabilityAcceptRelativePerformanceModel(double basePerformance, List<double> inputs, IConfidenceRegressionModel model) {
+      var inputVariables = inputs.Select((v, i) => "in" + i);
+      var ds = new Dataset(inputVariables.Concat(new[] { "out" }), inputs.Select(x => new List<double> { x }).Concat(new[] { new List<double> { double.NaN } }));
       var mean = model.GetEstimatedValues(ds, new[] { 0 }).Single();
       var sdev = Math.Sqrt(model.GetEstimatedVariances(ds, new[] { 0 }).Single());
 
-      var goal = Maximization ? Population.Min(x => x.Fitness) : Population.Max(x => x.Fitness);
+      // calculate the improvement goal
+      var goal = Maximization ? Population.Min(x => x.Fitness) - basePerformance : basePerformance - Population.Max(x => x.Fitness);
       var z = (goal - mean) / sdev;
-      return Maximization ? 1.0 - Phi(z) /* P(X >= z) */ : Phi(z); // P(X <= z)
+      // return the probability of achieving or surpassing that goal
+      return 1.0 - alglib.invnormaldistribution(z); /* P(X >= z) */
+    }
+
+    private static List<List<double>> ToListRow(List<Tuple<double, double>> rows) {
+      return rows.Select(x => new List<double> { x.Item1, x.Item2 }).ToList();
+    }
+    private static List<List<double>> ToListRow(List<Tuple<double, double, double>> rows) {
+      return rows.Select(x => new List<double> { x.Item1, x.Item2, x.Item3 }).ToList();
+    }
+    private static List<List<double>> ToListRow(List<Tuple<double, double, double, double>> rows) {
+      return rows.Select(x => new List<double> { x.Item1, x.Item2, x.Item3, x.Item4 }).ToList();
     }
 
@@ -556,32 +547,38 @@
     }
 
-    public void AddBreedingResult(ISingleObjectiveSolutionScope<TSolution> a, ISingleObjectiveSolutionScope<TSolution> b, ISingleObjectiveSolutionScope<TSolution> child) {
+    public void AddBreedingResult(ISingleObjectiveSolutionScope<TSolution> a, ISingleObjectiveSolutionScope<TSolution> b, double parentDist, ISingleObjectiveSolutionScope<TSolution> child) {
       if (IsBetter(a, b))
-        BreedingStat.Add(Tuple.Create(a.Fitness, b.Fitness, child.Fitness));
-      else BreedingStat.Add(Tuple.Create(b.Fitness, a.Fitness, child.Fitness));
-    }
-
-    public void AddRelinkingResult(ISingleObjectiveSolutionScope<TSolution> a, ISingleObjectiveSolutionScope<TSolution> b, ISingleObjectiveSolutionScope<TSolution> child) {
+        breedingStat.Add(Tuple.Create(a.Fitness, b.Fitness, parentDist, child.Fitness));
+      else breedingStat.Add(Tuple.Create(b.Fitness, a.Fitness, parentDist, child.Fitness));
+      if (breedingStat.Count % 10 == 0) RelearnBreedingPerformanceModel();
+    }
+
+    public void AddRelinkingResult(ISingleObjectiveSolutionScope<TSolution> a, ISingleObjectiveSolutionScope<TSolution> b, double parentDist, ISingleObjectiveSolutionScope<TSolution> child) {
       if (IsBetter(a, b))
-        RelinkingStat.Add(Tuple.Create(a.Fitness, b.Fitness, child.Fitness));
-      else RelinkingStat.Add(Tuple.Create(b.Fitness, a.Fitness, child.Fitness));
-    }
-
-    public void AddDelinkingResult(ISingleObjectiveSolutionScope<TSolution> a, ISingleObjectiveSolutionScope<TSolution> b, ISingleObjectiveSolutionScope<TSolution> child) {
+        relinkingStat.Add(Tuple.Create(a.Fitness, b.Fitness, parentDist, Maximization ? child.Fitness - a.Fitness : a.Fitness - child.Fitness));
+      else relinkingStat.Add(Tuple.Create(a.Fitness, b.Fitness, parentDist, Maximization ? child.Fitness - b.Fitness : b.Fitness - child.Fitness));
+      if (relinkingStat.Count % 10 == 0) RelearnRelinkingPerformanceModel();
+    }
+
+    public void AddDelinkingResult(ISingleObjectiveSolutionScope<TSolution> a, ISingleObjectiveSolutionScope<TSolution> b, double parentDist, ISingleObjectiveSolutionScope<TSolution> child) {
       if (IsBetter(a, b))
-        DelinkingStat.Add(Tuple.Create(a.Fitness, b.Fitness, child.Fitness));
-      else DelinkingStat.Add(Tuple.Create(b.Fitness, a.Fitness, child.Fitness));
-    }
-
-    public void AddSamplingResult(ISingleObjectiveSolutionScope<TSolution> sample) {
-      SamplingStat.Add(Tuple.Create(Population.Average(x => x.Fitness), sample.Fitness));
+        delinkingStat.Add(Tuple.Create(a.Fitness, b.Fitness, parentDist, Maximization ? child.Fitness - a.Fitness : a.Fitness - child.Fitness));
+      else delinkingStat.Add(Tuple.Create(a.Fitness, b.Fitness, parentDist, Maximization ? child.Fitness - b.Fitness : b.Fitness - child.Fitness));
+      if (delinkingStat.Count % 10 == 0) RelearnDelinkingPerformanceModel();
+    }
+
+    public void AddSamplingResult(ISingleObjectiveSolutionScope<TSolution> sample, double avgDist) {
+      samplingStat.Add(Tuple.Create(avgDist, sample.Fitness));
+      if (samplingStat.Count % 10 == 0) RelearnSamplingPerformanceModel();
     }
 
     public void AddHillclimbingResult(ISingleObjectiveSolutionScope<TSolution> input, ISingleObjectiveSolutionScope<TSolution> outcome) {
-      HillclimbingStat.Add(Tuple.Create(input.Fitness, outcome.Fitness));
-    }
-
-    public void AddTabuwalkingResult(ISingleObjectiveSolutionScope<TSolution> input, ISingleObjectiveSolutionScope<TSolution> outcome) {
-      AdaptivewalkingStat.Add(Tuple.Create(input.Fitness, outcome.Fitness));
+      hillclimbingStat.Add(Tuple.Create(input.Fitness, Maximization ? outcome.Fitness - input.Fitness : input.Fitness - outcome.Fitness));
+      if (hillclimbingStat.Count % 10 == 0) RelearnHillclimbingPerformanceModel();
+    }
+
+    public void AddAdaptivewalkingResult(ISingleObjectiveSolutionScope<TSolution> input, ISingleObjectiveSolutionScope<TSolution> outcome) {
+      adaptivewalkingStat.Add(Tuple.Create(input.Fitness, outcome.Fitness));
+      if (adaptivewalkingStat.Count % 10 == 0) RelearnAdaptiveWalkPerformanceModel();
     }
 
@@ -609,5 +606,5 @@
     // license: "This code is in the public domain. Do whatever you want with it, no strings attached."
     // added: 2016-11-19 21:46 CET
-    protected static double Phi(double x) {
+    /*protected static double Phi(double x) {
       // constants
       double a1 = 0.254829592;
@@ -629,5 +626,5 @@
 
       return 0.5 * (1.0 + sign * y);
-    }
+    }*/
     #endregion
 
Index: branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/Permutation/PermutationMemPR.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/Permutation/PermutationMemPR.cs	(revision 14562)
+++ branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/Permutation/PermutationMemPR.cs	(revision 14563)
@@ -52,5 +52,10 @@
       foreach (var trainer in ApplicationManager.Manager.GetInstances<ISolutionModelTrainer<PermutationMemPRPopulationContext>>())
         SolutionModelTrainerParameter.ValidValues.Add(trainer);
-      
+
+      if (SolutionModelTrainerParameter.ValidValues.Count > 0) {
+        var unbiased = SolutionModelTrainerParameter.ValidValues.FirstOrDefault(x => !x.Bias);
+        if (unbiased != null) SolutionModelTrainerParameter.Value = unbiased;
+      }
+
       foreach (var localSearch in ApplicationManager.Manager.GetInstances<ILocalSearch<PermutationMemPRSolutionContext>>()) {
         LocalSearchParameter.ValidValues.Add(localSearch);
@@ -290,5 +295,5 @@
         InversionMove bestOfTheRest = null;
         var improved = false;
-
+        
         foreach (var opt in ExhaustiveInversionMoveGenerator.Generate(current).Shuffle(random)) {
           var prev = opt.Index1 - 1;
@@ -395,5 +400,5 @@
       cache.Add(p2.Solution);
 
-      var cacheHits = 0;
+      var cacheHits = new Dictionary<int, int>() { { 0, 0 }, { 1, 0 }, { 2, 0 } };
       var evaluations = 0;
       ISingleObjectiveSolutionScope<Encodings.PermutationEncoding.Permutation> offspring = null;
@@ -401,5 +406,5 @@
       while (evaluations < p1.Solution.Length) {
         Encodings.PermutationEncoding.Permutation c = null;
-        var xochoice = Context.Random.Next(3);
+        var xochoice = cacheHits.SampleRandom(Context.Random).Key;
         switch (xochoice) {
           case 0: c = CyclicCrossover2.Apply(Context.Random, p1.Solution, p2.Solution); break;
@@ -408,6 +413,9 @@
         }
         if (cache.Contains(c)) {
-          cacheHits++;
-          if (cacheHits > 10) break;
+          cacheHits[xochoice]++;
+          if (cacheHits[xochoice] > 10) {
+            cacheHits.Remove(xochoice);
+            if (cacheHits.Count == 0) break;
+          }
           continue;
         }
@@ -431,5 +439,5 @@
       cache.Add(p2.Solution);
 
-      var cacheHits = 0;
+      var cacheHits = new Dictionary<int, int>() { { 0, 0 }, { 1, 0 }, { 2, 0 } };
       var evaluations = 0;
       ISingleObjectiveSolutionScope<Encodings.PermutationEncoding.Permutation> offspring = null;
@@ -437,5 +445,5 @@
       while (evaluations < p1.Solution.Length) {
         Encodings.PermutationEncoding.Permutation c = null;
-        var xochoice = Context.Random.Next(3);
+        var xochoice = cacheHits.SampleRandom(Context.Random).Key;
         switch (xochoice) {
           case 0: c = OrderCrossover2.Apply(Context.Random, p1.Solution, p2.Solution); break;
@@ -444,6 +452,9 @@
         }
         if (cache.Contains(c)) {
-          cacheHits++;
-          if (cacheHits > 10) break;
+          cacheHits[xochoice]++;
+          if (cacheHits[xochoice] > 10) {
+            cacheHits.Remove(xochoice);
+            if (cacheHits.Count == 0) break;
+          }
           continue;
         }
@@ -467,5 +478,5 @@
       cache.Add(p2.Solution);
 
-      var cacheHits = 0;
+      var cacheHits = new Dictionary<int, int>() { { 0, 0 }, { 1, 0 }, { 2, 0 } };
       var evaluations = 0;
       ISingleObjectiveSolutionScope<Encodings.PermutationEncoding.Permutation> offspring = null;
@@ -473,5 +484,5 @@
       while (evaluations <= p1.Solution.Length) {
         Encodings.PermutationEncoding.Permutation c = null;
-        var xochoice = Context.Random.Next(3);
+        var xochoice = cacheHits.SampleRandom(Context.Random).Key;
         switch (xochoice) {
           case 0: c = OrderCrossover2.Apply(Context.Random, p1.Solution, p2.Solution); break;
@@ -480,6 +491,9 @@
         }
         if (cache.Contains(c)) {
-          cacheHits++;
-          if (cacheHits > 10) break;
+          cacheHits[xochoice]++;
+          if (cacheHits[xochoice] > 10) {
+            cacheHits.Remove(xochoice);
+            if (cacheHits.Count == 0) break;
+          }
           continue;
         }
Index: branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/Permutation/SolutionModel/Univariate/BiasedModelTrainer.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/Permutation/SolutionModel/Univariate/BiasedModelTrainer.cs	(revision 14562)
+++ branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/Permutation/SolutionModel/Univariate/BiasedModelTrainer.cs	(revision 14563)
@@ -25,5 +25,4 @@
 using HeuristicLab.Core;
 using HeuristicLab.Data;
-using HeuristicLab.Encodings.PermutationEncoding;
 using HeuristicLab.Optimization;
 using HeuristicLab.Parameters;
@@ -36,4 +35,6 @@
     where TContext : IPopulationBasedHeuristicAlgorithmContext<ISingleObjectiveHeuristicOptimizationProblem, Encodings.PermutationEncoding.Permutation>,
     ISolutionModelContext<Encodings.PermutationEncoding.Permutation>, IEvaluationServiceContext<Encodings.PermutationEncoding.Permutation> {
+
+    public bool Bias { get { return true; } }
 
     [Storable]
Index: branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/Permutation/SolutionModel/Univariate/UnbiasedModelTrainer.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/Permutation/SolutionModel/Univariate/UnbiasedModelTrainer.cs	(revision 14562)
+++ branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/Permutation/SolutionModel/Univariate/UnbiasedModelTrainer.cs	(revision 14563)
@@ -21,9 +21,7 @@
 
 using System.Linq;
-using HeuristicLab.Algorithms.MemPR.Binary.SolutionModel.Univariate;
 using HeuristicLab.Algorithms.MemPR.Interfaces;
 using HeuristicLab.Common;
 using HeuristicLab.Core;
-using HeuristicLab.Encodings.PermutationEncoding;
 using HeuristicLab.Optimization;
 using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
@@ -35,5 +33,7 @@
     where TContext : IPopulationBasedHeuristicAlgorithmContext<ISingleObjectiveHeuristicOptimizationProblem, Encodings.PermutationEncoding.Permutation>,
     ISolutionModelContext<Encodings.PermutationEncoding.Permutation> {
-    
+
+    public bool Bias { get { return false; } }
+
     [StorableConstructor]
     protected UnbiasedModelTrainer(bool deserializing) : base(deserializing) { }
