Index: branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment/3.3/Moves/GQAPNMoveGenerator.cs
===================================================================
--- branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment/3.3/Moves/GQAPNMoveGenerator.cs	(revision 7419)
+++ branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment/3.3/Moves/GQAPNMoveGenerator.cs	(revision 7505)
@@ -30,5 +30,5 @@
 
 namespace HeuristicLab.Problems.GeneralizedQuadraticAssignment {
-  [Item("GQAPNMoveGenerator", "Base class for move operators that generate n-move moves.")]
+  [Item("N-Move Generator", "Base class for move operators that generate N-Move moves.")]
   [StorableClass]
   public abstract class GQAPNMoveGenerator : GQAPMoveGenerator, IGQAPNMoveOperator {
Index: branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment/3.3/Moves/NMove.cs
===================================================================
--- branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment/3.3/Moves/NMove.cs	(revision 7419)
+++ branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment/3.3/Moves/NMove.cs	(revision 7505)
@@ -21,4 +21,5 @@
 
 using System;
+using System.Collections.Generic;
 using HeuristicLab.Common;
 using HeuristicLab.Core;
@@ -27,15 +28,13 @@
 
 namespace HeuristicLab.Problems.GeneralizedQuadraticAssignment {
-  [Item("n-move", "An n-move describes moving n equipments to n locations.")]
+  [Item("N-Move", "An N-Move describes the relocation of n equipments to n different locations.")]
   [StorableClass]
   public class NMove : Item {
     [Storable]
-    public int[] Equipments { get; private set; }
-    [Storable]
-    public int[] Locations { get; private set; }
+    public Dictionary<int, int> NewAssignments { get; private set; }
     [Storable]
     public IntegerVector OriginalVector { get; private set; }
 
-    public int N { get { return Equipments.Length; } }
+    public int N { get { return NewAssignments.Count; } }
 
     [StorableConstructor]
@@ -43,6 +42,5 @@
     protected NMove(NMove original, Cloner cloner)
       : base(original, cloner) {
-      Equipments = (int[])original.Equipments.Clone();
-      Locations = (int[])original.Locations.Clone();
+      NewAssignments = new Dictionary<int, int>(original.NewAssignments);
       if (original.OriginalVector != null)
         OriginalVector = cloner.Clone(original.OriginalVector);
@@ -55,6 +53,7 @@
       if (locations == null) throw new ArgumentNullException("locations", "NMove: Locations must not be null.");
       if (equipments.Length != locations.Length) throw new ArgumentException("NMove: Length of equipments and locations is not identical.");
-      Equipments = equipments;
-      Locations = locations;
+      NewAssignments = new Dictionary<int, int>();
+      for (int i = 0; i < equipments.Length; i++)
+        NewAssignments[equipments[i]] = locations[i];
       OriginalVector = originalVector;
     }
Index: branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment/3.3/Moves/NMoveAbsoluteAttribute.cs
===================================================================
--- branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment/3.3/Moves/NMoveAbsoluteAttribute.cs	(revision 7505)
+++ branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment/3.3/Moves/NMoveAbsoluteAttribute.cs	(revision 7505)
@@ -0,0 +1,53 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 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.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Encodings.IntegerVectorEncoding;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.GeneralizedQuadraticAssignment {
+  [Item("N-Move Absolute TabuAttribute", "Attribute to determine whether a certain move is tabu.")]
+  [StorableClass]
+  public class NMoveAbsoluteTabuAttribute : Item {
+
+    [Storable]
+    public Dictionary<int, int> OldAssignments { get; private set; }
+    [Storable]
+    public double MoveQuality { get; private set; }
+
+    [StorableConstructor]
+    protected NMoveAbsoluteTabuAttribute(bool deserializing) : base(deserializing) { }
+    protected NMoveAbsoluteTabuAttribute(NMoveAbsoluteTabuAttribute original, Cloner cloner) : base(original, cloner) { }
+    public NMoveAbsoluteTabuAttribute(NMove move, IntegerVector assignment, double moveQuality)
+      : base() {
+      OldAssignments = new Dictionary<int, int>();
+      foreach (var kvp in move.NewAssignments)
+        OldAssignments.Add(kvp.Key, assignment[kvp.Key]);
+      MoveQuality = moveQuality;
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new NMoveAbsoluteTabuAttribute(this, cloner);
+    }
+  }
+}
Index: branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment/3.3/Moves/NMoveMaker.cs
===================================================================
--- branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment/3.3/Moves/NMoveMaker.cs	(revision 7419)
+++ branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment/3.3/Moves/NMoveMaker.cs	(revision 7505)
@@ -30,5 +30,5 @@
 
 namespace HeuristicLab.Problems.GeneralizedQuadraticAssignment {
-  [Item("NMoveMaker", "Performs an n-move.")]
+  [Item("N-Move Maker", "Performs an N-Move.")]
   [StorableClass]
   public class NMoveMaker : SingleSuccessorOperator, IAssignmentAwareGQAPOperator, IQualityAwareGQAPOperator, IMoveQualityAwareGQAPOperator, IGQAPNMoveOperator, IMoveMaker {
@@ -97,7 +97,6 @@
 
     public static void Apply(IntegerVector vector, NMove move) {
-      for (int i = 0; i < move.N; i++) {
-        vector[move.Equipments[i]] = move.Locations[i];
-      }
+      foreach (var kvp in move.NewAssignments)
+        vector[kvp.Key] = kvp.Value;
     }
 
Index: branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment/3.3/Moves/NMoveTabuChecker.cs
===================================================================
--- branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment/3.3/Moves/NMoveTabuChecker.cs	(revision 7505)
+++ branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment/3.3/Moves/NMoveTabuChecker.cs	(revision 7505)
@@ -0,0 +1,137 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Encodings.IntegerVectorEncoding;
+using HeuristicLab.Operators;
+using HeuristicLab.Optimization;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.GeneralizedQuadraticAssignment.Moves {
+  [Item("N-Move TabuChecker", "Checks if a certain N-Move is tabu.")]
+  [StorableClass]
+  public class NMoveTabuChecker : SingleSuccessorOperator, ITabuChecker,
+    IAssignmentAwareGQAPOperator, IGQAPNMoveOperator, IMoveQualityAwareGQAPOperator {
+    public override bool CanChangeName {
+      get { return false; }
+    }
+    public ILookupParameter<NMove> MoveParameter {
+      get { return (ILookupParameter<NMove>)Parameters["Move"]; }
+    }
+    public ILookupParameter<IntegerVector> AssignmentParameter {
+      get { return (ILookupParameter<IntegerVector>)Parameters["Assignment"]; }
+    }
+    public ILookupParameter<ItemList<IItem>> TabuListParameter {
+      get { return (ILookupParameter<ItemList<IItem>>)Parameters["TabuList"]; }
+    }
+    public ILookupParameter<BoolValue> MoveTabuParameter {
+      get { return (ILookupParameter<BoolValue>)Parameters["MoveTabu"]; }
+    }
+    public IValueLookupParameter<BoolValue> MaximizationParameter {
+      get { return (IValueLookupParameter<BoolValue>)Parameters["Maximization"]; }
+    }
+    ILookupParameter<BoolValue> IMoveQualityAwareGQAPOperator.MaximizationParameter {
+      get { return MaximizationParameter; }
+    }
+    public ILookupParameter<DoubleValue> MoveQualityParameter {
+      get { return (ILookupParameter<DoubleValue>)Parameters["MoveQuality"]; }
+    }
+    public ILookupParameter<DoubleValue> MoveFlowDistanceQualityParameter {
+      get { return (ILookupParameter<DoubleValue>)Parameters["MoveFlowDistanceQuality"]; }
+    }
+    public ILookupParameter<DoubleValue> MoveInstallationQualityParameter {
+      get { return (ILookupParameter<DoubleValue>)Parameters["MoveInstallationQuality"]; }
+    }
+    public ILookupParameter<DoubleValue> MoveOverbookedCapacityParameter {
+      get { return (ILookupParameter<DoubleValue>)Parameters["MoveOverbookedCapacity"]; }
+    }
+    public IValueParameter<BoolValue> UseAspirationCriterionParameter {
+      get { return (IValueParameter<BoolValue>)Parameters["UseAspirationCriterion"]; }
+    }
+
+    public BoolValue UseAspirationCriterion {
+      get { return UseAspirationCriterionParameter.Value; }
+      set { UseAspirationCriterionParameter.Value = value; }
+    }
+
+    [StorableConstructor]
+    protected NMoveTabuChecker(bool deserializing) : base(deserializing) { }
+    protected NMoveTabuChecker(NMoveTabuChecker original, Cloner cloner) : base(original, cloner) { }
+    public NMoveTabuChecker()
+      : base() {
+      Parameters.Add(new LookupParameter<NMove>("Move", GQAPNMoveGenerator.MoveDescription));
+      Parameters.Add(new LookupParameter<IntegerVector>("Assignment", GQAPSolutionCreator.AssignmentDescription));
+      Parameters.Add(new LookupParameter<ItemList<IItem>>("TabuList", "The tabu list contains previous move attributes."));
+      Parameters.Add(new LookupParameter<BoolValue>("MoveTabu", "Declares if a move is tabu or not."));
+      Parameters.Add(new ValueLookupParameter<BoolValue>("Maximization", "True if the problem is a maximization problem."));
+      Parameters.Add(new LookupParameter<DoubleValue>("MoveQuality", GQAPNMoveEvaluator.MoveQualityDescription));
+      Parameters.Add(new LookupParameter<DoubleValue>("MoveFlowDistanceQuality", GQAPNMoveEvaluator.MoveFlowDistanceQualityDescription));
+      Parameters.Add(new LookupParameter<DoubleValue>("MoveInstallationQuality", GQAPNMoveEvaluator.MoveInstallationQualityDescription));
+      Parameters.Add(new LookupParameter<DoubleValue>("MoveOverbookedCapacity", GQAPNMoveEvaluator.MoveOverbookedCapacityDescription));
+      Parameters.Add(new ValueParameter<BoolValue>("UseAspirationCriterion", "Whether moves can be aspired.", new BoolValue(true)));
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new NMoveTabuChecker(this, cloner);
+    }
+
+    public override IOperation Apply() {
+      ItemList<IItem> tabuList = TabuListParameter.ActualValue;
+      var move = MoveParameter.ActualValue;
+      var assignment = AssignmentParameter.ActualValue;
+      int length = assignment.Length;
+      double moveQuality = MoveQualityParameter.ActualValue.Value;
+      bool maximization = MaximizationParameter.ActualValue.Value;
+      bool useAspiration = UseAspirationCriterion.Value;
+      
+      bool isTabu = EvaluateTabuState(tabuList, move, assignment, moveQuality, maximization, useAspiration);
+
+      MoveTabuParameter.ActualValue = new BoolValue(isTabu);
+      return base.Apply();
+    }
+
+    private bool EvaluateTabuState(ItemList<IItem> tabuList, NMove move, IntegerVector assignment, double moveQuality, bool maximization, bool useAspiration) {
+      bool isTabu = false;
+      foreach (var t in tabuList) {
+        var attribute = (t as NMoveAbsoluteTabuAttribute);
+        if (attribute == null) continue;
+        if (!useAspiration
+          || maximization && moveQuality <= attribute.MoveQuality
+          || !maximization && moveQuality >= attribute.MoveQuality) {
+          isTabu = true;
+          foreach (var kvp in attribute.OldAssignments) {
+            if (move.NewAssignments.ContainsKey(kvp.Key)) {
+              if (move.NewAssignments[kvp.Key] != kvp.Value) {
+                isTabu = false;
+                break;
+              }
+            }
+          }
+        }
+        if (isTabu) break;
+      }
+      return isTabu;
+    }
+  }
+}
Index: branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment/3.3/Moves/NMoveTabuMaker.cs
===================================================================
--- branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment/3.3/Moves/NMoveTabuMaker.cs	(revision 7505)
+++ branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment/3.3/Moves/NMoveTabuMaker.cs	(revision 7505)
@@ -0,0 +1,79 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Encodings.IntegerVectorEncoding;
+using HeuristicLab.Optimization.Operators;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.GeneralizedQuadraticAssignment.Moves {
+  [Item("N-Move TabuMaker", "Declares an N-Move tabu.")]
+  [StorableClass]
+  public class NMoveTabuMaker : TabuMaker, IGQAPNMoveOperator, IAssignmentAwareGQAPOperator,
+    IMoveQualityAwareGQAPOperator {
+
+    public ILookupParameter<IntegerVector> AssignmentParameter {
+      get { return (ILookupParameter<IntegerVector>)Parameters["Assignment"]; }
+    }
+    public ILookupParameter<NMove> MoveParameter {
+      get { return (ILookupParameter<NMove>)Parameters["Move"]; }
+    }
+    ILookupParameter<BoolValue> IMoveQualityAwareGQAPOperator.MaximizationParameter {
+      get { return (ILookupParameter<BoolValue>)MaximizationParameter; }
+    }
+    public ILookupParameter<DoubleValue> MoveFlowDistanceQualityParameter {
+      get { return (ILookupParameter<DoubleValue>)Parameters["MoveFlowDistanceQuality"]; }
+    }
+    public ILookupParameter<DoubleValue> MoveInstallationQualityParameter {
+      get { return (ILookupParameter<DoubleValue>)Parameters["MoveInstallationQuality"]; }
+    }
+    public ILookupParameter<DoubleValue> MoveOverbookedCapacityParameter {
+      get { return (ILookupParameter<DoubleValue>)Parameters["MoveOverbookedCapacity"]; }
+    }
+
+    [StorableConstructor]
+    protected NMoveTabuMaker(bool deserializing) : base(deserializing) { }
+    protected NMoveTabuMaker(NMoveTabuMaker original, Cloner cloner) : base(original, cloner) { }
+    public NMoveTabuMaker()
+      : base() {
+      Parameters.Add(new LookupParameter<IntegerVector>("Assignment", GQAPSolutionCreator.AssignmentDescription));
+      Parameters.Add(new LookupParameter<NMove>("Move", GQAPNMoveGenerator.MoveDescription));
+      Parameters.Add(new LookupParameter<DoubleValue>("MoveFlowDistanceQuality", GQAPNMoveEvaluator.MoveFlowDistanceQualityDescription));
+      Parameters.Add(new LookupParameter<DoubleValue>("MoveInstallationQuality", GQAPNMoveEvaluator.MoveInstallationQualityDescription));
+      Parameters.Add(new LookupParameter<DoubleValue>("MoveOverbookedCapacity", GQAPNMoveEvaluator.MoveOverbookedCapacityDescription));
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new NMoveTabuMaker(this, cloner);
+    }
+
+    protected override IItem GetTabuAttribute(bool maximization, double quality, double moveQuality) {
+      var move = MoveParameter.ActualValue;
+      var assignment = AssignmentParameter.ActualValue;
+      double baseQuality = moveQuality;
+      if (maximization && quality > moveQuality || !maximization && quality < moveQuality) baseQuality = quality; // we make an uphill move, the lower bound is the solution quality
+      return new NMoveAbsoluteTabuAttribute(move, assignment, baseQuality);
+    }
+  }
+}
Index: branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment/3.3/Moves/StochasticNMoveMultiMoveGenerator.cs
===================================================================
--- branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment/3.3/Moves/StochasticNMoveMultiMoveGenerator.cs	(revision 7419)
+++ branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment/3.3/Moves/StochasticNMoveMultiMoveGenerator.cs	(revision 7505)
@@ -30,5 +30,5 @@
 
 namespace HeuristicLab.Problems.GeneralizedQuadraticAssignment {
-  [Item("Stochastic n-move MultiMoveGenerator", "Randomly samples a number of n-moves.")]
+  [Item("Stochastic N-Move MultiMoveGenerator", "Randomly samples a number of N-Moves.")]
   [StorableClass]
   public class StochasticNMoveMultiMoveGenerator : GQAPNMoveGenerator, ICapacitiesAwareGQAPOperator, IStochasticOperator, IMultiMoveGenerator {
Index: branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment/3.3/Moves/StochasticNMoveSingleMoveGenerator.cs
===================================================================
--- branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment/3.3/Moves/StochasticNMoveSingleMoveGenerator.cs	(revision 7419)
+++ branches/GeneralizedQAP/HeuristicLab.Problems.GeneralizedQuadraticAssignment/3.3/Moves/StochasticNMoveSingleMoveGenerator.cs	(revision 7505)
@@ -30,5 +30,5 @@
 
 namespace HeuristicLab.Problems.GeneralizedQuadraticAssignment {
-  [Item("Stochastic n-move SingleMoveGenerator", "Randomly samples a single n-move.")]
+  [Item("Stochastic N-Move SingleMoveGenerator", "Randomly samples a single N-Move.")]
   [StorableClass]
   public class StochasticNMoveSingleMoveGenerator : GQAPNMoveGenerator, ICapacitiesAwareGQAPOperator, IStochasticOperator, ISingleMoveGenerator {
