Index: /branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/Binary/BinaryMemPR.cs
===================================================================
--- /branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/Binary/BinaryMemPR.cs	(revision 14449)
+++ /branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/Binary/BinaryMemPR.cs	(revision 14450)
@@ -24,10 +24,9 @@
 using System.Linq;
 using System.Threading;
+using HeuristicLab.Algorithms.MemPR.Interfaces;
 using HeuristicLab.Common;
 using HeuristicLab.Core;
 using HeuristicLab.Encodings.BinaryVectorEncoding;
 using HeuristicLab.Optimization;
-using HeuristicLab.Optimization.LocalSearch;
-using HeuristicLab.Optimization.SolutionModel;
 using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
 using HeuristicLab.PluginInfrastructure;
@@ -38,5 +37,5 @@
   [StorableClass]
   [Creatable(CreatableAttribute.Categories.PopulationBasedAlgorithms, Priority = 999)]
-  public class BinaryMemPR : MemPRAlgorithm<BinaryVector, BinaryMemPRContext, BinarySingleSolutionMemPRContext> {
+  public class BinaryMemPR : MemPRAlgorithm<SingleObjectiveBasicProblem<BinaryVectorEncoding>, BinaryVector, BinaryMemPRPopulationContext, BinaryMemPRSolutionContext> {
     private const double UncommonBitSubsetMutationProbabilityMagicConst = 0.05;
     
@@ -45,17 +44,9 @@
     protected BinaryMemPR(BinaryMemPR original, Cloner cloner) : base(original, cloner) { }
     public BinaryMemPR() {
-      foreach (var trainer in ApplicationManager.Manager.GetInstances<IBinarySolutionModelTrainer<BinaryMemPRContext>>())
+      foreach (var trainer in ApplicationManager.Manager.GetInstances<ISolutionModelTrainer<BinaryMemPRPopulationContext>>())
         SolutionModelTrainerParameter.ValidValues.Add(trainer);
       
-      foreach (var localSearch in ApplicationManager.Manager.GetInstances<IBinaryLocalSearch<BinarySingleSolutionMemPRContext>>()) {
-        // only use local search operators that can deal with a restricted solution space
-        var lsType = localSearch.GetType();
-        var genTypeDef = lsType.GetGenericTypeDefinition();
-        // TODO: By convention, context type must be put last
-        // TODO: Fails with non-generic types
-        if (genTypeDef.GetGenericArguments().Last().GetGenericParameterConstraints().Any(x => typeof(IBinarySolutionSubspaceContext).IsAssignableFrom(x))) {
-          localSearch.EvaluateFunc = EvaluateFunc;
-          LocalSearchParameter.ValidValues.Add(localSearch);
-        }
+      foreach (var localSearch in ApplicationManager.Manager.GetInstances<ILocalSearch<BinaryMemPRSolutionContext>>()) {
+        LocalSearchParameter.ValidValues.Add(localSearch);
       }
     }
@@ -63,10 +54,4 @@
     public override IDeepCloneable Clone(Cloner cloner) {
       return new BinaryMemPR(this, cloner);
-    }
-
-    protected double EvaluateFunc(BinaryVector solution) {
-      var scope = ToScope(solution);
-      Evaluate(scope, CancellationToken.None);
-      return scope.Fitness;
     }
 
@@ -98,5 +83,5 @@
     }
 
-    protected override ISolutionSubspace CalculateSubspace(IEnumerable<BinaryVector> solutions, bool inverse = false) {
+    protected override ISolutionSubspace<BinaryVector> CalculateSubspace(IEnumerable<BinaryVector> solutions, bool inverse = false) {
       var pop = solutions.ToList();
       var N = pop[0].Length;
@@ -112,11 +97,5 @@
     }
 
-    protected override ISingleObjectiveSolutionScope<BinaryVector> Create(CancellationToken token) {
-      var child = ToScope(null);
-      RunOperator(Problem.SolutionCreator, child, token);
-      return child;
-    }
-
-    protected override void TabuWalk(ISingleObjectiveSolutionScope<BinaryVector> scope, int steps, CancellationToken token, ISolutionSubspace subspace = null) {
+    protected override void TabuWalk(ISingleObjectiveSolutionScope<BinaryVector> scope, int steps, CancellationToken token, ISolutionSubspace<BinaryVector> subspace = null) {
       var subset = subspace != null ? ((BinarySolutionSubspace)subspace).Subspace : null;
       if (double.IsNaN(scope.Fitness)) Evaluate(scope, token);
@@ -183,9 +162,8 @@
       var lastbp = 0;
       for (var i = 0; i < code.Length; i++) {
-        if (code[i] == p2Code[i]) continue; // common bit
         if (bp % 2 == 1) {
           code[i] = p2Code[i];
         }
-        if (Context.Random.Next(code.Length) < i - lastbp) {
+        if (Context.Random.Next(code.Length) < i - lastbp + 1) {
           bp = (bp + 1) % 2;
           lastbp = i;
@@ -195,5 +173,5 @@
     }
 
-    protected override void Mutate(ISingleObjectiveSolutionScope<BinaryVector> offspring, CancellationToken token, ISolutionSubspace subspace = null) {
+    protected override void Mutate(ISingleObjectiveSolutionScope<BinaryVector> offspring, CancellationToken token, ISolutionSubspace<BinaryVector> subspace = null) {
       var subset = subspace != null ? ((BinarySolutionSubspace)subspace).Subspace : null;
       offspring.Fitness = double.NaN;
Index: /branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/Binary/BinaryMemPRContext.cs
===================================================================
--- /branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/Binary/BinaryMemPRContext.cs	(revision 14449)
+++ /branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/Binary/BinaryMemPRContext.cs	(revision 14450)
@@ -20,4 +20,5 @@
 #endregion
 
+using HeuristicLab.Algorithms.MemPR.Interfaces;
 using HeuristicLab.Common;
 using HeuristicLab.Core;
@@ -28,27 +29,27 @@
 
 namespace HeuristicLab.Algorithms.MemPR.Binary {
-  [Item("BinaryMemPRContext", "MemPR context for binary encoded problems.")]
+  [Item("MemPR Population Context (binary)", "MemPR population context for binary encoded problems.")]
   [StorableClass]
-  public sealed class BinaryMemPRContext : MemPRContext<BinaryVector, BinaryMemPRContext, BinarySingleSolutionMemPRContext> {
+  public sealed class BinaryMemPRPopulationContext : MemPRPopulationContext<SingleObjectiveBasicProblem<BinaryVectorEncoding>, BinaryVector, BinaryMemPRPopulationContext, BinaryMemPRSolutionContext> {
 
     [StorableConstructor]
-    private BinaryMemPRContext(bool deserializing) : base(deserializing) { }
-    private BinaryMemPRContext(BinaryMemPRContext original, Cloner cloner)
+    private BinaryMemPRPopulationContext(bool deserializing) : base(deserializing) { }
+    private BinaryMemPRPopulationContext(BinaryMemPRPopulationContext original, Cloner cloner)
       : base(original, cloner) { }
-    public BinaryMemPRContext() : base("BinaryMemPRContext") { }
-    public BinaryMemPRContext(string name) : base(name) { }
+    public BinaryMemPRPopulationContext() : base("BinaryMemPRPopulationContext") { }
+    public BinaryMemPRPopulationContext(string name) : base(name) { }
 
     public override IDeepCloneable Clone(Cloner cloner) {
-      return new BinaryMemPRContext(this, cloner);
+      return new BinaryMemPRPopulationContext(this, cloner);
     }
 
-    public override BinarySingleSolutionMemPRContext CreateSingleSolutionContext(ISingleObjectiveSolutionScope<BinaryVector> solution) {
-      return new BinarySingleSolutionMemPRContext(this, solution);
+    public override BinaryMemPRSolutionContext CreateSingleSolutionContext(ISingleObjectiveSolutionScope<BinaryVector> solution) {
+      return new BinaryMemPRSolutionContext(this, solution);
     }
   }
 
-  [Item("BinarySingleSolutionMemPRContext", "Single solution MemPR context for binary encoded problems.")]
+  [Item("MemPR Solution Context (binary)", "MemPR solution context for binary encoded problems.")]
   [StorableClass]
-  public sealed class BinarySingleSolutionMemPRContext : SingleSolutionMemPRContext<BinaryVector, BinaryMemPRContext, BinarySingleSolutionMemPRContext>, IBinarySolutionSubspaceContext {
+  public sealed class BinaryMemPRSolutionContext : MemPRSolutionContext<SingleObjectiveBasicProblem<BinaryVectorEncoding>, BinaryVector, BinaryMemPRPopulationContext, BinaryMemPRSolutionContext>, IBinaryVectorSubspaceContext {
 
     [Storable]
@@ -57,15 +58,15 @@
       get { return subspace.Value; }
     }
-    ISolutionSubspace ISolutionSubspaceContext.Subspace {
+    ISolutionSubspace<BinaryVector> ISolutionSubspaceContext<BinaryVector>.Subspace {
       get { return Subspace; }
     }
 
     [StorableConstructor]
-    private BinarySingleSolutionMemPRContext(bool deserializing) : base(deserializing) { }
-    private BinarySingleSolutionMemPRContext(BinarySingleSolutionMemPRContext original, Cloner cloner)
+    private BinaryMemPRSolutionContext(bool deserializing) : base(deserializing) { }
+    private BinaryMemPRSolutionContext(BinaryMemPRSolutionContext original, Cloner cloner)
       : base(original, cloner) {
 
     }
-    public BinarySingleSolutionMemPRContext(BinaryMemPRContext baseContext, ISingleObjectiveSolutionScope<BinaryVector> solution)
+    public BinaryMemPRSolutionContext(BinaryMemPRPopulationContext baseContext, ISingleObjectiveSolutionScope<BinaryVector> solution)
       : base(baseContext, solution) {
 
@@ -74,5 +75,5 @@
 
     public override IDeepCloneable Clone(Cloner cloner) {
-      return new BinarySingleSolutionMemPRContext(this, cloner);
+      return new BinaryMemPRSolutionContext(this, cloner);
     }
   }
Index: /branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/Binary/BinarySolutionSubspace.cs
===================================================================
--- /branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/Binary/BinarySolutionSubspace.cs	(revision 14449)
+++ /branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/Binary/BinarySolutionSubspace.cs	(revision 14450)
@@ -20,7 +20,8 @@
 #endregion
 
+using HeuristicLab.Algorithms.MemPR.Interfaces;
 using HeuristicLab.Common;
 using HeuristicLab.Core;
-using HeuristicLab.Optimization;
+using HeuristicLab.Encodings.BinaryVectorEncoding;
 using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
 
@@ -28,5 +29,5 @@
   [Item("Solution subspace (binary)", "")]
   [StorableClass]
-  public sealed class BinarySolutionSubspace : Item, ISolutionSubspace {
+  public sealed class BinarySolutionSubspace : Item, ISolutionSubspace<BinaryVector> {
 
     [Storable]
Index: /branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/Binary/LocalSearch/ExhaustiveBitflip.cs
===================================================================
--- /branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/Binary/LocalSearch/ExhaustiveBitflip.cs	(revision 14449)
+++ /branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/Binary/LocalSearch/ExhaustiveBitflip.cs	(revision 14450)
@@ -20,22 +20,26 @@
 #endregion
 
+using System.Threading;
+using HeuristicLab.Algorithms.MemPR.Interfaces;
+using HeuristicLab.Algorithms.MemPR.Util;
 using HeuristicLab.Common;
 using HeuristicLab.Core;
+using HeuristicLab.Encodings.Binary.LocalSearch;
 using HeuristicLab.Encodings.BinaryVectorEncoding;
 using HeuristicLab.Optimization;
-using HeuristicLab.Optimization.LocalSearch;
 using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
 
-namespace HeuristicLab.Encodings.Binary.LocalSearch {
-  [Item("Exhaustive Bitflip Local Search (binary)", "")]
+namespace HeuristicLab.Algorithms.MemPR.Binary.LocalSearch {
+  [Item("Exhaustive Bitflip Local Search (binary)", "", ExcludeGenericTypeInfo = true)]
   [StorableClass]
-  public class ExhaustiveBitflip<TContext> : ExhaustiveBitflipOperator, IBinaryLocalSearch<TContext> 
-      where TContext : ISingleObjectiveSolutionContext<BinaryVector>, IStochasticContext, IMaximizationContext,
-                       IEvaluatedSolutionsContext, IIterationsManipulationContext {
+  public class ExhaustiveBitflip<TContext> : NamedItem, ILocalSearch<TContext> where TContext : ISingleSolutionHeuristicAlgorithmContext<SingleObjectiveBasicProblem<BinaryVectorEncoding>, BinaryVector> {
     
     [StorableConstructor]
     protected ExhaustiveBitflip(bool deserializing) : base(deserializing) { }
     protected ExhaustiveBitflip(ExhaustiveBitflip<TContext> original, Cloner cloner) : base(original, cloner) { }
-    public ExhaustiveBitflip() { }
+    public ExhaustiveBitflip() {
+      Name = ItemName;
+      Description = ItemDescription;
+    }
 
     public override IDeepCloneable Clone(Cloner cloner) {
@@ -44,9 +48,10 @@
 
     public void Optimize(TContext context) {
+      var evalWrapper = new EvaluationWrapper<BinaryVector>(context.Problem, context.Solution);
       var quality = context.Solution.Fitness;
       try {
-        var result = Heuristic.ExhaustiveBitFlipSearch(context.Random, context.Solution.Solution, ref quality,
-          context.Maximization, EvaluateFunc, CancellationToken);
-        context.EvaluatedSolutions = result.Item1;
+        var result = ExhaustiveBitflip.Optimize(context.Random, context.Solution.Solution, ref quality,
+          context.Problem.Maximization, evalWrapper.Evaluate, CancellationToken.None);
+        context.IncrementEvaluatedSolutions(result.Item1);
         context.Iterations = result.Item2;
       } finally {
Index: anches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/Binary/LocalSearch/ExhaustiveBitflipOperator.cs
===================================================================
--- /branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/Binary/LocalSearch/ExhaustiveBitflipOperator.cs	(revision 14449)
+++ 	(revision )
@@ -1,89 +1,0 @@
-﻿#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.Linq;
-using HeuristicLab.Common;
-using HeuristicLab.Core;
-using HeuristicLab.Data;
-using HeuristicLab.Encodings.BinaryVectorEncoding;
-using HeuristicLab.Operators;
-using HeuristicLab.Optimization;
-using HeuristicLab.Optimization.LocalSearch;
-using HeuristicLab.Parameters;
-using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
-
-namespace HeuristicLab.Encodings.Binary.LocalSearch {
-  [Item("Exhaustive Bitflip Local Search Operator (binary)", "")]
-  [StorableClass]
-  public class ExhaustiveBitflipOperator : SingleSuccessorOperator, ILocalSearch<BinaryVector>, ISingleObjectiveOperator, IStochasticOperator {
-
-    public ILookupParameter<IRandom> RandomParameter {
-      get { return (ILookupParameter<IRandom>)Parameters["Random"]; }
-    }
-    
-    public ILookupParameter<BinaryVector> SolutionParameter {
-      get { return (ILookupParameter<BinaryVector>)Parameters["Solution"]; }
-    }
-
-    public ILookupParameter<BoolValue> MaximizationParameter {
-      get { return (ILookupParameter<BoolValue>)Parameters["Maximization"]; }
-    }
-
-    public ILookupParameter<DoubleValue> QualityParameter {
-      get { return (ILookupParameter<DoubleValue>)Parameters["Quality"]; }
-    }
-
-    public ILookupParameter<BoolArray> SubspaceParameter {
-      get { return (ILookupParameter<BoolArray>)Parameters["Subspace"]; }
-    }
-
-    public Func<BinaryVector, double> EvaluateFunc { get; set; }
-
-    [StorableConstructor]
-    protected ExhaustiveBitflipOperator(bool deserializing) : base(deserializing) { }
-    protected ExhaustiveBitflipOperator(ExhaustiveBitflipOperator original, Cloner cloner) : base(original, cloner) { }
-    public ExhaustiveBitflipOperator() {
-      Parameters.Add(new LookupParameter<IRandom>("Random", "The random number generator to use."));
-      Parameters.Add(new LookupParameter<BinaryVector>("Solution", "The solution that is to be optimized"));
-      Parameters.Add(new LookupParameter<BoolValue>("Maximization", "Whether the solution's quality should be maximized or minimized."));
-      Parameters.Add(new LookupParameter<DoubleValue>("Quality", "The quality of the solution."));
-      Parameters.Add(new LookupParameter<BoolArray>("Subspace", "Whether the local search should be confined to a sub-space of the solution space (indicated by true in this vector)."));
-    }
-
-    public override IDeepCloneable Clone(Cloner cloner) {
-      return new ExhaustiveBitflipOperator(this, cloner);
-    }
-
-    public override IOperation Apply() {
-      var quality = QualityParameter.ActualValue.Value;
-      var subspace = SubspaceParameter.ActualValue != null ? SubspaceParameter.ActualValue.ToArray() : null;
-      try {
-        Heuristic.ExhaustiveBitFlipSearch(RandomParameter.ActualValue,
-          SolutionParameter.ActualValue, ref quality, MaximizationParameter.ActualValue.Value,
-          EvaluateFunc, CancellationToken, subspace);
-      } finally {
-        QualityParameter.ActualValue.Value = quality;
-      }
-      return base.Apply();
-    }
-  }
-}
Index: /branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/Binary/LocalSearch/ExhaustiveBitflipSubspace.cs
===================================================================
--- /branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/Binary/LocalSearch/ExhaustiveBitflipSubspace.cs	(revision 14449)
+++ /branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/Binary/LocalSearch/ExhaustiveBitflipSubspace.cs	(revision 14450)
@@ -20,22 +20,26 @@
 #endregion
 
+using System.Threading;
+using HeuristicLab.Algorithms.MemPR.Interfaces;
 using HeuristicLab.Common;
 using HeuristicLab.Core;
+using HeuristicLab.Encodings.Binary.LocalSearch;
 using HeuristicLab.Encodings.BinaryVectorEncoding;
 using HeuristicLab.Optimization;
-using HeuristicLab.Optimization.LocalSearch;
 using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
 
-namespace HeuristicLab.Encodings.Binary.LocalSearch {
-  [Item("Exhaustive Bitflip Local (Subspace) Search (binary)", "")]
+namespace HeuristicLab.Algorithms.MemPR.Binary.LocalSearch {
+  [Item("Exhaustive Bitflip Local (Subspace) Search (binary)", "", ExcludeGenericTypeInfo = true)]
   [StorableClass]
-  public class ExhaustiveBitflipSubspace<TContext> : ExhaustiveBitflipOperator, IBinaryLocalSearch<TContext>
-      where TContext : ISingleObjectiveSolutionContext<BinaryVector>, IStochasticContext, IMaximizationContext,
-                       IEvaluatedSolutionsContext, IIterationsManipulationContext, IBinarySolutionSubspaceContext {
+  public class ExhaustiveBitflipSubspace<TContext> : NamedItem, ILocalSearch<TContext>
+      where TContext : ISingleSolutionHeuristicAlgorithmContext<SingleObjectiveBasicProblem<BinaryVectorEncoding>, BinaryVector>, IBinaryVectorSubspaceContext {
 
     [StorableConstructor]
     protected ExhaustiveBitflipSubspace(bool deserializing) : base(deserializing) { }
     protected ExhaustiveBitflipSubspace(ExhaustiveBitflipSubspace<TContext> original, Cloner cloner) : base(original, cloner) { }
-    public ExhaustiveBitflipSubspace() { }
+    public ExhaustiveBitflipSubspace() {
+      Name = ItemName;
+      Description = ItemDescription;
+    }
 
     public override IDeepCloneable Clone(Cloner cloner) {
@@ -44,9 +48,10 @@
 
     public void Optimize(TContext context) {
+      var evalWrapper = new EvaluationWrapper(context);
       var quality = context.Solution.Fitness;
       try {
-        var result = Heuristic.ExhaustiveBitFlipSearch(context.Random, context.Solution.Solution, ref quality,
-          context.Maximization, EvaluateFunc, CancellationToken, context.Subspace != null ? context.Subspace.Subspace : null);
-        context.EvaluatedSolutions = result.Item1;
+        var result = ExhaustiveBitflip.Optimize(context.Random, context.Solution.Solution, ref quality,
+          context.Problem.Maximization, evalWrapper.Evaluate, CancellationToken.None, context.Subspace.Subspace);
+        context.IncrementEvaluatedSolutions(result.Item1);
         context.Iterations = result.Item2;
       } finally {
@@ -54,4 +59,24 @@
       }
     }
+
+    public sealed class EvaluationWrapper {
+      private readonly TContext context;
+      private readonly ISingleObjectiveSolutionScope<BinaryVector> scope;
+      private readonly SingleEncodingIndividual individual;
+
+      public EvaluationWrapper(TContext context) {
+        this.context = context;
+        // don't clone the solution, which is thrown away again
+        var cloner = new Cloner();
+        cloner.RegisterClonedObject(context.Solution.Solution, null);
+        this.scope = (ISingleObjectiveSolutionScope<BinaryVector>)context.Solution.Clone(cloner);
+        this.individual = new SingleEncodingIndividual(context.Problem.Encoding, this.scope);
+      }
+
+      public double Evaluate(BinaryVector b) {
+        scope.Solution = b;
+        return context.Problem.Evaluate(individual, null);
+      }
+    }
   }
 }
Index: anches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/Binary/LocalSearch/Heuristic.cs
===================================================================
--- /branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/Binary/LocalSearch/Heuristic.cs	(revision 14449)
+++ 	(revision )
@@ -1,71 +1,0 @@
-﻿#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.Linq;
-using System.Threading;
-using HeuristicLab.Core;
-using HeuristicLab.Encodings.BinaryVectorEncoding;
-using HeuristicLab.Random;
-
-namespace HeuristicLab.Encodings.Binary.LocalSearch {
-  public static class Heuristic {
-    private static bool IsBetter(bool maximization, double a, double b) {
-      return maximization && a > b
-        || !maximization && a < b;
-    }
-
-    public static Tuple<int, int> ExhaustiveBitFlipSearch(IRandom random, BinaryVector solution, ref double quality, bool maximization, Func<BinaryVector, double> evalFunc, CancellationToken token, bool[] subspace = null) {
-      if (double.IsNaN(quality)) quality = evalFunc(solution);
-      var improved = false;
-      var order = Enumerable.Range(0, solution.Length).Shuffle(random).ToArray();
-      var lastImp = -1;
-      var steps = 0;
-      var evaluations = 0;
-      do {
-        improved = false;
-        for (var i = 0; i < solution.Length; i++) {
-          // in case we didn't make an improvement this round and arrived at the index of the last improvement
-          // break means we don't need to try the remaining moves again as they have brought no improvement
-          if (!improved && lastImp == i) break;
-          var idx = order[i];
-          if (subspace != null && !subspace[idx]) continue;
-          // bitflip the solution
-          solution[idx] = !solution[idx];
-          var after = evalFunc(solution);
-          evaluations++;
-          if (IsBetter(maximization, after, quality)) {
-            steps++;
-            quality = after;
-            lastImp = i;
-            improved = true;
-          } else {
-            // undo the bitflip in case no improvement was made
-            solution[idx] = !solution[idx];
-          }
-          token.ThrowIfCancellationRequested();
-        }
-      } while (improved);
-      
-      return Tuple.Create(evaluations, steps);
-    }
-  }
-}
Index: /branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/Binary/LocalSearch/StaticAPI/ExhaustiveBitflip.cs
===================================================================
--- /branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/Binary/LocalSearch/StaticAPI/ExhaustiveBitflip.cs	(revision 14450)
+++ /branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/Binary/LocalSearch/StaticAPI/ExhaustiveBitflip.cs	(revision 14450)
@@ -0,0 +1,67 @@
+﻿#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.Linq;
+using System.Threading;
+using HeuristicLab.Algorithms.MemPR.Util;
+using HeuristicLab.Core;
+using HeuristicLab.Encodings.BinaryVectorEncoding;
+using HeuristicLab.Random;
+
+namespace HeuristicLab.Encodings.Binary.LocalSearch {
+  public static class ExhaustiveBitflip {
+    public static Tuple<int, int> Optimize(IRandom random, BinaryVector solution, ref double quality, bool maximization, Func<BinaryVector, double> evalFunc, CancellationToken token, bool[] subspace = null) {
+      if (double.IsNaN(quality)) quality = evalFunc(solution);
+      var improved = false;
+      var order = Enumerable.Range(0, solution.Length).Shuffle(random).ToArray();
+      var lastImp = -1;
+      var steps = 0;
+      var evaluations = 0;
+      do {
+        improved = false;
+        for (var i = 0; i < solution.Length; i++) {
+          // in case we didn't make an improvement this round and arrived at the index of the last improvement
+          // break means we don't need to try the remaining moves again as they have brought no improvement
+          if (!improved && lastImp == i) break;
+          var idx = order[i];
+          if (subspace != null && !subspace[idx]) continue;
+          // bitflip the solution
+          solution[idx] = !solution[idx];
+          var after = evalFunc(solution);
+          evaluations++;
+          if (FitnessComparer.IsBetter(maximization, after, quality)) {
+            steps++;
+            quality = after;
+            lastImp = i;
+            improved = true;
+          } else {
+            // undo the bitflip in case no improvement was made
+            solution[idx] = !solution[idx];
+          }
+          token.ThrowIfCancellationRequested();
+        }
+      } while (improved);
+
+      return Tuple.Create(evaluations, steps);
+    }
+  }
+}
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 14449)
+++ /branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/Binary/SolutionModel/Univariate/BiasedModelTrainer.cs	(revision 14450)
@@ -21,21 +21,35 @@
 
 using System.Linq;
+using HeuristicLab.Algorithms.MemPR.Interfaces;
 using HeuristicLab.Common;
 using HeuristicLab.Core;
+using HeuristicLab.Data;
 using HeuristicLab.Encodings.BinaryVectorEncoding;
 using HeuristicLab.Optimization;
-using HeuristicLab.Optimization.SolutionModel;
+using HeuristicLab.Parameters;
 using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
 
-namespace HeuristicLab.Encodings.Binary.SolutionModel.Univariate {
-  [Item("Biased Univariate Model Trainer (binary)", "")]
+namespace HeuristicLab.Algorithms.MemPR.Binary.SolutionModel.Univariate {
+  [Item("Biased Univariate Model Trainer (binary)", "", ExcludeGenericTypeInfo = true)]
   [StorableClass]
-  public class BiasedModelTrainer<TContext> : BiasedModelTrainerOperator, IBinarySolutionModelTrainer<TContext>, IBinaryVectorOperator
-    where TContext : ISingleObjectivePopulationContext<BinaryVector>, ISolutionModelContext<BinaryVector>, IStochasticContext, IMaximizationContext {
+  public class BiasedModelTrainer<TContext> : ParameterizedNamedItem, ISolutionModelTrainer<TContext>
+    where TContext : IPopulationBasedHeuristicAlgorithmContext<SingleObjectiveBasicProblem<BinaryVectorEncoding>, BinaryVector>, ISolutionModelContext<BinaryVector> {
     
+    [Storable]
+    private IValueParameter<EnumValue<ModelBiasOptions>> modelBiasParameter;
+    public ModelBiasOptions ModelBias {
+      get { return modelBiasParameter.Value.Value; }
+      set { modelBiasParameter.Value.Value = value; }
+    }
+
     [StorableConstructor]
     protected BiasedModelTrainer(bool deserializing) : base(deserializing) { }
-    protected BiasedModelTrainer(BiasedModelTrainer<TContext> original, Cloner cloner) : base(original, cloner) { }
-    public BiasedModelTrainer() { }
+    protected BiasedModelTrainer(BiasedModelTrainer<TContext> original, Cloner cloner)
+      : base(original, cloner) {
+      modelBiasParameter = cloner.Clone(original.modelBiasParameter);
+    }
+    public BiasedModelTrainer() {
+      Parameters.Add(modelBiasParameter = new ValueParameter<EnumValue<ModelBiasOptions>>("Model Bias", "What kind of bias towards better individuals is chosen."));
+    }
 
     public override IDeepCloneable Clone(Cloner cloner) {
@@ -44,5 +58,5 @@
 
     public void TrainModel(TContext context) {
-      context.Model = Trainer.TrainBiased(ModelBias, context.Random, context.Maximization, context.Population.Select(x => x.Solution), context.Population.Select(x => x.Fitness));
+      context.Model = Trainer.TrainBiased(ModelBias, context.Random, context.Problem.Maximization, context.Population.Select(x => x.Solution), context.Population.Select(x => x.Fitness));
     }
   }
Index: anches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/Binary/SolutionModel/Univariate/BiasedModelTrainerOperator.cs
===================================================================
--- /branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/Binary/SolutionModel/Univariate/BiasedModelTrainerOperator.cs	(revision 14449)
+++ 	(revision )
@@ -1,94 +1,0 @@
-﻿#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.Linq;
-using HeuristicLab.Common;
-using HeuristicLab.Core;
-using HeuristicLab.Data;
-using HeuristicLab.Encodings.BinaryVectorEncoding;
-using HeuristicLab.Operators;
-using HeuristicLab.Optimization.SolutionModel;
-using HeuristicLab.Parameters;
-using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
-
-namespace HeuristicLab.Encodings.Binary.SolutionModel.Univariate {
-  [Item("Biased Univariate Model Trainer Operator (binary)", "")]
-  [StorableClass]
-  public class BiasedModelTrainerOperator : SingleSuccessorOperator, ISolutionModelTrainer<BinaryVector> {
-
-    public ILookupParameter<IRandom> RandomParameter {
-      get { return (ILookupParameter<IRandom>)Parameters["Random"]; }
-    }
-
-    public ILookupParameter<BoolValue> MaximizationParameter {
-      get { return (ILookupParameter<BoolValue>)Parameters["Maximization"]; }
-    }
-
-    public IScopeTreeLookupParameter<DoubleValue> QualityParameter {
-      get { return (IScopeTreeLookupParameter<DoubleValue>)Parameters["Quality"]; }
-    }
-
-    public IScopeTreeLookupParameter<BinaryVector> SolutionParameter {
-      get { return (IScopeTreeLookupParameter<BinaryVector>)Parameters["Solution"]; }
-    }
-
-    public ILookupParameter<ISolutionModel<BinaryVector>> SamplingModelParameter {
-      get { return (ILookupParameter<ISolutionModel<BinaryVector>>)Parameters["SamplingModel"]; }
-    }
-
-    private IValueParameter<EnumValue<ModelBiasOptions>> ModelBiasParameter {
-      get { return (IValueParameter<EnumValue<ModelBiasOptions>>)Parameters["ModelBias"]; }
-    }
-
-    public ModelBiasOptions ModelBias {
-      get { return ModelBiasParameter.Value.Value; }
-      set { ModelBiasParameter.Value.Value = value; }
-    }
-
-    [StorableConstructor]
-    protected BiasedModelTrainerOperator(bool deserializing) : base(deserializing) { }
-    protected BiasedModelTrainerOperator(BiasedModelTrainerOperator original, Cloner cloner) : base(original, cloner) { }
-    public BiasedModelTrainerOperator() {
-      Parameters.Add(new LookupParameter<IRandom>("Random", "The random number generator to use."));
-      Parameters.Add(new LookupParameter<BoolValue>("Maximization", "Whether to maximize fitness or minimize it (only used when bias is not 'None')."));
-      Parameters.Add(new ScopeTreeLookupParameter<DoubleValue>("Quality", "The solution quality (only used when bias is not 'None')."));
-      Parameters.Add(new ScopeTreeLookupParameter<BinaryVector>("Solution", "The binary vectors that are used to create the sampling model."));
-      Parameters.Add(new LookupParameter<ISolutionModel<BinaryVector>>("SamplingModel", "The model that can be used to sample new solutions."));
-      Parameters.Add(new ValueParameter<EnumValue<ModelBiasOptions>>("ModelBias",
-@"What kind of bias should be used when creating the model, e.g. 
-no bias (all solutions are considered equally), rank-based bias 
-(higher ranked solutions contribute more), or fitness-based bias 
-(fitness proportional bias)", new EnumValue<ModelBiasOptions>(ModelBiasOptions.Rank)));
-
-      SolutionParameter.ActualName = "BinaryVector";
-    }
-
-    public override IDeepCloneable Clone(Cloner cloner) {
-      return new BiasedModelTrainerOperator(this, cloner);
-    }
-
-    public override IOperation Apply() {
-      SamplingModelParameter.ActualValue = Trainer.TrainBiased(ModelBias, RandomParameter.ActualValue,
-        MaximizationParameter.ActualValue.Value, SolutionParameter.ActualValue, QualityParameter.ActualValue.Select(x => x.Value));
-      return base.Apply();
-    }
-  }
-}
Index: /branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/Binary/SolutionModel/Univariate/StaticAPI/Trainer.cs
===================================================================
--- /branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/Binary/SolutionModel/Univariate/StaticAPI/Trainer.cs	(revision 14450)
+++ /branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/Binary/SolutionModel/Univariate/StaticAPI/Trainer.cs	(revision 14450)
@@ -0,0 +1,47 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2016 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using HeuristicLab.Algorithms.MemPR.Interfaces;
+using HeuristicLab.Core;
+using HeuristicLab.Encodings.BinaryVectorEncoding;
+
+namespace HeuristicLab.Algorithms.MemPR.Binary.SolutionModel.Univariate {
+  public enum ModelBiasOptions { Rank, Fitness }
+
+  public static class Trainer {
+    public static ISolutionModel<BinaryVector> TrainBiased(ModelBiasOptions modelBias, IRandom random, bool maximization, IEnumerable<BinaryVector> population, IEnumerable<double> qualities) {
+      switch (modelBias) {
+        case ModelBiasOptions.Rank:
+          return UnivariateModel.CreateWithRankBias(random, maximization, population, qualities);
+        case ModelBiasOptions.Fitness:
+          return UnivariateModel.CreateWithFitnessBias(random, maximization, population, qualities);
+        default:
+          throw new InvalidOperationException(string.Format("Unknown bias option {0}", modelBias));
+      }
+    }
+
+    public static ISolutionModel<BinaryVector> TrainUnbiased(IRandom random, IEnumerable<BinaryVector> population) {
+      return UnivariateModel.CreateWithoutBias(random, population);
+    }
+  }
+}
Index: anches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/Binary/SolutionModel/Univariate/Trainer.cs
===================================================================
--- /branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/Binary/SolutionModel/Univariate/Trainer.cs	(revision 14449)
+++ 	(revision )
@@ -1,47 +1,0 @@
-﻿#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 HeuristicLab.Core;
-using HeuristicLab.Encodings.BinaryVectorEncoding;
-using HeuristicLab.Optimization.SolutionModel;
-
-namespace HeuristicLab.Encodings.Binary.SolutionModel.Univariate {
-  public enum ModelBiasOptions { Rank, Fitness }
-
-  public static class Trainer {
-    public static ISolutionModel<BinaryVector> TrainBiased(ModelBiasOptions modelBias, IRandom random, bool maximization, IEnumerable<BinaryVector> population, IEnumerable<double> qualities) {
-      switch (modelBias) {
-        case ModelBiasOptions.Rank:
-          return UnivariateModel.CreateWithRankBias(random, maximization, population, qualities);
-        case ModelBiasOptions.Fitness:
-          return UnivariateModel.CreateWithFitnessBias(random, maximization, population, qualities);
-        default:
-          throw new InvalidOperationException(string.Format("Unknown bias option {0}", modelBias));
-      }
-    }
-
-    public static ISolutionModel<BinaryVector> TrainUnbiased(IRandom random, IEnumerable<BinaryVector> population) {
-      return UnivariateModel.CreateWithoutBias(random, population);
-    }
-  }
-}
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 14449)
+++ /branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/Binary/SolutionModel/Univariate/UnbiasedModelTrainer.cs	(revision 14450)
@@ -21,28 +21,31 @@
 
 using System.Linq;
+using HeuristicLab.Algorithms.MemPR.Interfaces;
 using HeuristicLab.Common;
 using HeuristicLab.Core;
 using HeuristicLab.Encodings.BinaryVectorEncoding;
 using HeuristicLab.Optimization;
-using HeuristicLab.Optimization.SolutionModel;
 using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
 
-namespace HeuristicLab.Encodings.Binary.SolutionModel.Univariate {
-  [Item("Uniased Univariate Model Trainer (binary)", "")]
+namespace HeuristicLab.Algorithms.MemPR.Binary.SolutionModel.Univariate {
+  [Item("Unbiased Univariate Model Trainer (binary)", "", ExcludeGenericTypeInfo = true)]
   [StorableClass]
-  public class UnbiasedModelTrainer<TContext> : UnbiasedModelTrainerOperator, IBinarySolutionModelTrainer<TContext>
-    where TContext : ISolutionModelContext<BinaryVector>, IPopulationContext<BinaryVector>, IStochasticContext {
+  public class UniasedModelTrainer<TContext> : NamedItem, ISolutionModelTrainer<TContext>
+    where TContext : IPopulationBasedHeuristicAlgorithmContext<SingleObjectiveBasicProblem<BinaryVectorEncoding>, BinaryVector>, ISolutionModelContext<BinaryVector> {
     
     [StorableConstructor]
-    protected UnbiasedModelTrainer(bool deserializing) : base(deserializing) { }
-    protected UnbiasedModelTrainer(UnbiasedModelTrainer<TContext> original, Cloner cloner) : base(original, cloner) { }
-    public UnbiasedModelTrainer() { }
+    protected UniasedModelTrainer(bool deserializing) : base(deserializing) { }
+    protected UniasedModelTrainer(UniasedModelTrainer<TContext> original, Cloner cloner) : base(original, cloner) { }
+    public UniasedModelTrainer() {
+      Name = ItemName;
+      Description = ItemDescription;
+    }
 
     public override IDeepCloneable Clone(Cloner cloner) {
-      return new UnbiasedModelTrainer<TContext>(this, cloner);
+      return new UniasedModelTrainer<TContext>(this, cloner);
     }
 
     public void TrainModel(TContext context) {
-      context.Model = UnivariateModel.CreateWithoutBias(context.Random, context.Population.Select(x => x.Solution));
+      context.Model = Trainer.TrainUnbiased(context.Random, context.Population.Select(x => x.Solution));
     }
   }
Index: anches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/Binary/SolutionModel/Univariate/UnbiasedModelTrainerOperator.cs
===================================================================
--- /branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/Binary/SolutionModel/Univariate/UnbiasedModelTrainerOperator.cs	(revision 14449)
+++ 	(revision )
@@ -1,67 +1,0 @@
-﻿#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.Encodings.BinaryVectorEncoding;
-using HeuristicLab.Operators;
-using HeuristicLab.Optimization.SolutionModel;
-using HeuristicLab.Parameters;
-using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
-
-namespace HeuristicLab.Encodings.Binary.SolutionModel.Univariate {
-  [Item("Uniased Univariate Model Trainer Operator (binary)", "")]
-  [StorableClass]
-  public class UnbiasedModelTrainerOperator : SingleSuccessorOperator, ISolutionModelTrainer<BinaryVector> {
-
-    public ILookupParameter<IRandom> RandomParameter {
-      get { return (ILookupParameter<IRandom>)Parameters["Random"]; }
-    }
-    
-    public IScopeTreeLookupParameter<BinaryVector> SolutionParameter {
-      get { return (IScopeTreeLookupParameter<BinaryVector>)Parameters["Solution"]; }
-    }
-
-    public ILookupParameter<ISolutionModel<BinaryVector>> SamplingModelParameter {
-      get { return (ILookupParameter<ISolutionModel<BinaryVector>>)Parameters["SamplingModel"]; }
-    }
-
-    [StorableConstructor]
-    protected UnbiasedModelTrainerOperator(bool deserializing) : base(deserializing) { }
-    protected UnbiasedModelTrainerOperator(UnbiasedModelTrainerOperator original, Cloner cloner) : base(original, cloner) { }
-    public UnbiasedModelTrainerOperator() {
-      Parameters.Add(new LookupParameter<IRandom>("Random", "The random number generator to use."));
-      Parameters.Add(new ScopeTreeLookupParameter<BinaryVector>("Solution", "The binary vectors that are used to create the sampling model."));
-      Parameters.Add(new LookupParameter<ISolutionModel<BinaryVector>>("SamplingModel", "The model that can be used to sample new solutions."));
-
-      SolutionParameter.ActualName = "BinaryVector";
-    }
-
-    public override IDeepCloneable Clone(Cloner cloner) {
-      return new UnbiasedModelTrainerOperator(this, cloner);
-    }
-    
-    public override IOperation Apply() {
-      SamplingModelParameter.ActualValue = UnivariateModel.CreateWithoutBias(RandomParameter.ActualValue, SolutionParameter.ActualValue);
-      return base.Apply();
-    }
-  }
-}
Index: /branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/Binary/SolutionModel/Univariate/UnivariateSolutionModel.cs
===================================================================
--- /branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/Binary/SolutionModel/Univariate/UnivariateSolutionModel.cs	(revision 14449)
+++ /branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/Binary/SolutionModel/Univariate/UnivariateSolutionModel.cs	(revision 14450)
@@ -23,13 +23,13 @@
 using System.Collections.Generic;
 using System.Linq;
+using HeuristicLab.Algorithms.MemPR.Interfaces;
 using HeuristicLab.Common;
 using HeuristicLab.Core;
 using HeuristicLab.Data;
 using HeuristicLab.Encodings.BinaryVectorEncoding;
-using HeuristicLab.Optimization.SolutionModel;
 using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
 using HeuristicLab.Random;
 
-namespace HeuristicLab.Encodings.Binary.SolutionModel.Univariate {
+namespace HeuristicLab.Algorithms.MemPR.Binary.SolutionModel.Univariate {
   [Item("Univariate solution model (binary)", "")]
   [StorableClass]
Index: /branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/HeuristicLab.Algorithms.MemPR-3.3.csproj
===================================================================
--- /branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/HeuristicLab.Algorithms.MemPR-3.3.csproj	(revision 14449)
+++ /branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/HeuristicLab.Algorithms.MemPR-3.3.csproj	(revision 14450)
@@ -90,14 +90,25 @@
     <Compile Include="Binary\LocalSearch\ExhaustiveBitflipSubspace.cs" />
     <Compile Include="Binary\LocalSearch\ExhaustiveBitflip.cs" />
-    <Compile Include="Binary\LocalSearch\ExhaustiveBitflipOperator.cs" />
-    <Compile Include="Binary\LocalSearch\Heuristic.cs" />
-    <Compile Include="Binary\SolutionModel\Univariate\BiasedModelTrainerOperator.cs" />
-    <Compile Include="Binary\SolutionModel\Univariate\Trainer.cs" />
-    <Compile Include="Binary\SolutionModel\Univariate\UnbiasedModelTrainerOperator.cs" />
+    <Compile Include="Binary\LocalSearch\StaticAPI\ExhaustiveBitflip.cs" />
+    <Compile Include="Binary\SolutionModel\Univariate\StaticAPI\Trainer.cs" />
     <Compile Include="Binary\SolutionModel\Univariate\UnivariateSolutionModel.cs" />
     <Compile Include="Binary\SolutionModel\Univariate\BiasedModelTrainer.cs" />
     <Compile Include="Binary\SolutionModel\Univariate\UnbiasedModelTrainer.cs" />
-    <Compile Include="Optimization\Interfaces.cs" />
+    <Compile Include="Interfaces\Interfaces.cs" />
     <Compile Include="MemPRAlgorithm.cs" />
+    <Compile Include="Permutation\PermutationMemPR.cs" />
+    <Compile Include="Permutation\PermutationMemPRContext.cs" />
+    <Compile Include="Permutation\LocalSearch\ExhaustiveHillClimbSubspace.cs" />
+    <Compile Include="Permutation\LocalSearch\ExhaustiveHillClimb.cs" />
+    <Compile Include="Permutation\PermutationSolutionSubspace.cs" />
+    <Compile Include="Permutation\LocalSearch\StaticAPI\Exhaustive.cs" />
+    <Compile Include="Permutation\LocalSearch\StaticAPI\Exhaustive1Shift.cs" />
+    <Compile Include="Permutation\LocalSearch\StaticAPI\Exhaustive2Opt.cs" />
+    <Compile Include="Permutation\LocalSearch\StaticAPI\ExhaustiveSwap2.cs" />
+    <Compile Include="Permutation\SimilarityCalculator.cs" />
+    <Compile Include="Permutation\SolutionModel\Univariate\StaticAPI\Trainer.cs" />
+    <Compile Include="Permutation\SolutionModel\Univariate\UnbiasedModelTrainer.cs" />
+    <Compile Include="Permutation\SolutionModel\Univariate\UnivariateRelativeModel.cs" />
+    <Compile Include="Permutation\SolutionModel\Univariate\UnivariateAbsoluteModel.cs" />
     <Compile Include="SingleObjectiveSolutionScope.cs" />
     <Compile Include="MemPRContext.cs" />
@@ -105,4 +116,6 @@
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="Util\CkMeans1D.cs" />
+    <Compile Include="Util\EvaluationWrapper.cs" />
+    <Compile Include="Util\FitnessComparer.cs" />
   </ItemGroup>
   <ItemGroup>
@@ -142,4 +155,9 @@
       <Private>False</Private>
     </ProjectReference>
+    <ProjectReference Include="..\..\HeuristicLab.Encodings.PermutationEncoding\3.3\HeuristicLab.Encodings.PermutationEncoding-3.3.csproj">
+      <Project>{dbecb8b0-b166-4133-baf1-ed67c3fd7fca}</Project>
+      <Name>HeuristicLab.Encodings.PermutationEncoding-3.3</Name>
+      <Private>False</Private>
+    </ProjectReference>
     <ProjectReference Include="..\..\HeuristicLab.Operators\3.3\HeuristicLab.Operators-3.3.csproj">
       <Project>{23da7ff4-d5b8-41b6-aa96-f0561d24f3ee}</Project>
@@ -176,4 +194,5 @@
     <None Include="HeuristicLab.snk" />
   </ItemGroup>
+  <ItemGroup />
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
   <PropertyGroup>
Index: /branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/Interfaces/Interfaces.cs
===================================================================
--- /branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/Interfaces/Interfaces.cs	(revision 14450)
+++ /branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/Interfaces/Interfaces.cs	(revision 14450)
@@ -0,0 +1,111 @@
+﻿#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.Collections.Generic;
+using HeuristicLab.Algorithms.MemPR.Binary;
+using HeuristicLab.Algorithms.MemPR.Permutation;
+using HeuristicLab.Core;
+using HeuristicLab.Encodings.BinaryVectorEncoding;
+using HeuristicLab.Optimization;
+
+namespace HeuristicLab.Algorithms.MemPR.Interfaces {
+
+  /*************************************************
+   * ********************************************* *
+   *                    DATA                       *
+   * ********************************************* *
+   *************************************************/
+
+  public interface ISolutionModel<TSolution> : IItem {
+    TSolution Sample();
+  }
+
+  public interface ISolutionSubspace<TSolution> : IItem { }
+
+  /*************************************************
+   * ********************************************* *
+   *                  OPERATORS                    *
+   * ********************************************* *
+   *************************************************/
+   
+  public interface ISolutionModelTrainer<TContext> : IItem {
+    void TrainModel(TContext context);
+  }
+
+  public interface ILocalSearch<TContext> : IItem {
+    void Optimize(TContext context);
+  }
+  
+  /*************************************************
+   * ********************************************* *
+   *                  CONTEXTS                     *
+   * ********************************************* *
+   *************************************************/
+
+  public interface IHeuristicAlgorithmContext<TProblem, TSolution> : IExecutionContext
+      where TProblem : class, ISingleObjectiveProblemDefinition {
+    TProblem Problem { get; }
+    IRandom Random { get; }
+    int Iterations { get; set; }
+    int EvaluatedSolutions { get; }
+    void IncrementEvaluatedSolutions(int byEvaluations);
+    double BestQuality { get; set; }
+    TSolution BestSolution { get; set; }
+  }
+
+  public interface IPopulationBasedHeuristicAlgorithmContext<TProblem, TSolution> : IHeuristicAlgorithmContext<TProblem, TSolution>
+      where TProblem : class, ISingleObjectiveProblemDefinition {
+    IEnumerable<ISingleObjectiveSolutionScope<TSolution>> Population { get; }
+  }
+
+  public interface ISingleSolutionHeuristicAlgorithmContext<TProblem, TSolution> : IHeuristicAlgorithmContext<TProblem, TSolution>
+      where TProblem : class, ISingleObjectiveProblemDefinition {
+    ISingleObjectiveSolutionScope<TSolution> Solution { get; }
+  }
+
+  public interface ISolutionModelContext<TSolution> : IExecutionContext {
+    ISolutionModel<TSolution> Model { get; set; }
+  }
+
+  public interface ISolutionSubspaceContext<TSolution> : IExecutionContext {
+    ISolutionSubspace<TSolution> Subspace { get; }
+  }
+  public interface IBinaryVectorSubspaceContext : ISolutionSubspaceContext<BinaryVector> {
+    new BinarySolutionSubspace Subspace { get; }
+  }
+  public interface IPermutationSubspaceContext : ISolutionSubspaceContext<Encodings.PermutationEncoding.Permutation> {
+    new PermutationSolutionSubspace Subspace { get; }
+  }
+
+
+  /*************************************************
+   * ********************************************* *
+   *                   SCOPES                      *
+   * ********************************************* *
+   *************************************************/
+
+  public interface ISingleObjectiveSolutionScope<TSolution> : IScope {
+    TSolution Solution { get; set; }
+    double Fitness { get; set; }
+
+    void Adopt(ISingleObjectiveSolutionScope<TSolution> orphan);
+  }
+}
Index: /branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/MemPRAlgorithm.cs
===================================================================
--- /branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/MemPRAlgorithm.cs	(revision 14449)
+++ /branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/MemPRAlgorithm.cs	(revision 14450)
@@ -26,4 +26,5 @@
 using System.Runtime.CompilerServices;
 using System.Threading;
+using HeuristicLab.Algorithms.MemPR.Interfaces;
 using HeuristicLab.Algorithms.MemPR.Util;
 using HeuristicLab.Analysis;
@@ -32,6 +33,4 @@
 using HeuristicLab.Data;
 using HeuristicLab.Optimization;
-using HeuristicLab.Optimization.LocalSearch;
-using HeuristicLab.Optimization.SolutionModel;
 using HeuristicLab.Parameters;
 using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
@@ -40,24 +39,18 @@
   [Item("MemPR Algorithm", "Base class for MemPR algorithms")]
   [StorableClass]
-  public abstract class MemPRAlgorithm<TSolution, TContext, TSolutionContext> : BasicAlgorithm, INotifyPropertyChanged
+  public abstract class MemPRAlgorithm<TProblem, TSolution, TPopulationContext, TSolutionContext> : BasicAlgorithm, INotifyPropertyChanged
+      where TProblem : class, IItem, ISingleObjectiveHeuristicOptimizationProblem, ISingleObjectiveProblemDefinition
       where TSolution : class, IItem
-      where TContext : MemPRContext<TSolution, TContext, TSolutionContext>, new()
-      where TSolutionContext : SingleSolutionMemPRContext<TSolution, TContext, TSolutionContext> {
+      where TPopulationContext : MemPRPopulationContext<TProblem, TSolution, TPopulationContext, TSolutionContext>, new()
+      where TSolutionContext : MemPRSolutionContext<TProblem, TSolution, TPopulationContext, TSolutionContext> {
     private const double MutationProbabilityMagicConst = 0.1;
 
     public override Type ProblemType {
-      get { return typeof(ISingleObjectiveHeuristicOptimizationProblem); }
-    }
-
-    public new ISingleObjectiveHeuristicOptimizationProblem Problem {
-      get { return (ISingleObjectiveHeuristicOptimizationProblem)base.Problem; }
+      get { return typeof(TProblem); }
+    }
+
+    public new TProblem Problem {
+      get { return (TProblem)base.Problem; }
       set { base.Problem = value; }
-    }
-
-    protected bool Maximization {
-      get {
-        return Problem != null && Problem.MaximizationParameter is IValueParameter<BoolValue>
-          && ((IValueParameter<BoolValue>)Problem.MaximizationParameter).Value.Value;
-      }
     }
 
@@ -122,15 +115,15 @@
     }
 
-    public IConstrainedValueParameter<ISolutionModelTrainer<TSolution, TContext>> SolutionModelTrainerParameter {
-      get { return (IConstrainedValueParameter<ISolutionModelTrainer<TSolution, TContext>>)Parameters["SolutionModelTrainer"]; }
-    }
-
-    public IConstrainedValueParameter<ILocalSearch<TSolution, TSolutionContext>> LocalSearchParameter {
-      get { return (IConstrainedValueParameter<ILocalSearch<TSolution, TSolutionContext>>)Parameters["LocalSearch"]; }
+    public IConstrainedValueParameter<ISolutionModelTrainer<TPopulationContext>> SolutionModelTrainerParameter {
+      get { return (IConstrainedValueParameter<ISolutionModelTrainer<TPopulationContext>>)Parameters["SolutionModelTrainer"]; }
+    }
+
+    public IConstrainedValueParameter<ILocalSearch<TSolutionContext>> LocalSearchParameter {
+      get { return (IConstrainedValueParameter<ILocalSearch<TSolutionContext>>)Parameters["LocalSearch"]; }
     }
 
     [Storable]
-    private TContext context;
-    public TContext Context {
+    private TPopulationContext context;
+    public TPopulationContext Context {
       get { return context; }
       protected set {
@@ -146,5 +139,5 @@
     [StorableConstructor]
     protected MemPRAlgorithm(bool deserializing) : base(deserializing) { }
-    protected MemPRAlgorithm(MemPRAlgorithm<TSolution, TContext, TSolutionContext> original, Cloner cloner) : base(original, cloner) {
+    protected MemPRAlgorithm(MemPRAlgorithm<TProblem, TSolution, TPopulationContext, TSolutionContext> original, Cloner cloner) : base(original, cloner) {
       context = cloner.Clone(original.context);
       qualityAnalyzer = cloner.Clone(original.qualityAnalyzer);
@@ -159,6 +152,6 @@
       Parameters.Add(new FixedValueParameter<BoolValue>("SetSeedRandomly", "Whether each run of the algorithm should be conducted with a new random seed.", new BoolValue(true)));
       Parameters.Add(new FixedValueParameter<IntValue>("Seed", "The random number seed that is used in case SetSeedRandomly is false.", new IntValue(0)));
-      Parameters.Add(new ConstrainedValueParameter<ISolutionModelTrainer<TSolution, TContext>>("SolutionModelTrainer", "The object that creates a solution model that can be sampled."));
-      Parameters.Add(new ConstrainedValueParameter<ILocalSearch<TSolution, TSolutionContext>>("LocalSearch", "The local search operator to use."));
+      Parameters.Add(new ConstrainedValueParameter<ISolutionModelTrainer<TPopulationContext>>("SolutionModelTrainer", "The object that creates a solution model that can be sampled."));
+      Parameters.Add(new ConstrainedValueParameter<ILocalSearch<TSolutionContext>>("LocalSearch", "The local search operator to use."));
 
       qualityAnalyzer = new BestAverageWorstQualityAnalyzer();
@@ -211,6 +204,6 @@
     }
 
-    protected virtual TContext CreateContext() {
-      return new TContext();
+    protected virtual TPopulationContext CreateContext() {
+      return new TPopulationContext();
     }
 
@@ -221,5 +214,5 @@
         Context.Random.Reset(Seed);
         Context.Scope.Variables.Add(new Variable("Results", Results));
-        Context.Maximization = Maximization;
+        Context.Problem = Problem;
       }
 
@@ -303,5 +296,5 @@
           }
         } else {
-          offspring = (SingleObjectiveSolutionScope<TSolution>)Context.AtPopulation(Context.Random.Next(Context.PopulationCount)).Clone();
+          offspring = (ISingleObjectiveSolutionScope<TSolution>)Context.AtPopulation(Context.Random.Next(Context.PopulationCount)).Clone();
           Mutate(offspring, token);
           PerformTabuWalk(offspring, Context.HcSteps, token);
@@ -458,6 +451,6 @@
     protected bool IsBetter(double a, double b) {
       return double.IsNaN(b) && !double.IsNaN(a)
-        || Maximization && a > b
-        || !Maximization && a < b;
+        || Problem.Maximization && a > b
+        || !Problem.Maximization && a < b;
     }
     
@@ -465,5 +458,5 @@
     protected abstract double Dist(ISingleObjectiveSolutionScope<TSolution> a, ISingleObjectiveSolutionScope<TSolution> b);
     protected abstract ISingleObjectiveSolutionScope<TSolution> ToScope(TSolution code, double fitness = double.NaN);
-    protected abstract ISolutionSubspace CalculateSubspace(IEnumerable<TSolution> solutions, bool inverse = false);
+    protected abstract ISolutionSubspace<TSolution> CalculateSubspace(IEnumerable<TSolution> solutions, bool inverse = false);
     protected virtual void Evaluate(ISingleObjectiveSolutionScope<TSolution> scope, CancellationToken token) {
       Context.EvaluatedSolutions++;
@@ -478,9 +471,13 @@
 
     #region Create
-    protected abstract ISingleObjectiveSolutionScope<TSolution> Create(CancellationToken token);
+    protected virtual ISingleObjectiveSolutionScope<TSolution> Create(CancellationToken token) {
+      var child = ToScope(null);
+      RunOperator(Problem.SolutionCreator, child, token);
+      return child;
+    }
     #endregion
 
     #region Improve
-    protected virtual int HillClimb(ISingleObjectiveSolutionScope<TSolution> scope, CancellationToken token, ISolutionSubspace subspace = null) {
+    protected virtual int HillClimb(ISingleObjectiveSolutionScope<TSolution> scope, CancellationToken token, ISolutionSubspace<TSolution> subspace = null) {
       if (double.IsNaN(scope.Fitness)) Evaluate(scope, token);
       var before = scope.Fitness;
@@ -492,5 +489,5 @@
     }
 
-    protected virtual void PerformTabuWalk(ISingleObjectiveSolutionScope<TSolution> scope, int steps, CancellationToken token, ISolutionSubspace subspace = null) {
+    protected virtual void PerformTabuWalk(ISingleObjectiveSolutionScope<TSolution> scope, int steps, CancellationToken token, ISolutionSubspace<TSolution> subspace = null) {
       if (double.IsNaN(scope.Fitness)) Evaluate(scope, token);
       var before = scope.Fitness;
@@ -501,6 +498,6 @@
         scope.Adopt(newScope);
     }
-    protected abstract void TabuWalk(ISingleObjectiveSolutionScope<TSolution> scope, int steps, CancellationToken token, ISolutionSubspace subspace = null);
-    protected virtual void TabuClimb(ISingleObjectiveSolutionScope<TSolution> scope, int steps, CancellationToken token, ISolutionSubspace subspace = null) {
+    protected abstract void TabuWalk(ISingleObjectiveSolutionScope<TSolution> scope, int steps, CancellationToken token, ISolutionSubspace<TSolution> subspace = null);
+    protected virtual void TabuClimb(ISingleObjectiveSolutionScope<TSolution> scope, int steps, CancellationToken token, ISolutionSubspace<TSolution> subspace = null) {
       if (double.IsNaN(scope.Fitness)) Evaluate(scope, token);
       var before = scope.Fitness;
@@ -546,5 +543,5 @@
 
     protected abstract ISingleObjectiveSolutionScope<TSolution> Cross(ISingleObjectiveSolutionScope<TSolution> p1, ISingleObjectiveSolutionScope<TSolution> p2, CancellationToken token);
-    protected abstract void Mutate(ISingleObjectiveSolutionScope<TSolution> offspring, CancellationToken token, ISolutionSubspace subspace = null);
+    protected abstract void Mutate(ISingleObjectiveSolutionScope<TSolution> offspring, CancellationToken token, ISolutionSubspace<TSolution> subspace = null);
     #endregion
 
@@ -651,5 +648,5 @@
       var biasedStdev = Math.Sqrt(varEnd - (cov * cov) / varStart);
 
-      if (Maximization) {
+      if (Problem.Maximization) {
         var goal = Context.Population.Min(x => x.Fitness);
         var z = (goal - biasedMean) / biasedStdev;
@@ -665,6 +662,6 @@
       return MaximumEvaluations.HasValue && Context.EvaluatedSolutions >= MaximumEvaluations.Value
         || MaximumExecutionTime.HasValue && ExecutionTime >= MaximumExecutionTime.Value
-        || TargetQuality.HasValue && (Maximization && Context.BestQuality >= TargetQuality.Value
-                                  || !Maximization && Context.BestQuality <= TargetQuality.Value);
+        || TargetQuality.HasValue && (Problem.Maximization && Context.BestQuality >= TargetQuality.Value
+                                  || !Problem.Maximization && Context.BestQuality <= TargetQuality.Value);
     }
 
Index: /branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/MemPRContext.cs
===================================================================
--- /branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/MemPRContext.cs	(revision 14449)
+++ /branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/MemPRContext.cs	(revision 14450)
@@ -23,9 +23,9 @@
 using System.Collections.Generic;
 using System.Linq;
+using HeuristicLab.Algorithms.MemPR.Interfaces;
 using HeuristicLab.Common;
 using HeuristicLab.Core;
 using HeuristicLab.Data;
 using HeuristicLab.Optimization;
-using HeuristicLab.Optimization.SolutionModel;
 using HeuristicLab.Parameters;
 using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
@@ -35,10 +35,10 @@
   [Item("MemPRContext", "Abstract base class for MemPR contexts.")]
   [StorableClass]
-  public abstract class MemPRContext<TSolution, TContext, TSolutionContext> : ParameterizedNamedItem,
-      ISingleObjectivePopulationContext<TSolution>, ISolutionModelContext<TSolution>, IStochasticContext,
-      IMaximizationContext, IEvaluatedSolutionsContext
+  public abstract class MemPRPopulationContext<TProblem, TSolution, TPopulationContext, TSolutionContext> : ParameterizedNamedItem,
+    IPopulationBasedHeuristicAlgorithmContext<TProblem, TSolution>, ISolutionModelContext<TSolution>
+      where TProblem : class, IItem, ISingleObjectiveProblemDefinition
       where TSolution : class, IItem
-      where TContext : MemPRContext<TSolution, TContext, TSolutionContext>
-      where TSolutionContext : SingleSolutionMemPRContext<TSolution, TContext, TSolutionContext> {
+      where TPopulationContext : MemPRPopulationContext<TProblem, TSolution, TPopulationContext, TSolutionContext>
+      where TSolutionContext : MemPRSolutionContext<TProblem, TSolution, TPopulationContext, TSolutionContext> {
 
     private IExecutionContext parent;
@@ -60,8 +60,8 @@
 
     [Storable]
-    private IValueParameter<BoolValue> maximization;
-    public bool Maximization {
-      get { return maximization.Value.Value; }
-      set { maximization.Value.Value = value; }
+    private IValueParameter<TProblem> problem;
+    public TProblem Problem {
+      get { return problem.Value; }
+      set { problem.Value = value; }
     }
 
@@ -95,4 +95,11 @@
 
     [Storable]
+    private IValueParameter<TSolution> bestSolution;
+    public TSolution BestSolution {
+      get { return bestSolution.Value; }
+      set { bestSolution.Value = value; }
+    }
+
+    [Storable]
     private IValueParameter<IntValue> hcSteps;
     public int HcSteps {
@@ -142,8 +149,4 @@
       set { random.Value = value; }
     }
-
-    IEnumerable<IScope> IPopulationContext.Population {
-      get { return scope.SubScopes; }
-    }
     
     public IEnumerable<ISingleObjectiveSolutionScope<TSolution>> Population {
@@ -183,13 +186,14 @@
 
     [StorableConstructor]
-    protected MemPRContext(bool deserializing) : base(deserializing) { }
-    protected MemPRContext(MemPRContext<TSolution, TContext, TSolutionContext> original, Cloner cloner)
+    protected MemPRPopulationContext(bool deserializing) : base(deserializing) { }
+    protected MemPRPopulationContext(MemPRPopulationContext<TProblem, TSolution, TPopulationContext, TSolutionContext> original, Cloner cloner)
       : base(original, cloner) {
       scope = cloner.Clone(original.scope);
-      maximization = cloner.Clone(original.maximization);
+      problem = cloner.Clone(original.problem);
       initialized = cloner.Clone(original.initialized);
       iterations = cloner.Clone(original.iterations);
       evaluatedSolutions = cloner.Clone(original.evaluatedSolutions);
       bestQuality = cloner.Clone(original.bestQuality);
+      bestSolution = cloner.Clone(original.bestSolution);
       hcSteps = cloner.Clone(original.hcSteps);
       byBreeding = cloner.Clone(original.byBreeding);
@@ -205,13 +209,14 @@
       Model = cloner.Clone(original.Model);
     }
-    public MemPRContext() : this("MemPRContext") { }
-    public MemPRContext(string name) : base(name) {
+    public MemPRPopulationContext() : this("MemPRContext") { }
+    public MemPRPopulationContext(string name) : base(name) {
       scope = new Scope("Global");
 
-      Parameters.Add(maximization = new ValueParameter<BoolValue>("Maximization", new BoolValue(false)));
+      Parameters.Add(problem = new ValueParameter<TProblem>("Problem"));
       Parameters.Add(initialized = new ValueParameter<BoolValue>("Initialized", new BoolValue(false)));
       Parameters.Add(iterations = new ValueParameter<IntValue>("Iterations", new IntValue(0)));
       Parameters.Add(evaluatedSolutions = new ValueParameter<IntValue>("EvaluatedSolutions", new IntValue(0)));
       Parameters.Add(bestQuality = new ValueParameter<DoubleValue>("BestQuality", new DoubleValue(double.NaN)));
+      Parameters.Add(bestSolution = new ValueParameter<TSolution>("BestSolution"));
       Parameters.Add(hcSteps = new ValueParameter<IntValue>("HcSteps", new IntValue(0)));
       Parameters.Add(byBreeding = new ValueParameter<IntValue>("ByBreeding", new IntValue(0)));
@@ -229,4 +234,9 @@
     public abstract TSolutionContext CreateSingleSolutionContext(ISingleObjectiveSolutionScope<TSolution> solution);
 
+    public void IncrementEvaluatedSolutions(int byEvaluations) {
+      if (byEvaluations < 0) throw new ArgumentException("Can only increment and not decrement evaluated solutions.");
+      EvaluatedSolutions += byEvaluations;
+    }
+
     #region IExecutionContext members
     public IAtomicOperation CreateOperation(IOperator op) {
@@ -246,18 +256,14 @@
     }
     #endregion
-
-    IEnumerable<ISolutionScope<TSolution>> IPopulationContext<TSolution>.Population {
-      get { return Population; }
-    }
   }
 
   [Item("SingleSolutionMemPRContext", "Abstract base class for single solution MemPR contexts.")]
   [StorableClass]
-  public abstract class SingleSolutionMemPRContext<TSolution, TContext, TSolutionContext> : ParameterizedNamedItem,
-      ISingleObjectiveSolutionContext<TSolution>, IEvaluatedSolutionsContext,
-      IIterationsManipulationContext, IStochasticContext, IMaximizationContext
+  public abstract class MemPRSolutionContext<TProblem, TSolution, TContext, TSolutionContext> : ParameterizedNamedItem,
+    ISingleSolutionHeuristicAlgorithmContext<TProblem, TSolution>
+      where TProblem : class, IItem, ISingleObjectiveProblemDefinition
       where TSolution : class, IItem
-      where TContext : MemPRContext<TSolution, TContext, TSolutionContext>
-      where TSolutionContext : SingleSolutionMemPRContext<TSolution, TContext, TSolutionContext> {
+      where TContext : MemPRPopulationContext<TProblem, TSolution, TContext, TSolutionContext>
+      where TSolutionContext : MemPRSolutionContext<TProblem, TSolution, TContext, TSolutionContext> {
 
     private TContext parent;
@@ -276,7 +282,17 @@
       get { return Parameters; }
     }
-    
-    public bool Maximization {
-      get { return parent.Maximization; }
+
+    public TProblem Problem {
+      get { return parent.Problem; }
+    }
+
+    public double BestQuality {
+      get { return parent.BestQuality; }
+      set { parent.BestQuality = value; }
+    }
+
+    public TSolution BestSolution {
+      get { return parent.BestSolution; }
+      set { parent.BestSolution = value; }
     }
 
@@ -299,19 +315,11 @@
     }
 
-    IScope ISolutionContext.Solution {
+    ISingleObjectiveSolutionScope<TSolution> ISingleSolutionHeuristicAlgorithmContext<TProblem, TSolution>.Solution {
       get { return scope; }
     }
 
-    ISolutionScope<TSolution> ISolutionContext<TSolution>.Solution {
-      get { return scope; }
-    }
-
-    ISingleObjectiveSolutionScope<TSolution> ISingleObjectiveSolutionContext<TSolution>.Solution {
-      get { return scope; }
-    }
-
     [StorableConstructor]
-    protected SingleSolutionMemPRContext(bool deserializing) : base(deserializing) { }
-    protected SingleSolutionMemPRContext(SingleSolutionMemPRContext<TSolution, TContext, TSolutionContext> original, Cloner cloner)
+    protected MemPRSolutionContext(bool deserializing) : base(deserializing) { }
+    protected MemPRSolutionContext(MemPRSolutionContext<TProblem, TSolution, TContext, TSolutionContext> original, Cloner cloner)
       : base(original, cloner) {
       scope = cloner.Clone(original.scope);
@@ -319,5 +327,5 @@
       iterations = cloner.Clone(original.iterations);
     }
-    public SingleSolutionMemPRContext(TContext baseContext, ISingleObjectiveSolutionScope<TSolution> solution) {
+    public MemPRSolutionContext(TContext baseContext, ISingleObjectiveSolutionScope<TSolution> solution) {
       parent = baseContext;
       scope = solution;
@@ -327,4 +335,9 @@
     }
 
+    public void IncrementEvaluatedSolutions(int byEvaluations) {
+      if (byEvaluations < 0) throw new ArgumentException("Can only increment and not decrement evaluated solutions.");
+      EvaluatedSolutions += byEvaluations;
+    }
+
     #region IExecutionContext members
     public IAtomicOperation CreateOperation(IOperator op) {
Index: /branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/Permutation/LocalSearch/ExhaustiveHillClimb.cs
===================================================================
--- /branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/Permutation/LocalSearch/ExhaustiveHillClimb.cs	(revision 14450)
+++ /branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/Permutation/LocalSearch/ExhaustiveHillClimb.cs	(revision 14450)
@@ -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 System.Threading;
+using HeuristicLab.Algorithms.MemPR.Interfaces;
+using HeuristicLab.Algorithms.MemPR.Util;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Encodings.PermutationEncoding;
+using HeuristicLab.Optimization;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Algorithms.MemPR.Permutation.LocalSearch {
+  [Item("Exhaustive Hillclimber (permutation)", "", ExcludeGenericTypeInfo = true)]
+  [StorableClass]
+  public class ExhaustiveHillClimb<TContext> : NamedItem, ILocalSearch<TContext>
+      where TContext : ISingleSolutionHeuristicAlgorithmContext<SingleObjectiveBasicProblem<PermutationEncoding>, Encodings.PermutationEncoding.Permutation> {
+
+    [StorableConstructor]
+    protected ExhaustiveHillClimb(bool deserializing) : base(deserializing) { }
+    protected ExhaustiveHillClimb(ExhaustiveHillClimb<TContext> original, Cloner cloner) : base(original, cloner) { }
+    public ExhaustiveHillClimb() {
+      Name = ItemName;
+      Description = ItemDescription;
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new ExhaustiveHillClimb<TContext>(this, cloner);
+    }
+
+    public void Optimize(TContext context) {
+      var evalWrapper = new EvaluationWrapper<Encodings.PermutationEncoding.Permutation>(context.Problem, context.Solution);
+      var quality = context.Solution.Fitness;
+      try {
+        var result = Exhaustive.HillClimb(context.Random, context.Solution.Solution, ref quality,
+          context.Problem.Maximization, evalWrapper.Evaluate, CancellationToken.None);
+        context.IncrementEvaluatedSolutions(result.Item1);
+        context.Iterations = result.Item2;
+      } finally {
+        context.Solution.Fitness = quality;
+      }
+    }
+  }
+}
Index: /branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/Permutation/LocalSearch/ExhaustiveHillClimbSubspace.cs
===================================================================
--- /branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/Permutation/LocalSearch/ExhaustiveHillClimbSubspace.cs	(revision 14450)
+++ /branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/Permutation/LocalSearch/ExhaustiveHillClimbSubspace.cs	(revision 14450)
@@ -0,0 +1,63 @@
+﻿#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.Threading;
+using HeuristicLab.Algorithms.MemPR.Interfaces;
+using HeuristicLab.Algorithms.MemPR.Util;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Encodings.PermutationEncoding;
+using HeuristicLab.Optimization;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Algorithms.MemPR.Permutation.LocalSearch {
+  [Item("Exhaustive Subspace Hillclimber (permutation)", "", ExcludeGenericTypeInfo = true)]
+  [StorableClass]
+  public class ExhaustiveHillClimbSubspace<TContext> : NamedItem, ILocalSearch<TContext>
+      where TContext : ISingleSolutionHeuristicAlgorithmContext<SingleObjectiveBasicProblem<PermutationEncoding>, Encodings.PermutationEncoding.Permutation>,
+                       IPermutationSubspaceContext {
+
+    [StorableConstructor]
+    protected ExhaustiveHillClimbSubspace(bool deserializing) : base(deserializing) { }
+    protected ExhaustiveHillClimbSubspace(ExhaustiveHillClimbSubspace<TContext> original, Cloner cloner) : base(original, cloner) { }
+    public ExhaustiveHillClimbSubspace() {
+      Name = ItemName;
+      Description = ItemDescription;
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new ExhaustiveHillClimbSubspace<TContext>(this, cloner);
+    }
+
+    public void Optimize(TContext context) {
+      var evalWrapper = new EvaluationWrapper<Encodings.PermutationEncoding.Permutation>(context.Problem, context.Solution);
+      var quality = context.Solution.Fitness;
+      try {
+        var result = Exhaustive.HillClimb(context.Random, context.Solution.Solution, ref quality,
+          context.Problem.Maximization, evalWrapper.Evaluate, CancellationToken.None, context.Subspace.Subspace);
+        context.IncrementEvaluatedSolutions(result.Item1);
+        context.Iterations = result.Item2;
+      } finally {
+        context.Solution.Fitness = quality;
+      }
+    }
+  }
+}
Index: /branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/Permutation/LocalSearch/StaticAPI/Exhaustive.cs
===================================================================
--- /branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/Permutation/LocalSearch/StaticAPI/Exhaustive.cs	(revision 14450)
+++ /branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/Permutation/LocalSearch/StaticAPI/Exhaustive.cs	(revision 14450)
@@ -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 System;
+using System.Threading;
+using HeuristicLab.Core;
+using HeuristicLab.Encodings.PermutationEncoding;
+
+namespace HeuristicLab.Algorithms.MemPR.Permutation.LocalSearch {
+  public static class Exhaustive {
+#if DEBUG
+    private const bool VALIDATE = true;
+#else
+  private const bool VALIDATE = false;
+#endif
+
+    public static Tuple<int, int> HillClimb(IRandom random, Encodings.PermutationEncoding.Permutation perm,
+      ref double quality, bool maximization, Func<Encodings.PermutationEncoding.Permutation, double> eval,
+      CancellationToken token, bool[,] noTouch = null) {
+      if (double.IsNaN(quality)) quality = eval(perm);
+      Tuple<int, int> changes;
+      switch (perm.PermutationType) {
+        case PermutationTypes.Absolute:
+          changes = ExhaustiveSwap2.HillClimb(random, perm, ref quality, maximization, eval, token, noTouch);
+          break;
+        case PermutationTypes.RelativeDirected:
+          changes = Exhaustive1Shift.HillClimb(random, perm, ref quality, maximization, eval, token, noTouch);
+          break;
+        case PermutationTypes.RelativeUndirected:
+          changes = Exhaustive2Opt.HillClimb(random, perm, ref quality, maximization, eval, token, noTouch);
+          break;
+        default: throw new ArgumentException(string.Format("Permutation type {0} is not known", perm.PermutationType));
+      }
+      if (VALIDATE && !perm.Validate()) throw new ArgumentException("HillClimb produced invalid child");
+      return changes;
+    }
+  }
+}
Index: /branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/Permutation/LocalSearch/StaticAPI/Exhaustive1Shift.cs
===================================================================
--- /branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/Permutation/LocalSearch/StaticAPI/Exhaustive1Shift.cs	(revision 14450)
+++ /branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/Permutation/LocalSearch/StaticAPI/Exhaustive1Shift.cs	(revision 14450)
@@ -0,0 +1,72 @@
+﻿#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.Algorithms.MemPR.Util;
+using HeuristicLab.Core;
+using HeuristicLab.Encodings.PermutationEncoding;
+
+namespace HeuristicLab.Algorithms.MemPR.Permutation.LocalSearch {
+  public static class Exhaustive1Shift {
+    public static Tuple<int, int> HillClimb(IRandom random, Encodings.PermutationEncoding.Permutation perm,
+      ref double quality, bool maximization, Func<Encodings.PermutationEncoding.Permutation, double> eval,
+      CancellationToken token, bool[,] noTouch = null) {
+      var current = perm;
+      if (double.IsNaN(quality)) quality = eval(current);
+      TranslocationMove lastSuccessMove = null;
+      int steps = 0, evaluations = 0;
+      while (true) {
+        foreach (var shift in ExhaustiveInsertionMoveGenerator.Generate(current)) {
+          if (lastSuccessMove != null && shift.Index1 == lastSuccessMove.Index1 && shift.Index2 == lastSuccessMove.Index2 && shift.Index3 == lastSuccessMove.Index3) {
+            // been there, done that
+            lastSuccessMove = null;
+            break;
+          }
+          var prev1 = shift.Index1 - 1;
+          var next1 = (shift.Index1 + 1) % current.Length;
+          if (prev1 < 0) prev1 += current.Length;
+          var prev3 = shift.Index3 - 1;
+          var next3 = (shift.Index3 + 1) % current.Length;
+          if (prev3 < 0) prev3 += current.Length;
+          if (noTouch != null && ((noTouch[current[prev1], current[shift.Index1]] || noTouch[current[shift.Index1], current[next1]]
+                                || noTouch[current[prev3], current[shift.Index3]] || noTouch[current[shift.Index3], current[next3]])))
+            continue;
+          TranslocationManipulator.Apply(current, shift.Index1, shift.Index2, shift.Index3);
+          var q = eval(current);
+          evaluations++;
+          if (FitnessComparer.IsBetter(maximization, q, quality)) {
+            steps++;
+            quality = q;
+            lastSuccessMove = shift;
+          } else TranslocationManipulator.Apply(current, shift.Index3, shift.Index3, shift.Index1);
+
+          if (token.IsCancellationRequested) {
+            lastSuccessMove = null;
+            break;
+          }
+        }
+        if (lastSuccessMove == null) break;
+      }
+      return Tuple.Create(steps, evaluations);
+    }
+  }
+}
Index: /branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/Permutation/LocalSearch/StaticAPI/Exhaustive2Opt.cs
===================================================================
--- /branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/Permutation/LocalSearch/StaticAPI/Exhaustive2Opt.cs	(revision 14450)
+++ /branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/Permutation/LocalSearch/StaticAPI/Exhaustive2Opt.cs	(revision 14450)
@@ -0,0 +1,69 @@
+﻿#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.Algorithms.MemPR.Util;
+using HeuristicLab.Core;
+using HeuristicLab.Encodings.PermutationEncoding;
+
+namespace HeuristicLab.Algorithms.MemPR.Permutation.LocalSearch {
+  public static class Exhaustive2Opt {
+    public static Tuple<int, int> HillClimb(IRandom random, Encodings.PermutationEncoding.Permutation perm,
+      ref double quality, bool maximization, Func<Encodings.PermutationEncoding.Permutation, double> eval,
+      CancellationToken token, bool[,] noTouch = null) {
+      var current = perm;
+      if (double.IsNaN(quality)) quality = eval(current);
+      InversionMove lastSuccessMove = null;
+      int steps = 0, evaluations = 0;
+      while (true) {
+        foreach (var opt in ExhaustiveInversionMoveGenerator.Generate(current)) {
+          if (lastSuccessMove != null && opt.Index1 == lastSuccessMove.Index1 && opt.Index2 == lastSuccessMove.Index2) {
+            // been there, done that
+            lastSuccessMove = null;
+            break;
+          }
+          var prev = opt.Index1 - 1;
+          var next = (opt.Index2 + 1) % current.Length;
+          if (prev < 0) prev += current.Length;
+          if (noTouch != null && ((noTouch[current[prev], current[opt.Index1]]) || (noTouch[current[opt.Index2], current[next]])))
+            continue;
+
+          InversionManipulator.Apply(current, opt.Index1, opt.Index2);
+          var q = eval(current);
+          evaluations++;
+          if (FitnessComparer.IsBetter(maximization, q, quality)) {
+            steps++;
+            quality = q;
+            lastSuccessMove = opt;
+          } else InversionManipulator.Apply(current, opt.Index1, opt.Index2);
+
+          if (token.IsCancellationRequested) {
+            lastSuccessMove = null;
+            break;
+          }
+        }
+        if (lastSuccessMove == null) break;
+      }
+      return Tuple.Create(steps, evaluations);
+    }
+  }
+}
Index: /branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/Permutation/LocalSearch/StaticAPI/ExhaustiveSwap2.cs
===================================================================
--- /branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/Permutation/LocalSearch/StaticAPI/ExhaustiveSwap2.cs	(revision 14450)
+++ /branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/Permutation/LocalSearch/StaticAPI/ExhaustiveSwap2.cs	(revision 14450)
@@ -0,0 +1,71 @@
+﻿#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.Algorithms.MemPR.Util;
+using HeuristicLab.Core;
+using HeuristicLab.Encodings.PermutationEncoding;
+
+namespace HeuristicLab.Algorithms.MemPR.Permutation.LocalSearch {
+  public static class ExhaustiveSwap2 {
+    public static Tuple<int, int> HillClimb(IRandom random, Encodings.PermutationEncoding.Permutation perm,
+      ref double quality, bool maximization, Func<Encodings.PermutationEncoding.Permutation, double> eval,
+      CancellationToken token, bool[,] noTouch = null) {
+      var current = perm;
+      if (double.IsNaN(quality)) quality = eval(current);
+      Swap2Move lastSuccessMove = null;
+      int steps = 0, evaluations = 0;
+      while (true) {
+        foreach (var swap in ExhaustiveSwap2MoveGenerator.Generate(current)) {
+          if (lastSuccessMove != null && swap.Index1 == lastSuccessMove.Index1 && swap.Index2 == lastSuccessMove.Index2) {
+            // been there, done that
+            lastSuccessMove = null;
+            break;
+          }
+          if (noTouch != null && (noTouch[swap.Index1, 0] || noTouch[swap.Index2, 0]))
+            continue;
+
+          var h = current[swap.Index1];
+          current[swap.Index1] = current[swap.Index2];
+          current[swap.Index2] = h;
+          var q = eval(current);
+          evaluations++;
+          if (FitnessComparer.IsBetter(maximization, q, quality)) {
+            steps++;
+            quality = q;
+            lastSuccessMove = swap;
+          } else {
+            current[swap.Index2] = current[swap.Index1];
+            current[swap.Index1] = h;
+          }
+
+          if (token.IsCancellationRequested) {
+            lastSuccessMove = null;
+            break;
+          }
+        }
+        if (lastSuccessMove == null) break;
+      }
+      return Tuple.Create(steps, evaluations);
+    }
+  }
+}
Index: /branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/Permutation/PermutationMemPR.cs
===================================================================
--- /branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/Permutation/PermutationMemPR.cs	(revision 14450)
+++ /branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/Permutation/PermutationMemPR.cs	(revision 14450)
@@ -0,0 +1,764 @@
+﻿#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;
+using System.Threading;
+using HeuristicLab.Algorithms.MemPR.Interfaces;
+using HeuristicLab.Algorithms.MemPR.Util;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Encodings.PermutationEncoding;
+using HeuristicLab.Optimization;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.PluginInfrastructure;
+using HeuristicLab.Random;
+
+namespace HeuristicLab.Algorithms.MemPR.Permutation {
+  [Item("MemPR (permutation)", "MemPR implementation for permutations.")]
+  [StorableClass]
+  [Creatable(CreatableAttribute.Categories.PopulationBasedAlgorithms, Priority = 999)]
+  public class PermutationMemPR : MemPRAlgorithm<SingleObjectiveBasicProblem<PermutationEncoding>, Encodings.PermutationEncoding.Permutation, PermutationMemPRPopulationContext, PermutationMemPRSolutionContext> {
+    private const double UncommonBitSubsetMutationProbabilityMagicConst = 0.05;
+
+#if DEBUG
+    private const bool VALIDATE = true;
+#else
+    private const bool VALIDATE = false;
+#endif
+
+    [StorableConstructor]
+    protected PermutationMemPR(bool deserializing) : base(deserializing) { }
+    protected PermutationMemPR(PermutationMemPR original, Cloner cloner) : base(original, cloner) { }
+    public PermutationMemPR() {
+      foreach (var trainer in ApplicationManager.Manager.GetInstances<ISolutionModelTrainer<PermutationMemPRPopulationContext>>())
+        SolutionModelTrainerParameter.ValidValues.Add(trainer);
+      
+      foreach (var localSearch in ApplicationManager.Manager.GetInstances<ILocalSearch<PermutationMemPRSolutionContext>>()) {
+        LocalSearchParameter.ValidValues.Add(localSearch);
+      }
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new PermutationMemPR(this, cloner);
+    }
+
+    protected override bool Eq(ISingleObjectiveSolutionScope<Encodings.PermutationEncoding.Permutation> a, ISingleObjectiveSolutionScope<Encodings.PermutationEncoding.Permutation> b) {
+      return new PermutationEqualityComparer().Equals(a.Solution, b.Solution);
+    }
+
+    protected override double Dist(ISingleObjectiveSolutionScope<Encodings.PermutationEncoding.Permutation> a, ISingleObjectiveSolutionScope<Encodings.PermutationEncoding.Permutation> b) {
+      return Dist(a.Solution, b.Solution);
+    }
+
+    private static double Dist(Encodings.PermutationEncoding.Permutation a, Encodings.PermutationEncoding.Permutation b) {
+      return 1.0 - PermutationSimilarityCalculator.CalculateSimilarity(a, b);
+    }
+
+    protected override ISingleObjectiveSolutionScope<Encodings.PermutationEncoding.Permutation> ToScope(Encodings.PermutationEncoding.Permutation code, double fitness = double.NaN) {
+      var creator = Problem.SolutionCreator as IPermutationCreator;
+      if (creator == null) throw new InvalidOperationException("Can only solve binary encoded problems with MemPR (binary)");
+      return new SingleObjectiveSolutionScope<Encodings.PermutationEncoding.Permutation>(code, creator.PermutationParameter.ActualName, fitness, Problem.Evaluator.QualityParameter.ActualName) {
+        Parent = Context.Scope
+      };
+    }
+
+    protected override ISolutionSubspace<Encodings.PermutationEncoding.Permutation> CalculateSubspace(IEnumerable<Encodings.PermutationEncoding.Permutation> solutions, bool inverse = false) {
+      var subspace = new bool[Problem.Encoding.Length, Problem.Encoding.PermutationTypeParameter.Value.Value == PermutationTypes.Absolute ? 1 : Problem.Encoding.Length];
+
+      switch (Problem.Encoding.PermutationTypeParameter.Value.Value) {
+        case PermutationTypes.Absolute: {
+            if (inverse) {
+              for (var i = 0; i < subspace.GetLength(0); i++)
+                subspace[i, 0] = true;
+            }
+            var first = solutions.First();
+            foreach (var s in solutions.Skip(1)) {
+              for (var i = 0; i < s.Length; i++) {
+                if (first[i] != s[i]) subspace[i, 0] = !inverse;
+              }
+            }
+          }
+          break;
+        case PermutationTypes.RelativeDirected: {
+            if (inverse) {
+              for (var i = 0; i < subspace.GetLength(0); i++)
+                for (var j = 0; j < subspace.GetLength(1); j++)
+                  subspace[i, j] = true;
+            }
+            var first = solutions.First();
+            var placedFirst = new int[first.Length];
+            for (var i = 0; i < first.Length; i++) {
+              placedFirst[first[i]] = i;
+            }
+            foreach (var s in solutions.Skip(1)) {
+              for (var i = 0; i < s.Length; i++) {
+                if (placedFirst[s[i]] - placedFirst[s.GetCircular(i + 1)] != -1)
+                  subspace[i, 0] = !inverse;
+              }
+            }
+          }
+          break;
+        case PermutationTypes.RelativeUndirected: {
+            if (inverse) {
+              for (var i = 0; i < subspace.GetLength(0); i++)
+                for (var j = 0; j < subspace.GetLength(1); j++)
+                  subspace[i, j] = true;
+            }
+            var first = solutions.First();
+            var placedFirst = new int[first.Length];
+            for (var i = 0; i < first.Length; i++) {
+              placedFirst[first[i]] = i;
+            }
+            foreach (var s in solutions.Skip(1)) {
+              for (var i = 0; i < s.Length; i++) {
+                if (Math.Abs(placedFirst[s[i]] - placedFirst[s.GetCircular(i + 1)]) != 1)
+                  subspace[i, 0] = !inverse;
+              }
+            }
+          }
+          break;
+        default:
+          throw new ArgumentException(string.Format("Unknown permutation type {0}", Problem.Encoding.PermutationTypeParameter.Value.Value));
+      }
+      return new PermutationSolutionSubspace(subspace);
+    }
+
+    protected override void TabuWalk(ISingleObjectiveSolutionScope<Encodings.PermutationEncoding.Permutation> scope, int steps, CancellationToken token, ISolutionSubspace<Encodings.PermutationEncoding.Permutation> subspace = null) {
+      var wrapper = new EvaluationWrapper<Encodings.PermutationEncoding.Permutation>(Context.Problem, scope);
+      var quality = scope.Fitness;
+      try {
+        TabuWalk(Context.Random, scope.Solution, wrapper.Evaluate, ref quality, Context.HcSteps, subspace != null ? ((PermutationSolutionSubspace)subspace).Subspace : null);
+      } finally {
+        scope.Fitness = quality;
+      }
+    }
+
+    public static void TabuWalk(IRandom random, Encodings.PermutationEncoding.Permutation perm, Func<Encodings.PermutationEncoding.Permutation, IRandom, double> eval, ref double quality, int maxIterations = int.MaxValue, bool[,] noTouch = null) {
+      switch (perm.PermutationType) {
+        case PermutationTypes.Absolute:
+          TabuWalkSwap(random, perm, eval, ref quality, maxIterations, noTouch);
+          break;
+        case PermutationTypes.RelativeDirected:
+          TabuWalkShift(random, perm, eval, ref quality, maxIterations, noTouch);
+          break;
+        case PermutationTypes.RelativeUndirected:
+          TabuWalkOpt(random, perm, eval, ref quality, maxIterations, noTouch);
+          break;
+        default: throw new ArgumentException(string.Format("Permutation type {0} is not known", perm.PermutationType));
+      }
+      if (VALIDATE && !perm.Validate()) throw new ArgumentException("TabuWalk produced invalid child");
+    }
+
+    public static void TabuWalkSwap(IRandom random, Encodings.PermutationEncoding.Permutation perm, Func<Encodings.PermutationEncoding.Permutation, IRandom, double> eval, ref double quality, int maxIterations = int.MaxValue, bool[,] noTouch = null) {
+      if (double.IsNaN(quality)) quality = eval(perm, random);
+      Encodings.PermutationEncoding.Permutation bestOfTheWalk = null;
+      double bestOfTheWalkF = double.NaN;
+      var current = (Encodings.PermutationEncoding.Permutation)perm.Clone();
+      var currentF = quality;
+      var overallImprovement = false;
+      //Console.WriteLine("Current    {0}", string.Join(", ", current));
+      var tabu = new double[current.Length, current.Length];
+      for (var i = 0; i < current.Length; i++) {
+        for (var j = i; j < current.Length; j++) {
+          tabu[i, j] = tabu[j, i] = double.MaxValue;
+        }
+        tabu[i, current[i]] = currentF;
+      }
+
+      for (var iter = 0; iter < maxIterations; iter++) {
+        var allTabu = true;
+        var bestOfTheRestF = double.NaN;
+        Swap2Move bestOfTheRest = null;
+        var improved = false;
+        //LogAlways("TabuWalk ({0}/{2}): {1}   ({3})", iter, currentF, maxIterations, string.Join(", ", current));
+        foreach (var swap in ExhaustiveSwap2MoveGenerator.Generate(current).Shuffle(random)) {
+          if (noTouch != null && (noTouch[swap.Index1, 0] || noTouch[swap.Index2, 0]))
+            continue;
+
+          var h = current[swap.Index1];
+          current[swap.Index1] = current[swap.Index2];
+          current[swap.Index2] = h;
+          var q = eval(current, random);
+          if (q < quality) {
+            overallImprovement = true;
+            quality = q;
+            for (var i = 0; i < current.Length; i++) perm[i] = current[i];
+          }
+          // check if it would not be an improvement to swap these into their positions
+          var isTabu = q >= tabu[swap.Index1, current[swap.Index1]] && q >= tabu[swap.Index2, current[swap.Index2]];
+          if (!isTabu) allTabu = false;
+          if (q < currentF && !isTabu) {
+            if (double.IsNaN(bestOfTheWalkF) || bestOfTheWalkF > q) {
+              bestOfTheWalk = (Encodings.PermutationEncoding.Permutation)current.Clone();
+              bestOfTheWalkF = q;
+            }
+
+            improved = true;
+            // perform the move
+            currentF = q;
+            // mark that to move them to their previous position requires to make an improvement
+            tabu[swap.Index1, current[swap.Index2]] = Math.Min(q, tabu[swap.Index1, current[swap.Index2]]);
+            //LogAlways("Making Tabu [{0},{1}] = {2}", swap.Index1, current[swap.Index2], tabu[swap.Index1, current[swap.Index2]]);
+            tabu[swap.Index2, current[swap.Index1]] = Math.Min(q, tabu[swap.Index2, current[swap.Index1]]);
+            //LogAlways("Making Tabu [{0},{1}] = {2}", swap.Index2, current[swap.Index1], tabu[swap.Index2, current[swap.Index1]]);
+          } else { // undo the move
+            if (!isTabu && (double.IsNaN(bestOfTheRestF) || q < bestOfTheRestF)) {
+              bestOfTheRest = swap;
+              bestOfTheRestF = q;
+            }
+            current[swap.Index2] = current[swap.Index1];
+            current[swap.Index1] = h;
+          }
+        }
+        if (!allTabu && !improved) {
+          tabu[bestOfTheRest.Index1, current[bestOfTheRest.Index1]] = Math.Min(currentF, tabu[bestOfTheRest.Index1, current[bestOfTheRest.Index1]]);
+          //LogAlways("Making Tabu [{0},{1}] = {2}", bestOfTheRest.Index1, current[bestOfTheRest.Index1], tabu[bestOfTheRest.Index1, current[bestOfTheRest.Index1]]);
+          tabu[bestOfTheRest.Index2, current[bestOfTheRest.Index2]] = Math.Min(currentF, tabu[bestOfTheRest.Index2, current[bestOfTheRest.Index2]]);
+          //LogAlways("Making Tabu [{0},{1}] = {2}", bestOfTheRest.Index2, current[bestOfTheRest.Index2], tabu[bestOfTheRest.Index2, current[bestOfTheRest.Index2]]);
+
+          var h = current[bestOfTheRest.Index1];
+          current[bestOfTheRest.Index1] = current[bestOfTheRest.Index2];
+          current[bestOfTheRest.Index2] = h;
+
+          currentF = bestOfTheRestF;
+        } else if (allTabu) break;
+      }
+      if (!overallImprovement && bestOfTheWalk != null) {
+        quality = bestOfTheWalkF;
+        for (var i = 0; i < current.Length; i++) perm[i] = bestOfTheWalk[i];
+      }
+    }
+
+    public static void TabuWalkShift(IRandom random, Encodings.PermutationEncoding.Permutation perm, Func<Encodings.PermutationEncoding.Permutation, IRandom, double> eval, ref double quality, int maxIterations = int.MaxValue, bool[,] noTouch = null) {
+      return;
+    }
+
+    public static void TabuWalkOpt(IRandom random, Encodings.PermutationEncoding.Permutation perm, Func<Encodings.PermutationEncoding.Permutation, IRandom, double> eval, ref double quality, int maxIterations = int.MaxValue, bool[,] noTouch = null) {
+      if (double.IsNaN(quality)) quality = eval(perm, random);
+      Encodings.PermutationEncoding.Permutation bestOfTheWalk = null;
+      double bestOfTheWalkF = double.NaN;
+      var current = (Encodings.PermutationEncoding.Permutation)perm.Clone();
+      var currentF = quality;
+      var overallImprovement = false;
+      //Console.WriteLine("Current    {0}", string.Join(", ", current));
+      var tabu = new double[current.Length, current.Length];
+      for (var i = 0; i < current.Length; i++) {
+        for (var j = i; j < current.Length; j++) {
+          tabu[i, j] = tabu[j, i] = double.MaxValue;
+        }
+        tabu[current[i], current.GetCircular(i + 1)] = currentF;
+        tabu[current.GetCircular(i + 1), current[i]] = currentF;
+      }
+
+      for (var iter = 0; iter < maxIterations; iter++) {
+        var allTabu = true;
+        var bestOfTheRestF = double.NaN;
+        InversionMove bestOfTheRest = null;
+        var improved = false;
+
+        foreach (var opt in ExhaustiveInversionMoveGenerator.Generate(current).Shuffle(random)) {
+          var prev = opt.Index1 - 1;
+          var next = (opt.Index2 + 1) % current.Length;
+          if (prev < 0) prev += current.Length;
+          if (noTouch != null && ((noTouch[current[prev], current[opt.Index1]]) || (noTouch[current[opt.Index2], current[next]])))
+            continue;
+
+          InversionManipulator.Apply(current, opt.Index1, opt.Index2);
+
+          var q = eval(current, random);
+          if (q < quality) {
+            overallImprovement = true;
+            quality = q;
+            for (var i = 0; i < current.Length; i++) perm[i] = current[i];
+          }
+          // check if it would not be an improvement to opt these into their positions
+          var isTabu = q >= tabu[current[prev], current[opt.Index1]] && q >= tabu[current[opt.Index2], current[next]];
+          if (!isTabu) allTabu = false;
+          if (q < currentF && !isTabu) {
+            if (double.IsNaN(bestOfTheWalkF) || bestOfTheWalkF > q) {
+              bestOfTheWalk = (Encodings.PermutationEncoding.Permutation)current.Clone();
+              bestOfTheWalkF = q;
+            }
+
+            improved = true;
+            // perform the move
+            currentF = q;
+            // mark that to move them to their previous position requires to make an improvement
+            tabu[current[prev], current[opt.Index2]] = Math.Min(q, tabu[current[prev], current[opt.Index2]]);
+            tabu[current[opt.Index2], current[prev]] = Math.Min(q, tabu[current[opt.Index2], current[prev]]);
+            tabu[current[opt.Index1], current[next]] = Math.Min(q, tabu[current[opt.Index1], current[next]]);
+            tabu[current[next], current[opt.Index1]] = Math.Min(q, tabu[current[next], current[opt.Index1]]);
+          } else { // undo the move
+            if (!isTabu && (double.IsNaN(bestOfTheRestF) || q < bestOfTheRestF)) {
+              bestOfTheRest = opt;
+              bestOfTheRestF = q;
+            }
+
+            InversionManipulator.Apply(current, opt.Index1, opt.Index2);
+          }
+        }
+        if (!allTabu && !improved) {
+          var prev = bestOfTheRest.Index1 - 1;
+          var next = (bestOfTheRest.Index2 + 1) % current.Length;
+          if (prev < 0) prev += current.Length;
+
+          tabu[current[prev], current[bestOfTheRest.Index1]] = Math.Min(currentF, tabu[current[prev], current[bestOfTheRest.Index1]]);
+          tabu[current[bestOfTheRest.Index1], current[prev]] = Math.Min(currentF, tabu[current[bestOfTheRest.Index1], current[prev]]);
+          tabu[current[bestOfTheRest.Index2], current[next]] = Math.Min(currentF, tabu[current[bestOfTheRest.Index2], current[next]]);
+          tabu[current[next], current[bestOfTheRest.Index2]] = Math.Min(currentF, tabu[current[next], current[bestOfTheRest.Index2]]);
+
+          InversionManipulator.Apply(current, bestOfTheRest.Index1, bestOfTheRest.Index2);
+
+          currentF = bestOfTheRestF;
+        } else if (allTabu) break;
+      }
+      if (!overallImprovement && bestOfTheWalk != null) {
+        quality = bestOfTheWalkF;
+        for (var i = 0; i < current.Length; i++) perm[i] = bestOfTheWalk[i];
+      }
+    }
+
+    protected override ISingleObjectiveSolutionScope<Encodings.PermutationEncoding.Permutation> Cross(ISingleObjectiveSolutionScope<Encodings.PermutationEncoding.Permutation> p1, ISingleObjectiveSolutionScope<Encodings.PermutationEncoding.Permutation> p2, CancellationToken token) {
+      Encodings.PermutationEncoding.Permutation child = null;
+
+      if (p1.Solution.PermutationType == PermutationTypes.Absolute) {
+        child = CyclicCrossover.Apply(Context.Random, p1.Solution, p2.Solution);
+      } else if (p1.Solution.PermutationType == PermutationTypes.RelativeDirected) {
+        child = PartiallyMatchedCrossover.Apply(Context.Random, p1.Solution, p2.Solution);
+      } else if (p1.Solution.PermutationType == PermutationTypes.RelativeUndirected) {
+        child = EdgeRecombinationCrossover.Apply(Context.Random, p1.Solution, p2.Solution);
+      } else throw new ArgumentException(string.Format("Unknown permutation type {0}", p1.Solution.PermutationType));
+
+      if (VALIDATE && !child.Validate()) throw new ArgumentException("Cross produced invalid child");
+      return ToScope(child);
+    }
+
+    protected override void Mutate(ISingleObjectiveSolutionScope<Encodings.PermutationEncoding.Permutation> offspring, CancellationToken token, ISolutionSubspace<Encodings.PermutationEncoding.Permutation> subspace = null) {
+      Mutate(Context.Random, offspring.Solution, UncommonBitSubsetMutationProbabilityMagicConst, subspace != null ? ((PermutationSolutionSubspace)subspace).Subspace : null);
+    }
+
+    public static void Mutate(IRandom random, Encodings.PermutationEncoding.Permutation perm, double p, bool[,] subspace) {
+      switch (perm.PermutationType) {
+        case PermutationTypes.Absolute:
+          MutateSwap(random, perm, p, subspace);
+          break;
+        case PermutationTypes.RelativeDirected:
+          MutateShift(random, perm, p, subspace);
+          break;
+        case PermutationTypes.RelativeUndirected:
+          MutateOpt(random, perm, p, subspace);
+          break;
+        default: throw new ArgumentException(string.Format("Permutation type {0} is not known", perm.PermutationType));
+      }
+      if (VALIDATE && !perm.Validate()) throw new ArgumentException("Mutate produced invalid child");
+    }
+
+    public static void MutateSwap(IRandom random, Encodings.PermutationEncoding.Permutation perm, double p, bool[,] subspace) {
+      //Log("BEFOR: {0}", string.Join(", ", lle));
+      // The goal of the mutation is to disrupt crossover when it's in an agreeing position
+      var options = new List<int>(Enumerable.Range(0, perm.Length).Where(x => subspace == null || !subspace[x, 0]));
+      if (options.Count < 1) return;
+
+      for (var i = options.Count - 1; i > 0; i--) {
+        if (random.NextDouble() < p) {
+          var j = random.Next(0, i);
+          var h = perm[options[i]];
+          perm[options[i]] = perm[options[j]];
+          perm[options[j]] = h;
+          if (subspace != null) {
+            subspace[options[i], 0] = true;
+            subspace[options[j], 0] = true;
+          }
+        }
+      }
+    }
+
+    public static void MutateShift(IRandom random, Encodings.PermutationEncoding.Permutation perm, double p, bool[,] subspace) {
+      //Log("BEFOR: {0}", string.Join(", ", lle));
+      // The goal of the mutation is to disrupt crossover when it's in an agreeing position
+      foreach (var shift in ExhaustiveInsertionMoveGenerator.Generate(perm).Shuffle(random)) {
+        var prev1 = shift.Index1 - 1;
+        var next1 = (shift.Index1 + 1) % perm.Length;
+        if (prev1 < 0) prev1 += perm.Length;
+        var prev3 = shift.Index3 - 1;
+        var next3 = (shift.Index3 + 1) % perm.Length;
+        if (prev3 < 0) prev3 += perm.Length;
+        if (subspace == null || !(subspace[perm[prev1], perm[shift.Index1]] && subspace[perm[shift.Index1], perm[next1]]
+            && subspace[perm[prev3], perm[shift.Index3]] && subspace[perm[shift.Index3], perm[next3]])) {
+          if (random.NextDouble() < p) {
+            if (subspace != null) {
+              subspace[perm[prev1], perm[shift.Index1]] = true;
+              subspace[perm[shift.Index1], perm[next1]] = true;
+              subspace[perm[prev3], perm[shift.Index3]] = true;
+              subspace[perm[shift.Index3], perm[next3]] = true;
+            }
+            TranslocationManipulator.Apply(perm, shift.Index1, shift.Index2, shift.Index3);
+            return;
+          }
+        }
+      }
+    }
+
+    public static void MutateOpt(IRandom random, Encodings.PermutationEncoding.Permutation perm, double p, bool[,] subspace) {
+      //Log("BEFOR: {0}", string.Join(", ", lle));
+      // The goal of the mutation is to disrupt crossover when it's in an agreeing position
+      foreach (var opt in ExhaustiveInversionMoveGenerator.Generate(perm).Shuffle(random)) {
+        var prev = opt.Index1 - 1;
+        var next = (opt.Index2 + 1) % perm.Length;
+        if (prev < 0) prev += perm.Length;
+        if (subspace == null || !(subspace[perm[prev], perm[opt.Index1]] && subspace[perm[opt.Index2], perm[next]])) {
+          if (random.NextDouble() < p) {
+            if (subspace != null) {
+              subspace[perm[prev], perm[opt.Index1]] = true;
+              subspace[perm[opt.Index1], perm[prev]] = true;
+              subspace[perm[opt.Index2], perm[next]] = true;
+              subspace[perm[next], perm[opt.Index2]] = true;
+            }
+            InversionManipulator.Apply(perm, opt.Index1, opt.Index2);
+            return;
+          }
+        }
+      }
+    }
+
+    protected override ISingleObjectiveSolutionScope<Encodings.PermutationEncoding.Permutation> Relink(ISingleObjectiveSolutionScope<Encodings.PermutationEncoding.Permutation> a, ISingleObjectiveSolutionScope<Encodings.PermutationEncoding.Permutation> b, CancellationToken token) {
+      if (double.IsNaN(a.Fitness)) Evaluate(a, token);
+      if (double.IsNaN(b.Fitness)) Evaluate(b, token);
+      if (Context.Random.NextDouble() < 0.5)
+        return IsBetter(a, b) ? Relink(a, b, token, false) : Relink(b, a, token, true);
+      else return IsBetter(a, b) ? Relink(b, a, token, true) : Relink(a, b, token, false);
+    }
+
+    protected virtual ISingleObjectiveSolutionScope<Encodings.PermutationEncoding.Permutation> Relink(ISingleObjectiveSolutionScope<Encodings.PermutationEncoding.Permutation> betterScope, ISingleObjectiveSolutionScope<Encodings.PermutationEncoding.Permutation> worseScope, CancellationToken token, bool fromWorseToBetter) {
+      var wrapper = new EvaluationWrapper<Encodings.PermutationEncoding.Permutation>(Problem, betterScope);
+      double quality;
+      return ToScope(Relink(Context.Random, betterScope.Solution, worseScope.Solution, wrapper.Evaluate, out quality));
+    }
+
+    public static Encodings.PermutationEncoding.Permutation Relink(IRandom random, Encodings.PermutationEncoding.Permutation p1, Encodings.PermutationEncoding.Permutation p2, Func<Encodings.PermutationEncoding.Permutation, IRandom, double> eval, out double best) {
+      if (p1.PermutationType != p2.PermutationType) throw new ArgumentException(string.Format("Unequal permutation types {0} and {1}", p1.PermutationType, p2.PermutationType));
+      switch (p1.PermutationType) {
+        case PermutationTypes.Absolute:
+          return RelinkSwap(random, p1, p2, eval, out best);
+        case PermutationTypes.RelativeDirected:
+          return RelinkShift(random, p1, p2, eval, out best);
+        case PermutationTypes.RelativeUndirected:
+          return RelinkOpt(random, p1, p2, eval, out best);
+        default: throw new ArgumentException(string.Format("Unknown permutation type {0}", p1.PermutationType));
+      }
+    }
+
+    public static Encodings.PermutationEncoding.Permutation RelinkSwap(IRandom random, Encodings.PermutationEncoding.Permutation p1, Encodings.PermutationEncoding.Permutation p2, Func<Encodings.PermutationEncoding.Permutation, IRandom, double> eval, out double best) {
+      var child = (Encodings.PermutationEncoding.Permutation)p1.Clone();
+
+      best = double.NaN;
+      Encodings.PermutationEncoding.Permutation bestChild = null;
+
+      var options = Enumerable.Range(0, child.Length).Where(x => child[x] != p2[x]).ToList();
+      var invChild = new int[child.Length];
+      for (var i = 0; i < child.Length; i++) invChild[child[i]] = i;
+
+      //Log(string.Join(", ", child));
+      while (options.Count > 0) {
+        int bestOption = -1;
+        var bestChange = double.NaN;
+        for (var j = 0; j < options.Count; j++) {
+          var idx = options[j];
+          if (child[idx] == p2[idx]) {
+            options.RemoveAt(j);
+            j--;
+            continue;
+          }
+          Swap(child, invChild[p2[idx]], idx);
+          var moveF = eval(child, random);
+          if (double.IsNaN(bestChange) || moveF < bestChange) {
+            bestChange = moveF;
+            bestOption = j;
+          }
+          // undo
+          Swap(child, invChild[p2[idx]], idx);
+        }
+        if (!double.IsNaN(bestChange)) {
+          var idx1 = options[bestOption];
+          var idx2 = invChild[p2[idx1]];
+          Swap(child, idx1, idx2);
+          invChild[child[idx1]] = idx1;
+          invChild[child[idx2]] = idx2;
+          //Log(string.Join(", ", child));
+          if (double.IsNaN(best) || bestChange < best) {
+            if (Dist(child, p2) > 0) {
+              best = bestChange;
+              bestChild = (Encodings.PermutationEncoding.Permutation)child.Clone();
+            }
+          }
+          options.RemoveAt(bestOption);
+        }
+      }
+      //Log(string.Join(", ", p2));
+
+      if (VALIDATE && bestChild != null && !bestChild.Validate()) throw new ArgumentException("Relinking produced invalid child");
+      if (VALIDATE && Dist(child, p2) > 0) throw new InvalidOperationException("Child is not equal to p2 after relinking");
+
+      if (bestChild == null) best = eval(child, random);
+      return bestChild ?? child;
+    }
+
+    public static Encodings.PermutationEncoding.Permutation RelinkShift(IRandom random, Encodings.PermutationEncoding.Permutation p1, Encodings.PermutationEncoding.Permutation p2, Func<Encodings.PermutationEncoding.Permutation, IRandom, double> eval, out double best) {
+      var child = (Encodings.PermutationEncoding.Permutation)p1.Clone();
+
+      best = double.NaN;
+      Encodings.PermutationEncoding.Permutation bestChild = null;
+
+      var invChild = new int[child.Length];
+      for (var i = 0; i < child.Length; i++) invChild[child[i]] = i;
+
+      var bestChange = double.NaN;
+      do {
+        int bestFrom = -1, bestTo = -1;
+        bestChange = double.NaN;
+        for (var j = 0; j < child.Length; j++) {
+          var c = invChild[p2[j]];
+          var n = invChild[p2.GetCircular(j + 1)];
+          if (n - c == 1 || c == child.Length - 1 && n == 0) continue;
+
+          if (c < n) Shift(child, from: n, to: c + 1);
+          else Shift(child, from: c, to: n);
+          var moveF = eval(child, random);
+          if (double.IsNaN(bestChange) || moveF < bestChange) {
+            bestChange = moveF;
+            bestFrom = c < n ? n : c;
+            bestTo = c < n ? c + 1 : n;
+          }
+          // undo
+          if (c < n) Shift(child, from: c + 1, to: n);
+          else Shift(child, from: n, to: c);
+        }
+        if (!double.IsNaN(bestChange)) {
+          Shift(child, bestFrom, bestTo);
+          for (var i = Math.Min(bestFrom, bestTo); i < Math.Max(bestFrom, bestTo); i++) invChild[child[i]] = i;
+          if (double.IsNaN(best) || bestChange < best) {
+            best = bestChange;
+            bestChild = (Encodings.PermutationEncoding.Permutation)child.Clone();
+          }
+        }
+      } while (!double.IsNaN(bestChange));
+
+      if (VALIDATE && !bestChild.Validate()) throw new ArgumentException("Relinking produced invalid child");
+      if (VALIDATE && Dist(child, p2) > 0) throw new InvalidOperationException("Child is not equal to p2 after relinking");
+      return bestChild;
+    }
+
+    public static Encodings.PermutationEncoding.Permutation RelinkOpt(IRandom random, Encodings.PermutationEncoding.Permutation p1, Encodings.PermutationEncoding.Permutation p2, Func<Encodings.PermutationEncoding.Permutation, IRandom, double> eval, out double best) {
+      var child = (Encodings.PermutationEncoding.Permutation)p1.Clone();
+
+      best = double.NaN;
+      Encodings.PermutationEncoding.Permutation bestChild = null;
+
+      var invChild = new int[child.Length];
+      var invP2 = new int[child.Length];
+      for (var i = 0; i < child.Length; i++) {
+        invChild[child[i]] = i;
+        invP2[p2[i]] = i;
+      }
+
+      var bestChange = double.NaN;
+      var moveQueue = new Queue<Tuple<int, int>>();
+      var undoStack = new Stack<Tuple<int, int>>();
+      do {
+        Queue<Tuple<int, int>> bestQueue = null;
+        bestChange = double.NaN;
+        //Log("{0}", string.Join(" ", child));
+        for (var j = 0; j < p2.Length; j++) {
+          if (IsUndirectedEdge(invChild, p2[j], p2.GetCircular(j + 1))) continue;
+
+          var a = invChild[p2[j]];
+          var b = invChild[p2.GetCircular(j + 1)];
+          if (a > b) { var h = a; a = b; b = h; }
+          var aprev = a - 1;
+          var bprev = b - 1;
+          while (IsUndirectedEdge(invP2, child.GetCircular(aprev), child.GetCircular(aprev + 1))) {
+            aprev--;
+          }
+          while (IsUndirectedEdge(invP2, child.GetCircular(bprev), child.GetCircular(bprev + 1))) {
+            bprev--;
+          }
+          var bnext = b + 1;
+          var anext = a + 1;
+          while (IsUndirectedEdge(invP2, child.GetCircular(bnext - 1), child.GetCircular(bnext))) {
+            bnext++;
+          }
+          while (IsUndirectedEdge(invP2, child.GetCircular(anext - 1), child.GetCircular(anext))) {
+            anext++;
+          }
+          aprev++; bprev++; anext--; bnext--;
+
+          if (aprev < a && bnext > b) {
+            if (aprev < 0) {
+              moveQueue.Enqueue(Tuple.Create(a + 1, bnext));
+              moveQueue.Enqueue(Tuple.Create(a + 1, a + 1 + (bnext - b)));
+            } else {
+              moveQueue.Enqueue(Tuple.Create(aprev, b - 1));
+              moveQueue.Enqueue(Tuple.Create(b - 1 - (a - aprev), b - 1));
+            }
+          } else if (aprev < a && bnext == b && bprev == b) {
+            moveQueue.Enqueue(Tuple.Create(a + 1, b));
+          } else if (aprev < a && bprev < b) {
+            moveQueue.Enqueue(Tuple.Create(a + 1, b));
+          } else if (aprev == a && anext == a && bnext > b) {
+            moveQueue.Enqueue(Tuple.Create(a, b - 1));
+          } else if (aprev == a && anext == a && bnext == b && bprev == b) {
+            moveQueue.Enqueue(Tuple.Create(a, b - 1));
+          } else if (aprev == a && anext == a && bprev < b) {
+            moveQueue.Enqueue(Tuple.Create(a + 1, b));
+          } else if (anext > a && bnext > b) {
+            moveQueue.Enqueue(Tuple.Create(a, b - 1));
+          } else if (anext > a && bnext == b && bprev == b) {
+            moveQueue.Enqueue(Tuple.Create(a, b - 1));
+          } else /*if (anext > a && bprev < b)*/ {
+            moveQueue.Enqueue(Tuple.Create(a, bprev - 1));
+            moveQueue.Enqueue(Tuple.Create(bprev, b));
+          }
+
+          while (moveQueue.Count > 0) {
+            var m = moveQueue.Dequeue();
+            Opt(child, m.Item1, m.Item2);
+            undoStack.Push(m);
+          }
+          var moveF = eval(child, random);
+          if (double.IsNaN(bestChange) || moveF < bestChange) {
+            bestChange = moveF;
+            bestQueue = new Queue<Tuple<int, int>>(undoStack.Reverse());
+          }
+          // undo
+          while (undoStack.Count > 0) {
+            var m = undoStack.Pop();
+            Opt(child, m.Item1, m.Item2);
+          }
+        }
+        if (!double.IsNaN(bestChange)) {
+          while (bestQueue.Count > 0) {
+            var m = bestQueue.Dequeue();
+            //Log("Applying opt {0} {1}", m.Item1, m.Item2);
+            //Log("{0}", string.Join(" ", child));
+            Opt(child, m.Item1, m.Item2);
+            //Log("{0}", string.Join(" ", child));
+          }
+          for (var i = 0; i < child.Length; i++) invChild[child[i]] = i;
+          if (double.IsNaN(best) || bestChange < best) {
+            best = bestChange;
+            bestChild = (Encodings.PermutationEncoding.Permutation)child.Clone();
+          }
+        }
+      } while (!double.IsNaN(bestChange));
+
+      //Log("{0}", string.Join(" ", p2));
+      if (VALIDATE && !bestChild.Validate()) throw new ArgumentException("Relinking produced invalid child");
+      if (VALIDATE && Dist(child, p2) > 0) throw new InvalidOperationException("Child is not equal to p2 after relinking");
+      return bestChild;
+    }
+
+    private static bool IsUndirectedEdge(int[] invP, int a, int b) {
+      var d = Math.Abs(invP[a] - invP[b]);
+      return d == 1 || d == invP.Length - 1;
+    }
+
+    private static void Move(Encodings.PermutationEncoding.Permutation child, int from, int to) {
+      if (child.PermutationType == PermutationTypes.Absolute) {
+        // swap
+        Swap(child, from, to);
+      } else if (child.PermutationType == PermutationTypes.RelativeDirected) {
+        // shift
+        Shift(child, from, to);
+      } else if (child.PermutationType == PermutationTypes.RelativeUndirected) {
+        // opt
+        Opt(child, from, to);
+      } else throw new ArgumentException(string.Format("Unknown permutation type {0}", child.PermutationType));
+    }
+
+    private static void Move(PermutationTypes type, bool[] arr, int from, int to) {
+      switch (type) {
+        case PermutationTypes.Absolute: {
+            /*var h = arr[from];
+            arr[from] = arr[to];
+            arr[to] = h;*/
+            arr[from] = false;
+            arr[to] = false;
+            break;
+          }
+        case PermutationTypes.RelativeDirected: {
+            var original = (bool[])arr.Clone();
+            var number = original[from];
+            int i = 0;  // index in new permutation
+            int j = 0;  // index in old permutation
+            while (i < original.Length) {
+              if (j == from) {
+                j++;
+              }
+              if (i == to) {
+                arr[i] = number;
+                i++;
+              }
+              if ((i < original.Length) && (j < original.Length)) {
+                arr[i] = original[j];
+                i++;
+                j++;
+              }
+            }
+            break;
+          }
+        case PermutationTypes.RelativeUndirected: {
+            if (from > to) {
+              var hu = from;
+              from = to;
+              to = hu;
+            }
+            for (int i = 0; i <= (to - from) / 2; i++) {  // invert permutation between breakpoints
+              var temp = arr[from + i];
+              arr[from + i] = arr[to - i];
+              arr[to - i] = temp;
+            }
+            break;
+          }
+        default:
+          throw new ArgumentException(string.Format("Unknown permutation type {0}", type));
+      }
+    }
+
+    private static void Swap(Encodings.PermutationEncoding.Permutation child, int from, int to) {
+      Swap2Manipulator.Apply(child, from, to);
+    }
+
+    private static void Shift(Encodings.PermutationEncoding.Permutation child, int from, int to) {
+      TranslocationManipulator.Apply(child, from, from, to);
+    }
+
+    private static void Opt(Encodings.PermutationEncoding.Permutation child, int from, int to) {
+      if (from > to) {
+        var h = from;
+        from = to;
+        to = h;
+      }
+      InversionManipulator.Apply(child, from, to);
+    }
+  }
+}
Index: /branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/Permutation/PermutationMemPRContext.cs
===================================================================
--- /branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/Permutation/PermutationMemPRContext.cs	(revision 14450)
+++ /branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/Permutation/PermutationMemPRContext.cs	(revision 14450)
@@ -0,0 +1,80 @@
+﻿#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.Algorithms.MemPR.Interfaces;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Encodings.PermutationEncoding;
+using HeuristicLab.Optimization;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Algorithms.MemPR.Permutation {
+  [Item("MemPR Population Context (permutation)", "MemPR population context for permutation encoded problems.")]
+  [StorableClass]
+  public sealed class PermutationMemPRPopulationContext : MemPRPopulationContext<SingleObjectiveBasicProblem<PermutationEncoding>, Encodings.PermutationEncoding.Permutation, PermutationMemPRPopulationContext, PermutationMemPRSolutionContext> {
+
+    [StorableConstructor]
+    private PermutationMemPRPopulationContext(bool deserializing) : base(deserializing) { }
+    private PermutationMemPRPopulationContext(PermutationMemPRPopulationContext original, Cloner cloner)
+      : base(original, cloner) { }
+    public PermutationMemPRPopulationContext() : base("PermutationMemPRPopulationContext") { }
+    public PermutationMemPRPopulationContext(string name) : base(name) { }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new PermutationMemPRPopulationContext(this, cloner);
+    }
+
+    public override PermutationMemPRSolutionContext CreateSingleSolutionContext(ISingleObjectiveSolutionScope<Encodings.PermutationEncoding.Permutation> solution) {
+      return new PermutationMemPRSolutionContext(this, solution);
+    }
+  }
+
+  [Item("MemPR Solution Context (permutation)", "MemPR solution context for permutation encoded problems.")]
+  [StorableClass]
+  public sealed class PermutationMemPRSolutionContext : MemPRSolutionContext<SingleObjectiveBasicProblem<PermutationEncoding>, Encodings.PermutationEncoding.Permutation, PermutationMemPRPopulationContext, PermutationMemPRSolutionContext>, IPermutationSubspaceContext {
+
+    [Storable]
+    private IValueParameter<PermutationSolutionSubspace> subspace;
+    public PermutationSolutionSubspace Subspace {
+      get { return subspace.Value; }
+    }
+    ISolutionSubspace<Encodings.PermutationEncoding.Permutation> ISolutionSubspaceContext<Encodings.PermutationEncoding.Permutation>.Subspace {
+      get { return Subspace; }
+    }
+
+    [StorableConstructor]
+    private PermutationMemPRSolutionContext(bool deserializing) : base(deserializing) { }
+    private PermutationMemPRSolutionContext(PermutationMemPRSolutionContext original, Cloner cloner)
+      : base(original, cloner) {
+
+    }
+    public PermutationMemPRSolutionContext(PermutationMemPRPopulationContext baseContext, ISingleObjectiveSolutionScope<Encodings.PermutationEncoding.Permutation> solution)
+      : base(baseContext, solution) {
+
+      Parameters.Add(subspace = new ValueParameter<PermutationSolutionSubspace>("Subspace", new PermutationSolutionSubspace(null)));
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new PermutationMemPRSolutionContext(this, cloner);
+    }
+  }
+}
Index: /branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/Permutation/PermutationSolutionSubspace.cs
===================================================================
--- /branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/Permutation/PermutationSolutionSubspace.cs	(revision 14450)
+++ /branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/Permutation/PermutationSolutionSubspace.cs	(revision 14450)
@@ -0,0 +1,50 @@
+﻿#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.Algorithms.MemPR.Interfaces;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Algorithms.MemPR.Permutation {
+  [Item("Solution subspace (Permutation)", "")]
+  [StorableClass]
+  public sealed class PermutationSolutionSubspace : Item, ISolutionSubspace<Encodings.PermutationEncoding.Permutation> {
+
+    [Storable]
+    private bool[,] subspace;
+    public bool[,] Subspace { get { return subspace; } }
+
+    [StorableConstructor]
+    private PermutationSolutionSubspace(bool deserializing) : base(deserializing) { }
+    private PermutationSolutionSubspace(PermutationSolutionSubspace original, Cloner cloner)
+      : base(original, cloner) {
+      subspace = (bool[,])original.subspace.Clone();
+    }
+    public PermutationSolutionSubspace(bool[,] subspace) {
+      this.subspace = subspace;
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new PermutationSolutionSubspace(this, cloner);
+    }
+  }
+}
Index: /branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/Permutation/SimilarityCalculator.cs
===================================================================
--- /branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/Permutation/SimilarityCalculator.cs	(revision 14450)
+++ /branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/Permutation/SimilarityCalculator.cs	(revision 14450)
@@ -0,0 +1,91 @@
+﻿#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 HeuristicLab.Encodings.PermutationEncoding;
+
+namespace HeuristicLab.Algorithms.MemPR.Permutation {
+  public static class PermutationSimilarityCalculator {
+
+    public static double CalculateSimilarity(Encodings.PermutationEncoding.Permutation left, Encodings.PermutationEncoding.Permutation right) {
+      if (left == null || right == null)
+        throw new ArgumentException("Cannot calculate similarity because one of the provided solutions or both are null.");
+      if (left.PermutationType != right.PermutationType)
+        throw new ArgumentException("Cannot calculate similarity because the provided solutions have different types.");
+      if (left.Length != right.Length)
+        throw new ArgumentException("Cannot calculate similarity because the provided solutions have different lengths.");
+      if (object.ReferenceEquals(left, right)) return 1.0;
+
+      switch (left.PermutationType) {
+        case PermutationTypes.Absolute:
+          return CalculateAbsolute(left, right);
+        case PermutationTypes.RelativeDirected:
+          return CalculateRelativeDirected(left, right);
+        case PermutationTypes.RelativeUndirected:
+          return CalculateRelativeUndirected(left, right);
+        default:
+          throw new InvalidOperationException("unknown permutation type");
+      }
+    }
+
+    private static double CalculateAbsolute(Encodings.PermutationEncoding.Permutation left, Encodings.PermutationEncoding.Permutation right) {
+      double similarity = 0.0;
+      for (int i = 0; i < left.Length; i++)
+        if (left[i] == right[i]) similarity++;
+
+      return similarity / left.Length;
+    }
+
+    private static double CalculateRelativeDirected(Encodings.PermutationEncoding.Permutation left, Encodings.PermutationEncoding.Permutation right) {
+      int[] edgesR = CalculateEdgesVector(right);
+      int[] edgesL = CalculateEdgesVector(left);
+
+      double similarity = 0.0;
+      for (int i = 0; i < left.Length; i++) {
+        if (edgesL[i] == edgesR[i]) similarity++;
+      }
+
+      return similarity / left.Length;
+    }
+
+    private static double CalculateRelativeUndirected(Encodings.PermutationEncoding.Permutation left, Encodings.PermutationEncoding.Permutation right) {
+      int[] edgesR = CalculateEdgesVector(right);
+      int[] edgesL = CalculateEdgesVector(left);
+
+      double similarity = 0.0;
+      for (int i = 0; i < left.Length; i++) {
+        if ((edgesL[i] == edgesR[i]) || (edgesL[edgesR[i]] == i))
+          similarity++;
+      }
+
+      return similarity / left.Length;
+    }
+
+    private static int[] CalculateEdgesVector(Encodings.PermutationEncoding.Permutation permutation) {
+      // transform path representation into adjacency representation
+      int[] edgesVector = new int[permutation.Length];
+      for (int i = 0; i < permutation.Length - 1; i++)
+        edgesVector[permutation[i]] = permutation[i + 1];
+      edgesVector[permutation[permutation.Length - 1]] = permutation[0];
+      return edgesVector;
+    }
+  }
+}
Index: /branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/Permutation/SolutionModel/Univariate/StaticAPI/Trainer.cs
===================================================================
--- /branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/Permutation/SolutionModel/Univariate/StaticAPI/Trainer.cs	(revision 14450)
+++ /branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/Permutation/SolutionModel/Univariate/StaticAPI/Trainer.cs	(revision 14450)
@@ -0,0 +1,47 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2016 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using HeuristicLab.Algorithms.MemPR.Interfaces;
+using HeuristicLab.Core;
+using HeuristicLab.Encodings.PermutationEncoding;
+
+namespace HeuristicLab.Algorithms.MemPR.Permutation.SolutionModel.Univariate {
+  public static class Trainer {
+    public static ISolutionModel<Encodings.PermutationEncoding.Permutation> Train(IRandom random, IList<Encodings.PermutationEncoding.Permutation> pop, int N) {
+      ISolutionModel<Encodings.PermutationEncoding.Permutation> model;
+      switch (pop[0].PermutationType) {
+        case PermutationTypes.Absolute:
+          model = UnivariateAbsoluteModel.Create(random, pop, N);
+          break;
+        case PermutationTypes.RelativeDirected:
+          model = UnivariateRelativeModel.CreateDirected(random, pop, N);
+          break;
+        case PermutationTypes.RelativeUndirected:
+          model = UnivariateRelativeModel.CreateUndirected(random, pop, N);
+          break;
+        default: throw new ArgumentException(string.Format("unknown permutation type {0}", pop[0].PermutationType));
+      }
+      return model;
+    }
+  }
+}
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 14450)
+++ /branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/Permutation/SolutionModel/Univariate/UnbiasedModelTrainer.cs	(revision 14450)
@@ -0,0 +1,53 @@
+﻿#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.Linq;
+using HeuristicLab.Algorithms.MemPR.Interfaces;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Encodings.PermutationEncoding;
+using HeuristicLab.Optimization;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Algorithms.MemPR.Permutation.SolutionModel.Univariate {
+  [Item("Unbiased Univariate Model Trainer (Permutation)", "", ExcludeGenericTypeInfo = true)]
+  [StorableClass]
+  public class UniasedModelTrainer<TContext> : NamedItem, ISolutionModelTrainer<TContext>
+    where TContext : IPopulationBasedHeuristicAlgorithmContext<SingleObjectiveBasicProblem<PermutationEncoding>, Encodings.PermutationEncoding.Permutation>,
+    ISolutionModelContext<Encodings.PermutationEncoding.Permutation> {
+    
+    [StorableConstructor]
+    protected UniasedModelTrainer(bool deserializing) : base(deserializing) { }
+    protected UniasedModelTrainer(UniasedModelTrainer<TContext> original, Cloner cloner) : base(original, cloner) { }
+    public UniasedModelTrainer() {
+      Name = ItemName;
+      Description = ItemDescription;
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new UniasedModelTrainer<TContext>(this, cloner);
+    }
+
+    public void TrainModel(TContext context) {
+      context.Model = Trainer.Train(context.Random, context.Population.Select(x => x.Solution).ToList(), context.Problem.Encoding.Length);
+    }
+  }
+}
Index: /branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/Permutation/SolutionModel/Univariate/UnivariateAbsoluteModel.cs
===================================================================
--- /branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/Permutation/SolutionModel/Univariate/UnivariateAbsoluteModel.cs	(revision 14450)
+++ /branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/Permutation/SolutionModel/Univariate/UnivariateAbsoluteModel.cs	(revision 14450)
@@ -0,0 +1,97 @@
+﻿#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.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Algorithms.MemPR.Interfaces;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Encodings.PermutationEncoding;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Random;
+
+namespace HeuristicLab.Algorithms.MemPR.Permutation.SolutionModel.Univariate {
+  [Item("Univariate solution model (Permutation.Absolute)", "")]
+  [StorableClass]
+  public sealed class UnivariateAbsoluteModel : Item, ISolutionModel<Encodings.PermutationEncoding.Permutation> {
+    [Storable]
+    public IntMatrix Probabilities { get; set; }
+    [Storable]
+    public IRandom Random { get; set; }
+
+    [StorableConstructor]
+    private UnivariateAbsoluteModel(bool deserializing) : base(deserializing) { }
+    private UnivariateAbsoluteModel(UnivariateAbsoluteModel original, Cloner cloner)
+      : base(original, cloner) {
+      Probabilities = cloner.Clone(original.Probabilities);
+      Random = cloner.Clone(original.Random);
+    }
+    public UnivariateAbsoluteModel(IRandom random, int[,] probabilities) {
+      Probabilities = new IntMatrix(probabilities);
+      Random = random;
+    }
+    public UnivariateAbsoluteModel(IRandom random, IntMatrix probabilties) {
+      Probabilities = probabilties;
+      Random = random;
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new UnivariateAbsoluteModel(this, cloner);
+    }
+
+    public Encodings.PermutationEncoding.Permutation Sample() {
+      var N = Probabilities.Rows;
+      var child = new Encodings.PermutationEncoding.Permutation(PermutationTypes.Absolute, N);
+      var indices = Enumerable.Range(0, N).Shuffle(Random).ToList();
+      var values = Enumerable.Range(0, N).Shuffle(Random).ToList();
+      for (var i = N - 1; i > 0; i--) {
+        var nextIndex = indices[i];
+        var total = 0.0;
+        for (var v = 0; v < values.Count; v++) {
+          total += Probabilities[nextIndex, values[v]] + 1.0 / N;
+        }
+        var ball = Random.NextDouble() * total;
+        for (var v = 0; v < values.Count; v++) {
+          ball -= Probabilities[nextIndex, values[v]] + 1.0 / N;
+          if (ball <= 0.0) {
+            child[nextIndex] = values[v];
+            values.RemoveAt(v);
+            indices.RemoveAt(i);
+            break;
+          }
+        }
+      }
+      child[indices[0]] = values[0];
+      return child;
+    }
+
+    public static UnivariateAbsoluteModel Create(IRandom random, IList<Encodings.PermutationEncoding.Permutation> pop, int N) {
+      var model = new int[N, N];
+      for (var i = 0; i < pop.Count; i++) {
+        for (var j = 0; j < N; j++) {
+          model[j, pop[i][j]]++;
+        }
+      }
+      return new UnivariateAbsoluteModel(random, model);
+    }
+  }
+}
Index: /branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/Permutation/SolutionModel/Univariate/UnivariateRelativeModel.cs
===================================================================
--- /branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/Permutation/SolutionModel/Univariate/UnivariateRelativeModel.cs	(revision 14450)
+++ /branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/Permutation/SolutionModel/Univariate/UnivariateRelativeModel.cs	(revision 14450)
@@ -0,0 +1,122 @@
+﻿#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.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Algorithms.MemPR.Interfaces;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Encodings.PermutationEncoding;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Random;
+
+namespace HeuristicLab.Algorithms.MemPR.Permutation.SolutionModel.Univariate {
+  [Item("Univariate solution model (Permutation.Relative)", "")]
+  [StorableClass]
+  public sealed class UnivariateRelativeModel : Item, ISolutionModel<Encodings.PermutationEncoding.Permutation> {
+    [Storable]
+    public IntMatrix Probabilities { get; set; }
+
+    [Storable]
+    public IRandom Random { get; set; }
+
+    [Storable]
+    public PermutationTypes PermutationType { get; set; }
+
+    [StorableConstructor]
+    private UnivariateRelativeModel(bool deserializing) : base(deserializing) { }
+    private UnivariateRelativeModel(UnivariateRelativeModel original, Cloner cloner)
+      : base(original, cloner) {
+      Probabilities = cloner.Clone(original.Probabilities);
+      Random = cloner.Clone(original.Random);
+      PermutationType = original.PermutationType;
+    }
+    public UnivariateRelativeModel(IRandom random, int[,] probabilities, PermutationTypes permutationType) {
+      Probabilities = new IntMatrix(probabilities);
+      Random = random;
+      PermutationType = permutationType;
+    }
+    public UnivariateRelativeModel(IRandom random, IntMatrix probabilties, PermutationTypes permutationType) {
+      Probabilities = probabilties;
+      Random = random;
+      PermutationType = permutationType;
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new UnivariateRelativeModel(this, cloner);
+    }
+
+    public Encodings.PermutationEncoding.Permutation Sample() {
+      var N = Probabilities.Rows;
+      var next = Random.Next(N);
+      var child = new Encodings.PermutationEncoding.Permutation(PermutationType, N);
+      child[0] = next;
+      var open = Enumerable.Range(0, N).Where(x => x != next).Shuffle(Random).ToList();
+      for (var i = 1; i < N - 1; i++) {
+        var total = 0.0;
+        for (var j = 0; j < open.Count; j++) {
+          total += Probabilities[next, open[j]] + 1.0 / N;
+        }
+        var ball = Random.NextDouble() * total;
+        for (var j = 0; j < open.Count; j++) {
+          ball -= Probabilities[next, open[j]] + 1.0 / N;
+          if (ball <= 0.0) {
+            child[i] = open[j];
+            next = open[j];
+            open.RemoveAt(j);
+            break;
+          }
+        }
+      }
+      child[N - 1] = open[0];
+      return child;
+    }
+
+    public static UnivariateRelativeModel CreateDirected(IRandom random, IList<Encodings.PermutationEncoding.Permutation> pop, int N) {
+      var model = new int[N, N];
+      for (var i = 0; i < pop.Count; i++) {
+        for (var j = 0; j < N - 1; j++) {
+          for (var k = j + 1; k < N; k++) {
+            model[pop[i][j], pop[i][k]]++;
+          }
+          model[pop[i][N - 1], pop[i][0]]++;
+        }
+      }
+      return new UnivariateRelativeModel(random, model, PermutationTypes.RelativeDirected);
+    }
+
+    public static UnivariateRelativeModel CreateUndirected(IRandom random, IList<Encodings.PermutationEncoding.Permutation> pop, int N) {
+      var model = new int[N, N];
+      for (var i = 0; i < pop.Count; i++) {
+        for (var j = 0; j < N - 1; j++) {
+          for (var k = j + 1; k < N; k++) {
+            model[pop[i][j], pop[i][k]]++;
+            model[pop[i][k], pop[i][j]]++;
+          }
+          model[pop[i][0], pop[i][N - 1]]++;
+          model[pop[i][N - 1], pop[i][0]]++;
+        }
+      }
+      return new UnivariateRelativeModel(random, model, PermutationTypes.RelativeUndirected);
+    }
+  }
+}
Index: /branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/SingleObjectiveSolutionScope.cs
===================================================================
--- /branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/SingleObjectiveSolutionScope.cs	(revision 14449)
+++ /branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/SingleObjectiveSolutionScope.cs	(revision 14450)
@@ -21,4 +21,5 @@
 
 using System.Drawing;
+using HeuristicLab.Algorithms.MemPR.Interfaces;
 using HeuristicLab.Collections;
 using HeuristicLab.Common;
@@ -139,9 +140,4 @@
       Fitness = orphan.Fitness;
     }
-
-    public void Adopt(ISolutionScope<T> orphan) {
-      Solution = orphan.Solution;
-      Fitness = double.NaN;
-    }
   }
 }
Index: /branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/Util/EvaluationWrapper.cs
===================================================================
--- /branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/Util/EvaluationWrapper.cs	(revision 14450)
+++ /branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/Util/EvaluationWrapper.cs	(revision 14450)
@@ -0,0 +1,50 @@
+﻿#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.Algorithms.MemPR.Interfaces;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Optimization;
+
+namespace HeuristicLab.Algorithms.MemPR.Util {
+  public sealed class EvaluationWrapper<TSolution>
+      where TSolution : class, IItem {
+    private readonly ISingleObjectiveProblemDefinition problem;
+    private readonly ISingleObjectiveSolutionScope<TSolution> scope;
+    private readonly SingleEncodingIndividual individual;
+
+    public EvaluationWrapper(ISingleObjectiveProblemDefinition problem, ISingleObjectiveSolutionScope<TSolution> solution) {
+      this.problem = problem;
+      this.scope = (ISingleObjectiveSolutionScope<TSolution>)solution.Clone();
+      this.individual = new SingleEncodingIndividual(problem.Encoding, this.scope);
+    }
+
+    public double Evaluate(TSolution b) {
+      scope.Solution = b;
+      return problem.Evaluate(individual, null);
+    }
+
+    public double Evaluate(TSolution b, IRandom random) {
+      scope.Solution = b;
+      return problem.Evaluate(individual, random);
+    }
+  }
+}
Index: /branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/Util/FitnessComparer.cs
===================================================================
--- /branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/Util/FitnessComparer.cs	(revision 14450)
+++ /branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/Util/FitnessComparer.cs	(revision 14450)
@@ -0,0 +1,29 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2016 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+namespace HeuristicLab.Algorithms.MemPR.Util {
+  public static class FitnessComparer {
+    public static bool IsBetter(bool maximization, double a, double b) {
+      return maximization && a > b
+             || !maximization && a < b;
+    }
+  }
+}
