Index: branches/LinearLinkage/HeuristicLab.Encodings.LinearLinkageEncoding/3.3/Crossovers/LargestGroupFirstCrossover.cs
===================================================================
--- branches/LinearLinkage/HeuristicLab.Encodings.LinearLinkageEncoding/3.3/Crossovers/LargestGroupFirstCrossover.cs	(revision 12285)
+++ 	(revision )
@@ -1,104 +1,0 @@
-﻿#region License Information
-/* HeuristicLab
- * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
- *
- * This file is part of HeuristicLab.
- *
- * HeuristicLab is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * HeuristicLab is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
- */
-#endregion
-
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using HeuristicLab.Common;
-using HeuristicLab.Core;
-using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
-
-namespace HeuristicLab.Encodings.LinearLinkageEncoding {
-  [Item("Largest Group First Crossover", "")]
-  [StorableClass]
-  public sealed class LargestGroupFirstCrossover : LinearLinkageCrossover {
-
-    [StorableConstructor]
-    private LargestGroupFirstCrossover(bool deserializing) : base(deserializing) { }
-    private LargestGroupFirstCrossover(LargestGroupFirstCrossover original, Cloner cloner) : base(original, cloner) { }
-    public LargestGroupFirstCrossover() { }
-
-    public override IDeepCloneable Clone(Cloner cloner) {
-      return new LargestGroupFirstCrossover(this, cloner);
-    }
-
-    public static LinearLinkage Apply(IRandom random, LinearLinkage p1, LinearLinkage p2) {
-      var len = p1.Length;
-      var groups1 = p1.GetGroups().ToList();
-      var groups2 = p2.GetGroups().ToList();
-      var childGroup = new List<HashSet<int>>();
-
-      var total = 0;
-      do {
-        var leastLinks = int.MaxValue;
-        var g1 = -1;
-        var g2 = -1;
-        var comparisons = 0;
-        // find those two groups in both parents that could be merged with least amount of new links
-        // put a bias on bigger groups in parent 1
-        for (var i = 0; i < groups1.Count; i++) {
-          var set1 = new HashSet<int>(groups1[i]);
-          for (var j = 0; j < groups2.Count; j++) {
-            var set2 = new HashSet<int>(groups2[j]);
-            var newLinks = set1.Except(set2).Count() * set2.Except(set1).Count();
-            if (newLinks < leastLinks || newLinks == leastLinks && groups1[i].Count > groups1[g1].Count) {
-              leastLinks = newLinks;
-              g1 = i;
-              g2 = j;
-              comparisons = 1;
-            } else if (newLinks == leastLinks && groups1[i].Count == groups1[g1].Count &&
-                       random.NextDouble() < 1.0 / (++comparisons)) {
-              leastLinks = newLinks;
-              g1 = i;
-              g2 = j;
-            }
-          }
-        }
-        var crossedGroup = new HashSet<int>(groups1[g1].Concat(groups2[g2]));
-        groups1.RemoveAt(g1);
-        groups2.RemoveAt(g2);
-        for (var i = 0; i < groups1.Count; i++) {
-          groups1[i] = groups1[i].Except(crossedGroup).ToList();
-          if (groups1[i].Count != 0) continue;
-          groups1.RemoveAt(i);
-          i--;
-        }
-        for (var i = 0; i < groups2.Count; i++) {
-          groups2[i] = groups2[i].Except(crossedGroup).ToList();
-          if (groups2[i].Count != 0) continue;
-          groups2.RemoveAt(i);
-          i--;
-        }
-        childGroup.Add(crossedGroup);
-        total += crossedGroup.Count;
-      } while (total < len);
-
-      var child = new LinearLinkage(len);
-      child.SetGroups(childGroup);
-      return child;
-    }
-
-    protected override LinearLinkage Cross(IRandom random, ItemArray<LinearLinkage> parents) {
-      if (parents.Length != 2) throw new InvalidOperationException(Name + ": Can only cross exactly two parents.");
-      return Apply(random, parents[0], parents[1]);
-    }
-  }
-}
Index: branches/LinearLinkage/HeuristicLab.Encodings.LinearLinkageEncoding/3.3/Crossovers/MultiLLECrossover.cs
===================================================================
--- branches/LinearLinkage/HeuristicLab.Encodings.LinearLinkageEncoding/3.3/Crossovers/MultiLLECrossover.cs	(revision 12286)
+++ branches/LinearLinkage/HeuristicLab.Encodings.LinearLinkageEncoding/3.3/Crossovers/MultiLLECrossover.cs	(revision 12286)
@@ -0,0 +1,99 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Collections;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Operators;
+using HeuristicLab.Optimization;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.PluginInfrastructure;
+
+namespace HeuristicLab.Encodings.LinearLinkageEncoding {
+  [Item("Multi LLE Crossover", "Randomly selects and applies one of its crossovers every time it is called.")]
+  [StorableClass]
+  public class MultiLinearLinkageCrossover : StochasticMultiBranch<ILinearLinkageCrossover>, ILinearLinkageCrossover, IStochasticOperator {
+    public override bool CanChangeName {
+      get { return false; }
+    }
+    protected override bool CreateChildOperation {
+      get { return true; }
+    }
+
+    public IScopeTreeLookupParameter<LinearLinkage> ParentsParameter {
+      get { return (IScopeTreeLookupParameter<LinearLinkage>)Parameters["Parents"]; }
+    }
+
+    public ILookupParameter<LinearLinkage> ChildParameter {
+      get { return (ILookupParameter<LinearLinkage>)Parameters["Child"]; }
+    }
+
+    [StorableConstructor]
+    protected MultiLinearLinkageCrossover(bool deserializing) : base(deserializing) { }
+    protected MultiLinearLinkageCrossover(MultiLinearLinkageCrossover original, Cloner cloner) : base(original, cloner) { }
+    public MultiLinearLinkageCrossover()
+      : base() {
+      Parameters.Add(new ScopeTreeLookupParameter<LinearLinkage>("Parents", "The parent LLE which should be crossed."));
+      ParentsParameter.ActualName = "LLE";
+      Parameters.Add(new LookupParameter<LinearLinkage>("Child", "The child LLE resulting from the crossover."));
+      ChildParameter.ActualName = "LLE";
+
+      foreach (Type type in ApplicationManager.Manager.GetTypes(typeof(ILinearLinkageCrossover))) {
+        if (!typeof(MultiOperator<ILinearLinkageCrossover>).IsAssignableFrom(type))
+          Operators.Add((ILinearLinkageCrossover)Activator.CreateInstance(type), true);
+      }
+
+      SelectedOperatorParameter.ActualName = "SelectedCrossoverOperator";
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new MultiLinearLinkageCrossover(this, cloner);
+    }
+
+    protected override void Operators_ItemsReplaced(object sender, CollectionItemsChangedEventArgs<IndexedItem<ILinearLinkageCrossover>> e) {
+      base.Operators_ItemsReplaced(sender, e);
+      ParameterizeCrossovers(e.Items);
+    }
+
+    protected override void Operators_ItemsAdded(object sender, CollectionItemsChangedEventArgs<IndexedItem<ILinearLinkageCrossover>> e) {
+      base.Operators_ItemsAdded(sender, e);
+      ParameterizeCrossovers(e.Items);
+    }
+
+    private void ParameterizeCrossovers(IEnumerable<IndexedItem<ILinearLinkageCrossover>> crossovers) {
+      foreach (var c in crossovers.Select(x => x.Value)) {
+        c.ChildParameter.ActualName = ChildParameter.Name;
+        c.ParentsParameter.ActualName = ParentsParameter.Name;
+        var stOp = c as IStochasticOperator;
+        if (stOp != null) stOp.RandomParameter.ActualName = RandomParameter.Name;
+      }
+    }
+
+    public override IOperation InstrumentedApply() {
+      if (Operators.Count == 0) throw new InvalidOperationException(Name + ": Please add at least one LLE crossover to choose from.");
+      return base.InstrumentedApply();
+    }
+  }
+}
Index: branches/LinearLinkage/HeuristicLab.Encodings.LinearLinkageEncoding/3.3/HeuristicLab.Encodings.LinearLinkageEncoding-3.3.csproj
===================================================================
--- branches/LinearLinkage/HeuristicLab.Encodings.LinearLinkageEncoding/3.3/HeuristicLab.Encodings.LinearLinkageEncoding-3.3.csproj	(revision 12285)
+++ branches/LinearLinkage/HeuristicLab.Encodings.LinearLinkageEncoding/3.3/HeuristicLab.Encodings.LinearLinkageEncoding-3.3.csproj	(revision 12286)
@@ -106,4 +106,5 @@
     <Compile Include="Crossovers\GroupCrossover.cs" />
     <Compile Include="Crossovers\LowestIndexMaxCrossover.cs" />
+    <Compile Include="Crossovers\MultiLLECrossover.cs" />
     <Compile Include="Interfaces\ILinearLinkageCreator.cs" />
     <Compile Include="LinearLinkage.cs" />
@@ -112,6 +113,8 @@
     <Compile Include="LinearLinkageManipulator.cs" />
     <Compile Include="LinearLinkageCrossover.cs" />
-    <Compile Include="ShakingOperators\SplitGroupShakingOperator.cs" />
-    <Compile Include="ShakingOperators\SwapNShakingOperator.cs" />
+    <Compile Include="Manipulators\MoveItemManipulator.cs" />
+    <Compile Include="Manipulators\MergeGroupManipulator.cs" />
+    <Compile Include="Manipulators\MultiLLEManipulator.cs" />
+    <Compile Include="ShakingOperators\LLEShakingOperator.cs" />
     <None Include="HeuristicLab.snk" />
     <None Include="Plugin.cs.frame" />
@@ -123,5 +126,5 @@
     <Compile Include="Interfaces\ILinearLinkageShakingOperator.cs" />
     <Compile Include="Manipulators\SplitGroupManipulator.cs" />
-    <Compile Include="Manipulators\SwapNManipulator.cs" />
+    <Compile Include="Manipulators\SwapItemManipulator.cs" />
     <Compile Include="Plugin.cs" />
     <None Include="Properties\AssemblyInfo.cs.frame" />
Index: branches/LinearLinkage/HeuristicLab.Encodings.LinearLinkageEncoding/3.3/Manipulators/MergeGroupManipulator.cs
===================================================================
--- branches/LinearLinkage/HeuristicLab.Encodings.LinearLinkageEncoding/3.3/Manipulators/MergeGroupManipulator.cs	(revision 12286)
+++ branches/LinearLinkage/HeuristicLab.Encodings.LinearLinkageEncoding/3.3/Manipulators/MergeGroupManipulator.cs	(revision 12286)
@@ -0,0 +1,74 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Encodings.LinearLinkageEncoding {
+  [Item("Merge Group Manipulator", "Performs a maximum of N merge operations on the groups. Groups may be merged multiple times.")]
+  [StorableClass]
+  public sealed class MergeGroupManipulator : LinearLinkageManipulator {
+
+    public IValueLookupParameter<IntValue> NParameter {
+      get { return (IValueLookupParameter<IntValue>)Parameters["N"]; }
+    }
+
+    [StorableConstructor]
+    private MergeGroupManipulator(bool deserializing) : base(deserializing) { }
+    private MergeGroupManipulator(MergeGroupManipulator original, Cloner cloner) : base(original, cloner) { }
+    public MergeGroupManipulator() {
+      Parameters.Add(new ValueLookupParameter<IntValue>("N", "The number of groups to merge.", new IntValue(1)));
+    }
+    public MergeGroupManipulator(int n)
+      : this() {
+      NParameter.Value = new IntValue(n);
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new MergeGroupManipulator(this, cloner);
+    }
+
+    public static void Apply(IRandom random, LinearLinkage lle, int n) {
+      var grouping = lle.GetGroups().ToList();
+      if (grouping.Count == 1) return; // nothing to merge
+
+      for (var i = 0; i < n; i++) {
+        var g1 = random.Next(grouping.Count);
+        var g2 = random.Next(grouping.Count);
+        while (g1 == g2) g2 = random.Next(grouping.Count);
+        grouping[g1].AddRange(grouping[g2]);
+        grouping.RemoveAt(g2);
+        if (grouping.Count == 1) break;
+      }
+
+      lle.SetGroups(grouping);
+    }
+
+    protected override void Manipulate(IRandom random, LinearLinkage lle) {
+      var N = NParameter.ActualValue.Value;
+      Apply(random, lle, N);
+    }
+  }
+}
Index: branches/LinearLinkage/HeuristicLab.Encodings.LinearLinkageEncoding/3.3/Manipulators/MoveItemManipulator.cs
===================================================================
--- branches/LinearLinkage/HeuristicLab.Encodings.LinearLinkageEncoding/3.3/Manipulators/MoveItemManipulator.cs	(revision 12286)
+++ branches/LinearLinkage/HeuristicLab.Encodings.LinearLinkageEncoding/3.3/Manipulators/MoveItemManipulator.cs	(revision 12286)
@@ -0,0 +1,82 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Encodings.LinearLinkageEncoding {
+  [Item("Move Item Manipulator", "Performs a maximum of N move operations between groups or to new groups. Items may be moved multiple times.")]
+  [StorableClass]
+  public sealed class MoveItemManipulator : LinearLinkageManipulator {
+
+    public IValueLookupParameter<IntValue> NParameter {
+      get { return (IValueLookupParameter<IntValue>)Parameters["N"]; }
+    }
+
+    [StorableConstructor]
+    private MoveItemManipulator(bool deserializing) : base(deserializing) { }
+    private MoveItemManipulator(MoveItemManipulator original, Cloner cloner) : base(original, cloner) { }
+    public MoveItemManipulator() {
+      Parameters.Add(new ValueLookupParameter<IntValue>("N", "The number of items to move.", new IntValue(1)));
+    }
+    public MoveItemManipulator(int n)
+      : this() {
+      NParameter.Value = new IntValue(n);
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new MoveItemManipulator(this, cloner);
+    }
+
+    public static void Apply(IRandom random, LinearLinkage lle, int n) {
+      var grouping = lle.GetGroups().ToList();
+      grouping.Add(new List<int>()); // add an empty group
+
+      for (var i = 0; i < n; i++) {
+        var src = random.Next(grouping.Count - 1); // only select from non-empty groups
+        var dest = random.Next(grouping.Count);
+        while (src == dest || grouping[src].Count == 1 && dest == grouping.Count - 1) {
+          src = random.Next(grouping.Count - 1);
+          dest = random.Next(grouping.Count);
+        }
+        if (dest == grouping.Count - 1) grouping.Add(new List<int>());
+
+        var e = random.Next(grouping[src].Count);
+        grouping[dest].Add(grouping[src][e]);
+        grouping[src].RemoveAt(e);
+        if (grouping[src].Count == 0)
+          grouping.RemoveAt(src);
+      }
+
+      lle.SetGroups(grouping.Where(x => x.Count > 0));
+    }
+
+    protected override void Manipulate(IRandom random, LinearLinkage lle) {
+      var N = NParameter.ActualValue.Value;
+      Apply(random, lle, N);
+    }
+  }
+}
Index: branches/LinearLinkage/HeuristicLab.Encodings.LinearLinkageEncoding/3.3/Manipulators/MultiLLEManipulator.cs
===================================================================
--- branches/LinearLinkage/HeuristicLab.Encodings.LinearLinkageEncoding/3.3/Manipulators/MultiLLEManipulator.cs	(revision 12286)
+++ branches/LinearLinkage/HeuristicLab.Encodings.LinearLinkageEncoding/3.3/Manipulators/MultiLLEManipulator.cs	(revision 12286)
@@ -0,0 +1,90 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Collections;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Operators;
+using HeuristicLab.Optimization;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.PluginInfrastructure;
+
+namespace HeuristicLab.Encodings.LinearLinkageEncoding {
+  [Item("Multi LLE Manipulator", "Randomly selects and applies one of its manipulators every time it is called.")]
+  [StorableClass]
+  public class MultiLinearLinkageManipulator : StochasticMultiBranch<ILinearLinkageManipulator>, ILinearLinkageManipulator, IStochasticOperator {
+    public override bool CanChangeName {
+      get { return false; }
+    }
+    protected override bool CreateChildOperation {
+      get { return true; }
+    }
+
+    public ILookupParameter<LinearLinkage> LLEParameter {
+      get { return (ILookupParameter<LinearLinkage>)Parameters["LLE"]; }
+    }
+
+    [StorableConstructor]
+    protected MultiLinearLinkageManipulator(bool deserializing) : base(deserializing) { }
+    protected MultiLinearLinkageManipulator(MultiLinearLinkageManipulator original, Cloner cloner) : base(original, cloner) { }
+    public MultiLinearLinkageManipulator()
+      : base() {
+      Parameters.Add(new LookupParameter<LinearLinkage>("LLE", "The encoding vector that is to be manipulated."));
+      foreach (Type type in ApplicationManager.Manager.GetTypes(typeof(ILinearLinkageManipulator))) {
+        if (!typeof(MultiOperator<ILinearLinkageManipulator>).IsAssignableFrom(type))
+          Operators.Add((ILinearLinkageManipulator)Activator.CreateInstance(type), true);
+      }
+      Operators.SetItemCheckedState(Operators.OfType<SwapItemManipulator>().First(), false);
+      SelectedOperatorParameter.ActualName = "SelectedManipulatorOperator";
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new MultiLinearLinkageManipulator(this, cloner);
+    }
+
+    protected override void Operators_ItemsReplaced(object sender, CollectionItemsChangedEventArgs<IndexedItem<ILinearLinkageManipulator>> e) {
+      base.Operators_ItemsReplaced(sender, e);
+      ParameterizeManipulators(e.Items);
+    }
+
+    protected override void Operators_ItemsAdded(object sender, CollectionItemsChangedEventArgs<IndexedItem<ILinearLinkageManipulator>> e) {
+      base.Operators_ItemsAdded(sender, e);
+      ParameterizeManipulators(e.Items);
+    }
+
+    private void ParameterizeManipulators(IEnumerable<IndexedItem<ILinearLinkageManipulator>> manipulators) {
+      foreach (var m in manipulators.Select(x => x.Value)) {
+        m.LLEParameter.ActualName = LLEParameter.Name;
+        var stOp = m as IStochasticOperator;
+        if (stOp != null) stOp.RandomParameter.ActualName = RandomParameter.Name;
+      }
+    }
+
+    public override IOperation InstrumentedApply() {
+      if (Operators.Count == 0) throw new InvalidOperationException(Name + ": Please add at least one LLE manipulator to choose from.");
+      return base.InstrumentedApply();
+    }
+  }
+}
Index: branches/LinearLinkage/HeuristicLab.Encodings.LinearLinkageEncoding/3.3/Manipulators/SplitGroupManipulator.cs
===================================================================
--- branches/LinearLinkage/HeuristicLab.Encodings.LinearLinkageEncoding/3.3/Manipulators/SplitGroupManipulator.cs	(revision 12285)
+++ branches/LinearLinkage/HeuristicLab.Encodings.LinearLinkageEncoding/3.3/Manipulators/SplitGroupManipulator.cs	(revision 12286)
@@ -20,4 +20,5 @@
 #endregion
 
+using System;
 using System.Collections.Generic;
 using System.Linq;
@@ -53,38 +54,41 @@
     }
 
+    public static void Apply(IRandom random, LinearLinkage lle, int n) {
+      var grouping = lle.GetGroups().ToList();
+      var groupsLargerOne = grouping.Select((v, i) => Tuple.Create(i, v))
+                                    .Where(x => x.Item2.Count > 1)
+                                    .ToDictionary(x => x.Item1, x => x.Item2);
+      if (groupsLargerOne.Count == 0) return;
+      var toRemove = new List<int>();
+
+      for (var i = 0; i < n; i++) {
+        var g = groupsLargerOne.Keys.SampleRandom(random);
+        var idx = random.Next(1, groupsLargerOne[g].Count);
+        // shuffle here to avoid a potential bias of grouping smaller and larger numbers together
+        var tmp = groupsLargerOne[g].Shuffle(random);
+        var before = new List<int>();
+        var after = new List<int>();
+        foreach (var t in tmp) {
+          if (idx > 0) before.Add(t);
+          else after.Add(t);
+          idx--;
+        }
+        if (before.Count > 1) groupsLargerOne[grouping.Count] = before;
+        grouping.Add(before);
+        if (after.Count > 1) groupsLargerOne[grouping.Count] = after;
+        grouping.Add(after);
+        toRemove.Add(g);
+        groupsLargerOne.Remove(g);
+        if (groupsLargerOne.Count == 0) break;
+      }
+      foreach (var r in toRemove.OrderByDescending(x => x))
+        grouping.RemoveAt(r);
+
+      lle.SetGroups(grouping);
+    }
+
     protected override void Manipulate(IRandom random, LinearLinkage lle) {
       var N = NParameter.ActualValue.Value;
-
-      // shuffle here to avoid bias due to lowest-index-first encoding
-      var grouping = lle.GetGroups().Select(x => x.ToList()).Shuffle(random).ToList();
-      var groupsLargerOne = grouping.Count(x => x.Count > 1);
-      if (groupsLargerOne == 0) return;
-
-      var i = -1;
-      while (N > 0) {
-        i = (i + 1) % grouping.Count;
-        if (grouping[i].Count <= 1) continue;
-        if (random.NextDouble() < N / (double)groupsLargerOne) {
-          var idx = random.Next(1, grouping[i].Count);
-          // shuffle here to avoid a potential bias of grouping smaller and larger numbers together
-          var tmp = grouping[i].Shuffle(random);
-          var before = new List<int>();
-          var after = new List<int>();
-          foreach (var t in tmp) {
-            if (idx > 0) before.Add(t);
-            else after.Add(t);
-            idx--;
-          }
-          grouping.Add(before);
-          grouping.Add(after);
-          grouping.RemoveAt(i);
-          i--;
-          N--;
-          if (before.Count > 1 && after.Count > 1) groupsLargerOne++;
-          else if (before.Count == 1 && after.Count == 1) groupsLargerOne--;
-        }
-        if (groupsLargerOne == 0) break;
-      }
-      lle.SetGroups(grouping);
+      Apply(random, lle, N);
     }
   }
Index: branches/LinearLinkage/HeuristicLab.Encodings.LinearLinkageEncoding/3.3/Manipulators/SwapItemManipulator.cs
===================================================================
--- branches/LinearLinkage/HeuristicLab.Encodings.LinearLinkageEncoding/3.3/Manipulators/SwapItemManipulator.cs	(revision 12286)
+++ branches/LinearLinkage/HeuristicLab.Encodings.LinearLinkageEncoding/3.3/Manipulators/SwapItemManipulator.cs	(revision 12286)
@@ -0,0 +1,80 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Encodings.LinearLinkageEncoding {
+  [Item("Swap Item Manipulator", "Swaps items between groups. Items may be swapped multiple times.")]
+  [StorableClass]
+  public sealed class SwapItemManipulator : LinearLinkageManipulator {
+
+    public IValueLookupParameter<IntValue> NParameter {
+      get { return (IValueLookupParameter<IntValue>)Parameters["N"]; }
+    }
+
+    [StorableConstructor]
+    private SwapItemManipulator(bool deserializing) : base(deserializing) { }
+    private SwapItemManipulator(SwapItemManipulator original, Cloner cloner) : base(original, cloner) { }
+    public SwapItemManipulator() {
+      Parameters.Add(new ValueLookupParameter<IntValue>("N", "The number of swaps to perform.", new IntValue(1)));
+    }
+    public SwapItemManipulator(int n)
+      : this() {
+      NParameter.Value = new IntValue(n);
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new SwapItemManipulator(this, cloner);
+    }
+
+    public static void Apply(IRandom random, LinearLinkage lle, int n) {
+      var grouping = lle.GetGroups().Select(x => x.ToList()).ToList();
+      if (grouping.Count == 1) return; // nothing can be changed
+
+      var prevGroup = random.Next(grouping.Count);
+      var prevItem = random.Next(grouping[prevGroup].Count);
+      for (var i = 0; i < n; i++) {
+        int nextGroup, nextItem;
+        do {
+          nextGroup = random.Next(grouping.Count);
+          nextItem = random.Next(grouping[nextGroup].Count);
+        } while (nextGroup == prevGroup);
+        var h = grouping[nextGroup][nextItem];
+        grouping[nextGroup][nextItem] = grouping[prevGroup][prevItem];
+        grouping[prevGroup][prevItem] = h;
+        prevGroup = nextGroup;
+        prevItem = nextItem;
+      }
+
+      lle.SetGroups(grouping);
+    }
+
+    protected override void Manipulate(IRandom random, LinearLinkage lle) {
+      var N = NParameter.ActualValue.Value;
+      Apply(random, lle, N);
+    }
+  }
+}
Index: branches/LinearLinkage/HeuristicLab.Encodings.LinearLinkageEncoding/3.3/Manipulators/SwapNManipulator.cs
===================================================================
--- branches/LinearLinkage/HeuristicLab.Encodings.LinearLinkageEncoding/3.3/Manipulators/SwapNManipulator.cs	(revision 12285)
+++ 	(revision )
@@ -1,96 +1,0 @@
-﻿#region License Information
-/* HeuristicLab
- * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
- *
- * This file is part of HeuristicLab.
- *
- * HeuristicLab is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * HeuristicLab is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
- */
-#endregion
-
-using System.Collections.Generic;
-using System.Linq;
-using HeuristicLab.Common;
-using HeuristicLab.Core;
-using HeuristicLab.Data;
-using HeuristicLab.Operators;
-using HeuristicLab.Optimization;
-using HeuristicLab.Parameters;
-using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
-
-namespace HeuristicLab.Encodings.LinearLinkageEncoding {
-  [Item("Swap-n Manipulator", "")]
-  [StorableClass]
-  public sealed class SwapNManipulator : InstrumentedOperator, ILinearLinkageManipulator, IStochasticOperator {
-    public ILookupParameter<IRandom> RandomParameter {
-      get { return (ILookupParameter<IRandom>)Parameters["Random"]; }
-    }
-
-    public ILookupParameter<LinearLinkage> LLEParameter {
-      get { return (ILookupParameter<LinearLinkage>)Parameters["LLE"]; }
-    }
-
-    public IValueLookupParameter<IntValue> NParameter {
-      get { return (IValueLookupParameter<IntValue>)Parameters["N"]; }
-    }
-
-    [StorableConstructor]
-    private SwapNManipulator(bool deserializing) : base(deserializing) { }
-    private SwapNManipulator(SwapNManipulator original, Cloner cloner) : base(original, cloner) { }
-    public SwapNManipulator() {
-      Parameters.Add(new LookupParameter<IRandom>("Random", "The random number generator to use."));
-      Parameters.Add(new LookupParameter<LinearLinkage>("LLE", "The encoding vector that is to be manipulated."));
-      Parameters.Add(new ValueLookupParameter<IntValue>("N", "The number of swaps to perform.", new IntValue(2)));
-    }
-    public SwapNManipulator(int n)
-      : this() {
-      NParameter.Value = new IntValue(n);
-    }
-
-    public override IDeepCloneable Clone(Cloner cloner) {
-      return new SwapNManipulator(this, cloner);
-    }
-
-    public override IOperation InstrumentedApply() {
-      var random = RandomParameter.ActualValue;
-      var vector = LLEParameter.ActualValue;
-      var N = NParameter.ActualValue.Value;
-
-      var grouping = vector.GetGroups().Select(x => x.ToList()).ToList();
-      if (grouping.Count == 1) return base.InstrumentedApply(); // nothing can be changed
-      var touched = new HashSet<int>();
-      var prevGroup = random.Next(grouping.Count);
-      var prevItem = random.Next(grouping[prevGroup].Count);
-      touched.Add(grouping[prevGroup][prevItem]);
-      for (var i = 0; i < N; i++) {
-        int nextGroup = -1, nextItem = -1, tries = 0;
-        do {
-          if (tries >= 100) break;
-          nextGroup = random.Next(grouping.Count);
-          nextItem = random.Next(grouping[nextGroup].Count);
-          tries++;
-        } while (nextGroup == prevGroup || touched.Contains(grouping[nextGroup][nextItem]));
-        if (tries >= 100) break;
-        var h = grouping[nextGroup][nextItem];
-        grouping[nextGroup][nextItem] = grouping[prevGroup][prevItem];
-        grouping[prevGroup][prevItem] = h;
-        touched.Add(h);
-        prevGroup = nextGroup;
-        prevItem = nextItem;
-      }
-      vector.SetGroups(grouping);
-      return base.InstrumentedApply();
-    }
-  }
-}
Index: branches/LinearLinkage/HeuristicLab.Encodings.LinearLinkageEncoding/3.3/ShakingOperators/LLEShakingOperator.cs
===================================================================
--- branches/LinearLinkage/HeuristicLab.Encodings.LinearLinkageEncoding/3.3/ShakingOperators/LLEShakingOperator.cs	(revision 12286)
+++ branches/LinearLinkage/HeuristicLab.Encodings.LinearLinkageEncoding/3.3/ShakingOperators/LLEShakingOperator.cs	(revision 12286)
@@ -0,0 +1,91 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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.Collections;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Optimization;
+using HeuristicLab.Optimization.Operators;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Encodings.LinearLinkageEncoding {
+  /// <summary>
+  /// A shaking operator for VNS.
+  /// </summary>
+  [Item("LLE Shaking Operator", "A shaking operator for VNS which LLE manipulators to perform the shaking.")]
+  [StorableClass]
+  public class LLEShakingOperator : ShakingOperator<ILinearLinkageManipulator>, IStochasticOperator, ILinearLinkageShakingOperator {
+
+    public ILookupParameter<IRandom> RandomParameter {
+      get { return (LookupParameter<IRandom>)Parameters["Random"]; }
+    }
+
+    public ILookupParameter<LinearLinkage> LLEParameter {
+      get { return (ILookupParameter<LinearLinkage>)Parameters["LLE"]; }
+    }
+
+    public ICheckedItemList<ILinearLinkageManipulator> Shakers {
+      get { return Operators; }
+    }
+
+    [StorableConstructor]
+    protected LLEShakingOperator(bool deserializing) : base(deserializing) { }
+    protected LLEShakingOperator(LLEShakingOperator original, Cloner cloner) : base(original, cloner) { }
+    public LLEShakingOperator()
+      : base() {
+      Parameters.Add(new LookupParameter<LinearLinkage>("LLE", "The encoding to shake."));
+      Parameters.Add(new LookupParameter<IRandom>("Random", "The random number generator that will be used for stochastic shaking operators."));
+      for (var i = 1; i < 4; i++) {
+        Operators.Add(new MoveItemManipulator(i * 2));
+        Operators.Add(new SwapItemManipulator(i * 2));
+        Operators.Add(new SplitGroupManipulator(i * 2));
+        Operators.Add(new MergeGroupManipulator(i * 2));
+      }
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new LLEShakingOperator(this, cloner);
+    }
+
+    #region Wiring of some parameters
+    protected override void Operators_ItemsAdded(object sender, CollectionItemsChangedEventArgs<IndexedItem<ILinearLinkageManipulator>> e) {
+      base.Operators_ItemsAdded(sender, e);
+      ParameterizeOperators(e.Items);
+    }
+
+    protected override void Operators_ItemsReplaced(object sender, CollectionItemsChangedEventArgs<IndexedItem<ILinearLinkageManipulator>> e) {
+      base.Operators_ItemsReplaced(sender, e);
+      ParameterizeOperators(e.Items);
+    }
+
+    private void ParameterizeOperators(IEnumerable<IndexedItem<ILinearLinkageManipulator>> items) {
+      if (!items.Any()) return;
+      foreach (var op in items.Select(x => x.Value).OfType<IStochasticOperator>())
+        op.RandomParameter.ActualName = RandomParameter.Name;
+      foreach (var op in items.Select(x => x.Value))
+        op.LLEParameter.ActualName = LLEParameter.Name;
+    }
+    #endregion
+  }
+}
Index: branches/LinearLinkage/HeuristicLab.Encodings.LinearLinkageEncoding/3.3/ShakingOperators/SplitGroupShakingOperator.cs
===================================================================
--- branches/LinearLinkage/HeuristicLab.Encodings.LinearLinkageEncoding/3.3/ShakingOperators/SplitGroupShakingOperator.cs	(revision 12285)
+++ 	(revision )
@@ -1,86 +1,0 @@
-﻿#region License Information
-/* HeuristicLab
- * Copyright (C) 2002-2015 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.Collections;
-using HeuristicLab.Common;
-using HeuristicLab.Core;
-using HeuristicLab.Optimization;
-using HeuristicLab.Optimization.Operators;
-using HeuristicLab.Parameters;
-using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
-
-namespace HeuristicLab.Encodings.LinearLinkageEncoding {
-  /// <summary>
-  /// A shaking operator for VNS.
-  /// </summary>
-  [Item("Split Group Shaking Operator", "A shaking operator for VNS which uses split group manipulators to perform the shaking.")]
-  [StorableClass]
-  public class SplitGroupShakingOperator : ShakingOperator<ILinearLinkageManipulator>, IStochasticOperator, ILinearLinkageShakingOperator {
-
-    public ILookupParameter<IRandom> RandomParameter {
-      get { return (LookupParameter<IRandom>)Parameters["Random"]; }
-    }
-
-    public ILookupParameter<LinearLinkage> LLEParameter {
-      get { return (ILookupParameter<LinearLinkage>)Parameters["LLE"]; }
-    }
-
-    public ICheckedItemList<ILinearLinkageManipulator> Shakers {
-      get { return Operators; }
-    }
-
-    [StorableConstructor]
-    protected SplitGroupShakingOperator(bool deserializing) : base(deserializing) { }
-    protected SplitGroupShakingOperator(SplitGroupShakingOperator original, Cloner cloner) : base(original, cloner) { }
-    public SplitGroupShakingOperator()
-      : base() {
-      Parameters.Add(new LookupParameter<LinearLinkage>("LLE", "The encoding to shake."));
-      Parameters.Add(new LookupParameter<IRandom>("Random", "The random number generator that will be used for stochastic shaking operators."));
-      for (var i = 1; i < 6; i++) Operators.Add(new SplitGroupManipulator(i));
-    }
-
-    public override IDeepCloneable Clone(Cloner cloner) {
-      return new SplitGroupShakingOperator(this, cloner);
-    }
-
-    #region Wiring of some parameters
-    protected override void Operators_ItemsAdded(object sender, CollectionItemsChangedEventArgs<IndexedItem<ILinearLinkageManipulator>> e) {
-      base.Operators_ItemsAdded(sender, e);
-      ParameterizeOperators(e.Items);
-    }
-
-    protected override void Operators_ItemsReplaced(object sender, CollectionItemsChangedEventArgs<IndexedItem<ILinearLinkageManipulator>> e) {
-      base.Operators_ItemsReplaced(sender, e);
-      ParameterizeOperators(e.Items);
-    }
-
-    private void ParameterizeOperators(IEnumerable<IndexedItem<ILinearLinkageManipulator>> items) {
-      if (!items.Any()) return;
-      foreach (var op in items.Select(x => x.Value).OfType<IStochasticOperator>())
-        op.RandomParameter.ActualName = RandomParameter.Name;
-      foreach (var op in items.Select(x => x.Value))
-        op.LLEParameter.ActualName = LLEParameter.Name;
-    }
-    #endregion
-  }
-}
Index: branches/LinearLinkage/HeuristicLab.Encodings.LinearLinkageEncoding/3.3/ShakingOperators/SwapNShakingOperator.cs
===================================================================
--- branches/LinearLinkage/HeuristicLab.Encodings.LinearLinkageEncoding/3.3/ShakingOperators/SwapNShakingOperator.cs	(revision 12285)
+++ 	(revision )
@@ -1,86 +1,0 @@
-﻿#region License Information
-/* HeuristicLab
- * Copyright (C) 2002-2015 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.Collections;
-using HeuristicLab.Common;
-using HeuristicLab.Core;
-using HeuristicLab.Optimization;
-using HeuristicLab.Optimization.Operators;
-using HeuristicLab.Parameters;
-using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
-
-namespace HeuristicLab.Encodings.LinearLinkageEncoding {
-  /// <summary>
-  /// A shaking operator for VNS.
-  /// </summary>
-  [Item("SwapNShakingOperator", "A shaking operator for VNS which uses swap-n operators to perform the shaking.")]
-  [StorableClass]
-  public class SwapNShakingOperator : ShakingOperator<ILinearLinkageManipulator>, IStochasticOperator, ILinearLinkageShakingOperator {
-
-    public ILookupParameter<IRandom> RandomParameter {
-      get { return (LookupParameter<IRandom>)Parameters["Random"]; }
-    }
-
-    public ILookupParameter<LinearLinkage> LLEParameter {
-      get { return (ILookupParameter<LinearLinkage>)Parameters["LLE"]; }
-    }
-
-    public ICheckedItemList<ILinearLinkageManipulator> Shakers {
-      get { return Operators; }
-    }
-
-    [StorableConstructor]
-    protected SwapNShakingOperator(bool deserializing) : base(deserializing) { }
-    protected SwapNShakingOperator(SwapNShakingOperator original, Cloner cloner) : base(original, cloner) { }
-    public SwapNShakingOperator()
-      : base() {
-      Parameters.Add(new LookupParameter<LinearLinkage>("LLE", "The encoding to shake."));
-      Parameters.Add(new LookupParameter<IRandom>("Random", "The random number generator that will be used for stochastic shaking operators."));
-      for (var i = 2; i < 5; i++) Operators.Add(new SwapNManipulator(i));
-    }
-
-    public override IDeepCloneable Clone(Cloner cloner) {
-      return new SwapNShakingOperator(this, cloner);
-    }
-
-    #region Wiring of some parameters
-    protected override void Operators_ItemsAdded(object sender, CollectionItemsChangedEventArgs<IndexedItem<ILinearLinkageManipulator>> e) {
-      base.Operators_ItemsAdded(sender, e);
-      ParameterizeOperators(e.Items);
-    }
-
-    protected override void Operators_ItemsReplaced(object sender, CollectionItemsChangedEventArgs<IndexedItem<ILinearLinkageManipulator>> e) {
-      base.Operators_ItemsReplaced(sender, e);
-      ParameterizeOperators(e.Items);
-    }
-
-    private void ParameterizeOperators(IEnumerable<IndexedItem<ILinearLinkageManipulator>> items) {
-      if (!items.Any()) return;
-      foreach (var op in items.Select(x => x.Value).OfType<IStochasticOperator>())
-        op.RandomParameter.ActualName = RandomParameter.Name;
-      foreach (var op in items.Select(x => x.Value))
-        op.LLEParameter.ActualName = LLEParameter.Name;
-    }
-    #endregion
-  }
-}
