Index: /branches/GeneralizedQAP/HeuristicLab.Problems.QuadraticAssignment.Algorithms/3.3/Plugin.cs.frame
===================================================================
--- /branches/GeneralizedQAP/HeuristicLab.Problems.QuadraticAssignment.Algorithms/3.3/Plugin.cs.frame	(revision 6800)
+++ /branches/GeneralizedQAP/HeuristicLab.Problems.QuadraticAssignment.Algorithms/3.3/Plugin.cs.frame	(revision 6801)
@@ -28,5 +28,4 @@
   [PluginDependency("HeuristicLab.Collections", "3.3")]
   [PluginDependency("HeuristicLab.Common", "3.3")]
-  [PluginDependency("HeuristicLab.Common.Resources", "3.3")]
   [PluginDependency("HeuristicLab.Core", "3.3")]
   [PluginDependency("HeuristicLab.Data", "3.3")]
Index: /branches/GeneralizedQAP/HeuristicLab.Problems.QuadraticAssignment.Views/3.3/Plugin.cs.frame
===================================================================
--- /branches/GeneralizedQAP/HeuristicLab.Problems.QuadraticAssignment.Views/3.3/Plugin.cs.frame	(revision 6800)
+++ /branches/GeneralizedQAP/HeuristicLab.Problems.QuadraticAssignment.Views/3.3/Plugin.cs.frame	(revision 6801)
@@ -26,4 +26,5 @@
   [PluginFile("HeuristicLab.Problems.QuadraticAssignment.Views-3.3.dll", PluginFileType.Assembly)]
   [PluginDependency("HeuristicLab.Analysis", "3.3")]
+  [PluginDependency("HeuristicLab.Collections", "3.3")]
   [PluginDependency("HeuristicLab.Common", "3.3")]
   [PluginDependency("HeuristicLab.Common.Resources", "3.3")]
@@ -34,4 +35,5 @@
   [PluginDependency("HeuristicLab.MainForm", "3.3")]
   [PluginDependency("HeuristicLab.MainForm.WindowsForms", "3.3")]
+  [PluginDependency("HeuristicLab.Optimization", "3.3")]
   [PluginDependency("HeuristicLab.Problems.QuadraticAssignment", "3.3")]
   public class HeuristicLabProblemsQuadraticAssignmentViewsPlugin : PluginBase {
Index: /branches/GeneralizedQAP/HeuristicLab.Problems.QuadraticAssignment/3.3/Evaluators/AffinitySwapMoveEvaluator.cs
===================================================================
--- /branches/GeneralizedQAP/HeuristicLab.Problems.QuadraticAssignment/3.3/Evaluators/AffinitySwapMoveEvaluator.cs	(revision 6801)
+++ /branches/GeneralizedQAP/HeuristicLab.Problems.QuadraticAssignment/3.3/Evaluators/AffinitySwapMoveEvaluator.cs	(revision 6801)
@@ -0,0 +1,110 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2011 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.Data;
+using HeuristicLab.Encodings.PermutationEncoding;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.QuadraticAssignment {
+  [Item("AffinitySwapMoveEvaluator", "Evaluated an affinity-based swap move on a QAP solution.")]
+  [StorableClass]
+  public class AffinitySwapMoveEvaluator : QAPMoveEvaluator, IAffinitySwapMoveOperator {
+    public ILookupParameter<AffinitySwapMove> AffinitySwapMoveParameter {
+      get { return (ILookupParameter<AffinitySwapMove>)Parameters["AffinitySwapMove"]; }
+    }
+
+    [StorableConstructor]
+    protected AffinitySwapMoveEvaluator(bool deserializing) : base(deserializing) { }
+    protected AffinitySwapMoveEvaluator(AffinitySwapMoveEvaluator original, Cloner cloner)
+      : base(original, cloner) {
+    }
+    public AffinitySwapMoveEvaluator() {
+      Parameters.Add(new LookupParameter<AffinitySwapMove>("AffinitySwapMove", "The move to evaluate."));
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new AffinitySwapMoveEvaluator(this, cloner);
+    }
+
+    /// <summary>
+    /// Calculates the quality of the move <paramref name="move"/> by evaluating the changes.
+    /// The runtime complexity of this method is O(M*N) with N being the size of the permutation and M the number of swaps
+    /// </summary>
+    /// <param name="assignment">The current permutation.</param>
+    /// <param name="move">The move that is to be evaluated if it was applied to the current permutation.</param>
+    /// <param name="weights">The weights matrix.</param>
+    /// <param name="distances">The distances matrix.</param>
+    /// <returns>The relative change in quality if <paramref name="move"/> was applied to <paramref name="assignment"/>.</returns>
+    public static double Apply(Permutation assignment, AffinitySwapMove move, DoubleMatrix weights, DoubleMatrix distances) {
+      if (!move.Swaps.Any()) return 0;
+      double moveQuality = 0;
+
+      foreach (KeyValuePair<int, int> swap in move.Swaps) {
+        int fac1 = swap.Key, fac2 = swap.Value;
+        int loc1 = assignment[fac1], loc2 = assignment[fac2];
+        for (int j = 0; j < assignment.Length; j++) {
+          if (j == fac1) {
+            moveQuality += weights[fac1, fac1] * (distances[loc2, loc2] - distances[loc1, loc1]);
+            moveQuality += weights[fac1, fac2] * (distances[loc2, loc1] - distances[loc1, loc2]);
+          } else if (j == fac2) {
+            moveQuality += weights[fac2, fac2] * (distances[loc1, loc1] - distances[loc2, loc2]);
+            moveQuality += weights[fac2, fac1] * (distances[loc1, loc2] - distances[loc2, loc1]);
+          } else {
+            int locJ = assignment[j];
+            bool isMoved = move.Contains(j);
+            if (isMoved) {
+              moveQuality -= weights[fac1, j] * distances[loc1, locJ];
+              moveQuality -= weights[fac2, j] * distances[loc2, locJ];
+              locJ = assignment[move.GetSwapLocation(j)];
+              moveQuality += weights[fac1, j] * distances[loc2, locJ];
+              moveQuality += weights[fac2, j] * distances[loc1, locJ];
+            } else {
+              moveQuality += weights[fac1, j] * (distances[loc2, locJ] - distances[loc1, locJ]);
+              moveQuality += weights[fac2, j] * (distances[loc1, locJ] - distances[loc2, locJ]);
+              moveQuality += weights[j, fac1] * (distances[locJ, loc2] - distances[locJ, loc1]);
+              moveQuality += weights[j, fac2] * (distances[locJ, loc1] - distances[locJ, loc2]);
+            }
+          }
+        }
+      }
+      return moveQuality;
+    }
+
+    public override IOperation Apply() {
+      AffinitySwapMove move = AffinitySwapMoveParameter.ActualValue;
+      if (move == null) throw new InvalidOperationException("Swap move is not found.");
+      Permutation assignment = PermutationParameter.ActualValue;
+      DoubleMatrix distances = DistancesParameter.ActualValue;
+      DoubleMatrix weights = WeightsParameter.ActualValue;
+
+      double moveQuality = QualityParameter.ActualValue.Value;
+      moveQuality += Apply(assignment, move, weights, distances);
+      MoveQualityParameter.ActualValue = new DoubleValue(moveQuality);
+      return base.Apply();
+    }
+  }
+}
Index: /branches/GeneralizedQAP/HeuristicLab.Problems.QuadraticAssignment/3.3/HeuristicLab.Problems.QuadraticAssignment-3.3.csproj
===================================================================
--- /branches/GeneralizedQAP/HeuristicLab.Problems.QuadraticAssignment/3.3/HeuristicLab.Problems.QuadraticAssignment-3.3.csproj	(revision 6800)
+++ /branches/GeneralizedQAP/HeuristicLab.Problems.QuadraticAssignment/3.3/HeuristicLab.Problems.QuadraticAssignment-3.3.csproj	(revision 6801)
@@ -111,4 +111,5 @@
     <Compile Include="Analyzers\QAPAlleleFrequencyAnalyzer.cs" />
     <Compile Include="Analyzers\QAPPopulationDiversityAnalyzer.cs" />
+    <Compile Include="Evaluators\AffinitySwapMoveEvaluator.cs" />
     <Compile Include="Evaluators\QAPScrambleMoveEvaluator.cs" />
     <Compile Include="Evaluators\QAPSwap2MoveEvaluator.cs" />
@@ -119,7 +120,11 @@
       <SubType>Code</SubType>
     </Compile>
+    <Compile Include="Interfaces\IAffinitySwapMoveOperator.cs" />
     <Compile Include="Interfaces\IQAPEvaluator.cs" />
     <Compile Include="Interfaces\IQAPMoveEvaluator.cs" />
     <Compile Include="LocalImprovement\QAPExhaustiveSwap2LocalImprovement.cs" />
+    <Compile Include="Moves\AffinitySwapMove.cs" />
+    <Compile Include="Moves\StochasticAffinitySwapMoveGenerator.cs" />
+    <Compile Include="Moves\AffinitySwapMoveMaker.cs" />
     <Compile Include="Parsers\QAPLIBSolutionParser.cs" />
     <Compile Include="Parsers\QAPLIBParser.cs" />
@@ -449,4 +454,5 @@
     <EmbeddedResource Include="Data\sko49.sln" />
   </ItemGroup>
+  <ItemGroup />
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
   <PropertyGroup>
Index: /branches/GeneralizedQAP/HeuristicLab.Problems.QuadraticAssignment/3.3/Interfaces/IAffinitySwapMoveOperator.cs
===================================================================
--- /branches/GeneralizedQAP/HeuristicLab.Problems.QuadraticAssignment/3.3/Interfaces/IAffinitySwapMoveOperator.cs	(revision 6801)
+++ /branches/GeneralizedQAP/HeuristicLab.Problems.QuadraticAssignment/3.3/Interfaces/IAffinitySwapMoveOperator.cs	(revision 6801)
@@ -0,0 +1,34 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2011 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.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Encodings.PermutationEncoding;
+using HeuristicLab.Optimization;
+
+namespace HeuristicLab.Problems.QuadraticAssignment {
+  public interface IAffinitySwapMoveOperator : IMoveOperator {
+    ILookupParameter<DoubleMatrix> WeightsParameter { get; }
+    ILookupParameter<DoubleMatrix> DistancesParameter { get; }
+    ILookupParameter<Permutation> PermutationParameter { get; }
+    ILookupParameter<AffinitySwapMove> AffinitySwapMoveParameter { get; }
+  }
+}
Index: /branches/GeneralizedQAP/HeuristicLab.Problems.QuadraticAssignment/3.3/Moves/AffinitySwapMove.cs
===================================================================
--- /branches/GeneralizedQAP/HeuristicLab.Problems.QuadraticAssignment/3.3/Moves/AffinitySwapMove.cs	(revision 6801)
+++ /branches/GeneralizedQAP/HeuristicLab.Problems.QuadraticAssignment/3.3/Moves/AffinitySwapMove.cs	(revision 6801)
@@ -0,0 +1,84 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2011 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.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.QuadraticAssignment {
+  [Item("AffinitySwapMove", "An affinity swap move may move affine facilities together with another item.")]
+  [StorableClass]
+  public class AffinitySwapMove : Item {
+
+    [Storable]
+    private Dictionary<int, int> reverseSwaps;
+    [Storable]
+    private Dictionary<int, int> swaps;
+    public IEnumerable<KeyValuePair<int, int>> Swaps {
+      get { return swaps.AsEnumerable(); }
+    }
+
+    [StorableConstructor]
+    protected AffinitySwapMove(bool deserializing) : base(deserializing) { }
+    protected AffinitySwapMove(AffinitySwapMove original, Cloner cloner)
+      : base(original, cloner) {
+      swaps = new Dictionary<int, int>(original.swaps);
+      reverseSwaps = new Dictionary<int, int>(original.reverseSwaps);
+    }
+    public AffinitySwapMove()
+      : base() {
+      swaps = new Dictionary<int, int>();
+      reverseSwaps = new Dictionary<int, int>();
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new AffinitySwapMove(this, cloner);
+    }
+
+    public bool AddSwap(int index1, int index2) {
+      if (Contains(index1) || Contains(index2)) return false;
+      swaps.Add(index1, index2);
+      reverseSwaps.Add(index2, index1);
+      return true;
+    }
+
+    public bool Contains(int index) {
+      return swaps.ContainsKey(index) || reverseSwaps.ContainsKey(index);
+    }
+
+    /// <summary>
+    /// Returns the swap partner for the given index.
+    /// </summary>
+    /// <remarks>
+    /// Throws a KeyNotFoundException when the <paramref name="index"/> is not part of the swap.
+    /// Check with <see cref="Contains"/> to see if it is included first.
+    /// </remarks>
+    /// <param name="index">The index for which to find the swap partner.</param>
+    /// <returns>The swap partner of the index.</returns>
+    public int GetSwapLocation(int index) {
+      if (swaps.ContainsKey(index)) return swaps[index];
+      else if (reverseSwaps.ContainsKey(index)) return reverseSwaps[index];
+      else throw new KeyNotFoundException(ItemName + ": The given index is not part of the affinity-based swap move.");
+    }
+  }
+}
Index: /branches/GeneralizedQAP/HeuristicLab.Problems.QuadraticAssignment/3.3/Moves/AffinitySwapMoveMaker.cs
===================================================================
--- /branches/GeneralizedQAP/HeuristicLab.Problems.QuadraticAssignment/3.3/Moves/AffinitySwapMoveMaker.cs	(revision 6801)
+++ /branches/GeneralizedQAP/HeuristicLab.Problems.QuadraticAssignment/3.3/Moves/AffinitySwapMoveMaker.cs	(revision 6801)
@@ -0,0 +1,89 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2011 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.Data;
+using HeuristicLab.Encodings.PermutationEncoding;
+using HeuristicLab.Operators;
+using HeuristicLab.Optimization;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.QuadraticAssignment {
+  [Item("AffinitySwapMoveMaker", "Peforms an affinity-based swap move on a given permutation and updates the quality.")]
+  [StorableClass]
+  public class AffinitySwapMoveMaker : SingleSuccessorOperator, IAffinitySwapMoveOperator, IMoveMaker {
+    public override bool CanChangeName {
+      get { return false; }
+    }
+    public ILookupParameter<DoubleMatrix> WeightsParameter {
+      get { return (ILookupParameter<DoubleMatrix>)Parameters["Weights"]; }
+    }
+    public ILookupParameter<DoubleMatrix> DistancesParameter {
+      get { return (ILookupParameter<DoubleMatrix>)Parameters["Distances"]; }
+    }
+    public ILookupParameter<DoubleValue> QualityParameter {
+      get { return (ILookupParameter<DoubleValue>)Parameters["Quality"]; }
+    }
+    public ILookupParameter<DoubleValue> MoveQualityParameter {
+      get { return (ILookupParameter<DoubleValue>)Parameters["MoveQuality"]; }
+    }
+    public ILookupParameter<AffinitySwapMove> AffinitySwapMoveParameter {
+      get { return (ILookupParameter<AffinitySwapMove>)Parameters["AffinitySwapMove"]; }
+    }
+    public ILookupParameter<Permutation> PermutationParameter {
+      get { return (ILookupParameter<Permutation>)Parameters["Permutation"]; }
+    }
+
+    [StorableConstructor]
+    protected AffinitySwapMoveMaker(bool deserializing) : base(deserializing) { }
+    protected AffinitySwapMoveMaker(AffinitySwapMoveMaker original, Cloner cloner) : base(original, cloner) { }
+    public AffinitySwapMoveMaker()
+      : base() {
+      Parameters.Add(new LookupParameter<DoubleMatrix>("Weights", "The weights matrix."));
+      Parameters.Add(new LookupParameter<DoubleMatrix>("Distances", "The distances matrix."));
+      Parameters.Add(new LookupParameter<DoubleValue>("Quality", "The quality of the solution."));
+      Parameters.Add(new LookupParameter<AffinitySwapMove>("AffinitySwapMove", "The move to make."));
+      Parameters.Add(new LookupParameter<DoubleValue>("MoveQuality", "The relative quality of the move."));
+      Parameters.Add(new LookupParameter<Permutation>("Permutation", "The solution as permutation."));
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new AffinitySwapMoveMaker(this, cloner);
+    }
+
+    public override IOperation Apply() {
+      AffinitySwapMove move = AffinitySwapMoveParameter.ActualValue;
+      Permutation permutation = PermutationParameter.ActualValue;
+      DoubleValue moveQuality = MoveQualityParameter.ActualValue;
+      DoubleValue quality = QualityParameter.ActualValue;
+
+      foreach (KeyValuePair<int, int> swap in move.Swaps)
+        Swap2Manipulator.Apply(permutation, swap.Key, swap.Value);
+
+      quality.Value = moveQuality.Value;
+
+      return base.Apply();
+    }
+  }
+}
Index: /branches/GeneralizedQAP/HeuristicLab.Problems.QuadraticAssignment/3.3/Moves/StochasticAffinitySwapMoveGenerator.cs
===================================================================
--- /branches/GeneralizedQAP/HeuristicLab.Problems.QuadraticAssignment/3.3/Moves/StochasticAffinitySwapMoveGenerator.cs	(revision 6801)
+++ /branches/GeneralizedQAP/HeuristicLab.Problems.QuadraticAssignment/3.3/Moves/StochasticAffinitySwapMoveGenerator.cs	(revision 6801)
@@ -0,0 +1,149 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2011 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.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Encodings.PermutationEncoding;
+using HeuristicLab.Operators;
+using HeuristicLab.Optimization;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.QuadraticAssignment {
+  [Item("StochasticAffinitySwapMoveGenerator", "This generator creates moves that also affect affine facilities.")]
+  [StorableClass]
+  public class StochasticAffinitySwapMoveGenerator : SingleSuccessorOperator, IMoveGenerator, IStochasticOperator, IAffinitySwapMoveOperator {
+    public override bool CanChangeName {
+      get { return false; }
+    }
+    public ILookupParameter<IRandom> RandomParameter {
+      get { return (ILookupParameter<IRandom>)Parameters["Random"]; }
+    }
+    public ILookupParameter<DoubleMatrix> WeightsParameter {
+      get { return (ILookupParameter<DoubleMatrix>)Parameters["Weights"]; }
+    }
+    public ILookupParameter<DoubleMatrix> DistancesParameter {
+      get { return (ILookupParameter<DoubleMatrix>)Parameters["Distances"]; }
+    }
+    public ILookupParameter<Permutation> PermutationParameter {
+      get { return (ILookupParameter<Permutation>)Parameters["Permutation"]; }
+    }
+    public ILookupParameter<AffinitySwapMove> AffinitySwapMoveParameter {
+      get { return (ILookupParameter<AffinitySwapMove>)Parameters["AffinitySwapMove"]; }
+    }
+    public ILookupParameter<DoubleArray> WeightsRowSumParameter {
+      get { return (ILookupParameter<DoubleArray>)Parameters["WeightsRowSum"]; }
+    }
+    public ILookupParameter<DoubleArray> DistancesRowSumParameter {
+      get { return (ILookupParameter<DoubleArray>)Parameters["DistancesRowSum"]; }
+    }
+
+    [StorableConstructor]
+    protected StochasticAffinitySwapMoveGenerator(bool deserializing) : base(deserializing) { }
+    protected StochasticAffinitySwapMoveGenerator(StochasticAffinitySwapMoveGenerator original, Cloner cloner) : base(original, cloner) { }
+    public StochasticAffinitySwapMoveGenerator() {
+      Parameters.Add(new LookupParameter<IRandom>("Random", "The random number generator to use."));
+      Parameters.Add(new LookupParameter<DoubleMatrix>("Weights", "The weights matrix."));
+      Parameters.Add(new LookupParameter<DoubleMatrix>("Distances", "The distances matrix."));
+      Parameters.Add(new LookupParameter<Permutation>("Permutation", "The current assignment."));
+      Parameters.Add(new LookupParameter<AffinitySwapMove>("AffinitySwapMove", "The affinity swap moves that are created."));
+      Parameters.Add(new LookupParameter<DoubleArray>("WeightsRowSum", "The row sum for each facility denoting the total weight to other facilities."));
+      Parameters.Add(new LookupParameter<DoubleArray>("DistancesRowSum", "The row sum for each location denoting the total distance to other locations."));
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new StochasticAffinitySwapMoveGenerator(this, cloner);
+    }
+
+    public override IOperation Apply() {
+      IRandom random = RandomParameter.ActualValue;
+      DoubleMatrix weights = WeightsParameter.ActualValue;
+      DoubleMatrix distances = DistancesParameter.ActualValue;
+      DoubleArray weightsRowSum = WeightsRowSumParameter.ActualValue;
+      if (weightsRowSum == null) {
+        weightsRowSum = GenerateRowSum(weights);
+        WeightsRowSumParameter.ActualValue = weightsRowSum;
+      }
+      DoubleArray distancesRowSum = DistancesRowSumParameter.ActualValue;
+      if (distancesRowSum == null) {
+        distancesRowSum = GenerateRowSum(distances);
+        DistancesRowSumParameter.ActualValue = distancesRowSum;
+      }
+      Permutation p = PermutationParameter.ActualValue;
+      var moves = Generate(random, p, weights, weightsRowSum, distances, distancesRowSum);
+      List<Scope> moveScopes = new List<Scope>();
+      int i = 1;
+      foreach (var move in moves) {
+        Scope scope = new Scope(i.ToString());
+        scope.Variables.Add(new Variable(AffinitySwapMoveParameter.ActualName, move));
+        moveScopes.Add(scope);
+      }
+      ExecutionContext.Scope.SubScopes.AddRange(moveScopes);
+      return base.Apply();
+    }
+
+    public static DoubleArray GenerateRowSum(DoubleMatrix matrix) {
+      DoubleArray result = new DoubleArray(matrix.Rows);
+      for (int i = 0; i < matrix.Rows; i++)
+        for (int j = 0; j < matrix.Columns; j++)
+          result[i] += matrix[i, j];
+      return result;
+    }
+
+    public static IEnumerable<AffinitySwapMove> Generate(IRandom random, Permutation permutation, DoubleMatrix weights, DoubleArray weightsRowSum, DoubleMatrix distances, DoubleArray distancesRowSum) {
+      int length = permutation.Length;
+      if (length == 1) throw new ArgumentException("ExhaustiveSwap2MoveGenerator: There cannot be a swap move given a permutation of length 1.", "permutation");
+
+      //int[] affineFacilities = new int[permutation.Length];
+      double totalSum = 0;
+      for (int i = 0; i < length; i++) {
+        //affineFacilities[i] = ProportionalSelect(random, weightsRowSum, weights, i);
+        totalSum += weightsRowSum[i];
+      }
+
+      for (int i = 0; i < length - 1; i++)
+        for (int j = i + 1; j < length; j++) {
+          AffinitySwapMove move = new AffinitySwapMove();
+          move.AddSwap(i, j);
+          if (weightsRowSum[i] / totalSum >= random.NextDouble()
+            || weightsRowSum[j] / totalSum >= random.NextDouble()) {
+            int sI = ProportionalSelect(random, weightsRowSum, weights, i), sJ = ProportionalSelect(random, weightsRowSum, weights, j);
+            if (!(sI == sJ || sJ == i || sJ == j || sI == i || sI == j))
+              move.AddSwap(sI, sJ);
+          }
+          yield return move;
+        }
+    }
+
+    protected static int ProportionalSelect(IRandom random, DoubleArray sums, DoubleMatrix matrix, int row) {
+      double total = sums[row];
+      double rand = random.NextDouble() * total;
+      for (int i = 0; i < matrix.Columns; i++) {
+        total -= matrix[row, i];
+        if (total <= rand) return i;
+      }
+      throw new InvalidOperationException("StochasticAffinitySwapMoveGenerator: Could not generate moves for any affine item.");
+    }
+  }
+}
Index: /branches/GeneralizedQAP/HeuristicLab.Problems.QuadraticAssignment/3.3/QuadraticAssignmentProblem.cs
===================================================================
--- /branches/GeneralizedQAP/HeuristicLab.Problems.QuadraticAssignment/3.3/QuadraticAssignmentProblem.cs	(revision 6800)
+++ /branches/GeneralizedQAP/HeuristicLab.Problems.QuadraticAssignment/3.3/QuadraticAssignmentProblem.cs	(revision 6801)
@@ -268,4 +268,5 @@
       Operators.RemoveAll(x => x is ISingleObjectiveMoveEvaluator);
       Operators.AddRange(ApplicationManager.Manager.GetInstances<IQAPMoveEvaluator>());
+      Operators.AddRange(ApplicationManager.Manager.GetInstances<IAffinitySwapMoveOperator>().Where(x => !(x is IQAPMoveEvaluator)));
       Operators.Add(new BestQAPSolutionAnalyzer());
       Operators.Add(new QAPAlleleFrequencyAnalyzer());
@@ -326,4 +327,9 @@
         op.PermutationParameter.ActualName = SolutionCreator.PermutationParameter.ActualName;
       }
+      foreach (IAffinitySwapMoveOperator op in Operators.OfType<IAffinitySwapMoveOperator>()) {
+        op.PermutationParameter.ActualName = SolutionCreator.PermutationParameter.ActualName;
+        op.WeightsParameter.ActualName = WeightsParameter.Name;
+        op.DistancesParameter.ActualName = DistancesParameter.Name;
+      }
       if (Operators.OfType<IMoveGenerator>().Any()) {
         string inversionMove = Operators.OfType<IMoveGenerator>().OfType<IPermutationInversionMoveOperator>().First().InversionMoveParameter.ActualName;
@@ -336,4 +342,8 @@
         foreach (IPermutationSwap2MoveOperator op in Operators.OfType<IPermutationSwap2MoveOperator>()) {
           op.Swap2MoveParameter.ActualName = swapMove;
+        }
+        string affinitySwapMove = Operators.OfType<IMoveGenerator>().OfType<IAffinitySwapMoveOperator>().First().AffinitySwapMoveParameter.ActualName;
+        foreach (IAffinitySwapMoveOperator op in Operators.OfType<IAffinitySwapMoveOperator>()) {
+          op.AffinitySwapMoveParameter.ActualName = affinitySwapMove;
         }
       }
Index: /branches/GeneralizedQAP/HeuristicLab.Problems.QuadraticAssignment/3.3/Tests/QAPMoveEvaluatorTest.cs
===================================================================
--- /branches/GeneralizedQAP/HeuristicLab.Problems.QuadraticAssignment/3.3/Tests/QAPMoveEvaluatorTest.cs	(revision 6800)
+++ /branches/GeneralizedQAP/HeuristicLab.Problems.QuadraticAssignment/3.3/Tests/QAPMoveEvaluatorTest.cs	(revision 6801)
@@ -87,5 +87,4 @@
     [TestMethod]
     public void Swap2MoveEvaluatorFastEvaluationTest() {
-
       for (int i = 0; i < 500; i++) {
         Swap2Move lastMove = new Swap2Move(random.Next(ProblemSize), random.Next(ProblemSize));
@@ -257,4 +256,51 @@
     }
 
+    [TestMethod]
+    public void AffinitySwapMoveEvaluatorTest() {
+      for (int i = 0; i < 500; i++) {
+        int index1, index2, index3, index4;
+        do {
+          index1 = random.Next(ProblemSize);
+          index2 = random.Next(ProblemSize);
+          index3 = random.Next(ProblemSize);
+          index4 = random.Next(ProblemSize);
+        } while (!(index1 != index2 && index1 != index3 && index1 != index4 && index2 != index3 && index2 != index4 && index3 != index4));
+        AffinitySwapMove affinityMove = new AffinitySwapMove();
+        affinityMove.AddSwap(index1, index2);
+        affinityMove.AddSwap(index3, index4);
+        Assert.IsTrue(affinityMove.GetSwapLocation(index1) == index2
+          && affinityMove.GetSwapLocation(index2) == index1
+          && affinityMove.GetSwapLocation(index3) == index4
+          && affinityMove.GetSwapLocation(index4) == index3);
+
+        // SYMMETRIC MATRICES
+        double before = QAPEvaluator.Apply(assignment, symmetricWeights, symmetricDistances);
+        Permutation clone = (Permutation)assignment.Clone();
+        Swap2Manipulator.Apply(assignment, index1, index2);
+        Swap2Manipulator.Apply(assignment, index3, index4);
+        double after = QAPEvaluator.Apply(assignment, symmetricWeights, symmetricDistances);
+        double move = AffinitySwapMoveEvaluator.Apply(clone, affinityMove, symmetricWeights, symmetricDistances);
+        Assert.IsTrue(move.IsAlmost(after - before), "Failed on symmetric matrices");
+
+        // ASYMMETRIC MATRICES
+        before = QAPEvaluator.Apply(assignment, asymmetricWeights, asymmetricDistances);
+        clone = (Permutation)assignment.Clone();
+        Swap2Manipulator.Apply(assignment, index1, index2);
+        Swap2Manipulator.Apply(assignment, index3, index4);
+        after = QAPEvaluator.Apply(assignment, asymmetricWeights, asymmetricDistances);
+        move = AffinitySwapMoveEvaluator.Apply(clone, affinityMove, asymmetricWeights, asymmetricDistances);
+        Assert.IsTrue(move.IsAlmost(after - before), "Failed on asymmetric matrices");
+
+        // NON-ZERO DIAGONAL ASSYMETRIC MATRICES
+        before = QAPEvaluator.Apply(assignment, nonZeroDiagonalWeights, nonZeroDiagonalDistances);
+        clone = (Permutation)assignment.Clone();
+        Swap2Manipulator.Apply(assignment, index1, index2);
+        Swap2Manipulator.Apply(assignment, index3, index4);
+        after = QAPEvaluator.Apply(assignment, nonZeroDiagonalWeights, nonZeroDiagonalDistances);
+        move = AffinitySwapMoveEvaluator.Apply(clone, affinityMove, nonZeroDiagonalWeights, nonZeroDiagonalDistances);
+        Assert.IsTrue(move.IsAlmost(after - before), "Failed on non-zero diagonal matrices");
+      }
+    }
+
   }
 }
