Index: branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/LinearLinkage/LinearLinkageMemPR.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/LinearLinkage/LinearLinkageMemPR.cs	(revision 14551)
+++ branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/LinearLinkage/LinearLinkageMemPR.cs	(revision 14552)
@@ -37,5 +37,5 @@
   [StorableClass]
   [Creatable(CreatableAttribute.Categories.PopulationBasedAlgorithms, Priority = 999)]
-  public class LinearLinkageMemPR : MemPRAlgorithm<SingleObjectiveBasicProblem<LinearLinkageEncoding>, LinearLinkage, LinearLinkageMemPRPopulationContext, LinearLinkageMemPRSolutionContext> {
+  public class LinearLinkageMemPR : MemPRAlgorithm<ISingleObjectiveHeuristicOptimizationProblem, LinearLinkage, LinearLinkageMemPRPopulationContext, LinearLinkageMemPRSolutionContext> {
     [StorableConstructor]
     protected LinearLinkageMemPR(bool deserializing) : base(deserializing) { }
@@ -69,12 +69,4 @@
     }
 
-    protected override ISingleObjectiveSolutionScope<LinearLinkage> ToScope(LinearLinkage code, double fitness = double.NaN) {
-      var creator = Problem.SolutionCreator as ILinearLinkageCreator;
-      if (creator == null) throw new InvalidOperationException("Can only solve linear linkage encoded problems with MemPR (linear linkage)");
-      return new SingleObjectiveSolutionScope<LinearLinkage>(code, creator.LLEParameter.ActualName, fitness, Problem.Evaluator.QualityParameter.ActualName) {
-        Parent = Context.Scope
-      };
-    }
-
     protected override ISolutionSubspace<LinearLinkage> CalculateSubspace(IEnumerable<LinearLinkage> solutions, bool inverse = false) {
       var pop = solutions.ToList();
@@ -95,10 +87,10 @@
         int maxEvals, CancellationToken token,
         ISolutionSubspace<LinearLinkage> sub_space = null) {
-      var maximization = Context.Problem.Maximization;
+      var maximization = Context.Maximization;
       var subspace = sub_space is LinearLinkageSolutionSubspace ? ((LinearLinkageSolutionSubspace)sub_space).Subspace : null;
       var evaluations = 0;
       var quality = scope.Fitness;
       if (double.IsNaN(quality)) {
-        Evaluate(scope, token);
+        Context.Evaluate(scope, token);
         quality = scope.Fitness;
         evaluations++;
@@ -168,5 +160,5 @@
               move.Apply(current);
               var qualityToRestore = tabu[i, current[i]]; // current[i] is new next
-              Evaluate(currentScope, token);
+              Context.Evaluate(currentScope, token);
               evaluations++;
               var moveF = currentScope.Fitness;
@@ -255,5 +247,5 @@
       var cachehits = 0;
       var evaluations = 0;
-      var probe = ToScope((LinearLinkage)p1.Solution.Clone());
+      var probe = Context.ToScope((LinearLinkage)p1.Solution.Clone());
       ISingleObjectiveSolutionScope<LinearLinkage> offspring = null;
       while (evaluations < p1.Solution.Length) {
@@ -268,5 +260,5 @@
           continue;
         }
-        Evaluate(probe, token);
+        Context.Evaluate(probe, token);
         evaluations++;
         cache.Add(c);
@@ -283,13 +275,4 @@
     protected override ISingleObjectiveSolutionScope<LinearLinkage> Link(ISingleObjectiveSolutionScope<LinearLinkage> a, ISingleObjectiveSolutionScope<LinearLinkage> b, CancellationToken token, bool delink = false) {
       var evaluations = 0;
-      if (double.IsNaN(a.Fitness)) {
-        Evaluate(a, token);
-        evaluations++;
-      }
-      if (double.IsNaN(b.Fitness)) {
-        Evaluate(b, token);
-        evaluations++;
-      }
-
       var probe = (ISingleObjectiveSolutionScope<LinearLinkage>)a.Clone();
       ISingleObjectiveSolutionScope<LinearLinkage> best = null;
@@ -306,5 +289,5 @@
           if (delink && distAfter > distBefore || !delink && distAfter < distBefore) {
             var beforeQ = probe.Fitness;
-            Evaluate(probe, token);
+            Context.Evaluate(probe, token);
             evaluations++;
             var q = probe.Fitness;
Index: branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/LinearLinkage/LinearLinkageMemPRContext.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/LinearLinkage/LinearLinkageMemPRContext.cs	(revision 14551)
+++ branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/LinearLinkage/LinearLinkageMemPRContext.cs	(revision 14552)
@@ -20,4 +20,6 @@
 #endregion
 
+using System;
+using System.Runtime.Remoting.Contexts;
 using HeuristicLab.Algorithms.MemPR.Interfaces;
 using HeuristicLab.Common;
@@ -31,5 +33,5 @@
   [Item("MemPR Population Context (linear linkage)", "MemPR population context for linear linkage encoded problems.")]
   [StorableClass]
-  public sealed class LinearLinkageMemPRPopulationContext : MemPRPopulationContext<SingleObjectiveBasicProblem<LinearLinkageEncoding>, LinearLinkage, LinearLinkageMemPRPopulationContext, LinearLinkageMemPRSolutionContext> {
+  public sealed class LinearLinkageMemPRPopulationContext : MemPRPopulationContext<ISingleObjectiveHeuristicOptimizationProblem, LinearLinkage, LinearLinkageMemPRPopulationContext, LinearLinkageMemPRSolutionContext> {
 
     [StorableConstructor]
@@ -47,9 +49,17 @@
       return new LinearLinkageMemPRSolutionContext(this, solution);
     }
+
+    public override ISingleObjectiveSolutionScope<LinearLinkage> ToScope(LinearLinkage code, double fitness = double.NaN) {
+      var creator = Problem.SolutionCreator as ILinearLinkageCreator;
+      if (creator == null) throw new InvalidOperationException("Can only solve linear linkage encoded problems with MemPR (linear linkage)");
+      return new SingleObjectiveSolutionScope<LinearLinkage>(code, creator.LLEParameter.ActualName, fitness, Problem.Evaluator.QualityParameter.ActualName) {
+        Parent = Scope
+      };
+    }
   }
 
   [Item("MemPR Solution Context (linear linkage)", "MemPR solution context for linear linkage encoded problems.")]
   [StorableClass]
-  public sealed class LinearLinkageMemPRSolutionContext : MemPRSolutionContext<SingleObjectiveBasicProblem<LinearLinkageEncoding>, LinearLinkage, LinearLinkageMemPRPopulationContext, LinearLinkageMemPRSolutionContext>, ILinearLinkageSubspaceContext {
+  public sealed class LinearLinkageMemPRSolutionContext : MemPRSolutionContext<ISingleObjectiveHeuristicOptimizationProblem, LinearLinkage, LinearLinkageMemPRPopulationContext, LinearLinkageMemPRSolutionContext>, ILinearLinkageSubspaceContext {
 
     [Storable]
Index: branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/LinearLinkage/LocalSearch/ExhaustiveSubspace.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/LinearLinkage/LocalSearch/ExhaustiveSubspace.cs	(revision 14551)
+++ branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/LinearLinkage/LocalSearch/ExhaustiveSubspace.cs	(revision 14552)
@@ -22,5 +22,4 @@
 using System.Threading;
 using HeuristicLab.Algorithms.MemPR.Interfaces;
-using HeuristicLab.Algorithms.MemPR.Util;
 using HeuristicLab.Common;
 using HeuristicLab.Core;
@@ -33,5 +32,6 @@
   [StorableClass]
   public class ExhaustiveSubspace<TContext> : NamedItem, ILocalSearch<TContext>
-      where TContext : ISingleSolutionHeuristicAlgorithmContext<SingleObjectiveBasicProblem<LinearLinkageEncoding>, LinearLinkage>, ILinearLinkageSubspaceContext {
+      where TContext : ISingleSolutionHeuristicAlgorithmContext<ISingleObjectiveHeuristicOptimizationProblem, LinearLinkage>,
+                       ILinearLinkageSubspaceContext, IEvaluationServiceContext<LinearLinkage> {
 
     [StorableConstructor]
@@ -48,9 +48,8 @@
 
     public void Optimize(TContext context) {
-      var evalWrapper = new EvaluationWrapper<LinearLinkage>(context.Problem, context.Solution);
       var quality = context.Solution.Fitness;
       try {
         var result = ExhaustiveLocalSearch.Optimize(context.Random, context.Solution.Solution, ref quality,
-          context.Problem.Maximization, evalWrapper.Evaluate, CancellationToken.None, context.Subspace.Subspace);
+          context.Maximization, context.Evaluate, CancellationToken.None, context.Subspace.Subspace);
         context.IncrementEvaluatedSolutions(result.Item1);
         context.Iterations = result.Item2;
Index: branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/LinearLinkage/LocalSearch/StaticAPI/ExhaustiveLocalSearch.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/LinearLinkage/LocalSearch/StaticAPI/ExhaustiveLocalSearch.cs	(revision 14551)
+++ branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/LinearLinkage/LocalSearch/StaticAPI/ExhaustiveLocalSearch.cs	(revision 14552)
@@ -21,8 +21,8 @@
 
 using System;
+using System.Collections.Generic;
 using System.Linq;
 using System.Threading;
 using HeuristicLab.Algorithms.MemPR.Util;
-using HeuristicLab.Collections;
 using HeuristicLab.Core;
 using HeuristicLab.Encodings.LinearLinkageEncoding;
@@ -30,120 +30,34 @@
 namespace HeuristicLab.Algorithms.MemPR.Grouping.LocalSearch {
   public static class ExhaustiveLocalSearch {
-    public static Tuple<int, int> Optimize(IRandom random, LinearLinkage solution, ref double quality, bool maximization, Func<LinearLinkage, IRandom, double> eval, CancellationToken token, bool[] subspace = null) {
+    public static Tuple<int, int> Optimize(IRandom random, LinearLinkage solution, ref double quality, bool maximization, Func<LinearLinkage, CancellationToken, double> eval, CancellationToken token, bool[] subspace = null) {
       var evaluations = 0;
-      var current = solution;
       if (double.IsNaN(quality)) {
-        quality = eval(current, random);
+        quality = eval(solution, token);
         evaluations++;
       }
       var steps = 0;
-      // this dictionary holds the last relevant links
-      var links = new BidirectionalDictionary<int, int>();
+      var lleb = solution.ToBackLinks();
       for (var iter = 0; iter < int.MaxValue; iter++) {
         var change = false;
-        // clear the dictionary before a new pass through the array is made
-        links.Clear();
-        for (var i = 0; i < current.Length; i++) {
-          if (subspace != null && !subspace[i]) {
-            links.RemoveBySecond(i);
-            links.Add(i, current[i]);
-            continue;
-          }
-          var pred = -1;
-          var isFirst = !links.TryGetBySecond(i, out pred);
-          var keepLink = false;
-          if (!isFirst) {
-            keepLink = subspace != null && !subspace[pred];
-          }
-          var next = current[i];
-          var isLast = next == i;
-
-          if (!keepLink) {
-            // try to insert current into each previous group
-            // first remove i from its group
-            var linksList = links.Where(x => x.Value != i).ToList();
-            if (linksList.Count > 0 && !isFirst) current[pred] = isLast ? pred : next;
-            for (var k = 0; k < linksList.Count; k++) {
-              var l = linksList[k];
-              current[l.Key] = i;
-              current[i] = Math.Max(i, l.Value);
-              var moveF = eval(current, random);
-              evaluations++;
-              if (FitnessComparer.IsBetter(maximization, moveF, quality)) {
-                steps++;
-                quality = moveF;
-                change = true;
-                links.RemoveBySecond(i);
-                links.SetByFirst(l.Key, i); // otherwise the link won't be removed
-                if (!isFirst) links.SetByFirst(pred, isLast ? pred : next);
-                next = current[i];
-                if (next == i) { isLast = true; }
-                pred = l.Key;
-                isFirst = false;
-                break;
-              } else { // undo
-                current[l.Key] = l.Value;
-                if (k == linksList.Count - 1) {
-                  // all attempts unsuccessful
-                  if (!isFirst) current[pred] = i; // undo - readd i to its group
-                  current[i] = next;
-                }
-              }
-            }
-          }
-
-          if (!isLast) {
-            // try to split group at this point
-            // this is safe even if keepLink was true
-            current[i] = i;
-            var moveF = eval(current, random);
+        var groupItems = new List<int>();
+        for (var i = 0; i < solution.Length; i++) {
+          foreach (var move in MoveGenerator.GenerateForItem(i, groupItems, solution, lleb).ToList()) {
+            move.Apply(solution);
+            var moveF = eval(solution, token);
             evaluations++;
             if (FitnessComparer.IsBetter(maximization, moveF, quality)) {
+              move.ApplyToLLEb(lleb);
               steps++;
               quality = moveF;
               change = true;
-              isLast = true;
-              next = i;
-              links.SetBySecond(i, i);
-              continue;
-            } else current[i] = next; // undo
+              break;
+            } else {
+              move.Undo(solution);
+            }
+            if (token.IsCancellationRequested) break;
           }
-
-          if (isFirst && !isLast) {
-            // try merge with all terminated groups
-            foreach (var l in links.Where(x => x.Key == x.Value && (subspace == null || subspace[x.Key]))) {
-              current[l.Key] = i;
-              var moveF = eval(current, random);
-              evaluations++;
-              if (FitnessComparer.IsBetter(maximization, moveF, quality)) {
-                steps++;
-                quality = moveF;
-                change = true;
-                isFirst = false;
-                pred = l.Key;
-                links.SetByFirst(l.Key, i);
-                break;
-              } else {
-                current[l.Key] = l.Value;
-              }
-            }
-          } else if (!isFirst && !keepLink) {
-            // try to extract current into own group
-            current[pred] = isLast ? pred : next;
-            current[i] = i;
-            var moveF = eval(current, random);
-            evaluations++;
-            if (FitnessComparer.IsBetter(maximization, moveF, quality)) {
-              steps++;
-              links.SetByFirst(pred, current[pred]);
-              quality = moveF;
-              change = true;
-            } else { // undo
-              current[pred] = i;
-              current[i] = next;
-            }
-          }
-          links.RemoveBySecond(i);
-          links.Add(i, current[i]);
+          if (lleb[i] != i)
+            groupItems.Remove(lleb[i]);
+          groupItems.Add(i);
           if (token.IsCancellationRequested) break;
         }
@@ -154,5 +68,5 @@
     }
 
-    public static Tuple<int, int> OptimizeSwapOnly(IRandom random, LinearLinkage solution, ref double quality, bool maximization, Func<LinearLinkage, IRandom, double> eval, CancellationToken token) {
+    public static Tuple<int, int> OptimizeSwap(IRandom random, LinearLinkage solution, ref double quality, bool maximization, Func<LinearLinkage, IRandom, double> eval, CancellationToken token) {
       var evaluations = 0;
       var current = solution;
Index: branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/LinearLinkage/SolutionModel/Univariate/UnbiasedModelTrainer.cs
===================================================================
--- branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/LinearLinkage/SolutionModel/Univariate/UnbiasedModelTrainer.cs	(revision 14551)
+++ branches/MemPRAlgorithm/HeuristicLab.Algorithms.MemPR/3.3/LinearLinkage/SolutionModel/Univariate/UnbiasedModelTrainer.cs	(revision 14552)
@@ -32,5 +32,5 @@
   [StorableClass]
   public class UniasedModelTrainer<TContext> : NamedItem, ISolutionModelTrainer<TContext>
-    where TContext : IPopulationBasedHeuristicAlgorithmContext<SingleObjectiveBasicProblem<LinearLinkageEncoding>, LinearLinkage>, ISolutionModelContext<LinearLinkage> {
+    where TContext : IPopulationBasedHeuristicAlgorithmContext<ISingleObjectiveHeuristicOptimizationProblem, LinearLinkage>, ISolutionModelContext<LinearLinkage> {
     
     [StorableConstructor]
